Skip to content

Provenance & Context Drift

Project context is useful only while its claims fit the project. A document might say that the package uses one module system, the tests run through one command, or authentication begins at one entry point. Code changes can invalidate those statements even though the document still looks complete.

Provenance records where a claim came from. Drift detection identifies recorded source bytes that no longer match. Neither one proves that the claim was correct in the first place.

HTML-knowledge repositories record this per claim instead: each source-observed record cites its files, each document keeps the commit it was last checked against, and knowledge.py stale lists exactly the records whose cited files changed since then. That check is advisory and never blocks a commit. The rest of this page describes the Markdown-format provenance records.

This is not a promise that every sentence has a provenance record. The mechanism covers the entries actually recorded under .codearbiter/.provenance/, and routine drift alarms consider only entries whose drift_trigger is explicitly true.

A derived document and its provenance record have different jobs. The document teaches the project’s conventions. The JSON record identifies the document, its creation date, whether it came from an interview, and the backing entries. An entry can name a repository-relative path, its recorded Git content hash, claims and their source lines, and whether changes should trigger a drift alarm.

For example, a claim in tech-stack.md might be backed by package.json. If the package changes from module syntax to commonjs, the old hash differs and the old statement may now be wrong. If only whitespace changes, the hash also differs, but the statement might still hold. The hash tells you to inspect the relationship; it does not choose the interpretation.

Follow the evidence into a read

A pointer is a selection, not a verdict

Actual Python helper output over fixed local fixtures, not an installed-host run, approval, or validation of your repository.

The fixture uses real Git content hashes and the repository's read/provenance helpers. Choose an already-recorded case; these controls do not run a tool.

Several governing sources match

Fixture read: src/auth/session.py

1. Gather matching pointers
  1. security-controlsSecurity policy governs this file: use CTX-SECURITY-CONTROLS records in HTML context, or security-controls.md in Markdown context.
  2. decisionsADR-0042-session-boundary (Session boundary) governs this file — do not contradict it; route changes via /ca:reconcile or /ca:adr.
  3. specsspec session governs this file — implement to its acceptance criteria.
  4. Provenance · standardsstandards.md notes (lines 1-2): Session checks are explicit.
2. Assemble the bounded result

99 estimated tokens · 1 provenance hash call

Security policy governs this file: use CTX-SECURITY-CONTROLS records in HTML context, or security-controls.md in Markdown context.
ADR-0042-session-boundary (Session boundary) governs this file — do not contradict it; route changes via /ca:reconcile or /ca:adr.
spec session governs this file — implement to its acceptance criteria.
standards.md notes (lines 1-2): Session checks are explicit.

Repeat in the same session: no additional context. The repeated call performs 0 provenance hash calls.

What this establishes: All four tiers contribute. Priority controls assembly order, not a first-match-only decision.

What you do next: Read the named documents. The pointer is not their complete contents or an approval.

The recorded source still matches

Fixture read: package.json

1. Gather matching pointers
  1. Provenance · standardstech-stack.md notes (lines 1): The package declares module syntax.
2. Assemble the bounded result

17 estimated tokens · 1 provenance hash call

tech-stack.md notes (lines 1): The package declares module syntax.

Repeat in the same session: no additional context. The repeated call performs 0 provenance hash calls.

What this establishes: The recorded package bytes match their current hash, so the provenance claim can contribute a pointer.

What you do next: Inspect the actual claim as well as the hash. Matching bytes do not establish that an earlier interpretation was correct.

The source changed

Fixture read: package.json

1. Gather matching pointers

No matching pointer survives the selection and freshness checks in this fixture.

2. Assemble the bounded result

0 estimated tokens · 1 provenance hash call

Observed output: empty string. The helper did not supply additional context.

Repeat in the same session: no additional context. The repeated call performs 1 provenance hash call.

What this establishes: The package changed from module to commonjs. The old claim is suppressed, and drift detection identifies the dependent document.

What you do next: Review the changed behavior and re-scout or defer. Replacing a hash alone would conceal the now-false claim.

Separate drift output: tech-stack → package.json → changed. The mutation was confined to a disposable fixture.

No mapping exists

Fixture read: src/ui/view.py

1. Gather matching pointers

No matching pointer survives the selection and freshness checks in this fixture.

2. Assemble the bounded result

0 estimated tokens · 0 provenance hash calls

Observed output: empty string. The helper did not supply additional context.

Repeat in the same session: no additional context. The repeated call performs 0 provenance hash calls.

What this establishes: No candidate covers this file. The helper emits nothing and makes no provenance hash call.

What you do next: Do not treat silence as a safety verdict. Confirm activation, mapping, and relevant requirements before changing sensitive code.

The 150-token limit uses ceil(character_count / 4), not the host model's tokenizer. See HTML advice diagnostics for the typed path; these legacy fixture reads do not certify it.

Inspect the captured read-injection source blob · Inspect inputs and recorded output · Understand freshness

Capture identity and method

Historical teaching baseline: aebee1bb753d29e34030ee22c98c9eb8fabb1752. Current helper bytes are bound separately by Git blob identities and SHA-256 hashes in the capture; a squash merge does not change those content identities. The checked-in capture is generated and rechecked by site/scripts/capture-context-examples.py. It runs the helpers in a temporary repository. It does not invoke a host, approve a specification, or change a real project. Source hashes and fixture inputs are retained in site/src/data/context-examples.json.

