Emerson attachment command prepared with isolated rollback and retry evidence
Prepared artifact
Coaching prepared scripts/repair-emerson-person-link.ts and a modules/coach-person-link module for the single existing-record attachment. The command hardcodes Emerson's Coach coa_3ff0f8c9-f8cf-444d-b1d0-e06d3f84c37d, Organization org_01900000-0000-7000-8000-000000000001, expected name, and expected null Person reference. It accepts an approved canonical Person ID, Platform mapping memo reference, audit actor, explicit database environment file, and explicit Platform origin. It defaults to preview. Apply requires the row timestamp returned by the reviewed preview.
The existing Platform Person-by-ID GET is read fresh using an operator session cookie supplied only through COACHING_REPAIR_PLATFORM_COOKIE. The read rejects absent authorization, failed reads, redirects, insecure remote origins, malformed or unnamed records, archived or merged records, a returned ID different from the supplied canonical ID, and an incompatible display name. No mint or name-patch operation is called. Contact values, auth cookies, and upstream error bodies are not printed.
Preview uses a database-enforced read-only transaction and does not run a schema-compatibility ALTER or touch audit rows. Apply locks the exact Coach row, checks the expected Person reference and reviewed timestamp, checks Person-and-Organization role uniqueness, and uses a reference compare-and-set update. The real unique constraint arbitrates races after the precheck. Only person_id and the normal row update timestamp change; a coach.person_link.repair audit is appended in the same transaction with before/after Person references and the approved mapping memo ID. An audit failure rolls back the link. The same already-applied canonical mapping returns a no-op without another update or audit. A changed Person link or unrelated row edit since preview requires review.
Review commands
Run from the Coaching repository. The operator must supply an authorized Platform session cookie through the environment without printing it. The canonical ID and mapping memo do not exist yet; the placeholders below deliberately cannot pass input validation. This is a reviewable command, not authorization to apply it.
npx tsx scripts/repair-emerson-person-link.ts --database-env-file .env --platform-base-url https://platform.sguildswim.com --person-id "<APPROVED_CANONICAL_PERSON_ID>" --mapping-reference "<PLATFORM_MAPPING_MEMO_ID>" --actor "<APPROVED_AUDIT_ACTOR>"
After Platform supplies the canonical mapping and the operator approves the exact production repair, rerun the reviewed command with --apply --expected-updated-at "<TIMESTAMP_FROM_REVIEWED_PREVIEW>". Retain the result's audit ID and linked Coach/Person IDs. Rerun the same apply inputs to verify already_attached and no second audit. The timestamp guard makes an obsolete preview fail closed rather than applying to changed Coach facts.
Isolated verification
npm test passed all 143 tests across 16 files, including 11 new canonical-read tests and three new service-guard tests. npm run typecheck passed. No subscriber path changed, so subscriber smoke was not required.
npx tsx scripts/test-coach-person-link-repair.ts passed seven grouped database checks using random Coach and Organization fixture IDs on the explicitly local platform_local database and a local HTTP fixture implementing the existing Person read path. It refuses a nonlocal or non-test database target, writes no Platform database rows, and cleans up only its own fixture IDs.
The checks establish: preview leaves the Coach, availability, and audit unchanged; wrong Organization, archived Person, incompatible name, conflicting role, and stale timestamp reject; injected audit failure rolls back the link; a competing role committed after precheck is rejected by PostgreSQL's real uniqueness constraint; a changed Person reference refuses repair; concurrent same-Coach applies serialize to one attachment and one no-op; and the successful attachment changes only Person reference and update timestamp, preserves every other Coach column plus availability template/exception and original creation audit, appends one repair audit, and is a no-op on rerun.
This is isolated local proof with a synthetic Person-read fixture. It is not evidence of a production canonical mapping, a real authenticated production Person read, a production attachment, or Sales selector success.
Source and release state
New Coaching paths are lib/platform-person-read.ts, lib/platform-person-read.test.ts, the seven canonical source/test files under modules/coach-person-link/, scripts/repair-emerson-person-link.ts, and scripts/test-coach-person-link-repair.ts. They are prepared in the Coaching working tree for review. No Coaching code commit, push, deployment, or production mutation was performed in this preparation turn. Existing availability edits were preserved; generated typecheck state was restored to its previously clean tracked state.
Platform's coordinator reported zero canonical candidates and a read-only bridge dry-run result of would_mint=1. That report does not supply a canonical Person ID. The original event:emerson-platform-person-mapping-ready, adr:0051, and event:coach-person-resolution-interface-ready gates remain unchanged. This memo closes no implementation commitment and clears no release or Sales verification gate. Portal creation integration remains a separate deliverable waiting on the approved resolution interface.