Skip to content

Feat/continuity source hygiene#4

Merged
Boulea7 merged 2 commits intomainfrom
feat/continuity-source-hygiene
Mar 20, 2026
Merged

Feat/continuity source hygiene#4
Boulea7 merged 2 commits intomainfrom
feat/continuity-source-hygiene

Conversation

@Boulea7
Copy link
Owner

@Boulea7 Boulea7 commented Mar 20, 2026

Summary

Describe the behavior change in user-facing terms.

What changed

Claude parity

Explain whether this change improves Claude Code auto memory parity, preserves it, or intentionally diverges.

Validation

  • pnpm lint
  • pnpm test
  • pnpm build

Docs

  • README updated if onboarding changed
  • docs/claude-reference.md updated if parity behavior changed
  • docs/architecture.md updated if internals changed
  • docs/native-migration.md updated if migration assumptions changed

Risks

List any risks, edge cases, or follow-up work.

Summary by Sourcery

Tighten continuity and memory reviewer hygiene by adding explicit confidence/warning surfaces, contradiction review for preference conflicts, and richer CLI/JSON diagnostics, while ensuring docs and CI enforce the updated reviewer-facing contract.

New Features:

  • Introduce contradiction review for extracted memory operations to conservatively suppress conflicting preference and workflow candidates while recording reviewer-visible conflict metadata.
  • Expose continuity confidence levels and warning messages across diagnostics, audit entries, recovery records, and session CLI surfaces, including startup provenance that only lists existing continuity files.
  • Surface suppressed memory conflict candidates and suppression counts in sync audit entries, memory CLI output, and pending sync recovery markers for better reviewer inspection.
  • Add CLI smoke tests and docs-contract tests, plus new test fixtures, to verify reviewer command surfaces, continuity hygiene, and packability from the public docs entry points.

Enhancements:

  • Refine heuristic session continuity summarization to track when fallback next steps are inferred, scrub reviewer warning prose from continuity bodies, and compute a normalized confidence signal.
  • Extend session continuity evidence collection with structured warning hints for reviewer noise and conflicting directive signals, feeding into diagnostics and prompts.
  • Normalize legacy continuity audit and recovery records to include confidence and warnings, and improve text drill-down formatting to show confidence, warnings, and evidence.
  • Ensure wrapper and session startup only inject or report continuity source files that actually exist, tightening startup provenance semantics.

Build:

  • Add a composite pnpm ci script and pack:check script to run lint, contract tests, smoke tests, unit tests, build, and dry-run packaging in a single command.

CI:

  • Extend CI workflow to run docs-contract, reviewer-smoke, CLI-smoke, and pack-check steps alongside lint, tests, and build to enforce the updated reviewer and packaging guarantees.

Documentation:

  • Update README (EN/CN), architecture docs, session continuity guide, release checklist, and contributing guide to describe confidence and warning surfaces, contradiction review behavior, CLI reviewer entry points, and release-time verification steps.

Tests:

  • Expand session continuity, sync service, extractor, memory, recovery-record, and session-command tests to cover warning hints, confidence levels, conflict suppression behavior, CLI JSON/text contracts, and legacy normalization paths.
  • Add docs-contract, reviewer-smoke, and CLI-smoke Vitest suites plus rollout fixtures for noisy and conflicting preference scenarios to guard the reviewer-facing contract.

Summary by cubic

Add contradiction review and reviewer confidence to keep session continuity and durable memory clean. Conflicting or hedged preferences are suppressed and surfaced in CLI output and audit instead of silently merging.

  • New Features

    • Add contradiction review to the sync path to detect conflicts within a rollout or against existing memory; suppress noisy/hedged candidates and record conflicts and suppressedOperationCount in audit/recovery.
    • Add session continuity confidence and warnings; summarizer emits high/medium/low plus reviewer-only warning hints; cam session shows confidence/warnings in text and JSON; prompt guards against copying reviewer hints into continuity.
    • Improve CLI surfaces: cam memory shows suppressed counts and a compact conflict review in pending recovery; wrapper only includes existing continuity file paths.
  • Refactors

    • CI hardening: add test:docs-contract, test:reviewer-smoke, test:cli-smoke, and pack:check; wire into workflow and pnpm ci.
    • Docs: update architecture with contradiction review and audit step; README notes suppressed conflicts; session continuity doc adds confidence/warnings; release checklist and CONTRIBUTING reflect new reviewer rules.
    • Types/validation: introduce MemoryConflictCandidate and continuity confidence; extend audit and recovery records; add fixtures and tests for conflicting preferences and reviewer noise.

Written for commit 0f112a4. Summary will update on new commits.

Summary by CodeRabbit

  • New Features

    • Memory sync now detects and conservatively suppresses conflicting candidates instead of silently merging them
    • Session continuity diagnostics include confidence levels and reviewer warnings for better visibility
    • Audit output displays suppressed operation counts and detailed conflict information
  • Documentation

    • Updated to reflect new conflict handling, confidence levels, and continuity diagnostic behavior
  • Tests

    • Added contract and smoke test coverage for enhanced verification

@sourcery-ai
Copy link

sourcery-ai bot commented Mar 20, 2026

Reviewer's Guide

Introduce continuity confidence and warning hygiene across session continuity, sync, and CLI surfaces, add contradiction review for memory extraction, and tighten reviewer-facing documentation and release/test contracts while ensuring CLI-based workflows are fully covered by smoke tests.

Sequence diagram for continuity confidence and warning propagation

sequenceDiagram
  actor Reviewer
  participant CLI as SessionCLI
  participant Store as SessionContinuityStore
  participant Summ as SessionContinuitySummarizer
  participant Ev as collectSessionContinuityEvidenceBuckets
  participant Audit as ContinuityAuditLog

  Reviewer->>CLI: cam session save or refresh
  CLI->>Store: readExistingState
  CLI->>Summ: generate(evidence, existingState, config)
  Summ->>Ev: collectSessionContinuityEvidenceBuckets(evidence)
  Ev-->>Summ: buckets including warningHints

  alt extractorMode heuristic
    Summ->>Summ: heuristicSummary(evidence, existingState, buckets)
    Summ-->>CLI: summary, diagnostics with confidence low|medium
  else extractorMode codex
    Summ->>Summ: tryCodexExtraction(evidence)
    alt codex success
      Summ->>Summ: buildDiagnostics(actualPath codex, warnings buckets.warningHints)
      Summ-->>CLI: summary codex, diagnostics confidence high|medium
    else codex failed or low signal
      Summ->>Summ: heuristicSummary(evidence, existingState, buckets)
      Summ->>Summ: buildDiagnostics(actualPath heuristic, fallbackReason, warnings buckets.warningHints, usedFallbackNext)
      Summ-->>CLI: summary heuristic, diagnostics confidence low
    end
  end

  CLI->>Audit: buildSessionContinuityAuditEntry(diagnostics)
  Audit-->>Audit: persist audit entry with confidence and warnings

  Note over Summ,Audit: Reviewer warning prose is scrubbed from continuity Markdown
  Note over Summ: scrubReviewerWarningProse(summary, buckets.warningHints)

  Reviewer->>CLI: cam session status or load
  CLI->>Store: readRecentAuditEntries
  Store-->>CLI: latest SessionContinuityAuditEntry
  CLI->>CLI: toSessionContinuityDiagnostics(entry)
  CLI->>CLI: normalizeContinuityRecoveryRecord(record)
  CLI-->>Reviewer: text and json including confidence and warnings while keeping continuity body clean
