4.4 KiB
4.4 KiB
Task 10 — Workspace Registry Manager Publish UX
Delivered
- Added a typed
WorkspacePublishDialogwith 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.commitandactual.bloband 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.headcommit, and whitelisted every canonicaldiagnostics.*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.
Review round 2
- Fixed recursive registry diffs so add/remove changes to optional nested diagnostics branches
report their actual canonical paths instead of the fallback
workspace.id. The regression cases cover both add and remove fordiagnostics.dwh_restanddiagnostics.vector_rest.reversible_probe. - Extended the conflict-path allowlist to accept the optional
diagnosticsroot and every optional diagnostics branch. The existing structural rebase now saves an explicitly selected branch (including an added or removed branch) in the revised browser draft, still pinned to the registry's actual revision and requiring normal validation and confirmation before publishing. - Wrote the backend/frontend cases first and observed the expected RED failures: backend conflict
fields were
workspace.id, while the frontend rejected the safe conflict payload before the resolution UI could render.
Verification
Run in frontend/ after the final changes:
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
npx vitest run
# 51 files passed, 398 tests passed
Round-2 focused verification:
backend: npx vitest run test/workspace-registry.test.ts
# 1 file passed, 23 tests passed
backend: npx tsc --noEmit -p .
# exit 0
frontend: npx vitest run
# 51 files passed, 398 tests passed
frontend: npx tsc -b
# exit 0
The full backend npx vitest run was also attempted after allowing its local SSE test socket.
The Task 10 registry tests passed, but seven unchanged SSE/session tests fail because their
default, unbootstrapped registry makes session authorization return the intentional
session storage is unavailable response. This failure is outside the Task 10 diff; it persists
without any changed Task 10 route or test-harness code.