You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Field incident (full report available; summarized with evidence)
On a second workspace, four of five architects died individually over ~two days. Tower — whose daemon ran CONTINUOUSLY the whole window (uptime 150,352s → 316,489s, so this was not a Tower crash) — kept serving all of them as registered. afx status listed an architect with a pid that ps -p showed dead; workspace terminal count dropped 14 → 10 with no deregistration. Worst part: afx send architect:<name> to a dead architect reported [ok] Message delivered. A gate approval relayed to a dead architect is lost with a positive confirmation and no error anywhere — the held-mailbox path exists precisely for this and never engaged because the target was believed live.
Why the gap exists (architecture)
Liveness reconciliation runs at Tower BOOT only. A long-lived Tower never re-checks; rows can only go stale. Compounding detail from the reporter's DB inspection: the architect table stores pid = 0 for every row (unusable for liveness; started_at also stale across restarts), while terminal_sessions carries real pid, shellper_pid, shellper_start_time — correct and sufficient, but nothing validates or prunes those rows during Tower's life. The data needed for liveness is already persisted; it just is not checked after boot.
Fix shape (hypothesis, for the builder to validate)
afx send must not report success to a dead target. Route to the durable mailbox with a dead-target (or similar) hold reason, consistent with existing hold semantics — the sender gets held+reason and the owner escalation path engages, instead of [ok] delivered into a void. Also investigate HOW delivery verification passed against a dead session: if the echo check can pass on a stale ring buffer, that is its own sub-defect of the tower: delivery write edge — verify-or-retry 'delivered', settle-before-write, loud size limit (silent-loss residuals of #1564/#1521) #1573 contract.
afx workspace recover equivalent for architects. Today it revives only builders. The field recovery that worked, worth building toward and documenting: afx workspace add-architect --name <same-name> then re-init — builder→architect affinity survives (builders keep their Owner), so same-name re-add restores routing with no builder disruption.
Docs note
The afx skill had no entry for recreating/restarting an architect (reporter had to discover workspace add-architect / remove-architect from --help). Being fixed directly in the skill docs alongside this filing; noted here for completeness.
Related: #1714 (registry-vs-substrate consistency check) is the audit-side complement; this issue is the runtime-liveness side.
Field incident (full report available; summarized with evidence)
On a second workspace, four of five architects died individually over ~two days. Tower — whose daemon ran CONTINUOUSLY the whole window (uptime 150,352s → 316,489s, so this was not a Tower crash) — kept serving all of them as registered.
afx statuslisted an architect with a pid thatps -pshowed dead; workspace terminal count dropped 14 → 10 with no deregistration. Worst part:afx send architect:<name>to a dead architect reported[ok] Message delivered. A gate approval relayed to a dead architect is lost with a positive confirmation and no error anywhere — the held-mailbox path exists precisely for this and never engaged because the target was believed live.Why the gap exists (architecture)
Liveness reconciliation runs at Tower BOOT only. A long-lived Tower never re-checks; rows can only go stale. Compounding detail from the reporter's DB inspection: the
architecttable storespid = 0for every row (unusable for liveness;started_atalso stale across restarts), whileterminal_sessionscarries realpid,shellper_pid,shellper_start_time— correct and sufficient, but nothing validates or prunes those rows during Tower's life. The data needed for liveness is already persisted; it just is not checked after boot.Fix shape (hypothesis, for the builder to validate)
afx status/ overview:kill(pid, 0)each terminal_sessions row withshellper_start_timecompared against the live process's start time (PID-reuse guard — same discipline as tower reconcile: failed reconnect triggers delete + SIGTERM without verifying the shellper is dead (destroyed 53 live sessions in the #1629 incident) #1686's proof-of-death), and present dead rows as STALE, never as live. Presentation-only: this must not delete or signal anything (tower reconcile: failed reconnect triggers delete + SIGTERM without verifying the shellper is dead (destroyed 53 live sessions in the #1629 incident) #1686's invariant stands — destruction requires proof of death AND stays reconcile's job).afx sendmust not report success to a dead target. Route to the durable mailbox with adead-target(or similar) hold reason, consistent with existing hold semantics — the sender getsheld+reason and the owner escalation path engages, instead of[ok] deliveredinto a void. Also investigate HOW delivery verification passed against a dead session: if the echo check can pass on a stale ring buffer, that is its own sub-defect of the tower: delivery write edge — verify-or-retry 'delivered', settle-before-write, loud size limit (silent-loss residuals of #1564/#1521) #1573 contract.afx workspace recoverequivalent for architects. Today it revives only builders. The field recovery that worked, worth building toward and documenting:afx workspace add-architect --name <same-name>then re-init — builder→architect affinity survives (builders keep their Owner), so same-name re-add restores routing with no builder disruption.Docs note
The afx skill had no entry for recreating/restarting an architect (reporter had to discover
workspace add-architect/remove-architectfrom--help). Being fixed directly in the skill docs alongside this filing; noted here for completeness.Related: #1714 (registry-vs-substrate consistency check) is the audit-side complement; this issue is the runtime-liveness side.