Loading

Class diagram for contradiction review and memory audit types

classDiagram
  class MemoryScope

  class MemoryOperation {
    <<interface>>
    action string
    scope MemoryScope
    topic string
    id string
    summary string
    details string
    sources string[]
    reason string
  }

  class MemoryEntry {
    <<interface>>
    id string
    scope MemoryScope
    topic string
    summary string
    details string
    sources string[]
    reason string
  }

  class MemoryConflictCandidate {
    <<interface>>
    scope MemoryScope
    topic string
    candidateSummary string
    conflictsWith string[]
    source MemoryConflictSource
    resolution MemoryConflictResolution
  }

  class MemoryConflictSource {
    <<type>>
    within-rollout
    existing-memory
  }

  class MemoryConflictResolution {
    <<type>>
    suppressed
  }

  class ReviewedMemoryOperations {
    <<interface>>
    operations MemoryOperation[]
    suppressedOperationCount number
    conflicts MemoryConflictCandidate[]
  }

  class SyncService {
    +syncFromRollout(evidence, isRecovery) Promise
    -extractOperations(evidence, existingEntries) Promise
  }

  class MemorySyncAuditEntry {
    <<interface>>
    appliedAt string
    status string
    appliedCount number
    suppressedOperationCount number
    scopesTouched MemoryScope[]
    conflicts MemoryConflictCandidate[]
    resultSummary string
  }

  class SyncRecoveryRecord {
    <<interface>>
    appliedCount number
    suppressedOperationCount number
    scopesTouched MemoryScope[]
    conflicts MemoryConflictCandidate[]
    failedStage string
    failureMessage string
  }

  MemoryConflictCandidate --> MemoryScope
  MemoryConflictCandidate --> MemoryConflictSource
  MemoryConflictCandidate --> MemoryConflictResolution

  ReviewedMemoryOperations --> MemoryOperation
  ReviewedMemoryOperations --> MemoryConflictCandidate

  MemorySyncAuditEntry --> MemoryConflictCandidate
  SyncRecoveryRecord --> MemoryConflictCandidate

  SyncService --> ReviewedMemoryOperations
  SyncService --> MemorySyncAuditEntry
Loading

File-Level Changes

Change Details Files
Add continuity confidence and warning plumbing end-to-end and ensure legacy audit/recovery data is normalized into the new shape.
  • Extend SessionContinuityDiagnostics and related types with confidence and warnings fields, plus normalization helpers for legacy data.
  • Update session continuity audit formatting and drill-down text to display confidence and warnings and surface them in JSON outputs.
  • Normalize continuity recovery records so pending recovery surfaces and CLI text include confidence and warning information.
src/lib/types.ts
src/lib/domain/session-continuity-diagnostics.ts
src/lib/domain/recovery-records.ts
src/lib/commands/session.ts
test/session-command.test.ts
test/recovery-records.test.ts
docs/session-continuity.md
Improve heuristic continuity summarization to track confidence, infer next-step warnings, and scrub reviewer-warning prose from continuity bodies while preserving it in diagnostics.
  • Augment continuity evidence buckets to collect reviewer warning hints and directive conflicts from user/agent messages.
  • Teach heuristicSummary to return whether it had to infer next steps from the latest request and propagate that into diagnostics warnings.
  • Implement a deterministic scrub that removes reviewer warning prose from codex/heuristic continuity layer summaries based on patterns and bucket hints, with tests for mixed-language and warning-only codex outputs and fallbacks.
src/lib/extractor/session-continuity-evidence.ts
src/lib/extractor/session-continuity-summarizer.ts
src/lib/extractor/session-continuity-prompt.ts
test/session-continuity.test.ts
Introduce contradiction review for extracted memory operations so conflicting preferences/commands are conservatively suppressed and audited instead of silently merged.
  • Add a contradiction-review module that groups reviewable memory operations, detects directive conflicts (package manager, repo search, command usage), and suppresses low-confidence or stale candidates while keeping conflict metadata.
  • Integrate contradiction review into SyncService so sync writes only apply reviewed operations and record suppressedOperationCount and conflict candidates into the sync audit log and recovery records.
  • Update memory command text/JSON surfaces and tests to show suppressed counts and conflict review, and document the behavior in README and architecture docs.
src/lib/extractor/contradiction-review.ts
src/lib/domain/sync-service.ts
src/lib/domain/memory-sync-audit.ts
src/lib/domain/recovery-records.ts
src/lib/commands/memory.ts
test/extractor.test.ts
test/sync-service.test.ts
test/memory-command.test.ts
test/memory-sync-audit.test.ts
README.md
README.en.md
docs/architecture.md
docs/architecture.en.md
src/lib/types.ts
test/fixtures/rollouts/within-rollout-preference-conflict.jsonl
test/fixtures/rollouts/hedged-preference-conflict.jsonl
test/fixtures/rollouts/mixed-language-reviewer-noise.jsonl
Tighten CLI-based session and memory flows and ensure continuity source file provenance only includes existing files.
  • Add CLI smoke tests that invoke the TSX-based CLI entrypoint for session load/status and memory commands, and assert startup payloads and JSON fields including confidence, warnings, and audit paths.
  • Ensure wrapper/session startup sourceFiles arrays only list continuity files that actually exist, so provenance reflects real reads.
  • Update release checklist and contributing docs to point to the TSX CLI entrypoints and new verification commands.
test/session-command.test.ts
test/memory-command.test.ts
src/lib/commands/wrapper.ts
docs/release-checklist.md
CONTRIBUTING.md
Add docs-contract and reviewer-smoke safeguards plus CI wiring to keep docs and reviewer surfaces in sync with implementation.
  • Introduce a docs-contract test that asserts key reviewer surfaces, wording, and commands remain present in README, architecture, continuity, and migration docs.
  • Add reviewer-smoke and CLI-smoke test scripts that cover session, memory, and audit reviewer flows, and wire them into package.json scripts and CI workflow.
  • Update README and architecture docs (both languages) to describe conservative suppression, conflict review, and continuity confidence/warning behavior, and document the combined CI script and pack check.
test/docs-contract.test.ts
package.json
.github/workflows/ci.yml
README.md
README.en.md
docs/architecture.md
docs/architecture.en.md
docs/native-migration.md
docs/session-continuity.md
docs/release-checklist.md
CONTRIBUTING.md

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@coderabbitai
Copy link

coderabbitai bot commented Mar 20, 2026

📝 Walkthrough

Walkthrough

This PR introduces conflict detection and reviewer confidence modeling to the memory sync system. It adds a new contradiction-review module to identify and suppress conflicting memory operations extracted from the same rollout or against existing memory, records conflict metadata in audit entries, and extends session continuity with confidence levels and warning hints to track sync reliability and provide reviewer diagnostics.

