Development record
2026-08-19 — bughunt round 1 (branch bughunt-b/round-1): captured iss-291..iss-304 and fixed
2026-08-19 — bughunt round 1 (branch bughunt-b/round-1): captured iss-291..iss-304 and fixed
ten. Code: iss-291 the guard exec-string cluster reader ignored value-taking short flags, so
script -Tc out.txt -c '<blocker>' was a silent allow that also disarmed the Tier-2 fail-safe
(value flags now abort the cluster read); iss-293 ParseSemver swallowed strconv.Atoi's range
error, clamping an oversized component to MaxInt64 (now propagated, matching spec.go); iss-292
the wrapper-probe test wrote junk files (0,1,PATH,root) into the tracked tree because runsCommand
had no cmd.Dir (now a temp dir; the four committed artefacts removed). Docs/record: iss-294
version --check "only network" claim, iss-295 README unshipped brief-onboarding claim, iss-296
ADR-index + ruleset-README count drift, iss-297 adr-40 verb-rename residue in roadmap+brief,
iss-298 all 18 broken/stale brief heading anchors and section citations (anchorcheck now 0),
iss-299 phantom "in-session dispatch" internals chapter, iss-300 persona glossary role-first
contradiction. Recorded not fixed (stay open): iss-301/iss-302 external-review.yml approval-tally
(paginated per-page --jq) and error-masking (|| echo none + under-permissioned collaborators
endpoint) — required-check workflow, unverifiable without a real Actions run; iss-303 links_resolve
never validates heading anchors (systemic fix behind the anchor cluster); iss-304 deferred nitpicks
(a-4 memory ingest --source size TOCTOU, b-4 completion/help omitted from the CLI reference, d-12
the CI job id record-lint runs the reviews-charter script). Refuted this round: the scripts/
payload over-inclusion (knowingly-deferred open dependency, iss-34), the attribution/reviews gates
running from the PR tree (CODEOWNERS contains it), AGENTS.md's CI-job list (ci.yml-scoped, iss-182),
the release Go-version float (deliberate), and the 05-personas.md random-picker line (prior art iss-49).
Frontmatter
| id | dcn-2608190000000003 |
|---|---|
| type | decision |
| date | 2026-08-19 |
.abcd/work/decisions/dcn-2608190000000003-bughunt-round-1-branch-bughunt-b-round-1.md
open on GitHub ↗ · commit history ↗
mentions18
- adr-40Review, audit, lint, and gate are four buckets, separated by what each compares
- iss-34refusal guards with zero coverage: the launch bundle symlink-dereference and scripts-deny guards (internal/core/launch/bundle.go:339), the memory quotation-budget and licence-detection compliance checks (internal/core/memory/lint.go:225), and the memory ask --file-back write path (internal/core/memory/ask.go:354) are all untested. A guard fails silent: when it regresses the system keeps working and simply stops refusing. Detector (per guards-prove-themselves): a convention that every refusal path ships a test presenting the forbidden input and asserting the rejection, its error shape, and the absence of side effects; a pairing lint between declared invariants and named tests is the promotion path. Acceptance corpus: the five guard paths above.
- iss-49record cosmetics batch: an orphaned .gitkeep; two verbatim doctrine blocks duplicated in the record; the ACKNOWLEDGEMENTS ccpm entry was added retroactively against its own same-change rule; the brief lacks a one-page arc42 crosswalk and an open-questions precedence line; 05-personas.md should be rewritten role-first with personas.json as the roster source of truth. Low individual impact; batched so the cleanup pass has one handle. Detector: none warranted beyond the existing lints — this is the residue after detector-shaped clusters were extracted, fixed directly per the fix-the-detector one-off bound.
- iss-182Three build-plumbing comments still describe the pre-push gate and CI by an older, smaller shape. Same class as iss-37 (claims must match reality), in living files its re-scope does not cover, and no ledger entry records them until now. The fix direction is the same bar: state what actually runs, verified against the recipe or workflow beside the comment.
- iss-291abcd guard silently allows a blocker whose exec-string verb carries a value-taking short-flag cluster before the payload flag (script -Tc out.txt -c '<blocker>'): clusteredPayload accepts the cluster without consulting the verb's value flags, mis-reads -Tc as -T -c, resolves a bogus payload and switches the Tier-2 fail-safe off for the segment
- iss-292abcd guard's wrapper-probe test (wrappers_test.go runsCommand) runs wrapper binaries with no cmd.Dir, inheriting the package source directory as cwd; flock opens its probe values (0 1 PATH root) as lock files, so go test writes four zero-byte files into the tracked tree — and they are already committed under internal/core/guard/
- iss-293launch.ParseSemver discards strconv.Atoi's range error (major,_ := ...), and semverRe's numID is unbounded, so a >int64 version component clamps to MaxInt64: distinct oversized versions collide to one String() and the next Patch++ wraps negative — reachable via GitExistingTags (git tag list) and changelog.DeriveNext; the identical defect was already guarded in spec/spec.go
- iss-294The 'abcd version --check' flag help calls it 'the only command that touches the network', but the same generated reference page also calls 'docs cite refresh' the only network verb and 'memory ingest <url>' does its own HTTP GET — three real fetch paths, contradicting adr-38's own two-verb model
- iss-295README.md's 'It starts with the brief' section claims in present tense that abcd 'has a skill that ingests that material and produces a plain-language draft of your project's brief' and that you sharpen it with 'a Socratic interview the framework provides' — but abcd ships zero skills (surface is commands-only) and the grill/Socratic interview is an unshipped planned intent (itd-27), an unmarked not-yet-real claim the README's own honesty rule forbids
- iss-296The hand-maintained ADR index table (.abcd/development/decisions/adrs/README.md) ends at adr-42 and omits committed records adr-43 and adr-44; the record-lint index_drift rule registers four indexes but not the ADR index, so this largest hand index is ungated. Same file: .abcd/work/rulesets/README.md says 'seven required status checks' where main-protection.json now lists eight (external-review added)
- iss-297adr-40's v0.6.0 verb renames (intent review -> intent audit, disembark oracle -> disembark review) left stale residue in durable present-tense docs: roadmap/phases/{README.md,phase-0-substrate.md,phase-6-lifeboat.md} still say 'intent review', and brief/05-internals/08-skills.md plus brief/04-surfaces/README.md still list 'oracle' as a disembark sub-verb the binary now refuses
- iss-298The brief carries broken and stale intra-record cross-references invisible to links_resolve (which strips the #fragment before resolving): six deep links name headings that were renamed or renumbered (04-launch.md, 04-universal-patterns.md, 01-ahoy.md, 05-intent.md sections 5/6/7), ten anchors mis-encode an em dash, 00-meta.md cites a deleted disembark section-3 budget rule, and three live README lines cite the pre-split monolithic brief by section number
- iss-299brief/README.md's 05-internals directory-tree comment enumerates ten chapters including a nonexistent 'in-session dispatch' (that is planned intent itd-2, not a chapter); the directory holds nine files and its own index has nine rows
- iss-300The persona glossary (brief/glossary/core/persona.md) and brief/01-product/05-personas.md say the persona picker 'chooses at random', contradicting personas.json and itd-79 whose rule is 'selection is by role, never by name'; the glossary's worked examples also assign off-role names (Carol as product lead, Alice as developer)
- iss-301external-review.yml computes its approver tally with 'gh api .../reviews --paginate --jq' where --jq runs per API page (not across the full set; --slurp is incompatible with --jq), and no per_page is set so pages are 30 — so the 'latest state per reviewer wins' reduction the comment promises fails once reviews span a page: a stale page-1 APPROVED survives a later page-2 CHANGES_REQUESTED, and a straddling double-approval is counted twice. Fail-open on a required security gate. Not fixed autonomously: required-check workflow that cannot be validated without running Actions
- iss-302external-review.yml's role_of() folds every 'gh api collaborators/<u>/permission' non-zero exit into the string 'none' via '2>/dev/null || echo none', indistinguishable from a legitimate no-role answer, so a transient/permission failure silently misclassifies authors and drops approvals; the job grants only contents:read + pull-requests:read while that endpoint needs push access (or an App members permission), so it likely 403s for every lookup and wedges the gate red for all human PRs with no diagnostic. Not fixed autonomously: required-check workflow, and the permission behaviour needs a real Actions run to confirm
- iss-303links_resolve (internal/core/lint/lint.go checkLinks) strips the #fragment before resolving and skips same-file # links, so no gate validates heading anchors even though both record-lint and docs-lint declare the rule blocking and the Makefile advertises it as catching a broken relative link; ~18 broken anchors sit on a green tree. Proposed: extend the rule to slug the target file's ATX headings and validate the fragment, landing warn-first
- iss-304Confirmed nitpicks deferred from bughunt round 1 (recorded not fixed): (a-4) memory ingest --source reads its operand with os.Stat-then-unbounded os.ReadFile, a size TOCTOU the URL branch's io.LimitReader avoids; (b-4) the generated CLI reference claims to list every user-facing command but omits Cobra's completion/help commands; (d-12) the CI job id 'record-lint' actually runs scripts/check-reviews.sh (reviews-charter), a misleading required-check name whose safe rename needs a coordinated live-ruleset edit