The steward asked whether he could be invoked. §9 says yes — "the steward calls it by
name, the executor or jurist yields the floor, the fool answers at length" — and it was
not built. Worse, yesterday's spec did not list it: not in what exists, not in what is
owed. A document whose whole job is to say what is and is not there, silently missing a
requirement. Recorded in the spec rather than quietly corrected, because that is the
fourth negative state-claim to go wrong in two days and the second inside a document
written to prevent the class.
The net is widened EXPLICITLY and in one dimension, per the steward's ruling: §9
licenses LENGTH for this surface and nothing else, so the ceiling goes 9 -> 180 and the
one-line rule lifts, while no-advice, no-questions, no-'we', no-vocabulary-of-lack and
no-addresses are untouched and are not parameterised anywhere. Silence-on-violation
holds here too. Six negative controls assert each clause still bites at length — the
executable form of "widen it explicitly, but never relax silence-on-violation".
⚠ Length is where the no-truth-value guard is most at risk: a fool given a paragraph
elaborates, and elaboration is how a gesture becomes a claim. The prompt spends its
budget there rather than on register.
It finds the newest transcript itself, so the steward runs it directly rather than
through the executor. That is the point of the surface: a relayed fool is the executor's
paraphrase of a fool.
⚠ One control asserted a literal the prompt did not use ("NO TRUTH VALUE" against
"NOTHING YOU SAY MAY HAVE A TRUTH VALUE"). It fired, correctly. Rewritten to test the
substance — phrase present AND negated — because the original would have passed happily
on any rewording that dropped the constraint entirely.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01J6hZXNYSxEfZseBGTni4sf
9.4 KiB
name, description, metadata
| name | description | metadata | ||||
|---|---|---|---|---|---|---|
| TARBUCKLE-SPEC-13.1-2026-08-25 | v2 §13 deliverable 1 — the spec for what was actually built on 2026-08-25: three tiers wired, the wrap seam not built and why, every deviation from the v2 draft named with its reason. Written AFTER the build, per §12's build order, so it describes what exists rather than what was intended. |
|
Tarbuckle — implementation spec (§13.1)
Provenance. Implements BUDDY-PATTERN-jurist-draft-v2-2026-08-22.md, against the bones
in seed/FOOL-BONES-2026-08-25.md and the register in seed/FOOL-SOUL-2026-08-25.md.
Cadence determinations: PENDING.md, PENDING-152 and the three ⚖ blocks of 2026-08-25.
Steward's four build rulings: this session, recorded in §6 below.
Commits 6f0ccde · 3df5e4f · 7a9dbf2.
⚠ Written last on purpose. §12's order puts the spec after the wiring so that it records the built thing. Four claims in the v2 draft and in PENDING-152 did not survive contact with the substrate; a spec written first would have carried all four.
1 · What exists
| tier | trigger | surface | file |
|---|---|---|---|
| body | every status-line render | status line | scripts/tarbuckle-body.py |
| mumble | wall clock, 20 min | status line, 120 s | + scripts/tarbuckle-mumble.py |
| voice | wake seam | SessionStart hook output | scripts/tarbuckle-seam.py |
| invoked | the steward calls him by name | stdout, run by the steward | scripts/tarbuckle-invoke.py |
Configuration, in ~/.claude/settings.json:
"statusLine": { "type": "command",
"command": "~/dotfiles/scripts/tarbuckle-body.py",
"refreshInterval": 60 }
plus tarbuckle-seam.py appended to the SessionStart hook chain.
State — three files under ~/.claude/state/, none of which is a budget:
tarbuckle-last-tick (one epoch), tarbuckle-slot.json (one utterance, expiring),
tarbuckle-invocations.jsonl and tarbuckle-rejects.jsonl (instrumentation, never read
back into behaviour).
2 · The body
Tarbuckle plus one mark, where the mark is one dot at three heights — . · ˙ —
advancing once per wall-clock minute.
The binding constraint is carried structurally, not by intention. render() takes the
minute and nothing else; a function that cannot see the session cannot leak it. Asserted
on co_argcount and co_names, with a deliberately leaky fixture proving the assertion
can fail.
⚠ len(MARKS) is coprime with the mumble interval. Had it been four marks rather than
three, the mark visible whenever a mumble landed would have been fixed, and the body would
have silently announced the voice. Asserted, with a commensurate 4-cycle as the negative
control. This is the first of two collisions that were invisible until checked for.
3 · The mumble
Occasion: the clock, 20 minutes. Draw: 73 / 20 / 7, consumed whatever it says — a conserved draw is a budget and a budget is memory. Material: the live session, tool output stripped. Register: the soul, read from its filed artifact at run time.
⚠ The register is never duplicated in code. No soul, no voice — there is deliberately no fallback register, because a fallback voice is a second fool nobody derived.
The net — 3–9 words, one line, no advice, no questions, no we, no vocabulary of lack,
nothing with an address. A violation yields silence, never a repaired line. Rewriting
his words would make the executor his editor.
Generation is detached: a headless call measures 7–12 s and a status line cannot wait.
4 · The voice, and the half that is not built
The wake seam speaks through the SessionStart hook, bounded at 15 s.
⚠ THE WRAP SEAM IS NOT BUILT. SessionEnd exists as a hook event, but its handler
writes to stderr only when a hook fails; a successful hook's stdout goes nowhere. §9
requires output to reach the steward, so wiring the wrap seam there would be a mechanism
that fires into nothing and reports success. Owed, not dropped. The remaining route is
the /wrap-up skill itself, which is a skill change and therefore goes through the
skill-harvest register rather than being taken unilaterally.
⚠ Bounded generation is legitimate because of the steward's ruling, not despite it: "A guaranteed occasion is not a guaranteed utterance. If a seam produces nothing that passes, let it produce nothing." Timeout ⇒ silence, logged.
5 · Deviations from the v2 draft and PENDING-152, each with its reason
| # | filed text | what the substrate says | disposition |
|---|---|---|---|
| 1 | PENDING-152: the tick is "a counter over refreshes rather than over events" | refreshInterval re-runs "in addition to event-driven updates", so invocations burst with activity |
Mechanism replaced, conclusion kept. The tick consults the clock. AMENDMENT 8 |
| 2 | PENDING-152: "whether Claude Code re-renders on a timer… not verified" | 14 consecutive 60 s gaps with no input, in the body's own log | Settled, by the experiment the item itself specified |
| 3 | §8 table: voice at seams "guaranteed" | — | Narrowed by steward ruling to guaranteed occasion |
| 4 | §8a: "whether a status line is already in use" | no statusLine in any settings file |
Confirmed free; nothing displaced |
6 · The steward's four rulings, carried
- The net carries to tier 3 unchanged — imported, never reimplemented. A second copy is a second, quietly divergent standard.
- Never relax silence-on-violation. Widening the seam's word cap is licensed if evidence warrants, explicitly and stated; the cap is left as filed on one near-miss, because widening on n=1 is tuning to taste.
- The rejection log is the diagnostic — true-versus-drawn rate and what was rejected. ⚠ Its first use exposed that it recorded the verdict and discarded the line. Fixed.
- Check any new periodicity for commensurability. A seam is aperiodic and adds no
period — but the check found that
last-tickpersists across sessions, so a gap longer than the interval left a mumble already due at the moment of waking. The seam now resets the clock. Second invisible collision found by an explicitly mandated check.
7 · Verification
python3 ~/dotfiles/scripts/tarbuckle-body.py --selftest # 30 controls
python3 ~/dotfiles/scripts/tarbuckle-mumble.py --selftest # 19 controls
python3 ~/dotfiles/scripts/tarbuckle-seam.py --selftest # 15 controls
python3 ~/dotfiles/scripts/tarbuckle-invoke.py --selftest # 17 controls
Positive and negative throughout: every claim has a fixture that makes it fail.
⚠ source_lacks() exists because the same bug was written twice in one session — a
control whose needle is a literal plants that literal in the file it searches. The second
instance was written minutes after the first was fixed, by the party who fixed it, while
watching for it. The fix is a mechanism, not a correction, because the correction had
already been tried and did not hold.
7a · Named invocation (§9)
! python3 ~/dotfiles/scripts/tarbuckle-invoke.py # bare
! python3 ~/dotfiles/scripts/tarbuckle-invoke.py "what now" # asked something
⚠ Run by the steward, not relayed by the executor. Anything the executor pastes is the executor's paraphrase of a fool; this surface exists so the floor is yielded rather than reported. It finds the newest transcript itself so it needs no session context.
The net is widened EXPLICITLY and in one dimension only — §9 licenses length for this surface and nothing else:
| ordinary | invoked | |
|---|---|---|
| word ceiling | 9 | 180 |
| one line | yes | no |
no advice · no questions · no we · no vocabulary of lack · no addresses |
unchanged | unchanged |
⚠ Length is where the no-truth-value guard is most at risk — a fool given a paragraph elaborates, and elaboration is how a gesture becomes a claim. The prompt spends most of its constraint budget there, and a violation is still silence.
8 · Owed
⚠ This list omitted named invocation in its first version, on the day it was written. §9 requires it; §1 did not carry it; §8 did not owe it. Caught by the steward asking whether he could be invoked — a question the document should have answered. The fourth negative state-claim to go wrong in two days, and the second inside a document written to prevent exactly that. Recorded rather than silently corrected.
mute/off(§9, "available at all times") — not built. The only off-switch is §9 below, which is removal, not muting. Muting is never a fault and there is currently no way to do it.- The wrap seam (§4) — no delivery surface; route is a skill change.
- The two-week rate report — §8 obliges it;
DEFERRED-DECISION: mumble-rate-two-week-report, convertedmanual→date 2026-09-08the day the body shipped. - Frequency remains UNKNOWN and is not guessed. The invocation log now measures the base it needs.
~/.claude/settings.jsonis untracked, and a divergent parallel copy sits at~/dotfiles/claude/settings/settings.json(2 keys against the live 8). Named, not fixed.
9 · Off
Remove statusLine from ~/.claude/settings.json and the seam line from the
SessionStart chain. Nothing else references either. mute/off per §9 is not built
— it is owed with the wrap seam.