Changes

Cohort / File(s) Summary
CI and Build Configuration
.github/workflows/ci.yml, package.json
Added CI steps for new test suites (test:docs-contract, test:reviewer-smoke, test:cli-smoke) and packaging verification (pack:check); introduced corresponding npm scripts.
Documentation and Contributing Guidelines
CONTRIBUTING.md, README.md, README.en.md, docs/architecture.md, docs/architecture.en.md, docs/release-checklist.md, docs/session-continuity.md
Updated architecture/flow diagrams and descriptions to document the new contradiction-review and conservative-suppression step; added guidance on reviewer-only warnings, confidence levels, and continuity diagnostics; expanded release checklist with new test/packaging verification steps and CLI command updates.
Public Type Definitions
src/lib/types.ts
Extended public types to include conflict-related structures (MemoryConflictCandidate, MemoryConflictSource, MemoryConflictResolution) and session continuity confidence modeling (SessionContinuityConfidence); added suppressedOperationCount and conflicts fields to memory sync audit and recovery records; added confidence and warnings to continuity diagnostics and recovery records.
Memory Sync Audit and Recovery Record Validation
src/lib/domain/memory-sync-audit.ts, src/lib/domain/recovery-records.ts
Added type guards, parsing, and validation for conflict metadata and suppression counts; extended audit entry building and formatting to include conflict review sections; updated recovery record builders to populate suppression and conflict fields.
Session Continuity Diagnostics and Normalization
src/lib/domain/session-continuity-diagnostics.ts
Added helpers to normalize confidence and warnings; extended diagnostics to compute and surface confidence levels; added scrubbing for reviewer-warning prose to prevent noise from continuity body; updated audit formatting to include confidence and warning sections.
Contradiction Detection and Review
src/lib/extractor/contradiction-review.ts
New module implementing reviewExtractedMemoryOperations to identify choice-level conflicts within same-rollout candidates and against existing memory; suppresses conflicting operations and records detailed conflict candidates with sources and resolutions.
Session Continuity Evidence and Prompting
src/lib/extractor/session-continuity-evidence.ts, src/lib/extractor/session-continuity-prompt.ts
Added warning-hints collection to flag reviewer/subagent noise, hedged directives, and conflicting signals; extended prompt output to expose warning hints as reviewer-only context with non-copyable instructions.
Session Continuity Summarization
src/lib/extractor/session-continuity-summarizer.ts
Introduced reviewer-warning scrubbing patterns and confidence determination logic; extended diagnostics building to track warnings and inferred-next-step fallback indicators; refactored heuristic output to expose fallback reasoning.
Command Implementations
src/lib/commands/memory.ts, src/lib/commands/session.ts, src/lib/commands/wrapper.ts
Updated memory/session command outputs to surface suppression counts and conflict reviews; added normalization of continuity recovery records before rendering; refactored continuity source file filtering to use explicit exists flags.
Sync Service and Memory Operations
src/lib/domain/sync-service.ts
Integrated reviewExtractedMemoryOperations post-processor to apply contradiction review before persisting sync results; extended recovery record writing to capture and persist suppression counts and conflict metadata.
Test Contracts and Fixtures
test/docs-contract.test.ts, test/fixtures/rollouts/within-rollout-preference-conflict.jsonl, test/fixtures/rollouts/hedged-preference-conflict.jsonl, test/fixtures/rollouts/mixed-language-reviewer-noise.jsonl
Added documentation contract verification test; created test fixtures for preference conflict scenarios (within-rollout, hedged, and mixed-language noise).
Test Suite Updates
test/extractor.test.ts, test/memory-command.test.ts, test/memory-sync-audit.test.ts, test/recovery-records.test.ts, test/session-command.test.ts, test/session-continuity.test.ts, test/sync-service.test.ts
Extended tests to validate conflict detection, suppression counts, confidence levels, and warning handling; added integration tests for CLI behavior; updated assertions to verify new audit/recovery record fields and continuity diagnostics.

Sequence Diagram(s)

sequenceDiagram
    participant Extractor as Extractor<br/>(Extract Ops)
    participant Review as Contradiction<br/>Reviewer
    participant Sync as SyncService
    participant Audit as Audit Entry<br/>Builder
    participant Recovery as Recovery Record

    Extractor->>Review: reviewExtractedMemoryOperations<br/>(operations, existingEntries)
    activate Review
    Note over Review: Identify choice-level<br/>conflicts within same-rollout<br/>& vs existing memory
    Review->>Review: Determine suppression<br/>decisions
    Review-->>Extractor: ReviewedMemoryOperations<br/>(filtered ops, suppressedCount,<br/>conflicts[])
    deactivate Review

    Extractor->>Sync: syncRollout(reviewed)<br/>with suppression metadata
    activate Sync
    Sync->>Audit: buildMemorySyncAuditEntry<br/>(suppressedOperationCount,<br/>conflicts)
    activate Audit
    Audit-->>Sync: MemorySyncAuditEntry<br/>with conflict reviews
    deactivate Audit

    Sync->>Recovery: writeSyncRecoveryRecord<br/>(suppressedOperationCount,<br/>conflicts)
    activate Recovery
    Recovery-->>Sync: Persisted recovery record
    deactivate Recovery
    deactivate Sync
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Poem

🐰 Conflicts arise when choices dance,
But vigilant review grants second chance.
We suppress the confused, keep wisdom clear,
With confidence high when the path is near.
Warnings whispered, noise gently gone,
Continuity marches safely on. 🎯

🚥 Pre-merge checks | ❌ 3

❌ Failed checks (2 warnings, 1 inconclusive)

Check name Status Explanation Resolution
Description check ⚠️ Warning The pull request description is largely incomplete. The required template sections are present but mostly empty: 'What changed' has only a dash, 'Claude parity', 'Validation', 'Docs', and 'Risks' sections lack meaningful content. The auto-generated summaries by Sourcery and cubic provide substantial detail, but the author-provided content is minimal. Complete the 'What changed', 'Claude parity', 'Validation', 'Docs', and 'Risks' sections with specific details. Use the auto-generated summaries as reference to articulate the key behavior changes, parity impact, and validation steps required.
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The title 'Feat/continuity source hygiene' is partially related to the changeset. It refers to a real aspect of the changes (continuity and source file handling), but is overly broad and does not clearly communicate the main feature additions such as contradiction review, confidence/warning surfaces, or suppression of conflicting candidates. Consider a more descriptive title that highlights the primary change, such as 'Add contradiction review and confidence/warning surfaces to memory sync and continuity' or 'Implement preference conflict suppression and reviewer confidence signals'.

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

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/continuity-source-hygiene
📝 Coding Plan
  • Generate coding plan for human review comments

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

Copy link

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

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

