Development record
Multi-project adoption raises the priority of itd-91 (AI-attribution preference) and itd-92 (branch-protection verification) from 'good hygiene' to 'the product claim'. What abcd-cli has today is its OWN answer hard-coded: scripts/check-attribution.sh names specific banned footers and a fixed required trailer, and .github/workflows/attribution.yml is a hand-written file in one repo. Neither is portable, which is exactly the gap itd-91 already states — a project adopting abcd inherits abcd's preference by reading its docs but has no first-class way to declare its own (Co-Authored-By, none at all, or house style). The durable home is a rule in internal/core/lint beside deliverystate, indexdrift and citations: reachable from CLI and plugin, run in any managed repo, reading a declared per-repo preference rather than a constant. Two further observations from the 2026-08-11 session. (1) SCAFFOLD IS THE DELIVERY MECHANISM. internal/core/launch/scaffold renders exactly three artefacts into a managed repo today (release.yml, auto-release.yml, the runbook); an attribution workflow becomes the fourth, so every managed repo inherits the gate from one template instead of someone copying a file. It would automatically gain the self-scaffold parity property — and with it the dependabot pin problem of iss-209, which the sync tool merged in PR #215 already handles. The work just landed is the delivery rail for making this portable. (2) ITD-92 GATES EVERYTHING ELSE. A scaffolded gate that no repo adds to its required status checks is decoration; across N repos the required-check wiring and the enforce_admins policy stop being settings a maintainer clicks and become policy abcd asserts and verifies. That makes itd-92 arguably the higher-leverage of the pair: it is what converts every abcd-scaffolded check, present and future, from advisory into binding. itd-92's own capture note already says this in miniature — 'captured 2026-07-17, the day abcd-cli's own main was protected by hand — work the tool should carry for every repo it manages'. Both intents are still ungrilled drafts.
Multi-project adoption raises the priority of itd-91 (AI-attribution preference) and itd-92 (branch-protection verification) from 'good hygiene' to 'the product claim'. What abcd-cli has today is its OWN answer hard-coded: scripts/check-attribution.sh names specific banned footers and a fixed required trailer, and .github/workflows/attribution.yml is a hand-written file in one repo. Neither is portable, which is exactly the gap itd-91 already states — a project adopting abcd inherits abcd's preference by reading its docs but has no first-class way to declare its own (Co-Authored-By, none at all, or house style). The durable home is a rule in internal/core/lint beside deliverystate, indexdrift and citations: reachable from CLI and plugin, run in any managed repo, reading a declared per-repo preference rather than a constant. Two further observations from the 2026-08-11 session. (1) SCAFFOLD IS THE DELIVERY MECHANISM. internal/core/launch/scaffold renders exactly three artefacts into a managed repo today (release.yml, auto-release.yml, the runbook); an attribution workflow becomes the fourth, so every managed repo inherits the gate from one template instead of someone copying a file. It would automatically gain the self-scaffold parity property — and with it the dependabot pin problem of iss-209, which the sync tool merged in PR #215 already handles. The work just landed is the delivery rail for making this portable. (2) ITD-92 GATES EVERYTHING ELSE. A scaffolded gate that no repo adds to its required status checks is decoration; across N repos the required-check wiring and the enforce_admins policy stop being settings a maintainer clicks and become policy abcd asserts and verifies. That makes itd-92 arguably the higher-leverage of the pair: it is what converts every abcd-scaffolded check, present and future, from advisory into binding. itd-92's own capture note already says this in miniature — 'captured 2026-07-17, the day abcd-cli's own main was protected by hand — work the tool should carry for every repo it manages'. Both intents are still ungrilled drafts.
Deferral 2026-09-29
Deferred past v0.11.1: The product thinker's ruling M4 of 2026-09-23: plan both itd-91 and itd-92 next cycle, each through its own planning interview and then a spec. Both are still drafts. Owed: the two interviews, and one question: which goes first, itd-91 (a declared attribution preference) or itd-92 (branch-protection verification)?
Remedy grounds (2026-09-29)
- The record's own argument holds both ways: itd-92 turns every scaffolded check from advisory into binding, itd-91 makes the gate portable. The order is the owed question, so the remedy states the first plan for each answer and picks neither.
- Rejected: copying scripts/check-attribution.sh into each managed repository, which is the non-portable state the record describes.
Frontmatter
| id | iss-211 |
|---|---|
| type | issue |
| lifecycle | open |
| severity | major |
.abcd/work/issues/open/iss-211-multi-project-adoption-raises-the.md
open on GitHub ↗ · commit history ↗
mentions5
- iss-209Every dependabot PR that bumps a pinned action in .github/workflows/release.yml or auto-release.yml fails TestSelfScaffoldParity and can never go green on its own. Observed on PR #211 (actions/attest 4.2.0 -> 4.2.2): 'release.yml: abcd rendering is not byte-identical to the committed workflow', failing check on BOTH platforms while gitleaks, record-lint, smoke and zizmor all pass. Root cause: the committed workflow is a GENERATED artefact. internal/core/launch/scaffold/templates/release.yml.tmpl:270 and .github/workflows/release.yml:248 both pin actions/attest@f7c74d28b9d84cb8768d0b8ca14a4bac6ef463e6 (v4.2.0), and TestSelfScaffoldParity asserts the two are byte-identical so that abcd's own release dogfoods the machinery a managed repo receives. Dependabot edits only the derived file, so parity breaks by construction on every such bump — this is recurring and structural, not a one-off. The obvious fix (bring the scaffold template into dependabot's scope) is NOT AVAILABLE: the github-actions ecosystem discovers only .github/workflows/*.yml and composite action.yml manifests under the configured directory, and no package-ecosystem scans an arbitrary .tmpl under internal/. .github/dependabot.yml today declares gomod and github-actions, both at directory /. Note also the wrong-direction trap: auto-rendering the scaffold on a dependabot PR would REVERT the bump, since render flows template -> workflow. Options, none adopted: (a) make the parity failure self-explaining — the message says 'not byte-identical' and prints the first diff but never names the template path or says 'an action bump must be applied to the template too', which is the cheapest change and matches the loud-staging principle; (b) propagate the bump backwards — a job on dependabot PRs that applies the changed pin to the template and commits to the bot branch, which is the durable fix but is custom automation writing to a bot branch; (c) drop these two workflows from dependabot's scope and manage their pins by hand from the template, trading automation for consistency. Secondary risk worth weighing: a permanently-red dependabot PR trains the maintainer to discount red CI on exactly the PRs where CI most needs to be trusted.
- iss-215The attribution gate is provider-asymmetric: its POSITIVE check is vendor-agnostic while its NEGATIVE check and the prose it enforces are Claude-specific, so the gate stops the failure it was built for only as long as the assisting model is Claude. Verified 2026-08-11 against scripts/check-attribution.sh: TRAILER_RE accepts any '<Vendor>:<version>' pair, so 'Assisted-by: OpenAI:gpt-5' and 'Assisted-by: Google:gemini-3' both PASS — correct and desirable. But GENERATED_RE bans only 'Generated with [', the robot-emoji 'Generated with', and 'Co-authored-by: Claude' / 'Co-Authored-By: Claude', so a body carrying 'Co-authored-by: ChatGPT <bot@openai.com>' alongside a valid trailer PASSES. That is precisely the failure mode the workflow header says it exists to stop — itd-91 records a reconciliation sweep across 78 pull requests after PR bodies picked up a tool's default footer — merely wearing a different vendor's name. The AI-co-authorship objection AGENTS.md:132 states is about authorship the tool does not hold and contributor-graph inflation, neither of which is Claude-specific. Second half of the same asymmetry: the documented convention hardcodes one vendor in the template — CONTRIBUTING.md:31 writes 'Assisted-by: Claude:<model-version>' and AGENTS.md:132 gives 'Assisted-by: Claude:claude-opus-4-8' — so prose names a vendor the gate does not require, leaving a contributor using another provider without a stated correct form even though the gate would accept one. Fix direction is itd-91's, whose scope is a per-repo declared attribution preference every surface reads; .github/workflows/attribution.yml calls itself a stopgap until that lands, and iss-211 already raises itd-91's priority on multi-project adoption. Two things this record asks of that work specifically: make the co-authorship ban match on the TRAILER KEY rather than on a vendor name, so 'Co-authored-by:' naming any AI is refused; and state the convention as '<Vendor>:<model-version>' with Claude as an example rather than as the literal.
- iss-2608290810032799The attribution gate validates the Assisted-by trailer's SHAPE but cannot tell whether the model id names the model that actually did the work, so a wrong but well-formed id passes green. In the itd-150..162 run four implementation agents were briefed with an incorrect model id: two used it as instructed and their commits passed the gate, two recognised it as a false disclosure and stamped their real id instead. The convention exists precisely to prevent a false disclosure, and the gate is blind to the only failure that matters. A full mechanical fix may be impossible because the runner cannot attest which model produced a commit, but two partial rungs exist: refuse a vendor and model pair absent from a maintained known-models list, so a typo or a stale id is caught; and have the dispatching harness supply its own model id to the agent, so a hand-written briefing cannot introduce a wrong one. Distinct from iss-211 (making the attribution preference portable) and iss-220 (composing the trailer at creation time): this is about the truthfulness of a trailer that is present and well-formed.
- itd-91A Project Declares Once How It Wants AI Acknowledged — And Every Commit, PR, And Record Follows
- itd-92abcd tells every repo the truth about its fence