HOMELAB-1730: feat(routines): LD4.8 agent-readiness score (R-24) #576
No reviewers
Labels
No labels
operator-review
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
Homelab/infra-core!576
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "plane/HOMELAB-1730-readiness"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
LD4.8 · agent-readiness score. Lands the already-reserved R-24 (not a new id). Brief:
.rpiv/artifacts/epic-ld4/design-LD4.8-readiness.md; orchestrator rulings on HOMELAB-1730 supersede it where they differ.Head:
8597d0e, rebased ontoepic/LD4(13 commits, incl. R-25/HOMELAB-1729 and the LD4.5a alert audit) so the PR is mergeable; the pre-rebase head reviewed wasf18f3b8. Landing-review fixes:b639d1a(fan-out + budget),2d9e34b(adapter tests),4af920d(clean calibration target + cost evidence),8597d0e(gofmt). Rebase conflicts were the registry/census hunks and are resolved to the merged totals: 22 corpus routines + R-24 (active, HOMELAB-1730) + R-25 (paused, HOMELAB-1729) = 24 registered, 4 active.What is in here
routines/readiness.yamlroutines/readiness_definition.go+_test.goroutines/readiness_probes.goroutines/readiness_workflows.goroutines/readiness.goroutines/readiness_digest.goroutines/readiness_{signals,git,forgejo}.go+readiness_{forgejo,git}_test.gocmd/readinesstargetfield (additive onld.routine.run/v1)routines/ledger.go+_test.goroutines/registry.yamlroutines/testdata/readiness-calibration.md+testdata/readiness-calibration/Seven lines per the ruling:
ci_present,ci_green,test_inventory,docs,lint,agent_context,dev_env(advisory v1). Floor: weakest line,never_below [ci_present, test_inventory],min_lines_passed 5of 6 counted.dev_envdeclarescounts: falseand is named infloor.advisory(the loader requires the two statements to agree, not to be duplicated in one place).Verify line 1 — calibration (scar, below-floor, clean)
Full evidence in
routines/testdata/readiness-calibration.md; reports + trimmedGET /actions/runsdumps are committed so the run is re-derivable offline.SEND-437-class —
Sendrast/api-sendrast @ 968c0cb→below-floor(reproduces exactly):main(derived from the workflows' ownon:blocks)success— newest run for the sha (ci.yml, push, main, run #552)(untagged) 119/132 (90%),functional 1/1,integration 9/74 (12%)docs/, 634-line README.forgejo/workflows/ci.yml(matchedvet) greenAGENTS.md/CLAUDE.md/spec treescripts/sim_reset/sandbox/docker-compose.ymlGreen gate over an invisible test class — the scar, mechanically. A blended file ratio says 90% executed; the per-class floor is what makes the invisible class visible.
CLEAN —
Sendrast/sendrast-web @ aa500803→ready(6/6). Added toroutines/readiness.yamland R-24'stargets.pathsper the orchestrator's calibration ruling: the Verify line needs the healthy direction, otherwise the calibration only shows the mechanism reddening a sick repo.main(.forgejo/workflows/ci.yml)success— push run for the scored sha (ci.yml, push, main, run #552)(untagged) 151/151 (100%)docs/, 238-line README.forgejo/workflows/ci.yml(matchedlint) has a successful runAGENTS.mdat the repository rootThe ruling's named repo does not exist.
Homelab/lab-director-contractreturns HTTP 404 on the live instance (and is absent from the token's repo list); the checkout named~/repos/lab-director-contractis a clone ofaaron/lab-director, which scores 1/6below-floorat bothf2e16ae(the contract-only state) and currentmain(no gate, no README, no tests — andci_presentisnever_below, so no contract-only repo can pass by construction). Recorded with evidence in §4 of the calibration doc; it was not forced green and not added to the scored scope.Sendrast/sendrast-webis the clean target instead."Clean" side in the ruled scope —
Homelab/infra-coredoes NOT reproduce the brief's expected verdict. At1519dd2(this branch's merge base):below-floor(3/6) —ci_greenfails (no run exists for the merge sha; the newestlivepush run was adocs-buildfailure),docsfails (80 files underdocs/but no repo-rootREADME.mdat all),agent_contextfails (noAGENTS.md;CLAUDE.md+INFRA_CONTEXT.md= partial). At the PR headb5a806a(run #568 green) the same tree is 4/6 with the same two non-CI failures. Details and the three independently checkable reasons are in the calibration doc.Systematic finding (for the architect / window two): merge commits on
livecarry no gate run — the gate runs on the PR head — so every three-tier repo's latest merge revision reads as ungated. The report now names the newest gate-branch run as evidence + a finding rather than a bare "no run". The ruling already made window one REPORT-ONLY, which is exactly the window that measures how often this fires.Homelab/prod @ f006b26(override exercised):below-floor(2/4 counted) — override works (test_inventory/docsadvisory,never_belownarrowed to[ci_present], printed in the digest asneverBelowNarrowed), butci_green(merge commit) andagent_contextfail.Cost (landing-review blocker 2)
v1 read one
GET /raw/{path}per test file, so cost was linear in the repo's test count and undeclared. The fix, measured live on this branch's build:Homelab/infra-coreSendrast/api-sendrastHomelab/prodFile()is served from the revision tarball, materialized by oneGET /archive/{rev}.tar.gz; the raw endpoint is a bounded fallback only (archive disabled, gitlink).TestForgejoSignalsFileCostIsConstantInTheFileCountpins it: reading 120 files costs the same as reading 2.?head_sha=<rev>and?head_branch=<gate>&event=push&page=1&limit=<n>— because the endpoint ignoreslimitwithout a filter and otherwise returns the whole history (612 runs / ~10 MB / ~20 s oninfra-core). Both cached;RunsOnBranchreachesprobeContext.runs()through the new optionalBranchRunSourceseam and the windows are merged by identity.ForgejoSignals.MaxRequests(default 16) is a hard stop that fails LOUDLY withForgejoRequestBudgetError, so a re-introduced fan-out cannot silently spend the routine's window. The adapter refuses an unfiltered runs read outright.cmd/readinessprints wall time and GET count per target, so cost is observed by the run rather than by a reviewer.Eight targets on this build is roughly two minutes of R-24's
maxDurationSeconds: 900(>7× margin).Deviations from the brief (all deliberate, all visible)
Homelab/infra-coreandHomelab/prodrun every gate onliveand receive zero CI runs onmain; scoringmainwould report "no run" for repos whose gate is green on every landing. Resolution order: definition override → branch most workflows trigger on (derived from primary sources) → default branch. Both three-tier repos nameliveexplicitly in the definition as well. The digest prints the branch and its source, and the divergence from the default branch is a finding.test_inventoryis per-class, not blended. The brief's formula (ran_by_ci / awith packages over files) is unit-inconsistent and, applied to the real data, passes the very revision it was written to catch (go test ./...really does run 90% of api-sendrast's files). The rule implemented: a file is executed iff a gate step references its package, its-tagscover the file's build tags, and any-runfilter matches a test function parsed out of the file; files are grouped by build-tag class and every class must be ≥test_class_min_ratio. This is the brief's own-runmechanism, made to actually fire.lintdoes not read job detail. Forgejo v14.0.3 has no/actions/runs/{id}/jobsendpoint (verified live: 404). The line uses the workflow file's own lint vocabulary plus that workflow's run status; the narrowing is stated in the definition'sdetail. The newest gate-branch run is read from the bounded push window (blocker-2 fix), not from the repo's whole history.registry.yamlmakes the reverse check ("registered but not in the corpus table") fire. It now derives the hosted 4.x set fromtestdata/registry-4x-shapes.yamlinstead of listing it, so R-24 cannot claim an exemption the fixture does not grant.testdata/corpus-table.mdis untouched (R-01…R-22 stays closed at 22);TestRealRegistryLoadsexpects 23.targets.pathsgained one entry (Sendrast/sendrast-web, the clean calibration target) on the orchestrator's calibration ruling. The definition'stargets:list and the registry's authority are now asserted equal inTestRealDefinitionLoads, so they cannot drift.Pin discipline
routines -checkprints 23 routines, 4 active (R-03, R-06, R-19, R-24);TestInProcessPinsMatchTheCodeis green on the newsha256forreadiness.go. Known limitation, stated rather than hidden: the mechanism is a file set (readiness_probes.go,readiness_workflows.go,readiness_{signals,git,forgejo,digest}.go+ the data filereadiness.yaml); the LD4.4 pin test covers one file. Editingreadiness.goafter registration requires re-pinning R-24 — that is the routine's own anti-drift rule, and extending the pin to the whole set is queued as a follow-up rather than smuggled into this ticket.Shared files (minimal, as declared)
routines/registry.yaml— my R-24 entry only (siblings own R-25 and any 4.5a entry): the reserved-ids header comment, the "active today" count, and the R-24targets.pathsaddition above.routines/ledger.go— additiveRun.Target,ValidateFor/TargetRequired,RunFilter.Target. No v2 stamp, no transport change.routines/registry_test.go,routines/parity_test.go,cmd/routines/main_test.go— count/parity/census adjustments (the last derives the census and active set fromRegistry.Census()instead of hard-coding 22/3).config/keys needed; no dispatcher/spawn changes (enforcement is HOMELAB-1857).Window policy
emitsWork: falseandRepairRefs(..., emit=false)— report-only, per the ruling. Window two flipsemitsWork: truewithemits: [R-07]so thereadiness-repair:tickets are visible to the entropy sweep; the dedup convention (blocked_byon the epic's first builder ticket) is documented as a human/agent act today, never as enforcement.Tests
go test -race ./...andgo vet ./...green inlab-director/dispatcher. No test opens a real socket.routines/readiness_forgejo_test.godrives the live adapter against anhttptestfixture and asserts the request shape (one archive request for N files, zero raw reads, filtered/bounded runs windows, the budget stop, error/redaction paths);routines/readiness_git_test.godrives the offline seam against a real temp git checkout (revision pinning,RunsFromFiledecoding, the branch-window merge) plus thehttptest-free fixture paths.Landing review blocker 2 (undeclared API fan-out): the adapter read one GET /raw/{path} per test file, so cost was linear in the repo's test count (207 files ~= 5 min against R-24's 900 s window). - File() is now served from the revision tarball, materialized by ONE /archive/{rev}.tar.gz request; the raw endpoint survives only as a bounded fallback (archive disabled, gitlink). - Runs are two bounded, filtered windows (the endpoint ignores limit without a filter): head_sha=<rev> and head_branch=<gate>&event=push. Both cached. - MaxRequests hard stop with a loud ForgejoRequestBudgetError. - BranchRunSource + probeContext.runs() merge the gate-branch window. - cmd/readiness reports per-target wall time + GET count on stderr.Fix worker — both blockers closed + calibration ruling applied
Commits on
plane/HOMELAB-1730-readiness:0433c8d(fan-out + budget),b88313b(adapter tests),bf29298(clean calibration target + cost evidence). PR body corrected to state only what the diff proves.go test -race ./...+go vet ./...green inlab-director/dispatcher.Blocker 1 — phantom adapter tests → CLAIM NOW TRUE (or removed where infeasible)
There were no adapter tests; now there are, and they assert the request shape, not just decoded output:
routines/readiness_forgejo_test.go— scriptedhttptestForgejo fixture: one archive request for N files / zero raw reads, cost-constant-in-file-count (TestForgejoSignalsFileCostIsConstantInTheFileCount: 120 files cost the same as 2), archive→raw bounded fallback, filtered+bounded runs windows with caching, refusal of an unfiltered runs read, typed 404 / 5xx-retried-once / decode / no-base-URL error paths, credential redaction of error bodies ([redacted], token never leaks), the request-budget stop,RevFor, target, tar prefix strip + oversize refusal.routines/readiness_git_test.go— real temp git checkout: revision pinning (tree/file at-rev), bad-rev failure,Runs()requires a source (unevaluated, never a pass),RunsFromFiledump decoding,BranchRunSourcemerge/de-dupe + degraded-window-as-finding.httptestclaim is now accurate; the false "nocmd/routineschanges" line was removed (cmd/routines/main_test.gois in the diff — it is listed in Shared files).Blocker 2 — undeclared API fan-out → batched, bounded, budgeted
File()is served from the revision tarball, materialized by oneGET /archive/{rev}.tar.gz; raw is a bounded fallback only. Runs are two filtered windows (?head_sha=<rev>,?head_branch=<gate>&event=push&page=1&limit=<n>— the endpoint ignoreslimitwithout a filter and otherwise returns the whole history: 612 runs / ~10 MB / ~20 s on infra-core). Both cached.MaxRequests(default 16) fails loudly withForgejoRequestBudgetError.cmd/readinessnow prints per-target wall time + GET count.Homelab/infra-coreSendrast/api-sendrastHomelab/prod(GETs: branch resolve, 3 tree pages, archive, revision runs window, gate-branch window.) Eight targets ≈ 2 min of the 900 s window — >7× margin, and a re-introduced per-file read hits the budget instead of the window.
Calibration ruling — the named repo does not exist; a real clean target does
Homelab/lab-director-contract→ HTTP 404 on the instance (absent from the token's repo list). The checkout named~/repos/lab-director-contractis a clone ofaaron/lab-director, which scores 1/6 below-floor at bothf2e16ae(contract-only state) and currentmain— no gate, no README, no tests, andci_presentisnever_below, so no contract-only repo can pass by construction. Not forced, not added to the scope.Sendrast/sendrast-web @ aa500803→ready(6/6) — ci.yml gatesmain, green push run for the scored sha,151/151 (100%)test files executed, 4 docs files + 238-line README, lint gate green,AGENTS.mdat root. Added toroutines/readiness.yamland R-24targets.paths(scored every window as the healthy control);TestRealDefinitionLoadsnow also asserts the definition's target list cannot drift from the registry's authority. Report + trimmed runs dump committed.Homelab/pi-extensions @ 93a0b5bbba67→ready-with-concerns(5/6, onlyagent_context), measured read-only.routines/testdata/readiness-calibration.md+ PR body updated (§3 clean target, §4 the 404, §6 cost).Not merging — landing decision stays with the pipeline. Re-review me on head
bf29298.Head is now
071fac2(addsgofmtoncmd/readinessafter the cost-telemetry edit; no behaviour change —gofmt -lclean, build + vet green). Everything in the previous fix-worker comment stands unchanged; re-review me on071fac2.071fac28148597d0e945Rebased onto
epic/LD4— PR is now mergeableCI run #1725 on head
8597d0eis green (all four jobs).mergeable: true(wasfalse: the branch was 13 commits behindepic/LD4).dep:routine-executor, HOMELAB-1729) = 24 registered, 4 active.registry_test.go: keptepic/LD4's derived floor plus R-25's shape assertions, raised the floor to 24 (was!= 23).parity_test.go: merged both intents — ids < R-23 must be in the corpus table; ids ≥ R-23 must be in the derived hosted-4.x fixture (fromtestdata/registry-4x-shapes.yaml) or name their owning ticket;hostedIDshelper retained.cmd/routines/main_test.go: kept the census count derived fromRegistry.Census()(no hard-coded total) and assertedR-24+R-25are present.registry.yamlheader reconciled: R-23, R-26, R-27 remain reserved.go test -race ./...+go vet ./...green across all 23 packages (incl.planfresh), calibration reports still byte-identical offline, and the clean target (Sendrast/sendrast-web @ aa500803→ready6/6) still in R-24'stargets.paths.Not merging — re-review me on
8597d0e.Landing review (delta re-review) — verdict: CLEAN, both blockers CLOSED
Posted by the orchestrator on behalf of the delta landing worker, whose own comment attempt fell victim to the aaron/-slug silent-drop documented earlier on #577. Review basis: the worker's full delta review of head
8597d0e(CI run #1725 green), completed 2026-10-02.routines/readiness_forgejo_test.go(640 lines) androutines/readiness_git_test.go(274) are real: one archive GET for N files, cost-constant-in-file-count, budget stop, redaction, error paths; PR body claims corrected to match the diff.Homelab/infra-core6.8 s / 7 GETs,Sendrast/api-sendrast20.1 s / 6 GETs (fix-worker claimed 11.9/7 and 19.0/6; GET counts exact, wall times same order) — ≤2% of the 900 s routine budget.routines -check= 24 routines, 4 active on the rebased tree; registry/parity/main-test conflicts resolved to merged totals.Sendrast/sendrast-web @ aa500803→ ready 6/6 verified; the ruled repo (lab-director-contract) 404 documented with evidence, not forced.No open blocker findings. Landing lock: CI green on head
8597d0e, this verdict posted after head, no blockers.