Hey - I've found 2 issues, and left some high level feedback:

  • The conflict/hedged directive detection logic (e.g., hedgedDirectivePattern, package manager/repo-search value handling, and directive extraction) is now implemented in both session-continuity-evidence.ts and contradiction-review.ts; consider centralizing this into a shared helper to avoid drift between continuity warnings and durable-memory contradiction review.
  • Confidence calculation is implemented in multiple places (determineConfidence in the summarizer vs. normalizeSessionContinuityConfidence for audit/recovery normalization) with slightly different inputs (e.g., usedFallbackNext); it would be safer to have a single canonical confidence computation to avoid inconsistent values across surfaces.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- The conflict/hedged directive detection logic (e.g., `hedgedDirectivePattern`, package manager/repo-search value handling, and directive extraction) is now implemented in both `session-continuity-evidence.ts` and `contradiction-review.ts`; consider centralizing this into a shared helper to avoid drift between continuity warnings and durable-memory contradiction review.
- Confidence calculation is implemented in multiple places (`determineConfidence` in the summarizer vs. `normalizeSessionContinuityConfidence` for audit/recovery normalization) with slightly different inputs (e.g., `usedFallbackNext`); it would be safer to have a single canonical confidence computation to avoid inconsistent values across surfaces.

## Individual Comments

### Comment 1
<location path="src/lib/extractor/session-continuity-summarizer.ts" line_range="284-287" />
<code_context>
+  warnings: string[] = [],
+  usedFallbackNext = false
 ): SessionContinuityDiagnostics {
+  const normalizedWarnings = [...new Set(warnings)];
+  if (usedFallbackNext) {
+    normalizedWarnings.push(
+      "Next steps were inferred from the latest request because the rollout did not contain an explicit next-step phrase."
+    );
+  }
</code_context>
<issue_to_address>
**nitpick (bug_risk):** Deduplication of warnings is lost when appending the fallback-next warning; consider re-normalizing or checking before push.

Here you dedupe `warnings` via `new Set`, but then always `push` the inferred-next-steps warning when `usedFallbackNext` is true. If a caller ever passes this same string in `warnings`, it will appear twice. Either add the inferred warning before creating `normalizedWarnings`, or check `normalizedWarnings.includes(...)` before pushing to preserve uniqueness.
</issue_to_address>

### Comment 2
<location path="src/lib/domain/session-continuity-diagnostics.ts" line_range="86-95" />
<code_context>
+    : [];
+}
+
+export function normalizeSessionContinuityConfidence(
+  confidence: unknown,
+  warnings: string[],
+  fallbackReason?: SessionContinuityFallbackReason
+): SessionContinuityConfidence {
+  if (isConfidence(confidence)) {
+    return confidence;
+  }
+
+  if (fallbackReason) {
+    return "low";
+  }
+
+  return warnings.length > 0 ? "medium" : "high";
+}
+
</code_context>
<issue_to_address>
**question:** Confidence normalization logic slightly diverges from `determineConfidence`; consider aligning the behaviors.

