Skip to content

feat(metadata-protocol/objectql): turn-atomic package publish — a commit cannot half-land (ADR-0067 D2, #3066)#3074

Merged
os-zhuang merged 3 commits into
mainfrom
claude/auth-model-design-eval-xxgzcl
Jul 16, 2026
Merged

feat(metadata-protocol/objectql): turn-atomic package publish — a commit cannot half-land (ADR-0067 D2, #3066)#3074
os-zhuang merged 3 commits into
mainfrom
claude/auth-model-design-eval-xxgzcl

Conversation

@os-zhuang

Copy link
Copy Markdown
Contributor

Summary

Implements ADR-0067 Decision-2 per the design in #3066: package-draft publishing is now all-or-nothing. Previously publishPackageDrafts promoted drafts per-item with catch-and-continue — a mid-batch failure left earlier items live and later ones unpublished, and the commit record described the partial landing. For AI-authored batches this was a main-path risk: a metadata state nobody reviewed.

Design (two-phase publish)

Phase 1 — atomic metadata writes. Every draft promotion AND the sys_metadata_commit record run inside ONE engine.transaction(). Any failure → the whole batch rolls back → publishedCount: 0; the causal item carries its real error/code/issues, every other draft reports code: 'batch_aborted'. The commit row and the state it describes land or roll back together — a recorded commit can never describe a partial publish.

Phase 2 — post-commit side effects. Registry refresh, table DDL, batched seed apply, ADR-0086 P2 materializers, ADR-0094 projections, mutation events — per item, after the metadata committed. Deliberately outside the transaction: DDL can't run inside the driver tx (deadlocks the single-connection SQLite pool), in-memory registry writes can't roll back, and projections are boot-healed. A side-effect failure is surfaced via materializeApplied.failures, never turned into a fake unpublish (the metadata IS live).

Key changes

  • metadata-protocol: publishMetaItem split into promoteDraftForPublish (guards + promote, metadata-only) and runPublishSideEffects; single-item behavior unchanged. publishPackageDrafts rewritten to the two-phase flow; recordPackageCommit moved inside the transaction (it stays internally best-effort, so a commit-store hiccup doesn't abort a good batch).
  • objectql: engine.transaction() now JOINS an already-open ambient transaction instead of opening a nested driver transaction — a nested begin deadlocks single-connection pools and escapes the outer rollback. This is what lets the repository's withTxn (promoteDraft's put + draft-delete) participate in the batch transaction unchanged — and closes promoteDraft's old best-effort draft-delete gap for free.
  • Fallback: engines without transaction() (memory driver, minimal stubs) keep the previous sequential behavior — same stance as the repo's withTxn.

BREAKING (behavioral, release-notes)

API consumers relying on partial batch publishes ("2 of 3 landed") now get all-or-nothing. The response shape is unchanged; failed[] now enumerates the causal item plus batch_aborted entries.

Also in this PR

The concurrent #3037 restructure (packages/dogfoodpackages/qa/dogfood) didn't carry #3065's three just-merged search-conformance files — they were orphaned outside every workspace (silently not running in CI). Moved to packages/qa/dogfood/test/; all 5 dogfood suites green at the new home.

Test plan

  • objectql: 904/904 (publish contract suite rewritten to the two-phase seams: +4 cases incl. transaction rollback/commit tracking, batch_aborted shape, side-effect-failure surfacing; commit-history + build-probes suites migrated; 2 new ambient-join engine tests incl. nested-throw → outer rollback).
  • metadata-protocol: 29/29.
  • dogfood (packages/qa/dogfood): search-conformance + showcase-search + two-doors-permission + showcase-permission-projection + showcase-permission-seeding — 21/21 (real kernel boot, the publish→materialize→project chain exercised end-to-end).
  • ESLint clean on all changed files. Changeset included (minor ×2, BREAKING noted).

Closes #3066.

🤖 Generated with Claude Code


Generated by Claude Code

claude added 2 commits July 16, 2026 15:13
…67 D2, #3066)

Phase 1: every draft promotion + the sys_metadata_commit record run inside
ONE engine.transaction() — a mid-batch failure rolls back everything
(publishedCount 0; causal item carries its real error, the rest report
batch_aborted). publishMetaItem is split into promoteDraftForPublish
(guards + promote, metadata-only) and runPublishSideEffects so the batch
can transact promotions while deferring side effects.

Phase 2 (post-commit): registry refresh, DDL, seed batch apply,
materializers, ADR-0094 projections, events — best-effort, surfaced via
materializeApplied.failures instead of faking an unpublish (metadata is
live; boot reconciliation heals side-effect drift).

objectql: engine.transaction() now JOINS an already-open ambient
transaction instead of opening a nested driver transaction — a nested
begin deadlocks single-connection pools (SQLite knex) and escapes the
outer rollback. Locked by two new engine-ambient-transaction tests.

BREAKING (behavioral): consumers relying on partial batch publishes now
get all-or-nothing. Engines without transaction() keep the previous
sequential behavior (same fallback stance as the repo's withTxn).

Tests: publish contract suite rewritten to the two-phase seams (+4 new
cases incl. rollback/commit tracking and side-effect-failure surfacing);
commit-history suite updated; 29 green across the three suites.
…aned search-conformance files

- build-probes.test.ts publish suite: spy promoteDraftForPublish +
  runPublishSideEffects (the batch no longer calls publishMetaItem per
  item, ADR-0067 D2). objectql suite back to 904/904.
- The #3037 packages/dogfood -> packages/qa/dogfood restructure merged
  concurrently with #3065 and did not carry its three just-added files;
  they were orphaned at the old path outside every workspace (silently
  not running in CI). git mv them to packages/qa/dogfood/test — all 5
  dogfood suites green at the new home (21 tests).
@vercel

vercel Bot commented Jul 16, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
spec Canceled Canceled Jul 16, 2026 3:26pm

Request Review

@github-actions github-actions Bot added documentation Improvements or additions to documentation tests tooling size/l labels Jul 16, 2026
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 3 package(s): @objectstack/metadata-protocol, @objectstack/objectql, packages/qa.

15 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:

  • content/docs/concepts/metadata-lifecycle.mdx (via @objectstack/metadata-protocol, @objectstack/objectql)
  • content/docs/data-modeling/formulas.mdx (via packages/objectql)
  • content/docs/deployment/migration-from-objectql.mdx (via @objectstack/objectql)
  • content/docs/deployment/vercel.mdx (via @objectstack/objectql)
  • content/docs/kernel/services-checklist.mdx (via @objectstack/objectql)
  • content/docs/kernel/services.mdx (via @objectstack/objectql)
  • content/docs/permissions/authentication.mdx (via @objectstack/objectql)
  • content/docs/permissions/authorization.mdx (via packages/qa)
  • content/docs/permissions/delegated-administration.mdx (via packages/qa)
  • content/docs/plugins/index.mdx (via @objectstack/objectql)
  • content/docs/plugins/packages.mdx (via @objectstack/objectql)
  • content/docs/protocol/kernel/index.mdx (via @objectstack/objectql)
  • content/docs/protocol/objectql/state-machine.mdx (via @objectstack/objectql)
  • content/docs/releases/implementation-status.mdx (via @objectstack/objectql)
  • content/docs/releases/v9.mdx (via @objectstack/objectql)

Advisory only. To re-verify, run the docs-accuracy-audit workflow scoped to these files:
node scripts/docs-audit/affected-docs.mjs origin/main → pass the list as args.docs.

@os-zhuang os-zhuang marked this pull request as ready for review July 16, 2026 15:34
@os-zhuang os-zhuang merged commit d75c7ac into main Jul 16, 2026
17 checks passed
@os-zhuang os-zhuang deleted the claude/auth-model-design-eval-xxgzcl branch July 16, 2026 15:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation size/l tests tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

ADR-0067 Decision-2 unimplemented: package-draft publish is not turn-atomic — a commit CAN half-land

2 participants