Development record
abcd's unattended work is spot-checked against specs and intents
Summary
Delivers itd-2610301750162657. abcd gains a spot-check in two lanes that never hold each other up. The collection lane runs inside the landings abcd already makes: when a change lands and the repository's window has passed, abcd fetches one value from a public randomness beacon, draws up to the set number of items per group from the work decided alone in that window, and appends the drawn items to a review queue on the shared remote. The review lane is a new verb, abcd spotcheck, through which the technical facilitator, a human facilitator and the product thinker work the queue whenever they have time, one judgement per item, never reading code. A finding files an issue against the rule that admitted the item; a clean cycle states per group what it rules out. Two smaller pieces ride with it: the drain's summary counts its hand-backs per pull request, and the implement loop refuses to have a change reviewed by the model that wrote it.
The intent is blocked by itd-2610301850454860 (the landing record), planned with spc-2610301950480609, settles the shape this spec reads and nothing more: the evidence of how a change was admitted is written into history before the merge (an Admitted-by: trailer on every lane's records commit); a read-only abcd landings reader classes every first-parent commit of the default branch as person-approved, drain, automatic or person-push, naming the rule that admitted it, from history and from the forge only where history cannot answer; its --unattended view lists drain and automatic and every row the evidence cannot place with a person; and a revert is traced through This reverts commit <sha>. This spec depends on no freeze of that listing at a release cut: each drawn item's state is copied into the queue at the draw. The drain's hand-backs and the automated facilitator's decisions are outside that record, so this spec records them itself.
Grounding, read on 30 October 2026:
- The drain's run state is
DrainState(internal/core/implement/loop/drain.go:124), written to.abcd/.work.local/run/drain.json(drain.go:49,state.go:73): one worktree's local tier, whichgit worktree removedeletes. Its hand-backs areDrainState.HandBacks []DrainRoute(drain.go:138, type at:183-208withIssue,From,Kind,Route,Rule,Reason,At,Bloband no pull request), built byrouteHandBack(:1365); the lane's pull request number isDrainLane.PR(:179). The only durable trace of a hand-back is the reservation tombstone'sAbcd-Handed-Back: <kind>trailer (internal/core/claim/message.go:27, written bymarkHandBack,claim/remote.go:709), whichreserve --sweeplater deletes. - The automated facilitator's decisions are of two kinds. The merge gate shipped with itd-2610150602547271:
DecideMerge(internal/core/landing/facilitator.go:396) gathers the mode as the default branch's committed.abcd/config.jsonand the machine layer declare it, the author's role, the counted approval and, inauto, whether a review receipt names the head (reviewReceipt,landing/review.go:179, under.abcd/.work.local/review-receipts), andmergeGate(facilitator.go:329) decides by its table:autoarms a maintainer's pull request only when a review receipt names its head,humanonly once an approval of the head counts, the facilitator's own recordedabcd land --approvefirst (countedApproval:188,RecordApproval:264,ApprovalsRelDir:54), a contributor's needs a maintainer's approval in either mode, and an unverified author arms nothing. It is asked fromabcd land'senqueue(landing/land.go:1284) and the loop's arm (loop/land.go:898), and itsMergeDecision{Arm, Method, Why}is kept nowhere. The second kind is the drain's judgement a model answered:DrainJudgement{Issue, Answer, Kind, Reason, Route *runner.RouteRecord, …}(loop/judgement.go:118-134),Routeset byadapterJudgement(loop/drain_decide.go:167) and nil when a person answered. - abcd proves a landing in three places: a lane's
landMergedancestor check (loop/land.go:939,ld.Mergedat:1030),abcd land's ownLandedandmergedAtre-run checks (landing/land.go:300,:315, fromprimitives.go:173,:217), and every drain move's fetch of origin's default branch (loop/drain.go:447).abcd landitself never waits for the merge and writes no file after one (landing/land.go:184, the PR body alone atprbody.go:145). - The drain's summary is
renderDrainRunandrenderDrainCounts(internal/surface/cli/drain.go:326,:435-445) overDrainCounts(loop/drain.go:298, filled at:1283); hand-backs are listed flat throughDrainSummaryLine(loop/drain.go:1570). - The review set:
ReviewSet{Roles, Judge, MaxReviewers}andReviewClass{Class, Model, …}(loop/reviewset.go:126,:95), resolved byresolveReviewSet(:260) and stored atState.Review(loop/state.go:381); the writer's model is the implementer's self-reportedReceiptRecord.Modeland itsRoute(state.go:548,:552); a validator's route is set atloop/validate.go:594(host-run) and:1003(runner);ValidatorRun.Verdictatstate.go:636. Nothing compares the two models; the only same-model logic ismatrix.sameModel(internal/core/matrix/export.go:560). - Filing an issue from Go is
capture.Capture(CaptureRequest)(internal/core/capture/workflow.go:65); the request (capture.go:168-222) takesText,Severity,Category,Source(one ofissueschema.Sources,internal/core/issueschema/issueschema.go:206-218),FoundDuring,FoundAt,Remedy,RelatedIntents,RelatedSpecs; the record lands in.abcd/work/issues/open/(alloc.go:319). The drain's admission asks its rules in order ineligibility(capture/eligible.go:131), and a remedy openingWaits onis handed back byRuleWaitsOnRuling(:158), whatever the category. - The board:
boardOutput(cli/board.go:26-64), filled atcli/cli.go:361, rendered throughboard.Render(internal/core/board/board.go); rows areboard.Row{Label, Text, Items}(board.go:75) appended inboardRows(cli/board_view.go:74-101) and shown by the facilitator view (board.go:338-386); the product view (:265-323) shows building, the next three and a count.--jsonwritesboardOutput. - Asking:
question.AskandQuestion{Material, Ask, Options, Later, Typed, …}(internal/core/question/ask.go:14,:20), its limits (limits.go:42: two to four options, 24 rows at 80 columns), the asking rules (asking.go:35, the thing decided quoted in full in the question), the terminal pickerask.Terminal.Put(internal/surface/cli/ask/loop.go:114) and the host route throughFields()(ask.go:209). The mode's states aremanaged,facilitatorandproduct-thinker(internal/core/mode/mode.go:54-61), set from a question's chip (cli/guard_question.go:248). - Shared-remote state abcd already keeps outside the tree: reservations on
refs/heads/abcd-reserved/<id>(internal/core/claim/claim.go:36-43), pushed bypush(claim/remote.go:454) and fetched byfetch(:1052), with every fetch named in invariant 7 (.abcd/development/brief/02-constraints/03-invariants.md:21-184). - Configuration: there is no config struct; each consumer claims its namespace through
layered.LoadandStack.Claim(internal/core/layered/layered.go:248,:610) and reads a bounded integer throughGet[int]with a check, asQuietDaysdoes (internal/core/ahoy/worktree/quiet.go:57-73). - A bounded HTTPS GET is
urlguard.NewDownload(internal/urlguard/download.go:38: https only, pinned hosts, no proxy, dial-time address check, bounded redirects), used bytools/fetch.go:58andupdate/update.go:880withio.LimitReader. - The beacon, read live on 30 October 2026:
https://api.drand.sh/v2/beacons/quicknet/rounds/latestanswers{"round": <n>, "signature": <96 hex>};…/quicknet/infogiveschain_hash 52db9ba70e0cc0f6eaf7803dd07447a1f5477735fd3f661792ba94600c84e971,period 3, schemebls-unchained-g1-rfc9380. The round's randomness is SHA-256 of the signature bytes, which abcd computes itself. The verification check of 31 October 2026 (.abcd/development/research/notes/2026-10-31-drand-beacon-verification-sota.md): signatures on G1 and keys on G2, the message SHA-256 of the big-endian round, andgithub.com/cloudflare/circl/sign/blsv1.6.5 verifying that shape with the same domain separation tag, with three indirect modules and no cgo. - The research note (
.abcd/development/research/notes/2026-10-30-spot-check-unattended-changes-sota.md:24-36,:45-52,:61-72): a seed the agents cannot touch and a chance for every item; zero findings in n reads bound the failure rate at about 3/n; the reader sees the item before any automated verdict.
Approach
- The store: one branch on the shared remote, written only by appending files. A new package
internal/core/spotcheckkeeps the spot-check's record onrefs/heads/abcd-spotcheckonorigin, tracked atrefs/remotes/origin/abcd-spotcheck, withclaim'spushandfetchexported for it (one refspec added to the fetch the calling verb already makes). The branch is an orphan whose tree holds four folders of small JSON files, each written once and never edited:window-open.json: The commit and time the first window opened (written by the first check that finds no cycle, which draws nothing).cycles/<cycle-id>.json: One per draw: the window (from_commit,to_commit,from_time,to_time,closed_by=daysorchanges, the observing site), the beacon (url,chain_hash,round,signature,randomness,fetched_at), the sample (per_groupfrom the configuration,sizeapplied,why=fullorhalved, the closed cycles counted), and per group the population's item keys (or, above 5,000 keys, the key range and the population's SHA-256) and the keys drawn.items/<cycle-id>/<nn>-<group>-<key>.json: One per drawn item: its group, its key, the roles it is for, and the whole of its state at the draw, copied in (the landings row, the promise, the outcome and the withheld verdicts, approach 6), so what a person later sees asthennever depends on a later read of history or the forge.handbacks/<at>-<issue>.jsonanddecisions/<at>-<ref>.json: The drain's hand-backs and the automated facilitator's decisions (approach 2).judgements/<cycle-id>/<nn>-<group>-<key>.<role>.json: One per judgement (approach 7). The queue is derived: an item waits while a role it is for has no judgement file. Because every write is a new file keyed by item and role, two writers never conflict; a pushoriginrejects is retried once after a fetch, and a judgement whose key the fetch shows already onoriginis dropped and the earlier one named. A push that fails offline leaves its commit on the local tracking copy, the sitting goes on, and the next push carries it; a sitting's end and the board say how many judgements have not reachedorigin. Why the shared remote and not a tier of the tree: The draw runs inside a landing, which has no tree to write into (landrefuses a dirty tree,landing/land.go:274; a lane's worktree is removed atlandMerged), and the landing on one machine must be seen by the facilitator and the product thinker on others, so a per-machine store under~/.abcd.noindex/would fragment the queue across whichever machines land. A committed.abcd/work/spot-checks/would dirty the observing worktree at every draw and send a hundred judgements through a pull request per sitting, through the very gates being checked. The remote branch is where abcd already keeps state every copy must see (reservations, announcements), under invariant 7's named-verb rule; the findings themselves become committed issues, the reviewed and durable trace, so a lost branch loses judgements but never a finding. A repository with nooriginhas no unattended landings to draw from; there the check and the verb refuse, naming the missing remote, and write nothing.
- Hand-backs and the automated facilitator's decisions are recorded as they happen. The drain writes
handbacks/<at>-<issue>.json(issue, kind,From,Route,Rule,Reason, the lane's pull request if one was opened, the run id, the record blob) fromrouteHandBack(loop/drain.go:1365), anddecisions/<at>-<issue>.json(kinddrain-judgement: issue, question, answer, kind, the route's model, the rule record, the reason) fromdecideDrainJudgementwhenRouteis set (loop/drain_decide.go:167). The merge gate's two callers (landing/land.go:1284,loop/land.go:898) writedecisions/<at>-pr<n>.json(kindmerge-gate: pull request, head, the mode and its layer, the author's role, whether a receipt named the head,Arm,Method,Why) whenever the mode isautoand the author a maintainer, which is the case in which abcd is the facilitator and no person's approval was counted; a decision inhumanmode, or over a contributor's pull request, waits for a person and is not recorded here. Each file is committed on the local tracking copy at once and pushed with the next push its verb makes anyway (the tombstone, the lane's branch, the half-lease renewal,land's own push), and at the drain's end; none adds a push of its own.DrainRoutegainsPR intfrom the lane, andrenderDrainCounts(cli/drain.go:435) gains the per-pull-request table the intent asks for: One line per pull request the run opened with its hand-back count and kinds, then the hand-backs with no pull request. - The window and the trigger.
.abcd/config.jsongains aspotcheckblock, claimed throughlayered(Claim("spotcheck", "window_days", "window_changes", "per_group")):window_days(1 to 90, bundled default 7),window_changes(10 to 100,000, no default, 0 meaning unset),per_group(1 to 100, default 10). Either window may be set and the first to pass closes it; the repository layer is read last and wins, as the drain's pace keys are read. One function,spotcheck.AfterLanding(root, now) Note, is called from the three observing sites:landMergedafterld.Mergedis set (loop/land.go:1030),LandwhenLandedormergedAtreports the branch on the default branch (landing/land.go:300,:315), and the drain move after its fetch of the default branch (loop/drain.go:447). It reads the last cycle'sto_commitandto_timefrom the branch as last fetched, countsgit rev-list --first-parent --count <to_commit>..origin/<default>and comparesnowwithto_time; when neither bound is passed it returns at once, having read two files and run one local git command and touched no network. Its return is a note for the run record or the verb's text, never an error, an outcome or a hold: a draw that refuses for any reason (beacon unreachable, forge unread, push rejected twice) leaves the window passed, writes nothing, and the next observed landing tries again. The window closes at the observing instant and spans everything since the last cycle, so a week with no landing is drawn at the next one and nothing falls between windows. - The beacon and the draw.
beacon.gopins two constants: the quicknet chain hash52db9ba70e0cc0f6eaf7803dd07447a1f5477735fd3f661792ba94600c84e971and the chain's group public key, the 96-byte compressed G2 point83cf0f2896adee7eb8b5f01fcad3912212c437e0073e911fb90022d3e760183c8c4b450b6a0a6c3ac6a5776a2d1064510d1fec758c921cc22b0e17e63aaf4bcb5ed66304de9cf809bd274ca73bab4af5a6e9c76a4bc09e76eae8991ef5ece45a(both from the chain'sinforeply, read on 31 October 2026 and recorded in2026-10-31-drand-beacon-verification-sota.md). The draw fetches the chain's latest round, addressed by the pinned hash (https://api.drand.sh/<chain-hash>/public/latest), throughurlguard.NewDownloadpinned toapi.drand.sh(falling back once toapi2.drand.sh, thenapi3.drand.sh), ten seconds in all, body bounded at 4 KiB, and accepts only a positiveroundwith a 96-hexsignature; a reply that names a chain hash other than the pinned one is refused. abcd then verifies the signature itself, at pick time: the pinned key is unmarshalled intobls.PublicKey[bls.KeyG2SigG1]fromgithub.com/cloudflare/circl/sign/bls(v1.6.5, pure Go, BSD-3-Clause), the message is SHA-256 of the round as a big-endian uint64, andbls.Verify(&pk, msg[:], sig)must hold; circl's built-in G1 domain separation tag is the one drand'sbls-unchained-g1-rfc9380scheme signs under, so no tag is passed. The randomness is SHA-256 of the signature bytes, which abcd computes itself, and a reply that carries arandomnessfield must carry that value. A reply that is late, malformed or unreachable, or whose signature does not verify, refuses the draw alike: nothing is written, one line names the beacon and the round, the landing's outcome is unchanged. The dependency is the one this spec adds, with the product thinker's sign-off of 31 October 2026: the build runsgo get github.com/cloudflare/circl@v1.6.5andgo mod tidy, reports every line it adds togo.modandgo.sum(circl's own module requires only go-ristretto, x/crypto, and x/sys; which of those lines are new is known only when tidy runs), and lands theACKNOWLEDGEMENTS.mdentries for circl and for drand in that same change, since credit lands with the change that integrates a tool.TestBeaconVerifyholds the published vector for round 1000 (signatureb44679b9a59af2ec876b1a6b1ad52ea9b1615fc3982b19576350f93447cb1125e342b73a8dd2bacbe47e4b6b63ed5e39, randomnessfe290beca10872ef2fb164d2aa4442de4566183ec51c56ff3cd603d930e54fdd) as its positive case and the same signature against round 1001 as its negative; the vector was not run against circl during the check, so the test's first run is that check, and a failure stops the build and is reported rather than loosened. The populations are read for the window: Groupsdrain-landedandautomatic-mergesfrom the landings reader's rows infrom_commit..to_commitclasseddrainandautomatic(every row the evidence cannot place with a person included, its decision 9; aperson-approvedrow excluded, its decisions 7 and 8); groupsdrain-hand-backsandfacilitator-decisionsfrom the branch'shandbacks/anddecisions/files withatinfrom_time..to_time. A row whose approval the reader could not settle from history and reports as unread from the forge refuses the draw, so a person's approval is never drawn as unattended on a guess. An automatic merge's rule isfacilitator.mode: auto, the requirement the gate's table holds; the review receipt itself stays in the local tier and is not recovered afterwards (itd-2610301850454860, decisions 6 and 7), so the reader names the mode's requirement and the item copies it. Each item's key is its merge commit or its file name; within a group the keys are sorted, each is givenHMAC-SHA256(randomness, cycle-id || group || key), and thesizesmallest are drawn. The same stored randomness and population give the same list, every item has a chance, and no agent can steer it: the value does not exist until the window has closed. The cycle record stores round, signature and chain hash, so the verification abcd made at the draw can be repeated by anyone later. The fetch is written into the documented meaning ofland,drainandimplement stepin invariant 7 and their pages, so abcd still asks the network nothing on its own. - The sample size adapts over fully reviewed cycles only.
sizeisper_groupunless the three most recent closed cycles, in window order, each have zero findings, when it isceil(per_group / 2), never below one; a closed cycle with any finding makes the next size full. A cycle is closed when every role slot of every item has a judgement; an open cycle is skipped in the count and counts as neither clean nor a finding. The cycle record names the cycles it counted. - A card, never code.
spotcheck.Card(item)renders what a role sees, in plain text, from records alone: the landings row (class, rule by id and path, when, pull request number); the promise, which is the issue's text and remedy, or the spec's criteria, or, for the product thinker, the intent's press release and acceptance criteria; the outcome, which is the pull request's title and the record section of the body the loop composed (prbody.go:61), theresolved_bystamp and the changelog line where one exists; and for a hand-back the issue, the kind, the route, the clause of the rule that applied and the question whether the drain was right to hand it back; for a decision the question put, the answer given and the rule record. Every card ends withthenandnow:thenis the item file's own copy, written at the draw and never re-read from history or the forge;nowis read at the sitting from the default branch as last fetched: still on it, reverted by<sha>(the landings reader's revert trace), changed again by later first-parent commits touching the change's paths, the issue reopened, or the handed-back issue since resolved, by whom. A card never includes a diff, a file body or a test body;TestCardCarriesNoCoderenders every fixture and refuses a fence, adiff --gitline or a path with a line number. Withheld until the judgement is saved, though copied into the item file at the draw: the validators' verdicts the pull request body carries, the drain judge's reason on a judgement item, the gate'sWhyon a merge-gate item, and any reviewer's verdict;showandnextleave them out and the card saysverdicts: shown after you judge. - The sitting.
abcd spotcheck review [--as facilitator|human-facilitator|product-thinker](the role defaults from the mode file and is asked when unset) makes one fetch of the branch and the default branch, then walks the queue in window order, oldest cycle first, group order within a cycle, item order within a group, for the role's unjudged slots. Each item is put throughquestion.Askwith the card asMaterial, the one question for its group (Does the outcome match its spec?,Was the drain right to hand this back?,Was the decision right under its rule?,Does what came back match the intent?) and the optionssound,wrongand the decide-later option, a typed line forwhyonwrong; in a terminal throughask.Terminal.Put, one key per item; in a host session the page has the agent renderspotcheck next --json --as <role> [--batch N]and put the same question through the host's tool, then record the answer withspotcheck judge <item> sound|wrong --why "<text>" --as <role>. Both routes end in the same judgement file (verdict,why,role,answered_in,at,state_now, the issue id onwrong), committed and pushed as it is made, so a sitting stopped at any item resumes at the first unjudged slot with nothing to restore.latermoves the item to the end of this pass and writes nothing. A progress line readsitem 37 of 112, cycle 3 of 9. After each saved judgement the withheld verdicts print, one line each, and the next card is already read. - A finding files an issue; abcd never edits the rule. On
wrong,spotcheckcallscapture.CapturewithSource: review-followup,FoundDuring: spot-check <cycle-id>,FoundAtthe admitting rule's file (the drain rule record for a drain item,.abcd/config.jsonfor an automatic merge or a merge-gate decision),Textnaming the item, its group, its cycle, the rule by id and the person's words, severityminorunless the person raises it, categoryprocess, and aRemedythat opensWaits on <rule id>: <the person's why>. That opening is whateligibilityhands back underRuleWaitsOnRuling(eligible.go:158), so no drain can take the issue and rewrite the rule;TestFindingIsNeverDrainEligiblerunsPlanDrainover such a record. The issue's id is written into the judgement. - The closing statement.
abcd spotcheckbare andspotcheck cyclesrender each cycle: per group,drawn n of N, judged j, findings k, and for a group withj = nandk = 0:rules out a failure rate above about one in r (95%),r = round(1 / (1 - 0.05^(1/n))), which is one in four at ten, and in words what it cannot rule out: a lower rate, and theN - nitems not read. A group with no items saysnothing drawn: no items in the window. No render ever saysno problems;TestStatementNeverSaysNoProblemsholds the phrase out of every fixture. - The board and the verb's surface.
boardOutputgainsSpotCheck{Waiting, ByRole, OldestDays, Unpushed, Due}computed from the branch as last fetched (disk only, nothing fetched), andboardRowsaspot-checkrow:37 wait (facilitator 30, product thinker 7), oldest 41 days; the product view adds one line when items wait for the product thinker;--jsoncarries it.Duesays the window has passed and no landing has been observed since. The verb is new and top-level,abcd spotcheck, with sub-verbsreview,next,judge,show <item>andcycles: no existing verb's documented meaning holds a review queue people work across months (reflectis one release's interview,labone snapshot,statusthe hour's announcements,landingsa read-only listing), and a sub-verb oflandordrainwould put the reader's verb under a writer's. It lands with its brief row (41,04-surfaces/README.md), its chapter04-surfaces/42-spotcheck.mdwith the## Sub-verbstable, its pagecommands/spotcheck.md(blockpeople), its sentence in theinternal/core/surfacemanifest, the regenerated snapshot, and thespotcheckblock in05-internals/03-configuration.md. Invariant 7 gains the branch's fetch and push forspotcheck, and the beacon fetch and branch push forland,drainandimplement step. - Nothing waits for the queue.
spotcheckexports toloopandlandingonlyAfterLanding, the two record writers of approach 2, and nothing that returns a hold, a count or a boolean;mergeGate,DrainJudging,RunningUnattendedand the away mode'sJudgeare untouched.TestNothingWaitsForTheQueuelands a lane and plans a drain over a branch holding ten thousand unjudged items and asserts the same outcomes and no read ofitems/orjudgements/. - A model other than the writer's reviews every change. Before a validator is dispatched (
loop/validate.go:594,:1003), the loop compares the implementer's reported model (ReceiptRecord.Model, or itsRoute.Model) with the reviewer's resolvedReviewClass.Model, bymatrix.sameModel's normalisation; on a match it takes the next class inBundledClasseswhose model differs, and when none does the lane hands back asstuckwith the reasonno reviewer model other than the writer's. A host-run validator's return must name its model, as the implementer's receipt does; a return naming none is treated as the writer's.ValidatorRungainsWriterModelandReviewerModel, the lane receipt and the composed pull request body name both, andrenderReview(cli/build.go:540) shows them.
How each criterion is met
- Seeded from a public value, stored, every item a chance, recomputable. Approaches 1 and 4. Tests:
TestDrawIsDeterministic(same cycle file, same list, across two runs and a shuffled population),TestEveryItemCanBeDrawn(over many fake randomness values every key of a 50-item group is drawn at least once),TestBeaconUnreachableWritesNothing(a refusing fake beacon: no cycle file, no item, the landing'sMergedstill set and exit 0),TestBeaconVerify(the round-1000 vector verifies under the pinned key and yields its published randomness; the same signature against round 1001 fails),TestBeaconBadSignatureWritesNothing(a fake beacon serving a round with a signature that does not verify, and one naming another chain hash: no cycle file, no item, one line naming the beacon and the round, the landing'sMergedstill set and exit 0). - Groups, ten by default, half after three clean, full after a finding. Approaches 3 to 5. Tests:
TestFourGroupsFromTheirSources(rows classeddrainandautomaticand the branch'shandbacks/anddecisions/files; aperson-approvedrow never drawn),TestSizeHalvesAfterThreeClosedCleanCycles,TestSizeFullAfterAFinding,TestOpenCycleCountsAsNeither,TestPerGroupBounds(0, 101 and a string refused with the key named). - Never code; the right thing beside each item; verdicts after the judgement. Approaches 6 and 7. Tests:
TestCardCarriesNoCode,TestCardPerRole(facilitator sees spec and outcome or rule and decision, product thinker sees the intent, human facilitator sees only decision items a model took),TestVerdictsShownOnlyAfterJudging(the rendered card lacks the verdict text; the post-judgement text holds it). - A finding files an issue naming item, group and rule; abcd never edits the rule. Approach 8. Tests:
TestWrongFilesAnIssue(the record names all three and the person's why),TestFindingIsNeverDrainEligible. - A clean cycle states what it rules out, never "no problems". Approach 9. Tests:
TestStatementAtTen(one in four),TestStatementAtFive(one in two),TestStatementNeverSaysNoProblems,TestEmptyGroupStatesNothingDrawn. - The window passes at a landing; otherwise nothing is drawn. Approach 3. Tests:
TestWindowByDays,TestWindowByChanges,TestWindowNotPassedDrawsNothingAndFetchesNothing(the zero-network harness),TestFirstCheckOpensTheWindow,TestThreeObservingSites(lane landing, land re-run, drain move each call once). - Nothing autonomous waits for the queue. Approach 11. Test:
TestNothingWaitsForTheQueue. - Items keep across months, ordered by window and group, stop and resume anywhere. Approaches 1 and 7. Tests:
TestQueueOrderOldestFirst(nine cycles, four groups),TestResumeAtFirstUnjudged(a sitting quit at item 37 resumes there, judgements intact on the branch),TestNoItemExpires(a two-year-old item still listed). - A late item shows then and now; its finding is filed like any other. Approaches 6 and 8. Tests:
TestCardThenAndNow(reverted, changed again, issue since resolved),TestLateFindingFilesAgainstItsRule. - Only fully reviewed windows count towards the halving. Approach 5. Tests:
TestOpenCycleCountsAsNeither,TestSizeCountsClosedCyclesInWindowOrder. - The board says how many wait, for whom, how old. Approach 10. Tests:
TestBoardSpotCheckRow(text, markdown,--json),TestBoardReadsTheBranchFromDiskOnly. - Hand-backs per pull request in the drain summary. Approach 2. Test:
TestDrainSummaryHandBacksPerPullRequest(two pull requests with one and zero hand-backs, three with none; text and--json). - A model other than the writer's, both named. Approach 12. Tests:
TestReviewerDiffersFromWriter(same model served: the next class is taken; the state names both),TestNoOtherModelHandsBack(one model only:stuck, reason named),TestHostValidatorMustNameItsModel.
Out of scope, recorded elsewhere: The landing classes, the admitting evidence written into history, the landings reader and the revert trace (itd-2610301850454860, which this spec reads and does not build; its landings.List honours the caller's context, so the draw passes its own deadline and refuses past it, while landing.ForgeTimeout bounds each forge call and the reader's per-pull-request cache keeps a window's second read cheap); the merge gate's table itself (itd-2610150602547271, shipped; this spec records its answers and changes none); a draw on a timetable (itd-13); a by-hand draw (ruled out by decision 3); the verification ladder (itd-173); the autonomy grant's report (itd-2610240850336695).
Footprint
- packages: internal/core/spotcheck/store.go, internal/core/spotcheck/window.go, internal/core/spotcheck/beacon.go, internal/core/spotcheck/draw.go, internal/core/spotcheck/groups.go, internal/core/spotcheck/size.go, internal/core/spotcheck/card.go, internal/core/spotcheck/judge.go, internal/core/spotcheck/statement.go, internal/core/spotcheck/config.go, internal/core/claim/remote.go, internal/core/implement/loop/drain.go, internal/core/implement/loop/drain_decide.go, internal/core/implement/loop/handback.go, internal/core/implement/loop/land.go, internal/core/implement/loop/validate.go, internal/core/implement/loop/reviewset.go, internal/core/implement/loop/state.go, internal/core/implement/loop/receipt.go, internal/core/landing/land.go, internal/core/landing/prbody.go, internal/core/board/board.go, internal/core/surface/manifest.go, internal/surface/cli/cli.go, internal/surface/cli/spotcheck.go, internal/surface/cli/board.go, internal/surface/cli/board_view.go, internal/surface/cli/drain.go, internal/surface/cli/build.go, commands/spotcheck.md, commands/drain.md, commands/land.md, commands/build.md, commands/implement.md, .abcd/development/brief/04-surfaces/README.md, .abcd/development/brief/04-surfaces/42-spotcheck.md, .abcd/development/brief/04-surfaces/35-drain.md, .abcd/development/brief/04-surfaces/38-land.md, .abcd/development/brief/04-surfaces/27-implement.md, .abcd/development/brief/02-constraints/03-invariants.md, .abcd/development/brief/05-internals/03-configuration.md, .abcd/development/release/surface.json, go.mod, go.sum, ACKNOWLEDGEMENTS.md
- tests: internal/core/spotcheck/store_test.go, internal/core/spotcheck/window_test.go, internal/core/spotcheck/beacon_test.go, internal/core/spotcheck/draw_test.go, internal/core/spotcheck/groups_test.go, internal/core/spotcheck/size_test.go, internal/core/spotcheck/card_test.go, internal/core/spotcheck/judge_test.go, internal/core/spotcheck/statement_test.go, internal/core/spotcheck/config_test.go, internal/core/implement/loop/drain_handbacks_perpr_test.go, internal/core/implement/loop/drain_spotcheck_records_test.go, internal/core/implement/loop/land_spotcheck_test.go, internal/core/implement/loop/validate_other_model_test.go, internal/core/landing/land_spotcheck_test.go, internal/surface/cli/spotcheck_surface_test.go, internal/surface/cli/board_spotcheck_test.go, internal/surface/cli/drain_counts_surface_test.go, internal/surface/cli/build_reviewset_surface_test.go
Steps
- The store, the drain's hand-backs and judgements and the merge gate's decisions recorded as they happen, with hand-backs per pull request in the summary
- packages: internal/core/spotcheck/store.go, internal/core/claim/remote.go, internal/core/implement/loop/drain.go, internal/core/implement/loop/drain_decide.go, internal/core/implement/loop/handback.go, internal/core/implement/loop/land.go, internal/core/landing/land.go, internal/surface/cli/drain.go, commands/drain.md, .abcd/development/brief/04-surfaces/35-drain.md
- tests: internal/core/spotcheck/store_test.go, internal/core/implement/loop/drain_handbacks_perpr_test.go, internal/core/implement/loop/drain_spotcheck_records_test.go, internal/core/landing/land_spotcheck_test.go, internal/surface/cli/drain_counts_surface_test.go
- The window, the beacon and the draw at the three observing sites. This step waits for itd-2610301850454860 to ship, since its reader supplies two of the four groups; steps 1 and 4 do not. It opens by adding the one dependency (
go get github.com/cloudflare/circl@v1.6.5, thengo mod tidy), reports every line added togo.modandgo.sum, and runsTestBeaconVerifybefore anything else is written, so a vector that fails stops the step at once; theACKNOWLEDGEMENTS.mdentries for circl and drand land in this step's change.- needs: 1
- packages: go.mod, go.sum, ACKNOWLEDGEMENTS.md, internal/core/spotcheck/config.go, internal/core/spotcheck/window.go, internal/core/spotcheck/beacon.go, internal/core/spotcheck/groups.go, internal/core/spotcheck/draw.go, internal/core/spotcheck/size.go, internal/core/implement/loop/land.go, internal/core/implement/loop/drain.go, internal/core/landing/land.go, commands/land.md, commands/build.md, commands/implement.md, .abcd/development/brief/04-surfaces/38-land.md, .abcd/development/brief/04-surfaces/27-implement.md, .abcd/development/brief/02-constraints/03-invariants.md, .abcd/development/brief/05-internals/03-configuration.md
- tests: internal/core/spotcheck/config_test.go, internal/core/spotcheck/window_test.go, internal/core/spotcheck/beacon_test.go, internal/core/spotcheck/groups_test.go, internal/core/spotcheck/draw_test.go, internal/core/spotcheck/size_test.go, internal/core/implement/loop/land_spotcheck_test.go, internal/core/landing/land_spotcheck_test.go
- The review lane: cards, the sitting, judgements, findings and the closing statement, through
abcd spotcheckand its page- needs: 2
- packages: internal/core/spotcheck/card.go, internal/core/spotcheck/judge.go, internal/core/spotcheck/statement.go, internal/core/surface/manifest.go, internal/surface/cli/cli.go, internal/surface/cli/spotcheck.go, commands/spotcheck.md, .abcd/development/brief/04-surfaces/README.md, .abcd/development/brief/04-surfaces/42-spotcheck.md, .abcd/development/release/surface.json
- tests: internal/core/spotcheck/card_test.go, internal/core/spotcheck/judge_test.go, internal/core/spotcheck/statement_test.go, internal/surface/cli/spotcheck_surface_test.go
- A model other than the writer's reviews every change, both named
- packages: internal/core/implement/loop/validate.go, internal/core/implement/loop/reviewset.go, internal/core/implement/loop/state.go, internal/core/implement/loop/receipt.go, internal/core/landing/prbody.go, internal/surface/cli/build.go
- tests: internal/core/implement/loop/validate_other_model_test.go, internal/surface/cli/build_reviewset_surface_test.go
- The board's row, and the proof that nothing waits for the queue
- needs: 3
- packages: internal/core/board/board.go, internal/surface/cli/board.go, internal/surface/cli/board_view.go
- tests: internal/surface/cli/board_spotcheck_test.go, internal/core/implement/loop/land_spotcheck_test.go
Frontmatter
| id | spc-2610301925429250 |
|---|---|
| type | spec |
| lifecycle | open |
.abcd/development/specs/open/spc-2610301925429250-a-person-spot-checks-what-abcd-s-agents.md
open on GitHub ↗ · commit history ↗
References1
- itd-2610301750162657abcd's unattended work is spot-checked against specs and intentsimplements
mentions6
- itd-13Reviews and Memory Stay Fresh, Always
- itd-173Verification escalates from the built-in check to an outside audit, and the product thinker picks the rung
- itd-2610150602547271The facilitator's mode gates the merge
- itd-2610240850336695The person grants their sessions what they may do alone, until a time
- itd-2610301850454860abcd records how each change landed
- spc-2610301950480609abcd records how each change landed