`determineConfidence` currently treats any fallback reason, any warnings, or `usedFallbackNext` as `low`, `high` for codex with no warnings/fallback, and `medium` otherwise. Here, `normalizeSessionContinuityConfidence` only returns `low` when `fallbackReason` is present and treats `warnings.length > 0` as `medium`, so legacy records with warnings but no fallback will differ from newly generated diagnostics. Consider either matching `determineConfidence`’s thresholds or clearly documenting the intentional difference and, if needed, passing additional inputs (e.g., `usedFallbackNext`) into this function.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment on lines +284 to +287
const normalizedWarnings = [...new Set(warnings)];
if (usedFallbackNext) {
normalizedWarnings.push(
"Next steps were inferred from the latest request because the rollout did not contain an explicit next-step phrase."
Copy link

Choose a reason for hiding this comment

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

nitpick (bug_risk): Deduplication of warnings is lost when appending the fallback-next warning; consider re-normalizing or checking before push.

Here you dedupe warnings via new Set, but then always push the inferred-next-steps warning when usedFallbackNext is true. If a caller ever passes this same string in warnings, it will appear twice. Either add the inferred warning before creating normalizedWarnings, or check normalizedWarnings.includes(...) before pushing to preserve uniqueness.

Comment on lines +86 to +95
export function normalizeSessionContinuityConfidence(
confidence: unknown,
warnings: string[],
fallbackReason?: SessionContinuityFallbackReason
): SessionContinuityConfidence {
if (isConfidence(confidence)) {
return confidence;
}

if (fallbackReason) {
Copy link

Choose a reason for hiding this comment

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

question: Confidence normalization logic slightly diverges from determineConfidence; consider aligning the behaviors.

determineConfidence currently treats any fallback reason, any warnings, or usedFallbackNext as low, high for codex with no warnings/fallback, and medium otherwise. Here, normalizeSessionContinuityConfidence only returns low when fallbackReason is present and treats warnings.length > 0 as medium, so legacy records with warnings but no fallback will differ from newly generated diagnostics. Consider either matching determineConfidence’s thresholds or clearly documenting the intentional difference and, if needed, passing additional inputs (e.g., usedFallbackNext) into this function.

Copy link

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

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

4 issues found across 32 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="package.json">

<violation number="1" location="package.json:31">
P3: `test:reviewer-smoke` redundantly includes `test/docs-contract.test.ts` (already run by `test:docs-contract` immediately before it in `ci`) and shares two test files with `test:cli-smoke`. Consider removing the overlap between the smoke scripts so each file runs once during the smoke phase and once in the full `pnpm test`.</violation>
</file>

<file name="src/lib/domain/recovery-records.ts">

<violation number="1" location="src/lib/domain/recovery-records.ts:123">
P2: Type guard accepts non-number `suppressedOperationCount` values. Because the variable defaults invalid types to `0`, any non-number value (string, boolean, object) silently passes. Validate the field type directly instead.</violation>

<violation number="2" location="src/lib/domain/recovery-records.ts:139">
P2: Type guard accepts non-array `conflicts` values. When `record.conflicts` is a non-array truthy value (e.g., a string or number), both sides of the length comparison resolve to `0`, so the check passes silently. Consider validating with `(record.conflicts === undefined || (Array.isArray(record.conflicts) && ...))` to reject invalid types.</violation>
</file>

<file name="src/lib/domain/session-continuity-diagnostics.ts">

<violation number="1" location="src/lib/domain/session-continuity-diagnostics.ts:99">
P2: `normalizeSessionContinuityConfidence` returns `"medium"` when warnings are present but `fallbackReason` is absent, whereas `determineConfidence` returns `"low"` for the same condition. Legacy records without a stored `confidence` that have warnings will therefore be normalized to `medium` instead of `low`, creating an inconsistency with newly generated diagnostics. Align the thresholds or document the intentional difference.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

suppressedOperationCount >= 0 &&
Array.isArray(record.scopesTouched) &&
record.scopesTouched.every((scope) => isMemoryScope(scope)) &&
conflicts.length === (Array.isArray(record.conflicts) ? record.conflicts.length : 0) &&
Copy link

@cubic-dev-ai cubic-dev-ai bot Mar 20, 2026

Choose a reason for hiding this comment

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

P2: Type guard accepts non-array conflicts values. When record.conflicts is a non-array truthy value (e.g., a string or number), both sides of the length comparison resolve to 0, so the check passes silently. Consider validating with (record.conflicts === undefined || (Array.isArray(record.conflicts) && ...)) to reject invalid types.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src/lib/domain/recovery-records.ts, line 139:

<comment>Type guard accepts non-array `conflicts` values. When `record.conflicts` is a non-array truthy value (e.g., a string or number), both sides of the length comparison resolve to `0`, so the check passes silently. Consider validating with `(record.conflicts === undefined || (Array.isArray(record.conflicts) && ...))` to reject invalid types.</comment>

<file context>
@@ -96,8 +133,10 @@ export function isSyncRecoveryRecord(value: unknown): value is SyncRecoveryRecor
+    suppressedOperationCount >= 0 &&
     Array.isArray(record.scopesTouched) &&
     record.scopesTouched.every((scope) => isMemoryScope(scope)) &&
+    conflicts.length === (Array.isArray(record.conflicts) ? record.conflicts.length : 0) &&
     isSyncRecoveryFailedStage(record.failedStage) &&
     typeof record.failureMessage === "string" &&
</file context>
Fix with Cubic

)
: [];
const suppressedOperationCount =
typeof record.suppressedOperationCount === "number" ? record.suppressedOperationCount : 0;
Copy link

@cubic-dev-ai cubic-dev-ai bot Mar 20, 2026

Choose a reason for hiding this comment

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

P2: Type guard accepts non-number suppressedOperationCount values. Because the variable defaults invalid types to 0, any non-number value (string, boolean, object) silently passes. Validate the field type directly instead.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src/lib/domain/recovery-records.ts, line 123:

<comment>Type guard accepts non-number `suppressedOperationCount` values. Because the variable defaults invalid types to `0`, any non-number value (string, boolean, object) silently passes. Validate the field type directly instead.</comment>

<file context>
@@ -84,6 +114,13 @@ export function isSyncRecoveryRecord(value: unknown): value is SyncRecoveryRecor
+      )
+    : [];
+  const suppressedOperationCount =
+    typeof record.suppressedOperationCount === "number" ? record.suppressedOperationCount : 0;
   return (
     typeof record.recordedAt === "string" &&
</file context>
Fix with Cubic

return "low";
}

return warnings.length > 0 ? "medium" : "high";
Copy link

@cubic-dev-ai cubic-dev-ai bot Mar 20, 2026

Choose a reason for hiding this comment

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

P2: normalizeSessionContinuityConfidence returns "medium" when warnings are present but fallbackReason is absent, whereas determineConfidence returns "low" for the same condition. Legacy records without a stored confidence that have warnings will therefore be normalized to medium instead of low, creating an inconsistency with newly generated diagnostics. Align the thresholds or document the intentional difference.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src/lib/domain/session-continuity-diagnostics.ts, line 99:

<comment>`normalizeSessionContinuityConfidence` returns `"medium"` when warnings are present but `fallbackReason` is absent, whereas `determineConfidence` returns `"low"` for the same condition. Legacy records without a stored `confidence` that have warnings will therefore be normalized to `medium` instead of `low`, creating an inconsistency with newly generated diagnostics. Align the thresholds or document the intentional difference.</comment>

<file context>
@@ -71,12 +77,35 @@ function isEvidenceCounts(
+    return "low";
+  }
+
+  return warnings.length > 0 ? "medium" : "high";
+}
+
</file context>
Suggested change
return warnings.length > 0 ? "medium" : "high";
return warnings.length > 0 ? "low" : "high";
Fix with Cubic

"test": "vitest run",
"test:cli-smoke": "vitest run test/audit.test.ts test/memory-command.test.ts test/session-command.test.ts",
"test:docs-contract": "vitest run test/docs-contract.test.ts",
"test:reviewer-smoke": "vitest run test/docs-contract.test.ts test/memory-command.test.ts test/session-command.test.ts test/session-continuity.test.ts",
Copy link

@cubic-dev-ai cubic-dev-ai bot Mar 20, 2026

Choose a reason for hiding this comment

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

P3: test:reviewer-smoke redundantly includes test/docs-contract.test.ts (already run by test:docs-contract immediately before it in ci) and shares two test files with test:cli-smoke. Consider removing the overlap between the smoke scripts so each file runs once during the smoke phase and once in the full pnpm test.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At package.json, line 31:

<comment>`test:reviewer-smoke` redundantly includes `test/docs-contract.test.ts` (already run by `test:docs-contract` immediately before it in `ci`) and shares two test files with `test:cli-smoke`. Consider removing the overlap between the smoke scripts so each file runs once during the smoke phase and once in the full `pnpm test`.</comment>

<file context>
@@ -20,10 +20,15 @@
     "test": "vitest run",
+    "test:cli-smoke": "vitest run test/audit.test.ts test/memory-command.test.ts test/session-command.test.ts",
+    "test:docs-contract": "vitest run test/docs-contract.test.ts",
+    "test:reviewer-smoke": "vitest run test/docs-contract.test.ts test/memory-command.test.ts test/session-command.test.ts test/session-continuity.test.ts",
     "test:watch": "vitest"
   },
</file context>
Suggested change
"test:reviewer-smoke": "vitest run test/docs-contract.test.ts test/memory-command.test.ts test/session-command.test.ts test/session-continuity.test.ts",
"test:reviewer-smoke": "vitest run test/session-continuity.test.ts",
Fix with Cubic

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
src/lib/commands/session.ts (1)

100-124: ⚠️ Potential issue | 🟡 Minor

Normalize diagnostics before compact-history grouping.

The preview row is rendered from toSessionContinuityDiagnostics(group.latest), but the grouping key still uses raw entry.confidence / entry.warnings. Legacy audit entries without explicit confidence therefore stop coalescing with equivalent normalized entries and show up as duplicate “similar” generations. Use the normalized diagnostics in the signature too.

