Skip to content

feat(provenance): context-drift detection, code map, commit-gate auto-heal#145

Merged
SUaDtL merged 2 commits into
mainfrom
feat/context-drift-provenance
Jun 27, 2026
Merged

feat(provenance): context-drift detection, code map, commit-gate auto-heal#145
SUaDtL merged 2 commits into
mainfrom
feat/context-drift-provenance

Conversation

@SUaDtL

@SUaDtL SUaDtL commented Jun 27, 2026

Copy link
Copy Markdown
Collaborator

Summary

The .codearbiter/ derived docs (tech-stack, coding-standards, security-controls, the scout-derived CONTEXT) are built once from scout evidence, then that evidence is thrown away. Nothing links a doc to the source it came from, and nothing notices when that source moves. Over a long-lived codebase the docs drift silently, and wrong context is worse than none, because every skill pre-flight trusts them.

This captures the discarded scout evidence as per-doc provenance (source paths, git hash-object content hashes, and file:line -> claim), detects drift on the sources that matter, ships a coarse code map for navigation, and keeps both fresh passively by riding commit-gate. Maintenance never becomes a command the user runs.

What changed

  • New plugins/ca/hooks/_provenancelib.py (stdlib only, injectable hasher): the provenance store, git hash-object --stdin-paths hashing, classify_source drift-trigger split, compute_drift, startup_drift_line, changed_scope, rebaseline, heal_worklist, lint_code_map, write_stub. Every failure path degrades to silence, with a bounded subprocess timeout.
  • SessionStart emits one drift line, and only when drift is above zero. The code map is read on demand in tdd/feature/fix pre-flight, never injected at SessionStart.
  • commit-gate gains a conditional Phase 5.5 auto-heal: a staged drift-trigger source whose hash diverged triggers an incremental re-scout of just that file. If the claim still holds, the hash re-baselines silently and rides the work commit. If the claim changed, the edit is proposed in the existing Phase 6 diff review. Any file staged after the Phase 4 secret scan is re-scanned.
  • context-creation and decompose write provenance (real entries, or greenfield stubs) plus the code map. /ca:context-check is the optional manual audit: report stale docs, then re-scout, re-baseline, or defer.

Why these decisions (conflict-hierarchy)

  • Hashing uses git hash-object, not raw byte sha256 or mtime, so .gitattributes EOL normalization means an LF/CRLF flip is not false drift. This sits at level 2 (correctness and data integrity): a trustworthy drift signal beats a faster but noisy one.
  • Only low-churn, high-signal sources fire drift (the drift_trigger split). General architecture source is stored for the map and the audit trail but never alarms. Same level-2 rationale: signal quality over raw coverage.
  • Auto-heal rides commit-gate rather than a separate command or a daemon, following ADR-0008 (board transitions land with the work). This favors reviewability (level 3) over a background mechanism that cannot be kept fresh passively.

Test plan

  • python .github/scripts/test_provenancelib.py (104 unit tests: hashing, drift, the degrade paths, real-git EOL normalization).
  • python .github/scripts/test_provenance_wiring.py (5 structural: commit-gate Phase 5.5, context-creation, decompose, read-on-demand, /ca:context-check).
  • python plugins/ca/hooks/tests/test_session_start.py (the SessionStart drift-line wrapper).
  • python -m unittest discover -s plugins/ca/hooks/tests (full hooks suite, 546 tests).
  • python .github/scripts/check-plugin-refs.py (catalog, routing, and reference-map entries resolve).
  • python .github/scripts/test_board_sync.py (no-renumber guard on the commit-gate phases).
  • Behavioral proof, run fresh against real git: an unchanged source stays silent, and a changed package.json produces exactly one drift line.

Reviews

  • security-reviewer: pass, no CRITICAL or HIGH. One accepted-residual LOW (reject a newline or .. in a provenance entry path before hashing), tracked as v2.harden.0001.
  • coverage-auditor: pass, all 13 public functions tested, above the stage-2 threshold. One informational gap noted: the load_provenance_dir filename-stem fallback lacks a dedicated test.

Follow-ups (on the board)

  • v2.feature.0001: file-scoped just-in-time context injection, the committed next feature, which consumes this provenance map.
  • v2.docs.0004: reconcile the scout-dispatch doc inconsistency.
  • v2.harden.0001: the path-hardening residual above.

Ref: ADR-0008 (auto-heal rides the work commit). Spec: .codearbiter/specs/context-drift-provenance.md.

https://claude.ai/code/session_012jvNq6cL8CVkLdseGB3Mz5

SUaDtL added 2 commits June 26, 2026 21:49
The .codearbiter/ derived docs (tech-stack, coding-standards,
security-controls, the scout-derived CONTEXT) are synthesized once from
scout evidence, then the evidence is discarded — nothing links a doc to
its source or notices when that source moves. At scale the docs silently
drift, and wrong context is worse than none because every skill's
pre-flight trusts them.

