Repository navigation
feat(spec)!: retire the ADR-0078 conversion-conflict channel — onConflict / reservedNodeTypes, the notice types, the conflicts arrays and the FLOW_CONVERSION_CONFLICT 409 - #24045
Conversation
…selines pending) Claude-Session: https://claude.ai/code/session_01WdZxJadrrYettvjrqiWeAV Co-authored-by: Claude <noreply@anthropic.com>
…s for the conflict-channel retirement Claude-Session: https://claude.ai/code/session_01WdZxJadrrYettvjrqiWeAV Co-authored-by: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WdZxJadrrYettvjrqiWeAV Co-authored-by: Claude <noreply@anthropic.com>
…upgrade-guide projection Claude-Session: https://claude.ai/code/session_01WdZxJadrrYettvjrqiWeAV Co-authored-by: Claude <noreply@anthropic.com>
…nversion-conflict-retire
📓 Docs Drift CheckThis PR changes 5 package(s): 27 hand-written doc(s) name something this change touched — list omitted above 15 rows. Re-derive on the tree named below: ⛔ 9 release-owned page(s) also affected — read-only, see AGENTS.md Documentation Guardrails. What this run could not see
Coarse fallback — 152 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): Which tree this was computed onThis run read A worktree cut from an older # while this PR is open — GitHub drops the merge commit once it closes
git fetch origin 27f33f9bd55019ff8ad0c8cdec4ce61b3bc4197d && git checkout 27f33f9bd55019ff8ad0c8cdec4ce61b3bc4197d
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin c4111c676aed66f12b7af06e73c2ce46899f1ae5 6f0bca9671b5139dfa750979304ce2a553388731 && git checkout -B drift-repro c4111c676aed66f12b7af06e73c2ce46899f1ae5 && git merge --no-ff 6f0bca9671b5139dfa750979304ce2a553388731
node scripts/docs-audit/affected-docs.mjs --json c4111c676aed66f12b7af06e73c2ce46899f1ae5
|
Contract reviewServed-tier: Inputs: card #24001 (body; comments 6221525633, 6222477086, 6224904559); PR #24045 (body, 32-file list, net diff against the merge-base ① Derived judgmentsIndependently measured on
Governed surfaces: none in the file list ( Remainder of the diff, the lane seat's ACCEPT at ② Semver level
③ Boundary flagsDev deviations (report 6224904559), each answered:
Open question 1 — the ledger's "Retiring a code" precondition (no consumer in objectui or cloud reads the literal), objectui measured clean, cloud NOT MEASURED:
Out-of-scope finding (#23986's Check-runs on the head, re-read before rendering: 41, all completed — 36 success, 5 skipped by filter or opt-in (Temporal Conformance, Dogfood Regression Gate matrix, Dogfood Verify CLI, Console Pin Gate, Packed-tarball smoke), 0 failure, 0 in progress. Nothing NOT MEASURED. Implemented-by: VERDICT: PASS |
Review: ACCEPT · #24001 · PR #24045 @
|
Fixes #24001
Clause-②: yes (narrowing)
What this does
Retires ADR-0078's conversion-conflict channel, which has had no producer since #23543 F5-http (PR #23954) reserved the three old callout node types (
FLOW_RESERVED_NODE_TYPES). Per the card's "Reader who acts" and triage6221525633:@objectstack/spec: the root exportsCONVERSION_CONFLICT_CODE,ConversionConflictNotice,ConversionConflictDetailleave;ApplyConversionsOptionslosesonConflict/reservedNodeTypes(and soStoredConversionOptions),ConversionContextlosesreservedNodeTypes/reportConflict,IAutomationService.canonicalizeStoredFlow's result losesconflicts.api-surface/root.jsonandexport-origins/root.jsonregenerated (−3 each);declaration-map/did not move (check:generated: all 14 current).FLOW_CONVERSION_CONFLICTcomes out ofERROR_CODE_LEDGERby the ledger's own "Retiring a code" rule ("A row whose last EMITTER is deleted comes out with it"; precedentOVERLAY_PERSISTENCE_FAILED).retired-error-codes.tsis NOT used: that table is forStandardErrorCodecatalogue members only (finding: QUOTA_EXCEEDED and CONCURRENT_LIMIT_EXCEEDED are registered StandardErrorCode members with zero producers — an ADR-0049 enforce-or-remove decision #17707'sCONCURRENT_LIMIT_EXCEEDED), and this is a ledger row. The error catalog's 409 row is the generatedcontent/docs/references/api/{contract,error-code-ledger}.mdxentry (regenerated bygen:docs);content/docs/api/error-catalog.mdxnever listed it.OS_METADATA_CONVERSION_CONFLICTforeign-vocabularyrow (its stamp site inapply.tsis gone) is deleted; the running-log comments no longer spell the retired code.@objectstack/service-automation:canonicalizeFlow/canonicalizeStoredFlowno longer build the live-name set or collectconflicts;plugin.ts's inert-mode rationale is restated for what still needs the registry (the registration preview's descriptor checks).@objectstack/metadata-protocol:StoredFlowCanonicalizationlosesconflicts; four consumer branches go — the save door's 409, the stored-migration pass'sfailedrow,duplicatePackage's failed item andimportUnmanagedPackage's 409 — with their docblocks.conversion-conflict-channel-removed(no D2 conversion, no tombstone: no metadata document ever carried any of it). One BREAKINGminorchangeset with FROM → TO, markeradr-0087: registered conversion-conflict-channel-removed.FLOW_RESERVED_NODE_TYPESand the F5-http reservation are untouched.Hypothesis 1 — zero producers (measured on
origin/mainfd9664ffac, before any edit)git grep -n -E 'reportConflict\(|onConflict|reservedNodeTypes|ConversionConflictNotice|ConversionConflictDetail|FLOW_CONVERSION_CONFLICT|ConversionConflict'(excludingCHANGELOG.md), plusCONVERSION_CONFLICT_CODE|OS_METADATA_CONVERSION_CONFLICTandreportConflict|\.conflicts\b:packages/spec/src/conversions/types.ts:37CONVERSION_CONFLICT_CODE,:96ConversionConflictDetail,:110ConversionConflictNotice,:178-:180context memberspackages/spec/src/conversions/apply.ts:70/:96options,:139,:158-:168thereportConflictbridgepackages/spec/src/conversions/index.ts:13,17,18packages/spec/src/contracts/automation-service.ts:20,857packages/spec/src/conversions/registry.ts:84packages/services/service-automation/src/engine.ts:70,4528,4575,4609-4628packages/metadata-protocol/src/protocol.ts:23077(save door 409),:24168(stored pass),:27555(duplicatePackage),:27829/:27853(unmanaged import 409);stored-migration.ts:60packages/runtime/src/dispatcher-error-vocabulary.ts:292,598,672onConflicthits inautomation/execution.zod.ts,data/data-engine.zod.ts,driver-sql,types/unbacked-conflict-target.ts,check-tenant-chokepoint.mjsProducer of a conflict = a conversion entry calling
context.reportConflict: zero. NoMetadataConversion.applyreadscontextfor it;flow-node-http-callout-rename'sapply(stack, emit)takes no context at all. No fork, so the hard delete proceeded.Cross-repo:
objectuiat the pinned.objectui-shaf8267df9and at its HEAD360e27a— 0 hits for all seven spellings, controldefineStacklit (38 / 37 files).cloudis private and was NOT MEASURED (the ledger rule asks for it; see the report's open question).Pins (one per retired export / code), all in
packages/spec/src/conversions/conversion-conflict-channel-retirement.test.ts§1 … every retired name has ZERO holders on any public entry, and the survivors still stand on the root—CONVERSION_CONFLICT_CODE,ConversionConflictNotice,ConversionConflictDetailby resolved symbol identity (export-origins/), survivorsCONVERSION_TODO_CODE,ConversionTodoNotice,ConversionContext, … present.§1 … the runtime barrel resolves without the retired constant and keeps its TODO twin.§1 … the D3 semantic entry is registered on step 18.§2 … the retired members are absent at the type level, the surviving ones present—onConflict,reservedNodeTypes(options and context),reportConflict, the result'sconflicts; compiled bycheck:test-typecheck.§3 … ErrorCode no longer parses it, and no owner lists it—FLOW_CONVERSION_CONFLICT, withDEFAULT_RECORD_PAGE_CONFLICT/CONCURRENT_UPDATEas lit controls.tree-scoped absence … no retired spelling survives inside the declared radius outside the retirement kit— all seven spellings overpackages/examples/skills/content/scripts(the spec: the rest of the incident-response, training and change-management families — every remaining key and all fifteen defs — has zero readers; whole-def enforce-or-remove is the open question left after #14477 #15513 radius, this file added as a witness on eachheldByrow inscripts/cross-package-test-inputs.mjs, and invitest.repo-tests.json). Excluded: the pin itself,packages/spec/src/migrations/(the D3 entry), the git-ignored generatedcontent/docs/protocol-upgrade/(the D3 registry's projection),content/docs/releases/,.changeset/,CHANGELOG.md.Ablation (one, on the pin file)
Restored the deleted export in
packages/spec/src/conversions/index.tsthroughscripts/ablation-replace.mjs(anchor 1 → 0, blob630ed35f→2bec0047), ran the pin file: 2 failed / 4 passed —the runtime barrel resolves without the retired constant…and the tree-scoped absence (offendersindex.ts spells CONVERSION_CONFLICT_CODE/OS_METADATA_CONVERSION_CONFLICT). Theexport-originsholder pin stayed green, as it must: it reads the committed artifact, which the source mutation does not regenerate (check:export-originsis that half's gate). Restored: blob == HEAD630ed35f,git diff HEADempty; re-run 6 / 6 passed. A first attempt was a no-op — its replacement contained its own anchor, so the tool refused (count 1 → 1) and ran nothing; it is not counted.The ablation also surfaced a real gap, fixed before push: the git-ignored upgrade-guide page
content/docs/protocol-upgrade/18.md, once generated locally, prints the D3 entry verbatim, so the scan now excludes that projection like the registry it projects.Serial constraint (hypothesis 5)
PR #23986 (#23903) also edits
protocol.ts: its hunks sit at theflowSaveReplaysRetireddocblock/body (~6612–6700) and the save door's comment and fallback lines (~23025–23115). This PR's save-door hunk is theresult.conflictsbranch below them (~23077–23094 at the base) plus three other doors. Disjoint: each lands on its own, and whichever lands second mergesmain. #23986's new test builds its canonicalizer stub withconflicts: []as a standalone arrow (no contextual type, so no excess-property check): it should still compile after this lands, as a dead key — whichever lands second re-runs that suite on the merge. #24010's three lines are in the package door, not touched here.Acceptance notes
packages/cli/src/commands/migrate/meta.ts,packages/cli/src/utils/data-migration-plugins.ts(comments that justified the inert engine by the conflict guard) andcontent/docs/deployment/cli.mdx(the "flow whose rename the conflict guard refused" decline row and two sentences) — each described a failure mode this PR removes.packages/metadata-protocol/src/stored-migration.tsis theStoredFlowCanonicalizationdeclaration the claim's "the contract'sconflictsarrays" names.scripts/cross-package-test-inputs.mjsandpackages/spec/vitest.repo-tests.jsondeclare the new pin's radius.a refused rename fails the item…,a refused rename fails the save loudly…,the conflict path stays silent — the 409 IS the signal,fails the row loudly when the guard refuses a rename over a live name): each constructed a conflict through a test double and asserted the branch this PR deletes.skippedreason for a flow with no engine is reworded (it named the conflict guard); no test pins its prose.claude/issue-24001-adr-0078-note).Verification
Reported in full in the
os-dev-reportcomment on #24001 (local gate union with exit codes, reconciled--ran139/139; per-packagepnpm test).🤖 Generated with Claude Code
https://claude.ai/code/session_01WdZxJadrrYettvjrqiWeAV
Generated by Claude Code