Repository navigation
feat(extract): wire connection detection into CLI with performance instrumentation (#239) - #252
Conversation
…strumentation (#239) Wire `detectConnections` from riviere-extract-ts into the `riviere extract` CLI command. Change output format from flat component array to `{ components, links }` object. Add `--stats` and `--patterns` flags. - Return `ConnectionDetectionResult { links, timings }` from detectConnections - Add ConnectionDetectionFailure error code and exit handler - Add formatExtractionStats and formatTimingLine for stderr output - Create detectAndOutputConnections command for connection pipeline - Update existing tests for new output shape - Add 8 new tests for connection detection, stats, timing, flags - Regenerate CLI reference docs Co-Authored-By: Claude Opus 4.6 <[email protected]>
Addresses SD-019 code review finding: use Zod schemas instead of type guards for runtime validation of parsed JSON in test fixtures. Co-Authored-By: Claude Opus 4.6 <[email protected]>
Connection detection is a read/output operation, not a write/mutate operation. Moves to queries/ layer per CS-010 layer responsibility alignment. Co-Authored-By: Claude Opus 4.6 <[email protected]>
Pure query (detect-connections-query.ts) returns data only. Presentation logic (timing, stats, output) stays in entrypoint. Fixes CS-010 layer responsibility alignment. Co-Authored-By: Claude Opus 4.6 <[email protected]>
Deploying living-architecture with
|
| Latest commit: |
5d2380d
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://ee77bb10.living-architecture.pages.dev |
| Branch Preview URL: | https://issue-239-m1-d1-8-d1-9-wire.living-architecture.pages.dev |
📝 WalkthroughWalkthroughWires connection detection into the Changes
Sequence Diagram(s)sequenceDiagram
participant CLI as User/CLI
participant Entrypoint as Extract Entrypoint
participant Enricher as Enrichment Phase
participant Detector as Connection Detector
participant Formatter as Stats Formatter
participant Output as Stdout/Stderr
CLI->>Entrypoint: riviere extract --stats --patterns ...
Entrypoint->>Enricher: run enrichment -> EnrichedComponent[]
Enricher-->>Entrypoint: EnrichedComponent[]
Entrypoint->>Detector: detectConnections(components, { patterns })
Note over Detector: measure setup (rgba(0,128,0,0.5)), callGraph (rgba(0,0,255,0.5)), async detection (rgba(255,165,0,0.5)), total (rgba(128,0,128,0.5))
Detector-->>Entrypoint: { links, timings }
Entrypoint->>Formatter: countLinksByType(...) / formatExtractionStats(...)
Formatter-->>Entrypoint: stats lines
Entrypoint->>Formatter: formatTimingLine(timings)
Formatter-->>Entrypoint: timing summary
Entrypoint->>Output: write { success:true, data: { components, links } } to stdout
Entrypoint->>Output: write stats/timings to stderr (if requested)
Estimated code review effort🎯 4 (Complex) | ⏱️ ~50 minutes Possibly related issues
Possibly related PRs
Suggested labels
Poem
🚥 Pre-merge checks | ✅ 4✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 6
🤖 Fix all issues with AI agents
In
`@packages/riviere-cli/src/features/extract/__fixtures__/extraction-test-fixtures.ts`:
- Around line 54-58: parseExtractionOutput currently throws TestAssertionError
with only result.error.message while parseFullExtractionOutput throws a richer
message including a custom JSON preview; make their error formatting consistent
by changing parseExtractionOutput (and the other parse helper at the other
location) to throw TestAssertionError with a combined message that includes both
the structured Zod error (result.error.message) and a short JSON preview of the
invalid input (use JSON.stringify(parsed) truncated/previewed), preserving the
existing TestAssertionError usage and the extractionOutputSchema/result
identifiers so the message mirrors parseFullExtractionOutput’s format for
uniform debugging.
In
`@packages/riviere-cli/src/features/extract/entrypoint/extract.connections.spec.ts`:
- Around line 68-105: Add a file-level afterEach hook to restore mocks so
vi.spyOn(console, 'error') in the tests does not leak into other tests;
specifically, add an afterEach that calls the Vitest restore function (e.g.,
vi.restoreAllMocks()) near the top of the test file (alongside createTestContext
/ setupCommandTest) so any spying on console.error is cleaned up after each
spec.
In `@packages/riviere-cli/src/features/extract/entrypoint/extract.ts`:
- Around line 51-52: The CLI --patterns flag is parsed but not used; add a
boolean patterns property to the ConnectionDetectionOptions type in
ConnectionDetectionOptions (used in detect-connections.ts), propagate that field
through detectConnectionsQuery (ensure the query builder accepts and forwards
options.patterns), and update detectConnections (the function that inspects
source files) to branch into pattern-based detection when options.patterns is
true (apply the existing pattern matching logic or add pattern matching steps
there and ensure return shape matches current ConnectionDetectionResult). Also
update any callers that construct ConnectionDetectionOptions to pass the parsed
patterns flag through.
In
`@packages/riviere-cli/src/features/extract/queries/detect-connections-query.ts`:
- Around line 10-13: DetectConnectionsInput duplicates the existing
ConnectionDetectionOptions type; replace the local interface by importing and
reusing ConnectionDetectionOptions so changes stay in sync. Update
detect-connections-query.ts to import the type (e.g., import type {
ConnectionDetectionOptions } from the extract package) and change any references
from DetectConnectionsInput to ConnectionDetectionOptions (remove the duplicate
interface declaration and adjust function/method signatures that use
DetectConnectionsInput such as the detect-connections query entry point).
In
`@packages/riviere-cli/src/platform/infra/cli-presentation/format-extraction-stats.spec.ts`:
- Around line 128-139: Rename the test to reflect that it checks truncation to
zero rather than precision: update the test description string in the spec that
calls formatTimingLine from "formats timing with sub-millisecond precision" to
something like "formats timing by truncating sub-millisecond values to 0.00s"
(or "truncates sub-millisecond timings to 0.00s") so the intent matches the
assertion.
In
`@packages/riviere-extract-ts/src/domain/connection-detection/detect-connections.ts`:
- Around line 47-50: The timing variable currently named filteringMs incorrectly
includes both ComponentIndex construction and file filtering; change the name
(e.g., indexingAndFilteringMs or componentIndexAndFilteringMs) to reflect that
it measures the duration between performance.now() assigned to filteringStart
and the later timestamp after new ComponentIndex(components) and
computeFilteredFilePaths(...) complete, update the variable declaration and all
usages, and also update the ConnectionTimings type/field names to match the new
identifier so semantics remain correct (references: filteringStart,
ComponentIndex, computeFilteredFilePaths, filteringMs, ConnectionTimings).
- Align error message format in parse fixtures (use Zod error.message) - Add afterEach mock restore in connection detection spec - Rename test: 'truncates sub-millisecond values to zero' - Rename filteringMs to setupMs (measures indexing + filtering) - Update timing output label from 'filtering' to 'setup' Co-Authored-By: Claude Opus 4.6 <[email protected]>
There was a problem hiding this comment.
Actionable comments posted: 0
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
packages/riviere-extract-ts/src/domain/connection-detection/detect-connections.ts (1)
1-76: 🛠️ Refactor suggestion | 🟠 MajorKeep timing side effects out of core detection logic.
Line 45+ reads from
performance.now(), makingdetectConnectionstime-dependent. Consider injecting anow()dependency (or moving timing to a wrapper) so the core detection stays deterministic while the CLI supplies the clock.💡 Possible refactor (inject clock via options)
export interface ConnectionDetectionOptions { allowIncomplete?: boolean moduleGlobs: string[] + now: () => number } export function detectConnections( project: Project, components: readonly EnrichedComponent[], options: ConnectionDetectionOptions, globMatcher: GlobMatcher, ): ConnectionDetectionResult { - const totalStart = performance.now() + const now = options.now + const totalStart = now() - const setupStart = performance.now() + const setupStart = now() const componentIndex = new ComponentIndex(components) const sourceFilePaths = computeFilteredFilePaths(project, options.moduleGlobs, globMatcher) - const setupMs = performance.now() - setupStart + const setupMs = now() - setupStart - const callGraphStart = performance.now() + const callGraphStart = now() const syncLinks = buildCallGraph(project, components, componentIndex, { strict, sourceFilePaths, }) - const callGraphMs = performance.now() - callGraphStart + const callGraphMs = now() - callGraphStart - const asyncStart = performance.now() + const asyncStart = now() const publishLinks = detectPublishConnections(project, components, { strict }) const subscribeLinks = detectSubscribeConnections(components, { strict }) - const asyncDetectionMs = performance.now() - asyncStart + const asyncDetectionMs = now() - asyncStart - const totalMs = performance.now() - totalStart + const totalMs = now() - totalStartAs per coding guidelines, implement detection logic as pure functions with no side effects.
…ry wrapper The detect-connections-query was a thin pass-through with no real orchestration. Inline the call directly in the entrypoint to satisfy CS-010 layer responsibility rules. Co-Authored-By: Claude Opus 4.6 <[email protected]>
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Fix all issues with AI agents
In `@packages/riviere-cli/src/features/extract/entrypoint/extract.ts`:
- Line 82: Replace the implicit-return arrow callback passed to
formatDryRunOutput(...).forEach so it uses a block body that explicitly calls
console.log; locate the expression using formatDryRunOutput and change the
forEach callback from an expression-bodied arrow to a block-bodied arrow that
calls console.log(line) inside the block to silence the lint warning.
- Around line 139-143: The stats printing uses a concise arrow in
formatExtractionStats(stats).forEach((line) => console.error(line)) which
creates an implicit return; change the forEach callback to a block body to avoid
that by rewriting the callback to use braces and an explicit statement (for
example: forEach((line) => { console.error(line) })); update the call site that
references options.stats, countLinksByType, enrichmentResult.components.length,
and formatExtractionStats to use the block-bodied arrow so the console.error is
executed as a statement rather than implicitly returned.
…ions call Address CodeRabbit feedback: replace forEach with implicit returns with block-body for-of loops. Compact detectConnections arguments to stay within 150-line entrypoint limit. Co-Authored-By: Claude Opus 4.6 <[email protected]>
…tion-e Co-Authored-By: Claude Opus 4.6 <[email protected]>
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Fix all issues with AI agents
In
`@docs/continuous-improvement/post-merge-reflections/2026-02-05-issue-239-m1-d1-8-d1-9-wire-connection-e.md`:
- Line 1: The document title and its storage directory are inconsistent: the
top-level heading "# Pre-Merge Reflection:
issue-239-m1-d1-8-d1-9-wire-connection-e" should match the directory name
"post-merge-reflections"; either change the heading to "Post-Merge Reflection:
issue-239-m1-d1-8-d1-9-wire-connection-e" to keep the file in its current
directory, or move the file into a "pre-merge-reflections/" directory if the
pre-merge label is intentional—update the heading or relocate the file
accordingly so naming is consistent.
Add AP-009 anti-pattern for inconsistent patterns between related functions. Add RFC-016 for mock cleanup detection (vi.spyOn without afterEach restore). Update pre-merge-reflection template with pipeline improvement proposals section. Fix stale hardcoded RFC range in bug-scanner agent. Co-Authored-By: Claude Opus 4.6 <[email protected]>
Allows pushing convention/process changes after the reflection file has been committed. Guards against bypass by verifying a reflection file exists in a prior commit on the branch. Co-Authored-By: Claude Opus 4.6 <[email protected]>
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
.claude/agents/bug-scanner.md (1)
16-18:⚠️ Potential issue | 🟡 MinorAlign RFC scope wording to the expanded “all RFC checks.”
Line 17 still says RFC-001 through RFC-009, but Line 156 now requires applying each RFC check. Update Line 17 to avoid contradictory guidance.
✅ Suggested update
-2. Read `docs/conventions/review-feedback-checks.md` for RFC checks (RFC-001 through RFC-009) +2. Read `docs/conventions/review-feedback-checks.md` for all RFC checksAlso applies to: 156-156
🤖 Fix all issues with AI agents
In @.claude/commands/pre-merge-reflection.md:
- Around line 198-201: The document contains a duplicated heading "Pipeline
Improvement Proposals" (the detailed subsection and the later top-level
section); consolidate by removing or renaming the later instance to avoid
confusion—e.g., rename the second heading to "Summary of Improvement Proposals"
and update any cross-references or the surrounding explanatory text so it
clearly states that one is the detailed template (the original "Pipeline
Improvement Proposals" subsection) and the other is a short summary, ensuring
consistency in naming and intent wherever the header "Pipeline Improvement
Proposals" appears.
Rename reflection heading to "Post-Merge Reflection" to match the post-merge-reflections/ directory. Remove duplicate "Pipeline Improvement Proposals" section from the template — the subsection under Pipeline Timeline already contains the detailed structure. Co-Authored-By: Claude Opus 4.6 <[email protected]>
|
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 Fix all issues with AI agents
In @.claude/commands/pre-merge-reflection.md:
- Line 84: This is inconsistent: the command and file are named
/pre-merge-reflection and pre-merge-reflection.md but the template header and
output path use "Post-Merge"; update the template header "Post-Merge Reflection"
to "Pre-Merge Reflection" and change any output directory references from
post-merge-reflections/ to pre-merge-reflections/, and search for and update any
other references to "Post-Merge Reflection" so all uses (file
pre-merge-reflection.md, command /pre-merge-reflection, header text, and output
directory) consistently say "Pre-Merge Reflection".
In
`@docs/continuous-improvement/post-merge-reflections/2026-02-05-issue-239-m1-d1-8-d1-9-wire-connection-e.md`:
- Line 30: Check the pipeline timeline vs the narrative: confirm whether there
were actually 4 architecture review iterations for the CS-010 rule or only 3
(review `#3`, review `#7`, review `#10` shown). If there were only 3, update the
sentence that says "4 architecture review iterations" to "3 architecture review
iterations" and adjust the explanatory sentence about detectConnections
accordingly; if there was a fourth review outside the table, add that missing
review entry to the timeline (with its identifier and brief note) or append a
parenthetical clarifying that one review occurred off-timeline. Reference the
detectConnections mention and the sentence claiming "4 architecture review
iterations" when making the edit.
- Around line 180-186: The "Recommended Follow-Ups" list has inconsistent status
markers: items "AP-009: Inconsistent Patterns Between Related Functions" and
"RFC-016: Mock Cleanup After vi.spyOn" use ✅ but the remaining items ("RFC:
'Prefer for-of over forEach for side-effect-only iteration'", "Create task: Add
pre-implementation placement check to task workflow", "Create task: Add 'single
function call = inline in entrypoint' guidance to separation-of-concerns") lack
any indicator; update the list under the "Recommended Follow-Ups" heading to use
a consistent checkbox convention (e.g., ✅ for completed and ❌ or ⬜ for pending)
and apply it to each list item so every entry clearly shows completion status
(adjust the three pending items to start with ❌ or ⬜).



Closes #239
Deliverable: CLI integration for connection extraction with performance timing and new flags
Context
PRD: `docs/project/PRD/active/PRD-phase-12-connection-detection.md` — M1 D1.8, D1.9
Connection detection must be wired into the existing `riviere extract` CLI command. This includes the breaking output format change, new flags (--patterns, --stats), and performance instrumentation showing per-phase timing.
Traceability
Acceptance Criteria
Edge Case Scenarios
Implementation Guidelines
Embedded Reasoning
Why: Connection detection is useless without CLI integration. The extract command is the primary user interface.
What: Extended extract command with connection detection wiring, new flags, output format change, performance timing.
How: After enrichment phase, call detectConnections(). Merge results into output. Add flag handling. Wrap phases in timing. Display summary.
Testing Strategy
Dependencies
Depends on #237 #238
Verification
```bash
pnpm nx test riviere-cli -- --testNamePattern "extract"
pnpm nx test riviere-cli -- --coverage
```
Summary by CodeRabbit
New Features
Documentation
Tests