Why: A domain outbox could not correlate its committed event with the host receipt because the bus generated the operation ID after the handler returned. Evidence: RED-to-GREEN bus and compiled-handler tests; local go test ./... -count=1 and isolated PostgreSQL operation/link checks passed as SELF. Impact: Expose a host-generated operation ID to handlers and resolve a unique committed audit offset after dispatch; missing receipts remain retryable and ambiguous rows fail closed. Refs: Stage 5 W9; approved Stage 6 audit-link design adjustment r1
6.0 KiB
6.0 KiB
W9 Backend project audit candidate
- Scope: TT-A01/A02/A04/U04, approved stage 5 W9. Stage 6 local implementation; human review, formal acceptance, PR, CI, tag, and deployment are pending.
- Branch/worktree:
feature/rdm-two-trees-project-auditat/home/weichen/projects/Agent-System-Backend-wt-feature-rdm-two-trees-project-audit. - R0: Backend authoritative
origin/main5d5fc9891c0eb8994545ccb8b740535d9b99fb0e; main was clean and equal to the fetched remote before this worktree was created. Core gitlink in this worktree is5773e74086791731059730bd3726dc8c9cd1381f. - Startup receipt:
/tmp/backend-w9-precheck-20261014-01.json(SELF, exit 2,SYNC_REQUIREDfor the separate Dev checkoutfeature/rdm-increment-acceptance-note, six commits behind Devorigin/main). This Backend task uses the independent-development path in BackendAGENTS.md; it does not write that Dev checkout or its task card. The receipt is preserved as a failure, not relabeled READY. - Approved affected design:
rdm-two-trees-stage6-audit-link-design-adjustment-r1.md, SHA256385d9d7570217ddcce9fe60a60c99dc58c9a4875ad790584a724d09a210a6e52; user approval in the task session covers this local Backend increment, not tag publication or Stage 7 acceptance.
Implemented local slice
- Optional
ProjectAuditHostand domainaudit.readregistration. A different plugin, absent registration, or unbound actor cannot read. - Store write snapshots the project from the owner-matched conversation; query requires the authenticated actor's owner and that immutable project. This deliberately excludes other members' private conversations and unbound historical rows, and does not move old receipts when a conversation changes projects.
- Command audit stores the current verified account display name at write time; old rows expose
not-recorded. Public receipts omit raw payload and parameter digest. Cursor uses project-and-owner scoped source cutoff. - Initial commit
c8dd169a1fdc1451fab3b475c14f9636a7f5bf6cexposed only the actor-owned project slice. The next local increment fixes button actor propagation and adds a trusted domain-commit link publisher, verifier callback, exact linked metadata read, currentaudit.readand per-object metadata checks, and durable idempotency. Unlinked personal conversations remain private. - Trusted command dispatch now creates an operation ID before calling the compiled handler and passes that ID through
extension.Request. The handler can commit the same ID with its domain event/outbox; the final Backend audit/receipt uses it. Clientparams.operationIdis ignored. An outbox link request withHostAuditOffset=0resolves a unique committed host row by owner, fixed project, and operation ID; a missing row returns retryableErrProjectAuditPending, while duplicate rows fail closed. The separate idempotency key still controls retry equivalence. - Exact-source linked reads do not enumerate hidden links or reveal raw payload, private conversation ID, or content. Body disclosure and a broad project link list are not implemented; the public coverage reports the narrower capability.
Verification and remaining work
- The session saw RED for the missing store and host interfaces, unscoped cutoff, cross-member private disclosure, and conversation-project reassignment before the respective fixes. These RED outputs were not captured by
make evidence, so this card does not use them as formal evidence. - SELF receipt
/tmp/backend-w9-go-test-20261014-01.json:go test ./..., exit 0, run on the pre-commit worktree based on R0. - SELF receipt
/tmp/backend-w9-build-20261014-01.json:CGO_ENABLED=0 go build ./cmd/agent-system, exit 0, run on that pre-commit tree. Generated local binary removed after the build. - SELF PostgreSQL receipt
/tmp/backend-w9-pg-cutoff-20261014-01.json: isolated PostgreSQL 18.6 instance on port 55442 reproduced a low-ID transaction committing after a higher visible ID./tmp/backend-w9-pg-link-20261014-02.jsonverifies the new link table, retry/conflict behavior, and the cutoff counterexample against isolated schemas. Both exited 0. The current PG cutoff means onlyoffset-upper-bound-only; it is not a fixed historical visibility snapshot or safe incremental cursor. - SELF PostgreSQL receipt
/tmp/backend-w9-pg-migrate-20261014-01.json: isolated SQLite→PostgreSQL migration preserved one linked receipt and advanced its target sequence; the same migration ID replayed idempotently. The temporary PG instance was stopped and removed after verification. - SELF PostgreSQL receipt
/tmp/backend-w9-pg-operation-20261014-01.json: a fresh isolated PG instance reran the link lookup, idempotency/conflict, and low-ID late-commit checks after trusted operation-offset resolution was added. The instance was stopped and removed. - Integration constraint: this branch uses schema v31 (audit attribution) and v32 (links), while the independent W6 Backend branch also has a local v31. Neither branch has consumed the other's unmerged work. After the first branch lands, the later branch owner must sync the new main, renumber its unpublished migrations without rewriting an already released version, and rerun fresh/old SQLite and PG migration plus combined regression on the actual merged source. These isolated tests do not prove W6+W9 compatibility.
- Required next W9 work: add a committed-order waterline or materialize the authorized ID set at the first read, then prove with PG low-ID late commits that history and cross-page incremental reads neither omit nor duplicate operations. The Backend project-event source, actual RDM committed-event verifier/outbox consumer, run ID propagation from command dispatch, model/tool/background receipts, body/detail disclosure, broad authorized list pagination, history/export, and combined product verification remain unfinished. A domain commit followed by a lost Backend audit append leaves the link pending; recovery must retain and reconcile that unknown state without claiming a host receipt. The exact-link slice is not Stage 7 audit acceptance.