Skip to content

refactor(tape): establish layered architecture#1996

Merged
zerob13 merged 29 commits into
devfrom
refactor/tape-layering
Jul 18, 2026
Merged

refactor(tape): establish layered architecture#1996
zerob13 merged 29 commits into
devfrom
refactor/tape-layering

Conversation

@yyhhyyyyyy

@yyhhyyyyyy yyhhyyyyyy commented Jul 17, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • Move Tape ownership into src/main/tape/ with domain, ports, application, and SQLite infrastructure layers.
  • Split the former monolithic SessionTape implementation into Fact, Reconciler, Recall, Lineage, View/Replay, and Fork services.
  • Keep SessionTape as a compatibility facade while narrowing consumers to capability-specific ports.
  • Preserve existing database schema, persisted Tape payloads, SessionTapePort, renderer APIs, View policies, and compaction behavior.

Reliability and boundary hardening

  • Make Tape generation reset and deletion atomic across entries, mutation projections, search projections, FTS data, and bootstrap creation.
  • Run pending-input deletion, transcript deletion, and Tape reset in one shared-connection transaction during clearMessages.
  • Recover corrupted FTS derivatives by invalidating and dropping the rebuildable index.
  • Prevent discarded forks from being merged or explicitly reused, even when best-effort cleanup fails.
  • Keep linked-Tape reads explicitly authorized and frozen at the recorded child head.
  • Prune stale pre-v3 and metadata-orphaned search projections during initialization.

Architecture changes

  • Introduce minimal consumer ports for reconciliation, fact writing, raw entry reading, anchor access, ViewManifest access, inspection, and lifecycle administration.
  • Remove production imports of legacy Tape paths and concrete storage adapters.
  • Freeze legacy compatibility modules as explicit deprecated re-exports.
  • Return domain DTOs instead of physical Tape rows from Memory inspection routes.
  • Reuse the composition-owned Tape writer during legacy chat import.
  • Add architecture guards for reverse dependencies, SQLite/Electron imports, legacy paths, raw table access, and Memory route bypasses.

Summary by CodeRabbit

  • New Features

    • Rolled out the structured Tape architecture (facts, search projections, replay/context recall, forks + subagent lineage, and tape lifecycle administration).
    • Updated memory routes to use tape inspection for source spans and manifest listings.
  • Bug Fixes

    • Strengthened idempotency and fail-open behavior for tool-fact persistence and tape backfills.
    • Hardened reset/delete flows with transactional rollback protections and safer projection rebuild behavior.
  • Documentation

    • Expanded Tape/system and Tape Layering documentation (plan, spec, boundaries, and lifecycle semantics).
  • Tests

    • Improved native-tape test discovery and scope validation.

@coderabbitai

coderabbitai Bot commented Jul 17, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 0569628f-335f-488c-8578-cd872115eff7

📥 Commits

Reviewing files that changed from the base of the PR and between 756ec81 and a0470d5.

📒 Files selected for processing (6)
  • scripts/check-memory-test-scope.mjs
  • test/main/app/compositionBoundaries.test.ts
  • test/main/routes/dispatcher.test.ts
  • test/main/scripts/memoryTestScope.test.ts
  • test/main/session/data/tapeReconciler.test.ts
  • test/main/session/data/tapeTestHarness.ts
🚧 Files skipped from review as they are similar to previous changes (5)
  • test/main/scripts/memoryTestScope.test.ts
  • test/main/app/compositionBoundaries.test.ts
  • test/main/session/data/tapeReconciler.test.ts
  • scripts/check-memory-test-scope.mjs
  • test/main/session/data/tapeTestHarness.ts

📝 Walkthrough

Walkthrough

The PR introduces a layered Tape subsystem with domain contracts, capability-scoped ports, application services, SQLite storage and lifecycle adapters, compatibility re-exports, updated runtime composition, memory inspection routing, transactional cleanup, and expanded architecture and native SQLite test coverage.

Changes

Tape layering refactor

