Wave Summary
| Field | Value |
|---|---|
| purpose | make “nothing is happening” a safe, observable factory state; stop autonomous token use after sustained idle; make server-backed Beads identity and note linkage fail closed instead of disappearing |
| development window | opened August 2, 2026; this entry records the opening checkpoint rather than a completed exit |
| baseline | b8ca1294 on main |
| identity hardening branch | beads-identity-ys-yes-zdry; 5 commits through 9708f916 |
| branch change surface | 19 files, 1,647 insertions, 56 deletions |
| triggering incidents | an orphaned ALS feature note exposed two clones with a stale Beads guard token; a manual shutdown request exposed the absence of a deterministic idle-to-off transition |
| current operating state | ALS and ALS-refinery are usable with 34 Beads issues each; eSPS is off; the hardening branch is not yet on main; automatic idle shutdown and message expiry remain open |
| exit condition | identity safeguards merged and audited across the workspace fleet; sustained authoritative idle stops every autonomous service exactly once; factory mail is purged; an explicit restart begins with an empty message session |
Wave 5 proved that Yesod could carry a real cross-language product slice to a merged result. Wave 6 begins with a less glamorous question: what should the factory do when there is no result left to produce?
An autonomous system can waste resources while appearing quiet. A propulsion loop can keep prompting agents, a dispatcher can keep reconsidering an empty or blocked queue, and old coordination messages can be mistaken for current intent after a restart. At the same time, machine-local state can look like ordinary source code and spread a bad identity to every clone.
The two failures share a boundary problem. Durable truth and disposable execution state were not separated sharply enough. Wave 6 makes that separation explicit: notes, Beads issues, commits, and audit events are durable; agent mail, sessions, leases, and clone-local guard tokens are not.
Idle Is a Derived State, Not an Empty Screen
On August 2 the operator disabled eSPS to stop further autonomous prompts. The
service status showed off with no daemon PID. That was the correct immediate
containment action, but it was not yet a factory-level idle protocol. Turning
off propulsion alone does not prove that a runner, gate, merge, or local agent
is not still working.
The open feature request ys-yes-6qs5 / yes-4pgc defines the stronger
contract. An idle decision must be derived from authoritative state across:
- live factory agents;
- claimed and in-flight dispatch runs;
- refinery gates and merges;
- actionable queued work; and
- a configurable grace period that spans normal gaps between steps.
Only sustained idle may trigger shutdown. The shutdown itself must be idempotent and must disable eSPS, factory roles, the mail broker, local dispatcher, refinery supervisor, and seat keeper. Active work blocks the transition. A status and dry-run surface must show the exact evidence behind the decision, and the audit record must be produced without spending another LLM call.
This is a cost-control feature, but it is also a correctness feature. “No work is visible to me” is not evidence that no work exists. The factory may go dark only after all of its ownership records agree.
Coordination Has a Lifetime
At the opening checkpoint, the catalog still held 1,914 factory mail rows. Those rows were useful coordination artifacts when they were written; they are not a durable knowledge base. Preserving them indefinitely makes a later session vulnerable to stale nudges, obsolete handoffs, and accidental revival of work that has already been resolved elsewhere.
Wave 6 therefore assigns each information surface a lifetime:
| Surface | Lifetime | Reason |
|---|---|---|
| Yesod notes and topics | durable | operator intent, decisions, incidents, and reusable knowledge |
| Beads issues and dependencies | durable | executable work identity and dependency state |
| Git commits and gate evidence | durable | implementation and verification record |
| audit event for an idle shutdown | durable | explains why and when autonomous execution stopped |
| agent mail and message rows | bounded and purgeable | transient coordination, not a source of truth |
| agent sessions and leases | process-scoped | execution ownership that must not survive its owner |
.beads/metadata.json |
clone-local | guard token binding one checkout to one server database |
Idle shutdown is the natural garbage-collection boundary. Once the factory has proven that no active work remains, it can wipe transient messages and stop the processes capable of consuming them. A later explicit start should recreate a clean session rather than replay the previous factory’s conversational debris.
The ALS Incident Exposed an Identity Boundary
The immediate Beads incident began when yesod tool als feature-request
created note ys-als-qh64 but could not create its linked issue. The note was
left without a Beads identity and was therefore invisible to the dispatcher.
Diagnosis showed that both the main ALS clone and its refinery clone failed all
bd operations with a project identity mismatch.
The server database was healthy and contained 33 issues. Its
metadata._project_id was 705f983c-c8f7-4ba6-b975-60772bfd6c3f. Both clones
instead carried the local token 2046f420-abb4-4503-a5e1-408413288ac4, an
identity minted by a later bd init. The guard correctly refused the
connection: accepting either side silently would have risked writing one
project’s issues into another project’s database.
The disease was propagation, not the guard. .beads/metadata.json had been
tracked in Git, untracked once, and then swept back into an unrelated feature
commit after its ignore rule disappeared. A machine-local token became
repository history and spread through ordinary pulls to every clone.
Recovery followed the authority boundary in the safe direction:
- query the server metadata and issue count first;
- establish that the populated server database is the source of truth;
- replace only the clone-local guard tokens;
- untrack and durably ignore the metadata file; and
- retry the missing note-to-Bead link.
The orphaned note became issue als-qwf, raising the database count to 34.
Both ALS workspaces then returned to ok. No issue history was copied or
reinitialized.
The Server Became Canonical
Bug report ys-yes-zdry / yes-vr8b produced a five-commit hardening branch.
Its central rule is simple: for a server-mode workspace, the canonical project
identity lives in the server database. A runner or provisioning path may seed
an identity only when the database is genuinely empty. If a populated database
has no _project_id, Yesod stops rather than inventing one.
The branch carries the rule through the whole lifecycle:
| Boundary | Safeguard |
|---|---|
| provisioning | read the existing server identity; generate only for an empty database |
| runner worktree staging | write the server’s identity into local metadata instead of calling uuid4() |
| diagnosis | yesod beads doctor compares local and server IDs and reports tracked or unignored metadata |
| repair | yesod beads repair-identity TOOL --from-server previews by default and writes only with --apply |
| source control | root ignore rule, pre-commit rejection, CI rejection, and worker instructions keep metadata out of commits |
| missing linkage | a PostgreSQL outbox leases and retries failed note-to-Bead creation with bounded backoff |
The last safeguard closes the exact invisibility gap exposed by ALS. Note creation and outbox enrollment occur in one catalog transaction. A temporary Beads failure no longer turns an actionable request into an untracked orphan; runners retry the recorded failure, and successful linkage removes the outbox row.
The branch contains regression coverage for canonical identity resolution,
safe repair, Git guards, runner staging, and outbox retry behavior. At this
checkpoint it is pushed through 9708f916, but it is not yet part of main.
That distinction matters: implemented on a branch is evidence of progress, not
fleet protection.
One Populated Database Still Needs a Deliberate Migration
The SJBGTD workspace demonstrates why the new code fails closed. Its server
database contains 151 issues but has no _project_id. There is no safe value
for an automated repair command to guess. The local token may be correct, but
it must first be proven against the long-lived workspace and every healthy
clone.
The handoff plan requires quiescing writers, capturing server and clone
evidence, taking a recoverable Dolt snapshot, establishing one canonical UUID,
inserting it server-side through an authorized path, and only then repairing
each clone from the server. Backup configuration is a separate least-privilege
operation; broad remote-admin authority must not be granted to yesoduser
merely to make bd dolt push succeed.
This is intentional friction. A repair tool is safe because it refuses the case in which the operator has not yet established the truth.
What Has Landed, and What Remains
| Area | Evidence at this checkpoint | Required before wave exit |
|---|---|---|
| ALS recovery | both clones use the server identity; the orphan note is linked as als-qwf; each reports 34 issues |
retain healthy identity after normal clone and refinery activity |
| identity implementation | five commits on beads-identity-ys-yes-zdry through 9708f916 |
merge, deploy, and run the fleet audit under the released Yesod |
| Git boundary | ALS metadata is untracked and ignored; branch adds hook, CI, and worker guards | audit every registered repo and refinery clone for tracked metadata |
| linkage durability | branch adds a leased outbox and runner retry path | demonstrate recovery from a real transient failure after deployment |
| immediate cost containment | eSPS is off with no daemon PID | implement and prove whole-factory idle detection and idempotent shutdown |
| message lifecycle | ephemeral-mail contract is recorded in ys-yes-6qs5 |
purge existing transient rows, enforce retention, and prove clean restart |
| SJBGTD | 151 server issues remain reachable; migration plan is documented | establish _project_id, align all clones, and complete a recoverable backup sync |
The New Exit Criterion
Earlier waves made the factory capable of continuing after failures. Wave 6 adds the complementary capability: stopping cleanly when continuation has no value.
The wave is complete only when two proofs exist. First, every server-backed workspace must derive identity from a known database of record, while every clone-local guard stays outside Git and every failed note linkage remains recoverable. Second, an idle factory must be able to explain that it is idle, wait through a bounded grace period, stop every autonomous component exactly once, remove transient coordination messages, and remain quiet until a human explicitly starts a clean session.
The durable lesson is that autonomy needs an off-state as carefully designed as its run-state. A factory that cannot distinguish durable truth from transient coordination will either forget important work or preserve activity forever. The quiet factory does neither.