Development record
A drain takes an issue alone only when its fields say it needs no decision
Context
abcd drain (itd-82)
works the open issue ledger unattended: it fixes what needs no decision and
hands the rest back to a person. The load-bearing part is the sorting, which
issue a machine may take alone. Its failure runs one way: a machine that
decides a thing needs no decision, and then makes one.
The evidence gathered on 2026-09-21 is recorded in the intent: models detect
their own ambiguity badly, triage passes that dispatched a coding agent were
reverted after unwanted pull requests, and clean-ups and tests merge far more
often than features and performance work. The product thinker ruled on
2026-09-21 (itd-82 decision 4) that the rule for "needs no decision" decides
what a machine may touch alone, so it is a recorded rule: a decision record and
a brief invariant, minted by the spec's first delivery, and until it exists an
unattended drain refuses to start. Decisions 6 and 7 of the same interview
settle the remedy: field and the order.
Decision
We will let a drain take an open issue alone only when its fields say it needs no decision, and route every other open issue by the rule that excluded it.
- The rule is the fields. An open issue is eligible when all of these
hold: no record in its
blocked_byis still open; its category is in the fixable set,bug,documentation,drift,inconsistency,tech-debtorux; its severity isnitpickorminor; and it carries a non-blankremedy:(a record carrying only the oldersuggested_fix:reads that value as its remedy). - What each exclusion means. The rules are asked in this order and the
first that excludes decides the disposition: blocked (skipped, the blocker
named); category
security(always a person's); a category outside the fixable set, which isprocess,observation,architectural-insight,future-work-seedandlapse(handed back, the category named); severitymajororcritical(handed back, the severity named); no remedy (ineligible, the field named, until someone adds one). A record the ledger reader refuses is named as unreadable. Every open issue receives exactly one disposition. - A judgement can only narrow. A host-delegated judgement (adr-25) over an eligible issue's remedy may hand it back as a user-visible or trust-boundary change. It never makes an excluded issue eligible, and no estimate an agent makes of its own confidence lets an issue through.
- The order is declared. Eligible issues are taken by category in the
order
tech-debt,documentation,inconsistency,drift,bug,ux, thennitpickbeforeminor, then oldest first. - The classification is re-derived every run and recorded with each disposition in the run's summary; nothing is written onto the issue for it (itd-82 decision 8).
- The drain refuses to start without this record. The rule is read from
the drained repository's own decision store, never from the binary: the
four
drain_fields in this record's frontmatter state it (drain_categories,drain_severities,drain_security,drain_remedy), and a repository whose store holds no accepted record carrying them is refused by the dry run and the start alike, naming how to add one (the product thinker's ruling BX2 of 2026-09-29, verbatim: "the PROJECT MUST HOLD the eligibility decision in its own record (e.g. added at setup); drain refuses there until it does"). This repository states abcd's strict baseline, which the binary bundles as the measure a loosening is named against, and a test holds this record to it. - Another project may loosen the floors, loudly. A project's own record
may list
majororcriticalamong its severities, or setdrain_security: take, and every floor it loosens is named by the dry run and at the start (ruling H11 of 2026-09-29, verbatim: "MAY LOOSEN abcd's floors (a project may let drain take major/critical and security issues). NOTE for the lane: make a loosened floor loud (drain --dry-run and the drain start name every floor the project loosened), and keep abcd's own repository at the stricter default."). It may narrow the fixable set but never widen it, and it cannot drop the remedy. A partial or malformed record refuses rather than falling back to either rule. - A record waiting on a person is a person's. Whatever the record says, an issue whose remedy opens "Waits on" (a fix that waits on an unanswered ruling) and an issue whose deferral past the current anchor tag is live are handed back, each naming its rule.
Alternatives Considered
- A model classifies each issue. Rejected: ambiguity self-detection is unreliable, and a classifier that can let an issue through is the failure this rule exists to prevent. The judgement stays, and it can only hand back.
- Severity alone. Rejected: severity says how much an issue matters, not
whether fixing it needs a decision. A
minorprocessissue is a rule change, and aminorsecurityissue is a trust question. - Everything with a remedy. Rejected: a remedy says what someone proposed, not that the proposal needs no decision. The category and severity carry that.
- The fields, read in a fixed order (chosen). Every field is on the
capture already, apart from
remedy:, and each exclusion names the rule a person reads to act on it.
Consequences
- The first drains over today's ledger are small: most records carry no
remedy:, and they wait until someone adds one. - A change to the fixable set, the severities or the order is a change to this record, never merely a code path.
- The issue-keyed lane of
itd-2609201916151817(decision 10) reads the same rule as the check before it starts, so the two cannot disagree about which issue is eligible. - The eligibility record is a file the drained repository authors, deciding what an unattended agent may do there. A contributor's pull request that loosens it is a trust change: it is committed history, reviewed like code, and a loosened floor is named on every dry run and start.
- Owed and out of this record: where a hand-back flag lives.
Amendment — 2026-10-16: an issue linked to an intent goes through that intent
Decision 8 names two holds. A third holds whatever the record says, from step 4
of spc-2610161044461448 and the decision recorded for it
(dcn-2610161040365515), and brief invariant 19 states it: an open issue whose
related_intents names an intent is handed back under the rule promoted,
naming the intents, because it goes through that intent and a machine never
takes it alone. In decision 2's order it is asked straight after blocked,
before security, so a reader is sent to the intent rather than to a field the
intent's work would settle. This amendment adds to decision 8; it does not
reverse it or any other decision.
- A consistency finding is not linked to its intents in this sense. The consistency pass names the two intents its contradiction is between, so the record it files is judged by its other fields and stays ineligible only until a person writes its remedy, as ruling H12 has every automatic filer's record (dcn-2610161425496537).
- A person's own build is still the lane route. The consequence above that
the issue-keyed lane reads the same rule as the drain holds for every rule
but this one:
abcd build <iss-N>takes an issue the drain hands back aspromoted, naming the intent, which is how an after-merge audit's owed check reaches a lane (dcn-2610161428244461).
Frontmatter
| id | adr-2609291342092738 |
|---|---|
| type | adr |
| status | accepted |
| date | 2026-09-29 |
.abcd/development/decisions/adrs/2609291342092738-a-drain-takes-an-issue-alone-only-when.md
open on GitHub ↗ · commit history ↗
References4
- adr-25The LLM is host-delegated by default; oracles are opt-in adaptersrelated
- adr-27The autonomous run is a pluggable seam, not a Ralph portrelated
- itd-82`abcd drain` fixes the issues that need no decision, and hands the rest back by kindrelated
- itd-2609201916151817One verb takes a READY intent to delivered, and refuses while a decision is openrelated
mentions11
- dcn-26093000000000122026-09-30 — The drain reads the drained repository's own eligibility record, which may loosen abcd's floors loudly, and it hands back every record still waiting on a person (the product thinker's rulings BX2 and H11 of 2026-09-29, applied by lane drainOwnRule of autonomous run A; partial of itd-82, whose spec stays open for the host judgement, the lane, the hand-back writes and the pace). BX2, verbatim: "the PROJECT MUST HOLD the eligibility decision in its own record (e.g. added at setup); drain refuses there until it does." H11, verbatim: "MAY LOOSEN abcd's floors (a project may let drain take major/critical and security issues). NOTE for the lane: make a loosened floor loud (drain --dry-run and the drain start name every floor the project loosened), and keep abcd's own repository at the stricter default." As built: the record is the one accepted decision record in the repository's `.abcd/development/decisions/adrs/` whose frontmatter carries `drain_categories` (an inline list, a subset of the fixable set), `drain_severities` (an inline list of severities), `drain_security` (`handback` or `take`) and `drain_remedy` (`required`, its only value, since the remedy is the brief a lane works from); abcd's own adr-2609291342092738 carries the strict baseline, which the binary also bundles as the measure a loosening is named against, and a test fails if abcd's record loosens anything. A repository without such a record, with one that is only proposed or superseded, with two accepted, or with one that misses, misspells, repeats or mis-values a field, is refused by `drain --dry-run` and bare `drain` alike, exit 2 and nothing written, never falling back to the baseline or a looser rule; widening the categories past the fixable set is refused as a decision by kind, which H11 does not name. Every loosened floor (`severity major`, `severity critical`, `security`) is named in the dry run's text, on stderr in both output modes, in `--json` as `loosened`, and in the start's refusal. `ahoy install` offers the baseline as an accepted record, written through the decision store's mint only on an answered yes; `--yes` skips it and reports `drain_rule.offered` under `optional_skipped`, as the routing offers are. The gap the remedy lanes found (50 of 54 dry-run-eligible records waiting on a ruling) is closed by BOTH hand-backs, each its own rule: a remedy opening "Waits on" (compared case-folded) is handed back as `waits-on-ruling`, because taking it would make the ruling the remedy waits on; and a record whose `deferred_after` names the current anchor tag is handed back as `deferred`, because a person carried it past this release and the waiver is that person's decision for the cycle. Both hold whatever the repository's record says. `capture defer` writes a deferral only onto a `major` or `critical` record, which H11 now lets a record take, but this ledger also carries hand-written deferrals on minor records (62 of the 231 open records on this branch are handed back as `deferred`), and the rule holds them back the same way. They are asked after the category and severity hand-backs, whose fix a ruling or a lapse would not change, and the ruling before the deferral, because it names which decision is owed; a record carrying both waits on both. The release tags are read only when an open record carries a deferral, and a failure to read them refuses the plan rather than letting a live deferral through. The threat is stated in the drain brief chapter: the record is a repository-authored file deciding what an unattended agent may do, so a contributor's pull request can loosen it; what guards it is that the record is committed history reviewed like code, a loosening is loud on every run, abcd's own repository keeps the baseline under a test, and the store is read inside the checkout so a symlink leaving it is refused.
- dcn-26093000000000172026-09-30 — The drain reads the drained repository's own eligibility record, which may loosen abcd's floors loudly, and it hands back every record still waiting on a person (the product thinker's rulings BX2 and H11 of 2026-09-29, applied by lane drainOwnRule of autonomous run A; partial of itd-82, whose spec stays open for the host judgement, the lane, the hand-back writes and the pace). BX2, verbatim: "the PROJECT MUST HOLD the eligibility decision in its own record (e.g. added at setup); drain refuses there until it does." H11, verbatim: "MAY LOOSEN abcd's floors (a project may let drain take major/critical and security issues). NOTE for the lane: make a loosened floor loud (drain --dry-run and the drain start name every floor the project loosened), and keep abcd's own repository at the stricter default." As built: the record is the one accepted decision record in the repository's `.abcd/development/decisions/adrs/` whose frontmatter carries `drain_categories` (an inline list, a subset of the fixable set), `drain_severities` (an inline list of severities), `drain_security` (`handback` or `take`) and `drain_remedy` (`required`, its only value, since the remedy is the brief a lane works from); abcd's own adr-2609291342092738 carries the strict baseline, which the binary also bundles as the measure a loosening is named against, and a test fails if abcd's record loosens anything. A repository without such a record, with one that is only proposed or superseded, with two accepted, or with one that misses, misspells, repeats or mis-values a field, is refused by `drain --dry-run` and bare `drain` alike, exit 2 and nothing written, never falling back to the baseline or a looser rule; widening the categories past the fixable set is refused as a decision by kind, which H11 does not name. Every loosened floor (`severity major`, `severity critical`, `security`) is named in the dry run's text, on stderr in both output modes, in `--json` as `loosened`, and in the start's refusal. `ahoy install` offers the baseline as an accepted record, written through the decision store's mint only on an answered yes; `--yes` skips it and reports `drain_rule.offered` under `optional_skipped`, as the routing offers are. The gap the remedy lanes found (50 of 54 dry-run-eligible records waiting on a ruling) is closed by BOTH hand-backs, each its own rule: a remedy opening "Waits on" (compared case-folded) is handed back as `waits-on-ruling`, because taking it would make the ruling the remedy waits on; and a record whose `deferred_after` names the current anchor tag is handed back as `deferred`, because a person carried it past this release and the waiver is that person's decision for the cycle. Both hold whatever the repository's record says. `capture defer` writes a deferral only onto a `major` or `critical` record, which H11 now lets a record take, but this ledger also carries hand-written deferrals on minor records (62 of the 231 open records on this branch are handed back as `deferred`), and the rule holds them back the same way. They are asked after the category and severity hand-backs, whose fix a ruling or a lapse would not change, and the ruling before the deferral, because it names which decision is owed; a record carrying both waits on both. The release tags are read only when an open record carries a deferral, and a failure to read them refuses the plan rather than letting a live deferral through. The threat is stated in the drain brief chapter: the record is a repository-authored file deciding what an unattended agent may do, so a contributor's pull request can loosen it; what guards it is that the record is committed history reviewed like code, a loosening is loud on every run, abcd's own repository keeps the baseline under a test, and the store is read inside the checkout so a symlink leaving it is refused.
- dcn-26101610403655152026-10-16 — A drain's hand-backs are published on origin (facilitator-on-delegation, drain-many-accounts): a drain's hand-back, from a lane or from a judgement, is the release of the reservation the drain took before judging, carrying a closed-vocabulary hand-back kind and the blob id of the issue record on origin's default branch, never free text; a reservation a drain makes backs off such a tip while the blob is unchanged, while a person's own abcd reserve or abcd build is let through with a note; a promotion the checkout cannot make because it does not hold the record as origin does publishes the tombstone alone and says so; an issue whose related_intents names an intent is ineligible, a clause added to brief invariant 19; and every account draining at once runs one build, since an older build reads the tombstone as a plain release (grounds: reasoned tombstones as Cassandra and Kafka keep them, and the fixed-form rule for the shared remote, dcn-2610150000000001; iss-2610161015370582).
- dcn-26101614254965372026-10-16 — A record the consistency pass files is outside the drain's promoted rule (facilitator-on-delegation, drain-many-accounts step 4): the pass writes into related_intents the two intents its contradiction is between, which are the finding's subjects and not intents that took the work on, so under the promoted rule its record would be handed back for good, against the product thinker's ruling H12 as dcn-2609290000000016 records it, that an automatic filer's record is filed and a drain passes it over only until a person writes a real remedy; such a record is skipped while it carries the machine remedy and may be taken by a drain once a person writes one. The record is told by the three fields the filer writes, category inconsistency, source agent-finding and a found_during opening "abcd intent consistency, finding ", which no other filer in the binary writes, and not by finding_ref, which a record the pass filed before keys existed lacks. This narrows the "no exception by source" of dcn-2610161401449155 by this one filer: every other issue whose related_intents names an intent, the after-merge audit's owed-check issue included, is still handed back as promoted (grounds: ruling H12; the filer's own fields in internal/core/capture/consistency.go; iss-2610161015370582).
- dcn-26101614282444612026-10-16 — An after-merge audit's owed-check issue reaches a lane through a person's own build, and a drain still hands it back as promoted (facilitator-on-delegation, drain-many-accounts step 4; a new record refining dcn-2610161401449155, since records are append-only): ruling DQ1a, that an undecided fidelity audit reopens the work and sends the feature back to a lane, is subsumed by ruling DQ1c, which says what reopening means for a shipped intent (it stays shipped and flagged, and one issue carries the owed check, dcn-2609300000000027), so DQ1a is met when that issue reaches a lane, and a person's abcd build <iss-N> remains the lane route for it: the eligibility check lets a promoted issue through with a note naming its intent, as dcn-2610161040365515 lets a person's own build through a hand-back, while every other hand-back is still refused. This overrides the resolution of iss-2608290820473197 where it says the captured issue is one "which a drain can take": a drain hands it back, and a person's build or abcd intent audit takes it (grounds: rulings DQ1a and DQ1c, dcn-2610161040365515, dcn-2610161401449155; iss-2610161015370582).
- iss-2610161655393137abcd's own drain rule (adr-2609291342092738) holds abcd at the strict baseline, taking nitpick and minor and handing every security issue back, and a test pins it there, so urgent fixes that need no decision wait for a person. The product thinker ruled on 2026-10-16 that abcd's own repository takes every severity and security, most urgent first.
- iss-2611020305525945abcd build refused the terminal interview fix (iss-2611011402496418) at 03:05 on 2026-11-02: 'is handback under adr-2609291342092738 (severity): severity major is above the drain's (nitpick, minor); remedy: the issue is a person's'. The product thinker had directed that fix the evening before and ruled that agent work runs on the API key, but the only route for a major issue is a host session, which bills the subscription the person asked to spare. Nothing lets a person admit one issue they have decided on to the loop, so a directed major fix waits for the person or runs on the route they ruled out.
- itd-2610112239022766Private security reports stay private until their fix ships
- itd-2610301750162657abcd's unattended work is spot-checked against specs and intents
- spc-2609212015054359drain-ledger-triage
- spc-2610161044461448drain-many-accounts