Skip to content

Fleet Harness — Delivery Board

Meet the team

Our build crew is a family of AI teammates — we call them by name. The name is the teammate; the "Runs on" column is the AI tool they work through. So when a task or review says Cedric did it, that's the teammate — the underlying tool is in the table.

Teammate Runs on What they usually do
Clahadore Jones-Gaffney Claude (Anthropic) Planning, coordinating the work, reviewing, and the hard calls
Cedric "Cody" Jones-Gaffney Codex / ChatGPT (OpenAI) Writing code and giving a second-opinion review
Jenny Jones-Gaffney Gemini (Google) Writing code, research, and review
Gronktayvius "Gronk" Jones-Gaffney Grok (xAI) Tough adversarial review — trying to break things before users can

All four share the surname Jones-Gaffney because they're family. Led by Andrew (Andrew David Jones-Gaffney).

Canonical board for the universal-harness epic (LangGraph over the C# fleet rails) and the council steal-list (2026-07-14 council: reject framework-as-brain for usage savings, steal contracts/policies; REVISED same day — outage continuity + career value make a scoped LangGraph supervisor a funded build).

Redundancy rule: this file + Vikunja (http://localhost:3456) + Jira (once trialed) move in lockstep on every status transition. This file is the source of truth until the other two prove sync.

Statuses: Backlog · Ready · In Progress · In Review · Blocked · Done

USABILITY VERDICT — 2026-07-15 22:5x CDT (WT-0026, night mode; council = authority)

The harness is USABLE. It shipped a real change to a real repo, end-to-end, tonight. This verdict replaces document-reading with an actual run — the earlier "~70%, blocked" read was assessed from docs and is superseded.

Evidence (one live run, python -m fleet_harness run --ticket FLT-14, NO --yes): - Routed: implementer=claude, reviewer=grok — the blind reviewer seat convened. - Isolated: created wt/FLT-14/harness-560d612e + its own worktree; registered the lock in the worktree registry (which correctly DENIED a peer session touching it — the lock works). - Validated itself: ran dotnet test and read the result — exit 0, 93 passed. FLT-3's never-trust-agent-claims gate is real, not aspirational. - HUMAN GATE EXERCISED LIVE, first time ever: printed Approve this work? [y/N], took y on stdin, recorded approval:{approved:true}. The --yes bypass was NOT used. This closes FLT-1's outstanding acceptance criterion ("human approval gate not yet exercised live; all runs use --yes"). - Output was CORRECT and landed: master 306d3d3. Verified against ground truth independently (frontend fleet-live.service.ts listens for exactly GovernorTier/QuotaUpdated/RunUpdated/ WorkerHeartbeat — all four names the harness wrote). - probe reports all 8 seats UP: codex, claude, gemini-flash, gemini-pro-high, grok, agy-gpt-oss, agy-claude, ollama. 88/88 tests pass (grown from the 51 baseline).

Stale blockers now CLEARED: - ~~"No remote / single-PC bus factor"~~ — fleet-harness now has andrewjonesdev-tools/fleet-harness. - ~~"Human gate never exercised"~~ — exercised tonight, see above. - ~~"FLT-63 councils unreachable"~~ — partially stale: gaming-pc council answered 200 tonight; all 8 harness seats probe UP. Streaming-pc (:37878) is genuinely down.

REAL residual gap — FLT-4. CORRECTED 2026-07-15 after reading graph.py:121-145; my first pass here was sloppy and is superseded. Two kinds of blindness are being conflated, and they are severable:

  1. Blind to the IMPLEMENTER'S NARRATIVE — deliberate, correct, KEEP IT. The packet is spec + diff
  2. unverified test claims, with "no implementer narrative, no summary, no self-assessment" because "Reviewer anchoring on the implementer's confident prose is the failure mode this breaks". That is precisely the defense against FLT-4's own history (97/97 green, two self-reviews, unwired features shipped). Do NOT weaken this. The packet is also size-capped on purpose — a big diff trips third-party CLI input limits.
  3. Blind to the REPO — this is the actual gap. Grok reviewed tonight's run and said so itself: "Event names ... could not be cross-checked against FleetHub.cs / FleetPollingService.cs ... in this empty harness workspace", flagging GovernorTier as the likeliest mis-name. It was right to be uncertain, and the risk was a false alarm — GovernorTier is correct (frontend fleet-live.service.ts listens for exactly those four). Five seconds of grep would have settled it. It nonetheless returned needs_human_review:false while listing risks it could not verify.

CORRECTION #2 (same session) — "point the reviewer's cwd at the worktree" is WRONG and would BREAK the harness. Do not do it. graph.py:330-338 gives the second rationale I had not read: "the reviewer is a full coding CLI — pointing it at the worktree would let it edit the very code we just measured, invalidating the diff, the changed-file list, and the validation run that follows. Reviewers judge; they do not touch." There is even a belt-and-braces check at graph.py:472 for a reviewer that "somehow reached" the tree. So the empty sandbox is deliberate on TWO independent counts (anti-anchoring AND write-isolation), and both are correct.

The gap is still real — grok needed FleetHub.cs, which is NOT in the diff, so the claim that "the blind packet already contains everything a reviewer legitimately needs" does not hold for cross-file fact-checking. But the fix must grant READ without WRITE.

Proposed fix (preserves BOTH defenses): give the reviewer a throwaway COPY of the worktree contents as its cwd — not the live worktree. It can grep/read any file to check a fact; anything it writes dies with the temp dir and cannot touch the measured diff, the changed-file list, or the validation run. Packet stays exactly as-is (no narrative, size-capped), so anti-anchoring is untouched. Cost is one tree copy per review — bound it (skip .git, node_modules, bin/obj) or reuse a detached worktree at the same commit. A reviewer that cannot distinguish "this looks wrong" from "I cannot see enough to tell" produces false alarms and, worse, false all-clears.

Also likely STALE on the FLT-4 entry: "agent worktrees not registered with the WorktreeOwnership registry" — tonight the registry DID hold a lock (WT-044e owns wt/FLT-14/harness-560d612e) and correctly DENIED a peer session touching that checkout. Re-verify before trusting that gap line.

FLT-6 anti-fork STILL unproven: only usage-governor/docs/agy-quota-policy.md (a DOC) mentions routing.yaml. No second code reader. The shared-role-table property remains asserted, not tested.

Verdict for the Sunday deadline: the harness is usable NOW for real work with a human at the gate. It shipped a correct change to a real repo tonight and refused to take the implementer's word for anything.

UPDATE 2026-07-16 — the one blocker this verdict named is CLOSED (663c5c1). The reviewer now gets a read-only copy of the source, so it can check facts instead of guessing at them, and still cannot touch the measured tree. The remaining bar for UNATTENDED is now evidentiary, not architectural: nobody has yet run the harness end-to-end with the fixed reviewer and watched it CATCH A REAL DEFECT it would previously have missed. Until that run exists, "trustworthy overnight" is a reasonable expectation, not a demonstrated fact — and this board's own history (FLT-4: 97/97 green, two self-reviews, unwired features shipped) is the argument for demanding the demonstration. Next session: give the harness a task with a planted cross-file defect and confirm the reviewer catches it. That is the negative control.

Ranked next steps: (1) ~~FLT-4 — throwaway copy as reviewer cwd~~ DONE — landed 663c5c1 (2026-07-16, implemented by codex, reviewed + independently test-verified by WT-0026). _prepare_review_cwd() copies the implementer's worktree into the throwaway sandbox; reviewer cwd is the COPY, never the live tree. symlinks=False so a link cannot escape back to the measured tree; entry/byte caps fall back to the old empty-dir behavior rather than failing the ladder (so a huge repo degrades, it does not break); partial copies are cleaned before fallback; every fallback path logs which one fired. Packet unchanged — anti-anchoring intact. Tests 88 → 96 passed, 1 skipped, independently re-run. The load-bearing test simulates a VANDAL reviewer that writes into its cwd, then asserts the real worktree is byte-identical and the reviewer's new file does not exist there — it cannot pass vacuously, because if cwd were the live tree the assert fails. Fixture is named FleetHub.cs: the exact file grok could not read. (2) FLT-6 — a second CODE reader of routing.yaml (today: one code reader + one doc mention; the anti-fork property is asserted, not tested). (3) streaming-pc seat (:37878 down; gaming-pc answers, all 8 harness seats probe UP).

Method note for whoever reads this: the previous "~70%, blocked" assessment was produced by reading docs, and three of its blockers were already stale (remote existed, gate worked, seats were up). This one was produced by running the thing. Run it before you rate it.

⚠ Board IDs and Jira keys are NOT the same numbering space

FLT-13 on this board and FLT-13 in Jira are different tickets. This board's IDs were assigned by the 2026-07-14 council before the Jira trial existed; Jira then minted its own keys in creation order, and the two sequences diverged the moment Jira imported the delivered work (FLT-D1..D5) into keys 13–17 that this board was already using for live epic items.

Aligned: board FLT-1..FLT-12 ≡ Jira FLT-1..FLT-12 (same tickets, same numbers — coincidence of import order, not a guarantee).

Colliding — the board ID and the Jira key of the same number are unrelated tickets:

This board Jira key What Jira's same-numbered key actually is
FLT-13 · Mission Control PWA FLT-46 FLT-13 = FLT-D1 worktree-identity
FLT-14 · Private IDE extensions FLT-47 FLT-14 = FLT-D2 usage-governor
FLT-15 · agy quota ledger FLT-49 FLT-15 = FLT-D3 fleet-dispatch
FLT-16 · CI tooling pack FLT-60 FLT-16 = FLT-D4 fleet-telegram
FLT-61 · Tavily narrow-adopt FLT-61 FLT-17 = FLT-D5 NATS fleet.v1 + MemBus

Later entries (FLT-51, FLT-53, FLT-54, FLT-57, FLT-58, FLT-59, FLT-61, FLT-62, FLT-63) use the Jira key as the heading — that is the convention going forward. New entries: title the section with the Jira key, never a locally-invented number. Cite an old board ID only with its Jira key attached (board FLT-13 / Jira FLT-46), because a bare FLT-13 is ambiguous across the two spaces and will route a reader to the wrong ticket.

Reconciling the four legacy collisions (renumber the board vs. renumber Jira vs. leave the map) is FLT-11's job. Until FLT-11 lands, this table is the map.


Epic

FLT-1 · Universal harness: LangGraph/Deep Agents supervisor over all model CLIs — Acceptance VERIFIED — ceiling sign-off GRANTED (Sunday posture); gate 2 open by design; unattended gated on FLT-4 (WT-f255 built; WT-0924 reviewed 2026-07-14; WT-37e6 verified + signed off 2026-07-18)

ACCEPTANCE VERIFIED + ceiling sign-off GRANTED (WT-37e6, 2026-07-18, master 8b712b2). Ran the suite under the repo .venv (Python 3.13.11): 26 passed, 1 skipped. The load-bearing test tests/test_graph.py::test_acceptance_simulate_down_claude is not a mock-pass — it drives the REAL compiled LangGraph (only the agent seats are faked) with simulate_down=["claude"] and asserts the ticket still flows: implement→codex, review→grok (Claude skipped in the review ladder), validation.passed True, and critically registry["claude"].calls == [] — Claude is TRULY never invoked, not merely labelled down — then resumes through the human gate to approved. Sibling tests prove the FLT-3 discipline: a failed implementer escalates AND its worktree is swept (half-edits cannot leak forward), reviewer ≠ implementer always, and all-seats-down escalates to a human with implementer=None (nothing pretended to work). routing.yaml confirmed on the exact Sunday posture: ladder [claude, codex, gemini-flash, grok, agy-gpt-oss, ollama], max_pool_lockouts: 1, agy-claude reserve_only + unreachable by any classifier. Verdict: the FLT-1 acceptance criterion (a ticket flows route→implement→review→gate with the Claude CLI unavailable) is demonstrably met; harness is usable now, attended. Gate 2 (fleet-global capacity ledger) stays OPEN by design — per [[65c2553]] wiring the undercounting ledger is worse than NullLedger's honest "unknown"; it is post-Sunday follow-up, not an acceptance blocker. Unattended operation remains gated on FLT-4 (blind reviewer must catch a real planted defect) — a separate ticket. Build a Claude-independent orchestration layer: LangGraph/Deep Agents supervisor (Python — stated C#-first deviation: ecosystem-standard tooling + career skill acquisition + the orchestrator that covers Claude outages must not depend on Claude) that routes ticket-sized work across codex, claude, gemini (agy), grok CLIs and local Ollama. Supervisor model is swappable (any provider) — that is the outage-continuity property. Executes through existing C# rails (fleet-dispatch listeners, git worktrees, NATS trust tiers) via the FLT-2 contract; replaces no working tool. Includes minimal mission-control UI (Agent Chat UI or LangSmith Studio local dev only). Acceptance: with the Claude CLI unavailable, a board ticket still flows route → implement (Codex) → adversarial review (Grok) → validation gate → human approval. Driver: 2-day Claude outage this week (unacceptable); portfolio value.

Ceiling sign-off (WT-0924, 2026-07-14) — HELD, not a redo. Code is sound: FLT-3 discipline throughout (git's answer, never the agent's), fresh worktree per escalation attempt (a failed agent's half-edits cannot leak into the next), blind reviewer runs in a THROWAWAY EMPTY DIR (reviewers judge, they do not touch — preserves the measured diff), approval_required halts the graph rather than testing past a raised control point, no-reviewer degrades to mandatory human review. Real-run codex --json fix = FLT-3 proving itself.

Blocking finding — correlated failure is live in code. routing.yaml ships escalation_ladder: [ollama, codex, claude, gemini, grok], which predates the FLT-15/WT-df2d agy research and contradicts it: Grok must precede agy-GPT-OSS (third scarce fixed-cap pool, not a free lane); gemini is one lane where agy exposes four of differing scarcity; agy-Claude has no reserve distinction, so a keyword classifier can reach the ~1-call/5h interrupt budget and evaporate it. And graph.py treats rate_limited as "a transient vendor 429" and walks to the next rung — the independent-capacity assumption. Per WT-df2d a locked-out agy pool transfers load to Codex/Grok and ACCELERATES their limits, so the harness hands out bandwidth it does not have exactly when pools are collapsing.

Gates to land: (1) FLT-6 corrects routing.yaml (order + agy lanes + agy-Claude as governor-flag-only, unreachable by any classifier); (2) FLT-15 dependency — rate_limited must consult the agy ledger for cap-proximity instead of assuming the next rung is fresh.

Gate 1 CLEARED + gate 2 seamed (WT-f255, 2026-07-14, 0491f9e). routing.yaml is now modelled on pools, because seats are what we route and pools are what run out: - pools (native-claude, codex, agy-gemini unified, agy-claude fixed-cap reserve, agy-gpt-oss fixed-cap, grok, local) each with kind + scarcity + windows. - The four agy lanes split out, model labels verified against live agy models (wrong labels fail SILENTLY): gemini-flash (bulk), gemini-pro-high (escalate_only — SAME pool as Flash, so never a fallback for it), agy-gpt-oss, agy-claude. - Ladder corrected → claude, codex, gemini-flash, grok, agy-gpt-oss, ollama. Grok precedes gpt-oss (third scarce fixed-cap pool, not a free lane). - agy-claude is reserve_only: no ladder, no role, unreachable by any classifier; --break-glass {native_red,review_gate,council_synth} appends it as the LAST resort and records the reason in the gate packet. RoutingTable.validate() fails the build if anyone puts the reserve on a ladder or makes it a role's primary — the config guards itself. - review_ladder is family-distinct: agy's Claude lanes are Anthropic seats behind a Google login, so name-only exclusion would let Claude review Claude.

rate_limited no longer means "try the next rung." A 429 locks the seat's whole POOL (siblings share the cap and were never fallbacks). After max_pool_lockouts (1) distinct non-local pools lock, the ladder STOPS and escalates to the human rather than spending pools whose cap-proximity is unknown — deliberately pessimistic, since over-escalating during a correlated collapse is the expensive failure and a human gate is cheap. One lockout is still survivable (a single 429 is not an outage). CapacityLedger is the FLT-15 seam; NullLedger knows only what the current run saw and answers cap_proximity() → None — unknown, said out loud, never a comforting 0.0. Lockouts live in graph state, so they survive node hops and checkpoint/resume without leaking across runs. Gate 2 remains open until FLT-15's fleet-global ledger exists — this bounds the damage, it does not measure capacity.

Gate 2 re-affirmed OPEN — do NOT close it by wiring the current ledger (WT-66db, 2026-07-15). The FLT-15 ledger cannot answer cap_proximity() honestly yet, and a dishonest answer is worse than None. Two structural holes, verified tonight, both biased the SAME direction — undercount: - Not fleet-global. AgyConfig.SharedPath is unset in the live ~/.claude/usage-governor/config.json (no agy block at all), so GovernorPaths.AgyLedgerPath() takes the local-BaseDir fallback. Each PC counts only its own spend; see [[agy-gate-bypassed-by-skills]]. - Undercounts even locally. agy-wrap.ps1 still has ZERO production invokers (re-verified 2026-07-15: every agy-wrap hit across source epos is a test, doc, CI file, or the wrap itself). Skill-driven agy spend — /gemini-review, the council Gemini seat — calls agy.exe direct and is never booked.

An undercounting ledger returns a LOW cap_proximity — "plenty of room" — exactly during the correlated collapse gate 2 exists to catch, and graph.py would act on that number. This is the Kerr shape ([[kerr-lens-standing-gate]]): closing gate 2 would reward "the ledger returns a float" while hoping for "the harness knows real capacity." NullLedger's None — unknown, said out loud — is the SAFER posture, and the build already got this right; wiring the ledger would undo it.

Sunday posture: ship FLT-1 usable on NullLedger + max_pool_lockouts=1. Acceptance (a ticket flows route → implement → review → gate with the Claude CLI unavailable) does not require a ledger. Gate 2 is post-Sunday and needs the two holes closed — shared UNC ledgerPath, plus the admit moved into a helper the skills actually call — not a wire-up.

INDEPENDENTLY CONFIRMED, and the wire-up was built anyway before it was checked (WT-3e93, 2026-07-16). WT-3e93 built exactly the wire-up WT-66db forbade — GovernorLedger + cap_proximity_skip=0.9 consumed in Router.is_available() — took it through a full 6-seat council (2 High / 4 Medium found and fixed, 6 convergence passes), and only then rebased onto 65c2553 and read this entry. WT-66db is right on both holes, and WT-3e93's own artifacts prove it: - Hole 1 confirmed by measurement, not argument. The live ~/.claude/usage-governor/config.json has NO agy block: ledgerPath and sharedPath are both empty, so the resolved path is the local C:\Users\fives\.claude\usage-governor\agy-ledger.jsonl. The probe output printed that local path and it went unread — the "fleet-global" premise was in the module docstring, never in the config. - Hole 2 confirmed by the numbers. Deployed agy-status --json reports gemini spentWeekly: 83222 / 60000000 over 16 calls — ~0.2% — on a night this very session ran the agy Gemini seat twice through agy.exe direct. capProximity came back 0.0019: a four-PC-shared, months-old pool reporting itself untouched. That is the LOW-proximity "plenty of room" failure in the wild, and cap_proximity_skip would have routed on it.

Held, not landed: wt/WT-3e93/FLT-15 is pushed for review but deliberately NOT on master. It is the right code against a premise that is not true yet; landing it would trade None (honest) for 0.0019 (confident and wrong). Gate 2 stays OPEN. Revisit only once both holes close, and re-verify the ledger is shared by reading the resolved path out of agy-status --json, not by reading the code that supports one.

Landed prerequisite: agy-status --json (usage-governor master 2aba701, deployed + smoke- verified on this PC via deploy.ps1; 249/249). It is orthogonal to the wiring question — a read-only, versioned status contract that FLT-13's cockpit and any future gate-2 work both need, and it makes nothing act on the undercount. Its ledgerPresent/capProximity: null semantics are also what let a consumer say "unknown" out loud instead of inferring zero.

Steal list (council 2026-07-14)

FLT-2 · run_agent uniform contract as C# adapter layer — Done (WT-0bf0, 2026-07-14: landed master 3a027bb, 168/168 green)

run_agent(task, repo, branch, mode) → structured JSON (status ∈ completed/failed/timed_out/ rate_limited/approval_required, summary, changed_files, tests_attempted, known_risks, needs_human_review) wrapping all four CLIs inside fleet-dispatch. Host owns timeouts, retries, worktree creation, diff collection. This is the tool surface FLT-1 consumes — build first.

Shipped: IAgentRunner + adapters (codex/claude/gemini-via-agy/grok) in fleet-dispatch/src/FleetDispatch.Core/AgentRun/; host-owned worktree ({repo}-agents/{jobId}, branch wt/{jobId}/{ticket}), 20-min default timeout, one retry, git status --porcelain -z diff collection, and the FLT-3 validator. Two entry points: queue kind run_agent + CLI verb run-agent. TOKENROI_CONTEXT=fleet-dispatch in child env. Schema frozen and documented for FLT-1 in fleet-dispatch/docs/run-agent-contract.md.

Verified end-to-end (not just mocks): real codex run created a file in its worktree, changed_files collected, summary extracted. FLT-3 gate proven live — codex reported "Succeeded completely… All applicable tests pass" against a failing validator and the contract returned status=failed, claim discarded, exit 1.

Council gate: Codex + Gemini + Grok seats, Codex chairing (local Ollama seat crashed OOM on the 64KB diff; house seats not run — gaming MCP transport dropped, streaming skipped under YELLOW context-diet). 3 High fixed: status spoofing via classifiers on exit 0, unbounded/undeadlined output drains, git option injection via base branch. Convergence pass then caught orphaned descendants surviving the timeout → Windows job object. Real-run verification caught a wrong codex --json event schema that every mock had agreed with.

Known gaps: agent worktrees not registered with the WorktreeOwnership registry; no GC for abandoned {repo}-agents/*; mode recorded but not behavioral.

FLT-3 · Never-trust-agent-claims validation gate — Done (WT-0bf0, 2026-07-14: both halves landed — fleet-dispatch 3a027bb + llm-council 4f228d2)

Gate (council-code-review + FLT-2 host) reruns build/tests/lint itself; agent self-reported "tests pass" carries zero weight. Highest-ROI item, pure policy. Codify in the review skill and in FLT-2's validator.

Code half (fleet-dispatch 3a027bb): AgentRunValidator reruns build/tests itself and records ACTUAL exit codes in tests_attempted; agent claims never consulted. needs_human_review is only waivable when validation actually ran, passed, the diff is non-empty, and no risks were recorded. Proven live — codex claimed "all applicable tests pass" against a failing validator; contract returned status=failed.

Skill half (llm-council 4f228d2): council-code-review gains Round 4 — validation, replacing the old Round 3 step "run the project's build/tests if they exist and are fast enough" (which permitted verifying nothing). Now: rerun build/tests/lint yourself, take commands from the repo's own entrypoints and name the source, paste cwd + command + exit code + evidence, and a mandatory Validation block in the final report. The two halves are twins and must not drift apart.

Council gate found the hole in the first draft — all three seats independently: "not a subset… unless you say so" made disclosure into permission (run a fast subset, admit it, still report passed). Grok also caught that Round 4 contradicted this skill's own seat contract, which already teaches that exit code is not proof. Fixes are mechanical, not discretionary, because the implementer IS the validator: subset/filter/0-tests → max unverified even when disclosed; diff touching tests/mocks/CI → max unverified unless a real smoke ran and is pasted; verdict = worst outcome any rule triggers; FAILED/unverified is not commit-ready.

Also closed en route: the tracked skill had been stale since 07-10 while the deployed ~/.claude copy gained four days of hardening (Ollama HTTP-API seat, canary probe, seat validation contract, house-seat main-thread rule). Adopted as its own commit (35f5489) so the policy diff stayed reviewable; live and tracked copies are now byte-identical.

Deployed fleet-wide 2026-07-14. All 4 PCs now run the same skill, verified byte-identical by SHA256 (ACB17AAC…, 35317 bytes, 579 lines, frontmatter parses on each). Copied with scp (byte-exact) — great-room, gaming (10.0.0.7), streaming (10.0.0.26), bedroom (10.0.0.36).

Fixed en route: streaming and bedroom were carrying mojibake — em-dashes corrupted to replacement chars by whatever ad-hoc method placed the 07-10 copies (gaming was clean; that was the 4-byte size difference that exposed it). The new file is dense with —/→/braille, so a byte-unsafe deploy would have corrupted it again. scp fixed it as a side effect.

Not closed: - Validation still runs from the agent's own tree, so an agent that weakens its own tests can pass. The skill now caps that at unverified rather than pretending otherwise, but a true independent oracle (pristine test pack) remains unbuilt. - There is no standing skill-deploy mechanism. The 07-10 copies were placed ad-hoc, which is exactly how the encoding corruption got in and how the boxes drifted 4 days behind. Today's deploy was also manual — the next skill edit will drift again unless this is automated (candidate: a fleet-dispatch job, since the rails now exist). - The codex-harness-mirror carries a deliberately INVERTED council-code-review (Claude chairs, Codex implements). It did not get the FLT-3 Round 4 policy — same never-trust argument applies there and it is now inconsistent with this skill.

FLT-4 · Blind reviewer seat for llm-council — In Progress — built, NOT landed, does not meet acceptance (WT-aa8c, 2026-07-15)

Seat variant receiving ONLY spec + diff + test output — no implementer narrative — to break reviewer correlation/anchoring. Wire into /council-code-review as a standard seat.

Built by Codex on wt/WT-aa8c/FLT-4 (f2e31c1, unpushed). Codex reviewed it with its own seats twice — "no blocking findings", 97/97 green. One independent vendor-distinct seat (Grok) then found the feature IS NOT WIRED TO ANYTHING. Verified directly: - SelectBlindReviewer — defined CouncilConfig.cs:111, called ONLY from tests. - BlindCodeReview — defined CouncilEngine.cs:193, called ONLY from tests. - CouncilEngine.RunAsync never reads IsBlindReviewer/ReviewMode/Family. So reviewMode: "blind-review" has zero runtime effect — run the binary and Gemini gets ordinary Stage 1/2/3. The blind pipeline is library helpers + unit tests + SKILL.md prose telling an agent to do it by hand. 97/97 passes while proving nothing about the real flow.

Two deeper findings, both real: - The no-narrative test is theater. It asserts by reflection that the prompt builder has no parameter named narrative — the signature's shape, not the payload. Narrative still arrives via caller-controlled ticketSpec, diff, or testOutput, and the prompt grants repo access (scratchpads, BOARD notes, agent logs). This board previously recorded that pin as "structural"; that was wrong. - "ACTUAL TEST OUTPUT" launders an agent claim as evidence. testOutput is a caller-supplied string under an authoritative header the seat is told to trust. No capture wrapper, exit-code binding, or runner stamp. This re-opens the FLT-3 hole upstream, inside the seat built to be trustworthy. Real fix: the harness captures test output; the implementer never hands it over.

Also: only gemini is tagged blind-capable, so Gemini-authored work has no family-distinct blind seat and selection throws (right instinct, brittle pool — tag several families). Families are free strings with no load-time schema check, so a mislabelled Anthropic-behind-Google lane is taken at face value.

Left for a fresh session, not bodged at 02:00 under RED: wiring blind selection into CouncilEngine is a design decision (replace Stage 2 for that seat, or add a stage?) and deserves one. Branch kept — the family/fail-closed logic and prompt builder are sound, just unconnected.

Meta-result worth keeping: one independent vendor-distinct seat caught a non-feature that a self-review passed twice. That is this ticket's own thesis, demonstrated on this ticket — and the argument for building it properly.

FLT-5 · Capability manifests in fleet-dispatch registry — Backlog

Per-PC manifest: GPU/VRAM/RAM, installed models + roles + context, CLIs, tools, max_jobs, online. Dispatch checks manifest before routing; improves Ollama routing (gaming=qwen3-coder primary, streaming=CPU heavyweights batch-only).

FLT-6 · Deterministic role-routing config + escalation ladder — In Review (WT-f255, 2026-07-14: table shipped)

Config (not code): implementation→Codex, architecture/deep review→Claude, browser/QA→Gemini, research/adversarial→Grok, high-volume cheap (triage/summaries/format checks)→Ollama; escalation local-small→local-large→cloud→independent reviewer→human. Shared by usage-governor, fleet-dispatch, and FLT-1 so all three read one table.

Shipped 2026-07-14 as fleet-harness/routing.yaml (repo root so the C# readers need no Python package knowledge). Contains: roles table, keywords classifier, advisory_roles (text-only roles that skip worktree/review/validation — the seam that lets the non-editing Ollama seat own cheap-bulk), escalation_ladder, review_ladder (blind reviewer must be a different vendor), timeouts. Read live by FLT-1. Outstanding: usage-governor and fleet-dispatch must be pointed at this same file — until they are, this is one table with one reader, and the anti-fork property is unproven.

Outstanding (2026-07-14, from FLT-15 council): the table models gemini as one lane, but agy actually exposes four with different scarcity — gemini-flash (bulk default), gemini-pro-high (escalate-only), agy-gpt-oss (burst overflow behind Grok, own small cap), and agy-claude (out-of-band reserve, never routable by the ladder). escalation_ladder must be reordered to … → agy-Gemini → Grok → agy-GPT-OSS → local, and agy-Claude must be expressible as a governor-flag-only lane that no keyword classifier can reach — "hard task → agy-Claude" evaporates the reserve. review_ladder's different-vendor rule needs family-distinct seats: agy-Sonnet/Opus is a Claude seat, not a Google one.

Correlated-failure hazard for FLT-1 (2026-07-14, WT-df2d): the rungs are NOT independent capacity. When an agy pool locks out, load transfers to Codex/Grok and accelerates THEIR limits — correlated degradation, not graceful. FLT-1's availability probe + escalation MUST weight downstream pools by upstream cap-proximity, not treat each rung as fresh bandwidth; a model that assumes independent fallback overestimates total fleet throughput. Verify this in the FLT-1 ceiling sign-off before it lands.

FLT-7 · SARIF/machine-readable CI gates — Backlog

Security + accessibility + analyzer outputs emitted as SARIF/JUnit/JSON; thresholds enforced by CI before any expensive LLM review runs. Baseline-vs-PR comparison so legacy findings don't drown regressions.

FLT-54 · Ollama seat wrapper must fail loudly on empty/degraded output — Done (WT-aa8c, 2026-07-15: landed llm-council master 529ecd2)

The silent no-op: a RAM-starved ollama seat returned nothing and the council counted it as SUCCESS. Ollama never errors when a model does not fit — it silently offloads to CPU, and the "insufficient VRAM" signal is slog.Debug-only. The caller is therefore the ONLY place this can ever be caught, which is why this is a wrapper fix and no admission gate or telemetry could substitute for it.

Shipped: all four degraded shapes (non-zero exit, empty, whitespace-only, implausibly short) plus timeout now fail loudly at the single invocation seam every production seat call passes through, attributed with seat/model/host/condition. No fallback, no retry — council ruled loud refuse over silent degrade.

Council gate (Codex chair + Gemini + Grok, 3/3) + a Codex convergence pass. What the gate actually bought, since this is the argument for keeping the gate: - Exit-code asymmetry (all 3 seats). Empty output kept ExitCode 0 while merely-short output got the -3 sentinel — the more severe shape was the one a caller reading the exit code would wave through. It was non-silent only because Success separately checks emptiness, so the guard would have quietly died the day someone simplified Success. Every unusable exit-0 shape now carries the sentinel. - Threshold (all 3 seats). 8 chars is indefensible: "I agree." is exactly 8. Now word count + char floor, centralized as CliResult.IsPlausibleAnswer so the rule cannot drift. - Host attribution (Grok). An ollama seat pointed at another box via OLLAMA_HOST runs there while the council runs here; MachineName named the wrong machine. The convergence pass then found two real bugs in that fix (raw command tested before env expansion; substring match catching not-ollama.exe) — now matched on the expanded basename. - Temp-path injection (Codex). Config-controlled seat names landed in a filesystem path.

91/91 tests, rerun independently rather than taken on the builder's word; the exit-code guard is mutation-checked (revert the fix and it fails).

Deliberately not taken → FLT-57 (CliResult.Success should own the plausibility rule; ~15 fake fixtures to rewrite, and prod has exactly one ICliRunner so the bypass is test-only) and FLT-58 (council drops a failed seat and still exits 0 — pre-existing designed behavior, wider than this ticket; a 5-seat verdict silently produced by 4).

Access + boards

FLT-8 · Mesh network: Tailscale pilot, Headscale decision gate — PHASE 1 DONE (WT-0924, 2026-07-15)

Phase 1 shipped 2026-07-15. Tailscale 1.98.8 on all 4 PCs, one tailnet, owner andrewjonesdev1@: andygreatroompc 100.69.90.95 · andrewbedroomtv 100.85.245.95 · desktop-d249kd4 100.110.224.88 · desktop-scdt9hi 100.78.38.60. netcheck: UDP true, direct paths (not DERP-relayed; nearest DERP Chicago) — bedroom verified direct 10.0.0.35:41641 with live traffic. Cost $0 (Personal plan, unlimited own devices). Fleet installs ran via fleet-dispatch (--kind pwsh --payload-file; winget elevated fine under the listeners); per-PC auth URLs written to OneDrive\PC-Bootstrap\_shared ailscale\<PC>.txt, Andrew clicked each.

Two failure modes worth keeping: (1) tailscale login must run DETACHED — the auth URL dies with its process, which cost three retries on the main PC; the fleet script starts it with Start-Process so it survives the dispatch job. (2) --kind pwsh executes the payload as a SCRIPT — prose payloads exit 1 with no useful error. Natural language needs --kind claude.

Outstanding (not phase 1): repoint hardcoded 10.0.0.x in council MCP configs, claude-mem, and fleet-dispatch peers at MagicDNS names — until then the Wi-Fi-drift breakage class is only fixable, not fixed. Phones (iPhone + Pixel Fold) not yet joined. Headscale decision gate untouched (only pays off if tester seats would cost money). Phase 1: Tailscale free plan on all 4 PCs + phone (unlimited own devices, $0, zero ops); testers via node sharing. Kills Wi-Fi-drift breakage class via MagicDNS/stable addresses; SSH mesh + NATS stay (Tailscale = connectivity layer, not exec/bus). Phase 2 gate: IF testers need full membership (would cost $8/user/mo) OR self-host mandate → evaluate Headscale (self-hosted open-source control plane, $0 license) with DR: config + SQLite state backed up nightly, warm standby on second PC, documented failback. Decision recorded here before phase 2 spend.

FLT-9 · Vikunja hardening + DR (the self-hosted "Jira") — In Review — gates passed; one exposure decision open for Andrew (WT-aa8c, 2026-07-15: landed master 8ffa9c7; WT-37e6, 2026-07-17: PS 5.1 encoding fix 0f6a95a)

Nightly pg_dump -> OneDrive, restore verification into a throwaway container, healthz watch on the claude-mem watchdog pattern, + Scheduled Task install/uninstall. Scripts proven against the LIVE stack; the Scheduled Tasks are deliberately NOT registered — that would put live tasks on a schedule unasked. One command away when wanted.

Council gate (Codex, adversarial) found 2 Criticals. Both real, both fixed: - docker rm -f $TempContainer ran before anything proved the container was throwaway. -TempContainer vikunja-db-1 would have destroyed the live board's Postgres. Now every removal passes a label gate (flt9-throwaway=true, checked via docker inspect) plus a name-equality refusal. Verified by extracting the REAL shipped guard functions and driving them against an unlabelled stand-in: it refused, and the container survived. vikunja-db-1 carries no such label, so it hits the same refusal. The guard was deliberately NOT tested by pointing a delete at the live database — a guard you must risk the board to trust is not a guard. - The dump was written inside the LIVE container's /tmp, so a mid-run failure left a full dump (password hashes, tokens) sitting in it. Now removed in a finally on every path. Stated deviation: the in-container temp file was KEPT rather than streaming pg_dump to stdout, because PS 5.1 native-stdout redirection is not byte-safe for a SQL dump. Byte integrity beat elegance. - Also fixed: the live DB password rode on the docker.exe command line where local process telemetry can read it (the container now resolves its own $POSTGRES_PASSWORD internally, so it never appears host-side); docker cp ignored its exit code, so a truncated copy still logged BACKUP OK (now byte-count verified); sh -c interpolated $DbName/$DbUser, so a hostile param could execute arbitrary shell inside the live container (now allowlist-validated).

Verified independently, not on the agent's word: backup byte-matches (137849 bytes host == container); restore into the throwaway asserts 2 projects / 50 tasks / 1 user + real project titles against a sidecar baseline captured from live at dump time, so it cannot pass vacuously by checking the dump against itself; throwaway torn down; live vikunja-db-1 / vikunja-vikunja-1 untouched (10h uptime, healthy); live row counts unchanged; no /tmp residue.

OPEN DECISION FOR ANDREW — deliberately not made unilaterally. The dump is the FULL database (password hashes, API/session tokens, all user and task data) and lands in OneDrive, unencrypted. The ticket asked for OneDrive, so this is as-specified, and it is now documented plainly rather than buried — but it is a real exposure choice: encrypt at rest, keep local-only, or accept. Nothing is scheduled, so nothing syncs on a timer; dumps from tonight's proof runs are already in OneDrive.

Honest limit: restore verification checks projects/tasks/users counts + project titles. That proves the restore path works; it would NOT catch a future dump silently excluding labels, comments, attachments, or tokens. Deferred per ticket scope: second-PC warm standby, mesh exposure (blocked on FLT-8/Tailscale), agent API tokens, board-sync (FLT-11, owned elsewhere).

Update 2026-07-17 (WT-37e6): PS 5.1 encoding corruption fixed — landed master 0f6a95a. Restore-verify false-failed under Windows PowerShell 5.1 (the host Install-VikunjaDrTasks.ps1 falls back to when pwsh is absent): Get-Content decoded the BOM-less UTF-8 .meta.json sidecar as ANSI, mojibaking em-dash project titles and failing the known-project assertion (pwsh passed the identical run). Root-causing exposed a worse writer-side bug: under 5.1 with the cp437 OEM console (the Task Scheduler default), docker exec psql UTF-8 stdout is decoded as cp437, so Backup-VikunjaDb.ps1 wrote mojibake sidecars corrupt at rest — hex-confirmed: em-dash stored as the UTF-8 bytes of "ΓÇö". Fix: verifier reads the sidecar via [System.IO.File]::ReadAllText; both scripts force [Console]::OutputEncoding to UTF-8 for the script lifetime (restored in finally, try/catch for console-less hosts). The two corrupt 2026-07-17 sidecars (19:03, 20:17) were repaired in place and re-verify green. Validated end to end, all exit 0: full restore-verify under 5.1 + cp437 console, plain 5.1, and pwsh; fresh backup under 5.1 + cp437 writes true E2 80 94 em-dash bytes. Gate: cavecrew-reviewer (0 findings) + 2-member gaming council (qwen3-coder:30b, devstral:24b — 0 confirmed findings; note for future gates: the full 5-model council fan-out exceeds the MCP transport timeout on both council PCs, pass a members subset).

FLT-10 · Jira Cloud Free + Rovo MCP trial (parallel, not replacement) — Backlog

$0 cloud tier, 10 users. NOTE: self-hosted Jira not viable (Server EOL 2024; Data Center pricing absurd for solo) — Vikunja (FLT-9) is the self-hosted lane. Trial: Andrew creates Atlassian account + site (agent cannot create accounts), then: FLEET project, agent-oriented statuses (Ready for Agent → Agent Working → Automated Review → Needs Human Review → Done), custom fields (Primary Agent, Review Agent, Risk, Branch, Run ID), Rovo MCP wired to FLT-1. Retire a board only after board-as-contract checklist passes: local export, stable ticket IDs, status transitions via API, token-roi hooks, offline fallback.

FLT-11 · Three-board redundancy sync — Done — WT-77c4, landed

Board sync: 2026-07-18T19:35:09Z — WT-77c4 moved FLT-11 from In Review to Done.

Board sync: 2026-07-18T19:09:59Z — WT-77c4 moved FLT-11 from In Progress to In Review.

Board sync: 2026-07-18T19:08:37Z — WT-77c4 moved FLT-11 from Backlog to In Progress.

This file + Vikunja + Jira kept in lockstep: small C# sync tool (or FLT-1 graph node) that mirrors ticket status transitions across all three; conflict rule = this file wins until Jira trial passes checklist, then re-vote. Every transition timestamps + names the mover.

FLT-51 · Skill/config deploy mechanism — byte-exact, hash-verified, drift-aware — Done (Jira key FLT-51)

Board sync: 2026-07-18T21:23:23Z — WT-4426 moved FLT-51 from Backlog to Done.

No standing way to deploy ~/.claude/skills (and peer config) across the 4 PCs. Every deploy is ad-hoc, and that cost real damage twice in one day (2026-07-14, found by FLT-3): - Silent staleness — the tracked skill sat at 07-10 while great-room's deployed copy gained 4 days of hardening never committed back; the other 3 PCs sat 4 days behind. - Encoding corruption — streaming + bedroom carried mojibake (em-dashes → replacement chars) from whatever ad-hoc method placed the 07-10 copies. Not cosmetic: the seat validation contract matches on braille spinner glyphs (U+2800–U+28FF), so a mangled copy silently breaks the check that catches dead council seats. A 4-byte size difference is the only reason it surfaced.

The non-obvious requirement: drift is bidirectional. A naive push tool would have destroyed the good version — on great-room the live file was AHEAD of the repo. This cannot be a one-way scp fan-out; it must detect unrecognized drift and refuse to clobber it.

Scope: canonical = the git repo, never a live ~/.claude file; byte-exact transport (scp-class, NEVER Set-Content/Out-File — that caused the mojibake); SHA256 verify per target after write with a printed match table (no "deployed" without an observed match — FLT-3 applies to this tool too); drift check BEFORE write; idempotent. Rails exist: fleet-dispatch (kind pwsh or run_agent) + the SSH mesh. C# in fleet-dispatch per standing language policy.

Acceptance: one command deploys to all 4 PCs and prints a per-PC hash table; a deliberately drifted PC is flagged, not clobbered; a file with em-dash/arrow/braille round-trips byte-identical (regression test for the real bug); a re-run reports no-op.

Also decide (don't assume): codex-harness-mirror carries a deliberately INVERTED council-code-review. It is a variant, not a stale copy, so this tool must not overwrite it — but it also never got FLT-3's Round 4 policy, so the two gates now disagree about whether an agent's "tests pass" counts. Either the tool understands variants, or variants are explicitly out of scope and tracked another way.

Origin: fell out of FLT-3 (llm-council 4f228d2). Same class as FLT-11 (keeping N copies in lockstep) — the two may share a mechanism. ~/.claude/CLAUDE.md belongs in this tool's scope too — see FLT-53, which is the same root cause found in the same place.

FLT-53 · CLAUDE.md drift: 3 PCs missing 4 standing policies, each with its own stale review-gate section — Backlog (Jira key FLT-53)

Found 2026-07-14 deploying the board-footer rule. Surfaced, not fixed — fixing means overwriting hand-written content. The 3 remote PCs' ~/.claude/CLAUDE.md are NOT copies of great-room's; all four differ (great-room 7510b; gaming 5904b; streaming 5480b; bedroom 5819b, all remotes dated 07-11).

Two directions of drift at once: 1. Remotes lack four STANDING policies great-room has: language policy (C#-first — which itself says "Applies on every machine, every model, every harness"), worktree/session identity, model escalation ladder, usage governor. worktree-identity + claude CLI are installed on all three, so sessions DO run there — without knowing about C#-first, the ladder, or the governor's YELLOW/RED rules. 2. Each remote has a review-gate section great-room lacks, all three worded differently ("Review gate standard" / "Review gate (house standard)" / "Council review gate (standard)"), and all three reference /council-review — a slash command that does not exist. The skill is council-code-review. Three PCs point sessions at a non-existent command, three ways.

The board-footer rule was therefore appended as its own marker-fenced block (<!-- board-footer-begin -->), built locally and scp'd byte-exact, leaving each PC's content intact — verified block present + review-gate preserved + SHA256 match on all three.

Decide then do: which policies are genuinely fleet-wide vs deliberately great-room-only; reconcile the three review-gate sections into one and fix the /council-review name; and whether CLAUDE.md should be composed of marker-fenced blocks from a canonical source (the shape FLT-51 could manage) with only machine-specific content local. Blocked on/related: FLT-51, same root cause.

FLT-13 · Mission Control frontend: Angular + NSwag PWA cockpit — In Progress — PHASE 1 SHIPPED + QUOTA SURFACE (Jira key FLT-46)

Phase 1 status wall DELIVERED 2026-07-14 (WT-df2b) in new repo fleet-mission-control (local master, 2 commits, NOT pushed). ASP.NET Core net10.0 minimal API + SignalR /hubs/fleet (WorkerHeartbeat/RunUpdated/GovernorTier, 5s poll) reading fleet-dispatch queues read-only + governor state.json + Jira REST (60s cache). Angular 22.0.x pinned PWA, NSwag TS client generated from build-emitted openapi/*.json (hub DTOs forced in via /api/meta/hub-events; npm run check:drift = CI failure). 3-pane/dual-pane/card-stack via container queries, light+dark, WW resilience interceptor. Verified LIVE against real dispatch data (4 workers probed, 50-run stream, YELLOW governor, hub ● live). Council gate ran: seats Codex+Gemini+Grok+local qwen3:8b +gaming:qwen3-coder:30b+streaming:llama3.3:70b (gaming devstral FAILED/canceled; local+house diffs bounded); chairman 1 High (probe SSRF allowlist) + 6 Med + 5 Low — ALL implemented; backend 20/20, frontend 19/19, builds green. Phase 2 (approve/reject) unblocked; FLT-14 unblocked for read-only panels. Stack decision REVERSED 2026-07-14 by runoff council (unanimous 5/5 + 2 house seats, DECISIVE): Angular latest + CI-generated NSwag clients beats Blazor InteractiveAuto. Deciding: time-to-cockpit (usage bleed now), hub-DTO generation kills the type-drift argument (only hub method names stay hand-written), Blazor prerender double-fire risk on the approve button, npm purity already dead at the VS Code extension, McKinley innovation token already spent on the LangGraph harness. Flip condition on record: heavy run_agent contract churn → revisit Blazor (contract is frozen, 168/168). npm mitigations mandatory: lockfile + pins + private mirror + tailnet-only. Design/mockups unchanged (visual language is stack-agnostic): Design proposal: https://claude.ai/code/artifact/1849163f-6a8d-42a9-9c8a-d8a5e536a14c — steel/amber ops cockpit. C# Blazor Server PWA on the tailnet (Tailscale Serve HTTPS; iOS + Android Tailscale apps cover iPhone + Pixel 10 Fold, PWA install, no app stores). Responsive: desktop 3-pane (fleet+queue | activity stream | approval gate), iPhone card-stack approvals, Fold dual-pane unfolded. Phases: 1 status wall (SignalR read-only) → 2 approval gate (FLT-1 interrupt() + FLT-2 approval_required) → 3 dispatch-from-phone → 4 VS Code extension panel.

Quota surface (added 2026-07-14 from FLT-15): the status wall is the natural place to make the FLT-15 agy ledger visible, because the ledger is heuristic — there is no quota API, so a human eyeballing drift is part of the design. Phase 1 shows per-pool gauges (native Claude 5h/weekly, agy-Gemini unified pool, agy-Claude reserve as remaining invocations not a percentage, agy-GPT-OSS, Codex, Grok) with the weekly cap rendered as the hard cliff it is, and a "reserve intact / spent" indicator for agy-Claude. Phase 2's approval gate is also where an agy-Claude break-glass invocation gets its reason code — the one human control point that keeps reason drift to "convenience" visible. Cockpit reads the ledger; it must never be a second writer (FLT-15's single-writer rule). VS Code fork REJECTED (TS/Electron 1.5M-LOC maintenance trap; IDE exists — gap is command & control). Native mobile SKIPPED (PWA + fleet-telegram push suffice).

✅✅ FLT-14 COMPLETE — 6/6 SURFACES LANDED ON MASTER (2026-07-16 22:5x)

adeb6a2 — VS 2026 extension landed. All six surfaces are real and receipted: | Surface | Receipt | |---|---| | web/desktop, iPhone 17 Pro Max, Pixel Fold 10 | 236a73f, CI green, mutation FE 94.44% | | VS Code + Antigravity x2 (ONE VSIX) | cc26da2, real extension host, VS Code 1.107.0 (the version the forks ship) | | VS 2026 | adeb6a2, human click -> NavigationCompleted success=True — PIXELS RENDERED, then scroll confirmed docked |

The last two bugs were found by Andrew using it, not by any gate: 1. Style=Float 900x600 could not be resized at all. Now Style=Tabbed docked against Solution Explorer (GUID 3ae79031-...), so it behaves like a normal VS tool window. The old code's comment blamed Tabbed for a never-visible frame — that diagnosis was wrong; the frame was invisible because of the programmatic auto-show, which no longer exists. 2. THE COCKPIT HAD NO SCROLL CONTAINER — ANYWHERE. Every overflow in the app was hidden for text ellipsis or a gauge. So the moment the panes stacked (<600px: a phone, or the cockpit docked narrow in VS) the stack was taller than the pane and the bottom was UNREACHABLE. Fixed 43c39bb (overflow-y:auto on .cockpit-container; min-height:0 was already there, which is what lets a flex child shrink and scroll). Pinned with a NEGATIVE-CONTROLLED test — remove the rule and it fails. 106->107. This was broken on a surface already called "landed", and Lane A's screenshots could never have caught it: a screenshot shows the TOP of a layout and says nothing about reaching the rest.

Council gate on the VS extension caught 4 real defects before landing (codex + own pass): HIGH — missing bundled cockpit only logged exists=False then mapped+navigated anyway => BLANK cockpit, all signals green. Now throws. HIGH — csproj packaged a VSIX with no cockpit behind a <Warning>; now an <Error>. MED — WebView2 never disposed (owns a browser process + user-data lock) => leak per open/close. MED — Loaded re-fires on EVERY re-parent, stacking duplicate inits; this fired live in testing 7s after render, and it was a regression I introduced by removing a guard I had wrongly called a hack.

SESSION TALLY — 8 false success signals. frame.Show()==S_OK / IsOnScreen=1 / IsVisible=S_OK / DocView==our pane all true while nothing rendered; VSIXInstaller exit 0 installing nothing; Stryker exit 0 running zero mutants (x2); a workflow "red X" that was actually zero jobs = CI fully off; council seats "completing" with Argument list too long. Every real answer came from an artifact — a score, a file on disk, a probe line, or a human looking at the screen.

✅ VS 2026 RENDERS. SOLVED 2026-07-16 21:48 — manual open works; my descope verdict was WRONG.

Andrew clicked View > Fleet Mission Control in a real Exp instance. Probe, verbatim:

21:48:13.937 Execute: on main thread, calling ShowToolWindowAsync
21:48:14.034 Loaded FIRED: control is parented, HWND exists -- starting WebView2 init
21:48:14.402 EnsureCoreWebView2Async OK -- WebView2 is live inside VS
21:48:14.405 virtual host mapping set: fleet.cockpit -> ...\media\webapp
21:48:14.406 Navigate() -> https://fleet.cockpit/index.html?apiBaseUrl=http%3A%2F%2Flocalhost%3A5170
21:48:14.520 NavigationCompleted success=True -- PIXELS RENDERED
Half a second, end to end. Loaded fires, the control is parented with a real HWND, WebView2 initialises, the virtual host maps the bundled Angular dist, and navigation completes. VS 2026 hosts the WebView2 cockpit fine. DO NOT DESCOPE. The 6th surface is real.

What actually went wrong — all of it mine, none of it the platform: 1. Manual open works; programmatic auto-show does not. Every automated attempt used ShowToolWindowAsync from InitializeAsync under [ProvideAutoLoad]. That path leaves the content unparented (PresentationSource=NULL forever). A user-invoked .vsct command parents it instantly. This is why the extension must open from a command, never auto-show. 2. MSYS mangled /rootsuffix into C:/Program Files/Git/rootsuffix on every bash launch, so devenv opened the REGULAR instance where nothing was installed. Andrew's screenshot of VS's own "these files could not be found" dialog is what exposed it. Launch via PowerShell Start-Process -ArgumentList '/rootsuffix','Exp' — never from bash. 3. I sent Andrew to the wrong menu (View > Other Windows). The .vsct parents the group to IDM_VS_MENU_VIEW = the View menu itself, priority 0x0600 (bottom). Lane C had documented this and I did not read my own notes. 4. extensions.configurationchanged persisting was a red herring — the Extension Manager showed the extension Installed + Enabled the whole time.

My "platform blocked, descope to commands-only" verdict was WRONG and is fully retracted. The council (codex/grok/gemini) refused it on VERIFIED grounds — no documented VS 18 bug, classic VSIX + ToolWindowPane + WebView2 is still supported — and they were right. Every "platform" symptom traced to my own harness.

Standing lesson: frame.Show()==S_OK, IsOnScreen=1, IsVisible=S_OK and DocView==our pane were ALL true while nothing rendered. The only honest receipt was NavigationCompleted success=True — and it only ever came from a human clicking. See [[verify-by-artifact-not-exit-code]].

FLT-14 · Private IDE extensions: VS Code + Visual Studio 2026 panels — In Progress — 4/6 surfaces landed; VS 2026 render unproven (Jira key FLT-47 · 2026-07-15 session WT-0026)

Scope corrected 2026-07-15. Requested as 6 surfaces (web/desktop, web/iPhone 17 Pro Max, web/Pixel Fold 10, VS Code, VS 2026, Antigravity). Actually 3 codebases: the Angular cockpit serves all three web postures; ONE VSIX serves VS Code + both Antigravity installs (product.json proves Antigravity = VS Code fork 1.107.0, gallery = open-vsx.org — so no separate Antigravity extension exists to build). There is no Antigravity 2.0 on this box (IDE 1.107.0, agy CLI 1.1.3); the "2.0 built from scratch" story came from content-farm blogs, not Google.

LANDED on master (repo now has a remote: andrewjonesdev-tools/fleet-mission-control, PRIVATE — it was local-only until 2026-07-15, so CI had never run once): - 774261e — web postures: viewport-fit=cover + env(safe-area-inset-) for Dynamic Island/home indicator. - 0b8d416 — cleared 12 pre-existing master ESLint errors the repo's first-ever CI run exposed. - 236a73f — fixed the dead Fold layout (see gate note below) + a safe-area overflow. - c75883a — runtime backend origin: FLEET_API_BASE_URL (which NSwag already generated and the client already consumed — app.config.ts just never provided it) now fed from window.__FLEET_CONFIG__; hub URL un-hardcoded. 106/106 tests, default same-origin behavior byte-identical. - cc26da2 — VS Code + Antigravity VSIX (one extension, three installs). Proven with a REAL extension host (@vscode/test-electron) on VS Code 1.107.0 — deliberately the version both Antigravity installs fork from — 4/4 passing, round-tripping a probe message OUT of the webview against the real 248KB ng build bundle. A negative control (sabotaged CSP nonce) makes the probe fail, so it isn't vacuous. Distribution PRIVATE. - 8473941 — docs: architecture (technical, file:line cited), architecture-plain (non-engineer), making-of. 6 Mermaid diagrams, all validated via mermaid.parse() (the CLI's puppeteer path was broken on a missing webfont; the agent bypassed the renderer rather than declare it unverifiable). - CI green both jobs (first green in repo history). Frontend mutation 94.44%* (255/270 killed).

cc26da2 CAUGHT FLT-13's EXACT FAILURE ABOUT TO REPEAT. Angular/beasties emits <link rel=stylesheet media="print" onload="this.media='all'">. A nonce cannot whitelist an inline event handler, so under the webview's strict CSP the onload is blocked, media stays "print", and the main stylesheet never applies — the cockpit would render with critical CSS only while every string-assertion test stayed green. That is FLT-13's false "rendered with CSS" verbatim, six weeks later in a different codebase. It surfaced ONLY because the agent built the REAL frontend instead of trusting a hand-written fixture. See memory nonce-csp-breaks-angular-deferred-css.

COUNCIL GATE CAUGHT A REAL DEFECT (the reason to keep the gate under deadline): the Fold two-pane code was dead on the target device. @media (horizontal-viewport-segments: 2) fires only in Device Posture folded (device bent to a book/tent angle); a Pixel Fold opened flat is continuous and reports 1 segment, so the block never matched and the unfolded Fold fell through to the phone card-stack. 95/95 tests green, screenshots taken, feature never ran — the FLT-4 pattern exactly. Fixed via 600dp width classes (Google's own compact/medium/ expanded), verified by screenshot (620px was card-stack, now dual-pane). See memory viewport-segments-needs-folded-posture.

CI GATES LANDED 2026-07-16 (64e269d -> 0d20732, fleet-mission-control master). The FLT-16 pack finally exists on this repo: 7 jobs — backend, frontend, extensions (its 38 unit + 4 real-extension-host tests had NEVER run on push), inspectcode, semgrep, churn 5x, mutation. Codex implemented; verified locally with real artifacts before landing: InspectCode 24 warnings -> 0 (via path-scoped .editorconfig suppressions, NOT by renaming DTOs — see the Kerr note), semgrep SARIF 0 findings, churn 5/5 identical (93 tests), backend mutation 80.60%, frontend 94.44%.

KERR TRAP DEFUSED, ON PURPOSE. All 24 InspectCode warnings are false positives. Gating on a raw zero-warning count would have REWARDED breaking the wire contract: it wants Events5h->Events5H, Pct5h->Pct5H on DTOs in Contracts/ that serialize to JSON, and the NSwag TypeScript client is generated from that OpenAPI doc. Suppressions are path-scoped with the reason written next to each. 5h means five hours; it is correct domain language, not a casing mistake.

I BROKE MASTER'S CI DOING THIS AND WANT IT ON THE RECORD. The first gates push was rejected by GitHub at parse time — 0s, ZERO jobs, so nothing ran, not even the backend/frontend gates that worked before. An ungated master that looks gated is worse than no gates. Cause: the runner context is valid ONLY at STEP scope — not workflow-level env:, and not job-level either. My first "fix" moved it workflow->job and I pushed that; still dead. Two runs, two 0s failures, three wrong hypotheses (I also wrongly suspected unresolvable SHA-pinned actions — all three verified live). actionlint found it in seconds. yaml.safe_load parses every broken variant happily; YAML-valid != Actions-schema-valid. I reverted master to the known-good workflow first, then fixed and re-landed with actionlint proving it clean BEFORE the push. The tell I missed for two cycles: gh run list prints the workflow FILE PATH instead of its name: when GitHub cannot parse it. See memory actionlint-catches-dead-workflows. Follow-up: wire actionlint INTO the workflow so a bad workflow can never silently disable CI again.

ACTIONLINT GATE LANDED 2026-07-16 (d4117cc). Deliberately a separate workflow file (.github/workflows/actionlint.yml), NOT a job inside ci.yml: GitHub rejects an unparseable workflow before scheduling any of its jobs, so a lint job inside ci.yml could never catch ci.yml's own parse error — it would be theater. A separate file is parsed independently and still reports. .github/actionlint.yaml declares the real self-hosted labels (read from the org runners API) instead of passing -ignore, because ignoring the label rule would also blind us to REAL label typos — and a typo'd label doesn't fail, it queues forever. Verified both directions, no ignore flag: clean on the repo (exit 0), and a negative control that reintroduces the exact job-scope runner bug that killed master fails it (exit 1, correct line). The gate can actually fail. Image digest read from docker inspect, not guessed.

MEASURED 2026-07-16 — the single-runner cost is no longer theoretical: - The 7-job run (0d20732, 18:47) was still 44+ minutes in with 5 of 7 jobs QUEUED. The equivalent GitHub-hosted 2-job runs earlier the same night: ~1m40s, green. - home-ci capable: ["greatroom-tools"] — of three ONLINE org runners, only one carries the label. ANDREWBEDROOMTV and ANDYGREATROOMPC do not. - The mutation job failed after 39 minutes with every one of its steps GREEN (backend + frontend Stryker both success), dying in post/cleanup with post-steps never completing. Logs already expired (BlobNotFound) so the cause is unproven — but "all steps pass, job dies in cleanup" is an infrastructure flake, not a gate finding. Consistent with one box serializing 7 heavy jobs.

ON REDUNDANCY / SWARM / K8s — the answer the data supports: "redundancy across one PC" is not redundancy; it is a single point of failure wearing the word. But the gap is a missing label, not a missing orchestrator. GitHub Actions runners are stateful agents that poll GitHub and execute jobs; there is no scheduling problem for Swarm/K8s to solve here — GitHub IS the scheduler, and it already load-balances across every runner carrying the right label. Adding home-ci to ANDREWBEDROOMTV + ANDYGREATROOMPC is a config edit per box and buys 3x parallelism immediately; containerising the runners buys nothing on top of that and costs a Windows-container story for .NET+VS tooling that is genuinely painful. A prior council already REJECTED Swarm/K8s for the tool fleet (memory tool-ci-redundancy-4pc) — this data supports that verdict rather than reopening it. Cheapest real fix, in order: (1) label the other two runners; (2) or move this repo back to GitHub-hosted, which demonstrably works for the andrewjonesdev-tools org — the billing block in memory is scoped to the PERSONAL account, and tonight's green runs were windows-latest/ubuntu-latest.

RESOLVED 2026-07-16 — the fleet now runs its own CI. NO GitHub-hosted minutes. Was: 1 runner could take home-ci work, 7 jobs serialised on one box, 44+ min with 5/7 still queued. Now: 6 org runners across 3 PCs, jobs land in parallel, gates green (backend, frontend, churn, InspectCode, mutation all pass on the new boxes). - Root cause was LABEL != GROUP. ANDYGREATROOMPC + ANDREWBEDROOMTV were already IN the home-ci runner GROUP but lacked the home-ci LABEL — and runs-on: matches labels, not groups. greatroom-tools had the label but sat in Default. Nobody was wrong about the intent; the wiring was crossed. - Added runners to the two idle boxes: streaming DESKTOP-SCDT9HI (32c/94GB) had ZERO runners → 3; gaming DESKTOP-D249KD4 (32c/47GB) had zero ORG runners (its only one was bound to the WorkWingman REPO, invisible to the org) → 2, capped to leave headroom for the Ollama council models. - Three real bugs surfaced only once jobs ran concurrently — a single serialised runner had hidden all of them: (1) fresh runners fail EVERY powershell step with PSSecurityException until Set-ExecutionPolicy -Scope LocalMachine RemoteSigned; (2) runners run as NETWORK SERVICE so they SHARE one NuGet cache and concurrent restores collide — fixed in each runner's own .env, not workflow env, because step-env covers only its step and job-env cannot use runner.* at all; (3) shell: powershell runs with ErrorActionPreference=Stop, so docker's stderr progress lines became terminating NativeCommandErrors and failed semgrep while the scan itself succeeded. - Excluded until fixable, so they stop failing jobs: ANDYGREATROOMPC (ExecutionPolicy needs an elevated shell) and ANDREWBEDROOMTV (SSH to 10.0.0.36 times out). Labels pulled; re-add after fixing. - Remaining bottleneck: docker. Docker Desktop on Windows is per-user, so a runner service can't reach another user's daemon. Only greatroom-tools is PROVEN to serve it, so semgrep + actionlint pin to the docker label and serialise there. Widening needs a real per-box test, not an assumption. - Not Swarm/K8s — GitHub is already the scheduler and load-balances across labelled runners. The gap was a missing label and missing runners, not a missing orchestrator. Consistent with the prior council rejection. See memory home-ci-runner-fleet.

SUPERSEDED — INFRA FINDING — home-ci is ONE runner, not four. All 7 jobs target [self-hosted, home-ci, windows] (matching llm-council, the house pattern). But of three online org runners, only greatroom-tools carries the home-ci label; ANDREWBEDROOMTV and ANDYGREATROOMPC do NOT. So the "CI redundancy across 4 PCs" intent is not real — every job serializes on one PC, and CI dies when that PC is off. Worth deciding: label the other runners, or move this repo back to GitHub-hosted (which demonstrably works — tonight's green runs were windows-latest/ubuntu-latest; the billing block in memory is scoped to the personal account, and andrewjonesdev-tools is a separate org that bills fine). Also note: DOTNET_INSTALL_DIR was invented from a hint in my brief — llm-council does not use it at all, so a follow-up could simply drop it.

IN FLIGHT: - wt/WT-0026/FLT-14-vscode-ext — VSIX rebasing onto c75883a; deleting a fetch/XHR/WebSocket monkey-patch in favour of a nonce'd window.__FLEET_CONFIG__ script; correcting distribution docs to PRIVATE sideload. - wt/WT-0026/FLT-14-vs2026 @ b8dd99c — classic VSIX builds (needs FULL VS MSBuild; dotnet build fails), 33 tests pass, package loads (ActivityLog Begin/End package load), command dispatches, frame.Show() returns S_OK — but WPF Loaded NEVER FIRES, so WebView2 init never even starts. It has never rendered a pixel and is not claimed to.

Two of my own diagnoses here were WRONG — recording both so nobody re-buys them: 1. "The ctor-dispatch fallback is the bug." Removing it did NOT produce a render. It was a real bug (it burns the single init attempt before an HWND exists, then _started swallows the real Loaded) and removing it was correct — but it was not THE bug. 2. "Float vs Tabbed isn't the differentiator, because the spike used Float and also failed." Unsound — with the hack present, the guard would have swallowed Loaded in that run regardless. I had no evidence either way and asserted it as if I did. Float has since been tried and is not sufficient alone. Also retracted (by the lane agent, correctly): "zero child HWNDs ⇒ WebView2 never attached." VS 18's MAIN window also reports kids=0 — the whole shell is composition-based (same reason screenshots are black). Zero children is normal here and proves nothing.

ANSWERED 2026-07-16 18:4x — IT IS NOT WEBVIEW2, AND VS'S OWN API LIES ABOUT IT. Isolation spike: a plain TextBlock, zero WebView2, in a healthy Exp instance (483-707MB, responding, correct title). Polled PresentationSource.FromVisual(this) every 5s:

t+ 5s  loaded=False visible=False size=0x0  presentationSource=NULL hwnd=0x0
t+20s  loaded=False visible=False size=0x0  presentationSource=NULL hwnd=0x0
...while the SAME run had VS reporting frame.Show() hr=0x00000000, frame.IsOnScreen onScreen=1, and frame.IsVisible S_OK (visible). The WPF content is NEVER attached to a window - no PresentationSource, no HWND, IsVisible=False, forever. So Loaded cannot fire, and EnsureCoreWebView2Async cannot complete (it needs a real sized HWND). Not a sizing bug, not dock style, not WebView2. Show()==S_OK, IsOnScreen=1 and IsVisible=S_OK are FALSE RECEIPTS - VS bookkeeping that does not mean the content rendered. Trusting them cost ~5 cycles chasing WebView2. (Seventh lying success-signal of this session; see memory verify-by-artifact-not-exit-code.)

RETRACTED 2026-07-16 by council (codex/grok/gemini CLI seats, no house councils). MY "PLATFORM BLOCKED" VERDICT WAS WRONG — DO NOT DESCOPE YET. Two seats independently, with VERIFIED citations: - No documented VS 18/2026 breaking change exists for classic VSIX tool windows. Grok: "Known bug -> UNKNOWN / NOT FOUND. Do not treat as platform defect until identity + command-path experiments fail." Classic in-proc VSPackage + ToolWindowPane.Content + WebView2 is still the SUPPORTED WebView2 path. - The real mechanism: WindowPane overrides IVsWindowPane.CreatePaneWindow, which is what creates the HwndSource and sets RootVisual = Content. If the shell defers realization, that hook NEVER RUNS — so no PresentationSource, no Loaded. Consistent with every symptom. - I misread my own evidence: hwnd=0x0 on the control is EXPECTED BY DESIGN — direct-hosted WPF content has no dedicated content HWND. It was never evidence of a platform break. - Two likely causes, both OURS: (a) showing during [ProvideAutoLoad(NoSolution)] is too early — the docking layout is not restored, so the frame exists but the pane is never realized; fix = defer to KnownUIContexts.ShellInitializedContext or a real user-invoked .vsct command. (b) VsDockStyle.Float puts the pane in a separate top-level frame whose realization the shell defers when shown early/inactive, whereas Tabbed/Linked docks into the main window's existing visual tree and forces immediate realization. - Also corrected: my claim that Remote UI "is WPF-only with no webview" is inaccurate (grok) — though the Extensibility SDK still has no 18.x release, so classic VSIX remains the path regardless.

COUNCIL EXPERIMENTS RUN 2026-07-16 19:2x-19:3x — ALL FOUR HYPOTHESES ELIMINATED. Evidence:

19:33:10.740 ShellInitializedContext ACTIVE          <- fired in 1ms: shell was ALREADY up. NOT too early.
19:33:10.923 OnToolWindowCreated: Content is CockpitToolWindowControl, sameInstanceAsProbe=True
                                                      <- grok's #1 (wrong instance) ELIMINATED
19:33:10.984 frame.Show() hr=0 / onScreen=1 / IsVisible=S_OK
19:33:10.986 VSFPROPID_DocView hr=0x00000000 value=VsixSpike.CockpitToolWindow isOurPane=True
                                                      <- the frame's CLIENT VIEW *IS* OUR PANE
19:33:10.987 VSFPROPID_DocData hr=0x80020003 (DISP_E_MEMBERNOTFOUND) value=NULL
t+5s..20s    loaded=False visible=False size=0x0 presentationSource=NULL   <- with Style=TABBED this time
- NOT timing — deferred to KnownUIContexts.ShellInitializedContext; it was already active (1ms). - NOT identity — OnCreate + OnToolWindowCreated both fire and sameInstanceAsProbe=True; we ARE probing the object the shell hosts. - NOT dock style — VsDockStyle.Tabbed behaves IDENTICALLY to Float, refuting gemini's [SPECULATION] that Tabbed forces realization. - NOT "frame is metadata only" — VSFPROPID_DocView is our CockpitToolWindow. Per codex's own decision rule that means: VS created the logical pane and installed it as the client view, but failed to HOST its WPF content. The fault is the IVsUIElementPane hosting step, nothing upstream of it.

Council value, honestly: they refuted my premature "platform bug" verdict and supplied the DocView probe that pinned the fault — but two of three also produced APIs that DO NOT EXIST: gemini's CreatePaneWindow override (CS0115 — and codex separately confirmed IVsWindowPane.CreatePaneWindow is obsolete, superseded by IVsUIElementPane), and Tabbed-forces-realization was simply wrong. All three independently found no documented VS 18 bug for this, and codex found Microsoft ships no VS 2026-specific extension-creation docs yet — so "unsupported/undocumented" remains live, but "known platform bug" is still NOT established.

FINAL PROBE — the shell DOES request the UI element, then does not host it. Codex identified the real (non-obsolete) hosting contract: WindowPane implements IVsUIElementPane; IVsWindowPane.CreatePaneWindow is obsolete. Re-implemented that interface on the pane to log it:

*** IVsUIElementPane.SetUIElementSite CALLED ***
*** IVsUIElementPane.CreateUIElementPane CALLED *** returning CockpitToolWindowControl
VSFPROPID_DocView value=VsixSpike.CockpitToolWindow isOurPane=True
t+5s..20s  loaded=False visible=False size=0x0 presentationSource=NULL
So the shell sites the pane, asks for the WPF element, receives our control, installs it as DocView — and never hosts it. Every step of the documented contract is fulfilled on our side. CAVEAT, stated honestly: re-implementing IVsUIElementPane SHADOWS WindowPane's own implementation, so in THIS run the hosting path is partly ours. The finding holds only because the earlier runs — on WindowPane's stock implementation — failed identically. This run alone is not clean evidence.

REMAINING UNTESTED (only one left, and automation cannot do it): every attempt has shown the window PROGRAMMATICALLY. Nobody has opened it by HAND from View > Other Windows in an interactive VS. That is now the single discriminator between "VS never hosts a programmatically-shown pane" and "VS 18 cannot host this at all" — and it needs a human at the keyboard, not automation.

PRIOR NEXT EXPERIMENT (now done, see above): override CreatePaneWindow and log it; switch Float -> Tabbed; defer the show to ShellInitializedContext. If CreatePaneWindow never logs, the shell is deferring realization (our bug, fixable). Also assert ReferenceEquals(window.Content, control) and read VSFPROPID_DocView to prove we are probing the object the shell actually hosts.

SUPERSEDED RECOMMENDATION (was premature) - descope the VS 2026 embedded cockpit. On VS 2026 Insiders 18.8.11925.187 a programmatically shown ToolWindowPane.Content does not render. Ship the VS 2026 extension as commands only (open the cockpit in a browser + status-bar state) - a real surface on the same backend - and revisit the embedded cockpit at VS 18 GA or when MS documents the composition-shell hosting contract. The other 5 surfaces already carry a real embedded cockpit. Untried leads: open the window MANUALLY from View > Other Windows (every attempt so far was programmatic), IVsWindowFrameNotify3.OnShow, or ToolWindowPane.Window (raw HWND) instead of .Content. See memory vs2026-classic-vsix-webview2.

PRIOR UPDATE 2026-07-16 12:1x - MY OWN "USE F5" RECOMMENDATION IS WRONG. Retracting it. F5 does not use VSIXInstaller; it uses MSBuild's DeployExtension target. I set <DeployExtension>true</DeployExtension> (the scripted equivalent of F5) and it fails immediately:

error VSSDK1048: Error trying to read the VSIX manifest file ...\obj\Debug\extension.vsixmanifest.
Could not load file or assembly 'System.Collections.Immutable, Version=10.0.0.8, ...'
The VSIX itself builds fine (exit 0) — only the DEPLOY task breaks, on an assembly-binding failure inside Microsoft.VSSDK.BuildTools 18.9.820. Since F5 drives that same target, F5 would very likely hit the same error. So "just open it in real VS and hit F5" is not the clean escape hatch I claimed it was. Anyone trying it should expect VSSDK1048 first, and may need to fix the System.Collections.Immutable binding (or find the version VS's own devenv resolves, since devenv may bind differently in-process) before F5 works.

Also newly observed: the Exp instance WEDGES ON REPEAT LAUNCH. Clean cycle (install → verify DLL on disk → /updateconfiguration → launch) gives pass-1 devenv healthy at 353MB responding; killing it and launching again gives pass-2 stuck at 33MB, no probe, no load. That reproduces the "48MB empty title" wedge seen earlier and is almost certainly what has been poisoning the last several attempts — it is a property of repeatedly cycling the Exp hive, not of the extension.

THE BEST EVIDENCE WE HAVE IS STILL THE EARLY RUNS, when the hive was healthy and the package DID load:

21:02:59.966 ctor: control constructed
21:02:59.972 frame.Show() hr=0x00000000        <- S_OK, VS says the window is shown
21:03:00.008 CoreWebView2Environment created, runtime=150.0.4078.65
22:13:12.987 ShowToolWindowAsync returned: window=ok frame=ok   (Lane C, later, hack removed)
22:13:12.989 frame.Show() hr=0x00000000
In both: Loaded never fires. That is the finding. Everything since has been fighting the environment.

PRIOR UPDATE 2026-07-16 07:5x — hive REBUILT, and the experiment STILL has not produced a result. Deleted both 18.0_7c1948ebExp dirs (Local + Roaming; the real 18.0_7c1948eb was never touched and is fine) and recreated via /updateconfiguration. That fixed a real fault: devenv used to hang at startup at ~48MB with an empty title; it now launches clean (351MB, responding, titled "Microsoft Visual Studio"). Reinstalled the TextBlock spike into the fresh hive — pkgdef registration is verifiably perfect (CodeBase=$PackageFolder$\VsixSpike.dll, AllowsBackgroundLoad=1, AutoLoadPackages under the NoSolution GUID {adfc4e64-...}, ToolWindow registered Style=Float) — and the package still never loads: no probe line, no ctor. An extensions.configurationchanged marker is present, i.e. VS knows the extension set changed but has not reconciled it. Honest status: ~4 cycles spent on ENVIRONMENT faults (corrupt cache, hung devenv, timed-out chains, MSYS arg mangling, a Remove-Item safety hook false-positiving on the VS path) and ZERO cycles that actually answered the question. The question is still exactly: does ANY WPF content realize in a VS 18 tool window, or is this WebView2-specific? Recommend the next session STOP re-running the same install/launch loop and instead build the spike as a normal VSIX project opened in the REAL VS (F5 → Experimental Instance is the supported, tooled path — StartAction=Program/StartArguments=/rootsuffix Exp are already in the csproj) rather than driving VSIXInstaller + devenv from a script. The scripted path has now failed for four distinct environmental reasons and is not earning its keep.

PRIOR STATE (superseded, kept for the record): the experiment was BLOCKED BY A CORRUPTED EXP HIVE. The next test (strip WebView2 entirely, host a plain TextBlock, see whether ANY WPF content realizes — if a TextBlock also never fires Loaded, this is VS 18 composition-shell hosting of ToolWindowPane.Content and every further WebView2 cycle is wasted) could not be run. The Exp hive 18.0_7c1948eb**Exp** is damaged after many install/uninstall cycles: ActivityLog shows CPkgDefCacheNonVolatileBase: PkgDef cache creation failed. Going volatile and trying again., VSSDK\ResetExperimental.cmd exits 1 and does not reset, and after a clean /updateconfiguration (exit 0, caches rebuilt 07:47) devenv still hangs at startup at ~48MB with an empty window title. Package never loads; no probe line. This is an environment fault. NEXT: rebuild the Exp hive from scratch (delete %LOCALAPPDATA%\Microsoft\VisualStudio\18.0_7c1948ebExp + the matching %APPDATA% dir, then devenv /rootsuffix Exp /updateconfiguration), THEN run the TextBlock isolation test. The real VS install (18.0_7c1948eb, no Exp suffix) was never touched and is fine.

One useful existence proof found: VS 18's own shell ships Microsoft.Web.WebView2.Core.dll in Common7\IDE\PrivateAssemblies, so WebView2 demonstrably works inside the devenv process. The open question is narrowly whether OUR tool window realizes its WPF content — not whether VS 2026 can host WebView2 at all.

VS 2026 path decided by spike (see memory vs2026-classic-vsix-webview2): classic in-proc VSIX + WebView2, NOT the "modern" VisualStudio.Extensibility SDK — that SDK has no 18.x release and its WPF Remote UI cannot host a webview at all, while Microsoft.VSSDK.BuildTools ships 18.x and VS 2026 ships v18.0 VSSDK targets. This means ONE cockpit across all six surfaces instead of a hand-written WPF twin that drifts.

Distribution stays PRIVATE per the design below — sideloaded VSIX + tailnet gallery + fleet-dispatch to all 4 PCs. No marketplace listing. (An earlier brief in this session wrongly said "VS Code Marketplace + Open VSX"; nothing was published — corrected.)

Mockups in the FLT-13 artifact. Thin clients on the cockpit API — VS Code: activity-bar tree (needs-you / running / queue / fleet) + status-bar gate + diffs open in the real editor (TS, UI-only; logic stays server-side C#). VS 2026: C#/VS SDK docked tool window + status bar. Distribution PRIVATE: sideloaded VSIX + self-hosted tailnet extension gallery (VS private gallery atom feed; VS Code --install-extension), pushed to all 4 PCs by fleet-dispatch. No marketplace listing.

FLT-142 · Vikunja board mirror + Option-1 failover — Done — deployed to all 4 PCs 2026-07-19 (WT-902b) (Jira FLT-142 · Vikunja proj 7/8 · master d1d1d0e)

Vikunja stood up as the third board-redundancy leg (Jira source + BOARD.md canonical + Vikunja derived mirror). One-way idempotent Jira→Vikunja sync (fleet-harness/ops/board-sync/), single-writer FleetBoardSync task on greatroom every 30 min (verified result 0; self-healing). Full mirror live: FLT (142) → Vikunja project 7, WING (86) → project 8. Codex review gate (6 findings, 3 HIGH on the restore path, all fixed). Backup leg = vikunja-dr VikunjaNightlyBackup (OneDrive) + VikunjaRestoreVerify (test-restore). Failover depth set by a 9-seat LLM council, unanimous Option 1 (rebuildable + replicated backup); hot HA rejected as over-engineering for a derived, minutes-to-rebuild mirror (report llm-council/reports/2026-07-19_003152_evaluate-the-right-failover-depth-for.md). Recovery on any PC: Rehydrate-Vikunja.ps1 -FromJira. Global ~/.claude/CLAUDE.md standing rule added. Known follow-up: vikunja-dr VikunjaHealthzWatch task fails to register (bad trigger duration — FLT-9 installer bug, flagged separately).

FLT-15 · agy quota ledger + agy-Claude reserve gate (usage-governor) — Done — Jira FLT-49 closed by Andrew 2026-07-17 after Raft HA landed; residual sub-items (skills-bypass undercount, fleet ledgerPath rollout, Raft deploy) tracked below, spin out new tickets if picked up (Jira key FLT-49 · Vikunja 48 · WT-902b, 2026-07-17)

Raft HA LIVE ON THE FLEET 2026-07-17 (WT-902b) — drill GREEN on real machines, single-writer authority replaced by the 3-voter Raft cluster + bedroom observer. Timing-stabilized (0 elections/9min). All 3 availability follow-ups (wedge watchdog, client peer-walk, E3 retro review) landed + rolled fleet-wide 2026-07-18 (usage-governor master 34418ed) — watchdog task Ready on gaming/streaming/bedroom, greatroom pending one elevated command. Runbook docs/RAFT-DEPLOY-RUNBOOK.md in usage-governor: usage-governor master → c553721 on origin (the 10 gated commits from wt/WT-0026/FLT-17-raft-ha, tip c091939; post-land suite 273/273 green — the branch name's "FLT-17" is the legacy board-ID space, NOT Jira FLT-17). The admission authority's Raft HA (3 voters + stateless observer, replicated quota ledger, leader-only admit, client AdmitId exactly-once) passed its final council re-gate: the last open item — a minority-live-leader partition test (RAFT-BLOCKERS #4, a still-running leader severed from the majority must not commit) — now runs as an executed fault-injection test via a blockable outbound IConnectionFactory (dotNext CustomTransportConfiguration seam; destination-side proxies provably cannot cut a dialing leader). Negative-controlled 3 ways (no-block RED, inbound-only RED reproducing the historical failure, executable NEGATIVE_CONTROL in CI); 273/273 green; seats codex+gemini+grok+local, codex chairman, all findings fixed. **Raft stays opt-in (raft.enabled=false); live authority = single-writer on gaming, untouched. Deploy = separate Andrew gate; pre-deploy gaps: WAL compaction (RAFT-BLOCKERS

2), Raft-port mTLS/firewall (#3).**

Follow-up 2026-07-18 (WT-902b) — Jepsen flaky-test fix committed 09184ae on wt/WT-0026/FLT-17-raft-ha (staged ONLY AgyRaftJepsenTests.cs): four converged-ledger asserts raced async follower-apply — AssertLedgersConverged reads every voter, but the tests waited on one node (or, for the happy path, not at all) before asserting, so a follower still applying committed entries could trip "expected N entries, found M" under full-parallel load. Each guard now waits on ALL voters (WaitUntil(cluster.Voters.All(v => Count == N))). Read-side race, independent of the E3 propose-timeout fix 3b33da0. Verified full suite 295/295 green + Jepsen class 8/8 under a stress loop. Local branch ahead of origin by 4 (b81270a, 2816953, 3b33da0, 09184ae) — held for the coordinated landing pass, not pushed.

Landed 2026-07-16 (2aba701, deployed + verified): agy-status --json, a versioned read-only status contract (schema: agy-status/v1). The council pass turned it into one rule — the score must derive from the same binding constraints as the gates — after finding four places where it did not: Claude's locked read a display tier the gate ignores; Gemini's proximity ignored the tapering floor (55% spend is ~92% of the way to denial under a 40% floor); weighted pools scored against 100% when ComputeTier REDs at 85%; and the Claude reserve was counted as routable. Ledger presence now comes from ONE open (TryReadSince) — the old Exists-then-read raced, and an unreachable share threw instead of degrading.

NOT done, and this is the actual ticket: the ledger still is not fleet-global (no agy block in the live config → local path) and still undercounts (skills call agy.exe direct, bypassing the admit). Until both close, cap_proximity is a confident lie and must not be wired — see the gate-2 entry under FLT-1. The remaining work is a shared ledgerPath on all 4 PCs plus an admit helper the skills actually call; the harness consumer already exists on wt/WT-3e93/FLT-15, held for that day. Google AI Ultra Max ($200/mo, 20x Pro) exposes four fallback lanes through the agy/Antigravity CLI that the fleet was not modelling: Gemini 3.5 Flash + 3.1 Pro (one unified pool, drawn at API prices, 20x multiplier — the big pool), Claude Sonnet/Opus 4.6 and GPT-OSS 120B (separate small fixed caps). Field-verified: one agy-Claude conversation burns ~60% of a 5h window even on Ultra; windows are 5h refresh plus a weekly cap (Google copied Anthropic); credits are paid overage only; no quota API exists. Probe-verified 2026-07-14: agy models lists all four; Sonnet + GPT-OSS lanes answer live.

Council verdict (fable tier, ranking Claude > Grok > Codex > Gemini > local; report llm-council/reports/2026-07-14_222458_fleet-routing-policy-question-context-researched.md): - agy-Gemini = primary offload pool. Flash default; 3.1 Pro High escalate-only (second gate failure, or security/architecture pre-escalate) — not the routine "hard" path. - agy-Claude is NOT a ladder rung — an out-of-band interrupt budget: triple gate (native Claude RED AND ceiling skip-list task AND no acceptable substitute), 1 call/5h window, ≤2-3/day, gated on the weekly cap (the 5h refresh is a decoy at ~60%/convo), Sonnet-first, one-shot print mode, size-bounded, no follow-ups (incomplete → Gemini Pro High, never a second Claude call), reason codes (native_red/review_gate/council_synth) on every invocation. - GPT-OSS-as-Haiku-lane REJECTED — it is a third scarce pool, not free relief. Burst overflow behind Grok/local only; never an arbiter/correctness chair. - Corrected ladder: Fable → Opus/Sonnet → Codex → agy-Gemini → Grok → agy-GPT-OSS → local ollama, with agy-Claude out-of-band alongside it.

Build (C#, in usage-governor): fleet-global single-writer ledger — 4 PCs × N sessions share one Google account, so per-session ledgers each think the pool is full and drain it 4x; must cover every agy consumer (offload subagents, /gemini-review, the council Gemini seat, the fleet-dispatch agy lane). Reserve units not percentages (no quota API ⇒ % is fake precision on an unknown denominator): always ≥1 agy-Claude invocation held per window; Gemini weekly floor ~40% Monday tapering to ~15% toward the weekly reset (floor covers remaining calendar exposure). Weekly-exhausted = hard-deny state until rollover (else agents thrash every 5h and burn the remainder). 429s are ground truth → recalibrate the ledger on every limit hit, distinguishing quota-lockout from transient transport failure (misclassification either corrupts the ledger or triggers a retry storm). allow_paid_overage=false default; floor = hard deny into the next tier, never "continue on credits". Pre-route token estimate (a massive-diff one-shot can burn 100% of a window). Weekly agy models + dry-run probe (labels/quotas drift silently; metering already regressed once in March 2026, so 60% is a point-in-time number). Council accounting: agy-Sonnet/Opus counts as a Claude seat for the ≥3-frontier-seats family-diversity rule.

Feeds FLT-6 (routing.yaml grows the agy lanes) and FLT-13 (cockpit surfaces the ledger). Memory: agy-multimodel-fallback-quotas.md. Gate via /council-code-review before landing.

FLT-16 · CI tooling pack fleet-wide (vuln gate + InspectCode + mutation baseline) — Done (Jira key FLT-60 · Vikunja 51 · WT-df2b, 2026-07-15: LANDED on origin/master, all 11 repos)

Standard analysis/security gates for every C# repo. Contract + rollout status: usage-governor/docs/ci-tooling-pack.md (piloted in usage-governor, council-gated there).

Pack: (1) vulnerable-package gate — enforcing, fails the build; (2) InspectCode (inspect.yml) — gates error-severity only (pilot: 177 findings / 0 errors; gating warnings would red every repo on day one and train the fleet to ignore a red X); (3) Stryker (mutation.yml) — report-only, weekly, staggered cron per repo; (4) npm audit + ESLint where a real JS/Angular toolchain exists.

Mutation stays report-only ON PURPOSE. This infra scores VsTest socket timeouts as KILLED mutants — the usage-governor pilot run itself logged 3 timeouts at 72.40%. The WorkWingman council removed a broad enforcing gate on 2026-07-11 for exactly this; a fleet-wide threshold on the same infra would repeat that mistake at 10x blast radius. Promote per-repo only once the score is real and the runner is stable.

Council gate (pack template, 6 seats: Codex, Gemini, Grok, qwen3:8b, gaming qwen3-coder:30b + devstral:24b; streaming llama3.3:70b FAILED at the 600s member cap). Chairman 0C/3H/4M/1L, all implemented. The three Highs were real and would each have multiplied 10x: - vuln gate failed OPEN — dotnet list package --vulnerable exits 0 when it FINDS vulnerabilities but nonzero when it FAILS TO RUN, and a failed scan emits no > rows, so parse-only reported a dead scan as a clean tree. Now checks $LASTEXITCODE first (verified: broken sln → exit 1, rows 0 → old version passed green). - floating dotnet tool install -g on persistent runners → results depend on leftover profile state / whatever NuGet serves. Now pinned via .config/dotnet-tools.json + tool restore/tool run. - identical Monday 06:00 cron in all 10 repos → hour-long jobs dogpile the shared home-ci pool, contradicting the workflow's own anti-starvation rationale. Now staggered (table in the pack doc).

Verified per repo by the orchestrator, not on the agent's word (FLT-3): fleet-dispatch 179/179, fleet-telegram 211/211, worktree-identity 207/207, token-roi 127/127, membus 101/101, llm-council 69/69, PavlokPager 59/59, claude-mem-house 31/31, audio-loop-mcp 22/22, WorkWingman build+gate, usage-governor pilot (Stryker 72.40%). 0 vulnerable packages fleet-wide.

Implementation offloaded to Codex (governor hit RED mid-sweep — projected 173%; Claude routed, reviewed and verified only).

Open: (a) all 11 branches UNPUSHED — awaiting land decision; (b) claude-mem-house has a stronger gate than the rest (asserts a positive clean-scan marker, so an exit-0 scan printing nothing can't read as clean) — backport to the other 10; (c) stryker-js does not bootstrap against Angular's builder-managed vitest ("No tests were executed") — frontend mutation parked, not claimed; (d) fleet-mission-control mutation baseline 39.19% needs real tests.

Follow-on (2026-07-15, WT-975b): test-impact-analysis for the pack's Stryker component — RESEARCHED, REJECTED, no work to do. Question was whether to scope mutation runs to changed code (TIA / affected-test selection) via GHA or MCP. Council convened (llm-council opus, 5/5 seats; report llm-council/reports/2026-07-15_195506_what-tooling-exists-to-pinpoint-test.md). The council's verdict is moot and the log carries a correction block — do not act on it. Measurement afterward killed the premise:

  • --coverage-analysis perTest is already the default. Stryker.NET's documented default IS perTest (https://stryker-mutator.io/docs/stryker-net/configuration/). All 11 backend configs leave the key unset, i.e. they have been running perTest all along. The council's #1 "free headline win" is a no-op.
  • No .NET mutation bottleneck exists. Real durations 2026-07-15: llm-council 2m35s (75 tests), membus 3m15s (67), claude-mem-house 5m14s (26), usage-governor 10m48s (157), audio-loop-mcp 15m23s (16). Separate repos → they run in parallel; fleet mutation wall-clock ≈ 15 min, bounded by the slowest single repo. TIA buys a few minutes against false-negative selection risk + stale-baseline score inflation. Bad trade.
  • No MCP server exposes TIA / coverage-diff → affected-test selection today (unanimous, and verified — Datadog/Develocity/Codecov/Sonar MCPs expose coverage queries, no selector). Nothing to adopt.
  • Verified NOT broken while measuring: staggered crons are real (Mon 06:00 usage-governor / 10:00 llm-council / 12:00 membus / 20:00 claude-mem-house — the High from the pack council holds); audio-loop-mcp only appears to lack mutation.yml locally (checkout 2 commits behind origin — it is on origin/master).

Kerr note for whoever revisits this: the reward here is minutes-saved/tests-skipped (countable, dashboard- friendly); the goal is regressions caught (a non-event nobody gets credit for). If TIA is ever reconsidered, escape rate — mutants/tests failing a nightly unscoped run that a scoped run skipped — must be published beside minutes saved, or the number is meaningless. Stryker baselines invert the metric outright: a stale baseline raises the reported score while real coverage decays. Baseline TTL + expired-means-full-run is the mitigation, and it is not optional garnish.

WorkWingman mutation CI — NOT part of FLT-16. ⚠️ This entry was written wrong TWICE (claim, then retraction). Third version, timestamp-verified. If you are reading a "capacity" explanation anywhere, it is the bad one.

What was actually true. Commit b606a93 (2026-07-08, "route jobs to the self-hosted warm pool") moved 8 ci.yml jobs and both mutation.yml jobs onto [self-hosted, workwingman, linux, docker, x64] when cloud minutes ran out. It pointed them at a designed pool of one Linux Docker runner + one Windows host runner per PC. The Windows half was registered. The Linux half was never built, and no provisioning code was ever committed. For a week, no runner matched the linux label, so those ten jobs per run queued until GitHub's 24-hour limit cancelled them. mutation.yml: 17 cancelled, 0 passed, ever. Any mutation score attributed to CI predates this and did not come from CI. (Source: .github/runner/README.md, PR #23.)

Timeline (verified against commit timestamps and docker inspect, not inferred): - 2026-07-08 — b606a93 routes 10 jobs to a linux label with nothing behind it. - 07-08 → 07-15 23:11 CDT — every one of those jobs queues to the 24h limit and dies. This is the window of the failures this entry set out to diagnose. - 2026-07-15 23:11:49 CDT — peer session lands 0f787ef "provision the Linux runner the workflows already required" (Dockerfile + start-runner.ps1 + README). Container ww-andygreatroompc-linux starts 41 seconds later at 04:12:30Z. - 2026-07-16 02:15 CDT — peer lands 228c3cf, raising the container cap 5g → 6g for StrykerJS. - 2026-07-16 04:22:25Z — mutation-gate (run 29467990821) executes for the first time in the repo's history. - 2026-07-16 04:54:37Z — killed at 32 min by cancel-in-progress when push 6cab516 landed at 04:42:43Z.

Three wrong calls, and why. Read this part; it is worth more than the finding. 1. ~~"Nothing answers that label set."~~ — Was RIGHT for 07-08 → 07-15 23:11, i.e. for exactly the failures being diagnosed. It only became false 34 minutes before it was checked, because a peer had just fixed it. 2. ~~"The runner is online, labels match — the cause is capacity."~~ — The retraction was itself WRONG. The runner was online (34 min old), but there was never a capacity problem: there was a nonexistent runner. Retracting a correct claim on a 34-minute-old observation is the worst error in this entry. 3. ~~"No OOM: zero memory errors in the log, container never restarted."~~ — Invalid method. Per start-runner.ps1: a worker killed by the cgroup OOM killer does NOT set the container's OOMKilled flag — only PID 1 dying does. The starvation is invisible to exactly the two measurements used, and surfaces as Stryker's opaque "Test runner crashed." The peer's 5g→6g raise was the real fix.

Root cause of all three: sampling a system a peer session was actively repairing, and reading their in-flight fixes as findings. Each diagnosis was published confidently and overturned within the hour. Contributing artifact: GitHub reports run status as queued while any job in it still waits, so runs?status=in_progress reads empty while a job is demonstrably running — run status ≠ job status; query /actions/runs/<id>/jobs. Before diagnosing shared infra: check git log for peer commits in the window, and date every observation against them.

Frontend mutation 94.16% on record is not merely stale — it never came from CI (local run 2026-07-15 measured 24.12%). CI had never run it.

Method lesson: five seats debated Coverlet attribution semantics and baseline TTL design for ~10 minutes of wall-clock; a 10-minute gh run list would have ended the question before it was worth asking. Measure the bottleneck before convening a council about it — a council will argue your premise, not tell you it is false. Note also the chairman seat and the top-ranked seat were the same lineage ("4-of-5 ranked A first" reads more independent than it was), and both house councils were unreachable (gaming dropped on FLT-63, streaming never queried), so no non-Anthropic lineage checked this.

FLT-61 · Tavily narrow-adopt: shared C# web-search MCP wrapper on membus — Backlog — blocked on BYO key (Jira key FLT-61 · WT-8f94, 2026-07-15: council-approved, not started)

Council verdict (llm-council opus, 5/5 seats converged independently): NARROW-ADOPT. Report: llm-council/reports/2026-07-15_103940_should-we-adopt-tavily-the-llm-oriented.md.

The gap is NOT search for Claude — WebSearch/WebFetch + the grounded Gemini/Grok seats already cover research at zero marginal cost. Three real gaps: (a) deployment — Codex and Ollama have no web tool at all, and a local model doing RAG has zero grounding today; (b) capability — WebFetch is one-URL/one-prompt, there is no primitive for "ingest all the NATS docs", so map/crawl is the actual purchase; (c) council parity — non-Claude seats can't cite the evidence the Claude seat saw. Capability purchase = crawl/map/extract; deployment reason = Codex/Ollama. Conflating the two is how this creeps into a paid fleet-wide default.

Scope: free tier only (1,000 credits/mo, alert at 800, no PAYG without an explicit decision) · one key server-side behind a C# MCP server on the membus, generic IWebSearch + Tavily adapter so Brave/Exa/Firecrawl are a config swap · basic search + extract for Codex/Ollama, map/crawl page-capped on demand · research and advanced hard-denied at the wrapper · wrapper owns credit ledger, URL-hash cache, page caps, truncate-to-disk, shared rate limiter, per-seat quotas · fallback native → Tavily basic → WebFetch → fail loudly.

NOT in scope: per-seat keys (ever) · routing Claude/Gemini/Grok through it by default (double taxation — you pay Tavily credits and model tokens, converting a free search into a paid one) · the vendor MCP server as permanent surface (fine for a time-boxed trial; it hands every seat a raw key with no credit accounting, exactly what the governor prevents) · a JSON-schema extraction gateway (Tavily returns cleaned page content, not schema-conformant objects — the Ollama seat proposed this from a misreading; four seats caught it).

Sharpest failure mode: the Research endpoint burns up to 250 credits in ONE call = 25% of the monthly free tier. Hard-deny it. Others: free-tier exhaustion blinding Ollama mid-overnight, crawl-loop burn, shared-key 429 starving the fleet, wrapper crash blinding seats (must degrade loudly, never hallucinate), scope creep to the Claude seats. Lock-in: near-zero — search+extract is a commodity; the only real lock-in is behavioral (prompts learning Tavily's result shape) and the interface kills it.

Unverified — do not propagate: Grok asserted (unsourced, uncorroborated) that Nebius acquired Tavily Feb 2026 and that 2026 benchmarks rank Brave/Exa/Firecrawl above Tavily. Chairman refused to certify both. Free-tier-only prices in roadmap risk either way; the exit condition is a head-to-head on our own query mix, not a leaderboard.

Exit condition: sustained >800 credits/mo → Brave/Exa head-to-head on our real query mix before paying anyone. Blocked on: BYO credentials — Andrew creates the account and supplies the key.

Caveat on the run: both house open councils were unavailable (streaming-pc MCP never connected; gaming-pc transport dropped mid-call twice), so this verdict rests on the 5 CLI seats with no open-model corroboration. Codex's peer-review pass also crashed on non-ASCII stdin (input is not valid UTF-8 (invalid byte at offset 2745)) — same root cause shape as the FLT-16 PowerShell non-ASCII bomb, unticketed as of this writing.

FLT-62 · llm-council writes child stdin in the ANSI codepage, not UTF-8 — In Review — gate PASSED, awaiting land + republish (Jira key FLT-62 · WT-8f94, 2026-07-15: 2377379 on wt/WT-8f94/FLT-62, NOT pushed)

src/CliRunner.cs:67 pinned StandardOutputEncoding/StandardErrorEncoding to UTF-8 but never StandardInputEncoding, so Windows wrote child stdin in cp1252. Every stage-2 review prompt (which embeds other seats' answers — LLM prose full of em-dashes and smart quotes) crossed the pipe corrupted. Codex refused it outright (input is not valid UTF-8, invalid byte at offset 2745) and the council continued with 4/5 review seats and still exited 0.

Worse than the error suggests, and measured, not inferred: without the fix an em-dash (UTF-8 226 128 148) arrives at the child as byte 45 — an ASCII hyphen — because the ANSI encoder best-fit maps rather than failing. Codex is simply the only stdin seat that validates its input and says so. The claude and local/ollama seats (promptVia: "stdin") were silently receiving mangled review prompts and returning confident rankings on corrupted text. The arg seats (gemini, grok) pass via argv and were unaffected.

Fix: StandardInputEncoding = new UTF8Encoding(false) — deliberately NOT Encoding.UTF8, whose encoderShouldEmitUTF8Identifier would prepend a BOM to the child's first stdin bytes and trade one corruption for another. Plus a byte-level regression test proven to fail without the fix (the pre-existing stdin test used pure ASCII, which is exactly why CI stayed green while the pipe was broken). Same family as the FLT-16 PowerShell non-ASCII parse bomb: non-ASCII crossing a process boundary with an unpinned encoding. FLT-58 (failed seat drops out, run still exits 0) is what let this hide.

The runtime smoke found a SECOND live bug the 92 green tests could not. Program.cs read the piped question via Console.In, which decodes with the console INPUT codepage (437 here) — so a non-ASCII question was mojibake before any seat saw it, the mirror image of the same bug on the way in. Proof, same input, real binary + real codex CLI: before, the report recorded the question as Here they are ΓÇö µùѵ£¼Φ¬₧; after, Here they are — 日本語, echoed back intact by the seat. The unit suite never caught it because it never feeds the real binary a real question — Program.cs is excluded from coverage by design (TESTING.md). Both ends now pinned.

Gate (council-code-review, 5 seats seated): codex (chairman + member), gemini, grok, local qwen3:8b, gaming-PC qwen3-coder:30b. Chairman surfaced exactly one finding — the capture path was interpolated into a single-quoted PowerShell literal, breakable by a temp path containing an apostrophe — applied. Dropped: the argv-has-the-same-bug claim (refuted by probe — ArgumentList → CreateProcessW → UTF-16, round-trips byte-identical) and the console-codepage-must-change claim (the child reads a redirected pipe, not a console). Streaming-PC skipped (box off, TCP probe to 10.0.0.26:37878 False); gaming-PC qwen3-next:80b FAILED (canceled at 863s, server member cap). Local seat's first canary was a false negative — $env:OLLAMA_HOST did not inherit into the pwsh child, so it fell back to :11434 and got connection-refused; healthy on retry in 3.5s.

Validation (run by hand, FLT-3): pwsh -File tests/Invoke-CI.ps1 — the CI entrypoint per ci.yml:33, not a hand-picked dotnet test — exit 0, 92/92, line coverage 100% (floor 70%). Runtime smoke exit 0.

NOT DONE — the fix is committed but not live. publish/ is gitignored, and the llm-council skill executes llm-council/publish/llm-council.exe from master. Landing the branch is not enough: master's publish/ must be rebuilt or every council run keeps the bug. Same trap as FLT-51 (publish/ gitignored ≠ deployed).

FLT-63 · House open councils unreachable in practice: open_council exceeds the MCP client's drop ceiling — Backlog (Jira key FLT-63 · WT-8f94, 2026-07-15)

Surfaced during the FLT-61 Tavily council: both house councils absent, so a council verdict shipped with zero open-model corroboration. Not a server fault — :37800/health answers 200 in 0.11s and ask_model on gpt-oss:20b returns instantly; ICMP loss to 10.0.0.7 is the firewall dropping ping, not an outage. Root cause is the known subagent-mcp-600s-cap: the MCP client abandons long calls at a variable ~390-700s, and open_council serializes N models on one GPU with weight hot-swaps between them. No member subset is both small enough to be safe and large enough to be a council. Fix direction: submit+poll job API (open_council_submit → jobId, open_council_status) so a client drop stops destroying completed GPU work; same treatment for code_review_council and the CPU-bound streaming PC. Also open: the streaming-PC MCP server did not connect at all this session.

FLT-12 · Macro self-host evaluation — Blocked (optional)

Only if comms-stack consolidation (email/chat/docs) becomes a goal — NOT a harness need (council: reject; MCP write surface unproven). If opened: AGPL self-host on spare capacity, DR on claude-mem pattern (Postgres replication + warm standby + watchdog), Tailscale-only exposure, license note: modifications served over network trigger AGPL source-sharing.


Delivered (pre-board fleet/tool work, retro-tracked 2026-07-14)

WW product work lives on the WorkWingman board (docs/BOARD.md + artifact kanban) — not duplicated here.

  • FLT-D1 worktree-identity — C# CLI + UserPromptSubmit hook, session naming/governance registry · Done
  • FLT-D2 usage-governor — scanner + GREEN/YELLOW/RED tiers + PreToolUse spawn gate, LIVE · Done
  • FLT-D3 fleet-dispatch — C# command queue + listeners, 4/4 PCs operational · Done
  • FLT-D4 fleet-telegram — C# Telegram command center, phase 1+2 · Done
  • FLT-D5 NATS fleet.v1 bus + MemBus C# — wire contract, 3 trust tiers, signed envelopes · Done
  • FLT-D6 llm-council — C# 5-seat council (answer/peer-review/verdict) + house council MCPs · Done
  • FLT-D7 token-roi — impact-per-token metering, CPDT, Stop hook, statusline · Done (phase 2 owed)
  • FLT-D8 PavlokPager — CLI + skill, wake-the-human escalation with budget · Done
  • FLT-D9 claude-mem house — worker :37777 + Docker server :37877 + DR standbys (bedroom, streaming) · Done (gaming standby outstanding)
  • FLT-D10 claude-session-watchdog — Scheduled Task pager on overnight session death · Done
  • FLT-D11 audio-loop-mcp — C# WASAPI loopback + Whisper STT + SAPI TTS MCP · Done
  • FLT-D12 caveman suite — compression skills + cavecrew subagents + savings scripts · Done
  • FLT-D13 tools org — andrewjonesdev-tools, 8 private repos, pipelines, home-ci runner group on 4 PCs · Done
  • FLT-D14 codex-harness-mirror — harness fleet (Codex/Gemini/NanoClaw/Odysseus/Grok) shared brief+brain, inverted review · Done
  • FLT-D15 home bootstrap kit — OneDrive PC-Bootstrap per-PC setup.ps1 · Done
  • FLT-D16 SSH mesh — all 4 PCs, PowerShell shells, EncodedCommand nesting · Done
  • FLT-D17 Grok MCP — healthy on 4 PCs · Done
  • FLT-D18 Docker update-outage fix — AutoDownloadUpdates off + root-cause writeup (2026-07-14) · Done

Prior open work (retro-boarded 2026-07-14, was tracked only in memory/repo boards)

  • FLT-B1 CMH-5 claude-mem failover watchdog — SHIPPED master d150527 (3-fail + 5-min grace failover, 5-min failback) but NOT INSTALLED on any PC; install fleet-wide. Feeds/merges with FLT-W1. · Backlog
  • FLT-B2 claude-mem gaming-PC DR standby — bedroom + streaming LIVE; gaming outstanding (blockers: logged out + UAC) · Backlog
  • FLT-B3 token-roi phase 2 — owed from TROI epic (two-ledger + Kerr follow-through) · Backlog
  • FLT-B4 fleet.v1 bus envelope mismatches — 2 mismatches between worktree-mail + fleet-telegram maps vs contract · Backlog
  • FLT-B5 worktree-identity hook fail-open fix — ed26858 (JSON-deny + add-A rescope) built; fleet-wide redeploy pending · Backlog
  • FLT-B6 fleet-dispatch listener hardening — RunLevel Highest + firewall rules on all 4 PCs · Backlog
  • FLT-B7 xAI credential vaulting + Grok seat polish (SuperGrok remaining work) · Backlog
  • FLT-B8 codex gpt-5.6 retest — bump llm-council fable tier when account enables it · Backlog
  • FLT-B9 CI exit-code masking fix across tool repos (WinPS wrapper propagation) · Backlog
  • FLT-B10 fleet-telegram acceptance completion — all worktrees × models × harnesses × councils reachable · Backlog

In flight (other sessions / blocked)

  • FLT-W1 claude-mem auto-failover watchdog — spawned task running (own session) · In Progress
  • FLT-W2 MCP dev-tool suite rollout (FLT-32) — DONE: 14 PRs merged. ESLint+Angular MCP (pinned, gated) + ReSharper CLT 12 repos + docker-autoheal (claude-mem) + read-only SQLite MCP (fleet-telegram). MSSQL deferred (no SQL/EF targets); KittySploit rejected (ZAP already in WW ci.yml). pwsh .mcp.json launchers need a Claude Code restart to verify. · Done
  • FLT-W3 WW-77 LiteRT.js embeddings spike — prototype c96d601, blocked on Gemma model availability · Blocked
  • FLT-W4 fleet-routine — cross-harness routines (WTS trigger + C# runner + NATS registry), not built · Backlog
  • FLT-W5 polyharness parity phase 2 — fleet-dispatch mirror @9cede5b · In Progress

Log

  • 2026-07-14 · Board created from council verdict + revised universal-harness framing (session WT-0924).
  • 2026-07-14 · Vikunja bootstrapped (was empty — zero users): fleet-agent service user + project 2 "FLEET — Universal Harness" + all 12 tickets mirrored. Creds + 1yr API token: C:\Users\fives\docker\vikunja\fleet-agent-credentials.json (local only, NOT for any repo). Board URL: http://ANDYGREATROOMPC:3456/projects/2 · Jira mirror pending FLT-10 account step.
  • 2026-07-14 · Jira mirrored: sites workwingman.atlassian.net (team: WW + FLEET) and andrewjonesdev.atlassian.net (private, invite nobody) created by Andrew (30d Premium trials, no card — auto-drop to Free). FLEET project = KAN-1..12 mirroring FLT-1..12 titles at https://workwingman.atlassian.net/jira/software/projects/KAN/list. Pending: Andrew's OTP step-up at id.atlassian.com → API token fleet-harness-sync → descriptions via REST + Rovo MCP wiring + project key rename KAN→FLT (cosmetic).
  • 2026-07-14 · Jira fully wired: API token fleet-harness-sync (expires 2027-07-12) stored at C:\Users\fives\.fleet-secrets\jira.json; project key renamed KAN→FLT (FLT-1..12 aligned); full descriptions pushed via REST; 23 retro issues created (18 Delivered → Done, 5 In-Flight); Rovo MCP atlassian-rovo registered user-scope — OAuth grant pending (run /mcp → authenticate). FLT-10 now ~70%: remaining = OAuth grant + agent statuses + custom fields.
  • 2026-07-15 · FLT-1 live run CLEAN on the designed path, first time (WT-f255, run FLT-1-final on 765fa3b): codex implemented on the first attempt (no escalation), claude reviewed blind, locked_pools: [], zero drift, validation reran pytest itself → 3 passed, branch wt/FLT-1-final/harness-b0d2e1d1. Every prior live run had reached the gate only via failover; this is the first where the intended implementation seat did the work. Codex's truncate also handles what gemini's missed — rejects negative limits, clamps limit<=3, keeps the ellipsis inside the bound — and the blind reviewer still added value (flagged the clamp branch and exact-fit boundary as untested).
  • 2026-07-15 · Two codex-seat faults found, both invisible to mocks AND to a bad live probe (WT-f255). The codex seat — the designated implementation seat — failed in 4/4 live runs while the harness looked healthy, because the escalation ladder silently carried the work to claude/gemini/grok every time. Working escalation masked a dead seat; that is worth remembering as its own lesson.
  • 0xC0000409 crashes (empty output): codex retried a configured-but-dead Figma MCP at 127.0.0.1:3845 and intermittently died. Fixed by the spawned config task; codex now clean 3/3 with zero rmcp fatals.
  • The sandbox, a SEPARATE fault (352e96d): codex reported "every filesystem operation failed because the Windows sandbox helper codex-windows-sandbox-setup.exe could not be launched." That helper ships only in the Store/AppX package, never the standalone CLI — so codex could not read or write a single file. Fixed with -c sandbox_mode="danger-full-access" (the override council-code-review already documents; safe because agents run in a disposable worktree on a trusted workstation). Pinned by a test so it cannot be "cleaned up". Why it hid, and the rule that follows: the earlier "verified live" probe asked codex to "print OK and do not edit anything" — a task needing ZERO filesystem access. It passed against a completely broken seat. A verification that cannot fail proves nothing. Re-verified by having codex write a real file and checking the DISK, not its claim (proof.txt, contents "WROTE"). This is the same family as the --json schema bug: mocks agreed with the author's guess, and a live probe agreed with the author's hope. Both only fell over on real work.
  • 2026-07-15 · Probe race found + fixed (WT-f255, 0491f9e): splitting agy into four seats made probe() fire four back-to-back agy --version calls, and ~1 in 4 lost the race — mis-marking a healthy lane DOWN and silently dropping it from the ladder (measured: 1 false DOWN per 4 probe runs, never the same lane; agy --version alone is 6/6 clean at 0.3–2.2s). Probes are now cached per executable and shared across the seats fronting it, with one retry: a false DOWN costs a seat for a whole run, a retry costs a second. 5/5 clean probe runs after, all 8 seats UP. Whether a LANE is spendable is a pool/quota question, never a binary-presence one.
  • 2026-07-14 · FLT-1 LIVE end-to-end verified against a real repo (WT-f255) — first run with real CLIs, real git worktrees, real pytest. Target: a purpose-built sandbox repo (textkit, real git history + passing test); deliberately NOT a fleet repo for the first live outing. Task: add truncate(text, limit) + tests. Both runs completed to the human gate, exit 0.
  • Run 1 (all seats up): codex FAILED → ladder escalated → claude implemented → grok reviewed blind → validation reran pytest itself: 3 passed. Zero review drift.
  • Run 2 (--simulate-down claude): codex FAILED and claude down → ladder walked to gemini → grok reviewed → validation: 2 passed. This is a stronger acceptance result than the scripted test: two seats were unavailable at once and the ticket still landed.
  • The layered defense earned itself, live. Gemini's truncate violated the spec (text[:limit] + "..." exceeds limit by 3) AND its own test asserted the wrong behavior — so the FLT-3 validation gate PASSED it. The blind FLT-4 reviewer (grok) caught the length violation independently and set needs_human_review=true. Validation alone would have shipped the bug; the reviewer alone had no test signal. Confirms the known FLT-3 gap in writing: an agent's own tests are not an independent oracle. Grok also flagged __pycache__ in the diff and negative-limit handling in both runs.
  • Real bug found + fixed (3b56a47): the codex --json parser guessed the event schema wrong (msg.text; real is item.completed → item.text). Every mock agreed with the wrong guess, so 51 green tests hid it — on every real run _extract_text returned None and results silently degraded to the "fields inferred" fallback. Now pinned by tests/fixtures/codex-events.jsonl captured verbatim from a real run, and verified live (codex returns a parsed contract, no inferred-fields warning). The C# FLT-2 session hit this same class of bug, also only on a real run — mocks agreeing with the author's guess is a pattern worth a standing rule, not a one-off.
  • Codex seat is flaky on this box: intermittent 0xC0000409 (STATUS_STACK_BUFFER_OVERRUN) with empty output, correlated with rmcp transport fatals against a configured-but-dead MCP server at http://127.0.0.1:3845/mcp (Figma dev MCP, not running). 2 crashes then 3/3 clean on retry. The harness handled it correctly every time (escalate, don't stall), but the codex seat is degraded fleet-wide until that dead MCP entry is removed from codex's config — worth its own ticket; it silently cost the implementation seat in BOTH live runs. RESOLVED 2026-07-14 (WT-f85a). Removed [mcp_servers.figma-desktop] from ~/.codex/config.toml (backup: config.toml.pre-figma-fix.20260714-233257.bak); the remote [mcp_servers.figma] stays, since that is the cross-client hub FLT-13 actually uses and the desktop server is selection-aware only — useful solely while Figma is open and Dev Mode MCP is toggled on, which it was not. Verified 7/7 codex exec --json runs: exit 0, zero 0xC0000409, zero rmcp fatals. The rmcp fatal fired on every invocation pre-fix (crashing or not), so its disappearance is the deterministic evidence; 7 green runs alone would not be, given the crash was intermittent.
    • "Fleet-wide" was wrong: gaming/streaming/bedroom never had any figma entry (verified by dumping their mcp_servers blocks over SSH). Both entries were added on great-room earlier the same day by the Figma-MCP research session, which is why both live FLT-1 runs hit it. No fleet push was needed.
    • Deliberately did NOT add a retry on 0xC0000409. The loud failure is the detector that found this; a silent retry would turn seat degradation into an invisible tax, and the ladder already makes a flaky seat cheap (work landed via claude/gemini both times). Instead the crash is now named — crash: STACK_BUFFER_OVERRUN (0xC0000409) in known_risks — while still FAILED + escalating. tests/test_codex_events.py:65 stays as-is; 4 tests added around it.
    • Prevention: fleet-dispatch mcp-health probes every url-backed [mcp_servers.*] entry and exits 3 on a dead one. Run against the pre-fix backup it reports figma-desktop DEAD, so the next stale entry gets caught by a gate instead of by a seat dying mid-run.
  • Not yet proven: the interrupt/resume gate ran with --yes (auto-approve) in both runs; a real human answering the gate, and a --simulate-down of the whole editing ladder, remain unexercised live. 56 tests green.
  • 2026-07-14 · FLT-1 scaffold built + council-gated (WT-f255). Repo fleet-harness git-init'd, committed LOCAL ONLY at 2863033 (no remote, not pushed). Python 3.13 + uv, exact pins (langgraph 1.2.9, deepagents 0.6.12, langchain 1.3.13, langchain-core 1.4.9, langchain-ollama 1.1.0, httpx 0.28.1, pyyaml 6.0.3). Shipped: swappable brain (default ChatOllama → 10.0.0.7 gaming PC, localhost fallback, zero API keys required); deterministic router over routing.yaml (FLT-6) + probes + escalation ladder; graph route → implement (git worktree) → blind cross-vendor review (FLT-4, read-only sandbox) → validation that reruns tests (FLT-3) → human interrupt() gate; advisory branch for text-only roles; FLT-2 contract wrappers (docs/contract.md = canonical schema shared with the C# fleet-dispatch run-agent build); CLI python -m fleet_harness run|probe. Acceptance met: --simulate-down claude completes route → implement(codex) → review(grok) → validate → human gate, covered by test_acceptance_simulate_down_claude. 51 tests green (real graph + shipped routing.yaml, fakes only at vendor/git edges); all 5 seats probe UP live. Council gate: Codex chairman; seats Codex + Gemini + Grok substantive. DEGRADED — local Ollama seat (gemma4) returned spinner output only, and BOTH house-council seats (gaming, streaming) failed with MCP transport drops inside their courier subagents even though TCP to 10.0.0.7:37800 and 10.0.0.26:37878 was UP and Wi-Fi was on the house SSID (not drifted) — i.e. a subagent MCP-transport fault, not a box/network fault. Worth a follow-up ticket. Verdict: 0 Critical, 3 High, 9 Medium, ~11 Low, Kerr findings none, 4 dropped as false positives. All High and Medium fixed + regression-tested (notably: reviewer was running inside the implementer's worktree and could mutate the measured diff; approval_required ran past the human control point; freeform mode bypassed isolation; cheap-bulk could never reach Ollama; secrets rode the diff to third-party reviewers). Next: point usage-governor + fleet-dispatch at routing.yaml (FLT-6 anti-fork property is unproven with one reader); swap wrappers to fleet-dispatch run-agent when the C# FLT-2 lands; decide repo remote + push; live end-to-end run against a real target repo (only fakes so far).
  • 2026-07-14 · Rovo MCP OAuth granted by Andrew — workwingman site ONLY (private site deliberately excluded from agent reach; REST token remains the deliberate-use path for it). claude mcp list = Connected. New sessions get Jira tools automatically. FLT-10 remaining: agent-oriented statuses + custom fields (Primary Agent, Review Agent, Risk, Branch, Run ID), then board-as-contract checklist evaluation.
  • 2026-07-14 · FLT-13 phase 1 (status wall) SHIPPED (WT-df2b): new repo fleet-mission-control, net10.0 API + SignalR + Angular 22 NSwag PWA, verified live against real fleet-dispatch data, council gate Codex+Gemini+Grok+qwen3:8b+gaming:qwen3-coder:30b+streaming:llama3.3:70b (devstral seat FAILED/canceled), chairman list (1H/6M/5L) fully implemented, backend 20/20 + frontend 19/19. Local-only, not pushed. FLT-13 → In Progress (phases 2-4 remain); FLT-14 read-only panels unblocked.
  • 2026-07-15 · FLT-13 quota surface + tooling gates landed (WT-df2b, fleet-mission-control local commits 4-5): /api/quota + QuotaUpdated hub event reading agy-ledger.jsonl READ-ONLY (single-writer honored); agy-Claude rendered as remaining invocations + reserve intact/spent (units, never %), weekly counts as distinct no-refresh lines, weekly limit rows → hard-deny banner + reserve spent. Tooling: angular-eslint clean, Stryker.NET 39.19% baseline (hardening chip spawned; stryker-js blocked on Angular vitest builder), ReSharper InspectCode (1 fix), ZAP baseline+API scan 0 FAIL (CORP/CSP/referrer/permissions headers added), 0 vulnerable packages (Microsoft.OpenApi 2.7.5, npm qs override). Delta council gate: Codex+Gemini+qwen3:8b+gaming:qwen3-coder:30b, chairman 3H/4M/2L all implemented incl. Kerr fix (reserve gated on weekly, not 5h proxy). 30/30 + 24/24.
  • 2026-07-15 · FLT-16 CI tooling pack rolled out to 11 C# repos (WT-df2b): vuln gate (enforcing)
  • InspectCode (error-severity) + Stryker (report-only, staggered) + pinned tool manifests. Council-gated on the pilot template (6 seats; 3 Highs caught — fail-open vuln gate, floating tool installs, cron dogpile — all fixed before replication). Every repo's build/tests/gate re-run by the orchestrator; 0 vulnerable packages fleet-wide. Codex implemented (governor RED). All branches wt/WT-df2b/FLT-16, committed, NOT pushed — land decision pending.
  • 2026-07-15 · FLT-16 LANDED on origin/master, all 11 repos (WT-32b7). Backporting the stronger clean-marker gate surfaced a deeper fail-open the council caught: a solution-wide scan proves only that SOME project got a verdict — one clean marker satisfies the aggregate match even if another project was never evaluated. Gate now enumerates projects and requires a per-project verdict; DOTNET_CLI_UI_LANGUAGE=en pinned (marker is literal English text). Council 5/7 seats (Gemini found the multi-project hole, Grok the locale brittleness; qwen3-next:80b hit the 480s cap; streaming PC down — TCP+ping fail while gaming answered from the same host). Validation: extracted each workflow's real gate script and executed it — 11/11, enumerated == clean verdicts (WW 29/29). That caught a pilot bug nothing else did: one em-dash in a run: block = Missing closing '}' under WinPS 5.1 (GH Actions writes BOM-less UTF-8, 5.1 reads ANSI) — gate bodies now ASCII-only, see winps-run-block-nonascii-parse-bomb. Landed per the multi-session FF-push edict (rebase in worktree → lease-pinned push straight to origin); origin was ancestor of every tip, 0 peer commits lost. membus now scans 4 projects (picked up MemBus.Contracts).
  • 2026-07-15 · FLT-16 follow-on: test-impact analysis RESEARCHED → REJECTED, premise was false (WT-975b). Asked whether to scope the pack's Stryker runs to changed code via GHA/MCP. Council convened (opus, 5/5 seats) and answered well — but optimized a bottleneck that does not exist, because it was never given the numbers. Measurement: --coverage-analysis perTest is already Stryker.NET's default (all 11 configs leave it unset = already on, so the council's #1 win is a no-op); .NET mutation wall-clock is ~15 min across the fleet (2m35s–15m23s, running in parallel across separate repos); no MCP exposes a TIA selector today. Nothing to buy, nothing to build. Council log carries a correction block — the verdict is moot. Real defect surfaced and spun out separately: WorkWingman mutation CI produces no result because the linux runner its workflows require was never built (b606a93, 07-08, routed 10 jobs at a label with nothing behind it; 17 mutation runs cancelled, 0 passed, ever). A peer session provisioned it at 07-15 23:11:49 CDT (0f787ef). See the FLT-16 section — this line was retracted once on a 34-minute-old observation and the retraction was itself wrong. Cleared while measuring: staggered crons are real (Mon 06/10/12/20), audio-loop-mcp has mutation.yml on origin (local checkout was 2 behind). Method lesson: measure the bottleneck before convening a council about it — a council argues the premise rather than telling you it is false, and here chairman and top-ranked seat were the same lineage while both house councils were unreachable (FLT-63), so no independent lineage checked it.
  • 2026-07-16 · ~~Retraction: the WorkWingman "runner label" defect was not real.~~ THIS RETRACTION WAS ITSELF WRONG — superseded, see below and the FLT-16 section. It claimed the backlog was "capacity". It was not. The linux runner the workflows require did not exist from 07-08 (b606a93) until a peer session provisioned it at 07-15 23:11:49 CDT (0f787ef) — 17 mutation runs cancelled, 0 passed, ever. The original "nothing answers that label set" claim was CORRECT for that entire window; it was retracted on an observation taken 34 minutes after the peer's fix landed.
  • 2026-07-16 · Post-mortem: four wrong diagnoses on WorkWingman CI in one night (WT-975b). Sequence: label unanswered → runner wedged → orphaned processes → memory-starvation-dismissed → "capacity". Every one published confidently; every one overturned within the hour. Root cause: sampling shared infra while a peer session was actively repairing it, and reading their in-flight fixes as findings. The peer landed the runner (0f787ef, 23:11 CDT), raised its cap 5g→6g (228c3cf, 02:15 CDT), and rebuilt the image three times — each change silently invalidated a conclusion drawn minutes earlier. Contributing artifacts: (a) GitHub reports run status as queued while any job in it still waits, so runs?status=in_progress reads empty while a job runs — run status ≠ job status; query /actions/runs/<id>/jobs; (b) a cgroup OOM of a worker does not set OOMKilled (only PID 1 dying does), so "no OOM in the log + restarts: 0" does not rule out memory starvation — it is exactly what starvation looks like. Standing rule: before diagnosing shared infra, git log the window for peer commits and date every observation against them. Cost: two false claims published to the board, pushed to a remote, and one handed to a spun-out session as its premise.
  • 2026-07-16 · Verified by spike, and it holds: the PR #21 shell fix survives a virgin runner (WT-975b). Reproduced the original PSSecurityException on demand (process-scope PSExecutionPolicyPreference=Restricted) on greatroom + gaming + streaming. Per box: unfixed shell under Restricted exits 1 (control fires — the simulation is real), PR #21's membus-form shell exits 0 (survives), and a failing command through it still exits 7 (no green-washing). So a NEW runner needs no machine-policy change — the in-repo fix is the anti-drift property. v1 of this spike was contaminated and reported a false pass: it was launched with -ExecutionPolicy Bypass, which exports PSExecutionPolicyPreference to every child, so the "unfixed" control ran under Bypass. Caught only because gaming — which had just thrown PSSecurityException in CI — reported Bypass. Also: all runners execute as NT AUTHORITY\NETWORK SERVICE, and ExecutionPolicy CurrentUser is per-user, so probing your own policy proves nothing about the runner's.
  • 2026-07-16 · usage-governor CI is green-washing failures — measured, not theorised (WT-975b). Its ci.yml shell omits the trailing exit $LASTEXITCODE that membus carries. Measured identically on three boxes: a body of cmd /c "exit 7" returns 7 through membus's form and 0 through usage-governor's. A red suite renders as a green check. Any recent green on that repo is unverified. Spun out as its own task; the other 9 FLT-16 pack repos need the same audit (this is the same fleet config drift that left WorkWingman without the setup-dotnet fix its 11 siblings got).

Fleet Routines build tickets (FLT-34 fleet-routine) — spun 2026-07-17 from opus council

Council opus 2026-07-17 (ranking D/grok>A/claude>B/codex>C/gemini>E/local; report llm-council/reports/2026-07-17_191704_should-the-fleet-harness-flt-1-the-universal.md) re-ratified the delegate seam now that FLT-1 exists: fleet-routine = C# scheduling plane (WHEN+budget); fleet-harness = the ONLY orchestration engine (HOW+adapter). Runner invokes the graph, never re-selects adapters. C# runner + Python graph, process boundary a feature. House councils 5 AGREE / 2 DISSENT (both dissents = the rejected "absorb into FLT-1/Python" minority; both heaviest votes gpt-oss:120b + qwen3-next:80b confirm).

Blocks chain: FLT-104 → FLT-105 → FLT-106 → FLT-107 → FLT-108. All anchored to FLT-34.

Key Phase Status Summary
FLT-104 Gate 0 To Do GO/NO-GO non-interactive auth smoke (fleet-routine doctor --noninteractive), 6/6 harnesses as Andrew user "whether logged on or not" (NOT SYSTEM). Blocks all scheduler code.
FLT-105 P1 To Do run-now vertical slice through the C#↔fleet-harness seam: registry+tombstones, CLI add/list/delete/run-now+cap-validate, fire-time fail-closed governor (defer=skip-tick), fleet-harness routine-fire entrypoint, emit fleet.v1. run-now BEFORE WTS.
FLT-106 P2 To Do WTS trigger via COM/API (trigger-only), StartWhenAvailable, reboot/sleep survival.
FLT-107 P3 To Do multi-PC JetStream durable replay + Claude-native routine normalize. Open fork: subprocess/sync (P1) vs NATS-command/async (multi-PC) — decide here.
FLT-108 P4 To Do Pavlok dedupe/escalation + full cap enforcement (maxTokens/cost/wallclock/concurrency/cooldown), missedRunPolicy=skip-retry-never-flush, immutable audit.

2026-07-29 night — WT-c556 (Clahadore) session close

Landed + deployed. All services now run from reconciled WorkWingman master 9f96e1a1d.

Ticket State What
WING-215 Needs Human Review board/docs.workwingman.ai behind Cloudflare Access; DNS migrated Google->Cloudflare (11 records preserved, yc untouched); tunnel + Pages; 8-email roster allowlisted
WING-225 Needs Human Review Vikunja standby replicas on gaming/streaming/bedroom; failover proven with primary down; link shares replicated to all replicas
WING-227 Done MPA mobile sweep (WT-ab3e) — deployed, verified 375/320px
WING-238 Needs Human Review branch topology reconciled: master IS the trunk again; 150 -> 70 branches
FLT-180 Done bedroom SSH restored, verified end-to-end
WING-228 To Do SPA Flow/Studio mobile epic — 3 open questions for Andrew

Fleet-harness commits: 628364b lane buckets · 82ea9c0 rehydrate lanes + DR validation repair · 156d481 standby replicas · ae329cd BoardSurfacesWatch · e87bd4a DR dump guards · 42e24f3 link-share replication. fleet-docs-hub: now a private repo in the tools org; ba10c61 Pages auto-publish; 42cd24a collector cwd + YAML escaping fixes.

Needs Andrew: (1) Vikunja primary 2.3.0 vs replicas 2.4.0 — upgrade primary deliberately, never downgrade replicas; (2) Access still One-time-PIN until WING-214 Google IdP; (3) nine fleet scheduled tasks were found disabled (incl. VikunjaNightlyBackup and VikunjaRestoreVerify) — re-enabled, but cause unknown and it can recur; (4) WING-228 open questions.

Incident, self-inflicted, recovered: testing a DR guard I passed -FromDump a 5-byte fake file; the .sql branch DROPs the database before reading input, so the primary board was wiped. Recovered in ~4 min from the Jul 23 dump + -FromJira. Real defect fixed in e87bd4a (refuses non-dumps and newer->older schema). Newest dump was 6 days old because the nightly backup was one of the disabled tasks — that is the finding worth acting on.

2026-08-04 — WT-3858 (Clahadore) · FLT-191 greatroom pagefile fault

FLT-191 · Greatroom pagefile on H: silently fails at boot — In Progress (WT-3858, 2026-08-04)

Symptom: H: pagefile config reverts every reboot; 08-04 commit exhaustion (error 1455) crashed grok.exe, agy.exe, pwsh, Claude Code.

Root-cause receipts (greatroom): PagingFiles = H:\pagefile.sys 32768 49152 but ExistingPageFiles = C:\pagefile.sys and TempPageFile = 1 — Windows failed to create the H: pagefile at boot and fell back to a temporary 81 GB C: pagefile. H: is internal NVMe (Samsung 990 EVO 4TB), Basic/GPT/NTFS/healthy, letter mapped in MountedDevices — not USB/dynamic/late-letter. BitLocker on H: = prime remaining suspect (elevated check dispatched fleet-wide). Continuous Resource-Exhaustion-Detector 2004 events; svchost ~55.9 GB commit (possible service leak, follow-up item).

Pending: elevated fleet diagnostic results (all 4 PCs); fix proposal to Andrew (C: primary pagefile system-managed or 64–128 GB; H: 48 GB max is undersized). Reboot = Andrew-only. System-settings change = Andrew approval first.

2026-08-05 — WT-290d (Clahadore) · FLT-204/205 MCP v2 migration + wingcms registration bug

FLT-204 · MCP v2 (spec 2026-07-28) migration: the 3 C# servers we own — To Do (WT-290d, 2026-08-05)

Question asked: can MCP's new stateless support make the MCP fleet stateless and fix RAM exhaustion?

Answer: no on RAM, yes on the protocol. Statelessness buys routing/safety properties, not bytes — process consolidation is the RAM lever, and they are orthogonal. Measured fixed floor is 62% of MCP commit (6.13 of 9.93 GB across 36 unique server identities), so the council's falsifier zero fired: consolidation concentrates the OOM rather than curing it. Physical pressure is 22 claude hosts (3.13 GB WS) + Chrome + WSL, not MCP.

Correction worth keeping: every process filter used node|python|uv and silently missed dotnet.exe, hiding two of the three servers in question. Corrected, the servers we own are 22 procs / 899 MB commit / 1.24 GB working set — consolidating them would recover ~1.0 GB physical. Real, but it does not move the fleet verdict: the bulk is plaud (18 procs/1.44 GB) + jdocmunch (35/1.04 GB) + jdatamunch (35/0.96 GB), all third-party and pinned mcp<2.0.0.

Scope collapsed from ~40 servers to 3: audio-loop, wingcms, workwingman-forms — all already on ModelContextProtocol 2.0.0-preview.1. Everything else is upstream or already remote HTTP.

Decision (Andrew): option 3 — v2 stdio now as the cutover target, HTTP behind an off-by-default flag, and the shared-daemon security suite built now so the flag stays flippable.

Proven on audio-loop (wt/WT-290d/mcp-v2-audio-loop, uncommitted pending gate): bump preview.1→2.1.0 builds 0 Warning(s) 0 Error(s); tests 22/22 passed; server/discover returns supportedVersions:["2026-07-28"]; legacy initialize (2025-06-18) still ACCEPTED and negotiates down, byte-identical to the current production build. Cutover cannot break Claude Code 2.1.222. Protocol work was one line, ~10 minutes — the audit's 6h was pre-existing hardening debt, not migration.

Two findings static analysis could not reach: (1) AddMcpServer() auto-advertises a logging capability despite zero logging code — and Logging is deprecated in 2026-07-28, so all three servers advertise a deprecated capability they do not implement; (2) ttlMs: 0, cacheScope: "private" means "do not cache", so the prompt-cache token benefit of stable tool lists is not realised by default — setting a real TTL is the one place this work touches the token bill.

FLT-205 · wingcms MCP registered fleet-wide from a stale, build-failing worktree — To Do (WT-290d, 2026-08-05)

~/.claude.json serves wingcms (31 tools, every session on the box) from _wt/ww-cms-merge — branch wt/WT-570b/wingcms-bucket-merge, 113 commits behind master and recorded in memory as build-failing. Compounding it, the registration ships "env": {} while WingCms.Cli/Program.cs:1079 resolves the content file by walking up from Directory.GetCurrentDirectory(), and WingCmsTools.cs:281-291 shells out without setting WorkingDirectory — so which site-content.json gets written depends on the launcher's CWD, across ~12 worktrees each holding a copy.

Blast radius: LATENT, not drifting. SHA256 across all copies shows one hash everywhere including canonical, and a second hash only in the registered tree explained by its own committed branch work; git status clean in both. No stray writes have happened yet.

Also noted: wingcms has no test project at all.

Standards debt, self-reported: this session ran ~10 turns of investigation before any ticket existed, and its board footer pointed at FLT-192, which was already Done. FLT-192's own description had already recorded "each session launches its own full MCP fleet" and named these servers — the measurement re-derived a documented cause. Tickets and board entry created retroactively on Andrew's prompt, which is the failure the standard exists to prevent.

audio-loop LANDED — 372f337 on wt/WT-290d/mcp-v2-audio-loop, pushed + fanned to gaming/streaming/bedroom. 1 of 3 servers. Receipts: dotnet build -c Release → 0 Warning(s) 0 Error(s); dotnet test -c Release → Passed! Failed: 0, Passed: 28, Total: 28; tools/call list_audio_devices returns text byte-identical to the preview.1 build (657 chars, 11 devices), differing only by resultType and _meta.serverInfo — both expected 2026-07-28 additions. Verdict: passed.

Gate: 4 seated / 1 skipped. Cedric (no findings, independently built + ran the suite) · Regular Jenny 4520 chars · Cyber Jenny 7564 chars · Gronktayvius 10375 chars · Clahadore skipped (codex-claude-admit denied; advisory-only since Claude authored). Clahadore chaired because Cedric appeared dead at synthesis time; Cedric's clean verdict arrived after and corroborated it.

Two silent seat deaths caught by the validation contract — both would have read as "no objections": Jenny attempt 1 exited 0 with empty stdout (jetski: no output produced — a tool required the "command" permission); Cedric attempt 1 exited 255 on rmcp ... Auth(AuthorizationRequired) because one of 10 configured mcp_servers demanded auth. Fixed with a no-tools instruction and -c mcp_servers="{}" respectively. This is exactly the failure mode the contract exists for.

The finding that mattered: Jenny and Gronktayvius independently spotted that AudioLoopMcp.Tests referenced Core only — 22 green tests proved domain logic and nothing about the wire. Fixed with McpProtocolContractTests (6 tests spawning the real server over stdio, pinned to verbatim captured payloads, including a negative assertion that top-level serverInfo stays absent). Negative control: pinned back to preview.1 → 3 of 6 FAIL. The tests have teeth.

Settled by decompile: Gronktayvius read McpServerImpl.ConfigureLogging in 2.1.0 — it sets Capabilities.Logging = new() unconditionally, which is why both of Clahadore's suppression attempts were no-ops on the wire while build and tests stayed green. Not an app defect, no public seam. FLT-204 acceptance criterion 3 is unmeetable as written and needs rewording.

Spun out: FLT-208 — transcribe opens any absolute path with no confinement (Cyber Jenny, HIGH). Pre-existing, not this diff, so it got its own ticket instead of expanding the commit or burying a HIGH in a line item.

Next: workwingman-forms (security-sensitive — _managedForms is the only control gating the forms.body grant), then wingcms (blocked on FLT-205).


2026-08-06 overnight — WT-1d04 (Clahadore) · FLT-201/202/203 built + FLT-206 opened

Andrew asked whether the deploy + branch-merge managers were ever built, and whether CLI-driven browser/app click-throughs could be fanned across the house PCs. Answer to the first: no, neither existed. Answer to the second: yes, but not via any vendor's own browser feature.

Shipped tonight — all committed and pushed, nothing merged to master

Ticket Branch / commit Receipts
FLT-201 fleet-uitest new private repo, wt/WT-1d04/FLT-201 @ 845d02c build 0/0 · 45/45 tests · displays verified live on greatroom
FLT-202 fleet-merge new private repo, wt/FLT-202/init @ 88d8bda build 0/0 · 4/4 tests · 33 files, 1803 insertions
FLT-203 rc artifact lane release-coordinator wt/FLT-203/installer-lane @ 0b66937 105 existing before → 105 after, +7 new = 112 · build 0 errors

FLT-201 written by Clahadore on greatroom; FLT-202 and FLT-203 by Cedric (Codex gpt-5.5, xhigh) on gaming, dispatched over SSH via hidden scheduled tasks.

The measured thing that made FLT-201 possible

Headed UI testing across the fleet was blocked by two facts, both proven rather than assumed:

  • SSH cannot see displays. The identical probe returns a phantom WinDisc 1024x768 over SSH and the real \.\DISPLAY1..3 in session 1. Fix is a hidden LogonType Interactive scheduled task.
  • On gaming, the 49in 32:9 ultrawide is the PRIMARY display. Every unpinned window defaults onto the one monitor Andrew asked us to stay off. So "fall back to primary" is a critical bug, and TargetSelector throws instead.

Exclusion is geometric, never by name: aspect >= 2.5 and width < 1280. Necessary — the two G95SC units report different EDID ids (SAME028 on gaming, SAME019 on streaming), so an allowlist would silently miss one. Both rules fired correctly and unprompted on two unlike layouts.

Two more traps encoded: DPI awareness must be set before reading bounds (4K panels read 1280x720 without it), and virtual-desktop origins are negative (gaming X=-2560, streaming X=-3584).

Fleet faults found by tripping over them — all feed FLT-206

  1. Codex sandbox is broken on 2 of 3 PCs. greatroom: CreateProcessWithLogonW failed: 2. streaming: windows sandbox: timed out after 15000ms connecting runner pipe-in. Only gaming works. This silently removed two-thirds of offload capacity, for an unknown length of time.
  2. gaming's claude CLI is not logged in — Not logged in - Please run /login, while exiting 0. Exit codes are worthless for auth checks.
  3. release-coordinator was in manifest.json but had never landed on gaming. Manifest presence is not evidence of on-disk presence; the sync is not reconciling.
  4. Codex sandbox output is owned by CodexSandboxOffline, not Andrew. Git refuses with dubious ownership; committing needed takeown /R + icacls /T on the repo (267 files) and on the parent's .git/worktrees metadata (60 files). Any remote codex job leaves unusable output.
  5. Codex sandbox blocks outbound network — a remote job cannot clone a missing repo. Repos must be pre-staged before dispatch.
  6. Dead Figma MCP entry on gaming and streaming, throwing AuthRequired into every codex run. Same class as the dead figma-desktop :3845 that previously crashed seats.
  7. greatroom at 0.7 GB free RAM of 29.4 GB, with 36 claude.exe processes against a cap of 2.

Standards debt, self-reported

  • Review gate is thin and I am not calling it passed. FLT-201 got ONE seat (Gemini, NO FINDINGS on the Core diff). Grok returned only a preamble and is counted FAILED. Codex was unavailable. FLT-202 and FLT-203 have had no independent review at all — Codex reviewing its own output is not a seat. None of this should land on master until a real gate runs.
  • fleet-uitest and fleet-merge are not yet in fleet-repo-sync/manifest.json, so they will not reach the other PCs. Deferred deliberately: that edit needs the review gate, and the gate seats are mostly broken tonight.
  • FLT-201's --via-session hangs, run was never executed against a real browser, and install/uninstall were never executed. All recorded on the ticket rather than glossed.

2026-08-06 — WT-fcc7 (Clahadore) · FLT-178 headless consoles

FLT-178 · Fleet-wide headless console enforcement — Done, with follow-ups (WT-fcc7)

Landed 79ac234 + afc21e9 on usage-governor master, fanned out to all peers.

Root cause was not what anyone assumed. LogonType=Interactive, not Settings.Hidden — per Microsoft's docs Hidden only hides the task's row in the Task Scheduler UI. Every offending task already had Hidden=$true and showed a console anyway. Control group on one machine: UsageGovernorRaftAuthority (S4U) produced no window; UsageGovernorAdmitAuthority and FleetDispatchServe (Interactive) did.

Machine Tasks flipped Visible consoles after
greatroom 17 none (verified)
bedroom 6 none (verified)
streaming 6 none (verified)
gaming queued offline 16h at the time

Two theories killed by measurement, so deliberately NOT built: a PATH shim for .NET grandchildren (a 120 s trace over a full build + 582 tests caught zero windows from dotnet/MSBuild/vstest/git) and a Claude desktop launcher (app.asar already ships windowsHide + conhost --headless + node-pty). The first detector, which reported "74 flashes", was itself invalid — CREATE_NO_WINDOW still spawns a conhost.

Review: council (Cedric chair, Jenny, Cyber Jenny, Gronktayvius) → 9 findings, all fixed. A second Cedric pass over the fixed code found 7 more, 3 P1 — including a StrictMode bug that made every backup fail and so blocked both mutators entirely. That is precisely what the first commit's unverified verdict was warning about.

Incidents, self-inflicted, recovered: (1) FMC API taken down on streaming — killing a stale instance revealed Device Guard/WDAC now blocks the self-contained .exe; it had survived since 07-19 only because it was loaded before the policy. Repaired by repointing its launcher at the dotnet.exe + DLL form bedroom already uses. (2) A stray unelevated FleetDispatch.exe (Explorer-parented, since 08-04) had been serving in place of the elevated task, which had never run.

Needs Andrew / follow-ups: 1. The usage-governor override never reaches fleet-dispatch. GovernorGate.ReadTier reads only state.json's tier while UsageGovernor.exe override writes a separate override.json, so a logged override still leaves every non-critical job deferred (governor RED). Only --critical bypasses it. This defeated the overnight override fleet-wide. 2. S4U + RunLevel Highest is a recovery deadlock. An unelevated session cannot stop or restart the session-0 listener — schtasks /End reports SUCCESS and does nothing. Dispatch is the fleet's only no-UAC elevation path, so a wedged dispatch needs manual elevation. Mitigation: register a FleetRestartDispatch task at RunLevel Highest that any session can Start. 3. FMC launchers differ per machine (one style WDAC-blocked) and append to a fixed log path with no lock handling, so a stale instance silently blocks restarts behind a misleading error.

Standards debt, self-reported: -WhatIf row emission and the action sweep have still never been executed on a real machine — both need elevation and dispatch would not accept jobs. Recorded on the commit rather than glossed. gaming is unconverted.

Full write-up: usage-governor/docs/FLT-178-findings.md.

2026-08-06 ~02:45 — FLT-206 fleet-healthcheck VALIDATED against ground truth

fleet-healthcheck now detects real faults on the real fleet. Private repo andrewjonesdev-tools/fleet-healthcheck, branch wt/FLT-206/init @ e60ca6d, 6 commits, 22/22 tests. Six live runs against all four PCs.

Run Result
1 42 FAIL / 0 PASS — a 15s global timeout starved every probe
2 16 PASS / 39 FAIL — timeouts calibrated; found 2 real fleet faults unprompted
3 17 PASS / 22 FAIL / 16 INCONCLUSIVE — false alarms became honest unknowns
6 matches ground truth; CLI probes now 9-74s, i.e. real model round trips

Faults it found on its own, all independently verified: - release-coordinator listed in fleet-repo-sync/manifest.json but never landed on gaming — manifest presence is not evidence of on-disk presence, the sync is not reconciling - .git directories owned by a foreign account on all four machines - greatroom RAM below threshold (WARN, correctly not FAIL) - bedroom claude is logged out — nobody knew. Verified: Not logged in - Please run /login on stdout, exit 1, governor banner on stderr - agy is unauthenticated on all four machines — prints an OAuth consent URL and blocks for 60s. This is why the Gemini review seat could not be seated for most of the night

It also correctly classifies rather than just detecting: gaming claude reports needs re-auth, not a generic failure. Those have different fixes.

Not ready for email yet. agy needs an auth-error pattern (4 misclassified FAILs/night), greatroom's broken codex sandbox is masked as INCONCLUSIVE by the duration heuristic, and mcp-configs still errors on greatroom/bedroom.

The CLI-probe defect: four stacked causes, each of which alone reads as "the CLI is down"

  1. 15s global timeout starved every probe
  2. ProcessStartInfo.FileName set to a bare tool name with UseShellExecute=false does no PATHEXT search, so codex resolved npm's extensionless bash shim
  3. closing stdin is not the same as redirecting from NUL — an open pipe hangs, a closed pipe errors (stdin is not a terminal), only the device works
  4. cmd.exe does not accept backslash-escaped quotes — the prompt shattered into tokens (error: unexpected argument 'with' found)

Standing memory codex-exec-stdin-hang corrected with all three stdin states measured. The old rule ("ALWAYS < NUL") was being applied shell-blind; in PowerShell < is a parse error, and the "obvious" C# substitute (RedirectStandardInput + Close()) is also wrong. Only cmd /c "... < NUL" works.

Self-reported: round 4 shipped a fix built on my own wrong conclusion — I mistook "PowerShell can't parse <" for "< isn't needed." Codex implemented my instruction faithfully and it failed.

What kept it converging was one invariant, not insight: the probe returns faster than PATH resolution takes. True every round regardless of what changed. That check is now permanent in the tool, so the next invocation defect announces itself instead of masquerading as a fleet outage.

The costly gap was diagnostic, not functional: the probe discarded stderr. Every failure named itself there and had to be re-derived by hand outside the tool. Now always recorded.

2026-08-09 — WT-1283 · FLT-223 passive agent awareness — Needs Human Review

FLT-223 · Fleet-native passive AgentMessage/v1 and Mission Control shadow timeline

Landed and demo-ready. Fleet now has a versioned, local, durable AgentMessage/v1 producer and a read-only Mission Control awareness timeline. The plane is fixed to trust=peer_untrusted, authority=non_authoritative, deliveryMode=shadow, and canAuthorizeActions=false. Raw message text stays out of REST, SignalR, browser state, the UI, Fleet evidence, prompts, approvals, and landing authority.

Commits: fleet-harness a344e59 · worktree-identity 2d85ddb · fleet-mission-control d98a4be · codex-harness-mirror 6f3fa14. FleetRepoSync triggered gaming, streaming, and bedroom after all four fast-forward pushes.

Gates: harness 215 passed / 1 skipped; producer 300/300; Mission Control backend 711/711; frontend 305/305; warning-as-error builds, lint, production build, and diff checks passed. Council PASS: Cedric adjudication, Regular Jenny, Cyber Jenny, Gronktayvius General, and Gronktayvius Red Team. Clahadore is explicitly absent until Tuesday 2026-08-11 12:00 PM America/Chicago.

Pilot limits kept visible: claimed sender is unauthenticated telemetry; disk content must remain synthetic/public; production drain/retention and scan-truncation health are follow-ups; a golden cross-repo fixture and evidence writer are required before cross-host or active awareness. Any prompt injection, approval, landing, or secret-bearing use requires a new council gate.

2026-08-14 — WT-afdb · FLT-232 gh auth probes — Landed

FLT-232 · gh auth status is not a health probe — standardize on gh api user

Landed. fleet-mac-bootstrap master 02c2d3c, home-bootstrap master 2f88b33; both PRs MERGED. The mac-bootstrap FF was refused on first attempt because master had moved to de9ca43 (WING-345 landing, new files only, no overlap) — rebased, re-verified, then fast-forwarded. All four Macs verified at the merged HEADs per-repo; the fan-out's own ff= counter read 0 on three boxes and was misleading. macmini4 picked up fleet-mac-bootstrap, which it had been missing, closing half of FLT-234. gh auth status aggregates every configured gh account and exits nonzero if any one fails, so a stale account fails the probe on a box whose auth is fine. In fleet-mac-bootstrap that probe gated the entire fleet-repo clone loop — and macmini4, the one box whose probe failed, is the one box missing fleet-mac-bootstrap. Root cause on that box: the token sat in the macOS keychain, which non-interactive ssh cannot unlock (errSecInteractionNotAllowed), so gh reported a live token as invalid. macmini4's hosts.yml was repaired first (backup kept).

PRs: fleet-mac-bootstrap#2 · home-bootstrap#2

Gates: Council 4/4 seats — Cedric (chairman), Regular Jenny, Cyber Jenny, Gronktayvius. Clahadore skipped (governor RED; advisory-only regardless, Claude authored). Chairman ruled changes requested, no Critical/High; all three in-scope findings fixed — hostname pinning at four call sites, a $LASTEXITCODE sentinel that was letting a non-launching gh read as authenticated, and corrected comments. Validation: bash -n 0, PS parse 0, repo regression suite PASS, cmd-block harness both branches, sentinel proven live (old 0 → new -1), gh api user --hostname github.com exit 0 on all five boxes. Neither repo has CI, so PR CI is N/A. Re-gated on the post-fix diff: 4/4 seats clean, no findings (Regular Jenny's first round-2 attempt truncated on an agy response timeout and was re-run rather than seated). No chairman pass on round 2 — nothing to synthesize over an empty finding set.

Dissent on record: Gronktayvius argued for gh auth status --active --hostname github.com (macOS only) and reverting the Windows sites. Chairman: sound but not disqualifying. Andrew can overrule.

Also found: FLT-239 — sync-push.ps1 fails to parse under Windows PowerShell 5.1 (BOM-less file, UTF-8 em-dash added by WING-345 018b917). pwsh 7 is fine. Scoped to that one script; the FleetRepoSync scheduled entrypoint parses clean, so automatic reconciliation is unaffected.

Follow-ups: FLT-233 probes conflate transient failure with a missing credential · FLT-234 macmini4 missing repo, and the GitHub token is cleartext in hosts.yml on three Macs (rotation is Andrew's call).

2026-08-14 — WT-f0af · FLT-235 review-seat contamination — In Review

FLT-235 · A review seat edited the tree it reviewed, then reported its own edit as P1

The review gate produced the failure it exists to prevent. During WING-501, the Cedric/Codex seat (codex review --base master) mutated worktree WorkWingman-wt-WT-ecb3-WING-501 after commit 40c4afb39 landed: seven files modified between 11:32 and 11:36, including a top-level zip block added to electron/package.json — which the seat then reported back as its P1 finding, "unsupported configuration blocks all installer builds". Its Contains("msedge") BrowserSession finding was likewise about code it had just written. Cost a full investigation to prove the P1 was not in the commit, plus a rebuild. Unnoticed, the seat's edits would have been committed as reviewed work.

Root cause is structural, not a bug. -c sandbox_mode="danger-full-access" is mandatory on Windows or Codex cannot inspect the diff and exits 0 with a blind "no findings" — and that same override is what grants the write. There is no read-only Codex sandbox here. Only cwd constrains the seat. Second occurrence: FLT-56 (2026-07-16) a Codex seat committed and pushed 3f48415. The skill also already contradicted the standing memory rule "review seat must not write — seats run from SCRATCHPAD".

Fix: disposable detached worktree at the sha under review for any seat with filesystem reach (git worktree add $rc $sha --detach, run, assert, remove --force); mandatory contamination assert (git status --porcelain + git rev-parse HEAD byte-identical before/after, in the seat's cwd and the live tree) on every seat every run; FAILED-CONTAMINATED as a status distinct from FAILED and excluded from quorum; findings citing seat-modified paths quarantined before the chairman pass (the chairman cannot tell seat-authored code from committed code — that is how the self-edit got ranked P1); roster gains mandatory cwd and Clean after columns.

Landed: usage-governor/docs/review-seat-isolation-policy.md (branch wt/WT-f0af/FLT-235, caa777e, pushed, not merged — council gate pending) · skills council-code-review, codex-review, gemini-review updated in ~/.claude/skills · memory review-seat-must-not-write refreshed with the second incident and the checkout mechanism.

Jenny / Gronktayvius: confirmed read-only, conditionally. Neither wrote. Gronk runs --disallowed-tools "write,edit,bash,shell"; Jenny gets the diff inline and any tool call is auto-denied headless. Both are read-only only because of a flag or a prompt line a future edit can drop silently, so the contamination assert now applies to them anyway and the no-tools instruction is stated as an invariant rather than a workaround.

Verified: disposable-checkout mechanism smoke-tested end to end on this box (add detached → assert clean → worktree remove --force → 0 remaining). Not verified: a live Codex seat run inside the checkout — the WING-501 workaround is the only evidence for that leg.

Follow-up: wrap checkout + assert + teardown in a script so a seat cannot be run without isolation; audit whether any past gate committed seat-authored edits as reviewed work.

2026-08-14 — WT-f37a · FLT-236 fan work off greatroom — In Progress

FLT-236 · No session work was fanning out, and no peer could run Gemini 3.7 Flash

The premise was false at every layer. The worktree-identity registry holds 1525 entries and zero have host, model, or harnessKind set — the schema has the fields, nothing has ever written them, so "which PC is this card running on, at which model?" was not an answerable question. 203 entries updated in the last 7 days, 42 with heartbeats under 24h, all effectively local to ANDYGREATROOMPC.

Three independent breaks underneath that. (1) Dispatch to DESKTOP-D249KD4 returned The type initializer for 'FleetDispatch.Core.RealJobExecutor' threw an exception. A TypeInitializationException is cached for the life of the process, so one transient cctor failure in a serve process running since 8/8 poisoned every job kind on gaming for ~6 days; its outbox last wrote 8/6. Streaming and bedroom ran the identical deployment (74e88fd) and were fine — the binary was never the variable, the process was. (2) agy is unauthenticated on gaming and streaming; the CLI falls into interactive OAuth and times out at 60s, so the entire Gemini leg only ever ran on greatroom. (3) bedroom ran agy 1.1.10, whose catalog stops at Gemini 3.6 Flash — 3.7 was not selectable there at all.

Docker CI was pinned to the machine Andrew works on. home-ci carries no PC-specific label, so generic fleet jobs could schedule anywhere — but greatroom-tools held the only docker label in the org pool, so fleet-mission-control's actionlint and semgrep jobs landed on greatroom every time. The workflow comments explained why ("Docker Desktop is per-user on Windows, so only the box proven to serve it is labelled") — that proof had simply never been re-run against the peers.

Fixed and verified: gaming's FleetDispatchServe restarted, round-trip ok:true · bedroom agy 1.1.10 → 1.1.13 via winget, gemini-3.7-flash-medium returns through dispatch · docker label added to DESKTOP-D249KD4-org-1 and DESKTOP-SCDT9HI-org-1 after proving NETWORK SERVICE is in docker-users and the engine pipe is live on both · docker removed from greatroom-tools and home-ci removed from both greatroom runners, so the pool is now 6 runners entirely on peers. Proof: actionlint run 31830452479 executed on DESKTOP-SCDT9HI-org-1, conclusion success.

Uncommitted, council gate pending (branch wt/WT-f37a/FLT-236 in four repos): Flash 3.5 → 3.7 at the four worker-lane pin sites — fleet-harness/routing.yaml + cli_agents.py (a duplicate pin of the same value, worth collapsing), fleet-dispatch AgyInvocation.DefaultMeterModel, usage-governor/agy-wrap.ps1 (must move in lockstep with the previous — its own comment says so), and llm-council/council.config.json sonnet/haiku tiers. Review seats deliberately not touched: Regular Jenny stays 3.1 Pro High, Cyber Jenny stays 3.6 Flash High. AgyModels matches on flash/pro/high substrings rather than version, so metering needed no change — verified at the producer, not assumed. fleet-dispatch suite: 503 passed, 0 failed. Two tests asserted the 3.5 literal while feeding DefaultMeterModel; they now interpolate the const so the pair cannot drift again.

Blocked on Andrew: agy needs interactive Google OAuth on gaming and streaming — browser login, not something an agent can or should complete. Until then only greatroom and bedroom can serve Flash 3.7.

Follow-up: nothing yet routes a card's work to a peer by default — fleet-dispatch is a manual send, and routing.yaml is read by the fleet-harness rail, not by the sessions doing the work. That gap is FLT-115 (auto-spawn engine, fan-out) and needs a design decision before anything is built.

FLT-235 update — enforcement landed (council-seat)

The policy doc alone was a paper control, and the Grok seat reviewing it said so ("a standing policy with no check in this change is a paper control"). council-seat (C# CLI, usage-governor/src/CouncilSeat.Cli, commit c954c96) is the check: it builds each seat's command line and working directory itself — no --exec, no --cwd, so no argument can point a seat at the tree under review. One call does checkout → snapshot (seat tree + live tree) → launch with push disabled and credentials stripped → snapshot → validate → self-citation scan → teardown. Exit 2 = FAILED-CONTAMINATED.

Two High findings from that Grok review, both fixed: (1) cwd is not a push boundary — FLT-56's real damage was a push, and a seat that commits+pushes from the disposable checkout leaves the live tree pristine, so prevention now precedes the assert: tokens/askpass removed, GIT_TERMINAL_PROMPT=0, remote pushurls overridden via GIT_CONFIG_COUNT in the child env (doing it via repo config would have disabled push in the real repo — a linked worktree shares .git/config; caught before shipping). (2) a contaminated seat is dropped whole, not filtered — it can edit A and file a finding on B, and the chairman cannot tell which half is trustworthy.

Four defects caught by the tests and by dogfooding: porcelain read through .Trim() ate the first character of every unstaged filename (hello.txt → ello.txt, breaking every quarantine lookup); a 5145-char review scored "explicit no-findings" because one of its own findings said "no findings enter quorum"; the default --out put a scratchpad seat's cwd inside the repo under review; and writing the tool's own .out/.err before the after-snapshot made it report itself as contaminated.

Verified: dotnet build 0W/0E · dotnet test 711/711 (58 new, no regressions in the existing 653) · live Grok seat end-to-end through the CLI (174s, 5145 chars, Seated, clean-after yes) · --cwd rejected exit 4 · checkout-parent inside the repo refused cleanly, no leaked dir. Integration tests run against real git with a negative control on the push block. Not verified: a live Codex seat through the tool. Not merged — council gate pending.

FLT-235 gate result — the tool reviewed itself and the premise was wrong

Ran the council gate on c954c96 through council-seat itself: 8 seat runs, Cedric over the whole 109KB diff via its disposable checkout, Regular Jenny / Cyber Jenny / Gronktayvius over chunks (chunking recorded as degradation). Every seat reported clean after: yes — the tool did not contaminate anything while reviewing its own commit. Seats: 6/8 reported; Cyber Jenny FAILED on both chunks by refusing the CWE framing, which the validator correctly caught as a refusal rather than seating it as "no findings"; Clahadore skipped (governor, and advisory-only since Claude authored).

Three independent security seats returned the same Critical: a git worktree is not an isolation boundary. It shares the common gitdir — objects, refs, hooks and config — so a seat could move a live branch, rewrite config, or plant a hook that fires on the next human commit, none of it touching its own cwd, so the assert would call it clean. I had already hit one instance of this (the push-url edit that would have disabled push in the real repo) and fixed the symptom without asking what else was shared. Everything was. Now git clone --local --no-hardlinks, origin removed, core.hooksPath pinned empty — which also deletes two earlier findings, since there is no worktree registration to leak.

Also fixed (b6404df): push prevention was far too narrow — URL-form pushes and stored Windows credentials both bypassed it, so every URL scheme is now rewritten via insteadOf, the credential helper is emptied, and the repo under review is blocked as a local path too (proven with a negative control). The containment guard was lexical and a junction defeated it — reparse points are now resolved and the guard re-runs on the materialized path. A refusal could satisfy the no-findings exemption and seat a non-review toward quorum. The assert had three blind spots (already-dirty file rewritten, update-ref, planted hook) and now carries content hashes, the ref set and a hooks digest. council-seat was not published by install.ps1 — a control nobody can invoke — so deploy.ps1 now publishes and smoke-tests it, including asserting --cwd still exits 4 so a future edit cannot quietly reintroduce an escape hatch.

The docs no longer claim more than the code does. "Only cwd constrains the seat" is gone; the policy states plainly that this is not a sandbox. ACLs on the main tree, Job Objects, and a restricted-token seat user are recorded as not-implemented rather than half-built.

Verified: dotnet build 0W/0E · dotnet test 717/717. Pushed, not merged.

FLT-235 MERGED — council-seat on master; OS boundary spun out as FLT-241

Fast-forwarded to master at 09c4988 (caa777e → c954c96 → b6404df → 5ce70f4 → 09c4988), pushed, fanned out to all three PCs and all four Macs (ff=3 each). Worktree removed.

Three gate rounds, three Criticals — and the pattern mattered more than any of them: round 1 found the worktree shares objects/refs/hooks/config; round 2's Critical was caused by the round-1 fix (worktree→clone turned teardown into a recursive walk that followed junctions, so mklink /J clone\x C:\repo would have deleted the live tree); round 3's was caused by the round-2 fix (the junction guard resolved only the deepest existing ancestor, leaving a junction one level up unresolved). Every finding reduces to an in-process check cannot constrain a process running with the user's full rights — spun out as FLT-241 rather than attempting a fourth round.

Verified end to end: dotnet test exit 0, 732/732 · deploy.ps1 publishes and smoke-tests council-seat (5 seats declared, --cwd refused, exe stamp matches HEAD) — that last one was Cedric's P1, a control nobody could invoke because nothing published it.

Re-gate receipts: 10/10 seats seated, every one clean after: yes. Cyber Jenny refused the CWE framing on both chunks in round 1 (correctly scored FAILED, not seated as "no findings") and seated 4/4 in round 2 after reframing to an engineering-standards ask. Gronktayvius took the whole 102KB post-fix diff in one run via --prompt-file, which was itself the first exercise of that fix.

Still true and written into the policy doc: this is not a sandbox. Restricted token, ACLs on the main tree, Job Objects and containers are recorded as NOT implemented rather than half-built. It raises the cost of an accident; it does not contain an adversary.

2026-08-15 — WT-afdb · FLT-239 fleet fan-out broken under PowerShell 5.1 — Landed

FLT-239 · sync-push.ps1 encoding, and scheduled tasks running detached copies

Landed. fleet-repo-sync master ed16d9a; PR #3 merged.

Found while fanning out the FLT-232 merges. sync-push.ps1 failed to parse under Windows PowerShell 5.1, so the fleet fan-out silently did nothing for any caller using that host. Encoding, not syntax: the file had no BOM, so 5.1 decoded it as ANSI; a U+2014 em-dash inside a string literal at line 56 destroyed the string terminator and the parser reported a bogus Missing closing '}' at line 55 — nowhere near the cause. pwsh 7 was never affected. Introduced by WING-345 018b917.

Fixed by prepending the 3-byte UTF-8 BOM, not by re-saving through an encoder: every byte after the prefix is unchanged, so the diff is one line instead of an EOL-churn rewrite. BOM over ASCII-replacing the dash because that dash is runtime output text.

Also fixed: three of four peers ran FleetRepoSync from an unmanaged home-directory copy rather than the repo, so repo fixes would never have reached the scheduled task. Repointed gaming, streaming and bedroom at their repo paths, each verified by starting the task and confirming LastTaskResult=0. Rollback files left on each box.

Gates: PS 5.1 PARSE_OK (was 4 errors), pwsh 7 PARSE_OK, body byte-identical, and the fixed script run under 5.1 pushed and fanned out its own fix — EXIT=0, all peers triggered, macs reconciled, failed=0. Council 3/3 seats approve: Cedric, Gronktayvius, Jenny. Seats split 2-1 on sweeping five sibling scripts; resolved against by evidence — their non-ASCII is comment-only, so latent rather than live, and one of them is the live scheduled-task entrypoint.

Corrections made during this work: an intermediate claim that streaming/bedroom had drifted was wrong — same git blob, different checkout line endings (core.autocrlf is not uniform fleet-wide). Compare the git blob, never raw bytes across boxes. An earlier claim that fleet reconciliation might be dead fleet-wide was also wrong; the scheduled entrypoint parses clean under 5.1.

Still open on FLT-239: the Task Scheduler Operational log is disabled on all four Windows boxes, which is why the original 0x800710E0 could not be diagnosed.

Follow-up: FLT-243 — repo-wide .ps1 encoding standardization plus a parse-check guard under both hosts. The guard must PARSE files, not grep them for non-ASCII. This bug bit twice in one session, the second time in an agent's own fix script.

2026-08-15 — WT-3594 · FLT-246 council-seat false FailedContaminated under peer sessions — In Review

FLT-246 · council-seat: live-worktree ref assert failed every seat when peers committed to sibling branches

PR: usage-governor#4 (branch wt/WT-3594/FLT-246). Found during the WING-549 gate: four concurrent WorkWingman sessions pushed to their own wt/* branches while the seats ran; the live-worktree assert fingerprinted ALL refs of the shared .git, so every seat came back FailedContaminated (refs) with zero modified paths and an unmoved HEAD.

Fix (council-ruled over four rounds, Cedric chair): the live tree now asserts every ref EXCEPT a peer set derived at the OPENING snapshot (PeerRefSet.Derive from git worktree list --porcelain -z + for-each-ref %(upstream)): branches sibling worktrees already had checked out plus their existing upstreams; MINUS this worktree's own branch/upstream; MINUS trunk (master|main, origin/*, origin/HEAD + target) which is never exemptible; prunable registrations exempt nothing; self must match exactly one record or the capture aborts; strict porcelain grammar; symbolic refs carry => target in the fingerprint. Peer moves surface as PeerRefActivity (logged, never a verdict). Reason strings are ASCII. rc-* seat clone unchanged (RefScope.All).

Gates: dotnet build UsageGovernor.sln -warnaserror exit 0; dotnet test 780/780. Every seat in all five rounds ran through THIS branch's council-seat.exe against the worktree (30+ seat runs; one Cedric seat caught writing to its own rc-* clone → FAILED-CONTAMINATED, dropped, re-run clean). Round-5 roster: Cyber Jenny + Gronktayvius seated/pass, Clahadore advisory; Cedric + Jenny re-run in flight at time of writing.

Incident during the gate: the SHARED usage-governor/.git/config lost all remotes and got a core.hooksPath under ug-wt-f0af-flt241/tests/.../GLOBALROOT/Device/Null/nope/rc-* (12:15, again ~12:44) — a peer FLT-241 test wrote to the live repo. Restored (remote add origin, unset hooksPath, branch -u); FLT-241 session notified.

Follow-up: FLT-248 — shared-.git metadata threat model (config, worktree registrations, reflog), directional API hardening, extra coverage.

2026-08-15 — WT-1f12 · FLT-249 retired xAI model slugs — fleet-dispatch Done, odysseus In Review

FLT-249 · retired xAI slugs: two cosmetic leftovers, one of which was not cosmetic

A fleet-wide grep for retired xAI slugs (grok-4-fast, grok-4-1-fast-*, grok-4-0709, grok-code-fast-1, grok-3, grok-imagine-image-pro) across ~/source/repos, ~/.claude, ~/.gemini, ~/.codex, ~/.grok and ~/.fleet-secrets found no live config carrying a retired slug. Two leftovers remained.

1. fleet-dispatch — DONE, merged. PR #6, branch wt/WT-a91c/FLT-249. HarnessRegistryTests.cs:305 used the literal grok-4-fast as its example model; HarnessRegistry passes the string through and holds no default, so nothing was broken — the dead id was just copyable. Now grok-4.6. dotnet test 503 passed / 0 failed; CI build-test and inspectcode both green; merged and fanned out via fleet-repo-sync (3 PCs, 4 Macs).

2. odysseus — the row was stale AND the pricing model was wrong. Local branch wt/WT-b73e/FLT-249, 4 commits. chatRenderer.js priced every xAI model from retired rows, so a current model fell through longest-key matching to grok-4 at $3/$15. Refreshing the rows exposed a larger defect the council caught: xAI doubles both rates at ≥200k prompt tokens and bills the higher rate for the whole request, and the new models carry 256k–1M windows, so long-context turns — ordinary traffic — were reported at half cost. Also grok-build-latest is a compatibility alias for grok-4.5, not the latest grok-build; Cedric raised this in round 1, Clahadore overruled it on absence of evidence, and Cedric was right.

MODEL_INFO moved to static/js/model/modelInfo.js and the cost path to modelCost.js, because chatRenderer.js cannot be imported outside a browser — the tests had been scraping the table with a regex and never executed the function the UI calls. getModelCost is now a one-line delegate. Half-written tier rows fail closed rather than silently pricing at base.

NOT PUSHED — no write access. pewdiepie-archdaemon/odysseus is a third-party public repo where Andrew has viewerPermission: READ, and local dev is diverged (ahead 1868 / behind 2028). The work is committed locally only. Andrew's call: fork and PR upstream, keep it local, or drop it.

Gate: 4 council rounds. Round 1 (3/3 seats) → round 4. Cedric timed out on 3 of 5 attempts; 2 seats survived each round, which meets quorum but left the odysseus test files without a reviewer in rounds 3–4. Two seats were marked FAILED-CONTAMINATED in round 2 by Clahadore's own concurrent edits, not by the seats — the skill warns about exactly this and it was still done. Both re-ran clean.

FLT-260 · Meter real Grok spend into the governor ledger + availability-derived tier directive — Done (landed; pool flip deferred) (WT-ac40, 2026-09-24)

FLT-260 · PR usage-governor#8 · landed usage-governor master c418a42 · deployed + smoke-verified on greatroom, gaming, streaming, bedroom.

  • Grok Build --output-format json carries usage.total_tokens; new grok-exec (metered replacement for bare grok -p) and grok-spend (book/replay a receipt) verbs; council-seat Gronktayvius books its spend and fails closed without a receipt.
  • Hook directives name only lanes below RED (Cedric P2 from FLT-253); PreTool admission now fails CLOSED on missing/unreadable state (council ruling).
  • grokPoolTokens held at null (UNKNOWN): llm-council and fleet-dispatch still call bare grok -p; flipping to 2.5M/24h is owned by the follow-up metering card.
  • Gate: 5 council rounds (Cedric chair) → READY TO MERGE. Gronktayvius FAILED every round (headless grok stalls on inherited MCPs/hooks on greatroom — separate card). Receipts: build 0/0, 833/833 tests, real-CLI smokes; live Grok end-to-end unverified (environment).
  • Follow-up hardening: FLT-261.