docs(issue-5): record atomic attribution and correct my earlier claim

The state-transition spec gains the rule that attempt identity lives in the
record, because a precondition can only be atomic with the commit if the
transaction can read it under its own lock, and checking attribution beforehand
leaves a window a re-dispatch fits through.

The operations note gets the same, plus the reason it is an opaque token rather
than the iteration counter: iteration already means the loop round, so comparing
a dispatch attempt against it is vacuous when they agree and wrong when they
diverge.

It also marks my earlier section as partly withdrawn rather than quietly editing
it. That section argued a record schema change was unnecessary because the
attempt guard lives in the evidence layer. That was right about comparing
evidence to a dispatch and wrong about atomicity, and the review proved the
difference by execution. The narrower point it made -- why not to reuse
iteration -- still holds and is kept.

Also records why the subscriber now deduplicates on the intent identity: a
replay arrives with a fresh wire sequence, so the monotonic guard cannot see it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UrDNJkHmm18uu7n7JwV5Qd
This commit is contained in:
GodopuandClaude Opus 5 committed 2026-09-06 23:22:12 +09:00
1 parent 01b465f50c
commit 9a651ccc71
3 files changed
+27 -2

No files matched your search

+3 -1
View File
@@ -1,6 +1,6 @@
# 📑 Target State Transitions and CAS Specification
- **Document Version**: Rev.5 (멱등 ACK 구분 및 관측 증거 필수 요건 명문화)
- **Document Version**: Rev.6 (dispatch token 기반 원자적 시도 귀속 추가)
- **Issue**: [Gitea Issue #5](https://git.godopu.com/tmpl/multi-agent-mux/issues/5)
- **Scope**: Target Compare-And-Swap (CAS) State Machine & Attribution Contract
@@ -54,6 +54,8 @@ $$\text{Attribution Tuple} = (\text{job\_id}, \text{attempt\_id}, \text{agent\_s
> 🔑 **권한 축(Authority)**: `redispatch`·`finalize`는 `source ∈ {registry_cli, operator}`에서만 허용된다. 에이전트(`publish_event`)는 **자신의 terminal을 되돌릴 수 없다** — 이것이 CAS 표의 존재 이유이며, 위 두 행은 그 원칙의 예외가 아니라 래퍼가 수행하는 별개 전이를 이름 붙인 것이다.
>
> 🔑 **시도 정체성은 레코드에 있다**: `dispatch_token`은 시도를 시작하는 요청(`claim`/`redispatch`)에서 새로 발급되며, `expected_dispatch_token` 전제조건으로 **락 안에서** 대조된다. 커밋 전에만 확인하는 귀속 검사는 그 사이의 재디스패치를 막지 못한다 — 전제조건이 커밋과 원자적이려면 트랜잭션이 자기 락 안에서 읽을 수 있어야 한다. `iteration`(루프 회차)과는 다른 개념이므로 별도 필드다. — 교차 리뷰 `a45e5b7f` R2
>
> 🔑 **멱등 ACK는 거부가 아니다**: `terminal` 상태에서 같은 terminal을 재수신하면 표는 이를 **No-op ACK**로 정의한다. 호출자(운영자 CLI)는 이를 성공(rc 0)으로 취급해야 한다. 실제 거부(상충 신호·권한 부족)만 non-zero다. — 교차 리뷰 `cb792e91` F-C
>
> 🔑 **status는 요청으로만 설정된다**: 임의 필드로 실린 `status`는 경계 내부에서 거부된다(`progress`가 terminal을 커밋하는 우회 차단). 알 수 없는 요청명도 거부된다. `pending`도 소유 요청(`redispatch`)을 갖는다.