Context
Grace's mandatory STEP_BACK partial and OQ5 require one unique atomic sourceEventId -> taskId binding before existing A2A Task authority begins. Existing Task ownership and transition event identity do not prevent two Tasks from being minted for one external response item.
This is one fully closeable PR leaf under Epic #15145. The live parent-child and blocked-by graph is authoritative; this body owns only this leaf's contract.
The Problem
If Task creation and source binding are separate writes, concurrent peers can each create a canonical-looking Task and both win downstream assignment. A crash can also leave an orphan Task or binding.
The Architectural Reality
The binding belongs in a Memory-Core activity service using the same SQLite transaction seam as MailboxService.transitionTask. It consumes an admitted durable response item. Existing MailboxService remains the downstream Task state/assignment authority after the binding commits.
The Agent OS structure map was run on 2026-07-14. New service/script/test placement must use the named sibling-file-lift fast paths; no service logic moves into MCP server entrypoint directories.
The Fix
Implement an atomic claim operation and unique binding table/index that validates tenant/source eligibility, creates or retrieves exactly one canonical A2A Task, commits Task plus sourceEventId -> taskId binding together, and returns the same Task to concurrent/retry callers.
Contract Ledger Matrix
| Target Surface |
Source of Authority |
Proposed Behavior |
Fallback / Edge Case |
Docs |
Evidence |
| Canonical claim |
OQ5 STEP_BACK |
One transaction binds eligible source event to one Task |
Concurrent/retry callers receive existing canonical Task |
Service/OpenAPI docs |
Race and idempotency tests |
| Task authority handoff |
MailboxService contracts |
Existing Task owner/state authority begins only after binding commit |
Failure exposes neither Task nor binding |
JSDoc |
Crash-point tests |
| Lifecycle exclusion |
ADR 0035/OQ5 |
Unclaimed community activity remains outside LifecycleFrontier |
Seen or count state cannot promote it |
Authority docs |
Negative frontier tests |
Decision Record impact
Depends on ADR 0036 and neutral admission; composes ADR 0035 and existing Task contracts without changing their state machine.
Decision Record
Required: ADR 0036. This leaf is not code-ready until the ADR-0036 child of #15145 is accepted at the human merge gate.
Discussion Criteria Mapping
| Upstream graduated criterion |
This leaf's executable contract |
| OQ5 |
Creates the missing admission-to-canonical-Task transition. |
| STEP_BACK point 4 |
Proves unique atomic sourceEventId-to-taskId before Task authority. |
| OQ7/OQ8 |
Claim is explicit, tenant-scoped, and independent of wake/read state. |
Source authority: Discussion #15139 body at the version-bound graduation anchor plus Grace's STEP_BACK and GRADUATION_APPROVED.
Acceptance Criteria
Out of Scope
Automatic assignment, automatic response, Task state-machine redesign, wake leases, or source acquisition.
Avoided Traps
Do not use Task creation alone as dedup, bind after Task publication, overload occurrence identity with task id, or let seen imply claim.
Related
Origin Session ID: 837ad74b-c2d2-413d-9aab-b7165a93a82a
Handoff Retrieval Hints
sourceEventId taskId atomic canonical Task claim
community activity claim race MailboxService transaction
Creation Freshness
Creation duplicate sweep: immediately before filing at 2026-07-14T05:31:21.422Z, checked the latest 20 open issues and last 30 all-state A2A messages. The independent broader audit at 2026-07-14T05:13:00Z covered open and closed issues, pull requests, A2A, ADRs, and code; no equivalent owner or foreign claim existed.
Context
Grace's mandatory STEP_BACK partial and OQ5 require one unique atomic
sourceEventId -> taskIdbinding before existing A2A Task authority begins. Existing Task ownership and transition event identity do not prevent two Tasks from being minted for one external response item.This is one fully closeable PR leaf under Epic #15145. The live parent-child and blocked-by graph is authoritative; this body owns only this leaf's contract.
The Problem
If Task creation and source binding are separate writes, concurrent peers can each create a canonical-looking Task and both win downstream assignment. A crash can also leave an orphan Task or binding.
The Architectural Reality
The binding belongs in a Memory-Core activity service using the same SQLite transaction seam as
MailboxService.transitionTask. It consumes an admitted durable response item. ExistingMailboxServiceremains the downstream Task state/assignment authority after the binding commits.The Agent OS structure map was run on 2026-07-14. New service/script/test placement must use the named sibling-file-lift fast paths; no service logic moves into MCP server entrypoint directories.
The Fix
Implement an atomic claim operation and unique binding table/index that validates tenant/source eligibility, creates or retrieves exactly one canonical A2A Task, commits Task plus
sourceEventId -> taskIdbinding together, and returns the same Task to concurrent/retry callers.Contract Ledger Matrix
Decision Record impact
Depends on ADR 0036 and neutral admission; composes ADR 0035 and existing Task contracts without changing their state machine.
Decision Record
Required: ADR 0036. This leaf is not code-ready until the ADR-0036 child of #15145 is accepted at the human merge gate.
Discussion Criteria Mapping
Source authority: Discussion #15139 body at the version-bound graduation anchor plus Grace's STEP_BACK and GRADUATION_APPROVED.
Acceptance Criteria
Out of Scope
Automatic assignment, automatic response, Task state-machine redesign, wake leases, or source acquisition.
Avoided Traps
Do not use Task creation alone as dedup, bind after Task publication, overload occurrence identity with task id, or let seen imply claim.
Related
Origin Session ID: 837ad74b-c2d2-413d-9aab-b7165a93a82a
Handoff Retrieval Hints
sourceEventId taskId atomic canonical Task claimcommunity activity claim race MailboxService transactionCreation Freshness
Creation duplicate sweep: immediately before filing at 2026-07-14T05:31:21.422Z, checked the latest 20 open issues and last 30 all-state A2A messages. The independent broader audit at 2026-07-14T05:13:00Z covered open and closed issues, pull requests, A2A, ADRs, and code; no equivalent owner or foreign claim existed.