Part 1. Golden 0.208.0 baked on the drill VM, published and ROUND-TRIP VERIFIED — 656 150 362 B, sha256 ba668f59..5ffb82, and ./etc/felhom-controller-image read OUT of the downloaded archive says felhom-controller:0.208.0. Acceptance markers all green (overlay2 x1, mount points x2 rootfs+mp0, upload HTTP 201 x1, excluding/FATAL/mp1 x0), Result=success. Token file->file, read inside the VM; systemctl show grep = 0; committed-log grep = 0 WITH a control proving the grep works. Bake VM destroyed, drill disk restored to virgin. NOT VOUCHED — the campaign halts there deliberately. golden_currency_gate.py was correctly RED on arrival and is green after the bake. No --no-verify was needed anywhere in this session. Parts 2-4. Seven defect classes swept for siblings by class rather than by feature. Analysis only: no product code, nothing deployed, no machine touched beyond the bake VM. Eight new rows R-256..R-263 (ceiling moved from R-255), grouped by class in OPEN-ITEMS.md. C1 produced no new instance and has no row. The sharpest is R-260: the agent reports operator_key_configured every heartbeat, the hub has no field for it, so the check that answers "can the operator get into this box" returns ok for a box with no operator key installed. Every class states whether its method re-found the known instances, because a method that cannot re-find them has not been shown to work: C1 2/3 (verified by replaying the pre-fix templates), C2 2/2, C3 2/3 + 1 as fixed, C4 fix-pattern re-found, C5 re-found, C6 deadcode 0/2 and bespoke 1/2, C7 weakest and said so. Blind spots stated per class; seven suspicions investigated and DISPROVED, including two of my own methods. Part 4's ranking is in ROADMAP.md as G-1..G-8. Gate C5 (cross-repo tag reachability — cheap, --fast-eligible, would have caught every R-260 instance on the introducing commit). Do NOT gate C6: golang.org/x/tools/cmd/deadcode was measured against a PLANTED probe and is blind to unreachable METHODS on widely-used types, which is exactly the shape both known instances have. R-242's untouched half is recorded, not built: this bake demonstrated it, the currency gate flipping green the moment the evidence DIRECTORY existed, before the round trip finished and with no vouch near it. Correction the campaign owed its own brief: escrow_stale was described as closed; it is R-247 and READY. The live repo is the source. Sampled rather than swept, exactly: C7 60 of 2652 production invariant comments and NONE of the 1440 test comments (that half is owed); C2 19 of 221 refusals; C3/C4 controller only. No finding was reproduced live. STATUS.md is 100 lines against its 93-line one screen.
26 KiB
CAMPAIGN 12 — the class sweep (2026-08-08, unattended)
Look for the siblings of everything this arc found, by class rather than by feature. Nothing was fixed, nothing was deployed beyond Part 1's golden, and no machine was touched beyond the bake VM, which was torn down.
Baselines re-read on arrival, all three clean and equal to origin/main:
| Component | Version | commit |
|---|---|---|
felhom-controller |
released v0.208.0 | 37b5ba08a704 |
felhom-agent |
v0.127.0 | 703db166e762 |
| hub | v0.98.0 deployed | 59527d00f9c4 |
app-catalog-felhom.eu |
— | 459766c |
Highest register ID on arrival R-255; re-checked before minting, unmoved. This session opens R-256 … R-263.
1. The bake — and the one approval awaiting the operator
Golden 0.208.0 is baked, published and round-trip verified. It is NOT vouched. Full evidence:
documentation/tests/golden-0.208.0-2026-08-08/ (README + the 324-line bake.log).
| version | 0.208.0 (derived from the controller image, which is a required argument) |
| size | 656 150 362 B |
| sha256 | ba668f59f063511dda122a5b05900f1350573cdc9619980872f87a58755ffb82 |
| round trip | downloaded back from Gitea, hashed independently on DooPlex — size and sha identical |
| the delivered artifact's own claim | ./etc/felhom-controller-image read out of the downloaded archive → gitea.dooplex.hu/admin/felhom-controller:0.208.0 |
| fourth confirmation | the sha the hub's /configuration dropdown offers for 0.208.0 matches the bake exactly |
Acceptance markers, each grepped verbatim against the real log: docker OK (overlay2; data-root /var/lib/docker) ×1 · including mount point ×2 (rootfs and mp0, no mp1) · upload OK (HTTP 201)
×1 · excluding ×0 · FATAL ×0 · mp1 ×0. Result=success, ExecMainStatus=0.
Hygiene. The token was copied file → file and read from a 0600 file inside the VM by a
runner script; systemctl show golden-bake -p Environment -p ExecStart | grep -c -F <token> → 0.
The committed log greps 0 for the literal token, and the grep was shown to work first — the
same grep on a copy with the token appended returned 1, then the copy was shredded.
404 pre-gate with a control: …/0.207.0/golden.tar.zst → 200 (the URL shape is right),
…/0.208.0/golden.tar.zst → 404 (nothing to overwrite).
Teardown: pct destroy 9100 --purge, pct list empty; token/runner/script/log shred -u'd and
/root residue clean; poweroff; qemu confirmed gone via ps -eo comm | grep -c qemu-system-x86 → 0
(never pgrep -f, which self-matches); qemu-img snapshot -a virgin restored and the snapshot
list re-read.
⚠ THE ONE THING ASKED OF THE OPERATOR
Vouch golden 0.208.0 — hub → Configuration → Day-0 artifacts → Golden 0.208.0 → Save.
| field | now | after | why |
|---|---|---|---|
golden_version |
0.207.0 | 0.208.0 | the only field that moves |
agent_version |
0.127.0 | 0.127.0 | already ≥ MinAgent 0.127.0 — read from the controller CHANGELOG header, checked not skipped |
min_agent |
0.127.0 | 0.127.0 | equals the declared MinAgent; not above agent_version (the R-216 shape hub v0.97.0 holds) |
Vouching is reversible — re-select 0.207.0 and Save. The 0.207.0 package was not deleted (the publish step's pre-delete targets only its own version), so a rollback is a form submission.
Until that Save, a machine installed tonight still receives controller 0.207.0.
2. What golden is vouched, and the currency gate's state
- Vouched at the time of writing: golden 0.207.0, agent 0.127.0,
min_agent0.127.0,min_controller_version0.156.0 — read live from the hub, not from a document. golden_currency_gate.pywas RED on arrival (controller v0.208.0 is released and NO golden carries it) exactly as §1 of the task predicted, and is GREEN after the bake.- No
--no-verifywas needed anywhere in this session.
3. Per class — new instances, the control, the method, and its blind spots
C1 — a secret in a response body
New instances: 0 on the surface the class names (a response body a customer can fetch).
Control — the shipped gate re-finds 2 of the 3 known instances, measured not assumed. The three
pre-fix templates were restored from history (8dbbc98^) into a scratch copy of the controller and
scripts/secret_in_markup_gate.py was run against them. It convicted
settings_security.html:408, :430 and app_info.html:185, and did not convict
deploy.html:482 (value="{{$val}}") — R-255's stated blind spot, now verified by replay rather
than by reading its docstring. The gate passes clean over today's 36 templates.
Method (the new half). The shipped gate is name-based on the TEMPLATE side. This sweep is its mirror on the GO side: every assignment into template data, a JSON response map or a render struct whose right-hand side names a secret, regardless of what the key is called — the shape the gate cannot see. 27 sites matched; 5 under a key that does not itself announce a secret.
All 5 resolve to non-findings, and the reasoning is recorded in §6.
Blind spots. One hop only — a secret laundered through a neutrally-named local two or more hops from its source is invisible. Struct-literal page data is covered only in the field-assignment form. A secret fetched inside a helper the handler calls is invisible. And the whole sweep reasons about source, never about rendered bytes — the runtime body assertion remains the only check that catches all three known shapes, and it still covers 4 of 27 pages.
C2 — a refusal that names no route
New instances: 2 (R-256, R-257).
Control. The known instances (R-252, R-253) were re-read in their pre-fix form at 8dbbc98^ and
in today's tree. The method distinguishes them correctly: the pre-fix strings state a reason and stop
("nincs mentés felhasználói adattal"), and today's backups_restore.html:79 names the route —
„Meghajtók", „Meglévő meghajtó csatolása". Utána gyere vissza ide. 2 of 2 re-found, as fixed.
Method + what was SAMPLED. 221 distinct customer-visible refusal strings exist across the
controller's production code. This was NOT swept exhaustively. The sample is the three files on
the surface where both known instances lived — recovery_handlers.go, offbox_handlers.go,
restore_wizard.go — yielding 19 distinct refusals, all read by hand. The other ~202 strings were
not examined.
Blind spots. Refusals composed at render time from template fragments are invisible to a string-literal grep; so are refusals whose text lives in the HTML rather than in Go. "Names a route" is a judgement, not a predicate — two readers could disagree on the borderline cases, and three of the 19 were called borderline and left unfiled.
C3 — a success verdict over an incomplete state
New instances: 1 (R-258). This class was swept COMPLETELY, not sampled.
Method. Every assignment of a success-valued status in the controller's production code: 9 sites, all read. That is the whole population, which is why this is the one class where "no others exist" is a claim the method can support.
Control — 2 of 3 known instances re-found, and the third re-found as fixed. offbox.go:1040
still carries R-240 verbatim: a configured box with nothing selected reports LastStatus = "ok" with
the warning „Sikeres — nincs mentésre jelölt alkalmazás". R-234's fix is visible in the same block
(missingUnprotected → incomplete). R-203's mandatory-gap fix likewise.
Blind spots. It sees only literal success values assigned to a name matching
Status|State|Verdict|Result. A verdict expressed as a boolean, an enum constant, or the absence of
an error is invisible — and the controller does use booleans for verdicts elsewhere. It covers the
controller only; the hub and agent were not swept for this class.
C4 — an absence reported as a fact
New instances: 1 (R-259).
Control — the fix pattern re-found. R-225's StatsKnown is exemplary and the sweep re-finds it
intact: on backups_remote.html every derived figure — size, snapshot count, quota text and the
bar itself — is behind {{if .Offbox.StatsKnown}}, with the honest alternative text
„a pillanatképek száma még ismeretlen". Its own comment states the principle this class is about:
"a 0%-wide bar over an unread store is a picture of emptiness, and a picture is a claim."
Method. Enumerate the rendered counts/sizes/percentages in the 36 templates, then ask of each
whether a *Known-style companion exists and whether the producing Go call can fail into a zero.
Blind spots. Name-based on the companion flag — a three-state encoding done some other way (a pointer, a sentinel, a separate error field) reads as "unguarded" and needs a human look; two candidates were dismissed that way. Only the controller's templates were covered; the hub's operator UI was not.
C5 — a field one side sends and the other drops
New instances: 1 register row (R-260) carrying a measured census of 8+ dropped fields. This class was the highest-yield, as predicted.
Control — re-found. The known instance is live: the hub's store.EscrowStatus carries
Stale bool json:"escrow_stale,omitempty" and the controller's report.EscrowStatus has no matching
field. Correction to the task's framing, recorded rather than dropped: this is R-247 and it is
READY, not closed. The live repo is the source (rule 7).
Method — and the first one was wrong. Attempt 1 paired structs across repos by json-tag-set
overlap. It false-positived badly, because the hub decodes the same controller report through
several ad-hoc anonymous structs — offsite.state and offsite.abandon_purge_requested looked
dropped and are in fact consumed at api/handler.go:530 and store/store.go:1490. Attempt 2 is the
tag-reachability test: for every json tag emitted on a real wire, does that literal string occur
anywhere in the receiving repo? A tag that occurs nowhere cannot be decoded by any struct, named
or anonymous. That is definitive, and it is the version that generalises into a gate.
Blind spots, several of them earned during the sweep. (a) The emit sets initially included
decode structs — hostReportPayload, applianceRegisterReq, WireDesiredState — producing
nonsense in the reverse direction; those rows were struck. (b) The struct extractor flattens
anonymous nested structs, which produced a phantom asymmetry on hostStorageTarget (§6). (c) 29
generic tag names (name, type, state, status, …) were excluded by name because a repo-wide
string test is meaningless for them — a genuine drop of a generically-named field would be missed.
(d) It cannot tell a deliberate ignore from an accidental one; the hub's hostReportPayload documents
that it ignores several collections on purpose, and those were not counted.
C6 — built and never wired
New instances: 1 (R-261). The more valuable output is the method result, not the list.
Control — and the standard tool FAILS it. golang.org/x/tools/cmd/deadcode was run against all
three binaries and re-found neither known instance. A planted probe measured why: an
unreachable exported function added to the hub's store package is reported; an unreachable exported
method on *Store, in the same file, is not. RTA treats the method set of a dynamically-used
type as potentially reachable. Both known instances are methods — (*Store).MarkEscrowStale and
(*RestoreTestState).Snapshot, both confirmed still callerless today — which is exactly the shape it
cannot see.
A method-aware textual sweep was then written. It re-finds 1 of 2 (MarkEscrowStale); it misses
RestoreTestState.Snapshot because a .Snapshot() call on a different type in
guestnet/report.go satisfies its name-based test. So: 1 of 2, and stated as 1 of 2.
Findings after triage: small, and mostly inert — which is itself the result. 137 raw candidates →
31 whose doc comment claims a consumer → after removing method-values-as-callbacks
(PBSDRAutoProvision), cross-repo name reuse (DebugLogs, AppStopGuard) and template dispatch,
five genuinely have only their own declaration. Four of those five are inert: the data reaches its
stated consumer by another route. OffboxOrphanedRenamedTo says "for the card copy" and has no
caller — but R-228 is genuinely closed, because the card reads the settings field
.Offbox.OrphanedRenamedTo directly in backups_remote.html:80. Same for OffboxEscrowState.
An unwired accessor whose data reaches its consumer another way is dead code, not a defect, and
ranking it as one would inflate this class.
The one that is not inert is R-261.
Blind spots. Go templates call methods with no .Name( syntax; method values passed as
callbacks likewise; reflection and struct-literal function fields likewise. Same-name methods on
different types are conflated, which makes the sweep conservative — it under-reports and never
over-reports. A method used only inside its own file counts as used, so whole-subsystem orphans are
invisible.
C7 — a comment asserting an invariant the code does not hold
New instances: 2 (R-262, R-263), both found while sweeping other classes.
Method + what was SAMPLED — this is the class where the honesty matters most. There are 4092
comments across the three repos matching the invariant vocabulary (never / always / must not /
cannot / is the only / guarantees / impossible) — 2652 in production code and 1440 in tests.
Exhaustive is not possible in one session and was not attempted. The sample is the 60 production
comments containing "is the only", chosen because a uniqueness claim is the one form that is
mechanically falsifiable by a grep. Of those 60, the safety-bearing ones were tested by hand.
The other ~2592 production comments and all 1440 test comments were not examined — and the task's
own instruction to check the tests' claims is therefore only partly discharged: the two instances
below are production comments.
Control. The nine known instances are the repo's own table (in the felhom-testing skill) and are
closed; the sample re-finds the pattern rather than the instances, so C7 has the weakest control
of the seven and should be read that way.
Both new instances are stated in the register. The sharper one, R-262, is the campaign in miniature: a comment claiming a contract is mirrored field-for-field and guarded by a key-set test, where the contract is two fields short and the fixture the test reads omits the same two fields — the instrument is blind in exactly the place the defect is.
4. Which classes can be gated — the ranking
Ranked by what a gate would be worth, using this campaign's own instance counts as the evidence.
| rank | class | gateable? | cost | what it would MISS |
|---|---|---|---|---|
| 1 | C5 | Yes — cheaply and definitively | ~150 lines of Python, no network, --fast-eligible |
generically-named tags; a deliberate ignore looks like an accident, so it needs an allowlist-with-reasons like the C1 gate has |
| 2 | C3 | Yes | small — the whole population is 9 sites | verdicts expressed as booleans or as the absence of an error |
| 3 | C4 | Partly | medium | the companion-flag convention must be adopted deliberately; a gate can enforce "every rendered figure has a *Known" only once that is the house style |
| 4 | C1 | Already gated, partly | completing it is the expensive one | see below |
| 5 | C7 | Narrowly | small for the narrow form | only uniqueness claims are mechanical; the other ~97% of the vocabulary is not |
| 6 | C2 | No, not mechanically | — | "names a route" is a judgement; a gate could only enforce a convention |
| 7 | C6 | No — and this is the finding | — | the off-the-shelf tool is blind to the project's own shape, measured |
C5 is the clear first. The tag-reachability test is a string comparison over two repos' source: it
convicts definitively (a tag occurring nowhere in the receiver cannot be decoded), needs no network,
and would have caught the escrow_stale instance, the operator_key_configured instance and every
other row in R-260's census on the commit that introduced them. It is the cheapest high-value gate
available to this project. Its one design requirement is an allowlist with stated reasons, because
the hub deliberately ignores some collections.
C6 does not hold, and saying so is the point. The class looks the most mechanical of the seven and it is the one where the standard tool measurably fails. Any gate here would have to be written from scratch, would be conservative by construction, and — on this campaign's evidence — would spend most of its output on inert dead accessors. Recommendation: do not gate C6. Gate C5 instead, which catches a strict subset of the same "the answer was available and discarded" family with none of the ambiguity.
C1's existing gate, stated honestly. secret_in_markup_gate.py covers all 36 templates on the
name-based check and is blind to the neutral-page-data-key shape — measured this session by replay,
not merely quoted: it convicts 2 of the 3 known instances and not the third. The runtime body
assertion, which catches all three, covers 4 of 27 pages. Completing it means constructing each
remaining page's data in a test — the cost is per-page and real, and it is the honest reason it has
not been done. The Go-side mirror written for this campaign is a cheap partial third net and is not
recommended as a gate on its own: it produced 27 candidates and 0 findings, which is a bad
signal-to-noise ratio to put in front of every push.
Nothing was built. These are candidates recorded in backlog/ROADMAP.md.
5. Harness faults, separated from product faults
Harness, not product:
- My first C5 method was wrong and would have produced ~10 false findings had it been believed — struct-pair diffing cannot see a receiver that decodes through ad-hoc anonymous structs. Replaced, not patched over.
- My struct extractor flattens anonymous nested structs, which manufactured a phantom
hostStorageTargetasymmetry (§6). - A
grep -v host_oob.goexcludedmonitor/host_oob.gotoo, and I briefly believedGetHostOOBStateshad no caller. Caught by checking before writing it down. Excluding by basename is a trap worth naming. deadcodefailing its control is a harness fault in the sense that matters here — but it is reported as a result in §3/C6, because "the standard tool cannot see this project's shape" is exactly what Part 4 was asked to establish.
Session hygiene, recorded: this session did not run inside tmux, contrary to the workspace
CLAUDE.md. Nothing was lost, but the whole unattended run was one dropped connection from dying.
6. Suspicions investigated and DISPROVED
A campaign reporting only what it found is half a campaign.
offsite.state/offsite.abandon_purge_requestedare dropped by the hub. DISPROVED. The hub'smonitor.offsiteReporthas neither, but both are consumed through separate ad-hoc structs —api/handler.go:530andstore/store.go:1490. This is what killed method 1.- A restore-test mount-parity mismatch is invisible to the hub. DISPROVED, and it mattered.
mount_parityandmount_inventorygenuinely are dropped, but a mismatch setsres.Errand returns beforeres.Pass = true(reconcile/restoretest.go:277-283), so the verdict travels aspass:falsewith the delta in the error string. What is lost is the depth of a pass, not the failure. R-260 states it that way rather than the way it first looked. hostStorageTargetdoes not mirror the agent field-for-field. DISPROVED. The 11 "missing" SMART fields are nested undersmarton both sides; my extractor flattened the hub's anonymous inner struct. That half of the comment is TRUE — which is what makes thehostRestoreTesthalf (R-262) a real finding rather than a sweeping accusation.GetHostOOBStateshas no caller (a C6 instance). DISPROVED —monitor/host_oob.go:40,77. My own grep excluded it.Validation.TableCountreports 0 tables over a validation that could not run (a C4 instance). DISPROVED.backups_apps.html:74-82is correctly three-stated:Valid→ the count,Error→ „Hiba", neither → „Az érvényesítés nem futott le". A good example of the class handled well.- The controller leaks a NAS password into a response body (a C1 instance). DISPROVED.
netstorage_handlers.go:163puts it in a request to the agent, documented in place as never persisted and never in the job status. OffboxOrphanedRenamedTobeing callerless means R-228 regressed. DISPROVED — the card reads the settings field directly (backups_remote.html:80). R-228 is genuinely closed.
7. What was SAMPLED rather than swept, exactly
| class | swept completely | sampled | NOT examined |
|---|---|---|---|
| C1 | all 36 templates (shipped gate); 27 Go-side candidate sites | — | the 23 pages with no runtime body assertion |
| C2 | — | 3 files / 19 refusals on the recovery-restore-offbox surface | ~202 of 221 refusal strings; all refusals composed in HTML |
| C3 | yes — all 9 success-status sites in the controller | — | the hub and the agent entirely; boolean/enum verdicts |
| C4 | the 36 controller templates' rendered figures | — | the hub operator UI |
| C5 | yes — all 4 wire directions, 465 emitted tags | — | 29 generically-named tags, excluded by name |
| C6 | all 3 binaries via deadcode; 1323 exported methods textually |
31 of 137 candidates triaged by hand | the 106 candidates whose doc comment claims no consumer |
| C7 | — | 60 of 2652 production invariant comments ("is the only" only) | ~2592 production + all 1440 test comments |
8. R-242's untouched half — what would catch a skipped vouch earliest
Recorded, not built. This bake demonstrated the gap rather than arguing it:
golden_currency_gate.py flipped from red to green the moment the evidence DIRECTORY existed —
before the round-trip download had finished, and with no vouch anywhere near it. Its positive signal
is "a directory named after the version is present in the repo".
Earliest catch, in order of how early it fires:
- Earliest and cheapest — make the vouch the thing that writes the evidence. The gate cannot read
the hub (its docstring records why: a network-reading gate is not
--fast, so it would run in neither the pre-push hook nor CI). But the bake session can: after the operator saves, re-read/configurationand write the observedgolden_versioninto the evidence README as a machine- readable line. The gate then requires that line, not merely the directory. It still cannot detect a lie, but it detects the forgetting, which is the actual failure mode the gate was built for. - Loudest — a hub-side check, not a repo-side one. The hub already knows both numbers: the
vouched
golden_versionand the newest controller the fleet reports. A daily monitor raisinggolden_behind_releasewould catch a skipped vouch and a vouch that silently rolled back, which nothing in git can ever see. It fires within a day rather than at the next push. - Weakest — a checklist item. R-242 already was a rule without a mechanism, and it recurred the next day. Recording it again is not a fix.
Recommendation: (1) now, (2) when the hub is next touched. (1) closes the recurrence that has cost two releases in two days; (2) closes the class.
9. Register rows opened, grouped by class
Highest ID moved: R-255 → R-263.
| class | rows |
|---|---|
| C1 | none — no new instance |
| C2 | R-256, R-257 |
| C3 | R-258 |
| C4 | R-259 |
| C5 | R-260 |
| C6 | R-261 |
| C7 | R-262, R-263 |
Gating candidates from Part 4 are items in backlog/ROADMAP.md, not register rows.
10. What did not run, and why
- The vouch. Deliberate — §3 of the task halts for it, and the campaign does not depend on it.
- Any fix. Deliberate — §0 forbids it; a campaign that fixes as it goes measures a moving target.
- C7 exhaustively. Not possible in one session: 4092 comments. Sampled and declared.
- C2 exhaustively. 221 refusals; 19 read. Sampled and declared.
- C3/C4 on the hub and agent. Only the controller was swept. Not attempted, not a claim.
- The tests' invariant claims (C7's second half). 1440 test comments; none examined. The task asked for this explicitly and it is owed, not done.
- Live validation of any finding. Every finding in this report is from source reading. None was reproduced on a live box — deliberately, since §6 rule 2 permits no machine beyond the bake VM. R-258 and R-259 are the two most worth confirming live before they are fixed.
11. Observations — noticed and NOT acted on
- The
felhom-goldenpackage list holds 14 goldens back to 0.136.0, none ever pruned. Not a problem today (a rollback needs the old package to exist), but nothing decides when one may go. - The hub's
host-report.golden.jsonfixture containscpu_temp_candloadavg, which no hub struct decodes. A fixture carrying keys the receiver cannot read is a quiet way for a "contract test" to look broader than it is — the same shape as R-262, one level down. readDiskUsage(R-259's site) is one of several collectors that return silently on error, leaving the caller's zero value. The class may be wider than the one rendered figure this campaign measured; only the dashboard's system-disk meter was traced to a customer-visible surface.- The re-enroll response echoes
new_api_keyback to the caller that sent it (api/dr.go:148). Not a leak — the box already holds it — but it puts a live credential in any transcript of that response, and the endpoint is one an operator drives by hand. - The hub operator UI renders
RetrievalPasswordinto page data (web/configs.go:672,:1262). Outside C1 as defined (operator-only, not a customer-fetchable page), so not filed — but it is the R-249 shape on the other surface, and the operator UI has no equivalent of the controller's gate. - This session did not run inside
tmux, contrary to the workspaceCLAUDE.md.