Skip to content

feat(extract): add scoped call graph with sync connection detection (#237) - #246

Merged
NTCoding merged 3 commits into
mainfrom
issue-237-m1-d1-1-d1-2-d1-3-d1-4-build-s
Feb 1, 2026
Merged

NTCoding merged 3 commits into
mainfrom
issue-237-m1-d1-1-d1-2-d1-3-d1-4-build-s

Conversation

@NTCoding

@NTCoding NTCoding commented Feb 1, 2026 •

Copy link
Copy Markdown
Owner

Closes #237

Deliverable: Scoped call graph construction, non-component transparency, interface resolution, and sync connection detection

Context

PRD: `docs/project/PRD/active/PRD-phase-12-connection-detection.md` — M1 D1.1, D1.2, D1.3, D1.4

Connection detection requires building a method-level call graph from known components, tracing through non-components, resolving single-implementation interfaces, and detecting sync connections via method calls on component-typed instances. These four deliverables share the same state dependencies (ts-morph Project, EnrichedComponent[], ComponentIndex) and form a single vertical slice through the connection detection capability.

Traceability

  • PRD Section: M1-D1.1 (Scoped call graph), M1-D1.2 (Non-component transparency), M1-D1.3 (Interface resolution), M1-D1.4 (Sync connection detection)
  • Functional Requirements: Type-based method call resolution, component-to-component edge production, single-impl interface auto-resolve
  • Success Criteria: SC-1 (Golden Path sync connections), SC-3 (non-component tracing), SC-4 (interface resolution)

Acceptance Criteria

  • ✓ ComponentIndex value object built from EnrichedComponent[] + AST, supporting type-name lookup and file:line location lookup for method-level components
  • ✓ Method-level call graph constructed via DFS from component methods using type-based resolution (declared types on constructor params, fields, variables)
  • ✓ Cycle detection via visited set per traversal path — already-visited methods skipped
  • ✓ Non-component classes traced through transparently: A → non1 → non2 → B produces A → B link
  • ✓ Dead-end chains (component → non-component → nothing) produce no link
  • ✓ One link per unique (source component, target component, type) tuple
  • ✓ Source location for transitive connections references call site in source component (lexically first occurrence)
  • ✓ Single-implementation interface/abstract class auto-resolves within extraction config module globs (node_modules excluded)
  • ✓ Zero implementations: fail fast in strict mode, mark uncertain in lenient mode
  • ✓ Multiple implementations: fail fast in strict mode, mark uncertain in lenient mode
  • ✓ Sync connections detected when calling methods on instances whose declared type is a known component
  • ✓ Constructor parameters provide type info — method call creates the link, not constructor declaration
  • ✓ Every connection includes sourceLocation (file path, line number, method name)
  • ✓ Unresolvable types: strict mode fails with error (file, line, type name, reason); lenient mode emits _uncertain
  • ✓ Generic types match against base type (Repository matches component Repository)
  • ✓ Self-links (source === target) excluded
  • ✓ Getters traced into (have method bodies); property access without getter not traced
  • ✓ Chained calls a.b().c() — each resolved independently via declared return type
  • ✓ await is transparent
  • ✓ 100% branch coverage

Edge Case Scenarios

  • Empty EnrichedComponent[] → empty links array, no errors
  • Component with no method calls → no links produced
  • Component calling only non-components that lead to dead ends → no links
  • Circular call chain (A → B → A) → cycle detected, no infinite loop, produces A → B and B → A links
  • Multiple call sites between same component pair → single link, lexically first source location
  • Interface with zero implementations in strict mode → structured error with file/line/interface name
  • Interface with 3+ implementations in strict mode → structured error listing implementation count
  • Generic type Repository → matches component named Repository
  • Method call on untyped variable (any) → strict fails, lenient marks uncertain
  • Component method calling this.field where field type is another component → link produced
  • Deeply nested non-component chain (5+ hops) → correctly traces through all
  • Self-referential component (calls own methods) → no self-link produced

Implementation Guidelines

  • Architecture: New `domain/connection-detection/` capability in `riviere-extract-ts` per §9.1.2
    • `call-graph/` — Scoped call graph construction + DFS traversal
    • `sync-detection/` — Method call detection
    • `interface-resolution/` — Single-impl auto-resolve
    • `detect-connections.ts` — Orchestrator
  • Firm constraints: §9.1.1 (no new packages), §9.1.2 (domain capability in extract-ts), §9.2.1 (ComponentIndex immutable value object)
  • Flexible decisions: §9.2.2 (ScopedCallGraph implementation details), §9.2.3 (ExtractedLink extends Link)
  • Use ts-morph for AST traversal (already a dependency of extract-ts)
  • Follow existing patterns in `domain/component-extraction/extractor.ts` and `domain/value-extraction/`
  • ExtractedLink extends Link from riviere-schema with optional `_uncertain?: string`
  • Apply SD-004 (dependency injection), SD-001 (fail-fast), SD-010 (wrap primitives as value objects)
  • Follow `docs/conventions/codebase-structure.md` CS-004 (organize by usage)

Embedded Reasoning

Why: Components are identified and enriched. Detecting how they connect via method calls is the foundation of flow-based architecture extraction. Call graph + sync detection is the core capability everything else builds on.
What: ComponentIndex (immutable lookup), ScopedCallGraph (DFS traversal with type-based resolution), interface resolution (single-impl auto-resolve), sync connection detection (method calls → ExtractedLink[]).
How: Build ComponentIndex from EnrichedComponent[] + AST. For each component method, DFS through call sites resolving receiver types via declared types. Collapse non-component nodes. Produce one ExtractedLink per unique (source, target, type) tuple.

Testing Strategy

  • Unit: ComponentIndex construction and lookups (type-name, file:line). Call graph DFS traversal. Interface resolution (0, 1, N implementations). Sync detection for direct calls, transitive calls, chained calls.
  • Integration: End-to-end from EnrichedComponent[] + ts-morph Project to ExtractedLink[] using multi-file test fixtures.
  • Edge Cases: Empty inputs, cycles, dead ends, self-links, generic types, untyped variables, getters vs property access, await transparency.
  • Performance: Not in scope for this task (D1.8).

Dependencies

None — this is the foundational task.

Verification

```bash
pnpm nx test riviere-extract-ts -- --testNamePattern "connection-detection"
pnpm nx test riviere-extract-ts -- --coverage
```

Summary by CodeRabbit

  • New Features

    • Added a connection-detection subsystem to analyze and emit component-to-component call links (multi‑hop tracing, interface resolution) and new public types/APIs for detection, indexing, extracted links, and structured errors.
  • Tests

    • Added extensive unit and coverage tests for call-graph building, type resolution, interface resolution, tracing edge cases, deduplication, and overall detection behavior.
  • Chores

    • Added a workspace dependency and updated TypeScript project references for the new subsystem.

✏️ Tip: You can customize this high-level summary in your review settings.

Implements connection detection for riviere-extract-ts: ComponentIndex,
type resolver, interface resolution, call graph DFS with non-component
transparency, and detectConnections orchestrator. 287 tests, 100% coverage.

Closes #237

Co-Authored-By: Claude Opus 4.5 <[email protected]>
@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Feb 1, 2026 •

Copy link
Copy Markdown

Deploying living-architecture with  Cloudflare Pages  Cloudflare Pages

Latest commit: 459b26b
Status: ✅  Deploy successful!
Preview URL: https://edfad062.living-architecture.pages.dev
Branch Preview URL: https://issue-237-m1-d1-1-d1-2-d1-3.living-architecture.pages.dev

View logs

@coderabbitai

coderabbitai Bot commented Feb 1, 2026 •

Copy link
Copy Markdown
📝 Walkthrough

Walkthrough

Adds a connection-detection subsystem to riviere-extract-ts: component indexing, receiver type resolution, interface resolution, call-graph construction with non-component tracing and deduplication, error type, orchestrator (detectConnections), fixtures/tests, and new public exports; also adds a workspace dependency and tsconfig project reference.

Changes

Cohort / File(s) Summary
Workspace config
packages/riviere-extract-ts/package.json, packages/riviere-extract-ts/tsconfig.lib.json
Add workspace dependency @living-architecture/riviere-schema and add project reference to ../riviere-schema/tsconfig.lib.json.
Public API exports
packages/riviere-extract-ts/src/shell/index.ts
Export connection-detection API: detectConnections, ConnectionDetectionOptions, ExtractedLink, ComponentIndex, ConnectionDetectionError.
Orchestrator
packages/riviere-extract-ts/src/domain/connection-detection/detect-connections.ts, packages/riviere-extract-ts/src/domain/connection-detection/detect-connections.spec.ts
Add detectConnections entrypoint, module-glob filtering, strict/lenient option mapping, and tests.
Core types
packages/riviere-extract-ts/src/domain/connection-detection/extracted-link.ts, .../call-graph/call-graph-types.ts, .../call-graph/call-graph-types.spec.ts
Introduce ExtractedLink with optional _uncertain, and call-graph interfaces (CallGraphOptions, CallSite, RawLink, UncertainRawLink) plus helpers.
Component index
packages/riviere-extract-ts/src/domain/connection-detection/component-index.ts, .../component-index.spec.ts
Add ComponentIndex value object indexing by type name and file:line with isComponent, getComponentByTypeName, getComponentByLocation and tests.
Call-graph implementation
packages/riviere-extract-ts/src/domain/connection-detection/call-graph/build-call-graph.ts, .../trace-calls.ts, .../call-graph/call-graph-shared.ts
Implement call-graph traversal: resolve receivers, trace through non-components recursively with visited-set, resolve via interfaces, collect raw/uncertain links; shared lookup and resolution helpers.
Deduplication
packages/riviere-extract-ts/src/domain/connection-detection/call-graph/deduplicate-links.ts, .../deduplicate-links.spec.ts
Deduplicate links by (source,target,type), prefer earliest call-site, emit uncertain links normalized as ExtractedLink.
Type resolver
packages/riviere-extract-ts/src/domain/connection-detection/call-graph/type-resolver.ts, .../type-resolver.spec.ts, .../type-resolver.coverage.spec.ts, .../type-resolver-fixtures.ts
Add receiver-type resolution (strip generics/Promise, fallback to vars/params/fields), strict vs lenient behavior (throw vs uncertain), and extensive tests/fixtures.
Interface resolution
packages/riviere-extract-ts/src/domain/connection-detection/interface-resolution/resolve-interface.ts, .../resolve-interface.spec.ts
Resolve interface/abstract to single implementation within scoped source files (exclude node_modules), strict vs lenient outcomes and tests.
Errors & utilities
packages/riviere-extract-ts/src/domain/connection-detection/connection-detection-error.ts
Add ConnectionDetectionError exposing file, line, typeName, reason for structured failures.
Test fixtures & coverage tests
packages/riviere-extract-ts/src/domain/connection-detection/call-graph/*, .../type-resolver.coverage.spec.ts, .../build-call-graph.coverage.spec.ts
Add in-memory ts-morph fixtures and many unit/coverage tests covering tracing, getters/await transparency, strict/lenient modes, deduplication, and edge cases.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant Detect as detectConnections
    participant Index as ComponentIndex
    participant Build as buildCallGraph
    participant Resolver as resolveCallExpressionReceiverType
    participant Interface as resolveInterface
    participant Dedup as deduplicateLinks

    Client->>Detect: project, components, options, globMatcher
    Detect->>Index: build ComponentIndex from components
    Index-->>Detect: ComponentIndex
    Detect->>Build: project, components, ComponentIndex, sourceFilePaths, options
    Build->>Build: iterate components & methods
    Build->>Resolver: resolve receiver type for call
    alt resolver returns concrete type
        Resolver-->>Build: typeName
    else resolver uncertain
        Resolver->>Interface: resolve interface within sourceFilePaths
        Interface-->>Resolver: implementationName or unresolved(reason)
        Resolver-->>Build: resolved typeName or uncertain
    end
    Build->>Build: trace into non-component methods recursively (visited set avoids cycles)
    Build->>Dedup: rawLinks[], uncertainLinks[]
    Dedup-->>Build: ExtractedLink[] (deduplicated, normalized)
    Build-->>Detect: ExtractedLink[]
    Detect-->>Client: ExtractedLink[]
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related issues

  • NTCoding/living-architecture#239 — This PR implements detectConnections and public exports that enable wiring connection detection into the CLI as described in the issue.

Suggested labels

Review effort 4/5

Poem

🐰 I hopped through types and method trails,

tracing calls through fields and tail-to-tail.
When interfaces hid, I sniffed the clue—
one impl or many, strict or loose, I knew.
Call graphs bloom where rabbit paws prevail.

🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat(extract): add scoped call graph with sync connection detection' accurately summarizes the main change: implementing call graph construction and synchronous connection detection as described in the PR objectives.
Linked Issues check ✅ Passed The PR implements all four major deliverables from issue #237: ComponentIndex construction with dual lookups, scoped method-level call graph via DFS, interface resolution with single-implementation auto-resolve, and sync connection detection via method invocations on typed instances, including cycle detection, non-component transparency, generic type matching, and strict/lenient error handling.
Out of Scope Changes check ✅ Passed All changes are directly aligned with #237 deliverables: connection-detection infrastructure, call-graph construction, interface resolution, type resolution, component indexing, and appropriate test coverage. The package.json and tsconfig updates support the new riviere-schema dependency required for the implementation.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch issue-237-m1-d1-1-d1-2-d1-3-d1-4-build-s

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 10

🤖 Fix all issues with AI agents
In
`@packages/riviere-extract-ts/src/domain/connection-detection/call-graph/build-call-graph.ts`:
- Around line 27-105: resolveTypeThroughInterface currently forces strict: false
and drops interface resolution results; update it to pass options.strict into
resolveInterface and return both the found component (if any) and the interface
resolution result (e.g., { component, interfaceResult }) instead of just a
component. Then update processCallExpression to use that returned pair: if
interfaceResult.resolved is true but component is undefined, call
traceNonComponent using interfaceResult.typeName (so non-component
implementations are traced), and if interfaceResult has a non-empty reason and
options.strict is false (lenient) push an uncertainLinks entry with that reason
and currentCallSite; ensure when a component is found you keep the existing
rawLinks logic and when resolveInterface failed you still push uncertainLinks as
before.

In
`@packages/riviere-extract-ts/src/domain/connection-detection/call-graph/call-graph-fixtures.ts`:
- Around line 5-12: The sharedProject constant duplicates the same Project setup
(useInMemoryFileSystem and identical compilerOptions) used elsewhere; replace
duplication by extracting a reusable factory or shared fixture function (e.g.,
createSharedProject or getSharedProject) and use that from both
call-graph-fixtures.ts and type-resolver-fixtures.ts, or if test isolation is
required, add a short comment explaining why a separate sharedProject instance
is intentional; update references to the new function (look for sharedProject
and Project) and ensure imports are updated accordingly.

In
`@packages/riviere-extract-ts/src/domain/connection-detection/call-graph/call-graph-types.spec.ts`:
- Around line 9-17: Add edge-case unit tests for stripGenericArgs in the
existing spec: add cases asserting that stripGenericArgs('') returns '' (empty
input), stripGenericArgs('Map<K, List<V>>') returns 'Map' (nested generics), and
stripGenericArgs('Pair<A, B>') returns 'Pair' (multiple type parameters) so the
function's robustness is validated alongside the existing tests.

In
`@packages/riviere-extract-ts/src/domain/connection-detection/call-graph/deduplicate-links.spec.ts`:
- Around line 22-70: Add three edge-case tests for deduplicateLinks: (1) assert
deduplicateLinks([], []) returns an empty array to cover empty inputs; (2)
provide multiple UncertainRawLink entries and assert all are present in result
(e.g., two different uncertain links with distinct callSite entries and reasons)
to ensure uncertain links are fully included; (3) create duplicate RawLink
entries with the same source/target and identical sourceLocation.lineNumber and
assert deterministic/stable outcome (e.g., resulting length is 1 and the
preserved link equals the first input) to verify behavior when line numbers are
equal. Reference the deduplicateLinks function and existing test helpers like
buildRawLink/buildComponent to construct inputs.

In
`@packages/riviere-extract-ts/src/domain/connection-detection/call-graph/trace-calls.ts`:
- Around line 38-130: resolveCallExpressionReceiverType and resolveInterface are
being called with strict: false and interface-resolution uncertainty is dropped;
update resolveTypeThroughInterface to accept options.strict and pass
options.strict into resolveInterface so strict mode is honored, return any
uncertainty (e.g., change resolveTypeThroughInterface signature to return
{component, uncertain, resolvedTypeName?}), then in traceCallsInBody call
resolveCallExpressionReceiverType with { strict: options.strict }, call
resolveTypeThroughInterface with the same options, if
resolveTypeThroughInterface returns an uncertain reason push an UncertainRawLink
into uncertainResults (include originCallSite and the uncertainty string), and
if interface resolution succeeded but component is undefined, replace typeName
with the resolved implementation name from resolveTypeThroughInterface before
forming visitKey and before calling resolveMethodDeclaration so tracing
continues against the concrete type even when it's not a registered component.

In
`@packages/riviere-extract-ts/src/domain/connection-detection/component-index.spec.ts`:
- Around line 7-19: The test defines a local buildComponent helper that largely
duplicates the one in call-graph-fixtures.ts; extract this into a shared test
fixture (e.g., tests/fixtures/component-fixtures.ts) and import it into
component-index.spec.ts and call-graph-fixtures.ts, keeping EnrichedComponent as
the shared type; if the differing defaults (type: 'service' and name:
'OrderService') are intentional, expose buildComponent with optional parameters
or an overload/variant (e.g., buildComponent({ type?, name? })) so callers can
pass differing defaults rather than maintaining two copies.

In
`@packages/riviere-extract-ts/src/domain/connection-detection/component-index.ts`:
- Around line 3-9: Duplicate stripGenericArgs function found in
component-index.ts; remove this local implementation and reuse the shared helper
instead. Replace the local function by importing the shared stripGenericArgs
from the common utilities module (where the canonical implementation lives),
update any references in component-index.ts to use that imported symbol, and
ensure the import statement is added/updated and any local tests still pass.

In
`@packages/riviere-extract-ts/src/domain/connection-detection/detect-connections.spec.ts`:
- Around line 9-18: Replace the magic numeric targets in createProject by using
ts-morph enums: set compilerOptions.target to ScriptTarget.ESNext and
compilerOptions.module to ModuleKind.ESNext (import these enums from ts-morph)
to make intent clear; also remove the duplicated local buildComponent helper and
import the shared buildComponent fixture used elsewhere (the duplicate helper in
this spec should be replaced with the shared fixture import) so tests reuse the
common fixture.

In
`@packages/riviere-extract-ts/src/domain/connection-detection/detect-connections.ts`:
- Around line 13-25: The function filterSourceFiles currently mutates the shared
Project by calling project.removeSourceFile which causes side effects; change it
to be pure by returning a filtered list (e.g., array of SourceFile or file
paths) instead of removing files. Update filterSourceFiles to compute the keep
list using project.getSourceFiles(), moduleGlobs and globMatcher and return that
list; remove any calls to project.removeSourceFile inside it and update callers
to traverse only the returned files (or file paths) when performing connection
detection (references: filterSourceFiles, project.getSourceFiles,
project.removeSourceFile, moduleGlobs, globMatcher).

In
`@packages/riviere-extract-ts/src/domain/connection-detection/interface-resolution/resolve-interface.ts`:
- Around line 39-46: The current name comparisons in implementsInterface and
extendsAbstractClass use getText() which breaks on aliased imports; change both
to resolve the referenced symbol name first (use
impl.getExpression().getType().getSymbol()?.getName() or
extendsClause.getExpression().getType().getSymbol()?.getName()) and fall back to
getExpression().getText() if the symbol lookup is undefined, following the
pattern in type-resolver.ts; apply the same symbol-first matching fix to the
analogous checks in evaluate-predicate.ts and
evaluate-extraction-rule-generic.ts so aliased interface/class names are
correctly detected.

Comment thread packages/riviere-extract-ts/src/domain/connection-detection/component-index.ts Outdated
Comment thread packages/riviere-extract-ts/src/domain/connection-detection/detect-connections.ts Outdated
…no mutation

Wire strict/lenient mode through interface resolution and type resolver.
Extract shared functions from build-call-graph and trace-calls. Remove
project mutation in detectConnections. Add symbol-based interface matching.

Co-Authored-By: Claude Opus 4.5 <[email protected]>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 8

🤖 Fix all issues with AI agents
In
`@packages/riviere-extract-ts/src/domain/connection-detection/call-graph/build-call-graph.spec.ts`:
- Around line 39-70: The test hardcodes the call site lineNumber (10) which is
fragile because the template literal's leading newline and any formatting
changes will shift line numbers; update the spec to compute the expected line
number dynamically from the generated source instead of a magic constant. Use
the same file string produced by nextFile(...) and derive the line index of the
call (e.g., find the line containing "this.repo.save()" or compute line offset
from the class/method declaration) and assert that sourceLocation.lineNumber
equals that computed value; adjust references in the test around buildComponent,
buildCallGraph, ComponentIndex and defaultOptions to use the computed value so
the assertion remains correct if the template formatting changes.

In
`@packages/riviere-extract-ts/src/domain/connection-detection/call-graph/call-graph-shared.spec.ts`:
- Around line 55-76: The test for resolveTypeThroughInterface uses a fragile
hardcoded import './shared-test-${counter.value - 1}' in implFile; instead build
the impl import from the actual generated interface file name returned by
nextFile (e.g. derive the import path from interfaceFile's filename/path) so the
import always points to the interface created just above; update implFile
creation in the spec to reference that derived filename (affecting the
implFile/nextFile usage and the import string) so resolveTypeThroughInterface
and symbols like SharedGateway, interfaceFile, implFile, nextFile, and counter
no longer rely on counter ordering.
- Around line 15-23: The spec duplicates the test fixture pattern
(sharedProject, counter, nextFile) already defined in call-graph-fixtures.ts;
remove the local declarations (sharedProject, counter, nextFile) and import the
equivalent fixtures from call-graph-fixtures.ts (use the exported Project
instance, counter helper, and nextFile helper) so this spec reuses the shared
utilities—if test isolation is required, instead export a factory from
call-graph-fixtures.ts (e.g., createSharedProject or nextFileFactory) and call
that from this spec to get isolated instances.

In
`@packages/riviere-extract-ts/src/domain/connection-detection/call-graph/call-graph-shared.ts`:
- Around line 20-23: getCalledMethodName currently calls asKindOrThrow and will
throw when the CallExpression's expression is not a PropertyAccessExpression;
add a short JSDoc to document this precondition and thrown behavior and state
that callers must ensure
Node.isPropertyAccessExpression(callExpr.getExpression()) (or equivalent) before
calling getCalledMethodName; update the comment above the getCalledMethodName
function to describe that it extracts the method name from a property access
call expression and will throw if the expression is not a property access.
- Around line 56-76: findMethodInProject currently does a full scan of
project.getSourceFiles() each call which is costly; implement a module-level
cache (e.g., Map<string, MethodLookup> or Map<string, ClassDeclaration>) and
change findMethodInProject to check the cache first and only do the full scan
once to populate the cache on first miss; update the cache key by class name
(typeName) and return cached MethodLookup (method and classFound) thereafter;
alternatively replace the scan with ts-morph type resolution if you prefer, but
the quick fix is to add the cache and populate it inside the findMethodInProject
function so repeated lookups are O(1).

In
`@packages/riviere-extract-ts/src/domain/connection-detection/detect-connections.spec.ts`:
- Around line 115-160: Update the two tests to exercise unresolved-type
behavior: create a class that references a missing interface/type (e.g., use a
parameter or property typed to MissingInterface with no implementation) instead
of only defining execute(): void; then in the strict test (StrictComp) call
detectConnections(project, [comp], { moduleGlobs: [...] }, matchesGlob) and
assert it throws (or returns the strict-mode error) due to the unresolved type;
in the lenient test (LenientComp) pass allowIncomplete: true and assert
detectConnections returns a result entry for that component with status
'_uncertain' (or the lenient unresolved marker your code uses). Reference
detectConnections, StrictComp, LenientComp, and allowIncomplete to locate where
to change the test.

In
`@packages/riviere-extract-ts/src/domain/connection-detection/detect-connections.ts`:
- Around line 32-34: The double-negative mapping for strict is confusing: change
the mapping so strict is set directly from a non-negated flag or rename the
option; specifically, update the call to buildCallGraph in detect-connections
(the strict: options.allowIncomplete !== true line) to use strict:
!options.allowIncomplete for clarity, or alternatively rename the option in
ConnectionDetectionOptions from allowIncomplete to strict and propagate that
rename through callers so buildCallGraph receives strict directly.

In
`@packages/riviere-extract-ts/src/domain/connection-detection/interface-resolution/resolve-interface.ts`:
- Around line 71-78: createError currently constructs ConnectionDetectionError
with empty file/line, losing call-site context; change
createError(interfaceName: string, reason: string) to accept and forward caller
file and line (e.g., createError(interfaceName: string, reason: string, file:
string, line: number)) and update every call site in this module that invokes
createError to pass the actual source context (the file path and line number
available where the unresolved interface is detected). Ensure the returned
ConnectionDetectionError uses the provided file and line instead of ''/0 so
callers of resolve/interface-resolution logic receive actionable location info.

…ion mapping

Strict/lenient tests now trigger on unresolvable `any` types. Simplified
double negative in options mapping.

Co-Authored-By: Claude Opus 4.5 <[email protected]>
@sonarqubecloud

sonarqubecloud Bot commented Feb 1, 2026

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In
`@packages/riviere-extract-ts/src/domain/connection-detection/detect-connections.ts`:
- Around line 24-35: In detectConnections, validate the incoming
ConnectionDetectionOptions before using moduleGlobs and allowIncomplete: ensure
options.moduleGlobs exists and is a non-empty array of non-empty strings (filter
out invalid/malformed entries) and ensure options.allowIncomplete is a boolean
(coerce or set a safe default if missing); if validation fails, either throw a
clear error or fall back to a safe default and log/warn; perform this check
right before calling computeFilteredFilePaths and then pass the sanitized
moduleGlobs and boolean into computeFilteredFilePaths/buildCallGraph
(referencing detectConnections, ConnectionDetectionOptions, moduleGlobs,
allowIncomplete, computeFilteredFilePaths, buildCallGraph, and ComponentIndex to
locate where to add the guard).

@NTCoding
NTCoding merged commit 8ce1d84 into main Feb 1, 2026
24 of 25 checks passed
NTCoding pushed a commit that referenced this pull request Feb 1, 2026
…nent reflection storage

Process improvements from post-merge reflection on PR #246:
- Post-merge-completion: pipeline timeline, inefficiency
  diagnosis, permanent storage, failure descriptions
- Task-check: behavioral correctness verification
- SD-022: never mutate function parameters
- CR-007: assertion-to-title alignment in tests
- CR-008: edge case checklist enforcement on test files
- CR-004: duplication checks apply equally to test files
- RFC-010: symbol-based AST name resolution
- BS-015: inconsistent patterns across feature files

Closes #247

Co-Authored-By: Claude Opus 4.5
<[email protected]>
@coderabbitai coderabbitai Bot mentioned this pull request Aug 10, 2026
7 tasks done
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[M1-D1.1/D1.2/D1.3/D1.4] Build scoped call graph with sync connection detection

1 participant