♻️ Proposed fix
   const preview = buildCompactHistoryPreview(entries, {
     excludeLeadingCount: 1,
     maxGroups: recentContinuityPreviewGroupLimit,
-    getSignature: (entry) =>
-      JSON.stringify({
+    getSignature: (entry) => {
+      const diagnostics = toSessionContinuityDiagnostics(entry);
+      return JSON.stringify({
         rolloutPath: entry.rolloutPath,
         sourceSessionId: entry.sourceSessionId,
         scope: entry.scope,
         trigger: normalizeSessionContinuityAuditTrigger(entry.trigger),
         writeMode: normalizeSessionContinuityWriteMode(entry.writeMode),
         preferredPath: entry.preferredPath,
         actualPath: entry.actualPath,
-        confidence: entry.confidence ?? "high",
-        warnings: entry.warnings ?? [],
+        confidence: diagnostics.confidence,
+        warnings: diagnostics.warnings,
         fallbackReason: entry.fallbackReason ?? null,
         codexExitCode: entry.codexExitCode ?? null,
         evidenceCounts: {
           successfulCommands: entry.evidenceCounts.successfulCommands,
           failedCommands: entry.evidenceCounts.failedCommands,
           fileWrites: entry.evidenceCounts.fileWrites,
           nextSteps: entry.evidenceCounts.nextSteps,
           untried: entry.evidenceCounts.untried
         },
         writtenPaths: entry.writtenPaths
-      })
+      });
+    }
   });
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/lib/commands/session.ts` around lines 100 - 124, The grouping signature
passed to buildCompactHistoryPreview uses raw fields (e.g., entry.confidence,
entry.warnings) causing legacy entries to not coalesce; update the getSignature
logic inside buildCompactHistoryPreview to use the normalized diagnostics
instead (call toSessionContinuityDiagnostics(entry) or apply the same
normalization helpers) and replace raw entry.confidence/entry.warnings (and
other diagnostic-derived fields like fallbackReason, codexExitCode if produced
by normalization) with the normalized values so the signature matches what
preview rows render; keep existing keys (rolloutPath, sourceSessionId, scope,
trigger via normalizeSessionContinuityAuditTrigger, writeMode via
normalizeSessionContinuityWriteMode, preferredPath, actualPath, evidenceCounts,
writtenPaths) but source diagnostic values from the normalized diagnostics
object.
src/lib/domain/sync-service.ts (1)

123-141: ⚠️ Potential issue | 🟡 Minor

Surface fully suppressed syncs explicitly.

If contradiction review suppresses every candidate, applied stays empty and this path collapses into the same no-op result as “nothing was extracted”. Callers then get the generic no-op message even though suppressedOperationCount > 0 and conflict metadata exists. Consider a dedicated all-suppressed message so the new reviewer flow is visible without opening the audit log.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/lib/domain/sync-service.ts` around lines 123 - 141, Currently code sets
status = "no-op" whenever applied.length === 0, which hides cases where
reviewExtractedMemoryOperations suppressed all candidates; change the status
calculation after calling reviewExtractedMemoryOperations/applyOperations so
that if applied.length === 0 AND reviewedOperations.suppressedOperationCount > 0
(or there are non-empty reviewedOperations.conflicts if you want to surface
conflict-only cases) you set status to "all-suppressed" instead of "no-op"
before calling buildMemorySyncAuditEntry, ensuring callers see a distinct
all-suppressed audit status.
🧹 Nitpick comments (6)
src/lib/commands/wrapper.ts (1)

85-87: Consider centralizing continuity source-path selection logic.

This exists+map pattern is likely to recur across command surfaces; extracting a shared helper would reduce future drift between wrapper/session code paths.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/lib/commands/wrapper.ts` around lines 85 - 87, Extract the exists+map
logic into a shared helper (e.g., a function like selectExistingPaths or
pickExistingPaths) and replace the inline array handling in wrapper.ts where
[projectLocation, localLocation].filter(...).map(...) is used; the helper should
accept an array of location-like objects (with exists and path properties) and
return an array of path strings for those with exists=true so both wrapper and
session command code paths can call the same utility and avoid divergence.
package.json (1)

23-23: De-duplicate the smoke suites in ci.

test/docs-contract.test.ts, test/memory-command.test.ts, and test/session-command.test.ts now run in the targeted suites and then run again under pnpm test. That makes pnpm ci slower and increases flake surface without strengthening the gate. Consider keeping the smoke suites disjoint, or trimming the redundant targeted runs from the top-level chain.

Also applies to: 29-31

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@package.json` at line 23, The CI script "ci" currently runs targeted smoke
suites ("test:docs-contract", "test:reviewer-smoke", "test:cli-smoke") and then
runs the full "test" script again causing duplication; remove the redundant
targeted runs from the "ci" pipeline or modify the "test" script to exclude
those specific tests so smoke suites run only once. Locate the "ci" npm script
entry in package.json and either delete the duplicate targeted scripts
("test:docs-contract", "test:reviewer-smoke", "test:cli-smoke") from the chain
or update "test" to accept an env/flag that skips those suites, ensuring the
smoke suite scripts remain disjoint from the top-level "test" invocation.
src/lib/commands/memory.ts (1)

63-65: Normalize conflicts before folding it into the compaction key.