Capture the discarded scout evidence as per-doc provenance
(.codearbiter/.provenance/<doc>.json: source paths + git-hash-object
content hashes + file:line -> claim), then:
  - detect drift on low-churn/high-signal sources only — the drift_trigger
    split (config/manifest/schema/security-entry fire; general source is
    stored but never alarms) is what keeps the signal trustworthy;
  - ship a coarse, capped .codearbiter/code-map.md for navigation;
  - keep both fresh passively by riding commit-gate (new Phase 5.5
    auto-heal, the ADR-0008 board-done-flip pattern) — a staged
    drift_trigger source that diverged triggers an incremental re-scout of
    just that file: claim holds -> silent re-baseline, claim changed ->
    edit proposed in the existing diff review. Maintenance is never a
    command the user runs.

Hashing is git hash-object --stdin-paths (one subprocess, injectable
runner) so .gitattributes EOL normalization means a CRLF flip is not
false drift. Read-on-demand: the code map is read in tdd/feature/fix
pre-flight, never at SessionStart; the sole passive SessionStart cost is
one drift line, emitted only when drift > 0. /ca:context-check is the
optional manual audit (report -> re-scout / re-baseline / defer).

CHANGELOG: Passive context-drift detection (one SessionStart line when a
derived doc's tracked source goes stale), a coarse .codearbiter/code-map.md
for task orientation, commit-gate auto-heal that re-baselines or proposes
doc updates with the work commit, and /ca:context-check for manual audits.

Ref: spec .codearbiter/specs/context-drift-provenance.md; ADR-0008 (auto-heal rides the work commit)
Claude-Session: https://claude.ai/code/session_012jvNq6cL8CVkLdseGB3Mz5
The context-check command and skill landed in #145 but the README surface
metadata was not regenerated, failing the badge-consistency CI gate (and its
three Hooks test matrices). Sync the mechanical counts to the repo: commands
37 to 38, skills 20 to 21, the prose catalog count, the tree-view counts, and
add the missing full-catalog table row for /ca:context-check.

Ref: #145
Claude-Session: https://claude.ai/code/session_015hUAbnXMxf9yDbgJ8XTeDo
@SUaDtL
SUaDtL merged commit 4c0d82c into main Jun 27, 2026
22 checks passed
@SUaDtL
SUaDtL deleted the feat/context-drift-provenance branch June 27, 2026 02:26
SUaDtL added a commit that referenced this pull request Jun 27, 2026
…-heal (#145)

* feat(provenance): drift detection, code map, commit-gate auto-heal

The .codearbiter/ derived docs (tech-stack, coding-standards,
security-controls, the scout-derived CONTEXT) are synthesized once from
scout evidence, then the evidence is discarded — nothing links a doc to
its source or notices when that source moves. At scale the docs silently
drift, and wrong context is worse than none because every skill's
pre-flight trusts them.

Capture the discarded scout evidence as per-doc provenance
(.codearbiter/.provenance/<doc>.json: source paths + git-hash-object
content hashes + file:line -> claim), then:
  - detect drift on low-churn/high-signal sources only — the drift_trigger
    split (config/manifest/schema/security-entry fire; general source is
    stored but never alarms) is what keeps the signal trustworthy;
  - ship a coarse, capped .codearbiter/code-map.md for navigation;
  - keep both fresh passively by riding commit-gate (new Phase 5.5
    auto-heal, the ADR-0008 board-done-flip pattern) — a staged
    drift_trigger source that diverged triggers an incremental re-scout of
    just that file: claim holds -> silent re-baseline, claim changed ->
    edit proposed in the existing diff review. Maintenance is never a
    command the user runs.

Hashing is git hash-object --stdin-paths (one subprocess, injectable
runner) so .gitattributes EOL normalization means a CRLF flip is not
false drift. Read-on-demand: the code map is read in tdd/feature/fix
pre-flight, never at SessionStart; the sole passive SessionStart cost is
one drift line, emitted only when drift > 0. /ca:context-check is the
optional manual audit (report -> re-scout / re-baseline / defer).

CHANGELOG: Passive context-drift detection (one SessionStart line when a
derived doc's tracked source goes stale), a coarse .codearbiter/code-map.md
for task orientation, commit-gate auto-heal that re-baselines or proposes
doc updates with the work commit, and /ca:context-check for manual audits.

Ref: spec .codearbiter/specs/context-drift-provenance.md; ADR-0008 (auto-heal rides the work commit)
Claude-Session: https://claude.ai/code/session_012jvNq6cL8CVkLdseGB3Mz5

* docs(readme): sync count badges + add context-check catalog row

The context-check command and skill landed in #145 but the README surface
metadata was not regenerated, failing the badge-consistency CI gate (and its
three Hooks test matrices). Sync the mechanical counts to the repo: commands
37 to 38, skills 20 to 21, the prose catalog count, the tree-view counts, and
add the missing full-catalog table row for /ca:context-check.

Ref: #145
Claude-Session: https://claude.ai/code/session_015hUAbnXMxf9yDbgJ8XTeDo

---------

Co-authored-by: SUaDtL <SUaDtL@users.noreply.github.com>
SUaDtL added a commit that referenced this pull request Jun 27, 2026
* docs(changelog): roll the 2.6.0 release notes

Reconcile the [2.6.0] CHANGELOG section for the release: broaden the intro
beyond the farm work, add context-drift provenance (#145) and file-scoped
context injection (#146) under Added, note the MIT to AGPLv3 relicense (#147,
ADR-0009) under Changed, and add a Fixed section for #143, #139, and #138.
Dated 2026-06-27.

Also flips v2.feature.0001 to done now that file-scoped context injection has
shipped and merged; the flip rides this release commit per ADR-0008.

No version bump: plugin.json is already 2.6.0 and the ca-scoped commit window is
unchanged. The relicense and docs commits touch no plugins/ca/ payload.

Claude-Session: https://claude.ai/code/session_01QaLw7nTrRbHwygFar2R6zu

* docs(license): reserve the dual-licensing right without offering it yet

Soften the README "Commercial licensing" wording. The prior text implied
proprietary licenses were actively on offer; the intent is narrower: the owner
retains sole ownership and reserves the right to dual-license, but is not
offering commercial licenses at this time. Inquiries may still be sent through
GitHub and will be considered if and when a commercial path is established.

The legal substance is unchanged. AGPLv3 plus sole copyright already secures the
right; this only corrects the public statement so it does not overstate an
active commercial offering. ADR-0009, the CLA, and the CHANGELOG already use the
reserves-the-right framing, so no other file changes.

Claude-Session: https://claude.ai/code/session_01QaLw7nTrRbHwygFar2R6zu

---------

Co-authored-by: SUaDtL <SUaDtL@users.noreply.github.com>
SUaDtL added a commit that referenced this pull request Jun 28, 2026
All three prioritized recommendations in this 2026-06-26 deep dive shipped
in v2.6.0 — drift/staleness + scout provenance via #145, file-scoped JIT
injection via #146 — so the report's to-do framing was stale.

- Rename README.md -> verdict-and-roadmap.md: the dated folder already names
  the topic, so "README" carried no information about what the file is.
- Add a status banner pointing at the shipping PRs (#145/#146), including
  that #146 resolved the plugin-hook additionalContext risk the report flagged.
- Drop the two now-consumed brainstorming kickoff prompts; they seeded those
  PRs and only referenced each other and the report.

Retained as the durable decision record: the "do not add vectors/daemons/
transcript-mining" verdict and the Anthropic-docs constraint table.

Ref: #145, #146
Claude-Session: https://claude.ai/code/session_01LuWyr8xxjBcJ43GTSK7XGB
SUaDtL added a commit that referenced this pull request Jun 28, 2026
* docs: project-context deep-dive findings + roadmap

Verdict on .codearbiter context handling vs four external memory/context
archetypes (claims verified against source + Anthropic docs). Sound design;
one real gap (drift/staleness). Prioritized: drift layer, scout provenance
index, file-scoped JIT injection. Explicit do-not list (vectors/daemons/
transcript-parsing/MITM proxy).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017ELqqfPQUTXWJEDSwQDFe6

* docs: add implementation-grounding appendix + brainstorming kickoff prompts

Harden the project-context deep-dive report into a self-contained handoff:
codeArbiter internals map (creation/storage/consumption/maintenance/pruning,
hook surface, injection mechanics + #16538 caveat) so a fresh session needs
no re-discovery. Add two parallel /ca:brainstorming kickoff prompts:
drift+provenance (the flaw-fix) and file-scoped JIT injection (enhancement).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017ELqqfPQUTXWJEDSwQDFe6

* docs(report): rename project-context deep-dive, mark recs 1-3 shipped

All three prioritized recommendations in this 2026-06-26 deep dive shipped
in v2.6.0 — drift/staleness + scout provenance via #145, file-scoped JIT
injection via #146 — so the report's to-do framing was stale.

- Rename README.md -> verdict-and-roadmap.md: the dated folder already names
  the topic, so "README" carried no information about what the file is.
- Add a status banner pointing at the shipping PRs (#145/#146), including
  that #146 resolved the plugin-hook additionalContext risk the report flagged.
- Drop the two now-consumed brainstorming kickoff prompts; they seeded those
  PRs and only referenced each other and the report.

Retained as the durable decision record: the "do not add vectors/daemons/
transcript-mining" verdict and the Anthropic-docs constraint table.

Ref: #145, #146
Claude-Session: https://claude.ai/code/session_01LuWyr8xxjBcJ43GTSK7XGB

---------

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: SUaDtL <SUaDtL@users.noreply.github.com>
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