Layer / File(s) Summary
Domain and port contracts
src/main/tape/domain/*, src/main/tape/ports/*
Defines Tape entry, fact, replay, effective-view, manifest, storage, application, and capability contracts.
Tape application services
src/main/tape/application/*
Splits fact persistence, reconciliation, recall, lineage, fork, lifecycle, and replay behavior behind a SessionTape facade.
SQLite infrastructure
src/main/tape/infrastructure/sqlite/*
Adds entry storage, search projection/FTS handling, lifecycle deletion, effective queries, and projection fallback behavior.
Compatibility and composition
src/main/session/data/*, src/main/app/*
Converts legacy Tape modules to deprecated re-exports and wires Tape capabilities into transcripts, settings, imports, and transactions.
Runtime and memory integration
src/main/agent/*, src/main/memory/*
Replaces concrete Tape dependencies with narrow reconciliation, writer, reader, and inspection ports.
Validation and tests
test/main/*, scripts/*, test/memory-test-scope.json
Adds boundary checks, lifecycle/lineage/recall/replay coverage, transaction assertions, and native SQLite test-scope discovery.

Estimated code review effort: 5 (Critical) | ~120 minutes

Suggested reviewers: zerob13

Sequence Diagram(s)

sequenceDiagram
  participant DeepChatLoopRunner
  participant TapeToolFactWriter
  participant SessionTape
  participant SQLiteTapeEntries
  DeepChatLoopRunner->>TapeToolFactWriter: appendToolFact(input)
  TapeToolFactWriter->>SessionTape: persist tool fact
  SessionTape->>SQLiteTapeEntries: append idempotent tape entry
  SQLiteTapeEntries-->>SessionTape: entry reference
  SessionTape-->>TapeToolFactWriter: entry reference
  TapeToolFactWriter-->>DeepChatLoopRunner: persistence result
Loading
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.89% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ 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 clearly summarizes the main change: refactoring Tape into a layered architecture.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ 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 refactor/tape-layering

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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 11

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@scripts/check-memory-test-scope.mjs`:
- Around line 9-10: Update the NATIVE_TAPE_TEST pattern to recognize both
.test.ts and .spec.ts suffixes for tape suites and deepchatTapeEntriesTable,
matching the walker’s supported naming conventions while preserving the existing
native-test path constraints.

In `@src/main/tape/application/forkService.ts`:
- Around line 288-294: Update the receipt data construction for the
external-merge event, including the corresponding block noted at the second
occurrence, so metadata cannot overwrite the authoritative forkId,
forkSessionId, or referencedEntryCount fields. Move the metadata spread before
these explicitly assigned receipt fields while preserving the existing metadata
values for all other keys.
- Around line 103-113: Update createFork to also check for an existing merge
receipt using the corresponding merge provenance key for parentSessionId and
forkIdValue. If either a discard or merge receipt exists, reject reuse by
throwing an error before creating the fork, preserving the existing discard
behavior.

In `@src/main/tape/application/lineageService.ts`:
- Around line 390-438: Update linkSubagentTape to validate both
normalized.parentSessionId and normalized.childSessionId inside the transaction
before appendEvent, ensuring the parent exists and the child is a direct
subagent session as required by resolveLinkedTapeSources(). Preserve the
existing unavailable-child error behavior while rejecting invalid parent/child
lineage before persisting the link.

In `@src/main/tape/application/reconcilerService.ts`:
- Around line 32-34: Update the historyRecords construction in the reconciler
flow to shallow-copy the array returned by messageStore.getMessages(sessionId)
before applying the orderSeq sort. Preserve the existing ascending sort behavior
while ensuring the retrieved or cached messages array is not mutated.

In `@src/main/tape/application/viewReplayService.ts`:
- Around line 435-453: The toViewManifestRecord method must reject manifests
whose embedded messageId or requestSeq disagrees with the persisted event
envelope. Validate the normalized manifest against the row’s
source_id/source_seq values before returning a record, and return null for
mismatches while preserving the existing normalization and hash verification
flow for valid rows.

In `@src/main/tape/domain/effectiveSemantics.ts`:
- Around line 45-61: Update the block predicates used to build
pendingInteractionToolIds and determine the final blocks.some result so they
safely handle null or primitive entries from parsed JSON. Use optional property
access for block fields, including nested action/tool_call data as needed, while
preserving the existing matching behavior for valid block objects.

In `@src/main/tape/infrastructure/sqlite/tapeSearchProjectionStore.ts`:
- Around line 794-838: Update the catch path in searchFts to invalidate the FTS
derivative when the SQLite query fails by resetting ftsReady and clearing the
current FTS metadata through the existing state-management mechanism. Preserve
the empty-result fallback behavior so callers continue to fall back to LIKE,
while ensuring the next search retries FTS recovery instead of reusing stale
readiness state.

In `@test/main/app/compositionBoundaries.test.ts`:
- Around line 12-13: Update the assertions in the composition boundary test to
target the LegacyChatImportService constructor call structurally or with a
constructor-specific pattern, rather than matching a raw whitespace-sensitive
substring. Ensure the assertion verifies memoryDatabase and
sessionData.tapeStore are passed within that constructor invocation, and format
the test according to Oxfmt.

In `@test/main/routes/dispatcher.test.ts`:
- Around line 1275-1278: Separate Tape inspection mocking from the SQLite-backed
deepchatTapeEntriesTable in the affected route test setup: create a dedicated
tapeInspection mock implementing getEffectiveMessageSourceSpan and
listMemoryViewManifestsByAgent, and have the relevant dependency container
return it through getTapeInspection. Remove these DTO methods from
deepchatTapeEntriesTable while preserving the existing storage mock behavior
across all referenced test cases.

In `@test/main/session/data/tapeTestHarness.ts`:
- Around line 93-99: Update the idempotent lookup in the tape test harness
around the existing and entries.find logic to run only when provenanceKey is
non-null. Preserve the current session and provenance matching for keyed writes,
while treating idempotent writes without a provenance key as having no existing
entry.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 28becfcc-3a9b-4e9b-a1fb-203e2be7c4f3

📥 Commits

Reviewing files that changed from the base of the PR and between e84428b and 13a8678.

📒 Files selected for processing (87)
  • docs/FLOWS.md
  • docs/architecture/baselines/agent-system-layered-runtime-baseline.json
  • docs/architecture/memory-system.md
  • docs/architecture/session-management.md
  • docs/architecture/tape-layering/plan.md
  • docs/architecture/tape-layering/spec.md
  • docs/architecture/tape-layering/tasks.md
  • docs/architecture/tape-system.md
  • scripts/check-memory-test-scope.mjs
  • scripts/generate-architecture-baseline.mjs
  • src/main/agent/acp/compatibility/adapters.ts
  • src/main/agent/acp/compatibility/dependencies.ts
  • src/main/agent/deepchat/loop/ports.ts
  • src/main/agent/deepchat/memory/memoryRuntimeCoordinator.ts
  • src/main/agent/deepchat/runtime/contextBuilder.ts
  • src/main/agent/deepchat/runtime/deepChatLoopRunner.ts
  • src/main/agent/deepchat/runtime/deepChatRuntimeCoordinator.ts
  • src/main/agent/deepchat/runtime/process.ts
  • src/main/agent/deepchat/runtime/turnCoordinator.ts
  • src/main/agent/deepchat/runtime/types.ts
  • src/main/app/composition.ts
  • src/main/app/startupMigrations/legacyChatImportService.ts
  • src/main/data/schemaCatalog.ts
  • src/main/memory/data/tables/deepchatMemoryIngestionProjection.ts
  • src/main/memory/routes.ts
  • src/main/session/data/database.ts
  • src/main/session/data/index.ts
  • src/main/session/data/settings.ts
  • src/main/session/data/tables/deepchatTapeEffectiveSemantics.ts
  • src/main/session/data/tables/deepchatTapeEntries.ts
  • src/main/session/data/tables/deepchatTapeSearchProjection.ts
  • src/main/session/data/tape.ts
  • src/main/session/data/tapeEffectiveView.ts
  • src/main/session/data/tapeFacts.ts
  • src/main/session/data/tapeViewManifest.ts
  • src/main/session/data/transcript.ts
  • src/main/session/transcriptMutations.ts
  • src/main/tape/application/common.ts
  • src/main/tape/application/contracts.ts
  • src/main/tape/application/factPersistence.ts
  • src/main/tape/application/factService.ts
  • src/main/tape/application/forkService.ts
  • src/main/tape/application/generationLifecycle.ts
  • src/main/tape/application/lineageService.ts
  • src/main/tape/application/recallProjection.ts
  • src/main/tape/application/recallService.ts
  • src/main/tape/application/reconcilerService.ts
  • src/main/tape/application/sessionTape.ts
  • src/main/tape/application/viewReplayService.ts
  • src/main/tape/domain/effectiveSemantics.ts
  • src/main/tape/domain/effectiveView.ts
  • src/main/tape/domain/entry.ts
  • src/main/tape/domain/facts.ts
  • src/main/tape/domain/replay.ts
  • src/main/tape/domain/viewManifest.ts
  • src/main/tape/infrastructure/sqlite/tapeEntryStore.ts
  • src/main/tape/infrastructure/sqlite/tapeLifecycleAdapter.ts
  • src/main/tape/infrastructure/sqlite/tapeSearchProjectionStore.ts
  • src/main/tape/ports/application.ts
  • src/main/tape/ports/capabilities.ts
  • src/main/tape/ports/storage.ts
  • test/main/agent/acp/compatibility/adapters.test.ts
  • test/main/agent/deepchat/memory/memoryRuntimeCoordinator.test.ts
  • test/main/agent/deepchat/runtime/deepChatRuntimeCoordinator.test.ts
  • test/main/agent/deepchat/runtime/process.test.ts
  • test/main/app/compositionBoundaries.test.ts
  • test/main/app/startupMigrations/legacyChatImportService.test.ts
  • test/main/evals/nativeAgent/harness.ts
  • test/main/memory/deepchatMemoryIngestionProjection.test.ts
  • test/main/routes/dispatcher.test.ts
  • test/main/scripts/memoryTestScope.test.ts
  • test/main/session/data/settings.test.ts
  • test/main/session/data/tables/deepchatTapeEntriesTable.test.ts
  • test/main/session/data/tape.test.ts
  • test/main/session/data/tapeFork.test.ts
  • test/main/session/data/tapeLifecycle.test.ts
  • test/main/session/data/tapeLineage.test.ts
  • test/main/session/data/tapeRecall.test.ts
  • test/main/session/data/tapeReconciler.test.ts
  • test/main/session/data/tapeTestHarness.ts
  • test/main/session/data/tapeViewReplay.test.ts
  • test/main/session/data/transcript.test.ts
  • test/main/session/runtimeIntegration.test.ts
  • test/main/session/transcriptMutations.test.ts
  • test/main/session/usageStatsService.test.ts
  • test/main/tape/layerBoundaries.test.ts
  • test/memory-test-scope.json

Comment thread scripts/check-memory-test-scope.mjs Outdated
Comment thread src/main/tape/application/forkService.ts
Comment thread src/main/tape/application/forkService.ts
Comment thread src/main/tape/application/lineageService.ts
Comment thread src/main/tape/application/reconcilerService.ts Outdated
Comment thread src/main/tape/domain/effectiveSemantics.ts
Comment thread src/main/tape/infrastructure/sqlite/tapeSearchProjectionStore.ts
Comment thread test/main/app/compositionBoundaries.test.ts Outdated
Comment thread test/main/routes/dispatcher.test.ts Outdated
Comment thread test/main/session/data/tapeTestHarness.ts Outdated
@zerob13
zerob13 merged commit 3faf784 into dev Jul 18, 2026
4 checks passed
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.

2 participants