The comparison above is actual helper output over a disposable example, not a claim that an installed agent examined your repository. Switch between fresh and changed source to see why a stale provenance pointer disappears rather than being injected as current knowledge.

Inspect the static relationship map
Changed recorded source can suppress stale read advice. Commit-time re-scout and manual per-document disposition remain distinct paths.
The full reading explanation remains in this page. This map describes source-defined relationships, not a captured host run.

At SessionStart, the shared provenance helper loads usable records and hashes the existing, confined source paths marked as drift triggers. A mismatch is reported as changed; a genuinely absent path can be reported as missing. It produces a concise advisory drift line, not a blocking decision or a rewritten document.

Read that line as an invitation to investigate. No line can also mean no recorded sources, no eligible trigger, an unreadable or malformed record, or a hashing failure. The startup helper intentionally degrades to silence on those failures. A blank startup result is therefore not a certificate that all repository knowledge is current. One malformed record does not discard the remaining valid records, but the ordinary startup path does not promise a per-record warning.

Greenfield context may be interview-derived before source exists. An empty entry set does not make an interview answer false; it means this source-hash mechanism cannot yet validate it. Do not invent code citations merely to remove that distinction. See Plan a new project and Understand existing code.

Re-scout when meaning may have changed. The incremental scout reads the changed paths and checks the dependent claims. If a claim no longer holds, review the proposed document change before the new baseline is recorded. This is a scoped update, not a reason to rescan the entire repository or rewrite its architecture.

Re-baseline when you can justify keeping the claim. This updates matching source hashes without changing the claim text. A cosmetic change can justify it after inspection. A missing source is not silently replaced: the helper preserves its old hash when there is no current one. Do not use re-baselining as a warning-dismissal button.

Defer when the work should remain open. The manual workflow leaves the document and mismatch alone so the next session can surface them. Record an owner and reopen condition when the work needs to survive this conversation, but do not pretend the defer operation creates a dedicated persistent debt record automatically. A defer is not a fresh result.

The choice belongs to the relationship between this document and these sources. One document can be safely re-baselined while another needs new claims. A global reset of all hashes would erase that distinction.

The commit path and manual audit are different

Section titled “The commit path and manual audit are different”

During commit-gate Phase 5.5, before the commit lands, maintenance selects claims whose recorded sources intersect staged paths. Legacy v1 records use heal_worklist; managed v2 pairs use v2_heal_worklist with a current bounded source and document snapshot. An empty legacy worklist does not establish v2 freshness. Reinspect only selected claims. Unknown evidence defers that document’s automatic update without blocking independent commit work.

If claims still hold, a managed pair uses native preview/apply for its selected owned fields, retaining document bytes and updating inspected source evidence. The writer rechecks source and target identities and writes the pair together. Legacy v1 re-baselining remains separate; it never writes v2 records. Stage the resulting paths explicitly with the required secrets re-scan. Changed claims enter normal diff review. Auto-heal does not silently rewrite conclusions or require another approval for maintenance already authorized by the commit request.

The manual context-check route is for drift outside that particular commit path: a merge you did not author, an external edit, or a recorded source you are not staging now. Its compatibility entry remains available as /ca:context-check, $ca-context-check, or /ca-context-check, depending on the host. The catalog also advertises the canonical status-drift route; inspect the installed command reference rather than inventing a new command.

For an audit-only request, the owner reports first and waits for a selected disposition. A direct request to refresh named documents or full context already authorizes that selection; it does not need repeated per-document permission. Inspection may be direct or use optional scoped agents. The writer previews selected changes and rechecks the source and target identities before applying the document/provenance pair; supported missing/v1 provenance can be explicitly adopted while its prior bytes are retained. Unowned content and initialization state stay intact. It does not stage or commit. Any revised provenance or document rides a later user-authorized commit. See the context-check reference and commit gate.

Inspect a real repository without changing its history

Section titled “Inspect a real repository without changing its history”

Start by confirming the checkout, branch and current work. Read the affected document and its provenance JSON. Check that the named path exists inside this repository, the record has the expected shape, and the reported change concerns that path. Ask for the source diff and the claim it could invalidate. A number of commits since a change is not part of the hash-comparison report unless separately established from Git history.

Before accepting a re-baseline, explain why the statement remains true. Before accepting new text, inspect the supporting source and preserve unresolved questions. After either action, repeat the audit and inspect the actual file diff. A re-scouted document should have the intended claim and source relationship; a deferred document should still have its unresolved mismatch.

Do not delete markers, clear provenance directories or edit protected authority to manufacture a clean result. If a helper is missing or a record cannot be interpreted, preserve its path and the observed diagnostic, then use Troubleshooting. Redact secrets and private source content before sharing a diagnostic.

Freshness is one layer, not the whole authority model

Section titled “Freshness is one layer, not the whole authority model”

A source hash, an ADR acceptance record, a typed artifact’s normative identity, and a fresh test result answer different questions. Updating provenance does not approve a feature, verify an ADR, or accept a task. Conversely, a passing feature test does not refresh an unrelated project claim.

Just-in-time context explains how a fresh claim can contribute a pointer at a read. Artifacts explains which records govern a change, and Auditability explains how to examine their evidence later.