AIOS · M2 · host TopBook-Pro · uid 502

Round 2 Capability Ledger

Eleven diagnostic tools, three staged production defects, and every published number re-measured from scratch. Three rounds of inflated figures are corrected below. The corrections section is the part worth your time.

Closed 2026-09-13 05:25 PDT by A3 Sol
Adopt script applied 2026-09-13 05:33Z · CLAUDE.md and settings.json both live
Packet: comms/outputs/2026-09-13-round2-capabilities/ROUND2-PACKET.md

00 · Safety gateThe config that every future session depends on

If ~/.claude/settings.json were broken, nothing else on this page would matter. It is not broken.

settings.json parses clean and every hook target exists

Valid JSON. 4,308 bytes on disk, 2,951 minified. Four PreToolUse:Bash hooks in order: pre-bash-guard, path-guard, syntax guard-bash, block-cue-hook. All sixteen files referenced across the whole hook chain are present on disk. Eight timestamped backups sit beside it, oldest 2026-05-04. ~/CLAUDE.md is intact at 9,523 bytes and still carries the agent-live block at line 101 and the aios-doctor block at line 112.

python3 -c "import json;d=json.load(open('$HOME/.claude/settings.json'));print(len(json.dumps(d)))"

01 · The honest measureHow much of three rounds survives without a human

Reachability counted against four places a tool can actually be invoked from: CLAUDE.md, settings.json, a LaunchAgent, or aios-doctor.sh.

Reachable
10 / 11
Every round-2 script except block-cue-bench.py, which has zero references anywhere.
Runs itself
2 / 11
The Bash hook and the Stop staleness check. The other nine wait for a human to type a command.
Doctor umbrella
2.9-5.0s
quick, three runs. full at 5.17s and 5.41s. Nothing schedules either.
Recall gain
0
Block-cue controls scored 7/8 before the index fix and 7/8 after, at two sample sizes.
Tool reachability, measured 2026-09-13
ToolCLAUDE.mdsettings.jsonLaunchAgentaios-doctorVerdict
aios-doctor.shyesnonoyesreachable
agent-live.shyesnonoyesreachable
block-cue-hook.pynoyesnonoautomatic
block-cue-staleness.pynoyesnoyesautomatic
block-cue-index.pynoyesnoyesreachable
agent-ledger.shnononoyesmanual
agent-run-ledger.pynononoyesmanual
skill-doctor.pynononoyesmanual
comms-map.pynononoyesmanual
memory-doctor.pynononoyesmanual
block-cue-bench.pynonononoorphan

02 · Tomorrow morningOne command that replaces three habits

bash ~/AI_OS/ops/scripts/aios-doctor.sh

Replaces an ssh to the box you are already sitting on (agent-check.sh at 71.6s for 1,615 undated rows), ls comms/outputs (103,603 bytes of bare filenames into context), and reading LaunchAgent plists by hand. It writes nothing except memory-doctor refreshing its own proposed-index file, and it refuses to forward any writing flag.

bash ~/AI_OS/ops/scripts/aios-doctor.sh              # quick, 2.9-5.0s
bash ~/AI_OS/ops/scripts/aios-doctor.sh full         # every check, ~5.4s
bash ~/AI_OS/ops/scripts/aios-doctor.sh list         # the tool table

03 · WiredRuns without you

Two of eleven. These fire on their own and were observed firing during this audit.

block-cue-hook.py

livePreToolUse:Bash

Matches every Bash command against the compiled ICM wall library and injects at most two already-climbed blocks as advice. Never denies, never writes, never shells out, fails open on any exception.

python3 ops/scripts/block-cue-hook.py --explain "some command text"
Honest value

Verified by observation, not by claim: it injected B15 and B104 advisories into two of this session's own Bash calls unprompted. One of those two was relevant, one was noise. Measured noise floor is 8.6% of real commands at a 1,200-command sample.

block-cue-staleness.py

liveStop hook

Compares the index's stored source hash against icm/blocks.json by reading the index head, not by parsing 115KB. Chains into a rebuild on mismatch.

python3 ops/scripts/block-cue-staleness.py
Honest value

0.02s measured. Currently FRESH: index and blocks.json both at sha 7e4f14f9657c, both at 128 blocks. The chain has fired for real once, taking the index from 124 to 128 blocks with nobody typing anything. This is the only self-healing loop the three rounds produced.

04 · One-shot diagnosticsRe-run when something smells

Six tools, all reachable through the doctor, none of them self-starting.

agent-live.sh

pass

Which subagents actually moved, dated and sorted. The old agent-check.sh was slow because the observer LaunchAgent re-registers long-dead subagents every minute, so a May corpse rendered identically to a live agent.

~/AI_OS/ops/scripts/agent-live.sh --since 24h
Honest value

3.08s and 4.97s over 2,081 sidecars tonight, against a 71.6s baseline that is itself getting slower. Quote it as 3-5s warm and 6-7s on the first run of the day, never as "under 5 seconds" — the first run has never met that.

agent-ledger.sh

partial

One row per installed plist, with verdict, exit code, schedule and log age, plus an overlay coverage audit and a stop-criteria section.

bash ops/scripts/agent-ledger.sh
Honest value, and one column to distrust

RED 11 | AMBER 11 | GREEN 11 across all 33 plists. It found RED C on its own before any human did: "mailer-guard.sh — SILENT DEATH (0 tg/notify refs): it can take a live system down and tell nobody." But its wake-count column prints ~1,033,815 no-op wakes for screen-audit-capture, computed as plist age over the declared 5s interval. The live counter says 54,588. That column overstates by 18.9x and is the source of every inflated wake figure in this project.

skill-doctor.py

pass

Separates the three skill tiers so the token bill is the injected tier only, and scores each skill against real usage evidence from transcripts.

python3 ops/scripts/skill-doctor.py cost
Honest value

8,344 tokens injected per session across 144 loadable skills; 5,420 of those (65%) belong to 124 skills with zero usage evidence. The read-only tier adds 4,849 tokens of findability cost that never reaches a system prompt. Never blend the tiers — the blend reads 13,193 tokens and overstates the real bill by 58%.

memory-doctor.py

partial

Lints the memory store that seeds every session: orphans, dead homes, broken wiki-links, and a proposed MEMORY.md index block.

python3 ops/scripts/memory-doctor.py all
Honest value

335 fact files, 140 true orphans at 384,721 bytes and 41% of the store, 53 of them hard-isolated. The orphan histogram is live drift, not a legacy backlog: 51 in July, 46 in August, 12 in September. It has now reported 140 orphans three times and nothing has been actioned once. Output is a paste-by-hand block.

comms-map.py

partial

A bounded view of a tree that costs 26k tokens to list. Reads from a manifest, never from the directory.

python3 ops/scripts/comms-map.py digest
python3 ops/scripts/comms-map.py links
Honest value

2,861 citations, 444 dead (15.5%), splitting 48 repairable / 122 ambiguous / 274 with no candidate. Seven hours ago the same tool against the same unrebuilt manifest read 517 dead. This round's own file creation healed 73 citations. Treat the dead count as a moving number, not a score.

agent-run-ledger.py

pass

Subagent run accounting against a stable key rather than exact call ids.

python3 ops/scripts/agent-run-ledger.py --stalls --older-than 15m
Honest value

19 unmatched starts in the window, every one labelled SYNTHETIC harness row and most tagged as the known hash-break artifact, plus 23 older than 7d from pre-repair log damage. The stable key leaves 42 dangling where exact-call_id would have called 82.

05 · ShelfwareBuilt, correct, and nothing calls it

block-cue-index.py

no gain yet

The one writer in the block-cue family. It was stuck at 120 blocks because the collision rule was inverted: every rebuild diverted to a sidecar the hook never loaded, so the index silently stopped tracking icm/blocks.json.

python3 ops/scripts/block-cue-index.py
Honest value — the fix is real, the gain is zero

The index now matches icm/blocks.json exactly, 128 blocks and sha 7e4f14f9657c on both sides. But measured on the tool's own eval set, the stale 120-block index scored 7/8 on the must-fire controls and the live 128-block index also scores 7/8. Noise floor identical to the command at both 500 and 1,200 samples. The eight added blocks fired on zero of 1,200 real historical commands, because they are walls recorded this week that have not recurred. Currency was bought. Accuracy was not. The permanent miss is launchctl bootout — no launchctl, bootout or plist cue exists anywhere in the index.

block-cue-bench.py

orphan + defect

Measures the hook's noise floor against real harvested commands. Referenced nowhere except one reference doc.

grep -rn '\.round2' --include='*.py' --include='*.sh' ops/ skills/
Honest value

It is the last script still implementing the retired collision rule, in live executable code at line 300 and line 305. A second --md run writes a .round2 twin instead of refreshing. Three rounds passed and no unit ever owned this file. Fix it to the P.1-P.9 rule or delete it.

aios-doctor.sh

opt-in

The umbrella that makes the other tools get run instead of remembered. Named in CLAUDE.md, which is the only thing that will make anyone type it.

bash ops/scripts/aios-doctor.sh full
Honest value

Nothing schedules it. The umbrella is the whole durability argument for round 2 and it depends entirely on a human remembering. That is the open question about whether any of this survives the month.

06 · Staged production defectsThree REDs, all verified, none applied

Files live in ops/reference/staged/. No launchd state was touched by any round.

RED A — screen-audit-capture wakes every ~9.7s to do nothing

verified

The sentinel ops/screen-audit/PAUSED is 0 bytes with an mtime of 2026-07-26 16:00 — 48.6 days. The job is still loaded and still waking; last exit code = 0 is truthful because thirteen lines of bash decide to exit each time. The plist declares a 5 second interval but launchd also reports minimum runtime = 10, and the floor wins.

uid is 502, not 501. launchctl print gui/501/com.aios.screen-audit-capture returns "Could not print domain: 125: Domain does not support specified action".
Measured 9.69 s/wake (8 wakes in 78s). A 6.6-hour cross-check gives 9.5-9.8.
Live counter 54,588 runs · plist age 59.83 days · machine uptime 10.75 days.
Sleep-corrected lifetime estimate ~304,000 wakes, not 1,028,518.
launchctl bootout gui/$(id -u)/com.aios.screen-audit-capture
launchctl disable gui/$(id -u)/com.aios.screen-audit-capture   # persist across login

Tradeoff, written up in RED-A-screen-audit-capture.md: after disable, deleting the PAUSED sentinel no longer re-arms capture. Sentinel and job state become two switches that can disagree.

RED B — deliverables-cesar: invalid XML plus a cleartext credential

verified

The live plist fails plutil -lint on a bare ampersand at line 13, so it will not survive a reboot, and PID 1002 is running against it right now. It also carries SHELL_BASIC_AUTH_PASSWORD in cleartext under EnvironmentVariables, world-readable since 2026-07-19.

live plist → "Encountered unknown ampersand-escape sequence at line 13"
staged replacement → OK
install -m 755 ops/reference/staged/RED-B-with-secret.sh ops/scripts/with-secret.sh
plutil -lint ~/Library/LaunchAgents/com.aios.deliverables-cesar.plist   # must say OK first
curl -s -o /dev/null -w '%{http_code}\n' http://127.0.0.1:3120/          # expect 401

Full seven-step install in RED-B-NOTES.md. Read the secret out of the live plist yourself; never ask an agent to echo it. Step 7 is the one people skip: shred the .bak- copy and rotate the password. The backup is a live secret.

RED C — the booking mailer already killed itself once, silently

verified · already fired

Twelve consecutive failures at 300s is one hour. The block at lines 27-36 of mailer-guard.sh reaches exactly four side effects: a cat > into a markdown file, an echo >> into a log, an rm -f, and a launchctl bootout. There is no notification path. Runs on Nano, so apply there.

Strike block grepped for tg | curl | osascript | sendmail | /usr/bin/mail | notify | node | wget | nc → no match. mailer.mjs grepped for tg | osascript | telegram | webhook → 0.

