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:
@@ -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.started` | upsert `message_drafts` (status=streaming) |
|
||||||
| `assistant.message.created` | insert `messages` + delete matching `message_drafts` |
|
| `assistant.message.created` | insert `messages` + delete matching `message_drafts` |
|
||||||
| `assistant.message.failed` | `message_drafts.status=error` or failure artifact ref |
|
| `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` |
|
| `agent.completed/failed/lost/cancelled` | update `agents.status` |
|
||||||
| `task.created` | insert `tasks` (+ optional `task_dependencies`) |
|
| `task.created` | insert `tasks` (+ optional `task_dependencies`) |
|
||||||
| `task.started` | `tasks.status=running`, set started/agent/workspace; insert `task_attempts` |
|
| `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 |
|
| 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` |
|
| `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` |
|
| `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
|
### 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
|
```text
|
||||||
starting ──ready──▶ running
|
(insert) ──agent.started──▶ starting | running
|
||||||
running ──agent.completed──▶ completed
|
running ──agent.completed──▶ completed
|
||||||
running ──agent.failed──▶ failed
|
running ──agent.failed──▶ failed
|
||||||
running ──agent.lost──▶ lost
|
running ──agent.lost──▶ lost
|
||||||
running ──agent.cancelled──▶ cancelled
|
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
|
### 20.5 Workspace Status Transitions
|
||||||
|
|
||||||
From db-schema §16:
|
From db-schema §16:
|
||||||
|
|||||||
Reference in New Issue
Block a user