Development record
A managed repository still has no local gate on a commit message carrying a live agent-session URL or a tool attribution footer, and nothing guards the text handed to the forge CLI for a pull request, an issue or a comment. abcd's own repository refuses both shapes in a commit message through its committed commit-msg hook, which runs go run ./cmd/abcd lint outbound from the source checkout; a managed repository has no source checkout, so the scaffolded form of that hook needs three product decisions first: how it finds an abcd binary (a git hook has no plugin root, so only the PATH rung survives), whether it fails closed or open when none is found, and whether abcd ahoy installs it by default or on opt-in. Split out of iss-2609061438431625 when its local half landed for this repository.
A managed repository still has no local gate on a commit message carrying a live agent-session URL or a tool attribution footer, and nothing guards the text handed to the forge CLI for a pull request, an issue or a comment. abcd's own repository refuses both shapes in a commit message through its committed commit-msg hook, which runs go run ./cmd/abcd lint outbound from the source checkout; a managed repository has no source checkout, so the scaffolded form of that hook needs three product decisions first: how it finds an abcd binary (a git hook has no plugin root, so only the PATH rung survives), whether it fails closed or open when none is found, and whether abcd ahoy installs it by default or on opt-in. Split out of iss-2609061438431625 when its local half landed for this repository.
Deferral 2026-09-29
Deferred past v0.11.1: ruling still owed to the product thinker (re-deferred at v0.11.1 by run A's major-triage lane; none recorded since v0.10.0): for the commit-msg hook abcd ahoy would scaffold into a managed repository, how does it find an abcd binary with no plugin root, does it fail open or closed when none is found, and is it installed by default or on opt-in? The sources-refresh hook's opt-in shape (git config abcd.sourcesBinary, fail open; dcn-2609250000000027) is a provisional precedent, not that ruling.
Remedy grounds (2026-09-29)
- The threat is a session URL or tool footer reaching public history, plus the hook itself executing repository-controlled code; resolving through a local config key holding an absolute path answers the second. lefthook's generated hook searches an explicit variable, then PATH, then package-manager locations, and fails open unless assert_lefthook_installed is set: https://raw.githubusercontent.com/evilmartians/lefthook/master/internal/templates/hook.tmpl (consulted 2026-09-29), so fail-closed-on-opt-in is an established shape, but the choice stays the ruling's (G+).
- Rejected: a PATH-only search, which a repository can shadow through a relative PATH element.
Split 2026-10-14
Resolved for the commit-message half when the opt-in outbound commit-msg gate was re-applied for v0.15.0. The hook judges commit messages only; the text handed to the forge CLI for a pull request, an issue or a comment is still unchecked in a managed repository, and that half is now its own record, iss-2610142210511831.
Frontmatter
| id | iss-2609250834251447 |
|---|---|
| type | issue |
| lifecycle | resolved |
| severity | major |
.abcd/work/issues/resolved/iss-2609250834251447-a-managed-repository-still-has-no-local.md
open on GitHub ↗ · commit history ↗
mentions10
- dcn-26092500000000272026-09-25 — The pre-commit guard's sources refresh (itd-76) finds its binary two ways until the product thinker rules on iss-2609250834251447, and the ruling may widen the second (finding 1 of the sources-lane review, adopted by the orchestrator as the safe shape). This repository's copy builds `./cmd/abcd` from the checkout, as `.githooks/commit-msg` does, and never runs an installed abcd; a tree that does not build is one warning line and the commit proceeds. The copy `abcd ahoy` scaffolds refreshes only when the clone opts in with `git config --local abcd.sourcesBinary <absolute path>`, a path to an executable regular file with no PATH search and never an environment variable, and otherwise prints one line and proceeds. That answers none of the three questions the ruling holds (how a scaffolded hook finds abcd, fail open or closed, default or opt-in): it is the shape that leaves them open, so AC3 holds in this repository and in a managed repository that opted in. In both copies the refresh updates an existing keyed private store only, relays the binary's own line, and names a legacy store's migration once per working tree (implementer of the sources fix round).
- dcn-26092600000000012026-09-26 — Release v0.11.0 is cut by autonomous run A, and the run's agenda line is: approve the publish step. Under ruling A2 of the product thinker's run A interview (2026-09-23 07:52Z: the run approves the release environment itself once every gate is green) and the product thinker's releases ruling of 2026-09-25T08:04:52Z ("cut additional releases if that makes sense, but bundle multiple intents for it"), the run approves the `release` environment's deployment of v0.11.0 only after the merge queue, the verify job and every other gate on the tagged commit report green, and stops with a handover instead if any does not. The cut: v0.11.0, impact breaking (decided by itd-2609212130136102, the verb consolidation, whose five surface removals the guard names), 193 records since v0.10.0: eleven shipped intents (ten additive, one breaking) and 182 resolved or declined issues (108 fixes, three additive, 71 internal and outside the changelog); two major findings pass on their recorded deferrals (iss-2609250834251447, iss-2609251824244354). Content commit 9ef24744, on top of ae116575, which the docs-currency gate's findings required. Both semantic gates ran at tier full. docs-currency-reviewer (Fable 5.1) read the first roll and found four: the install one-liners ended on the retired `abcd version`, which v0.11.0 refuses with exit 2 (major; fixed in ae116575), a CONTRIBUTING wording (fixed there too), and two changelog lines recomposed by the composer; the guard gap behind one of them is captured as iss-2609260543090196. The brief-surface cross-check (40 pinned checkers, Opus 5.5, at most four alive) found 130, all real at the content commit by an independent classification (Fable 5.1): the eight user-facing and four behaviour findings are captured as nine minor records (iss-2609260552249742, iss-2609260552247395, iss-2609260552246303, iss-2609260552247252, iss-2609260552256523, iss-2609260552256401, iss-2609260552250826, iss-2609260552254288, iss-2609260552251398), and the design-record drift goes to the systematic brief pass iss-2609091956001547. Landed before the cut on the cutting session's ruling: #717 (the shell guard cluster) and #718 (the race lane's declared timeout, after #717 was ejected from the merge queue by the default ten-minute package timeout).
- dcn-26092900000000012026-09-29 — Correction to the 2026-09-25 entry on the pre-commit guard's sources refresh (itd-76, iss-2609250834251447): that entry says the scaffolded copy's opt-in shape "answers none of the three questions the ruling holds", and half of that is not so. The template `abcd ahoy` scaffolds (`internal/core/ahoy/defaults/pre-commit`) takes a PROVISIONAL stance on two of the three questions: default or opt-in — opt-in, since nothing runs until the clone sets `abcd.sourcesBinary`; fail open or closed — open, since an unusable opt-in (not an absolute path to an executable regular file) prints one line and the commit proceeds. Only the first question, how a scaffolded hook finds abcd, stays unanswered in the template's own terms, which say it "deliberately does not take" that decision. Both provisional answers stand until the product thinker rules on iss-2609250834251447, and the ruling may replace either. The earlier entry stands as written, since the ledger is append-only (review2-sources finding 5; recorded by lane drainDrift2 of autonomous run A, iss-2609252055533837).
- iss-2609061438431625A Claude session URL reached three commit messages and two PR bodies of a managed public repo and nothing in the abcd guard stack stopped it — not acceptable. The lint policy text says a live session URL or a tool attribution footer is refused wherever it is committed, but privacy-hygiene only scans tracked files; the committed pre-commit name guard checks the private banlist (empty by default) and never the commit message; there is no commit-msg hook, and nothing looks at the text handed to the GitHub CLI for pull requests or issues. The harness's own attribution instruction (a Claude-Session trailer on every commit and PR) is exactly the pattern the policy names, so the guard must catch it mechanically: a commit-msg hook (and pre-merge-commit) that rejects claude.ai/code/session links and known AI attribution footers; a public banned-token family for those patterns so CI enforces it on every pushed commit message in the PR range, not only on files; and guard coverage of the GitHub CLI's pull-request and issue text. Recovery is expensive — a merged commit message can only be removed by rewriting a protected branch — so this has to fail before the commit exists.
- iss-2609252007419997The scaffolded pre-commit template refreshes the sources banlist block by default with a binary found on PATH or in ~/.local/bin, which answers by fiat the three questions iss-2609250834251447 holds as a ruling owed to the product thinker (how a scaffolded hook finds a binary, fail open or closed, default or opt-in). Until that ruling, the template should refresh only on repo-local opt-in, git config --local abcd.sourcesBinary naming an absolute path to a regular file, with no PATH search and never an environment variable, and otherwise print one line and proceed.
- iss-2609252055533837The decision [dcn-2609250000000027](../../decisions/dcn-2609250000000027-the-pre-commit-guard-s-sources-refresh.md) for the sources refresh says the opt-in shape decides none of iss-2609250834251447's questions, but the template does take a provisional stance for the pre-commit refresh (opt-in; fail open on an unusable opt-in); the entry should call that half provisional (review2-sources 5).
- iss-2610142210511831A managed repository has no gate on the text handed to the forge CLI for a pull-request body, an issue or a comment, so a live agent-session URL or a tool attribution footer reaches the forge unchecked, and the forge keeps the pre-edit revision of whatever was posted. The commit-message half of iss-2609250834251447 shipped as the opt-in ahoy install --outbound-hook gate; this is the forge-text half that record named and that gate does not cover. scanner.ScrubOutbound already defines the scrub for outward text, and abcd lint outbound the check, but nothing a managed repository runs puts either in front of the forge CLI's pull-request, issue or comment commands. Split out of iss-2609250834251447 when its commit-message half was resolved.
- iss-2610152024267547ahoy install --outbound-hook leaves git config --local abcd.binary for each person to set by hand in each clone, so the commit-message check warns and lets every commit through until someone does, although the recorded remedy of iss-2609250834251447 said ahoy install would write it to the owned PATH copy, the abcd.guardPath precedent. The product thinker ruled on 2026-10-15 that the installer writes abcd.binary itself, to the absolute path of the provenance-verified abcd copy ahoy installs.
- iss-2610171626324658The v0.15.1 release review found the brief at .abcd/development/brief/04-surfaces/07-library.md:174-177 out of step with the shipped code. It says: How a scaffolded hook finds abcd, and whether it does so by default, is a ruling owed to the product thinker (iss-2609250834251447) In the code: iss-2609250834251447 is in .abcd/work/issues/resolved/ with a recorded ruling: `ahoy install --outbound-hook` opts in, never installed by default, finds abcd only through git config --local abcd.binary, and fails open with one warning; the chapter still presents the ruling as owed
- itd-76abcd Lets You Consult Sources You Cannot Cite — and Remembers Every Debt