Repository navigation
Files Changed: full session-lineage mutation ledger #972
Description
Files Changed: full session-lineage mutation ledger
Important
Problem - Files Changed currently infers a current net diff from fragmented tool metadata, snapshots, and external-file fallbacks. It omits valid session mutations, loses create-delete and restore history, cannot safely combine descendant work, and can misrepresent opaque or concurrent writes. The surface cannot honestly account for every declared session-visible resource mutation.
Approach - Reclassify this parent epic around a server-owned, append-only mutation ledger scoped to a root session and explicit spawned descendants. Every registered local mutator receives a session-bound mutation context, records intent and one receipt per affected resource, and commits a verified outcome. Compact receipt metadata lives with session data; bounded private evidence lives separately. Files Changed remains one file-first surface with expandable receipt history, final state, origin, and uncertainty.
Approaches considered - A global filesystem observer was rejected because it cannot safely attribute concurrent local activity, creates a broad-surveillance boundary, and does not cover remote tools. Incrementally extending today's tool metadata was rejected because every new mutation path can bypass it. The ledger makes provenance an enforceable contract rather than a best-effort UI convention.
Scope - in: registered session-visible business resources changed by local tools, user actions through Amicode, explicit spawned descendants, authorized external files, internal state records, artifacts, directories, outcomes, conflicts, redaction, retention, capability negotiation, and end-to-end coverage. out: ledger and retention infrastructure, unrelated editor or process writes, covert machine-wide monitoring, and claims about opaque remote side effects beyond explicit uncertainty.
Assumptions - The engine can issue short-lived session-bound capabilities. Only explicit task and session-spawn edges create ledger lineage; a fork begins a separate root. Pre-existing sessions remain legacy, while an already-open session may record a clearly labelled post-upgrade epoch. The researcher authorizes private retention of approved external baselines for a bounded session lifetime.
Acceptance Criteria
- A versioned mutator registry classifies every supported route as ledger-backed, opaque-with-unknown-receipt, or explicitly out of scope; raw storage APIs are unavailable to unregistered session-visible writers.
- Ledger and retention infrastructure are excluded from the registry and cannot recursively create session-visible receipts.
- Protocol discovery selects a legacy view only when the server does not advertise a supported ledger capability. Mutation-context validation denies missing, expired, revoked, wrong-panel, wrong-session, or invalid replayed contexts before filesystem access; an exact idempotent retry returns the already-recorded operation-group result only. Context capabilities, canonical paths, hashes, baselines, and redaction decisions never enter browser state, transcripts, logs, telemetry, shares, or errors.
- Each requested action creates one operation group and each declared resource receives one receipt with lineage, origin, logical target, canonical target, operation, outcome, and timestamp.
- Immutable receipts keep requested operation, declared resources, origin, and execution outcome separate from append-only or derived current assessments. Assessments independently represent observation confidence, net state, evidence availability, and expiry; denied, failed, aborted, partial, opaque, conflicted, and unavailable cases are unambiguous.
- A parent Files Changed view aggregates only explicit spawned descendants while preserving each originating session and origin type; forks remain separate roots and archived or deleted children retain only the receipt projection allowed by root retention policy.
- Created then deleted, edited then restored, moved, trashed, restored, and recursive-directory resources remain visible with a truthful final state or an explicit bounded-manifest outcome.
- Implicit parent directories are declared before creation. Recursive operations over the configured resource or evidence budget fail closed or return an explicit partial receipt; they never silently omit descendants.
- Compact receipt metadata remains in the session database with a per-root record and metadata budget, paged queries, retention, and compaction policy. A known local mutation that would exceed the active root budget is rejected before storage work; it never becomes untracked. Text patches and external preimages use a separate host-local evidence store with per-resource and per-session budgets; oversized or binary resources retain metadata, hashes, and an owning-artifact link rather than copied content.
- External and symlink-resolved targets are authorized, deduplicated, and revalidated by physical target at write time. A known local mutator on a provider without safe no-follow or descriptor-based traversal is denied before mutation; only explicitly opaque remote actions may report an unverified outcome.
- Sidebar, Preview, Files Changed editing, plugin bookkeeping, and runner-originated records are session-linked and labelled with their user, system, or agent origin.
- An opaque-context variant without declared local endpoints emits an operation-level Unknown Mutation Receipt for shell, MCP, and custom-tool actions that cannot produce declared resource receipts. The receipt has no resource identity, renders in a dedicated uncertainty group, contributes to coverage counts, carries no patch evidence, and cannot authorize a known local mutation route.
- Conflicting or unavailable observations preserve the attempted operation but never attribute later bytes from another writer.
- Host-only evidence is distinct from display-safe receipt projections. A schema-owned field exposure matrix specifies allow, redact, or deny for every receipt and evidence field across Files Changed, export, sharing, telemetry, logs, and error responses.
- Ledger rows are owned by the root at creation and retain a compact origin-session projection after child archival or deletion. Child-local evidence follows root retention; deleting the root deletes its ledger and evidence according to retention policy.
- Older engines and pre-existing sessions cannot present the full-provenance state; they expose an explicitly labelled legacy or post-upgrade-partial view. Unsupported protocol discovery resolves deterministically to legacy without probing mutation routes. In-flight legacy reservations resolve as legacy rather than being silently adopted.
- The capability handshake, mixed-version matrix, migration boundary, rollback behavior, fork-release ordering, verified binary pin, and extension release are tested before default enablement.
- An adversarial end-to-end matrix covers all mutation origins, descendant lineage, path classes, outcomes, privacy boundaries, conflicts, and capability fallback before default enablement.
Testing Decisions
- Add a schema-owned mutator registry and field exposure matrix; test that every route is ledger-backed, opaque, or explicitly out of scope and that raw storage adapters reject unregistered session-visible writers.
- Cover operation-group publication separately from non-atomic filesystem execution, including ordered resource locking or compare-and-swap, partial recursive work, formatting side effects, cross-device moves, Trash, restore, and implicit parent creation.
- Cover root and descendant lineage aggregation, task-spawn versus fork semantics, archival, deletion, post-upgrade epochs, source-session links, user-originated operations, and unrelated-session isolation.
- Cover canonicalization through relative paths, symlinks, hard-link identity where available, case and Unicode normalization, nonexistent leaves, ancestor replacement races, unsupported providers, external authorization, redaction, expiry, and sharing exclusion.
- Cover receipt, evidence, and serializer storage budgets; assert pagination, root-capacity denial before mutation, retention, compaction, and that ledger infrastructure cannot emit recursive receipts or host-only metadata cross display, export, telemetry, sharing, or error boundaries.
- Cover failed, denied, aborted, partial, conflicted, unavailable, and opaque outcomes without allowing a false clean state.
- Run a development-host end-to-end matrix against workspace files, non-Git siblings, external repositories, internal records, generated artifacts, concurrent writers, mixed engine and extension versions, and a legacy session.
- Verify the unified surface is keyboard-operable, status is not color-only, and light and dark themes retain the established visual contract.
Key Decisions
- One surface, not two - Files Changed remains file-first. A row persists for every touched canonical resource and expands into chronological receipt history; a final net diff is a derived property, not a reason to erase history.
- Session lineage is explicit - Only registered task and session-spawn edges aggregate into a root. A fork creates a new root; child archival and deletion preserve only the receipt projection permitted by root retention policy. Each receipt retains the originating session so concurrent work is never anonymous.
- Mutation context is the gate - Known local mutators must prepare, commit, or abort through an authenticated short-lived server capability bound to the initiating panel and session, exact operation type, canonical endpoints, expiry, and replay semantics. Unsupported protocol discovery selects legacy display only; an invalid mutation context denies before filesystem access, while an exact idempotent retry returns the prior operation result. Direct uncontextualized writes are blocked rather than silently becoming untracked. An opaque context has no local endpoints and can report uncertainty only.
- Observation is not attribution - Watchers and snapshots can revalidate known receipts but cannot create ownership. Unowned local activity appears only as a conflict or unavailable state when it affects an existing receipt.
- Opaque actions are honest gaps - Shell, MCP, and custom actions either emit declared receipts or a visible unknown-side-effect receipt. The UI never implies that an unknown action made no changes.
- Receipt facts and current assessments are separate - An immutable receipt records intent and execution outcome. Current net state, conflict, evidence availability, and evidence expiry are derived or append-only assessments, so revalidation never rewrites history.
- Evidence is bounded and separate - Receipt metadata lives in the session database under a root quota and paged retention policy. External baselines and patches live in a private bounded evidence store, are redacted where needed, excluded from normal sharing, and removed at expiry or root deletion. Capacity exhaustion blocks known local work before it becomes untracked. Ledger infrastructure is not a ledger resource.
- Capability-gated delivery - The engine protocol ships before clients advertise full provenance. The app, extension, plugin, and vendored binary negotiate one supported protocol generation; existing sessions remain legacy or explicitly partial after upgrade.
- This issue is the parent epic - Files Changed: trace one server-assessed non-Git external edit #973 through Files Changed: session-bind Sidebar external file mutations #976 remain v1 foundation slices. New ledger slices migrate their contracts deliberately rather than silently changing their guarantees.
Data Contracts
| Contract | Owner | Invariant |
|---|---|---|
| Lineage edge | Session service | Only registered spawn edges aggregate. Forks are separate roots; retention defines child archival and deletion projections. |
| Mutator registry | Gate | Every supported route is ledger-backed, opaque, or explicitly out of scope; raw session-visible storage adapters require a registry route. |
| Mutation context | Server | Authenticated, panel and session-bound, origin-bound, operation-bound, endpoint-bound, expiring, revocable, and single-use or idempotent as declared; invalid contexts deny before filesystem access. |
| Operation group | Ledger | Atomically publishes declared receipts even when physical work is partial or non-atomic. |
| Mutation receipt | Session database | Immutable compact intent and execution facts, owned by the root and retaining an origin-session projection after child deletion. |
| Unknown mutation receipt | Session database | Operation-level uncertainty record with no resource identity, no patch evidence, a source session and origin, and explicit coverage-count semantics. |
| Mutation assessment | Ledger | Derived or append-only observation, net, and evidence state with revision and expiry semantics. |
| Resource evidence | Host-local evidence store | Bounded private patches or preimages referenced by receipts; display-safe projections expose only permitted evidence. |
| Field exposure matrix | Schema | Classifies every receipt and evidence field for UI, export, sharing, telemetry, logs, and errors. |
| Capability response | Server API | States protocol version, full or legacy support, migration boundary, detail guarantees, and deterministic unsupported-protocol fallback. |
Constraints & Invariants
- The surface is a session-lineage record, not global filesystem status.
- Ledger storage, evidence retention, telemetry, and compaction are operational infrastructure, not session-visible resources.
- Root quotas and retention bound both receipt metadata and evidence. A capacity limit blocks known local session-visible writes before filesystem mutation.
- No unrelated process, editor, or session write is attributed merely by timing or path overlap.
- Canonical physical targets, safe traversal where supported, and write-time revalidation control authorization, deduplication, conflict detection, and watching.
- A receipt distinguishes intent, execution outcome, observation confidence, net state, and evidence state.
- Missing evidence, conflict, and opaque side effects are visible uncertainty states, never silently dropped rows.
- Sensitive external or internal content and metadata never cross normal session sharing, export, telemetry, error, or retention boundaries without an explicit serializer policy.
- The OpenCode fork remains the application source of truth. Delivery is fork release, verified vendored-binary pin, extension release, then overlay synchronization proof.
Prior Art
- Files Changed: full session-lineage mutation ledger #972's existing external-baseline and assessed-diff design
- Files Changed: session-bind Sidebar external file mutations #976's session-bound Sidebar reservation design
- fix(app): trust server session diff for Files Changed panel #720's server-authoritative zero-net behavior
- Slice 1: Contamination fix — derive agent-file filter from tool filediff only #742 and Slice 2: External-change reactivity — watcher ungating + client event handler #743's session-scoped ownership filtering
- Files Changed: show cross-project edits (merge server + tool-metadata diffs) #778's cross-project metadata merge and its attribution limits
Source
Reclassifies #972 from an external-current-diff parent into the full session-lineage provenance epic. #973 through #976 remain v1 foundation slices. Paired durable decision: ADR 0017, Session-lineage mutation ledger for Files Changed.
Notes
Delivery is multi-slice: lineage persistence and lifecycle, mutator registry enforcement, capability and resource identity, compact receipt storage and bounded evidence, protected serializers, directory and Trash semantics, legacy migration, paged APIs, mutator adoption, unified UI, capability-gated release, and the adversarial end-to-end matrix. Existing external-diff and Sidebar-reservation work remains useful as early slices, but no partial slice may claim full provenance.
Activity
[-]Files Changed: authoritative current diffs for all external files[/-][+]Files Changed: full session-lineage mutation ledger[/+]Merge pull request #1119 from harmoniqs/jj/sync-overlay-972