From abc244f0daa4e639ec9d909f27ae5ba960d6a136 Mon Sep 17 00:00:00 2001 From: AirCoding Date: Mon, 1 Jun 2026 15:09:46 +0800 Subject: [PATCH] Detailed design: fix two semantic findings from Opus deep re-audit MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit An Opus-perspective semantic re-audit (reading state-machine semantics, event-sourcing invariants, and baseline together rather than grep-style structural checks) surfaced two issues the prior seven rounds missed. O2 [P1] §5.4 + §20.4: removed the event-less `starting → running` status transition. The prior R1-02 fix eliminated the same-event atomicity error but left a second status-machine arc that (a) has no basis in baseline (event-registry §3 says agent.started inserts status = running OR starting, with no second transition) and (b) had WorkerManager UPDATE agents.status directly, bypassing the event log and violating runtime-semantics §3 (all same-session domain updates go through BEGIN→insert events row→ project→COMMIT). agents.status is now written only by agent.* projection; worker.ready handshake is clarified as a live IPC signal, not a status write. O1 [P2] §5.4: MemoryRepository (an orphan name appearing exactly once, never defined in §4.3/§11.3/contracts/code-view) corrected to LearnedMemoryStore, matching §11.3 and the §21.3 traceability matrix. Detailed design re-frozen with these corrections. Co-Authored-By: Claude Opus 4.8 --- .../docs/architecture/system-detailed-design.md | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/AirPlan/docs/architecture/system-detailed-design.md b/AirPlan/docs/architecture/system-detailed-design.md index 308c1e3..85b094e 100644 --- a/AirPlan/docs/architecture/system-detailed-design.md +++ b/AirPlan/docs/architecture/system-detailed-design.md @@ -380,7 +380,7 @@ post-commit outbox/compensation work explicit, the map is split into two tables. | `assistant.message.started` | upsert `message_drafts` (status=streaming) | | `assistant.message.created` | insert `messages` + delete matching `message_drafts` | | `assistant.message.failed` | `message_drafts.status=error` or failure artifact ref | -| `agent.started` | insert `agents` row with `status = 'starting'` when emitted at spawn (handshake not yet acknowledged) or `status = 'running'` when emitted after the WorkerProcess handshake has completed; the event carries exactly one terminal-of-emission status. The follow-up `starting → running` transition (without a dedicated durable event) is recorded by `WorkerManager` updating the row directly per the state machine in §20.4 | +| `agent.started` | insert `agents` row with `status = 'running'` when the event is emitted after the WorkerProcess handshake has completed (the normal case), or `status = 'starting'` when emitted before handshake acknowledgement; the event carries exactly one status and projects it once (event-registry §3: "insert row with status = running or starting"). There is **no** runtime `starting → running` UPDATE that bypasses the event log: if a row was inserted as `starting` and the agent later becomes fully ready, the next durable `agent.*` event (or a re-emitted `agent.started` for the running phase) carries the status; `agents.status` is only ever written by `agent.*` event projection (runtime-semantics §3), never by a direct `WorkerManager` write | | `agent.completed/failed/lost/cancelled` | update `agents.status` | | `task.created` | insert `tasks` (+ optional `task_dependencies`) | | `task.started` | `tasks.status=running`, set started/agent/workspace; insert `task_attempts` | @@ -427,7 +427,7 @@ eventually consistent (§18.4, runtime-semantics §6.3-§6.4). | Event type | Projection step (in session-DB transaction) | External write (already done by owner before event is ingested) | Owner | |---|---|---|---| -| `memory.promoted` | append durable event (event log row); domain side has no dedicated table — `MemoryRepository` is project-DB only | write `rules/`, `skills/`, or `learned-memory.db` row | `LearnedMemoryStore` / rules subsystem | +| `memory.promoted` | append durable event (event log row); domain side has no dedicated session-DB table — `LearnedMemoryStore` is project-DB only | write `rules/`, `skills/`, or `learned-memory.db` row | `LearnedMemoryStore` / rules subsystem | | `memory.archived` | append durable event | mark memory inactive in external store | `LearnedMemoryStore` | | `debug.record.created` | append durable event | insert/update row in `debug-records.db` | `DebugKnowledgeStore` | @@ -1752,16 +1752,25 @@ blocked ──decision received──▶ pending ### 20.4 Agent Status Transitions -From db-schema §10: +From db-schema §10. Each transition below is driven by a durable `agent.*` event and +applied to `agents.status` only through event projection (runtime-semantics §3); there is +no direct status write that bypasses the event log. ```text -starting ──ready──▶ running +(insert) ──agent.started──▶ starting | running running ──agent.completed──▶ completed running ──agent.failed──▶ failed running ──agent.lost──▶ lost running ──agent.cancelled──▶ cancelled ``` +`agent.started` sets the initial status to `running` (handshake completed before emission, +the normal case) or `starting` (emitted before handshake). The `starting` value is the +initial projected status, not a separate event-less transition; baseline defines no +durable `starting → running` event, and `agents.status` is never updated outside +`agent.*` projection. Process readiness (`worker.ready` handshake, §8.2) is a live IPC +signal, not a status-column write. + ### 20.5 Workspace Status Transitions From db-schema §16: