HOMELAB-1938: docs(ld5): B10 spike register — Plane actor probe result, S1/S15 prep, S12 dependency #13
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "plane/HOMELAB-1938-spikes"
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?
Adds
design/ld5/for LD5-B10's four spikes. Docs only, no code.spikes.md— the register. Only one spike was answerable today.Plane actor spike: ANSWERED (yes). The API does return who moved a ticket and
from/to which state, via an endpoint the public docs do not list:
GET .../projects/{pid}/work-items/{wid}/activities/→ per-transition entries withverb,field,old_value,new_value,actor(member UUID, resolved against.../projects/{pid}/members/). 5/5 transitions recorded for a scratch ticket(HOMELAB-2204, created → Todo → In Progress → Blocked → Cancelled) with sub-second
freshness.
work-items/{id}/exposes onlycreated_by/updated_by; comments andplane_get_itemexpose no actor at all.The 429s turned out not to be our own rate: 25-parallel and 50-sequential bursts
both returned 100% 200, while one early 20-request burst got 5×429 and the pi tools
got 2 at session start. The limiter is a token bucket keyed on the API key, and
every workstation session shares one key (
claude-agent), so the 429 rate is afunction of fleet-wide concurrency on one identity.
x-ratelimit-remaining(freshwindow: 40) is present on 200s but absent on 429s, which stall ~1 s rather than
fast-failing. Two consequences recorded: self-throttle on the header, and treat actor
attribution as an identity problem — B2's "signer account with no API token" ruling is
load-bearing, and the record DB (B5), not Plane, is the proof.
spike-s1-token.md— PREP ONLY. Rotation is the decisive leg: the operator rulingon HOMELAB-2007 makes the quarterly cadence conditional on S1 proving old tokens die,
so the procedure polls the old token on a schedule and reports a kill window, not
"instant". Plus the environment-exposure checklist (
/proc/*/environby name, nevervalues). Blocked on B2 + the operator, because it rotates their token.
spike-s15-cost.md— PREP ONLY. Records why the requested model is not theanswer (combos resolve at request time; served connection sets the price). Verified
today that
pi_agent_tokens_totalexists withllm_model/sandbox_env/subagent_outcomelabels, but OmniRoute has no Prometheus job and
/metricsis 401 — so served-modeland per-connection spend are not collected anywhere yet. Blocked on B2 + B9.
S12 — checklist entry only; the workflow validator it is scored against is built on
the E3 knob schema, so scoring it earlier measures a moving target.
Origin: HOMELAB-1938 / LD5-B10, epic HOMELAB-2194.
Landing review — APPROVE (no blockers)
Reviewer context: fresh, not the implementer. Sources: this diff only, HOMELAB-1938 (description + findings comment), the HOMELAB-2007 ruling comment,
design/README.md+design/where-we-are/next.htmlonmain, plus two live re-probes of the PR's own claims.Verdict per dimension
spike-s1-token.md:70-105polls the old token on a fixed ladder (t+0 … 24 h, then daily to 7 d), stops at the first hard rejection, and reports a kill window as an interval (last-good / first-bad), explicitly forbidding "instant" unless two adjacent probes prove it. The result template carrieskill window:andcadence ruling input:fields. Distinguishing a revocation from a usage-limit refusal is called out as a failure mode (:100-104). That is exactly the measurement the ruling conditions the quarterly cadence on.spike-s15-cost.md:17-30). I re-verified its two factual claims myself:pi_agent_tokens_totalexists in Prometheus withllm_model/sandbox_env/plane_ticket_id/subagent_type/subagent_outcome(sandbox_env="unbound"today, as written), and OmniRoute has no Prometheus job (count by (job) (up{job=~".*omni.*"})→ 0 series) with/metrics→ 401 (confirmed by unauthenticated curl). The "not collected anywhere yet" prerequisite is stated as a prerequisite, not papered over, and the doc forbids reporting $0.00 for invisible quota (:85-87).spikes.md:124-134records only the checklist and the consequence ("if it fails, the planner is switched off").next.htmlonmaincorroborates the dependency verbatim: "the knob schema is frozen. If kimi fails it, the planner is switched off."PREP ONLYin frontmatter, table, and body; nothing is claimed as run. The rotation risk to the operator's own token is stated three times and unambiguously (spike-s1-token.md:27-41"kills the operator's working token … cannot be run opportunistically or by an autonomous worker";spikes.md:105-109; plus the scratch-slot requirement). The only executed spike (Plane actor) is corroborated: I re-ranGET …/work-items/580f998f-…/activities/on scratch ticket HOMELAB-2204 and got 5 entries (1created+Backlog→Todo→In Progress→Blocked→Cancelled), actor401b58dc…on all five, and the quoted example entry (In Progress → Blocked,05:31:20.072118Z) matches byte-for-byte. The B2 claim inspikes.md:96-99matchesnext.html: "signer account: browser only, with MFA and no API token."design/ld5/spikes.md,spike-s1-token.md,spike-s15-cost.md), 387 lines, no other paths, anddesign/ld5/is a new subdirectory of an existing docs tree./work-items/{IDENT}/PATCH-403 trap, and — the part that actually changes the build — the 429 analysis: token bucket keyed on the shared API key (x-ratelimit-remaining: 40, absent on 429, ~1 s stall rather than fast-fail), self-throttle with reserve ≥ 10, and "attribution is an identity problem, not a logging problem" with the record DB (B5) as proof and Plane as mirror (spikes.md:58-100). Two consequences land correctly for B2 and B5.Concerns (non-blocking — fix in a follow-up, do not hold this PR)
spikes.md:52— "5 of 5 state transitions" is one off: the feed holds 5 activity entries, of which one isverb: createdand four are state transitions (verified above). Say "5 of 5 activity entries (1 creation + 4 transitions)" so B2 does not later treatcreatedas a transition with an actor/signer.spikes.md:108— "step 4 of the procedure" rotates the token; inspike-s1-token.mdthe rotation is Leg 2 step 3 (Mint B); step 4 is "prove B works". One-word fix, but it is the leg whose sequencing matters.spike-s1-token.md:79— the middle outcome row ("keeps working for hours/days → … quarterly gains little → yearly + on exposure stands") pre-judges the call. On a strict reading of 2007, a multi-hour kill window does prove old tokens die, so the cadence is the operator's to rule. Suggest keeping the row to the measurement and its implication ("rotation is a delayed, not immediate, revocation control"), leaving the ruling to thecadence ruling input:field the template already has.spike-s15-cost.md:47,82— "$ per node … priced at the served connection's rate" never names where the rate (or a gateway-computed cost) comes from. Add one row: gateway-reported cost if the usage endpoint exposes it, otherwise a rate card committed with the findings (with its date). Without that, step 5 is not reproducible by a second worker.design/README.mdonmainindexes the design tree by folder and does not mentionld5/. A one-line addition would keep the new folder discoverable — deliberately out of this PR's stated scope, so follow-up.Merging per landing convention (docs-only, non-dangerous, no open blockers).
Merge outcome — blocked by the landing lock (needs a UI merge)
I attempted the merge and it was refused:
Not a defect in this PR.
.forgejo/workflows/ci.yamltriggers onpull_request: branches: [live], and this PR targetsmain, so no run is ever recorded and the lock fails closed on a docs-only change. There is no override parameter by design (HOMELAB-1679) — a human merges from the Forgejo UI.Review verdict stands: APPROVE, no blockers, concerns in the comment above are follow-ups. Nothing in the diff needs to change before merge.
View command line instructions
Checkout
From your project repository, check out a new branch and test the changes.Merge
Merge the changes and update on Forgejo.Warning: The "Autodetect manual merge" setting is not enabled for this repository, you will have to mark this pull request as manually merged afterwards.