Repository navigation
feat(context-engine): D3 P3 — two-phase write-once consequence writer (human --apply) - #48
Merged
Merged
Conversation
… (human --apply) New context_engine/attribution_apply.py: dispatches the P2 attribution plan into cold-item frontmatter via dataclasses.replace + cold.write_item (atomic whole-file rewrites), strictly inside the existing reviewed --apply interlock. Phase A writes acted_on_commit + the planned tests_green VERBATIM (a planned "unknown" stays "unknown"; nonstandard values degrade to "unknown", never True), with write-once and cold-tier re-checked at write time against fresh disk state (a stale plan skips, with recorded reasons). Phase B flips previously-attributed "unknown" items only on a literal True/False from the fail-closed CI seam — monotone: "unknown"->True|False at most once, True/False never touched, no re-flip. The apply path never raises; every per-item failure is recorded and the batch continues. Phase-B identity carries no argv secret and reads no env: injectable providers default to `gh auth token` and `git remote get-url origin` (https/ssh/scp parsed to owner/repo); any failure => None => "unknown" => safe-inert. consolidate.plan_consolidation gains an additive attribution_runner (default None keeps every existing caller unchanged) and ConsolidationPlan.attribution; the CLI wires run_attribution so the dry-run renders the attribution plan + PENDING-CI-FLIP worklist for the human reviewer (zero writes, fail-soft — attribution failure never breaks consolidation, incl. scaffolded consumers lacking the attribution modules), and under --apply the writer runs FIRST so gate_promotions sees fresh consequences in the same pass (spec §4.3). No autonomous apply: P4 is an explicit operator decision — no new CLI, no mutation surface outside the human interlock. 33 new tests (tests/test_attribution_apply.py, all seams faked); full suite 498 pass; ruff clean. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
The D3 P3 consequence WRITER: dispatches the P2 attribution plan (#47) into cold-item frontmatter, strictly inside the EXISTING human
--applyinterlock. With this, the D3 learn-loop is functional end-to-end — attribution → consequence write → promotion gate — still human-applied.New
context_engine/attribution_apply.py+ a 4-line-visible integration inconsolidate.py(additive only).Two-phase semantics (spec §3.5, §4.3, §4.4)
Phase A — new attributions. For each planned
(slug, sha, tests_green): the item is re-loaded FRESH from disk and skipped (with a recorded reason) unless it is still cold-tier ANDacted_on_commitis not already a real sha — write-once is re-checked at write time, not just plan time (a stale plan skips:already_attributed,not_cold_tier,item_missing). The write isdataclasses.replace+cold.write_item(atomic whole-file rewrite, the single writer), withtests_greenEXACTLY as planned: a planned"unknown"is written as"unknown", never upgraded; any nonstandard planned value degrades to"unknown", never toTrue.Phase B — CI flip for attributed items. Every cold item on disk with a real
acted_on_commitsha andtests_green == "unknown"(including fresh Phase-A writes — an immediate §3.5 "arrival") gets its CI resolved for THAT sha via an injectable seam (default: the P2/P1 fail-closedci_statuspath). Only a literalTrue/Falseis ever written. Monotone, guarded in code + tests:"unknown" → True|Falseat most once;True/Falseitems never enter the worklist AND are re-checked before the write — neverTrue → anything, neverFalse → anything, never a re-flip, no path defaults toTrue.Never raises: every per-item failure is recorded (
write_failed,flip_failed,ci_unresolved, …) and the batch continues;AppliedResult{applied, flipped, skipped}is fully auditable.Human interlock preserved — no autonomous path
consolidate.py --apply.plan_consolidation/ the CLI without--apply) now additionally computes and RENDERS the attribution plan + thePENDING-CI-FLIPworklist for the human reviewer — zero writes (byte-identical tree, tested), and fail-soft: attribution failure never breaks the existing consolidation output (verified incl. a scaffolded-consumer sim where the attribution modules are absent).--applythe writer runs FIRST, before the cold index loads, sogate_promotionssees the freshly-written consequences in the SAME pass (§4.3) — covered both ways (Phase-ATruepromotes; Phase-B flip promotes).plan_consolidationkeeps its exact behavior/signature for existing callers: one additiveattribution_runner=Noneparameter + one additiveConsolidationPlan.attributionfield.Token via gh-auth seam (no argv/env secrets)
Phase B in the human-run CLI needs a GitHub token + repo identity. No secret on argv (the deliberate P2 CLI choice, preserved) and NO env reads (C13/E1): injectable providers default to
gh auth token(gh is the repo's auth source of truth —ci_statusalready shells to gh) andgit remote get-url originparsed toowner/repo(https/ssh/scp forms). Both are bounded subprocesses; any failure ⇒None⇒ CI resolves"unknown"⇒ Phase B safe-inert. Providers are consulted lazily — a Phase-A-only pass spawns no subprocess. The plan path stays token-less so Phase-A writes match the reviewed dry-run plan verbatim.Tests (33 new, all seams faked; full suite 498 pass, ruff clean)
True,False,"unknown"-stays-"unknown", nonstandard→"unknown"unknown→True,unknown→False; unresolved/nonstandard seam values leave"unknown"TruestaysTrue,FalsestaysFalse, no re-flip across passes — even against a contradicting seamrun_attributiondry-run byte-pure + plan/pending visibility; plan failure degrades without applyplan_consolidation(apply=True)pass (Phase A and Phase B variants); CLI default-runner smokegh auth token/ remote-URL parsing (subprocess seams faked)Custodian pre-push: 0 findings (first pass flagged D11
_loadclone — resolved by importing attribution.py's loader instead of cloning it).🤖 Generated with Claude Code