It has already fired: comms/outputs/2026-09-06-booking-mailer-SELF-DISABLED.md, 230 bytes, written 2026-09-06T21:35:32Z. Booking mail stopped and nobody was told. com.aios.booking-mailer shows active count = 0 today.
cp skills/booking-mailer/mailer-guard.sh skills/booking-mailer/mailer-guard.sh.bak-$(date -u +%Y%m%dT%H%M%SZ)
patch -p1 -i ops/reference/staged/RED-C-mailer-guard-notify.patch skills/booking-mailer/mailer-guard.sh
bash -n skills/booking-mailer/mailer-guard.sh

After patching, force a real twelve-strike run and confirm your phone buzzes. An untested alarm is not an alarm.

07 · CorrectionsEvery number that changed, and why

This is the centrepiece. Three rounds produced three generations of figures; these are the ones that moved and the reason each one was wrong.

block-cue recall "gain from 4 new blocks"7/8 → 7/8, no change

No earlier round measured this, and it is the correction that matters most. Replaying the tool's own must-fire control set against the stale 120-block index and the live 128-block index gives an identical 7 of 8, and an identical noise floor, at both a 500-command and a 1,200-command sample. The eight blocks the fix added fired on zero of 1,200 real historical commands. The staleness repair is genuine — the index hash now matches blocks.json, so future walls will reach the hook — but it bought currency, not accuracy.

screen-audit lifetime wakes 1,028,518~829,000~304,000 est. / 54,588 observed

The original figure is fully reproducible and fully wrong. It is agent-ledger.sh's own arithmetic, plist age divided by the declared 5 second interval, and the tool still prints ~1,033,815 today. It is 18.9x the live counter because launchd throttles to a 10 second floor and the machine sleeps roughly 41% of wall time. The intermediate 829,000 used 17,280 wakes per day and is 2.7x too high. Use 54,588 observed and stop quoting the ledger column.

wake interval 5s documented10.0s claimed9.69s measured

The plist says 5, launchd reports minimum runtime 10, and direct measurement lands at 9.69 rather than a clean 10.0. The conclusion is unchanged; the precision was overstated.

RED A uid 501502

Every command in the first draft targeted a launchd domain that does not exist on this box. gui/501 returns error 125.

RED C notification grep 0 matches11 matches

All eleven are the substring "mail" inside "booking-mailer". The finding was right and the transcript was wrong: a command-position grep still returns zero notification calls, so the defect stands undowngraded.

skill-doctor token bill 13,023 / 46%8,344 / 65%

The old figure blended three loadability tiers including 83 skills the Skill tool cannot load, overstating the real per-session bill by 58%. It drifted again tonight: the read-only tier moved from 82 skills at 4,679 tokens to 86 (83 deduped) at 4,849, and the blend now reads 13,193 / 45%.

comms-map dead citations 517 (55/124/338)444 (48/122/274)

Certified "CONFIRMED correct against a live re-run" seven hours ago. Tonight it reads 444 against the identical, unrebuilt manifest, because this round's own file creation resolved 73 previously-dead paths. The tool is stable; the filesystem is not. The "126 fixable now" that preceded both was first-match guessing and stays retired.

agent-check baseline 59.4s / 1,610 rows71.6s / 1,615 rows

Measured a day apart. The tool is getting slower as the observer accumulates dead subagents, so the speedup claim for agent-live.sh is stated against the newer, slower baseline.

LaunchAgent verdict RED 10 | AMBER 12RED 11 | AMBER 11

com.aios.overnight-council went RED on LastExitStatus 1 between rounds. Separately, AGENT-LEDGER.md moved from 124 to 135 lines: the shipped render used --quiet-green and silently dropped 11 of 33 agents.

memory store 329330335 fact files

Live drift from concurrent sessions writing memory. The orphan count held at exactly 140 through all three measurements.

disk reclaim -1.49 MB reclaimed+3.75 MB added

33 backup and sidecar files totalling 3,935,955 bytes now sit on disk, plus a 112 KB quarantine entry. The emitted delete command also reclaims zero bytes on the day it runs, because gc-safe-delete moves files into a quarantine inside the same tree.

08 · Still openWhat three rounds did not close