Detailed design: fix two semantic findings from Opus deep re-audit

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 <noreply@anthropic.com>
This commit is contained in:
AirCoding
2026-06-01 15:09:46 +08:00
parent fbcd114f8d
commit abc244f0da

View File

@@ -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: