v0.12.0 integration 24b3: the build loop lands and records, drain lanes, gitleaks opt-in, terminal check, record-lint edge and ADR-id rules, follow-ups - #761
Merged
Conversation
itd-4, itd-6, itd-50, itd-65 and itd-66 cite spec ids of the retired predecessor store without the specs charter's qualifier, and each id is at or below spc-70, so it resolves in the live store to a spec on another subject. Each site was read against the live spec it collides with: - itd-6: spc-2, spc-4 and spc-5 are the earlier Python lineage's RP MCP specs (live: lifecycle automation, the transcript clock, folder classification); lines that already said "earlier Python lineage" in words now also carry the parenthetical. - itd-50: spc-52 is the audit-loop spec (live: dangling supersedes). - itd-65 and itd-66: spc-64 is the gitleaks and pii.py secret/PII gate (live: the read-block eval) and spc-27 the oracle (live: the surface-coverage registry). - itd-4: spc-20 to spc-23 are the ledger specs of the superseded record system (live: banlist, fresh install, stale-binary warning, tier placement). Two shipped acceptance criteria gain the qualifier (itd-4's drift criterion and itd-65's fail-closed criterion). Each names a precedent or an owner, not what is promised, so the qualifier restores the authored reading and changes no promise: a wording clarification, with no Audit Notes line. Refs: iss-2609290448510918 Assisted-by: Claude:claude-opus-5-5
…ecs stand itd-36's Implementing specs section said the frontmatter spec_id records spc-38 as the primary delivering spec; the frontmatter records spc-2609211905174684, and live spc-38 and spc-39 are itd-136's record explorer and itd-137's relationship chart. itd-4's said its spc-20 to spc-23 do not exist in the native spec store; the live store holds all four as other specs. Both sections now name the live spec_id, say the native store reuses each number, and qualify every predecessor id, the shape itd-4's own spc-6 catch-up paragraph already had. Neither section is an acceptance criterion. The finding is captured in this change and resolved in the next. Refs: iss-2609300025372991, iss-2609290448510918 Assisted-by: Claude:claude-opus-5-5
…e specs The fix landed in 542737b: both Implementing specs sections name the live spec_id and qualify every predecessor-store id. Resolves: iss-2609300025372991 Assisted-by: Claude:claude-opus-5-5
…intents cite itd-17, itd-20, itd-27, itd-29, itd-47 and itd-49 sit in superseded/ and describe pre-rebuild work in the predecessor store's terms: the flow-next checkpoints, the Python oracle and Codex leg, the Ralph quota work and the grill skill's first spec. Every spc-N they cite at or below spc-70 was read against the live spec it collides with, and none names the live one (live spc-3 is the lifeboat coverage experiment, spc-6 issue capture, spc-12 the disembark grounding, spc-41 the banner), so each carries the specs charter's qualifier. Where one id repeats within one line of prose, the first mention carries it. Left as written: itd-27's reclassification_history reason (a dated reason keeps the words it was written with) and itd-47's Implementing specs section, whose false spec_id claim is corrected in its own change. Refs: iss-2609290448510918 Assisted-by: Claude:claude-opus-5-5
Superseded itd-47's Implementing specs section said its frontmatter spec_id records spc-27 as the primary delivering spec. The frontmatter holds spec_id: null, and spc-27 and spc-32 are predecessor-store ids that the live store reuses for the surface-coverage registry and abcd update. The section now says the ids are history, that no native spec delivers the intent (adr-22 supersedes it), and qualifies each id. This is the same defect as iss-2609300025372991 in a third intent. The finding is captured in this change and resolved in the next. Refs: iss-2609300032219282, iss-2609300025372991, iss-2609290448510918 Assisted-by: Claude:claude-opus-5-5
… not hold The fix landed in 8f5b726: the Implementing specs section of superseded itd-47 keeps its predecessor-store ids as qualified history and says no native spec delivers it. Resolves: iss-2609300032219282 Assisted-by: Claude:claude-opus-5-5
iss-2609290448510918 gains a dated progress section and a remedy line. The census over the four intent folders counts 186 sites; 94 were the predecessor store's and carry the qualifier, 72 cite live specs and 15 are data. The five sites in itd-82 and itd-130 were read but not edited, because other branches carry those intents, so the record stays open until they are confirmed at the merged tip. Refs: iss-2609290448510918 Assisted-by: Claude:claude-opus-5-5
Both are used only inside the changelog package, so they leave the exported surface and the reach-audit baseline. DeriveNext stays baselined: launch/semver.go cites it by its qualified name, and launch is being edited elsewhere. Refs: iss-2609252211487887 Assisted-by: Claude:claude-opus-5-5
glossary.RenderIndex and RenderLayout are reached only by the package's own README anti-drift tests; grounds.ParseToken and identity.EffectiveCommitter only by their own packages. All four leave the exported surface and the reach-audit baseline; the fence-writer reason in mdrecord follows the rename. glossary.Scan stays baselined (site cites it by qualified name, and site is being edited elsewhere), as does identity.LoadPin (the ahoy tests call it across packages). Refs: iss-2609252211487887 Assisted-by: Claude:claude-opus-5-5
Render (now renderMapping, the table the brief's anti-drift test pins), Tiers (now allTiers), VerifyManifest and RecordManifestSHA256 are reached only from inside the lifeboat package. They leave the exported surface and the reach-audit baseline. ManifestSHA256 stays baselined: a cli test calls it across packages. Refs: iss-2609252211487887 Assisted-by: Claude:claude-opus-5-5
cite.NewHTTPChecker (now newShippedHTTPChecker, beside the existing newHTTPChecker it wraps), cite.ParseReceipt and machineload.ParseLoadavgSysctl are reached only from inside their own packages. They leave the exported surface and the reach-audit baseline. Refs: iss-2609252211487887 Assisted-by: Claude:claude-opus-5-5
BuildCitation, CountSourceTokens, CoverageIndexPath, DetectLicence, NormaliseSourceText, QueryPages, RenderCitedMatches, RenderNoMatches, ResolveDistilledPages, SourceContentHash and ValidateDistilledPage are reached only from inside the memory package, and none is named by writer.go. They leave the exported surface and the reach-audit baseline. The ten names writer.go calls (Dir, IsMemoryPageName, LoadRegistry, ParsePageFilename, RenderContradictions, RenderIndex, SerializeRegistry, SourceClasses, SourceHashes, SourcesIndexPath), MergeIngest (writer.go names it in a comment) and writer.go's own two stay baselined: that file is reserved to another lane. Refs: iss-2609252211487887 Assisted-by: Claude:claude-opus-5-5
Only the external mode tests read the question marker through QuestionOpen; no production path calls it. It becomes QuestionOpenForTest, the audit's convention for a test seam, and leaves the reach-audit baseline. SetAt stays baselined: cli tests call it across packages. Refs: iss-2609252211487887 Assisted-by: Claude:claude-opus-5-5
Admits, AssemblingPositions, DefinitionPath, DeriveCandidateRun, EncodeBundle, EncodeManifest, ExclusionsFor, Kinds (now allKinds), LoadDefinitions, ManifestHash, PresetFor, PresetWindow, Render (now renderCharter, the charter table), Scans (now allScans) and WideningRuns are reached only from inside the reading package, its tests included. They leave the exported surface and the reach-audit baseline; no rendered output changes, so the include-table digest holds. AssemblerVersion, DecodeManifest and LoadDefinition stay baselined: cli tests call them across packages. Refs: iss-2609252211487887 Assisted-by: Claude:claude-opus-5-5
ParseColor, ContrastRGB, Contrast, FormatRatio, Render (now renderRow) and Validate (now validateSettings) are reached only from inside the statusline package. They leave the exported surface and the reach-audit baseline. LoadFrom stays baselined: an ahoy test calls it across packages. Refs: iss-2609252211487887 Assisted-by: Claude:claude-opus-5-5
Pin (now summaryPin) and Read (now readEntries) are reached only from inside the reviews package; the board reaches them through Staleness. They leave the exported surface and the reach-audit baseline, and the reviews-charter scripts' comments that cite them by path follow the rename. Refs: iss-2609252211487887 Assisted-by: Claude:claude-opus-5-5
…nctions readingitem.LocateDisposition and LocateSurprise, scribe.DecodeManifest and Exclusions, source.Load (now loadCorpus), and spec.RenderSteps and SortByNumber are reached only from inside their own packages. They leave the exported surface and the reach-audit baseline. scribe.AllowList stays baselined (a lint test calls it across packages), as does spec.Validate (spec/store.go calls it and lint cites it by qualified name). Refs: iss-2609252211487887 Assisted-by: Claude:claude-opus-5-5
The record stays open. Its progress section names the 55 names this lane paid (54 unexported, 1 renamed to a declared test seam, none deleted), the 28 names left in its packages and why, and the one candidate for a later wiring lane; the deferral reason carries the new count of 140. Refs: iss-2609252211487887 Assisted-by: Claude:claude-opus-5-5
…ss exec Found while consolidating the flock sites: a re-exec test whose WithFileLock holder starts a child and is killed finds the lock still held for its whole budget while the child lives. Refs: iss-2609300109005165 Refs: iss-129 Assisted-by: Claude:claude-opus-5-5
openLockFd opened the lock file with a raw syscall.Open and no O_CLOEXEC, so every child a holder started inherited the descriptor. flock holds until every descriptor on the open file description closes, so a child that outlived its parent kept the lock: the next writer waited out its whole budget and got contention from a process that no longer existed. The new re-exec tests take the lock in a child process: another process is excluded for its budget and then granted the lock, and a holder killed with or without a still-running grandchild frees it. The grandchild case failed before this change (contention after 2s) and passes after it. Refs: iss-2609300109005165 Assisted-by: Claude:claude-opus-5-5
Three record stores (decide, intent, spec) lock their own directory descriptor so no lock artefact sits in the committed tree, and each ran a hand-rolled flock loop to do it, because WithFileLock takes a lock file and cannot lock a directory. WithDirLock is that primitive beside it, on the same contract: the shared acquireFlock poll, ErrLockContention past the caller's budget naming it, fn's error unwrapped. The directory is opened O_NOFOLLOW|O_DIRECTORY|O_CLOEXEC and never created: a symlink or a non-directory is ErrLockPathUnsafe (told apart by Lstat, since the errno differs between kernels), and an absent directory is the open's own not-exist error, which spec's store-must-exist mode depends on. The re-exec tests now run both primitives: exclusion between two processes, release when the holder dies (with and without a grandchild), and the bounded wait with its error. Refs: iss-129 Assisted-by: Claude:claude-opus-5-5
The ADR store's mint lock ran its own flock loop on the store directory.
It now takes fsutil.WithDirLock on the same directory, so an older binary
flocking that directory by hand and this one still exclude each other.
The contention refusal keeps its words ("decide: could not acquire mint
lock within <budget>") and fn's error passes through unchanged; the wait
polls on fsutil's backoff (5ms doubling to 100ms) instead of a flat 10ms,
inside the same 5s budget.
A new test holds the store with a raw flock, as an older binary does, and
pins the refusal text and the grant after release; it passed on the old
loop before the move and passes after it.
Refs: iss-129
Assisted-by: Claude:claude-opus-5-5
The spec store's lock ran its own flock loop on specs/. It now takes fsutil.WithDirLock on the same directory, so an older binary flocking specs/ by hand and this one still exclude each other. An absent store in storeMustExist mode is still errStoreAbsent (the open's ENOENT, which the primitive returns unwrapped), the busy refusal is still ErrStoreLockBusy "within <budget>", and fn's error passes through unchanged. The wait polls on fsutil's backoff instead of a flat 10ms, inside the same budget. A new test holds specs/ with a raw flock, as an older binary does, and pins the refusal text and the grant after release; it passed on the old loop before the move and passes after it. Refs: iss-129 Assisted-by: Claude:claude-opus-5-5
The intent store's mint lock ran its own flock loop on intents/. It now takes fsutil.WithDirLock on the same directory, so an older binary flocking intents/ by hand and this one still exclude each other. The busy refusal is still errIntentLockBusy "within <budget>" and fn's error passes through unchanged. The busy seam the lock tests observe a blocked writer through (onIntentMintLockBusy) is kept without a seam in fsutil: the lock takes one attempt that does not wait, fires the seam on its refusal, then waits the whole budget. The seam fires once per acquisition rather than once per poll; its only user closes a channel once. The wait polls on fsutil's backoff rather than a flat 10ms, and the pair acquisition's rest note says so: 2 x fsutil.LockPollCeiling is now the bound for every waiter on all three record-store locks, not only the ledger's. A new test holds intents/ with a raw flock, as an older binary does, and pins the refusal text and the grant after release; it passed on the old loop before the move and passes after it. Refs: iss-129 Assisted-by: Claude:claude-opus-5-5
The memory store's lock opened .abcd/memory/.lock and flocked it by hand,
non-blocking. It now takes fsutil.WithFileLock on the same path with no
wait, so an older binary flocking that file by hand and this one still
exclude each other, and a held lock still fails closed at once as a bare
*StoreLockHeldError. The path pre-check keeps its words; a descriptor the
primitive refuses (a symlink or non-regular file judged on the fd) maps to
the same *UnsafeStorePathError, and fn's error passes through unchanged.
Two race-only branches change shape: a lock file unlinked between the open
and the lock was refused ("zero links") and is now reopened by the
primitive's inode revalidation, and the fd-level type refusal reads as the
path pre-check does.
lockModeIsRegular goes with the hand-rolled check; its unit test becomes a
behavioural one (a FIFO at the lock path is refused), and fsutil gains the
same pin on the descriptor check that now carries iss-2608261133210491's
S_IFMT mask. A new test holds the lock file with a raw flock, as an older
binary does; it passed on the old code before the move and passes after.
Refs: iss-129
Refs: iss-2608261133210491
Assisted-by: Claude:claude-opus-5-5
The per-repo records lock opened records/.lock and flocked it blocking, with no timeout, handing back a release func. It now takes fsutil.WithFileLock on the same path, so an older binary flocking that file by hand and this one still exclude each other, and Capture and Migrate run their locked work in a closure (captureLocked, migrateLocked, moved unchanged). Behaviour change: the wait is bounded. A capture or migration behind a holder that never lets go used to hang, and with it the session-end hook that runs a capture; past repoLockTimeout (2 minutes, since the holder redacts a whole transcript of up to 64 MiB under the lock) it now fails with fsutil.ErrLockContention, "history: acquire lock <path>: ...", and writes nothing. A lock path the primitive refuses (a symlink, or not a regular file on the descriptor) keeps its *StorePathError and words. TestCaptureGivesUpOnAHeldRecordsLockWithinItsBudget holds the lock with a raw flock and watched Capture still waiting after 10s against a 300ms budget before the change; after it, Capture gives up within the budget and captures once the lock is released. Refs: iss-129 Assisted-by: Claude:claude-opus-5-5
With the five hand-rolled flock sites moved onto fsutil.WithFileLock and fsutil.WithDirLock, a test parses every non-test Go file in the module and fails on any Flock or FcntlFlock selector outside internal/fsutil, naming each file:line, so a sixth loop cannot appear. Test files stay free to flock directly: that is how they stand in for another process or an older binary holding the lock. Before the moves it listed nine lines across the five sites (decide, history, intent, memory, spec); it passes now. Refs: iss-129 Assisted-by: Claude:claude-opus-5-5
Resolves: iss-2609300109005165 Assisted-by: Claude:claude-opus-5-5
…rimitives Impact fix rather than internal: history's records lock used to wait with no end and now gives up after repoLockTimeout (2 minutes) with fsutil.ErrLockContention; every other site keeps its refusal, its budget and its lock path. Resolves: iss-129 Assisted-by: Claude:claude-opus-5-5
Assisted-by: Claude:claude-opus-5-5
Assisted-by: Claude:claude-opus-5-5
Lifts the skip integ24b2 left on TestStartBlockedRowRefusesADecisionIdTwoFilesClaim (follow-up ai1). With adrIdUnique landed, recordid.LookupOne refuses an id two decision files claim with *recordid.AmbiguousIDError, so the start check carries that refusal out instead of settling the edge on whichever copy sorts first. The test asserts the typed refusal naming adr-37 and both files, and that no settled row comes back. Assisted-by: Claude:claude-opus-5-5
Follow-up ta1 (review-ttyAdr, review-adrIdUnique). reclassify's resolveSuccessor listed the decision store root itself and wrote into the first file whose name carried the id, so an ADR id two files claim was settled first-wins on the write path while every reader refuses it. It now resolves the id through recordid.LookupOne, which refuses an ambiguous id naming each claimant; nothing is written. TestReclassifySupersededByAnADRIdTwoFilesClaimRefuses was watched fail (the reclassify succeeded) before the change. Assisted-by: Claude:claude-opus-5-5
Assisted-by: Claude:claude-opus-5-5
Semantic conflict (le1): cfSettled on main changed followBlocker to (repoRoot, corpus, id) (blockerEnd, error), which lintEdges' intent.SupersessionChainOf called with the old shape, so the build broke. SupersessionChainOf now takes (repoRoot string, links []ChainLink, id string) and returns (chain, endID, endBucket, problem string, err error), calling followBlocker(repoRoot, corpus, id); lint.SetSupersessionChain, stale_edge's call (which propagates err) and the test stub follow it. A chain that ends at an accepted decision (CF1) or a discipline (CF2) is settled, so stale_edge says 'is settled by adr-N (accepted)/itd-N (disciplines): drop the edge' instead of inviting a repoint; TestStaleEdgeSaysASettledChainIsSettled was watched fail on a scratch copy with the old wording. Assisted-by: Claude:claude-opus-5-5
Follow-up rd1. Draft itd-22's blocked_by itd-2 and draft itd-33's builds_on itd-2 named in-session subagent dispatch, superseded by itd-2609201916056194, which does not carry that dispatch contract; the dispatch is standing practice the conventions router states. Read under ruling CF2 of 2026-09-30 (decision logged by orchestrator abcd-b3), both edges are settled and dropped, each with a linkage note under the record's Audit Notes. record-lint's stale_edge rule now reports nothing; the three edge_cycle warnings remain. Assisted-by: Claude:claude-opus-5-5
Assisted-by: Claude:claude-opus-5-5
Conflict: internal/reachaudit/testdata/core-unreached.txt. Kept both sides' deletions (main's three: guard.Defaults, intent.WithMintLock, oracle.BundledDenylist; the branch's 55); neither side added a name. 137 names remain and TestEveryExportedCoreFunctionIsReachedOrBaselined passes. Assisted-by: Claude:claude-opus-5-5
…ap ids Follow-up cr1 (review-citeReach). The qualifier sweep labelled itd-29's two predecessor spec ids '(predecessor store)', but the record itself says they are speculative substrate from the legacy roadmap and were never in a store; the three citations now say 'legacy roadmap'. Assisted-by: Claude:claude-opus-5-5
Assisted-by: Claude:claude-opus-5-5
Assisted-by: Claude:claude-opus-5-5
Follow-up rp1 (review-rootPin). supersededRoot's hardening, an executable path the lookup cannot read says nothing and walks nothing from the working directory, had only the reviewer's scratch probe. TestVersionSaysNothingWhenTheExecutableIsUnknown commits it: with the working directory inside a differently named plugin root, an erroring lookup yields no note, whether it returns no path or a relative one beside its error. The relative case was watched fail on a scratch copy with executablePath's error check removed; the empty case resolves to '.' and walks nothing either way, so it pins rather than discriminates. Assisted-by: Claude:claude-opus-5-5
Carries fidelityOnce. Assisted-by: Claude:claude-opus-5-5
Conflict: internal/surface/cli/history.go, two new functions at one spot; kept both, gitleaksAug's scanGapLines and loopLanding's captureTranscriptSource. The capture verb calls the extracted helper and still renders the scan gap. Assisted-by: Claude:claude-opus-5-5
Conflicts: - internal/core/decide/decide.go: main (9804500) and the branch (675519d) fixed the same stated-ADR delimiter search with different helpers; main's renderKeys/renderCloseAndTitle shape is kept in all four hunks, and nothing else names the branch's renderHead. - internal/core/implement/loop/land.go: kept loopLanding's records commit (hooks on, the implementer's model named, never Assisted-by: None) and the branch's issue-lane description of what landed. Semantic conflicts: - loop.go StatusPeers (main, CC1) called the old peersCheck(r, session, snap); the branch generalised it to (id, bucket, session, snap), so it now passes r.IntentID and r.Bucket. - issue_test.go: the issue lane's receipt reported a placeholder model loopLanding's trailer rule refuses; it now reports claude-test-5, and the test asserts the records commit names it. Assisted-by: Claude:claude-opus-5-5
…now needs Semantic conflict between gitleaksAug (978a00c) and remedyRequired on main: the three augmenter capture tests filed an issue with no remedy, which main's capture refuses, so each failed before reaching the scan it tests. The shared fixture now names a remedy. The merge itself was clean; the failure surfaced in the capture package's run after drainLoop. Assisted-by: Claude:claude-opus-5-5
Conflict: commands/drain.md, the --json field paragraph. Kept the fix round's wording (a deferral past anchor stays live until the newer tag is fetched, which supersedes 76f3320's 'has lapsed') and drainLoop's new title field in dispositions. Assisted-by: Claude:claude-opus-5-5
Follow-up fl1 (review-fixLoop item 4). A handed-back run stays in progress by construction until itd-50's drafts/ move lands terminal liveness, and no verb clears it; yet every later step's refusal named no way past it, and build next excluded the intent with 'resume it with abcd implement step', a step that refuses. Both now name the run's directory, .abcd/.work.local/run/<run-id>, as the thing to remove once the intent is replanned, and the pick's exclusion says the run handed the intent back rather than inviting a resume. commands/implement.md and commands/build.md say the same. TestALaneThatExhaustsItsFixRoundsIsHandedBack was watched fail on both assertions before the change. Refs: iss-2609301303434847 Assisted-by: Claude:claude-opus-5-5
… out Resolves: iss-2609301303434847 Assisted-by: Claude:claude-opus-5-5
Follow-up cr1 (review-citeReach). iss-2609252211487887's deferral reason counted the 140 names drainReach's sort left on its own branch; merged beside main's and the other lanes' removals, the baseline holds 136, and TestEveryExportedCoreFunctionIsReachedOrBaselined passes on it. Refs: iss-2609252211487887 Assisted-by: Claude:claude-opus-5-5
Integration interaction between gitleaksAug and loopLanding. implement record --transcript stores each transcript through the history capture, but the record's transcript entry dropped the capture's scan gap, so a transcript stored with the native scanner alone, in a repository that armed gitleaks where gitleaks is not installed, was not disclosed there while history capture names it. The entry now carries scan_gap (home-redacted, omitted when empty), and the text record renders it with the same scanGapLines history capture uses. commands/implement.md and the implement surface chapter say so. TestImplementRecordRendersATranscriptsScanGap was watched fail with the field present and unwired. Refs: iss-2609301307566557 Assisted-by: Claude:claude-opus-5-5
…pts' scan gap Resolves: iss-2609301307566557 Assisted-by: Claude:claude-opus-5-5
Measured on a clean clone of cb46dbe (the 24b-3 merges and the follow-ups): widening 1,463,871 estimated tokens, window 1,460,000 -> 1,480,000; detection 1,472,907, 1,470,000 -> 1,490,000; entailment 418,715, 420,000 -> 430,000 (0.31% headroom, under the 1% rule). Refs: iss-2609251455354719 Assisted-by: Claude:claude-opus-5-5
…n gap f41a1a7's sentence spelled the history verb in code form above the generated appendix, which TestSurfaceChapterProseStatesNoShape refuses; the prose now names the verb in words. Refs: iss-2609301307566557 Assisted-by: Claude:claude-opus-5-5
Joining main with the implement-loop lanes, which held six itd-111 entries in the opposite order around the BU1/BT1 entry, leaves those six repeated after BU1: keeping main's copy alone would drop the lanes' order (DA002), and repeating BU1 instead exceeds the merge base's bound (DA003). The appended entry names the six and says the first copy is the record. Assisted-by: Claude:claude-opus-5-5
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.
Integration 24b-3 lands seventeen reviewed branches in one change, still inside the unreleased, breaking v0.12.0. For a user: a repository that opts into gitleaks gets it in every scan abcd makes; the build loop can take a lane from review to a merged pull request by itself and hands a lane back to the person after its fix rounds;
abcd drainnow works issues through that loop one lane at a time; record-lint catches stale and circular dependency edges between intents and two files claiming one ADR id; prompts no longer appear when stdin is /dev/null; andabcd --versionsays when it answers from a superseded plugin root.gitleaks in every scan (gitleaksAug). A repository that opts into gitleaks now gets it in every scan abcd makes, not in transcript capture alone: the launch scan, the privacy lint, a lifeboat pack, and the transcript, issue-capture, memory, decision, intent, ideate, reading and release write paths all report what gitleaks finds, beside the native scanner. When the repository armed gitleaks and the binary is not installed, a release and a lifeboat pack refuse, the privacy lint reports an error, and the write paths still write on the native scanner and name the gap in their receipt. What gitleaks hands back is treated as untrusted input: capped, position-checked, forced to hard_fail, and never shown in clear.
One lock primitive for every flock (flockSites, carried by gitleaksAug). The five record stores that ran their own flock loops (ADR, intent and spec mint locks, the memory store, the history records) now go through fsutil's two lock primitives, with byte-identical lock paths, and a detector stops a sixth from appearing. The history records lock's wait is now bounded at two minutes instead of hanging, and lock descriptors are close-on-exec, so a child a holder started no longer keeps the lock.
Guard-teaching follow-ups (teachFollow). A repository's own guard lesson has its why and its successor capped at 1,024 bytes each, and a longer one refuses the guard file loudly. When the rules overflow the injection budget, the notice names the file that filled it. Under a committed guard switch-off every taught lesson says the guard is off, and when a rules override leaves out a lesson the repository's guard file teaches, the load names that lesson too.
A malformed repository route is skipped (routeNameSkip). A repository's
.abcd/config.jsoncan no longer stopabcd ahoy credential,ahoy connectand the providers board by giving a route a name that is not a plain lower-case name, or a value that is not<provider>/<model>: per ruling CD2 the route is skipped with one sanitised warning naming the file and the name, and everything else keeps working. The same mistakes in the person's own~/.abcd/config.jsonstill refuse.Filing-match follow-ups (filingFollow).
reverses:is a checked cross-reference field in record-lint, the promote route's ADR states its lock exactly, and dead code in the reading match is removed.Terminal detection (ttyDetect). abcd asked install and identity questions when stdin came from /dev/null, because its terminal check treated any character device as a terminal. It now asks the kernel whether the descriptor is a terminal, so a redirected or closed stdin declines with "no terminal to ask at". A program PATH finds inside the checkout no longer counts as installed. By design,
abcd update </dev/nullnow proceeds as it does from a pipe.One ADR id, one file (adrIdUnique). record-lint's new
adr_id_uniqueblocker refuses two ADR files that claim one id, and the resolver andabcd adr-Nrefuse such an id naming both files instead of taking whichever sorts first.Stale intent edges relinked (recDefects). A sweep of planned and draft intents relinks or drops nine
builds_on/blocked_byedges that named a superseded intent, each dropped edge saying why under the intent's Audit Notes.Dependency-edge lint (lintEdges). record-lint warns on a planned or draft intent whose
builds_onorblocked_bynames a superseded intent (stale_edge), naming where the chain ends, and on a cycle through those edges (edge_cycle), naming every record on it.Predecessor-store citations qualified (drainCitations). Intents that cite spec numbers from the retired predecessor store now say so with a "(predecessor store)" qualifier where the number also names a different live spec; citations of live specs are unchanged. Records only.
Reach baseline shrunk (drainReach). In eighteen packages, exported core functions nothing outside their package calls are made package-private or marked as test seams. Nothing is deleted and no behaviour changes.
Superseded plugin root named (supersededRoot).
abcd --version(andupdate --check) and bareabcd ahoyadd asuperseded_rootnote when the running binary sits in a plugin root other than the one this session resolves, so an old binary a pinned command page still runs no longer answers confidently with a version that is false of this machine.Pinned-action bump intent filed (iss209). A draft intent records the automation ruling M3 asked for: a dependabot bump of an action in a scaffolded workflow syncs its template and lands re-authored. Nothing is built; it waits on its planning interview.
Undecided audits reopen the work; fix rounds are capped (fixLoop, carrying fidelityOnce). When the build loop's fidelity audit cannot decide whether a criterion is met, the work goes back to a fresh implementer as it does for a not-met criterion; it never lands on an undecided audit (ruling DQ1a). A lane takes at most the run's fix rounds (3 unless
--fix-roundsorpace.fix_roundssays otherwise, ruling DR1); past that it is handed back to the person as unachievable with the last round's findings, and the run starts nothing further for it.The loop lands its own lanes (loopLanding). Once a lane's reviewers pass,
abcd implement stepcloses the spec, resolves the captures the lane fixed, commits those records with the repository's hooks running and anAssisted-by:naming the model the lane's receipts reported, waits for the preflight receipt, pushes, opens the pull request, arms the merge as the ruleset says, and cleans up only after the commit is on the default branch.abcd implement recordshows what the run did and captures its transcripts into the history store.The drain works issues through the loop (drainLoop).
abcd drainhands each open issue that needs no decision to the implement loop, one lane at a time, and hands every other issue back to a person by kind;abcd build <iss-N>starts an issue-keyed lane whose brief is the issue and its remedy. The drain stops at the end of its working window and at--max.A stale tag no longer lapses a deferral (anchorStale). A checkout that has not fetched the newest release tag no longer reads a record deferred past that tag as lapsed: the record is handed back as "anchor stale", naming the tag and
git fetch --tags, with no remote call. The drain's rule is no longer read through a linked decision store.Integration follow-ups. A handed-back run names the way out: every later step's refusal and
build next's exclusion now name the run's directory under the local run tier as the thing to remove once the intent is replanned (fl1).abcd implement record --transcriptnow carries a transcript's scan gap on the run record, ashistory capturedoes, when gitleaks is armed and not installed.reclassify --by adr-Nresolves the ADR through the record-id seam, so an id two files claim refuses there too, and the start check's two-file case now asserts that refusal.stale_edgefollows supersession chains through the build's own blocked check, so a chain settled by an accepted decision or a discipline says "settled by ...: drop the edge" (rulings CF1, CF2). Drafts itd-22 and itd-33 drop their settled edges on itd-2, so record-lint shows only the three cycle warnings. The reading windows are recalibrated at the tip. Six decision-log entries appear twice because two histories held them in opposite order; an appended entry says so. The reflect command (itd-24) is not in this change: its review returned FIX FIRST.Resolves: iss-129
Resolves: iss-2608291814575788
Resolves: iss-2609020113012227
Resolves: iss-2609300025372991
Resolves: iss-2609300032219282
Resolves: iss-2609300109005165
Resolves: iss-2609300841407812
Resolves: iss-2609300841466575
Resolves: iss-2609300903497125
Resolves: iss-2609300905174086
Resolves: iss-2609300905225841
Resolves: iss-2609300916451435
Resolves: iss-2609300916459279
Resolves: iss-2609300916465620
Resolves: iss-2609300929557796
Resolves: iss-2609301000153822
Resolves: iss-2609301002043276
Resolves: iss-2609301046433372
Resolves: iss-2609301128211767
Resolves: iss-2609301128253254
Resolves: iss-2609301303434847
Resolves: iss-2609301307566557
Assisted-by: Claude:claude-opus-5-5