Development record
abcd-s-typed-judgements-can-run-through-a-decision-adapter
specclosedspc-2609221011151661
Summary
The design record for itd-2609221009495079: the decision interface, the shadow lab, the harvest and the per-type switch.
Scope
- The interface (
internal/core/decide/judge.go, distinct from the ADR verb's package):Judge(state, question) (value, prob), three question kinds; the host implementation renders the question as a prompt and parses the answer with probability 1 (criteria 1, 6). - The callers: each judgement-shaped step names its type and calls the interface; the registry of types is the closed list in scope (criterion 1).
- Shadow: the router reads the configuration per type (
host|shadow:<provider/model>|<provider/model>); shadow runs both and appends the pair to~/.abcd.noindex/lab/<lab-id>/pairs.jsonl(criteria 1, 5). - Harvest:
abcd lab harvestgains the agreement report for a pairs file (criterion 2). - Turned on: the router calls the adapter and records the route; fallback with a receipt (criterion 3).
- Allowlist: the resolver of adr-2609221009491186 runs before any call (criterion 4).
Out of scope
- Generative steps; learned routers; the pick.
Approach
One interface, one router with three modes, one adapter over the API adapter's client; the lab verb records and harvests, so the evidence path is the lab's, not a new one.
Steps
- The interface, the per-type routes and their three modes, the shadow pairs and their harvest, and the drain's eligibility judgement through the router
- packages: internal/core/decide, internal/core/lab, internal/adapter/openaiapi, internal/core/oracle, internal/core/implement/loop, internal/surface/cli
- tests: the router's three modes with a fake adapter; a drain move in each mode; the pairs file and its line-at-a-time harvest; the window skip; the fallback receipt
- landed: #1245
- Embark's lesson ranking as a host judgement routed through the adapter (dcn-2610300523005947), and the first step's review notes
- needs: 1
- packages: internal/core/reflect/lessons.go, internal/core/reflect/lessons_test.go, internal/core/lifeboat/retrospectives.go, internal/core/lifeboat/retrospectives_test.go, internal/surface/cli/cli.go, internal/surface/cli/embark_lessons.go, internal/surface/cli/embark_lessons_test.go, internal/surface/cli/reflect_lifeboat_cli_test.go, commands/embark.md, .abcd/development/brief/04-surfaces/03-embark.md, docs/reference/cli/commands.md, .abcd/development/release/surface.json, internal/core/decide, internal/core/lab, internal/core/implement/loop/drain.go, internal/core/implement/loop/drain_decide.go, internal/core/implement/loop/drain_decide_test.go, internal/core/implement/loop/drain_adapter_wire_test.go, internal/core/implement/loop/judgement.go, commands/lab.md, .abcd/development/brief/04-surfaces/31-lab.md, .abcd/development/brief/05-internals/02-adapters.md, .abcd/development/brief/05-internals/03-configuration.md, internal/README.md
- tests: one score question per lesson; lessons ranked by the host's scores with term overlap breaking ties; no scores leaves today's term-overlap order; shadow records one pair per lesson beside the host's scores; turned on ranks by the adapter's scores and asks the host nothing; an adapter that cannot answer leaves the host's request standing with a receipt; no brief lists the lessons unranked and asks nothing; a route naming an unknown judgement type is reported; a request whose routed judge never started is not marked asked
Footprint
- packages: internal/core/decide, internal/core/lab, internal/adapter/openaiapi, internal/core/oracle/config.go, internal/core/oracle/judgement_mode_test.go, internal/core/oracle/connect_guide.go, internal/core/implement/loop/drain_decide.go, internal/core/implement/loop/drain_decide_test.go, internal/surface/cli/lab.go, internal/surface/cli/lab_surface_test.go, internal/README.md, commands/lab.md, .abcd/development/brief/04-surfaces/31-lab.md, .abcd/development/brief/05-internals/02-adapters.md, .abcd/development/brief/05-internals/03-configuration.md, .abcd/development/intents/planned/itd-2609221009495079-abcd-s-typed-judgements-can-run-through.md, .abcd/work/issues/open/iss-2610262033055327-the-decision-adapter-intent-treats.md, .abcd/work/issues/resolved/iss-2610262033055327-the-decision-adapter-intent-treats.md, .abcd/work/issues/open/iss-2610262037348735-the-decision-adapter-intent-needs-lab.md, .abcd/work/issues/resolved/iss-2610262037348735-the-decision-adapter-intent-needs-lab.md, internal/core/reflect/lessons.go, internal/core/reflect/lessons_test.go, internal/core/lifeboat/retrospectives.go, internal/core/lifeboat/retrospectives_test.go, internal/surface/cli/cli.go, internal/surface/cli/embark_lessons.go, internal/surface/cli/embark_lessons_test.go, internal/surface/cli/reflect_lifeboat_cli_test.go, commands/embark.md, .abcd/development/brief/04-surfaces/03-embark.md, docs/reference/cli/commands.md, .abcd/development/release/surface.json, internal/core/implement/loop/drain.go, internal/core/implement/loop/drain_adapter_wire_test.go, internal/core/implement/loop/judgement.go
- tests: the router's three modes with a fake adapter; the pairs file; the harvest's rates; the window skip; the fallback receipt
How the criteria are satisfied
| Criterion | Where |
|---|---|
| 1 shadow records pairs | scope 3 |
| 2 harvest and the note | scope 4 |
| 3 turned on, fallback | scope 5 |
| 4 allowlist | scope 6 |
| 5 window skip | scope 3 |
| 6 one interface | scope 1, 2 |
Frontmatter
| id | spc-2609221011151661 |
|---|---|
| type | spec |
| lifecycle | closed |
.abcd/development/specs/closed/spc-2609221011151661-abcd-s-typed-judgements-can-run-through.md
open on GitHub ↗ · commit history ↗
References1
- itd-2609221009495079abcd's typed judgements can run through a decision adapter, measured in a lab before it decides anythingimplements
mentions8
- adr-2609221009491186A provider adapter serves only the models it lists, under a vendor denylist no listing overrides; everything else runs on the host
- dcn-26092600000000042026-09-26 — The lab store is keyed `~/.abcd/lab/<root-sha>/<lab-id>/`, with one `index.jsonl` registry per root-sha lane beside the lab homes (lane implementer, autonomous run A, on review-lab's third finding against spc-2609212141418943 for itd-2609212137128014). This supersedes two recorded texts: the spec's literal `~/.abcd/lab/<lab-id>/` (scope item 1), and the 2026-08-31 lab-convention entry's hand-run keying `~/.abcd/lab/<timestamp>-<source-sha7>/` with a single top-level `~/.abcd/lab/index.jsonl`, whose stated divergence from root-sha keying is withdrawn. Why: the intent's scope condition keys the store "as the other machine-scoped stores are", and the worktree and transcript stores key on the repository's root commit, because a checkout moves, is renamed and is cloned twice on one machine while its root commit does none of that; a lab's identity is still its intention, carried by its id `lab-<yymmddHHMMSS>-<pin7>` (the UTC mint time and the pin), so several labs share one baseline inside one lane. The hand-run labs that predate the verb stay where they are, beside the root-sha lanes, and the verb neither reads nor writes them or the top-level registry, so no real lab is moved or migrated by the change. A later text naming `~/.abcd/lab/<lab-id>/` (the open spc-2609221011151661's `pairs.jsonl` among them) means the lab home inside its root-sha lane.
- dcn-26102905183769042026-10-29 — Spec footprint entries (iss-2610241549334990): the comma split that respects parentheses lives in spec.ReadFootprint, the one parser every reader shares, so the readiness score's package count stops counting half a note as a package; the leading-path read and the prose refusal live in the build's specPackages. Grounds: one split rule for every reader, and the score's 100-divided-by-packages part was miscounting the same entries. An entry with whitespace is kept when it names something in the working tree (a real path with a space), checked only for a path that stays inside the tree. A prose entry excludes its intent from build next at the footprint check instead of aborting the pick, which mirrors how a spec with no footprint is excluded. The remedy's 'leading path' is read as the entry up to its trailing parenthetical, not its first word, since the remedy's own refusal clause presumes whitespace can remain. An entry is first read as written, and kept whole when that names something in the tree, so `docs/Archive (2019)` is not cut back to a different path; and a trailing parenthetical counts as a note only when a space sets it off, so a route-group path such as `app/(marketing)` stays whole (review finding). Of the three open specs whose entries were prose, two are rewritten with their paths alone in the same change; spc-2609221011151661 is left to the lane rewriting its line, and a build of it is refused, naming the entry, until that lands.
- dcn-26103005230059472026-10-30 — Decided by the technical facilitator on delegation (the product thinker's ruling of 2026-10-29 that embark's lesson ranking stays in the decision adapter intent as a real judgement; iss-2610262033055327 named that it has no host answer to pair), how embark's lesson ranking becomes a judgement, for step 2 of spc-2609221011151661 to build. (a) The judgement is one score question per lesson, on a scale of 0 to 4: how far does this lesson apply to the new voyage as its brief frames it. Its state is the brief's framing (bounded to fit the window) and the one lesson. A choose question over the lessons is not used, because a lesson is often longer than an option may be and the option set would grow with the lifeboat. (b) The host answers it: embark lessons lists each lesson's question in its result, the agent running the embark page scores them, and passes the scores back with a scores file; the lessons are then ranked by those scores, term overlap breaking ties. Without a scores file the result is today's term-overlap order, still named a heuristic, so no caller breaks. (c) The type routes like the drain's judgement: in shadow the adapter scores each lesson beside the host's answer and each pair is recorded in the newest lab home; turned on (only from the person's own machine file) the adapter's scores rank the lessons and no host scores are asked for; an adapter that cannot answer leaves the host's request standing with a fallback receipt. (d) With no brief, the lessons stay listed unranked, as today, and nothing is asked.
- dcn-26103015070149302026-10-30 — How a judgement route picks the decision adapter's second candidate, the small text model scored by log-probability (itd-2609221009495079, spc-2609221011151661; lane implementer on the run coordinator's delegation): a provider block on the person's own machine lists, under logprob_models, the models from its own models list that are asked that way, and a route to one of them is judged by the log-probability candidate while every other route keeps the first, typed-decision candidate. No new route prefix and no new judgement mode: the route grammar (host, shadow:<provider>/<model>, <provider>/<model>) stays as it is, the provider block already holds what is per model (its allowlist and pins) and sits on the machine layer alone, so a repository cannot change how a model is asked, and the field marks only a listed model, so it admits nothing the allowlist does not. Both candidates call through the same APIConfig.Call, so the allowlist, the denylist, the key by name and the router's window check apply to both unchanged; with logprob_models absent every path is as before.
- iss-2610241549334990A spec's Footprint packages line is reserved exactly as written. An entry carrying a note or prose therefore becomes a footprint path with that text in it. A build of spc-2610111627213138 would reserve internal/core/memnote (new). A build of spc-2610120941441282 would reserve internal/surface/cli (the pre-push hook's fixture tests), and its parenthetical containing a comma would split into the two entries scripts/cloud/connectors/claude (new and the host connector). Overlap compares paths segment by segment, and claim.ValidFootprintPath accepts spaces. So such an entry shares no path with the package it means, and the build does not hold that package against another build. Several open specs carry such entries, among them spc-2609221011151661, spc-2610111627213138 and spc-2610120941441282.
- iss-2610262033055327The decision-adapter intent treats embark's lesson ranking as a judgement the host answers by default; the embark page ranks lessons by term overlap, with no judgement in that step.
- iss-2610262037348735The decision-adapter intent needs lab harvest to report agreement rates with probability bands; the lab brief's harvest only assembles prose sections from findings and probe records