…back pair and delete ActionCallback (objectui#7068)
`@object-ui/types` published a THIRD meaning of `onSuccess`: the legacy
`crud.ts` `ActionSchema` carried `onSuccess?` / `onFailure?` as Phase-2
`ActionCallback` objects, zod-mirrored and taught by two docs pages, with zero
producers outside the package's own fixture and zero runtime readers, while
`@objectstack/spec`'s `ActionSchema` refuses the shape at publish. Maintainer
ruling option 1 (2026-09-05): retire it, both faces, docs in the same PR.
- crud.ts: `ActionCallback` DELETED (the objectui#7664 / PR #7743 route for a
standalone retired type); `onSuccess?: never` / `onFailure?: never` with the
RETIRED docblocks — tombstones, not deletions, because `BaseSchema`'s index
signature would admit a deleted key
- crud.zod.ts: `ActionCallbackSchema` and its inferred alias DELETED; the two keys
are `retirementTombstone()` named refusals whose guidance names the spec's
`{ navigate, openIn }` block on `UIActionSchema` and `successMessage` /
`errorMessage`
- both barrels drop the two names; parity ledger drops the pair
(`EXPECTED_MIRROR_PAIRS` 159 -> 158, header chain extended); the 7340 handler
census records the two new `on*?: never` members (26 -> 28, `onFailure` in
the name net)
- phase2-schemas fixture no longer authors the callback shape; new pin
action-callback-retired-7068: both faces refuse at path with the guidance
(direct, via DetailSchema.actions, via the union door), base-vs-extended
contrast on both faces, neighbours stay legal, absence of the deleted names
(barrel object + AST), spec comparison (refuses the callback shape, accepts
the navigation block), docs corpus scan, tsc legs
- docs: the three enhanced-actions.mdx fences author successMessage /
errorMessage; "Callbacks" becomes a "Post-success behaviour" note (no fence);
schema-overview.md fragment / bullet / checklist row rewritten; the stale
doc-types `message` exemption removed
- changeset (types minor, "Breaking for authored metadata")
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BAZFhALsQsGqxui8sNqM8s
Fixes #7068
Retires the THIRD meaning of
onSuccessthat@object-ui/typespublished: the legacycrud.tsActionSchema's Phase-2 callback paironSuccess/onFailure(each anActionCallbackobject), its zod mirror, and the two docs pages that taught the shape — in one PR, because the docs fences compile against the type. Maintainer ruling option 1 (2026-09-05, verbatim 「其他同意」, record comment 5555360195). Clause-② yes: a published accept set narrows on both faces. Contract-review tier.Premise, re-verified on
900f8d99(branch base)packages/types/src/crud.ts:29export interface ActionCallback;:163/:167onSuccess?: ActionCallback/onFailure?: ActionCallbackon the legacyActionSchema.zod/crud.zod.ts:33ActionCallbackSchema,:98/:99the two keys,:187the inferred alias. Barrelsindex.ts:892,zod/index.zod.ts:287. Parity ledger rowszod-mirror-parity.test.ts:597/:760.git grep -l ActionCallbackoverpackages content skillshits exactly the fivepackages/typesfiles; positive controlSchemaNodeSchemahits 22 files, so the zero is a reading. The repo-wideonSuccess: { type: … }hits outside those are runner-sideActionDeftests (packages/core,packages/app-shell) — the SECOND meaning,{ type: 'notify' }action defs, notActionCallbackproducers.ActionRunner.tsimports onlyRunnableActionType/UIActionSchemafrom@object-ui/types; itsonFailuresits on its ownActionDef(the second meaning). Stop condition 2 does not fire.content/docs/core/enhanced-actions.mdx— threetsfences ("Ajax Actions", "Callbacks", "Complete Example"), all importingActionSchemafrom@object-ui/types;content/docs/guide/schema-overview.md— thedoc-snippet: fragmentblock under "Enhanced Actions", the "Key Features" bullet, the "Enhanced ActionSchema" checklist row.skills/**: the onlyonSuccesshit is a React prop onLoginForm(auth guide), not this shape — no card needed.@objectstack/spec@17.2.0:ActionSchema.safeParse({ name, label, type: 'script', target, onSuccess: { type: 'toast', message: 'x' } })is REFUSED —invalid_typeat pathonSuccess.navigate("expected string, received undefined") plusunrecognized_keysat pathonSuccess("Unrecognized key(s) on this action's onSuccess block:type,message. …").onFailure: { type: 'message', … }is REFUSED at the root —unrecognized_keysnamingonFailure.onSuccess: { navigate: '/done', openIn: 'self' }is ACCEPTED with the block preserved. So an author who wrote the docs' shape already failed at publish; this PR moves the failure to the authoring site.What moves
crud.ts:ActionCallbackDELETED;onSuccess?: never/onFailure?: neverwith the RETIRED docblocks (what it was, why it is gone, where the live meaning lives).zod/crud.zod.ts:ActionCallbackSchemaandActionCallbackSchemaTypeDELETED; the two keys areretirementTombstone(...)named refusals — one guidance string each, feeding both the parse-time message and.describe(); the guidance names the spec's{ navigate, openIn }block onUIActionSchema(objectui#5934) andsuccessMessage/errorMessage.index.tsandzod/index.zod.tsdrop the two names.zod-mirror-parity.test.ts: thecrud.zod.ts#ActionCallbackSchemarows leaveMIRRORSandDeclared(the pair had no entry in any drift ledger, so no other count moves);EXPECTED_MIRROR_PAIRS159 → 158; the header's pair-population chain gains the 159 → 158 step.component-docs-retired-handler-keys-7340.test.ts: its name-shaped census ofon*?: nevermembers reads the two new tombstones — total 26 → 28,crud.ts1 → 3,onFailureenters the "no shipped interface declares it callable" net (onSuccessstays ambiguous becauseUIActionSchema.onSuccessis live). Recorded as a ruled move with the reason, the way that pin asks.phase2-schemas.test.ts: the only in-repo producer fixture no longer authors the callback shape (it authorssuccessMessage/errorMessage); the refusal lives in the new pin.action-callback-retired-7068.test.ts(34 tests): both keys refused at path with the exact guidance — direct, throughDetailSchema.actions(pathactions.0.onSuccess), throughsafeValidateSchema's union door;.describe()carries the same string; BASE CONTROL on both faces (BaseSchemaalone accepts the same document — the tombstone shadows the passthrough / the index signature); controls (legacy action without the keys,successMessage/errorMessage,chain/redirect, a wrong-typedsuccessMessagestill refused, an undeclared key still passes through); absence of the deleted names (barrel object,crud.zod.tsmodule,crud.tsAST, barrel text); the?: nevercensus of the interface; the spec comparison pin (refuses the callback shape, refusesonFailure, accepts the navigation block); acontent/docscorpus scan; and@ts-expect-errorlegs (fresh literal, indexed member type, widened value) thattsconfig.test.jsonenforces.enhanced-actions.mdxfences authorsuccessMessage/errorMessageinstead of the callbacks; the "Callbacks" section becomes a "Post-success behaviour" note with no fence — the legacyActionSchemacarries no spec-derived post-success block (measured: its post-action keys arereload/redirect), so the note points at the spec block onUIActionSchemaand atchain.schema-overview.md: fragment line removed, feature bullet rewritten, the ✅ checklist row is now a retirement note, two prose mentions of "callbacks" corrected.scripts/check-doc-component-types.mjs: the per-file exemptionmessageforenhanced-actions.mdx("underonFailure") is removed — it went stale with the fence, and a stale exemption is exit 1 for that gate..changeset/action-callback-retired-7068.md:@object-ui/types: minor, opening "Breaking for authored metadata:".Disposition of the standalone type, and the precedent
Deleted, not tombstoned. This package's precedent for a retired standalone pair is objectui#7664 / PR #7743, which deleted the
DeclarativeKanban*trio from both faces and the barrels, removed the ledger rows, and pinned the absence (membersOf('DeclarativeKanbanSchema')throws). The key-level tombstones follow PR #7761 (TextSchema.value) and PR #7769 (TreeViewSchema.data). Four axes: no producer or reader (measured); one contract, no stub kept alive in the barrel; an import of a deleted name fails at the import line with TS2305 and an authored key fails at the site with TS2322 / a named zod refusal — both loud; immediate, no window.Before / after, both faces, read from the built dist
ActionSchema.safeParse(callback shape).success = true, also throughDetailSchema.actionsandsafeValidateSchema;ActionCallbackSchemaexported; a stricttscprobe assigningonSuccess: { type: 'toast', … }/onFailuretoActionSchemaand importingActionCallbackexits 0 (harness control on the same tsconfig: a wrong-typedlabelexits 2 with TS2322).success = falsewithinvalid_type/ expectedneveratonSuccessandonFailure, the message beginning "RETIRED (objectui#7068) — …";DetailSchemarefuses atactions.0.onSuccess/actions.0.onFailure; the union door refuses;ActionCallbackSchemaabsent from the barrel; the sametscprobe exits 2 with exactly three errors — TS2305 "no exported member 'ActionCallback'", TS2322 atonSuccess, TS2322 atonFailure; thesuccessMessage/errorMessagecontrol and a legacy action without the keys still parse.Ablation (Clause-② yes)
Subject resolved through source imports (the pin imports
../zod/crud.zod.js), so no dist leg is involved. With the implementation committed, the zod face alone was reverted to the pinned BASE commit by path (git checkout 900f8d99 -- packages/types/src/zod/crud.zod.ts), proven on disk (retirementTombstone(count 4 → 2,export const ActionCallbackSchema0 → 1, "RETIRED (objectui#7068)" 2 → 0, blob changed), then the pin and the parity ledger were run under the verify lock:VERDICT command-exit 1, 20 failed / 34 passed — the 18 zod-half legs and theActionCallbackSchemaabsence leg red, the ledger's population-closed test red, every control leg (neighbours, spec comparison, docs scan, TS half) green. Restored withgit checkout HEAD -- ABSOLUTE-PATHunder an EXIT/INT/TERM trap;git diff HEADempty,git statusclean, blob hash6dd88e95identical to HEAD's. Direction as predicted: turns red.Gates (exit captured before any pipe; heavy runs under
os-verify-lock.sh; final headbe90f812after mergingorigin/main)pnpm --filter @object-ui/types build— VERDICT command-exit 0, "dist completeness: 1 package(s) complete (124 emitted files verified)".pnpm exec vitest run --maxWorkers=2 packages/types/— VERDICT command-exit 0, "Test Files 128 passed (128) / Tests 2298 passed (2298)"; rerun onbe90f812after the merge: same figures. The new pin alone: 34 passed.pnpm --filter @object-ui/types type-check— VERDICT command-exit 0 (script nametype-checkechoed;tsc --noEmit && tsc -p tsconfig.examples.json && tsc -p tsconfig.test.json, noerror TS).@object-ui/core(VERDICT 0),@object-ui/plugin-form(VERDICT 0, 11 closure builds),@object-ui/app-shell(VERDICT 0, 28 closure builds). Every closure package'sbuildis itstsc, so 34 consumer builds green is the consumer reading; no consumer authored the retired shape.pnpm --filter @object-ui/types lint— exit 0; 274 warnings, all pre-existingno-explicit-any(the three in touched files are lines present byte-identical at BASE).pnpm check:doc-snippets— ran for real in the worktree after building the gate's own--build-filterclosure (34 tasks, 28 cached): VERDICT command-exit 0, "Semantic phase: 455 of 455 block(s) judged, 0 failed. Every covered documentation snippet compiles against the built types." Supplementary differential compile of the touched page'stsfences against the rebuilt dist: edited page 10 fences, 0 errors; BASE page 11 fences, exactly 6 errors, all TS2322 at the callback sites (fences 1, 7, 10 — two keys each) — the docs half is load-bearing.pnpm check:doc-types— exit 0 ("Every documented component type is registered"; 117 exempted after the stalemessageexemption left).pnpm check:doc-fences— exit 0.node scripts/check-doc-links.mjs— exit 0 ("Links are valid across 17 scan roots").pnpm check:control-bytes— exit 0 (6360 files).pnpm check:spec-symbols— exit 0.check-changeset-presence/-fixed/-no-major/-overwriteall exit 0, rerun after the merge.scripts/pm/check-governed-merges.mjs --testover all 12 paths): "0 of 12 path(s) hit the register … NOT governed".turbo ls --affectedlists nearly every workspace package because@object-ui/typesis a root dependency); the consumer reading above covers their type surface.Out of scope, noticed
None filed. The
.changeset/5867-plaintext-fenced-ts-batch2.mdmention ofActionCallbackis a historical changeset and stays.Related: objectui#5934 · PR #7065 · objectui#7664 / PR #7743 · PR #7761 · PR #7769 · objectui#7340 · objectui#4314. Placeholders in this body are spelled as words (the GitHub sanitizer strips angle-bracket shapes). Dev of the
domain:spec@ objectui seat's dispatch, sessionsession_01BAZFhALsQsGqxui8sNqM8s.🤖 Generated with Claude Code
https://claude.ai/code/session_01BAZFhALsQsGqxui8sNqM8s
Generated by Claude Code