The recent-audit preview now treats conflict array order as part of the grouping signature. If the same conflict set is emitted in a different order on retry/recovery, equivalent sync events will stop coalescing and reviewers will see duplicate groups. Sorting by stable fields before JSON.stringify would keep this preview deterministic.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/lib/commands/memory.ts` around lines 63 - 65, The compaction key
currently embeds entry.conflicts as-is which makes grouping order-sensitive;
before folding conflicts into the key (where suppressedOperationCount,
scopesTouched, conflicts are combined), normalize the conflicts array by sorting
it deterministically (e.g., by a stable field such as conflict.id or
conflict.path, then secondary fields as needed) and/or by deep-sorting objects'
keys, then use that sorted structure when JSON.stringify-ing the key; update the
place that builds the compaction key (referencing the conflicts property used
alongside suppressedOperationCount and scopesTouched) to sort/normalize
conflicts first so equivalent conflict sets always produce the same grouping
signature.
test/docs-contract.test.ts (1)

19-23: Prefer stable contract anchors over exact prose fragments.

A few of these checks lock CI to editorial wording ("reviewer warning prose", "deterministic scrub", mixed-language sentence fragments) instead of stable contract markers like command names, field names, or section headings. That will create noisy failures on harmless copy edits. I’d narrow these assertions to the normative surface and leave descriptive wording flexible.

Also applies to: 51-54

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@test/docs-contract.test.ts` around lines 19 - 23, The assertions in
test/docs-contract.test.ts currently assert exact prose fragments (the
expect(...) calls checking "reviewer warning prose", "cam memory", "cam session
status", "confidence", "deterministic scrub"), which is brittle; change those
asserts to check for stable contract anchors instead (e.g., section headings,
field or command names, or backticked identifiers) using case-insensitive
substring or regex matches so copyedits don't break CI—update the expect calls
that read readme/readmeEn (also the similar checks around 51-54) to look for
headings like a "Reviewer" or "Review" section header, explicit field names such
as "confidence" as a standalone word boundary match (e.g. /\bconfidence\b/i) or
backticked API/command names, rather than exact editorial phrases.
src/lib/extractor/contradiction-review.ts (1)

273-289: Consider caching directive choices for existing entries.

The extractDirectiveChoices call inside the filter loop reconstructs a synthetic operation for each existing entry on each review iteration. For large existing entry sets, this could be optimized.

♻️ Potential optimization
+  const existingChoicesCache = new Map<string, DirectiveChoice[]>();
+  for (const entry of existingEntries) {
+    if (!reviewableTopics.has(entry.topic)) continue;
+    const key = `${entry.scope}::${entry.topic}::${entry.id}`;
+    existingChoicesCache.set(key, extractDirectiveChoices({
+      action: "upsert",
+      scope: entry.scope,
+      topic: entry.topic,
+      id: entry.id,
+      summary: entry.summary,
+      details: entry.details,
+      sources: entry.sources,
+      reason: entry.reason
+    }));
+  }

   // Then in the loop:
   const conflictingExisting = existingEntries
     .filter((entry) => {
+      const key = `${entry.scope}::${entry.topic}::${entry.id}`;
+      const existingChoices = existingChoicesCache.get(key) ?? [];
       return (
         entry.scope === review.operation.scope &&
         entry.topic === review.operation.topic &&
-        choicesConflict(review.choices, extractDirectiveChoices({...}))
+        choicesConflict(review.choices, existingChoices)
       );
     })

This is a minor optimization since existing entries are typically small in practice.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/lib/extractor/contradiction-review.ts` around lines 273 - 289, The filter
is calling extractDirectiveChoices for every existing entry on each review which
is wasteful; precompute and cache each existing entry's directive choices once
(e.g., build a Map keyed by entry.id or by the entry object) by invoking
extractDirectiveChoices for the synthetic upsert operation for each entry, then
replace the inline extractDirectiveChoices call inside the conflictingExisting
computation with a lookup to the cache so choicesConflict(review.choices,
cachedChoices) is used instead.
src/lib/domain/recovery-records.ts (1)

34-56: Consider extracting shared type guards to reduce duplication.

The type guards isConflictSource, isConflictResolution, and isMemoryConflictCandidate are duplicated in both recovery-records.ts and memory-sync-audit.ts. Consider extracting these to a shared validation utilities module.

♻️ Suggested approach

Create a shared module like src/lib/util/type-guards.ts:

// src/lib/util/type-guards.ts
export function isMemoryScope(value: unknown): value is MemoryScope { ... }
export function isConflictSource(value: unknown): value is MemoryConflictCandidate["source"] { ... }
export function isConflictResolution(value: unknown): value is MemoryConflictCandidate["resolution"] { ... }
export function isMemoryConflictCandidate(value: unknown): value is MemoryConflictCandidate { ... }
export function isStringArray(value: unknown): value is string[] { ... }

Then import from both recovery-records.ts and memory-sync-audit.ts.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/lib/domain/recovery-records.ts` around lines 34 - 56, Extract the
duplicated guards into a single shared module (e.g., type-guards) and export
isConflictSource, isConflictResolution, isMemoryConflictCandidate, plus the
helper guards used inside them (isMemoryScope and isStringArray); then remove
the duplicated implementations from recovery-records.ts and memory-sync-audit.ts
and import the exported functions from the new module, ensuring all callers
still use the same function names (isConflictSource, isConflictResolution,
isMemoryConflictCandidate) so type narrowing behavior is preserved.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@docs/release-checklist.md`:
- Line 28: The release checklist currently contradicts itself by treating the
`pnpm exec tsx src/cli.ts audit` (the "audit" step) as both optional and
required; pick one policy (either make the audit step mandatory or clearly
optional) and make the wording consistent in both places that mention the audit
and the phrase "record its findings" so they match; update the two checklist
entries that reference the `audit` command and the instruction to record
findings to use identical language reflecting the chosen policy (e.g., "Run and
record the results of `pnpm exec tsx src/cli.ts audit`" if required, or
"Optionally run `pnpm exec tsx src/cli.ts audit`; record findings if run" if
optional).

In `@src/lib/extractor/session-continuity-evidence.ts`:
- Around line 276-319: collectWarningHints applies authoritative "clear and
replace" semantics via applySignal but processes all agentMessages then all
userMessages, which breaks interleaved ordering; change collectWarningHints to
operate on a single ordered transcript instead of separate role buckets by
merging agentMessages and userMessages into one sequence preserving original
chronological order (e.g., by attaching an index/timestamp to each message or by
accepting a pre-interleaved array) and then iterate that combined array, calling
isPromptLikeContinuityMessage and extractDirectiveChoice for each entry and
applying applySignal in that real order so authoritative clears respect actual
message order.

---

Outside diff comments:
In `@src/lib/commands/session.ts`:
- Around line 100-124: The grouping signature passed to
buildCompactHistoryPreview uses raw fields (e.g., entry.confidence,
entry.warnings) causing legacy entries to not coalesce; update the getSignature
logic inside buildCompactHistoryPreview to use the normalized diagnostics
instead (call toSessionContinuityDiagnostics(entry) or apply the same
normalization helpers) and replace raw entry.confidence/entry.warnings (and
other diagnostic-derived fields like fallbackReason, codexExitCode if produced
by normalization) with the normalized values so the signature matches what
preview rows render; keep existing keys (rolloutPath, sourceSessionId, scope,
trigger via normalizeSessionContinuityAuditTrigger, writeMode via
normalizeSessionContinuityWriteMode, preferredPath, actualPath, evidenceCounts,
writtenPaths) but source diagnostic values from the normalized diagnostics
object.

In `@src/lib/domain/sync-service.ts`:
- Around line 123-141: Currently code sets status = "no-op" whenever
applied.length === 0, which hides cases where reviewExtractedMemoryOperations
suppressed all candidates; change the status calculation after calling
reviewExtractedMemoryOperations/applyOperations so that if applied.length === 0
AND reviewedOperations.suppressedOperationCount > 0 (or there are non-empty
reviewedOperations.conflicts if you want to surface conflict-only cases) you set
status to "all-suppressed" instead of "no-op" before calling
buildMemorySyncAuditEntry, ensuring callers see a distinct all-suppressed audit
status.

---

Nitpick comments:
In `@package.json`:
- Line 23: The CI script "ci" currently runs targeted smoke suites
("test:docs-contract", "test:reviewer-smoke", "test:cli-smoke") and then runs
the full "test" script again causing duplication; remove the redundant targeted
runs from the "ci" pipeline or modify the "test" script to exclude those
specific tests so smoke suites run only once. Locate the "ci" npm script entry
in package.json and either delete the duplicate targeted scripts
("test:docs-contract", "test:reviewer-smoke", "test:cli-smoke") from the chain
or update "test" to accept an env/flag that skips those suites, ensuring the
smoke suite scripts remain disjoint from the top-level "test" invocation.

In `@src/lib/commands/memory.ts`:
- Around line 63-65: The compaction key currently embeds entry.conflicts as-is
which makes grouping order-sensitive; before folding conflicts into the key
(where suppressedOperationCount, scopesTouched, conflicts are combined),
normalize the conflicts array by sorting it deterministically (e.g., by a stable
field such as conflict.id or conflict.path, then secondary fields as needed)
and/or by deep-sorting objects' keys, then use that sorted structure when
JSON.stringify-ing the key; update the place that builds the compaction key
(referencing the conflicts property used alongside suppressedOperationCount and
scopesTouched) to sort/normalize conflicts first so equivalent conflict sets
always produce the same grouping signature.

In `@src/lib/commands/wrapper.ts`:
- Around line 85-87: Extract the exists+map logic into a shared helper (e.g., a
function like selectExistingPaths or pickExistingPaths) and replace the inline
array handling in wrapper.ts where [projectLocation,
localLocation].filter(...).map(...) is used; the helper should accept an array
of location-like objects (with exists and path properties) and return an array
of path strings for those with exists=true so both wrapper and session command
code paths can call the same utility and avoid divergence.

In `@src/lib/domain/recovery-records.ts`:
- Around line 34-56: Extract the duplicated guards into a single shared module
(e.g., type-guards) and export isConflictSource, isConflictResolution,
isMemoryConflictCandidate, plus the helper guards used inside them
(isMemoryScope and isStringArray); then remove the duplicated implementations
from recovery-records.ts and memory-sync-audit.ts and import the exported
functions from the new module, ensuring all callers still use the same function
names (isConflictSource, isConflictResolution, isMemoryConflictCandidate) so
type narrowing behavior is preserved.

In `@src/lib/extractor/contradiction-review.ts`:
- Around line 273-289: The filter is calling extractDirectiveChoices for every
existing entry on each review which is wasteful; precompute and cache each
existing entry's directive choices once (e.g., build a Map keyed by entry.id or
by the entry object) by invoking extractDirectiveChoices for the synthetic
upsert operation for each entry, then replace the inline extractDirectiveChoices
call inside the conflictingExisting computation with a lookup to the cache so
choicesConflict(review.choices, cachedChoices) is used instead.

In `@test/docs-contract.test.ts`:
- Around line 19-23: The assertions in test/docs-contract.test.ts currently
assert exact prose fragments (the expect(...) calls checking "reviewer warning
prose", "cam memory", "cam session status", "confidence", "deterministic
scrub"), which is brittle; change those asserts to check for stable contract
anchors instead (e.g., section headings, field or command names, or backticked
identifiers) using case-insensitive substring or regex matches so copyedits
don't break CI—update the expect calls that read readme/readmeEn (also the
similar checks around 51-54) to look for headings like a "Reviewer" or "Review"
section header, explicit field names such as "confidence" as a standalone word
boundary match (e.g. /\bconfidence\b/i) or backticked API/command names, rather
than exact editorial phrases.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 7ed7756e-998f-41c7-a684-e81ca6e955cc

📥 Commits

Reviewing files that changed from the base of the PR and between 24c35ef and 0f112a4.

📒 Files selected for processing (32)
  • .github/workflows/ci.yml
  • CONTRIBUTING.md
  • README.en.md
  • README.md
  • docs/architecture.en.md
  • docs/architecture.md
  • docs/release-checklist.md
  • docs/session-continuity.md
  • package.json
  • src/lib/commands/memory.ts
  • src/lib/commands/session.ts
  • src/lib/commands/wrapper.ts
  • src/lib/domain/memory-sync-audit.ts
  • src/lib/domain/recovery-records.ts
  • src/lib/domain/session-continuity-diagnostics.ts
  • src/lib/domain/sync-service.ts
  • src/lib/extractor/contradiction-review.ts
  • src/lib/extractor/session-continuity-evidence.ts
  • src/lib/extractor/session-continuity-prompt.ts
  • src/lib/extractor/session-continuity-summarizer.ts
  • src/lib/types.ts
  • test/docs-contract.test.ts
  • test/extractor.test.ts
  • test/fixtures/rollouts/hedged-preference-conflict.jsonl
  • test/fixtures/rollouts/mixed-language-reviewer-noise.jsonl
  • test/fixtures/rollouts/within-rollout-preference-conflict.jsonl
  • test/memory-command.test.ts
  • test/memory-sync-audit.test.ts
  • test/recovery-records.test.ts
  • test/session-command.test.ts
  • test/session-continuity.test.ts
  • test/sync-service.test.ts

- Run `cam session load --json` and confirm older JSON consumers still receive the existing core fields.
- Run `cam session status --json` and confirm the latest explicit audit drill-down matches the newest audit-log entry when present.
- Run `pnpm pack:check`
- Run `pnpm exec tsx src/cli.ts audit` if you want the repository privacy scan; keep it as a manual release-time check instead of a CI gate.
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Make the audit step either required or optional, not both.

Line 28 frames pnpm exec tsx src/cli.ts audit as an optional release-time check, while Line 55 requires recording its findings. That contradiction makes the checklist easy to apply inconsistently. Pick one policy and use the same wording in both sections.

Also applies to: 55-55

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/release-checklist.md` at line 28, The release checklist currently
contradicts itself by treating the `pnpm exec tsx src/cli.ts audit` (the "audit"
step) as both optional and required; pick one policy (either make the audit step
mandatory or clearly optional) and make the wording consistent in both places
that mention the audit and the phrase "record its findings" so they match;
update the two checklist entries that reference the `audit` command and the
instruction to record findings to use identical language reflecting the chosen
policy (e.g., "Run and record the results of `pnpm exec tsx src/cli.ts audit`"
if required, or "Optionally run `pnpm exec tsx src/cli.ts audit`; record
findings if run" if optional).

Comment on lines +276 to +319
function collectWarningHints(agentMessages: string[], userMessages: string[]): string[] {
const warnings = new Set<string>();
const directiveValues = new Map<string, Set<string>>();
let promptNoiseDetected = false;

const applySignal = (signal: DirectiveSignal) => {
const values = directiveValues.get(signal.key) ?? new Set<string>();
if (signal.authoritative) {
values.clear();
}
values.add(signal.value);
directiveValues.set(signal.key, values);
};

for (const message of agentMessages) {
if (isPromptLikeContinuityMessage(message)) {
promptNoiseDetected = true;
continue;
}
const choices = [
extractDirectiveChoice(message, packageManagerValues, "package-manager"),
extractDirectiveChoice(message, repoSearchValues, "repo-search")
].filter((choice): choice is DirectiveSignal => Boolean(choice));

for (const choice of choices) {
applySignal(choice);
}
}

for (const message of userMessages) {
if (isPromptLikeContinuityMessage(message)) {
promptNoiseDetected = true;
continue;
}

const choices = [
extractDirectiveChoice(message, packageManagerValues, "package-manager"),
extractDirectiveChoice(message, repoSearchValues, "repo-search")
].filter((choice): choice is DirectiveSignal => Boolean(choice));

for (const choice of choices) {
applySignal(choice);
}
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Preserve transcript order before applying authoritative directive clears.

applySignal() implements a “latest authoritative choice wins” rule, but this function only sees role-separated arrays and then processes all agentMessages before all userMessages. src/lib/domain/rollout.ts::parseRolloutEvidence() does not preserve a single interleaved message stream, so warning/confidence outcomes here can flip based on speaker bucket rather than actual rollout order. This needs an ordered transcript input before using authoritative replacement semantics.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/lib/extractor/session-continuity-evidence.ts` around lines 276 - 319,
collectWarningHints applies authoritative "clear and replace" semantics via
applySignal but processes all agentMessages then all userMessages, which breaks
interleaved ordering; change collectWarningHints to operate on a single ordered
transcript instead of separate role buckets by merging agentMessages and
userMessages into one sequence preserving original chronological order (e.g., by
attaching an index/timestamp to each message or by accepting a pre-interleaved
array) and then iterate that combined array, calling
isPromptLikeContinuityMessage and extractDirectiveChoice for each entry and
applying applySignal in that real order so authoritative clears respect actual
message order.

@Boulea7 Boulea7 merged commit 6a35f9a into main Mar 20, 2026
5 checks passed
@coderabbitai coderabbitai bot mentioned this pull request Mar 23, 2026
7 tasks
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.

1 participant