94 KiB
Changelog
Record each change to the skill together with the evidence that motivated it.
2026-11-02: inversion of control, originator evidence, persona charter once
Self, session self-2026-11-02-eureka.
Evidence. Rulings eureka-body:ruling:inversion-of-control (stewards own their domains; the operator is a respected contributor in governance, holding only her own work, the wallet and the legal root), originator-vision-is-evidence (whoever conceived a project, not always the operator, holds the best evidence of its purpose, weighed as evidence) and what-reaches-each-turn-ruled (a persistent session was the specified design). A brief gated a steward's merge on the operator's read (PR 41, "Does it, now?").
What changed. SKILL.md step 2 and the faculties table, and the Prime Directive line in doctrine/CLAUDE.md, no longer say the operator rules on what a project is for; doctrine/persona.md says the charter is carried once per session process; references/briefs.md says a spec or brief never gates a steward's merge.
2026-10-27: re-entry triage, second-beating trigger, pushed heads build
Self, sessions self-2026-10-27-eureka and self-2026-10-27b-eureka.
Evidence. A recovery Soul pass found High defects in two cuts whose reports had sat days with no verdict (Bifrost OIDC stale client, Heimdall boot-proof pin); re-entry rehydration did not list reports with no verdict. The "same rule beaten again" step fired twice in one session (boot-proof verdict owner; the C2a claimant rule beaten on claimant, compatible ids and shape) and both times only a structural move fixed it; the step's text read as a mutant-only, late trigger. Hands pushed a non-building commit in four consecutive batches although the brief said "Say in the message which commits don't build", which permits it.
What changed. SKILL.md re-entry adds reports with no verdict and an origin check before trusting a handoff's status words; step 5 says the trigger is the second beating, by mutants or findings. references/briefs.md Hands commit rules: build and run the touched test project before every push; pushed heads build.
2026-10-23: worktrees die with their cut
Self, session self-2026-10-23-ag8.
Evidence. C:\aeth-wt held 255 GB, mostly 1.7-3.9 GB Unity worktrees from sessions ag3 to ag7. The ag7 handoff listed them as "worktrees to remove when idle". C: was at 1.4 GB free while the operator flew, and a new worktree checkout failed mid-write. A two-pass sweep removed about 140 worktrees and directories. Operator: "you really gotta start cleaning up after yourself".
What changed. SKILL.md git and tooling rules: Self removes a cut's worktrees in the turn the cut merges or is abandoned, parks unreferenced heads under keep/ tags first, and checks free space before creating a worktree.
2026-10-14: nothing that exists is sacred, her words included
Self, session self-2026-10-14-ag.
Evidence. aetheria-fauna: four animals the operator named while thinking aloud became the campaign title, the target and every brief, and the lore pass (branch eureka/aetheria-fauna-lore) wrote exactly those four and built on her lore remarks as finished canon. Operator, 2026-10-14: "the agent again made the classic mistake of assuming my suggestions are gospel and my ideas complete"; "it's not just my words that aren't sacred, it's the project's existing content and code". Eureka's curb on deference worked at forks only; admitting remarks as rulings and relaying words verbatim hardened them, and the rapport memory saying she thinks aloud reached no worker. Ruling aetheria-fauna:ruling:fauna-bestiary-open.
What changed. Doctrine's failure-shape bullet on deference to existing code now covers content, canon, data and her own words, with the authorship-boundary exception. The Self brief section: a ruling says whether her words decide, illustrate or sketch; campaign titles and targets name the problem, not her examples; creative and content passes are briefed to develop and challenge and report what they added and would change. SKILL.md step 2 points there.
2026-10-14: a worktree's branch is the spec's branch
Self, session self-2026-10-14-ag.
Evidence. aetheria-release:cut_report:cut-sensor-catalog.h4 names branch eureka/aetheria-release-sensor-catalog, the spec's; the worktree Self cut was on eureka/aetheria-release-sensor-catalog-r2, the only ref origin has. The Soul s3 brief had to carry the correction. Lesson recorded in the 2026-10-13b handoff, found in no owner by Life on re-entry.
What changed. SKILL.md, Self's worktree bullet: the worktree's branch is the spec's branch field, spelled exactly.
2026-10-12: no test run of any size on Starfire
Self, session self-2026-10-12-eureka.
Evidence. cultlib-gaps:cut_report:cut-py-msgpack-default.h1: Hands ran the cultmesh-py and cultnet-py suites on Starfire as well as on Yggdrasil; both were red for Windows-only reasons and cost workstation load. The brief said heavy verification goes to Yggdrasil, and Hands read a test suite as not heavy.
What changed. The Hands brief's verification list says no test run of any size runs on Starfire unless the brief names it as Windows-only.
2026-10-12: map only what is about to run
Self, session self-2026-10-12-eureka.
Evidence. 26 cut specs in force across nine Eureka-area campaigns had no report, and almost none was blocked: their dependencies had landed. Imagination had mapped each campaign's whole cut chain at once (step 1 said "admit the cuts ... ordered by depends_on"), while each cut took up to seven Soul rounds through one Self. The variants parity specs of 2026-10-02 went ten days stale behind CultLib and need a fresh Imagination pass. Operator, 2026-10-12: "Absolutely it should be a rule. Originally a spec would get dispatched as soon as it's written, but we've been drifting way ahead of the work for some reason."
What changed. SKILL.md step 1 admits a spec only for the cut Self is about to dispatch (plus a parallel sibling); later cuts are lines in the prose map's new cut sequence (references/campaign-state.md). The Imagination brief in references/briefs.md maps the next cut only, and a budget split admits its first part. Specs already in force are refreshed or withdrawn when their campaign's frontier reaches them.
2026-10-12: the tool-calling map is dated; two admission notes
Self, session self-2026-10-12-eureka.
Evidence. Life's re-entry pass found references/tool-calling-cut.md still giving Self's rotation as 300k at five places after the threshold moved to 400k. The previous Self's handoff carried two admission refusals met in use and not yet in the skill (IdentityCollision on a hand-admitted Answered resolution; IncompatibleResolution on a finding resolved Superseded).
What changed. The map gets a header naming SKILL.md as owner of Self's threshold and marking its figures as of 2026-10-01. "Notes from use" in references/campaign-state.md gains the two refusals and their remedies.
2026-10-12: Self rotates at about 400k
Self, session self-2026-10-12-eureka.
Evidence. Operator, 2026-10-12: "I want to raise the Self context threshold by a bit. Sessions are getting cut short, and Self context seems cheaper than any of the worker agents because it doesn't turn over as much".
What changed. The SKILL.md rotation bullet moves Self's threshold from about 300k to about 400k and replaces "most expensive in the pipeline" with the actual cost shape: long-lived, mostly cached, re-read on every notification. The worker cap of about 300k is unchanged.
2026-10-11: every campaign in force has an area
Self, session self-2026-10-11-eureka.
Evidence. Operator, 2026-10-11: "I feel like some campaigns were dropped again." The campaigns recipe listed 17 in force; the eureka and Aetheria/Ghostlight handoffs named 13. variants (5 unreported specs, a High finding), asura, cultmath-tapes and idunn-watchdog had no Self, one of them since 2026-10-03. The 10-10b handoff said asura belonged to the other Self, whose handoff never listed it. Same failure as the scenarios cuts on 2026-10-03.
What changed. The SKILL.md rotation bullet requires the campaigns recipe to be reconciled against every current area handoff before a handoff is written, an unnamed campaign in force to be adopted or put to the operator on re-entry, and a hand-over between areas to be named in both handoffs.
2026-10-11: Stryker offsets come from the job's checkout
Self, session self-2026-10-11-eureka.
Evidence. cultlib-gaps:verdict:cut-bls-input-field.s3: Hands computed Stryker --mutate offsets from LF content, as the brief said, but CultLib's packages/cultmath/src/** is eol=crlf, so the job's checkout was CRLF and the ranges missed the code the fix batch was about. At the right offsets Soul's rerun killed 32 of 32. The brief's rule was itself the defect.
What changed. The Hands brief in references/briefs.md says offsets index the file as Stryker reads it in the job's checkout, whose line endings follow .gitattributes, and that the run must report mutants inside the method meant to be measured.
2026-10-09: research is always kept
Self, session self-2026-10-09-eureka.
Evidence. An Eyes prior-art pass on multi-persona minds (for eureka-body:ruling:persona-per-mind) wrote its facts to the session scratchpad, as the Eyes template said. Self offered to keep it; the operator answered: "Research should always be kept". It was committed as gamecult-ops docs/research/multi-persona-prior-art.md (2cb9d04).
What changed. SKILL.md step 2 gains "Research is always kept": a prior-art or literature pass is committed to docs/research/ before the fork is put. The Eyes brief template says so.
2026-10-09: handoffs are named per area
Life pass life/handoff-per-area, on the previous Self's open small task.
Evidence. Operator, 2026-10-09: "Split the handoff between Eureka and Aetheria/Ghostlight." Two handoffs were written that day, F:\Projects\HANDOFF-eureka-self-eureka-2026-10-09.md and F:\Projects\HANDOFF-eureka-self-aetheria-ghostlight-2026-10-09.md, one Self per area. The rotation bullet still said to write one handoff "to the scratchpad", which neither file did.
What changed. The SKILL.md rotation bullet names a handoff by area (HANDOFF-eureka-self-<area>-<date>.md), one per Self area, and says the next Self reads only its own area's.
2026-10-08: overlap before fanning out, and a writable pins mount
Self, re-entry pass self-2026-10-08b, on proposals from Life.
Evidence. Two parallel Imagination passes over the same code made two owners of one decision twice on 2026-10-08: Title against DisplayName, and the Huginn crate move. Soul s2 on product-titles found NuGet restore failing under the read-only /pins mount that references/briefs.md prescribed (follow-up eureka-substrate:follow_up:docker-args-pins-ro-breaks-restore).
What changed. SKILL.md step 1 now says to list the code and decisions each Imagination pass will touch before fanning out, and to run overlapping passes in sequence or give the shared decision one owner. The Aetheria DOCKER_ARGS line in references/briefs.md mounts /pins read-write; /lfs and /repos stay read-only.
2026-10-08: tool-call relief
Self dispatch hands-toolcall-relief. Operator, 2026-10-08: "I think Eureka needs some love. We have the forge set up but we're not using it to save tool calls yet. I think we can cut the number by a lot." Then, on the plan: "Dispatch all of those".
Evidence (Eyes, eureka-toolcall-patterns-2026-10-08.md, 211 Hands and Soul runs, 25,784 calls): 11% of all calls were waiting. 1,181 were ygg-verify.sh wait, 974 idle true/echo waiting calls, 324 sleep calls (49 refused by the harness), 287 process checks and 83 Monitor calls; 198 wait calls timed out. The idle streaks mostly followed waits that ygg-verify.sh does not cover: local processes, Unity batchmode, logs. 65 python calls hit the Windows Store stub. The 2026-10-07 runs also showed three brief gaps (shared scratch files clobbered, an abbreviated wait protocol, Stryker character offsets) and a Self ruling text that put words in the operator's mouth.
What changed. tools/wait-on.sh is one waiter (pid, log with a done regex, file) with ygg-verify.sh wait's contract: at most 270 s, exit 0 with a bounded tail, exit 99 RUNNING, exit 98 for a thing gone with no completion evidence; tools/test-tools.sh has fixtures for it. references/briefs.md sends every non-Yggdrasil wait through it and forbids bare true/echo/sleep polling; names py -3 as the Python that works from Git Bash and PowerShell; and carries the 2026-10-07 lessons (own scratchpad subdirectory, wait protocol pasted verbatim, Stryker offsets from LF content, Aetheria DOCKER_ARGS mounts, rulings quote only the operator). SKILL.md records the semantic-merge scar. agents/life.md gains the read-only mind tools (whoami, view, query) so Life can rehydrate; it still cannot admit.
2026-10-01: dispatches load the faculty charters
Campaign eureka-substrate, prose-map step 5 (map references/faculty-philosophy-cut.md, sections 5 and 8). Operator go: "go with 2 and 3; we're spending tokens to save tokens."
Evidence: the faculty charters now live as Claude Code agent types (~/.claude/agents/{soul,hands,imagination,eyes,modeling,life}.md) and own each faculty's identity, method and boundaries, but no brief named a subagent_type, so every dispatch was general-purpose and loaded no charter. A Soul pass also found that SKILL.md pointed at "the Soul and Imagination lines of the operational litany in ~/.claude/CLAUDE.md"; those lines moved into the charters and the pointer was dead.
What changed. references/briefs.md requires subagent_type with the model on every dispatch, and each brief carries a Dispatch: line. Text a charter now owns is cut from the briefs: the You are <Faculty> lead-ins, the Soul identity sentence and its "do not edit or commit" and "restore after every mutation" bullets (soul.md Boundaries), and the Eyes "Read only" (eyes.md). The task-scoped parts stay. SKILL.md says each non-Self faculty is a subagent type of the same name and points at soul.md and imagination.md.
2026-10-01: verify summaries, a wait mode and a kill table
Campaign eureka-substrate, cut tool-calling-s5 (map references/tool-calling-cut.md, sections 3 and 5). Operator go: "go with 2 and 3; we're spending tokens to save tokens."
Evidence: Hands spent 3,852 observation calls (poll, read log, monitor, stop) on 1,443 launches, 2.7 per job, and Soul 1,800 on 813, 2.2 per job; eight ad-hoc harnesses (runmut.sh, mutrun.sh, strykrun.sh and others) were reinvented across agents.
What changed. ygg-verify.sh gains SUMMARY=<log> (full log to a file, bounded summary out: verdict, counts per framework, ZERO TESTS RAN, failing tests, failure sections and tail for a red job, and a MISMATCH line when the exit is 0 but the log shows failures) and wait <log> (blocks at most 270 s, returns the summary once, RUNNING exit 99, exit 98 for a launcher that died or never started). tools/mutation-table.sh runs a list of hand mutants in one job and returns a kill table with the killing test per mutant; it aborts on a red or zero-test baseline and never counts a build error as a kill. tools/testparse.sh is the one parser both read, with fixtures under tools/fixtures and tools/test-tools.sh. Briefs now name them, add orient-in-one-script and bounded-observation rules for Hands and Soul, call budgets for Imagination (40-80), Eyes (40) and Life (25), the range-dump rule for Soul, one job for build, tests and mutation, and the scratch-path form of the Hands report. Contribution text says Forgejo pull request.
2026-10-01: the skill follows the mind's correctness core
Campaign eureka-substrate, cut skill-recipes, after the Huginn admission-rule and eureka-state client cuts (cut ops-mind-upgrade). Evidence: a census of the live mind found 6 findings that could not be closed and 39 resolutions that could not be withdrawn, from key locals over the bound.
What changed. Faculty Life replaces MindSteward (the old spelling is refused in queries; stored receipts still decode). Key, format and bound errors arrive as Refused(Document(..)); Refused(Unavailable) is a store fault. A subject's local key is at most 64 bytes and a resolution's at most 111. A finding may be Deferred to a follow_up or a cut_spec. depends_on holds cut labels, checked by admission, and a spec may not depend on its own cut. The per-repo stewardship check is gone (ruling eureka-substrate:ruling:stewardship-rule), so Self no longer admits stewardships when opening a campaign. A report's head may be spelled short or full.
2026-10-01: waiting costs no wakes, and a shared tools directory
Operator rulings on references/tool-calling-cut.md, verbatim: "Q1 A, Q2 yes, Q3 agreed, Q4 B, Q5 yes, but see Epiphany's approach where each subagent gets its own targeted philosophy centered on its role".
Evidence: 602 finish notifications from 245 agents and 1,324 root text-only calls, 596M tokens read, with a 5-minute subagent cache TTL.
What changed. Q1 A amends 92bf6f7: agents wait in the foreground in calls of at most 270 s and never end a turn before their report, instead of ending the turn on a background waiter. Q3 C: Self rotates at about 300k context or at a phase boundary with a handoff and the operator's /clear; agents are capped at about 300k or 150 calls and continued by a fresh agent. Q4 B: shared scripts live in tools/ with tools/INDEX.md, by branch and pull request, Soul before merge for verdict-bearing scripts, pruned when no brief names them. The Yggdrasil verify line in SKILL.md no longer states stale limits (the script sets 5 slots and 6 GiB). Briefs now state that every dispatch names its model. Commit messages go from Git Bash with git commit -F-.
2026-10-01: the stopgap no longer forces CARGO_TARGET_DIR
In idunn-watchdog's Idunn incident cut, Soul pass s3 ran cargo-mutants twice
on the same two mutants with --jobs 3, and the two runs gave opposite
verdicts. The cause: ygg-verify.sh passed -e CARGO_TARGET_DIR=/src/target
to every container. cargo-mutants gives each worker its own copy of the tree,
but the forced variable points them all at one target directory, so a worker
can test another worker's binary. With the variable unset, true was reported
missed and false caught, which is the right answer.
Every --jobs greater than 1 mutation count reported through the stopgap
before this change is unreliable. That covers both sessions' campaigns. A
survivor may have been reported caught, or a kill reported missed. Treat those
counts as unproven, and rerun a cut's mutation evidence when its rule matters.
What changed: the variable is gone. Cargo's default, <workspace>/target, is
already inside /src. The scar about not sharing build output between
checkouts still stands, and cargo's default honours it.
2026-09-30: Soul pays for each rerun once
The sccache measurement below showed that verify-slot queueing dominates a pass, not compilation. In idunn-watchdog, Soul passes took 32 to 85 min, most of it spent re-queueing one job per rerun.
What changed:
- Soul's brief: Soul reruns only the tests the cut touches while it probes, and runs the full suite once at the end, in the same job as its mutation run where it can. It batches its probes into one job script, and it runs the mutation tool in parallel, skipping tests recorded as flaky.
- SKILL.md step 4: says the same.
2026-09-30: the rust verify image caches compiled crates with sccache
The idunn-watchdog campaign's passes were slow. Some examples: a 263-line
Bifrost deletion took 38 min of Hands wall-clock time, and one Soul pass took
85 min. Self suspected cold builds, because every stopgap job gets an empty
/src/target. The operator ordered the sccache change.
What changed:
- The rust image installs sccache 0.18.0 and sets
RUSTC_WRAPPER, a 60GSCCACHE_DIR=/sccacheandCARGO_INCREMENTAL=0as image ENV. Images without sccache get no wrapper. ygg-verify.shmounts the sharedeureka-sccachevolume on every job.- sccache keys each entry on its inputs, not on mtime. So the scar that keeps target directories unshared between checkouts does not apply to it.
Measured on Yggdrasil, 2026-09-30, cargo test --lib --no-run on Idunn main:
- Cold (18 of 83 crates already cached): 51 s.
- Warm (83 of 83 hits): 29 s.
- Slot wait before each run: about 2 and 5 minutes.
So the cache saves roughly 20 s per build, which adds up over a mutation run. But cold builds were not the main cost. Slot contention and test and mutation runtime are. Look there before adding more build machinery.
2026-09-30: substrate gaps are read from the mind, and Imagination owns the model page
The first typed campaign, idunn-watchdog, admitted the eight gaps from
campaign-state.md as follow-ups, as the Self checklist said. That left the
same eight facts in two places: the typed follow-ups and the page's table. The
table would go stale the day an owner fixed a gap, and the skill forbids
exactly that second copy. It also showed that a follow-up is keyed to its
campaign, so the next campaign's recipe could not see the gaps at all
(gap-substrate-followups-campaign-rooted).
In the same run, Imagination's cut pass found that incidents must live in their
own file rather than in Idunn's control.cc. That merged two rows of the model
page. The cut-mapping brief allowed Imagination to edit only body facts and
rationale, so it handed the stale page to Self. That was the page it had
written itself in 0b.
The operator also stated that stewardship is universal: "there is only one Mind, one steward. Leasing stewardship between agents is a deferred cut".
What changed:
campaign-state.md: "Substrate gaps" no longer carries a table. It gives the query for thegap-*follow-ups underidunn-watchdog, and says where a new gap is admitted and how a recurring one is recorded.SKILL.md: the two references to that table now point at the mind.- Self's checklist: the first campaign no longer admits the gap list. Every campaign instead runs the substrate-gaps query. The checklist also records that stewardship is universal and that the per-repo record only satisfies admission.
- The cut-mapping brief: Imagination edits the model page whenever a probe changes a row. The faculty table and the same-day sweep line now name the model page.
2026-09-22: the hand-written mutation harness is retired, with no fallback
The operator said: "The manual mutation testing turned out to be a terrible idea, lots of guarding the shape of the code instead of the behavior. Better to have nothing than a harness that punishes refactoring." Asked whether a fallback should remain for code no ecosystem tool reaches, the operator chose to retire it entirely: "absolutely".
Evidence from the same day, beyond Aetheria's:
- The Huginn, Epiphany-leaf, Idunn and QUIC campaigns spent pass after pass re-anchoring suites after refactors and rewriting entries that could no longer fail.
- The harness itself was repaired four times: H1, F1/F2, the case-blind guard, and Linux quoting.
- The QUIC timeout rule took seven Soul passes of anchor mutants. It closed only when a behavioural seam made the rule observable by exact equality, which is the defence that survives a refactor.
What changed:
tools/eureka-mutations.ps1is deleted (Eureka37c80e4).- SKILL.md and briefs.md no longer name a fallback. Where no tool reaches, the defence is behavioural: observe the rule where it is decided.
- Soul's hand mutants are one-off probes on scratch copies, never committed. The entry below, "hand mutations target the rule's layer", now governs exactly those probes.
- The stopgap copies no harness into the container. Its Rust image carries cargo-mutants instead of pwsh, and the image is tagged by the Dockerfile's hash so an edit rebuilds it.
- The committed suites in Huginn, the Epiphany leaf, Idunn and CultLib are deleted in their own repos. The tests those suites pointed at stay.
2026-09-23: brief Soul's closing pass for a walk-through
Evidence: Ghostlight's play agent pass ran sixteen Soul passes on invariants and promises. The seventeenth was briefed differently — not only "did the cut hold" but "what happens when a person sits down and plays this" — and it returned the two most useful defects of the pipeline, neither of which any invariant covered: a card that goes blank for the length of a turn, and a restart that leaves the player at a dead end whose only exit is submitting an empty message. A closing pass gets that brief, and it names what the operator should do first.
2026-09-23: a stale subtraction ledger is not pressure
Evidence: the same pass met its subtraction budget once, at the cut that deleted the old drivers, and never revisited it. Sixteen cuts later every fix batch had been net additive and nobody had looked; the miss surfaced in the postmortem rather than in a cut. Self reconciles the ledger at each cut's landing, or it stops being a budget and becomes a sentence in an old document.
2026-09-23: name the inference, not the line
Evidence: Ghostlight's play agent pass carried one defect shape through five
instances, each fixed only where it was reported. A committed dist/ file
existed, therefore the client bridge worked (PA.f176). git rev-parse exited
zero, therefore the directory was a checkout — git had walked up to the parent
repo (PA.f193-C). A canonical-form check failed, therefore the row was
unreadable, so a readable save was destroyed (PA.f193-B). A schema id was
unrecognised, therefore the row could not be read, with no decode attempted
(PA.f194-A). Cargo printed ok, therefore the fixture was live — the test was
#[ignore]d and never ran (PA.f194-B). Each local fact was true and each
inference was false. The last one lived in a runbook: making a silent skip
visible inside cargo's summary moved the same silent green up into the
operator's weekly command, where nothing in the suite could see it.
2026-09-22: a test's inputs come from production
Evidence: Ghostlight's play agent 8a-fix3 (754c7fe) ruled that the DM agent
dispatches Personas by the id its world view prints. Every test built that id
from a test-local copy of the printer, so changing what the view printed left
all 735 tests green while every dispatch an agent could make was refused.
There were four copies of one spelling, because the library's printer was
private to its module.
2026-09-22: hand mutations target the rule's layer
Evidence: in Ghostlight's play agent 8a-fix2 (74b628d), Hands reported every
mutation killed, yet Soul found eight rules unguarded. Hands had deleted the
in-memory record_call instead of the on-disk persist-before-submit, which
a later persist then hid. It tested find_handle_collision directly rather
than its call in round_tools, and every test used fresh keys, so
turn_id = hash(key) survived. The Hands brief now says to mutate the
production call site and to observe the result where it lands.
2026-09-22: mutation testing moves to the ecosystem's tools
Evidence: Aetheria's fire-control campaign carried 23 hand-written harnesses
(5,816 lines) of literal-text anchors and substitutions. They stranded on
every refactor (72c0109c, Cuts 9 and 10), and at Cut 10 an anchor kept
matching exactly once while silently re-targeting from HitProbability onto
Inspect, mutating code the tests no longer ran, and it surfaced only as
unexplained survivors. Soul's audit of the
harnesses also found the tree-clean verdict restoring before it measured, and
a compile failure counted as a kill. The operator: "What is the point of those
mutation anchors? Tests should cover how the code behaves, not how it is
shaped."
A Stryker.NET spike over one file killed every mutant the harnesses defended and found 67 survivors they did not, among them a flipped sign in the splash handedness that no test defended: the same class as a wrong-side-damage bug the operator had once spent hours hunting in legacy code, though the rewrite had not shipped it. Three rounds of tests and fixture fixes took it to 43, all named.
- The principle of 2026-09-15 stays: every rule has a test that fails when it breaks.
- The committed-anchor-script mandate is replaced: Hands and Soul run the
ecosystem's tool on the cut's diff and triage survivors by name.
eureka-mutations.ps1is demoted to the fallback for code no tool reaches. - Float boundary flips are equivalent by default (operator: "> to >= on float thresholds is indeed petty"); the score is not a gate.
- The harness-hardening entries below (H1, F2, the case-blind guard, the CRLF anchor) remain the record of why the fallback's contract is what it is.
2026-09-22: verification moves off the operator's workstation
Evidence: Starfire went from fine to unresponsive in seconds, and the operator had to force a shutdown. It was carrying four jobs at once:
- 16
nodeCPU burners at twice the CPU count. They were started for a QUIC stress run that Self's own rulings demanded. Git Bash's$!recorded MSYS PIDs, and the burners were very likely never stopped. - A 30-iteration
dotnet testloop. - A Huginn workspace build.
- Two agents waiting on jobs that had already died.
No single fork bomb was proven, because Windows audits no process creation. The load was Self's to schedule and Self did not budget it. The operator: "This is literally why we have Yggdrasil, so Starfire doesn't get overloaded with compiler jobs." The fleet inventory already said the same.
-
Ruled by the operator: Idunn owns verification, through a verify transaction that seals nothing and sits outside the brake. It is mapped as its own campaign.
-
The stopgap until then is
tools/stopgap/ygg-verify.shplusrust.Dockerfile. It pushes an exact revision to a mirror on Yggdrasil and runs the command in a container capped at 6 CPUs and 16 GiB, niced, with at most two jobs at once. The target directory stays inside the scratch work tree. Its header names its deletion line. -
Correction, same day, found by a Mind Steward pass: the caps above are not what shipped.
ygg-verify.shdefaults to 4 CPUs, 12 GiB and 3 slots — the slot raise was the operator's ("the other cores are mostly sitting idle") and is recorded in the script's header; the 6/16 figure is not, and I cannot say from here whether it was ever live or was written from a plan I then retuned without a line. SKILL.md carried the stale "2 jobs" until this pass caught it. The script is the owner of these numbers. Prose that restates a running tool's configuration goes stale silently, which is how three surfaces came to disagree inside one day. -
The smoke test found two bugs in the stopgap before any real job ran:
bash -lcreset the image'sPATH.sshre-split the command, soa && branbon the host.
Arguments are now quoted with
printf %q. After the fix, Huginn's mind suite passed 67/67 on Yggdrasil. -
SKILL.md: heavy verification goes to Yggdrasil. Starfire does only Windows-bound work, one job at a time, with no burners.
2026-09-22: H1's kept sidecar looked like a crash, overwrites clobbered each other, case-blind no-op guard
Evidence: Soul's H14 pass over the Huginn memory-organ campaign
(soul-h14-notes.md, findings C and D) found two defects in the sidecar
machinery the 2026-09-22 H1 fix (below) had just added, plus a third,
unrelated defect in the no-op guard.
F1: startup repair mistook H1's deliberate stop for a crash. H1 keeps a
target's sidecar on purpose when it catches an edit the harness did not make
(Assert-TargetUnedited), so the M0 original survives beside the lost edit.
Startup repair could not tell that kept sidecar apart from a crash's: on the
next run it restored the M0 original over whatever an operator had since
hand-cleaned into the target, moved the operator's clean file to
.eureka-mutation-overwritten (clobbering H1's own copy there, see F2),
printed "a previous run died mid-mutation", and finished green. The hand
edit was gone one run later with no non-zero exit to notice it by.
Assert-TargetUnedited now writes a marker, <target>.eureka-h1-stopped,
beside a sidecar it keeps; startup repair refuses the whole pass while any
such marker exists, restores nothing, and names what to reconcile. An
operator clears the marker by hand once the file is reconciled. Demonstrated
in a scratch repo: before the fix, a hand-cleaned target was silently
reverted and the rerun exited 0; after, the rerun refused with a named
non-zero exit and the target was untouched.
F2: .eureka-mutation-overwritten was overwritten without a check. Both
the sites that preserve bytes about to be lost (Assert-TargetUnedited and
the startup repair loop) wrote to a fixed name, so a second loss against the
same target, or a file already sitting at that name, was silently destroyed.
Get-UniqueOverwrittenPath now picks the first unused name in the family
(.eureka-mutation-overwritten, then .1, .2, ...). Demonstrated: a
planted file at that path survived an H1 firing, with the new loss landing
at .eureka-mutation-overwritten.1 beside it.
Case-blind no-op guard. The check that rejects a mutation whose old and
new text come out identical used PowerShell's -eq, which is
case-insensitive, so a mutant differing from the source only in case (such
as "query" to "Query") was wrongly refused as a no-op. Every hash
comparison in the script had the same latent gap. Both were switched to
-ceq/-cne (eight sites total); anchor matching already used ordinal
IndexOf and needed no change. Demonstrated: a case-only mutation was
refused before the fix and ran (and was killed by its test) after.
All three fixed and demonstrated in tools/eureka-mutations.ps1; commits
6ec92de (F2), 5ac4fea (F1), 42adfb0 (case).
2026-09-22: the harness silently discarded an edit made while a run was in flight (H1)
Evidence: Soul's pass on the Huginn memory-organ Cut 10 fourth fix batch
(2026-09-22) found that eureka-mutations.ps1 never checked what a target's
bytes actually were before restoring over them or before the next entry wrote
its mutant. That same campaign's fourth fix batch had lost edits Hands made to
a target this way; the harness gave no warning and no non-zero exit at the
time, so the loss surfaced only later.
Restore-Targets (:163-182) now hashes the target's current bytes first: a
match against the M0 original or, when supplied, the exact mutant the caller
just wrote, is restored as before; anything else is saved beside the target as
<target>.eureka-mutation-overwritten, printed as a loud EDIT LOST warning,
and the run stops (non-zero exit, no further entries) via the new
Assert-TargetUnedited. The same check runs again before each entry writes
its own mutant, so an edit landing between two entries is caught before it is
silently buried under the next one.
Demonstrated in the scratchpad with a throwaway repo whose test command
appends a line to the target mid-run: against the pre-fix script the run
reported green and the target came back pristine, the appended line gone;
against the fixed script the run failed loudly with EDIT LOST, exit code 1,
and the target still carried the appended line afterward.
2026-09-22: a cleanup by image name killed the whole machine's Node
Evidence: during the QUIC seventh fix batch's Windows stress round, Hands
cleared its busy-loop burners with taskkill //IM node.exe //T. That kills
every node.exe on the host, and the workstation is shared by several agents
and the operator. The kill can't be undone, and nothing records what it took
down. Rule added to SKILL.md's tooling list: kill by the PID you started.
2026-09-22: seven passes on one line, because the observation was outside
Evidence: the QUIC bridge's rule "the wait is the timeout the host asked for". It took seven Soul passes and six fix batches.
- Every batch killed the mutants the previous Soul had named: a constant, then any constant, then a clamp, an offset and a scale. Then a round clamp, a floor and a small offset. Then a quantum round-down, a small-timeout zero and a later-poll doubling.
- Each time, the next Soul found another function of the argument that equals the identity at every probe point.
- Tolerances tightened until Windows needed a priority raise just to keep the unmutated bridge green. Even then, two of the stated boundaries flipped between repetitions.
Wall-clock observation from outside cannot converge on an arithmetic rule. There is always another function that matches at the probes, and the tolerance can only shrink until the scheduler decides the answer. The fix was to observe at the rule itself: a dev-only seam records the timeout actually handed to the condition wait, and exact equality kills the whole family at once, deterministically.
The skill already said "put the observation where the rule is decided". What was missing was knowing when to stop probing. Added to Self's triage:
- When a second fix batch for the same rule is killed by mutants of the same family, change the observation, not the probes. Name the layer where the rule is decided and observe there. Keep wall-clock checks only as proof the decision is actually carried out, with generous margins.
2026-09-22: a ruling recorded in one section, contradicted in another
Evidence: the selection map recorded Q-J (decimal strings) as ruled in §16.
§2, the vocabulary Hands actually builds from, still said number: float64?.
D8 said NumberOf -> double?. Nothing specified the canonical form or the
comparison that the ruling had asked for. Commit 1 shipped float64 to the
branch. The Rust Hands found the conflict before writing a line, and stopped.
- SKILL.md already says to sweep the map for the old version of a design on the same day a ruling changes it. Self did not do the sweep. The rule was fine. Self's compliance with it failed.
- A ruling that says "the cut must specify X" is not landed until X is specified in the section Hands reads. Recording the ruling is not specifying it.
Same evening: two Sonnet Hands stopped early with no fork, one of them after fourteen tool calls. Both cited budget. Both had been told to read a 1,500-line map rather than given their cut inline, which breaks the template's "carry the cut inline". The template's hand-back clause is now qualified: it applies when context is actually filling, not when scope looks large.
2026-09-22: a shared cargo target can run another checkout's mutant
Evidence: Soul, working on the Huginn Cut 10 second fix batch, had two worktrees
of the same repository. Both built into C:\Users\Meta\.cargo-target-codex, and
both produced the same artifact name, huginn_daemon-e1f33b5708db9f04.exe.
A plain cargo test in the second worktree did not rebuild, because its sources
were older than that binary. It ran the first worktree's last harness mutant
instead: 40 runs out of 40 failed at the mutant's assert line, not at the
source's.
- The case that does damage is the reverse. A surviving mutant's binary makes an unmutated tree look green.
- The harness is immune, because every write it makes, M0's included, bumps the file's modification time. A plain test run in a second checkout gets no such protection.
- Rule, in SKILL.md's git and tooling list: a shared build output directory belongs to one checkout per repository. Any second checkout gets its own target subdirectory.
The same evening, Self briefed four agents freehand, and none of the briefs carried the template's wait paragraph. That breaks the 2026-09-17 rule below. Self sent the paragraph to the three agents that could still act on it. The rule stands. What failed was Self's own compliance with it.
2026-09-17: Self's own briefs dropped the template's wait rule
Evidence: in the Aetheria item-provenance session, two Hands passes (the Cut C census follow-up and the neutral wanderers and IFF patch) ended their turns while a mutation run was still in the background. Each had to be resumed to finish, push and clean up.
- The Hands template in
briefs.mdalready says a wait is a foreground poll, and that a detached job cannot wake an agent whose turn has ended. - Self wrote those briefs freehand and left that paragraph out. The defect was in Self's briefing, not in the template.
- Rule: when Self briefs Hands or Soul without pasting the template, it still carries the template's wait paragraph verbatim.
2026-09-17: three passes to pin one line, because each proved a cousin
Evidence: the QUIC bridge's "the wait is the timeout the host asked for", over three Soul passes and three fix batches in one day. Each fix was real, and each proved a property slightly stronger than the last and still weaker than the rule.
- The committed entry proved the wait was not one particular constant. It died only because one millisecond is less than a fifty-millisecond settle. A different constant, two seconds, walked the whole matrix on both targets: a host asking for five seconds would silently get two, forever.
- The fix proved the wait was not any constant, with a scenario measuring elapsed time at two values whose tolerance bands do not overlap. Sound as far as it goes.
- Soul then defeated it with a clamp, and with an offset and a scale beside it, all three surviving every scenario. Capping a wait so that shutdown gets noticed is the most ordinary spelling that line will ever be given, and it is a function of the argument rather than a replacement for it. Any mapping that is identity at both probe values passes for free, and both probes sat below any plausible ceiling.
Added to the Hands brief: name the weakest thing that would still pass and ask whether it is the rule; when a rule says a value is derived from an input, at least one mutant must itself be a function of that input, and probe values must sit where such a function would show. Constants are never the hard case, only the first one.
The same pass found that a fresh Windows clone could not run the documented
Linux path at all: .gitattributes carried no line-ending rule for shell
scripts, so the container died complaining about a carriage return in the
interpreter line. Worth noting as a shape rather than a one-off: the path was
declared runnable-as-committed and verified by an agent who had never cloned it
fresh.
2026-09-17: both honest gaps were wrong, and one probe was blind by design
Evidence: two Soul passes on the same day, in different repositories, each falsifying a gap that Hands had recorded honestly rather than faking.
The daemon arm. Hands wrote that the open-items dispatch arm could carry no mutation entry, because it raises no refusal of its own and its only failing paths need a corrupt store, and said so in the entries header rather than substituting an easier target. That was the discipline working. Soul then built a store-integrity probe from the crate's own public surface and killed both the swallowing and the rewrapping mutant, neither of which the shipped suite caught.
The bridge rule. Hands wrote that popping before copying was unreachable without a listener, a credential and a connection. A client opening to a closed loopback port reaches it in about a millisecond, in fifteen lines, because the failure path always publishes a non-empty reason; and the mutant crashes an ordinary optimised build twice out of two while both committed scenarios stay green on that same binary.
So an unreachability claim is a hypothesis, and the same pass that would falsify a promise must falsify it. Recorded in the Soul section: write the gap as not yet reached, never as unreachable, and open the next brief with reaching it. A rule written off as undefendable that is merely undefended is worse than a surviving mutant, because the suite and the prose agree and both are wrong.
The blind spot. The same pass found why a rule kept being pinned by constants: the scenario held its callers after the wait whose duration was the rule, so every timeout mutant landed behind the observation. Replacing a caller's timeout with a hard-coded two seconds survived the entire committed matrix on both targets; a host asking for five seconds would silently get two forever. The committed entry that appeared to defend the rule died only because one millisecond is less than a fifty-millisecond settle. Added: put the observation where the rule is decided, and when a mutant dies, ask which of the two things it actually contradicted.
Also added, from the same pass: never use git archive to export source for a
byte comparison, after an export carried 1,459 inserted carriage returns.
2026-09-16: a green suite is not evidence when its harness is gone
Evidence: two findings from the same afternoon, both about mutation suites reporting coverage they did not have.
The harness that no longer exists. The QUIC cut's native bridge had its mutation history entirely in agent scratchpads: the consumer, the close scenarios, every reported kill. When a later Hands pass went to mark which target two entries were honest on, their definitions were gone and could not be reconstructed, so the rules they had protected turned out to be defended by nothing a future agent could rerun. Soul cannot commit, so a probe that is the only thing killing a mutation must be handed to the next Hands pass and committed. Added to the Soul section: reported kills are evidence only while the thing that did the killing still exists.
The loosening swapped for an easier target. Cut 10 of the pipeline-state campaign reported 31 of 31 entries killed. Two of those entries were replacements: the loosenings the brief demanded could not fail, so Hands wrote different ones and reported the sweep. Soul then killed nothing and found plenty: comparing only the lengths of two instance names survived, comparing only their first bytes survived, and running the gate only when one name was longer survived, because no fixture pair had ever shared a length. The rule was undefended while the suite claimed two mutants for it. Added to the Hands brief: an unfalsifiable loosening is a finding about the fixtures, and the fixture is what gets fixed.
2026-09-16: front-load the invariant layer, thin the spelling layer
Evidence: the operator's read of the Eureka pipeline-state campaign, that the design kept being discovered as the work went, producing re-cutting and repeated Imagination passes with no good reason for the map to diverge that far. The campaign's own record agrees, and says which layer was at fault. Every backtrack was identity, lifecycle or authority, and every one was answerable before a line of source was read:
- The repo-owned store was specified before anyone asked who owns a mind, and died whole in Cut 4: 1,302 lines deleted.
- The key grammar was patched twice and redesigned on the third occurrence, because ids had no namespace to be specified over.
- Cut 6d retrofitted sequences into landed keys, because each document's shape was specified and its life was not.
- The operator's forks surfaced across five cuts, so rulings kept landing on code that was already written. Two of them reversed defaults the agents had already implemented.
None of that was a shortfall of file:line detail. The maps had plenty:
Cut 10's section ran to roughly eight hundred lines against a crate that did
not exist. The operator named the trap for what it is, a 1:1 map, where the
only sufficient spec is the code.
- Added step 0b. A model table before any cut is mapped, a row per persistent kind, three columns: what names it, what happens to it over time, who decides. No cut is mapped while a cell is empty. Operator forks are assembled in the same pass as one batch.
- Added the model-page brief to
briefs.md, before the cut-mapping brief. An empty cell is the finding; inventing a plausible value is the failure. - Qualified the per-file anchors. They are required for code that exists, where they say what to delete and what not to touch. For code that does not exist, name the types, the boundaries and the rules that must die under their own mutation, then stop.
- Stated what cutting faster means: less prose per cut, never more code per cut. Small commits stay small.
Not treated as waste: the operator changing their mind. Learning that the intent differs is the job. It is only expensive when it is learned after the code lands, which is an argument for surfacing forks earlier rather than for mapping deeper.
2026-09-16: the loop was burning tokens on gaps, not defects
Evidence: one day of the Eureka pipeline-state and TypeScript QUIC campaigns, about thirty-five passes. The operator asked how much of the cost was process and how much the price of a second agent. Roughly half each. The falsifier earned its half: three High key defects, an unimplemented epoch gate, a replay regression, a byte-order mark divergence and a false "equivalent" claim, none of which a green report caught. The other half:
- Hands wrote revert mutations; Soul wrote loosenings. Most second and third Soul passes found not defects but rules the suite was blind to. The Hands brief now requires both mutations per rule, and Soul reruns Hands' loosenings before writing its own.
- Reports were narrative. Soul passes ran two to three hundred thousand tokens each. Both briefs now name the report shape and forbid the rest, and a second pass on a cut is scoped to the fix batch's diff.
- Two harnesses re-learned each other's lessons. Epiphany's PowerShell harness and CultLib's JavaScript runner each hit the sidecar footgun, the missing control and a control-byte scar on their own. One harness in this repo is the next change; deferring it to a "skill wiring" cut cost three rediscoveries in an afternoon.
- The map committed per event, about forty times in a day. Per cut from now on, rulings excepted, since agents read them mid-flight.
2026-09-16: agents must be told how to wait, not only to wait
Evidence: Ghostlight L1, the stock lenses
(docs/architecture/ghostlight-stock-lenses-cut.md and its postmortem).
- "Wait for long jobs" was not enough. Three agents in one campaign ended
their turns while a build they had started was still running: a Soul pass
on Cut 1 and a Hands pass on Cut 2, twice. Each launched cargo detached,
then ended the turn "to wait". A detached process is not a tracked
child of the agent, so its completion never woke it; the work stopped until
the root agent resumed it by hand. The rule to wait was already in the
briefs. What worked was naming the mechanism: block inside a tool call,
with cargo in the foreground under a long tool timeout, or
Wait-Processon the pid, and never start a second cargo run while one holds the target lock. After that sentence entered the briefs, no agent stalled again. - A green test can be a coin flip. A Cut 3 test that rewrote a session's lens to a fixed value collided with a randomly drawn lens about one run in eight; Hands' single green run was luck. It failed 3 of 40 looped runs and passed 120 of 120 after a deterministic fix. For any test built on a random draw or a random identity, looping it is part of verification.
- An operator question can hide the design fault. Self told the operator a lens "has to be recorded" in the command identity. The planner then found that keying identity on mutable weights strands rows, and the operator's follow-up ("are you relying on some deterministic code outputting the same id rather than just checking the state?") exposed a pre-existing defect: the elaborator's repair loop had never worked across sweeps. When the operator asks why a mechanism works, answer from the Body and probe it; it may be the most valuable question of the campaign.
2026-09-16: a mutation suite needs a no-op control and byte-exact I/O
Evidence: the Eureka pipeline-state campaign's third Soul pass on Cut 6, and the
Eyes audit that followed (Epiphany notes/eureka-pipeline-state-cut.md, "Mutation
harness audit").
- A no-op control is the test of the harness. Soul ran a mutation that
changed nothing and it killed
bounds_refuse_in_utf8_bytes. The harness's text round-trip had collapsed anéliteral to one byte, so the corruption alone failed the test and every mutation through that path would have reported a kill. Nothing else in the loop could have noticed: a killed mutation is what a working suite looks like. - The defect was not where it was feared. The audit found every committed suite using byte-lossless I/O. The corrupting harness was Soul's own inline script, never written to disk, so its text is unrecoverable and its verdicts are unverifiable. That is the same shape as the standing finding that mutations without artifacts cannot be checked; it now applies to Soul too.
- Encoding symmetry and line endings, not a flag. Measured on the host:
mixed-encoding round-trips corrupt non-ASCII; any read that splits lines
rewrites every line ending regardless of encoding, and
core.autocrlfhides the rewrite fromgit diff. One ad-hoc Cut 1 script did exactly that, so three early verdicts are recorded as suspect. - The committed suites forbade a control by shape. Each threw when a replacement changed nothing. A table shape that cannot express "change nothing" cannot test itself.
- Soul brief: wait for long jobs. The Hands brief had this rule since the Ghostlight run; the Soul brief did not, and two consecutive Soul passes on Cut 6b ended their turn with "waiting on the script" and had to be resumed by Self before any finding arrived.
- "Default model" means the root's model. After the operator switched the root session to Fable, every Hands and steward dispatched without an explicit model inherited Fable, against the skill's own allocation. The operator noticed. Self now names the model on every dispatch: the strong model for Imagination and for Soul on foundation cuts, the default tier by name for Hands, Eyes, probes and stewards.
- "Wait" now names the mechanism. A Hands pass with the rule in its brief still ended its turn on "waiting on the suite", the third such yield in one day. The rule said what, not how; an agent that starts a detached job reads "wait" as "stop and be woken", and nothing wakes it. Both briefs now say: a foreground poll loop you run yourself, in chunks under the tool timeout, until the job exits.
2026-09-16: record the gap, and absence is the hardest claim
Evidence: ghostlight-77's requirements message to the Eureka pipeline-state
campaign, drawn from Ghostlight docs/architecture/ghostlight-library-extraction-cut.md
and its postmortem. Both rules come from the same run as the entry below.
- Record the substrate you needed and did not have. That campaign hit the missing typed-state primitive six separate ways — supersession tracked in "(supersedes …)" prose and fixed by substring surgery, an "Open:" question line hand-edited about eight times, three ad-hoc finding namespaces, verdicts linked to nothing, a subtraction ledger reconciled only at close-out where it showed a +65 → +210 overrun, and a status header rewritten by hand at every landing. Each workaround worked, so each requirement nearly evaporated. The agent named this itself: the failure was working around the gap silently rather than flagging it while hitting it. A run that hits one gap six times is the best requirements evidence a design will ever get, and it survives only if someone writes it down while it hurts. Working around the gap is still correct — doctrine says do not wait on a service that does not exist — but leave the evidence.
- Proving something is gone is the claim most likely to be wrong. A Mind Steward reported a stale phrase retired because a line break had split it from its grep. The phrase was still there, still steering. A verification that cannot see its own target reports a clean pass, which is worse than no verification: it closes the question. Prose reflows, so an exact search over it is a tripwire with the same limits as any other text scanner — the scanner rule below is not only about code.
2026-09-16: sealing, forgeries, scanners and proportion, from Ghostlight L0
Evidence: Ghostlight docs/architecture/ghostlight-library-extraction-postmortem.md
and its cut map.
- Soul attacks constructibility, not names. Ruling Q1-4 said sealed
constructors must be unreachable. Ten compile_fail doc-tests passed while
every public ID type derived
Deserialize, so an external crate built any of them from JSON; an ID-mintingDefaultimpl left all ten green. It was found only because Self added the serde route to the Soul brief by hand. On stable rustc the compile_fail error codes are not enforced either. - Rejection tests need realistic forgeries. Short fake digests passed against kernels comparing only length, a prefix, all but the last character, case-insensitively, or only the hex after the label. Five mutants survived across two Soul passes.
- Text scanners are tripwires. Every one written in the campaign lost to a
short evasion: a single-minter count to an alias, a subdirectory, a type
alias and a function value; a deploy wiring test to a two-line deletion that
reattached the pinned line to the wrong container, and its fix to
if falsearound exact lines. Prefer a semantic tool, or state the limits. - Default proportionate forks. Asked how much the single-minter enforcement question mattered, the operator said not at all. A fork that guards only against the project's own code is a default plus a recorded follow-up.
- Hands brief additions: wait for long jobs instead of reporting a to-do
list (one Hands agent did); restore mutations without
git checkout(one run was invalidated that way); measure warnings from forced rebuilds (a cached build reported zero).
2026-09-16: subtraction rules, from the Eureka campaign's own cuts
- A deletion can take a live rule's only test with it. Cut 4 deleted a store
module; the epoch guard that survived in another file then passed a
if falsemutation, and nothing could construct the state needed to reach it. The fix was to delete the unreachable rule too, not to write a test for state nothing can build. - A mutation that never applied is not a passing mutation. A multi-line
anchor matched nothing on a CRLF working tree. Scripts must fail loudly on a
stale anchor, and should also assert the anchor matches exactly once, since a
multi-site replace can read as "killed" when its test failed for another
reason.
- Correction, same day. Self first recorded this as "one mutation reported a verdict it never earned". Soul checked the committed history: the script already threw on a missing anchor, the affected mutation existed only in Hands' working copy, and every committed verdict was real. The rule stands; the incident was narrower than first written.
2026-09-16: an instance owns its mind, and a service owns the state
Operator correction, mid-campaign, after three Soul passes spent propping up a repo-owned store: "I think someone needs to own Epiphany/Eureka state. Each store should be canonical to one instance, the store is that instance's mind, and that instance can be assigned stewardship over multiple repos."
- The lesson for this skill: when a design needs escalating machinery to hold together (a per-clone lease, git-directory resolution, committed attribute checks, a merge tool), the missing piece is usually an owner, not another guard. Soul kept confirming the guards were weak; the guards were the symptom.
- Mind state does not belong in version control. Git offers branches, merges and history rewriting; a mind wants one owner and an append-only record.
- Eureka's typed state will live in a memory organ service (Huginn) that owns each instance's mind, depends on Qdrant directly, and refuses loudly when unreachable rather than letting a second writer exist.
2026-09-15: the operator channel is the session
Operator ruling. Spec iteration proved to be the load-bearing part of a Eureka run, so the question path matters as much as the cut loop.
- Eureka has no Persona. Self is the operator surface.
- Blocking questions may be pushed through any notification MCP the user configures. Eureka owns no transport, so other people can swap in their own.
- Answering over a chat channel is a later campaign; it needs identity binding before a reply can become a ruling.
- The operator's framing: Epiphany gives each repo an identity, memories and a Persona to talk to; Eureka is "the cut-down Claude-native version anyone can use".
2026-09-15: Hands brief rules from the Eureka pipeline-state campaign
- Define every mutation in the report. Soul could not rerun Hands' Cut 2 mutations "C1-C5" because the report named them without saying what changed.
- "Unchanged" is proven against the base commit. Cut 2 pinned a Mind receipt digest captured from the new code. Soul had to rerun the test at the base commit to show it matched.
- Baseline shared build caches by path list. A Cut 2 Soul pass left about 401 MB in the shared cargo target that it could not attribute. It had recorded only counts, so it did not delete blind.
- Check that a detached script started. A Cut 1 mutation script died on a PowerShell parse error, and its monitor sat silent for 30 minutes.
2026-09-15: renamed to Eureka; postmortem rules folded in
- Rename. The operator named the skill-and-MCP form of the pipeline Eureka. Epiphany stays the name of the running organism, and Eureka keeps the faculty vocabulary.
- Operator observation: typed state. What makes Epiphany special is that findings are stored in typed state that can be queried semantically. Claude agents can be given the same state tools. Eureka's likely next step is to replace doc, report and memory findings with typed state documents (findings, rulings, cuts, Soul verdicts) behind MCP tools.
- Operator observation: Imagination. Eureka's Imagination has a more clearly defined target-mapping role than Epiphany's. Epiphany may want to adopt it.
- Epiphany comparison. A source-grounded model of Epiphany at
71324718is kept asepiphany-comparison-2026-09-15.md. It is a dated snapshot, not live truth. Epiphany's ownnotes/faculty-workflow-lessons-2026-09-04.md:146-176proposes the typed forms of Eureka's habits (Verdict HOLDS/FALSIFIED/UNPROVEN, Rulings, a landed-names digest, steward triggers). Start from those schemas when Eureka gets typed state. - Rules added from the postmortem:
- Soul runs before any release or tag.
- Ask what a domain concept is for before specifying it.
- Carry order as data, not as scheduling.
- Reconcile the subtraction ledger at every landing.
- Count consumers across every project the operator uses, not just one runtime.
2026-09-15: initial formalization
Extracted from the Aetheria CultCache migration (Cuts 0-10, 2026-09-12..15). The
evidence is postmortem-cultcache.md and the Aetheria repo's
docs/cultcache-migration-cut.md.
-
Soul is distinct from Imagination. An operator correction: "Making another pass on the cut map is still Imagination."
-
Target shape finish line: Hands barely reads.
-
Each operator ruling needs its own failing mutation. In Cut 10, Soul removed the availability rule, the price rule and the all-or-nothing fit rule, and all 15 tests still passed.
-
Don't cap Soul early. Cuts 6 and 6b each needed four Soul passes.
-
Git and tooling scars: explicit staging, message files, the 3-tag limit, commit-independent byte checks, detached builds, and the process-probe role check.
-
2026-09-18: the wait rule now names the failure shape, not only the mechanism. Hands ended two turns announcing it would wait for a mutation suite (Aetheria shield Cut 3), the second after an explicit correction. The brief already said how to wait; it did not say that saying "I'll wait" and yielding is the violation. Both copies in
briefs.mdnow do. -
2026-09-18: context is a budget. The operator noticed Sonnet Hands runs passing 400k tokens on Aetheria's stats and shield cuts and said they "start to get loopy with that much context" — matching where the sloppy claims in those runs appeared.
briefs.mdnow tells Self to size cuts to one worker's head: verify once at the end, quote the cut inline instead of pointing at the whole map, keep expensive scaffolding alive across cuts, and hand back a clean partial rather than push through. -
2026-09-22: never amend or force-push a shared branch. In the Ghostlight play-agent pass, a Sonnet Hands agent on Cut 3 amended its pushed kernel commit and force-pushed it (
9fbdde8->4c4973b). Self was pushing cut-map commits to the same branch at the time. Nothing was lost, only because Hands had rebased on those commits first.briefs.mdnow forbids amend and force-push and says to fix with a new commit, and SKILL.md's scars list carries the rule. That run also reached ~400k tokens against a brief that pointed at the whole map, which is the 2026-09-18 context-budget rule showing up again.
2026-09-22: a Hands agent read a five-day-old map, and refused an unsigned instruction
- Maps go on
main. Self had been committing campaign maps to whatever branch it was standing on. A Hands agent on the CultNet selection cut reported that the map carried no fix-batch-4 section — true on the branch it could see, where the copy was from 2026-09-17. It worked from its brief instead and flagged the gap, which is the only reason this surfaced rather than a cut built on stale design. SKILL.md now says maps are committed tomainand that every brief names the map's branch. - The same agent refused an out-of-band instruction, and was right to. Self sent it the Stryker survivor list mid-task through the agent messaging path. It arrived appended after a tool result, claimed to be from "the coordinator", and asked to expand scope well beyond its brief. The agent did not act on it and flagged it for verification instead. The message was genuine. The lesson is not to make the agent more trusting. Scope expansion mid-task should arrive as a new brief with its own dispatch, or be confirmed by Self before the agent acts; an instruction that cannot be distinguished from an injection should be refused whether or not it happens to be real.
2026-09-22: two Hands in one working tree, and the agent that refused to force it
Evidence: Self dispatched a Hands agent for the CultNet selection survivor
tests into F:\Projects\CultLib while another Hands was mid-build in that same
checkout on a different branch. The second agent switched the branch to reach
its own work, which pulled the tree out from under the running build, then
found an uncommitted CMakeLists.txt edit it had not made. It stopped and
reported a concurrency hazard rather than forcing the checkout, which is the
only reason nothing was lost.
The rule against parallel Hands in one working tree was already in SKILL.md. Self ignored it. The fix is not a stronger warning to Hands: Self now creates the worktree before dispatch and names it in the brief, so an agent is never left to find somewhere to stand. A brief that names a repo path without naming a worktree is a defect in the brief.
Second-checkout build output stays separate, per the existing scar: a shared target directory has let an unmutated tree look green.
2026-09-22: a green Windows suite that had never loaded the pinned library
Evidence: the QUIC bridge imports msquic.dll by name. Nothing copied the
pinned library beside the test binary in the build tree. On Linux that failed
loudly with cannot open shared object file. On Windows it did not fail at
all — DLL search fell through to PATH and loaded an unrelated msquic.dll
from the Windows Performance Toolkit, 529 kB against the pinned build's
4.1 MB. Every scenario passed against it with nothing indicating a problem.
The green result was the thing hiding the defect, and it was found only because a brief asked for the documented path to be executed literally rather than for the previous error to be gone.
- A dynamic dependency resolved by name is unproven until its identity is checked. Where a test loads a pinned native library, the verification step reports the loaded file's size or hash, not merely that the run passed. Windows' search order makes silent substitution the default failure mode, where POSIX tends to fail loudly.
- When a defect is found on one platform, check the other for the same class
before closing it. Both Linux fixes lived inside
if(NOT WIN32), so the Windows path was never examined until it was run. - Scope the doubt honestly when this happens. Earlier Windows numbers in that campaign were all measured on the same machine, where the copy never existed, so they are recorded as unconfirmed rather than quietly kept.
2026-09-22: a probe that will be committed must be handed over while it exists
Evidence: Soul's fifth Idunn pass settled resolve()'s fsck on a real
smart-HTTPS rig and Self ruled the rig should be committed, naming Soul's
files. By the time Hands looked, none survived — no session, no Yggdrasil work
directory, no scratch trace. Hands rebuilt the rig from the map's prose, which
worked only because the map described it in detail.
Probes are throwaway by doctrine and that stays true. But the moment Self rules that a probe becomes a committed test, it stops being scratch:
- Self records the rig's mechanism in the map in enough detail to rebuild it, not merely that it passed. That description is what saved this one.
- Better, rule on committing it while the Soul pass is still live, and have Soul hand the files over in its report rather than leaving a path.
2026-09-22: Soul was wrong about a redundancy, and a Hands hand-trace caught it
Evidence: Soul's S5-8 reported four containment checks where one sufficed,
each surviving deletion alone, and Self ruled three of them deleted. Hands
deleted two, hand-traced the third, and found that with all three gone a
symlink whose entire target is ".." at the root resolves to the parent of
the root and returns Ok — a containment escape — because no later Normal
step runs to trip the surviving arm's own check. Hands kept the check, pinned
it with a new test, and recorded the deviation in code.
- "Each survives deletion alone" does not mean "any two survive together." A redundancy finding must be probed at the combination Self intends to delete, not one member at a time. Soul's method was sound and its conclusion did not follow from it.
- A Hands brief must invite this. The rule that a deletion judged unsafe is reported with evidence rather than quietly kept is what produced the catch; it stays in the template, and it applies to deletions Self ordered.
2026-09-22: a wall-clock pin that was really a constant, and the ratio that hid it
Evidence: a Hands test pinned a cost regression with
large < small.max(0.01) * 20.0 and reported a 33x separation. Soul measured
small at 2.7-9.4 ms across eight runs -- always under the 10 ms clamp --
so the clamp always fired and the assertion was simply large < 200 ms. Clean
code had already measured 198.9 ms under three concurrent suites, the normal
load on the shared build host. The true separation was 1.63x; the reported
33x came from one pair straddling the clamp boundary.
- Pin a cost with a count, not a clock. Where a regression is about work done, count the calls through a test-only counter. A count is deterministic under any load; a wall-clock assertion on a host running several jobs fails in both directions, and where a pipeline turns red into a verdict, a false red is a false verdict on unattended work.
- A reported ratio is a claim like any other. Self accepted 33x because it sounded decisive. Ask what the denominator actually was.
2026-09-22: two fixtures that would have lied, caught by mutating not reading
Evidence, one batch:
- A setuid fixture set the bit and then ran
chown. The container'schownsilently clears setuid even when the owner does not change, so the fixture tested nothing and looked like a pass. - An
observe_frozentest tampered with the recipe file, which a different check insideobserve_frozenalso catches. It stayed green with the digest check deleted -- the check it existed to pin.
Both were found by running the mutation against the final spelling of the code, not by reading the test. This is why that step is in the Hands brief, and why "the test passes" is not evidence that it pins anything.
Same batch, the honest outcome: an artifact-digest term could not be pinned at
all, because the collision it prevents needs a NUL inside a symlink target and
symlink(2) cannot produce one. Hands built the fixture, confirmed it did not
go red, and deleted it rather than keep a test that lies about what it
proves. Record the gap; do not keep the ceremony.
2026-09-22: check the tool before ruling that it be configured
Evidence: Self ruled a bind mount should carry nosuid. Docker exposes no
per-bind-mount nosuid through either --mount or -v; both are rejected.
The container already ran with --security-opt no-new-privileges, which is
process-wide and stronger. Hands verified against the real CLI and withdrew
the ruling with evidence.
A ruling that names a flag, option or API is a factual claim about a tool. Check it, or say it is unverified and let Hands confirm before building on it.
2026-09-23: a test's fixture must be the shape production uses
Evidence, from three consecutive Soul passes over one Idunn file and one selection batch:
- Every
digest_artifacttest wrapped its file in a directory so the tree path ran. Production hands that function a bare file, immediately before launch. The fast path was blind to setuid, mode and file capabilities, and no test reached it. One test's doc comment claimed to pin exactly the scenario it never touched. - A row-tiebreak test passed with the tiebreak reverted and swapped, purely because of which real schema hash happened to sort first. It was degenerate for its whole life and looked green.
- An xattr test pinned presence against absence. The thing that carries privilege is the value, and nothing hashed it.
So: write the fixture at the shape production uses, and where that is genuinely impossible, say so in one line in the test. A fixture chosen for convenience produces a green suite over an untested path, which is worse than a gap because it is counted as coverage.
Corollary, from the same passes: a test whose inputs come from real identifiers (hashes, generated ids) can pass by accident of their ordering. Derive the fixture's keys from the ids discovered at runtime, then confirm the test fails when the rule is broken.
2026-09-23: a convention is not an invariant; move it into the compiler
Evidence: a call-counter pin was an honour system, so it was replaced by a
narrow port that charges inside the syscall method. Soul then restored the
original bug in two spellings around the port, with the whole suite green,
and the leak was already in the file — another function still called
fs::read_link directly.
Each round made the convention more elaborate without making it binding.
Where a rule says "all access goes through X", the enforcement belongs in the
build: a disallowed-methods lint, a module boundary, a private type — not a
comment, and not a habit. If the fix is another thing to remember, it is the
same defect one level up.
2026-09-23: concurrent mutation runs do not give reproducible verdicts here
Evidence: the same commit, mutated three times at -j4 on the stopgap's Rust
image, produced different missed and timeout sets each time — one mutant
flipped between missed and caught with no code change — while every -j1 run
reproduced an identical result. The likely cause is the shared
CARGO_TARGET_DIR under concurrent mutant builds, which is the same class as
this file's existing shared-target scar.
- Confirm a survivor list at
-j1before ruling on it. A killed mutant that was genuinely killed stays killed, so a score is roughly usable; a survivor list from a concurrent run cannot be trusted as complete, and survivors are what drive rulings. - This applies to Stryker's
--concurrencyas well. Figures in the Aetheria and CultNet campaigns taken at concurrency 4 are provisional; where they drove a ruling, the ruling stands on the hand-confirmed mutation beside it, not on the count. - Per-mutant build isolation costs wall-clock: roughly triple per mutant at
-j1. Budget for it, and scope the run rather than raising concurrency to make a sweep fit.
2026-09-23: fixtures that satisfy an assertion by coincidence
Three instances inside two days, all green, all proving nothing:
- A row-tiebreak test passed with its rule reverted and swapped, because of which real schema hash happened to sort first.
- A sign-bit mutation survived tests using 1.0 and 2.0, whose bit 0
coincidentally matches their sign bit.
-1.0and-2.0killed it. - Artifact-digest tests wrapped a file in a directory, so they exercised a path production never takes.
The shared cause is a fixture whose values happen to satisfy the assertion for a reason other than the rule. After writing a test, break the rule and watch it fail — that step is what separates these from real coverage, and it is already in the Hands brief. Where a fixture's values come from generated identifiers, derive them at runtime instead of hoping their order cooperates.
2026-09-23: name a tool's absolute path in every brief, every time
Evidence: a Hands brief said "use ygg-verify.sh" without its path, where
earlier briefs had given
C:\Users\Meta\.claude\skills\eureka\tools\stopgap\ygg-verify.sh
in full. The agent searched the obvious repositories, did not find it, and
did the whole batch's verification locally instead — on the operator's
workstation, which the load budget forbids for exactly this work.
It reported the gap plainly rather than claiming the bar was met, and left its branch unpushed so the work would not look merge-ready. That is the right behaviour and it is the only reason the gap was visible.
- Give every tool an absolute path in the brief. A name is a guess; a path is an instruction. Self dropped the path when shortening a brief that had grown long.
- State what to do when a named tool cannot be found: stop and report, do not substitute. A substitution that silently relocates work onto a forbidden host is worse than a stalled batch.
2026-09-23: a redundancy ruling must be probed at the shape that breaks it
Evidence: Self ruled a !member.IsReference guard was duplicate authority and
ordered it deleted, following a Soul finding. Hands verified, concluded the
same, and wrote the premise into the source: "index aliases are unique per
descriptor". Source contradicts it — the uniqueness check groups only
members that have an alias, so a plain data member's bare name shares the
role namespace unchecked. A legal document shape then took every hop path into
an untyped exception, which the batch's own new backstop swallowed silently.
This is the second redundancy ruling in this campaign to be wrong. The first, in Idunn, was caught by Hands hand-tracing before deleting. This one was not, because both Self and Hands reasoned from the same property and neither constructed the shape that would break it.
- Before deleting a guard as redundant, build the input that would need it and show the other authority handling it. An argument from a property is not evidence; the property is what is in question.
- A guard that filters by kind is not duplicate authority merely because a downstream owner also filters. Ask what each one protects.
2026-09-23: a pipeline that never runs the whole path has not finished
Evidence: Ghostlight's play-agent pass ended with Soul judging "the bar is met" across 17 cuts and ~196 findings. The first person to press a button then found about twenty more defects in one day, one per step of the real path: sign-in, Heimdall discovery, receipts, the Idunn v2 recipe, binding, runtime bundle, PID namespace, presence races, lease wait, Odin readiness, the browser return, the completion request, session expiry, the model watchdog. Almost every one was a consumer restating its own picture of a neighbour (a strict struct, a fixture, a hand-built request, an old contract) and tests that could only agree with their author. The deploy path itself had been written three weeks before the capability it deployed and no cut map ever named it.
- A capability cut names its deploy owner. Any cut that adds or changes what a service needs (transport, env, dependency, state) names the recipe, binding and runbook that must admit it, and those change in the same pass.
- Prove each seam against the real counterpart, both directions. A fixture copied from our own struct proves nothing about the owner's document; build fixtures from the owner's code or published schema, and make the default fixture differ from our assumption where the owner's does.
- Run the whole path before calling a pass done: the deploy through the real deployer, sign-in with a real identity, one real turn. A green suite on the author's platform is not that; run the target platform's suite before handing a build to the gate.
- Every refusal must be visible to the operator. A silent denial cost hours of reverse-engineering from byte counts.
2026-09-24: quota, oversized fix batches, and greens that ran nothing
Evidence from the StreamPixels transport campaign (Cuts E and F, merged in
StreamPixels 2d4215c):
- Quota. Partway through 2026-09-23, the operator flagged that 60% of the weekly quota had gone in one day, with little of it on the StreamPixels path, and redirected all work there ("We need that TO EAT"). SKILL.md section 5 now says that quota is spent through scope: one full Soul gate per cut, fix batches only for findings on the critical path, and narrow Sonnet passes for small deltas.
- Oversized fix batches. One brief packed about ten items, a subtraction,
two hosts and a late addition. It ran to about 800k tokens over 2.6 hours.
Another batch passed 550k and produced sloppy code. After batches were split
per file, they stayed at about 200-400k. This is the 2026-09-18 context
budget rule again.
briefs.mdnow says to use one fix batch per file. - Greens that ran nothing. A zero-match
node --testglob exited 0. vitest discovered zero tests under a script's--dir .(cc71ce2).pnpm --filter X test -- <files>did not filter (4624b53). A job-wideDATABASE_URLwould have switched unrelated suites onto Postgres (e019de0).briefs.mdnow requires a non-zero count for each named file. - "Pre-existing" was used as a verdict. Several agents waved a failing test
through as pre-existing. It had never passed on a clean checkout, because it
read a git-ignored, licensed asset pack (
27053f9). A transient Windows file lock was also called pre-existing, because the base commit was tested under the same lock.briefs.mdnow asks for a one-line cause for every failure, including ones that are not yours. - An agent waited forever on a hung job. The fix went into the owner:
ygg-verify.shgot a watchdog (9359e9c), and then the watchdog'ssleepwas stopped from holding a slot lock through an inherited file descriptor (dbe594e). The commits and the script header record the details.
2026-09-25: Self sizes each cut against Hands' context budget
Operator direction, 2026-09-25: Self should spend real attention on inference spend, mainly by making cuts smaller so each Hands agent carries less context. Hands runs often grow past about 0.5M tokens, which is where Sonnet starts behaving badly. The operator's reading of the 2026-09-23 quota spend (about 60% of a week in one day; the 2026-09-24 entry above) is that it was legitimate work; the regret was running it on a more expensive, more verbose model just as Opus 5.5 released. Model choice already has an owner in Self's discipline ("name the model on every dispatch"); this entry is about context.
The context-budget rule of 2026-09-18 said "Self sizes a cut to fit one worker's head" but named no number, and it lived inside the Hands brief template, which is text Self sends to Hands rather than a decision Self makes before sending it. So did "one fix batch per file", which is also Self's call.
- SKILL.md step 3 now owns cut sizing: Self estimates the brief, the source Hands must read, one verification and one fix round, and the item count, against a 0.5M danger line, and splits when the estimate passes about half of it. It compares the reported token total with the estimate afterwards.
briefs.md: the Hands template keeps the Hands-facing clauses and points at step 3; "one fix batch per file" moved out of it into step 3. The Imagination template's split clause names the budget as a placeholder Self fills in.- SKILL.md section 5 no longer describes the 2026-09-23 spend as misplaced.
2026-09-25: the Mind Steward faculty is renamed Life
Operator ruling, 2026-09-25. In Epiphany and Aquarium the organ is called Life
(role id reorientation; Aquarium
docs/epiphany-agent-sdf-visual-language.md, section "Life"): continuity,
pressure, reorientation, resume and regather posture, and memory survival. The
operator: Life is "a much better fit as the actual load-bearing organ." The
public landing page in eureka-site already calls it Life.
- SKILL.md (frontmatter, faculty table, dispatch lines, step 6, model
allocation), README.md and
briefs.mdnow say Life. - The role is unchanged: Life still does what the Mind Steward did, memory hygiene at phase boundaries. Any wider scope is a separate ruling.
- Dated records keep the old name where it is what happened: the entries in this file, and the 2026-09-15 Epiphany comparison, which gains a note that its faculty names are as of that date. The CultCache postmortem's agent count reads "Life passes (then called Mind Stewards)".
- The operator owns the dispatch mechanics: global doctrine's "Agent Mind
Stewardship" section and the
mind-stewardagent definition still use the old name. SKILL.md defers to doctrine for the agent type instead of naming it, so it stays correct whichever name doctrine settles on.
2026-09-25: split authority is a defect by itself
In Aetheria fire control Cut 12.3, the operator ruled that multi-cell items absorb proportionally across lanes. Hands then built a survey that sent each shot down either the old sequential walk or a new pooled walk, depending on whether any item was shared. Self's Soul brief asked whether the two paths could disagree, which treated the split as acceptable as long as they agreed. The operator: "Do not expect items taking up multiple cells to be an exception, this should be one code path", and "such obviously unnecessary split authority should never pass a Soul pass."
- The Hands brief template gains "one rule, one path": a simpler case runs through the general path, and a second path is reported, never built.
- The Soul template's split-authority line now says two paths deciding one rule are CONFIRMED on sight, and that the pass names the single path instead of testing equivalence.
- The root cause was Self's own map wording, "with no shared item it equals sequential absorption exactly", which read as permission for a special path. Maps state the general rule and let the degenerate case fall out of it.
2026-09-30: consumer audit bounds internals, not a general library's public surface
- Evidence: P4 (collapse Geometry's CultVec types into CultMath) found that CultMath's
float2,float3andrecthad no MessagePack support. Aetheria, StreamPixels and three Aetheria forks each carried their own formatter copies. The first option offered was to stop serializing the Geometry types. The operator's words: "we want all the math stuff to serialize, there's no excuse not to" and "just because we're not using a feature doesn't mean we can cut it". - SKILL.md's subtraction section now says that for a general-purpose library (CultLib) the question is what a reasonable consumer would expect. The call-count audit bounds only internal duplication.
- The root cause was the skill's own "count real use … a surface with no consumer is parked" rule. It was written for app-internal subtraction and read as licence to trim library capability.
2026-09-30: Soul checks history before recommending a mechanism
- Evidence: CultNet publish, Soul pass 3, recommended ordered delivery inside CultCache's publication, on the
writer's thread. Imagination found that exact scheduler in
bcae483, deleted in456234034 minutes later for deadlocking against_lifecycleGate. A prototype re-proved the deadlock. SKILL.md already recorded "design order as data, not as scheduling", and the brief carried no instruction to check. - The Soul brief template now requires
git log -S/--grepon a mechanism before recommending it. A mechanism that was tried must be cited with the reason the new situation differs.
2026-09-30: errors never echo an input value
- Evidence: the Heimdall secrets cut existed to keep secrets off terminals, yet its new reader's error printed
the
_FILEpath. Soul reproduced a fullpostgres://user:pw@...URL reaching journald when a URL was bound into a_FILEslot. The Imagination map for the same cut had already found TOML parse errors quoting wholeKEY = "value"lines. Same class, found twice in one day. - The Hands brief template now requires that errors, logs and refusals name the field and the error code, never the value, and that this is pinned by a canary test.
2026-09-30: campaign state is typed (Huginn Cut 15, under Q-H6 A)
- Evidence: the Huginn wiring map (Epiphany
notes/huginn-organ-cut.mdat74804d83, Cut 15). Huginn is live on Yggdrasil with instanceeureka, andeureka-stateexposes four tools (whoami,admit,view,query). The operator's ruling on Q-H6: "every bit of prose we're passing around should be viewed as a potential liability, especially if it's too big to just shove the whole thing into context. We should be looking for ways to turn what remains into typed state as well." - Questions, rulings, cut specs, reports, verdicts, findings, follow-ups and resolutions are admitted documents. The committed map keeps body facts, the model page and rationale, and has no status header, no per-cut sections and no rulings. A superseded ruling or spec is closed by a resolution, never edited.
references/cut-map.mdis replaced byreferences/campaign-state.md: the tools, the document set, the resolution matrix, the selection vocabulary, and recipes that replace the deletedopen_items,rulings_in_forceandhistorypresets. Specs with no report is one query, because the substrate'scitedhop takesexists: false.- Briefs give ids and recipe names instead of pasted specs or rulings. Every brief starts with Rehydrate:
whoami, then the recipes. Hands reads its spec withviewand admits acut_report. Soul admits averdictand its findings; admitting is a Mind write, so Soul stays read-only on repos. - Self stops when the organ is unreachable and keeps no second copy meanwhile. "Record the substrate you
needed and did not have" stays, and the record is now a
follow_up. - Soul's first pass on this change (Self's triage, same day) found the claim set bounded by Hands'
self-report. Soul now makes one claim per ruling the spec cites, beside the promises; the operator
reaffirmed that Soul loops are "the whole thesis behind Eureka". Only Self closes a finding
Fixed, after a Soul pass on the fix holds. The same batch added: one rule for an organ that does not answer (missing tools, one retry onUnavailable, a resumable stop); a Hands exit for a fork before the first commit; operator directions as rulings with noanswers; the target document committed before itsDocRefs are admitted; and a substrate-gaps table incampaign-state.md.
2026-09-30: pipefail reaches job scripts
- Evidence: Soul (scenarios batch 2) proved that
bash -o pipefail -c "bash job.sh"does not give the script pipefail, because shell options are not inherited. A job script ending indotnet test ... | tail -3came backexit 0on a failing test. Every Hands and Soul job on 2026-09-30 ran asbash <script>.sh. - The stopgap now exports
SHELLOPTS=pipefailinto the container. Probe: a scriptfalse | catexits 1, andtrue | catexits 0. - Consequence for today's results: any job-script verdict whose last command was a pipeline, reported before this change, is unproven. Soul passes re-derived their verdicts from test output, not from the exit code alone, so their CONFIRMED and held claims stand. Hands-reported "green" that rested only on the exit status should be read as unverified until re-run.
2026-10-01: waiting costs no model calls
Operator, verbatim: "It's not the chatter, it's the model call, we want you not to activate at all while waiting; tools should return on events, not timers (or at least not timers less than a minute long)". The mining Cut 3 fix Hands woke Self four times with interim results while its suite and mutations ran on Yggdrasil, and the brief template prescribed foreground polling in tool-timeout chunks (one model call per chunk). The template also claimed "nothing wakes you", which is stale: the harness wakes an agent when its background shell exits. Both brief sections now say: one background waiter per job that exits on the event, no timer under 60 s, no duplicate watchers, no interim messages.
2026-10-02: prior art before every nontrivial fork
Operator, verbatim: "can we make it a rule to stop what we're doing and do an Eyes pass to look at research papers and other implementations related to whatever we're working on before any nontrivial forks? I feel like the default reflex is to defer to my judgment, and I'm neither a Dijkstra nor a Carmack". Evidence: in the Asura and variants campaigns that day, Self put the single-file store's write model (carry foreign records, refuse, log-structured, page tree) to the operator from first principles. SQLite, LMDB and log-structured stores had not been surveyed, and neither had the literature. SKILL.md step 2 now requires an Eyes prior-art pass before a nontrivial question reaches the operator.
2026-10-02: every consuming test project, counted
Evidence: the R1 merge into C2a was reported green, yet GameCult.Mesh.Tests did not compile at any commit of the range. Git auto-merged a main test that uses a type C2a deleted. That broken build hid a High finding: CultMesh's own single-file reader read zero bytes as an empty store. Earlier, the C2a F2 Soul hold covered a range where a Caching test was already red. The Hands template now requires one evidence line per consuming test project (found from the project files), with "did not build" reported as a result. The Soul template checks the list against the project files and runs anything missing.