# Task 10 — Workspace Registry Manager Publish UX ## Delivered - Added a typed `WorkspacePublishDialog` with an explicit two-stage flow: validate the canonical draft, then confirm publication. The dialog displays the action and pinned base revision before a request can be sent. - Connected the workspace editor's Publish action and staged deletion action to that dialog; local browser drafts remain local until the explicit confirmation. - Added registry pull, workspace bundle import, and Blob-URL export controls. Imports are saved as browser-only drafts and never publish automatically; export URLs are revoked after download. - Added field-level 409 conflict presentation with base, local, and registry values. The only recovery actions are Pull latest registry and Reload workspace; no automatic merge, overwrite, or re-publication occurs. - Kept diagnostics user-initiated and restricted UI/API draft data to canonical workspace fields. Conflict payloads now pass through the canonical draft sanitizer and reject unknown/secret fields before rendering. ## Review round 1 - Replaced the pull/reload-only conflict recovery with an explicit choice of the local draft or registry value for every changed field. A revised draft can be saved only after every field has a choice; it is rebased to the conflict's `actual.commit` and `actual.blob` and is never published automatically. - Kept normal validation and the explicit publish confirmation as mandatory steps after saving a resolution. Nothing silently discards the local draft or merges it into the registry. - Added typed expected/actual conflict revisions, displayed the active registry `status.head` commit, and whitelisted every canonical `diagnostics.*` leaf path structurally. ## TDD evidence - Wrote the publish-dialog and manager import/export tests before the implementation and observed the expected RED failures (missing dialog/import control). - Added a regression test for conflict payloads containing a secret field and observed it fail before wiring the conflict parser through the canonical sanitizer. - Added a regression test for a failed pull during conflict recovery and observed the original unhandled rejection before adding the redacted in-dialog error state. - Added review-round tests first for per-field local/registry selection, rebased draft saving without a second publish, active-commit rendering, and every canonical diagnostics conflict path; these initially failed against the pull/reload-only UI and narrow path parser. ## Verification Run in `frontend/` after the final changes: ```text npx vitest run src/shell/WorkspacePublishDialog.test.tsx src/api/workspaces.test.ts src/shell/WorkspaceManager.test.tsx src/workspaces/drafts.test.ts # 4 files passed, 47 tests passed npx tsc -b # exit 0 ``` ```text npx vitest run # 51 files passed, 392 tests passed ```