Repository navigation
MST/2 T05: wire the remaining publication writers (CL merge, attach, import receive-pack, import registry) #14
Description
Context
The MST/2 publication model (spec 09) is implemented up to one writer:
src/ceres/snapshot/publication.rs— coordinator core: canonical operation id,
expected-old CAS, read-set predicates, writer-epoch fence, immutable receipt,
outbox, idempotent replay.src/callisto/mst2_publication.rs,mst2_publication_outbox.rsand
src/jupiter/migration/m20260917_000200_add_mst2_publication.rs— tables
(operation_idunique, per-namespace sequence inmst2_namespace_seq).MonoStorage::record_publication_in_txn/publication_sequence
(src/jupiter/storage/mono_storage.rs) — bump the namespace sequence with
INSERT … ON CONFLICT … RETURNING, write the receipt and append the outbox
row inside the caller's transaction.PushQueueService::b3_execute_push_inner(src/jupiter/service/push_queue_service.rs)
— records the publication in the same transaction as the root CAS and
mark_done, which is the trunk-push path.
Everything is behind mst2.publication_enabled (default off), so an
unconfigured deployment is unchanged.
Already covered, do not re-wire: the Web write endpoints (/create-entry,
/edit/save in src/api/router/preview_router.rs) go through
land_api_tip_push → push queue → the same B3 path, so they publish correctly
today.
Scope
Wire the remaining entry points in the spec 09 §5 writer matrix. The pattern in
each case is the same: call record_publication_in_txn inside the
transaction that already performs the visible ref mutation, with a
deterministic operation id.
| Writer | Entry point | Transaction to join | Operation id source |
|---|---|---|---|
| CL merge into trunk | PushQueueService::b3_execute_merge_inner (src/jupiter/service/push_queue_service.rs) |
the merge executor's txn (it writes the root via apply_push_in_txn/descendant advance) |
merge_operation_id(cl_link) (already exists) |
| Repo/kind attach to the monorepo parent | b3_execute_attach_inner (same file) |
its txn (attach_to_monorepo_parent_in_txn) |
attach_operation_id(repo_id, normalized_commands) (already exists) |
| Import receive-pack | src/ceres/pack/import_repo.rs (update_refs / finalize path) |
the ref-update transaction for the selected ref | import push identity (define; must be stable across retries) |
| Import registry add/remove/path change | import registry service + src/ceres/pack/import_repo.rs |
binding update transaction | registry revision |
| Tag / release management | src/api/router/tag_router.rs |
— (see note) | tag name + target oid |
Note on tags: tags do not advance the served default namespace, so their
publication is only meaningful once the immutable-release policy exists
(spec 09 §5 "tag/release管理"). Treat that row as blocked on the release
policy registry rather than doing it piecemeal.
Note on admin/backfill: any tool that can change a visible root must run
through the same plan; today they bypass it. The deliverable is either (a)
routing them through land_api_tip_push, or (b) refusing to start while
mst2.publication_enabled is true and a maintenance epoch is not held.
Acceptance
- For each wired writer: a test that performs the real operation twice with the
same operation id and asserts one receipt, one sequence advance and one
outbox row (idempotent replay, PUB-11). - A test that runs two writers concurrently against the same expected-old and
asserts exactly one wins and the loser getsCONFLICT(409) and no ref move. - A test that injects a failure between the object write and the DB commit and
asserts no publication exists afterwards. - PUB-01..12 from spec 16 §4, with the writer named in each case.
- Only after all of the above: consider flipping
publication_enabledper the
spec 09 §9 rollout (shadow comparison + maintenance window with all writers
stopped).
References
- Spec 09 §§1–5, §9 (
Mega_ScorpioFS_MST2_Specs_0.2.1,specs/09-…md) - Spec 16 §4 PUB-01..12
- Existing pattern to copy:
b3_execute_push_inner
Activity