Development record
a gate that validates a proxy for a claim switches off the vigilance an absent gate would have preserved
a gate that validates a proxy for a claim switches off the vigilance an absent gate would have preserved
enforcement-claims-are-facts states the rule for a gate that does not exist:
a phantom gate is worse than no gate, because readers who believe a check exists
stop compensating with the vigilance they would otherwise apply.
Three findings from 2026-08-22/23 are that same failure arriving with the reassuring signal intact, which is what makes them harder to see. All three are gates. They differ in what the gate got wrong.
1. No gate at all. research/notes/01-harness-interface.md carried
Status: Accepted (Phase 0 lock) and the title ADR-01 while filed in the
evidence folder. No gate ran on that status claim, because record_schema is
scoped to the configured record stores and a file outside them is not a record
it can see. Recorded as iss-2608221457227162, with the detector gap as
iss-2608230752354926.
2. A real gate measuring the wrong property. The
cli-verb-taxonomy-restructure ideate verdict marked a leg 1 claim verified
that was wrong in its denominator. Its own errata states the lesson exactly:
"ideate record proves every cited id resolves, and proves nothing about
whether a claim is true. A verified mark is a claim about the author's
diligence, not an assertion the binary checked." See
the verdict's errata.
3. A real gate measuring the right property over the wrong subjects.
TestParentsRefuseAnUnknownSubverbAtExitTwo asserts that every parent command
refuses an unknown sub-verb at exit 2, and derives its subjects from the live
command tree so that a parent added later is exercised without anyone
remembering to add it. That is good design and it worked. It was green while
abcd capture nosuchthing minted a durable issue at exit 0, because the sweep
derived from the live tree minus freeTextParents = ["capture", "intent"].
Three details make this the sharpest of the three. The exclusion carried a
written justification that read as a design choice, so a reader met a reason
rather than an omission. The two exempted verbs were the two where an unwanted
write costs most, so the exclusion selected for blast radius in the wrong
direction. And the exemption had its own guard, TestFreeTextParentsAreStillExempt,
whose stated purpose was that the exemption must keep earning itself.
That guard could not fail. It called cmd.Args(cmd, []string{"some prose"})
on a cobra.ArbitraryArgs validator, which accepts everything by definition.
The second-order gate is the mechanism by which the first-order hole became
invisible rather than merely undocumented: a reader who wondered whether the
exemption was still earned would find a test asserting exactly that, and it was
incapable of reporting otherwise. Recorded as iss-2608221328552172, fixed by
deleting the exclusion rather than adding entries to it, and by replacing the
vacuous guard with one that asserts behaviourally that prose still files.
Why 2 and 3 are worse than 1. An absent gate leaves a reader with nothing to trust, so some vigilance survives. A gate that runs and reports green actively withdraws that vigilance and supplies false assurance in its place. The existing principle's own reasoning, that the harm is the withdrawal of compensating attention, applies with more force here than to the phantom case it was written for.
2 and 3 are orthogonal, and the distinction is operational. Shape 2 is right subjects, wrong property. Shape 3 is right property, wrong subjects. A search that finds one will not find the other: a reader holding only the proxy formulation would grep for proxy measurement and walk straight past an exclusion list. The rule shape 3 yields: an exemption from a gate is an enforcement claim in negative form, and carries the same burden of proof as the gate. If a name is excluded from a check, something must be able to fail when the exclusion stops being true, and a test asserting that an exemption is still earned must itself be capable of failing.
The class, stated to cover the three: a gate is evidence only for the property it measures over the subjects it measures, and a reader will credit it with the property they care about across the subjects they assume. A status field is a claim rather than evidence for it; a gate that checks a claim's form has not checked its truth; and an exclusion from a gate is a claim carrying the gate's own burden of proof.
An adjacent case, deliberately not folded in
A session-end capture finding reported a clean monotone threshold from 11 of 24 transcripts. The full sweep breaks it, and the way it breaks is the point. The eleven omitted every confounded row in the set: the counterexample just below the claimed boundary, three sessions still running, and two predating the store. Six rows, all six of them the ones that would have broken the claim, none excluded deliberately. The sample was drawn in a way correlated with the very property being measured, which is structure rather than luck. Recorded as iss-2608230817034768, corrected by the session that filed it once a peer pushed on the width of the interval.
Stated best by the session that found shape 3: a sample that excludes its own counterexamples is an exemption list with no list. That is also why it is the hardest of these to catch. An exemption list is a written artefact somebody can read and challenge, as shape 3 proves; a sample's exclusions are invisible unless somebody widens it.
It is recorded here as adjacent rather than as a fourth shape, and the
difference is named so a later reader can split it out cheaply. Shapes 1 to 3
are all gates, and all involve a claim somebody made about enforcement that a
reader believed. Here there was no gate and no such claim: nobody asserted a
check, and the assurance was inferred from the presentation of the evidence
itself. enforcement-claims-are-facts is specifically about claims made in
documents about enforcement, and its stated Why is readers who believe a check
exists. Admitting this case moves the class from gates that do not gate to
assurances nobody issued but everyone read in, which removes its boundary and
makes it harder to apply rather than easier. Whether to admit it is a maintainer
call, and it is deliberately not taken here.
What did not catch any of them
No instrument surfaced any of these. No lint, test or gate reported a problem, and the one gate that ran on shape 2 reported success. That is the defensible statement, and it says where to look: not at the failures, at the greens.
What did catch them is deliberately not claimed here. The tempting stronger version, that a peer caught every one, does not survive its own standard: it reads as more assurance than the evidence supports, which is the failure this record is about. It is recorded separately as iss-2608230847432287, with its qualifications about thin independence, catches that were record recall rather than review, and at least one that was luck. Whatever is catching these, it is not yet a property of the system, and this record claims only that no instrument is.
Routing is left open deliberately. The paragraph is the cheapest rung, but whether the class also warrants detectors is a maintainer call, and so is whether the adjacent case is admitted. Agents agreeing that a principle should change is not the gate that changes it.
Deferral 2026-09-29
Deferred past v0.11.1: The principle half is done: enforcement-claims-are-facts carries the proxy-gate paragraph (7bed788f2, the product thinker's ruling M9 of 2026-09-23; the adjacent sampling case is left out). The detectors M9 commissioned are owed a planning interview, which opens on one question: which gates do the proxy-gate detectors audit first, and does a finding warn or refuse?
Remedy grounds (2026-09-29)
- Exemption lists come first because they are written artefacts a detector can enumerate, while a proxy measure needs a human to name the property it stands in for; the record's shape 3 was the costliest of the three.
- The warn path reuses the baseline ruled on 2026-09-29 (BT3) rather than a second warning channel.
- Rejected: a detector for the adjacent sampling case, which ruling M9 left out of the class.
- This remedy supersedes the suggested_fix: its principle paragraph landed in enforcement-claims-are-facts (7bed788f2), so what remains is the detectors.
Frontmatter
| id | iss-2608230847432286 |
|---|---|
| type | issue |
| lifecycle | open |
| severity | major |
.abcd/work/issues/open/iss-2608230847432286-a-gate-that-validates-a-proxy-for-a.md
open on GitHub ↗ · commit history ↗
mentions16
- adr-1Three-layer mental model (brief / intent / spec)
- dcn-26092300000000042026-09-23 — The proxy-gate class joins enforcement-claims-are-facts as one paragraph, not as a sibling principle (product thinker, ruling on iss-2608230847432286; one-canonical-primitive): a gate that runs and reports green is evidence only for the property it measures over the subjects it measures, so a gate that measures a proxy, or exempts the cases that matter, withdraws vigilance just as a phantom gate does, and an exemption from a gate carries the gate's own burden of proof. Detectors for the class are commissioned and need planning; itd-147 already cites the class. The adjacent sampling case (iss-2608230817034768), an assurance nobody issued but a reader inferred, is NOT admitted, because it would remove the class's boundary.
- dcn-26092300000000142026-09-23 — Four corrections to the entries of 2026-09-23 above that record the product thinker's run A interview, appended because the ledger is append-only and its gate refuses an in-place edit even of an entry that has not reached the default branch. (1) The interview entry leaves out a clause of ruling B4: itd-43 ships in the next release, so the next cut announces it. That stands against AGENTS.md's rule that a record closed for work an earlier release already carried is stamped `shipped_in:` with that release, since v0.2.0's changelog already named the GL002 gate (itd-43); the product thinker's ruling resolves the tension, so itd-43 carries no `shipped_in:` stamp and the next release's changelog names it. (2) In the ceiling entry, the sentence "A fork of an agent is an agent, so a lane does not fork itself to get under it" is the run's own rule for its lanes, not part of the product thinker's ruling. (3) In the proxy-gate entry, a gate that measures a proxy, or exempts the cases that matter, withdraws vigilance more thoroughly than a phantom gate does, as enforcement-claims-are-facts and iss-2608230847432286 say, not "just as" a phantom gate does. (4) In the cold-reading fork entry, the closing sentence "The code that ships here is unaffected by the move" is not part of the ruling and is withdrawn.
- enforcement-claims-are-factsEnforcement claims are facts
- iss-2608221328552172abcd intent and abcd capture both swallow an unrecognised sub-verb as content and mint a record at exit 0, violating unrecognised-input-never-writes on the two highest-traffic mutating verbs. Verified on 45afe46 against a freshly built binary: 'abcd intent nosuchthing' prints 'created itd-148 (drafts)' and exits 0; 'abcd capture nosuchthing' prints 'captured iss-... (open)' and exits 0. Both records were durable files on disk, removed by hand afterwards. The principle at development/principles/unrecognized-input-never-writes.md states the rule -- a verb that mutates state fails closed, anything not exactly recognised is an error, never a fallback interpretation -- and cites this precise scenario as its founding evidence: a misspelled capture subcommand swallowed as capture text, filing an issue when the user asked to resolve one. The principle is therefore documented and unenforced, and the failure it was written about is still live on both verbs. The cause is structural rather than accidental: both verbs take free text as their canonical create path, so an unknown token is indistinguishable from intended content. That makes a bare token ambiguous by construction, which is the design question a fix must answer -- candidates include requiring quoting or an explicit create flag for the text path, refusing a single bare token that matches no sub-verb and resembles one, or accepting text only from stdin. A typo costs a spurious durable record, a burnt id under the max+1 intent allocator, and a record-lint index_drift blocker until the stray is noticed. Related: adr-45 on id allocation.
- iss-2608221457227162a superseded Phase-0 pseudo-ADR sits in research/notes/ claiming ADR-01, outside every record gate
- iss-2608230752354926ADR-23: Transport Agnostic Core (probe)
- iss-2608230817034768`hook session-end` redacts the whole transcript in-line before it writes, at
- iss-2608230847432287the adversarial-review floor assumes below-the-line artefacts are covered by their gates, and today they were not
- iss-2608231000561060The repo-conformance lint runs in no gate while the record says it gates CI, and it is not currently gate-ready, which are two problems needing separate decisions. Verified 2026-08-23 on origin/main. brief/04-surfaces/README.md row 16 describes /abcd:lint as checking the three-tier layout, AGENTS.md router, durable decisions, docs currency, privacy hygiene and identity positioning, and states it 'backs prepare-this-repo and gates CI (itd-85)'. It does not gate CI. The Makefile's preflight target is lint-reviews record-lint docs-lint plus build, vet, test and race, with no abcd lint, and the Makefile has no abcd lint or repolint target at all. Searching .github/workflows for an invocation of the repo-conformance lint, excluding the unrelated 'abcd docs lint', returns nothing in ci.yml or release.yml, whose only lint steps are go run ./cmd/record-lint and go run ./cmd/abcd docs lint. The surface runs only when a human types it. The second problem is why simply wiring it up does not work. On current main the lint emits 19 privacy-hygiene findings, 17 at blocker severity, and the sampled ones are not leaks. Nine of the 19 are in the scanner's own source or in ledger entries about the scanner, where the patterns appear as subject matter. Three sampled outside that set are documentation examples: a Linuxbrew prefix in a spec table and again in [dcn-2608200000000006](../../decisions/dcn-2608200000000006-homebrew-distribution-recorded-and.md), and a CHANGELOG entry recording that certain path shapes stopped being read as usernames. So gating it today would fail every build on content that is correct. iss-305, resolved, records the mechanism -- hasAbsHomePath lacks the leading-boundary predicate its scanner twin has -- and iss-307, iss-308 and iss-324 are adjacent boundary defects in the same family. A waiver marker exists, abcd-lint:allow with the legacy spelling abcd-audit:allow, and the rule's own source uses it on two lines, so the mechanism is available but is not applied across the corpus. What makes this worth deciding rather than filing and forgetting: the rule is right about the case that actually bit. An absolute home path written into a ledger issue body is exactly what its pattern catches, and on 2026-08-23 two sessions independently wrote one. Neither was caught by an instrument. record-lint did not see them because its roots are ['.abcd/development'] and the ledger is in .abcd/work; the lint that would have seen them does not run. Note the two are not interchangeable, since record-lint is scoped to the durable record while privacy-hygiene scans every tracked file, so widening record-lint's roots is a different fix from running the lint. Decide in order: whether the record's gates-CI claim is corrected or made true, and if made true, whether the false-positive rate is addressed by waivers, by the iss-305 boundary fix, or by narrowing what blocks. Leaving the claim standing while the surface runs nowhere is the shape enforcement-claims-are-facts names, and iss-2608230847432286 records the class.
- iss-2608231025198888abcd capture writes to the ledger without running the redaction scanner
- iss-2608231120121681a lint-and-test-green write path can still be broken; nothing requires running the built binary
- iss-2608231346137587A full-tier `iss35-brief-surface-crosscheck` at content commit `7a4ee00`
- iss-2608231409595789`.abcd/development/release-gate/manifest.json` describes itself as "the
- iss-2608241612007530the issue-resolution gate is triggered by the trailer, so a fix that lands without one is invisible to it. RS001 fires only on a commit carrying a Resolves trailer, and RS002/RS003 only on stamps that already exist, so a merged fix whose commit names no issue passes all three rules and leaves its record in open/ — the exact backlog iss-2608241347321757 was built to stop, reached from the other direction. Measured 2026-08-24: 1315 commits name an iss- id somewhere in the message and 3 carry the trailer. iss-202 is the standing instance: its fix merged on 2026-08-24 in a commit ending with a bare 'iss-202' line rather than the trailer form, and its record sits in open/ with the fix shipped. The missing detector is the inverse direction — a change touching code an open record describes, declaring no resolution.
- itd-147The brief's surface chapters are a generated reflection of the shipped surface, so a shape claim cannot drift