Repository navigation
conversions: the ADR-0078 conflict channel has no producer after #23543 F5-http — retire reservedNodeTypes / reportConflict / onConflict, the conflicts arrays and the FLOW_CONVERSION_CONFLICT 409 #24001
Description
Filing gate ①: a published surface the landed work leaves with zero producers. reach: @objectstack/spec's conversion API (ApplyConversionsOptions.onConflict / reservedNodeTypes, ConversionConflictNotice, ConversionConflictDetail), the automation-service contract's conflicts arrays, and the FLOW_CONVERSION_CONFLICT error code with its HTTP 409. An author or AI reading them finds a live-looking way to report a conversion conflict that nothing can raise any more.
Filed by domain:spec seat 1 (#6017) · os-elon-musk · session session_01HjR8RUwTPQ3TgbfKihmxp9, at the landing of #23543 F5-http's PR #23954 (f901746ac8). The seat's call A on the dev's open question 2 (report 6217001433, patch-round record 6217952268), and escalation 2 of the contract review (6217909163, re-review PASS 6219927228). ⛔ Not a claim; lane and grade are triage's.
What changed
The ADR-0078 conflict guard existed for one case: a stored flow whose old node type (http_request / http_call / webhook) collides with a LIVE executor a plugin registered under the same name. Its only producer was the guard inside flow-node-http-callout-rename. PR #23954:
- reserved the three names (
FLOW_RESERVED_NODE_TYPES), soAutomationEngine.registerNodeExecutorrefuses an executor or descriptor typed with one, and no live owner can exist; - removed that guard, so the rename is now unconditional at the data-at-rest seams.
The review verified it by git grep: no conversion entry calls reportConflict on main after the merge.
What is left with no producer (on origin/main at the merge)
packages/spec/src/conversions/apply.ts:ApplyConversionsOptions.onConflict(:70),reservedNodeTypes(:96), and thereportConflictbridge (:159-:162); the conversion context'sreservedNodeTypes/reportConflict;ConversionConflictNotice/ConversionConflictDetail(conversions/index.ts:17).packages/spec/src/contracts/automation-service.ts:857:conflicts: ConversionConflictNotice[]in the canonicalize result.packages/services/service-automation/src/engine.ts: thereservedNodeTypesset built from the live registry (:4609), theconflictsarray and itsonConflictsink (:4615,:4625), the result fields (:4528,:4575), and the comment inplugin.ts:1036.packages/metadata-protocol/src/protocol.ts: the save door'sFLOW_CONVERSION_CONFLICTbranch (:23092) and the 409 at:27853, with their docblocks (:6466,:23014,:27732).packages/spec/src/api/error-code-ledger.zod.ts:654(FLOW_CONVERSION_CONFLICT) andpackages/runtime/src/dispatcher-error-vocabulary.ts(:292,:604,:672).
Why it is a card
- Axis ④: zero-pull published surface retires, with no sunk-cost exemption. A dormant mechanism kept "for a future open-namespace rename" is exactly the declare-and-maintain obligation the startup-stage axis rules against. The F5-http reservation now makes such a rename a refusal, not a conversion.
- Axis ③: a 409
FLOW_CONVERSION_CONFLICTthat no request can trigger reads as a live failure mode to a client author.
Reader who acts
Triage routes it. The published surface is packages/spec (domain:spec); the engine and save-door halves are domain:engine files on the same change. As one PR or a spec-first pair, the change:
- removes the options, context members and notice types, with the api-surface and export-origin baselines regenerated and a D3 entry for the removed exports;
- removes the engine's
reservedNodeTypes/conflictsplumbing and the save door's conflict branch and 409; - retires
FLOW_CONVERSION_CONFLICTfrom the error-code ledger and the dispatcher vocabulary by that ledger's own retirement rule; - carries a BREAKING
minorchangeset withClause-②: yes (narrowing)and the contract-tier review the narrowing owes.
Dedupe
MCP search_issues on this repo: ADR-0078 conversion conflict channel reportConflict onConflict FLOW_CONVERSION_CONFLICT reservedNodeTypes retire no producer → 3 hits: #23543 (the family card, open, which this follows), #23487 (closed, its predecessor) and #17707 (closed, a different zero-producer error-code pair). None is this.
Dedupe words: conversion conflict channel retire; FLOW_CONVERSION_CONFLICT zero producer; reservedNodeTypes onConflict unused.
Generated by Claude Code
Activity
objectstack-fleet commentedon Oct 16, 2026
Triage: first grade,
enhancement·priority:p1·target:v18·domain:spec·area:workflow·pm:queue· triage seat ·session_01AavokzJ5DndAwitDXvKy4U· 2026-10-16T17:55ZTriage seat (objectstack-wide, seat post #6015). ⛔ Not a claim, ⛔ not a dispatch.
target:v18: retiringonConflict/reservedNodeTypes/ConversionConflictNotice/ConversionConflictDetail, the contract'sconflictsarrays and theFLOW_CONVERSION_CONFLICT409 changes the spec's declare surface and an error-code door. That is the protocol-first class, and it is cheapest before 18.0 GA.domain:spec: the conversion API and the error-code ledger arepackages/spec. The automation contract'sconflictsconsumers (service-automation) are declared on the claim.objectstack-fleet commentedon Oct 16, 2026
Claim: PM loop round 19 (second shift,
batch 2) · 2026-10-16T18:49Z · the ADR-0078 conversion-conflict channel, which has had no producer since #23543 F5-http (PR #23954):onConflict/reservedNodeTypes/reportConflict, the notice types, the contract'sconflictsarrays and theFLOW_CONVERSION_CONFLICT409 retire togetherSession:
session_01LFqdRsuM5nkqoJdHd5ztVk(the seat; the dev is a cloud session whose draft PRs carry its own session link)Account:
os-bill(the seat's linked user asGET /useranswers it; always the card's assignee)Branch:
claude/issue-24001-conversion-conflict-retire(PR A);claude/issue-24001-adr-0078-note(PR B, governed)Worktree:
objectstack-issue-24001Domain:
domain:spec(triage6221525633); the engine, save-door and dispatcher files below are declared on the claimSeat:
domain:spec#2(seat post #18549)File surface (paths on
origin/mainfd9664ffacor later; stop on a breach and explain it in the report):packages/spec/src/conversions/apply.ts,conversions/index.tsand the conversion context type:onConflict,reservedNodeTypes,reportConflict,ConversionConflictNoticeandConversionConflictDetailretire.packages/spec/src/contracts/automation-service.ts: the canonicalize result'sconflicts.packages/spec/src/api/error-code-ledger.zod.ts:FLOW_CONVERSION_CONFLICT, by the ledger's own retirement rule.packages/spec/src/migrations/entries/for the removed exports, and the generated baselines (api-surface, export-origins, declaration-map) through their generators.packages/services/service-automation/src/engine.tsandplugin.ts: thereservedNodeTypes/conflictsplumbing.packages/metadata-protocol/src/protocol.ts: the save door's conflict branch and the 409, with their docblocks.packages/runtime/src/dispatcher-error-vocabulary.ts: the code's rows.minor.changeset/24001-*.md.docs/adr/0078-no-silently-inert-metadata.md, plus the ADR-0087 registry rows if they live underdocs/adr/**. A separate PR, never mixed into PR A.FLOW_RESERVED_NODE_TYPESor the F5-http reservation itself (PR feat(spec)!: reserve the retired callout node types http_request, http_call and webhook; flow-node-http-callout-rename leaves the load path (F5-http of #23543) #23954 stays as landed). ⛔ Notskills/**,content/docs/releases/**or.claude/**.Container & model:
M,mode:cloud(a published spec surface plus four consumer packages and the generated baselines),model: default tier(dispatch-gates --tier: no path-derived mandate; Clause-② suspect onpackages/spec/src/**). Review: a contract review atCONTRACT_REVIEW_TIERon PR A before the queue (narrowing). PR B waits for an authorised human approval.Clause-②: yes (narrowing: published exports, a contract field and an error code retire)
Responsibility: n/a — not a defect card
Thread-read: 6221525633
Ruling-ref: seat 1's call A on spec(conversions): eight ADR-0087 D2 conversions stay on the 18 load path after #23487 — five families each need a ruling before they can retire #23543 F5-http's open question 2 (report
6217001433, patch-round record6217952268), and escalation 2 of that PR's contract review (6217909163, re-review PASS6219927228), as the card body quotes them. Under the startup-stage axis, a zero-pull published surface retires with no sunk-cost exemption.Serial constraints cleared:
batch 2: this seat's other session is packages API: the served installed-package row declares no origin. Declare a closedsource(code / marketplace / authored); objectui's Packages Source column joins the undeclaredwritablewith a second read today #23972 (claim6220830814, PR feat(spec): the installed-package row declares its origin, a closed source (code / marketplace / authored), and the served writable verdict #24010). PR test(spec): the two type-graph test files declare their measured CI budget #24015 (test budget (domain:spec): 26 test file(s) over 10 s of wall in the hourly full battery (Part of #23151) #23180) is landing; its dev has finished.packages/metadata-protocol/src/protocol.ts:The hunks are expected to be disjoint, and whichever lands second merges
main. If feat(metadata-protocol)!: a flow re-save that newly introduces a retired spelling is refused like a new flow's #23986's hunk meets the conflict branch, this PR rebases its removal onto feat(metadata-protocol)!: a flow re-save that newly introduces a retired spelling is refused like a new flow's #23986's landing; ⛔ it does not race it.objectstack-fleet commentedon Oct 16, 2026
os-dev-report
{ "issue": 24001, "status": "done", "branch": "claude/issue-24001-conversion-conflict-retire", "pr": "https://github.com/objectstack-ai/objectstack/pull/24045", "pr_b": "https://github.com/objectstack-ai/objectstack/pull/24046 (claude/issue-24001-adr-0078-note, Part of #24001, Tier H, docs/adr only)", "session": "session_01WdZxJadrrYettvjrqiWeAV", "premise_still_valid": true, "summary": "Retired the ADR-0078 conversion-conflict channel end to end. @objectstack/spec: CONVERSION_CONFLICT_CODE / ConversionConflictNotice / ConversionConflictDetail leave the root; ApplyConversionsOptions loses onConflict + reservedNodeTypes, ConversionContext loses reservedNodeTypes + reportConflict, IAutomationService.canonicalizeStoredFlow loses conflicts; FLOW_CONVERSION_CONFLICT comes out of ERROR_CODE_LEDGER by its own 'Retiring a code' rule (row deleted with its last emitter; retired-error-codes.ts is for StandardErrorCode members only, the #17707 class); dispatcher vocabulary row for OS_METADATA_CONVERSION_CONFLICT deleted. service-automation stops building the live-name set; metadata-protocol drops StoredFlowCanonicalization.conflicts and FOUR consumer branches (save door 409, stored-pass failed row, duplicatePackage failed item, importUnmanagedPackage 409 — the card named two). D3 semantic entry conversion-conflict-channel-removed, BREAKING minor changeset (spec, service-automation, metadata-protocol), api-surface/export-origins/reference docs regenerated (-3 exports). PR B carries the ADR-0078 amended line and an ADR-0087 dated note. Card assignee untouched (os-bill, set by PM).", "tests": "Final head 6f0bca96 (after merging origin/main, 8 incoming commits touching spec+runtime): pnpm --filter @objectstack/spec test 691 files / 20939 passed; spec test:repo 66 files / 1105 passed; service-automation test 189 / 2533 passed; metadata-protocol test 242 passed + 3 skipped / 20608 passed; runtime test 404 / 6139 passed; cli vitest --project unit 307 / 4573 passed (integration layer declared to CI: diff touches cli comments only); turbo typecheck spec+service-automation+metadata-protocol+runtime+cli 5/5. Pins: conversion-conflict-channel-retirement.test.ts 6/6 (§1 zero holders x3 exports + survivors; §1 runtime barrel; §1 D3 registered on step 18; §2 type-level absence of onConflict/reservedNodeTypes/reportConflict/conflicts; §3 ErrorCode refuses FLOW_CONVERSION_CONFLICT with lit controls; §4 tree-scoped absence of 7 spellings, radius declared as third heldBy witness). Ablation: scripts/ablation-replace.mjs restored the export in conversions/index.ts (anchor 1->0, blob 630ed35f->2bec0047): 2 failed / 4 passed (barrel + tree pins red; export-origins pin green by design, it reads the committed artifact); restore blob == HEAD 630ed35f, git diff HEAD empty, rerun 6/6. First ablation attempt was a no-op (replacement contained its anchor, tool refused 1->1, nothing ran). The ablation exposed the git-ignored content/docs/protocol-upgrade/18.md projection tripping the scan; excluded before push, pin green with that page present. No dist ablation needed: the pin imports src relatively and scans source.", "gates": "Local union: node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack derived 139 families on the pre-merge head; all 139 run with exit codes captured before any pipe; 133 exit 0 first pass, 6 exit 3 PREREQUISITE (plugin-teardown-shape --self-test: fixture commit 621a4876 fetched; check:skill-examples, check:i18n, check:i18n-coverage, check:i18n-walk-parity, check:dual-build-cjs-loads: dists built via turbo) then all 6 rerun exit 0. --ran reconciliation with exit codes: '139 derived, 139 run, 0 NOT-MEASURED (a DERIVED zero)'. Ratchet re-run on final head 6f0bca96: check:generated (14/14 current) exit 0, check:api-surface 0, check:adr-0087-registration --base origin/main 0, check:cross-package-test-inputs 0, check:dispatcher-error-vocabulary 0, check:type-check-debt 0 (first attempt queue-timeout exit 3 behind this run's own test lock, rerun under the lock: OK), check:type-check-coverage 0, check:doc-authoring 0, check:error-code-casing 0, check:error-code-provenance 0, check:liveness 0, check:issue-citations 0, check:nul-bytes 0, check-empty-changeset 0, check-changeset-no-major 0, check-platform-checklist --changed-from origin/main 0 (55 anchors, 0 lost); local-only check:dev-prereqs 0, check:skill-frame-freshness 0. PR B: check-adr-anchors exit 0. CI on #24045 at report time: success — Lint & Repo Gates, Build Core, Build Docs, Check Changeset, Governed Surface Queue Guard, Type Check · source gates / debt ledger / consumer gates, all Lint · lanes, Spec property liveness, Dogfood Regression Gate, single-writer/claim checks; in_progress — Test Core (1/6..6/6), Type Check · workspace.", "line_budget": "PR A: 32 files, +486 / -436 (generated: api-surface -3, export-origins -3, reference mdx -2/+1); PR B: 2 files, +3 / -0. Both far under the 3000-line class (c) threshold.", "files_changed": [ ".changeset/24001-conversion-conflict-channel-retired.md", "content/docs/deployment/cli.mdx", "content/docs/references/api/contract.mdx (generated)", "content/docs/references/api/error-code-ledger.mdx (generated)", "packages/cli/src/commands/migrate/meta.ts (comments)", "packages/cli/src/utils/data-migration-plugins.ts (comments)", "packages/metadata-protocol/src/protocol.ts", "packages/metadata-protocol/src/stored-migration.ts", "packages/metadata-protocol/src/protocol.flow-canonicalizer.test.ts", "packages/metadata-protocol/src/protocol.save-flow-canonicalization.test.ts", "packages/metadata-protocol/src/protocol.stored-conversions.test.ts", "packages/metadata-protocol/src/protocol.stored-migration.test.ts", "packages/runtime/src/dispatcher-error-vocabulary.ts", "packages/services/service-automation/src/engine.ts", "packages/services/service-automation/src/plugin.ts", "packages/services/service-automation/src/canonicalize-stored-flow.test.ts", "packages/services/service-automation/src/flow-load-conversion.test.ts", "packages/services/service-automation/src/inert-mode.test.ts", "packages/spec/api-surface/root.json (generated)", "packages/spec/export-origins/root.json (generated)", "packages/spec/src/api/error-code-ledger.zod.ts", "packages/spec/src/contracts/automation-service.ts", "packages/spec/src/conversions/apply.ts", "packages/spec/src/conversions/index.ts", "packages/spec/src/conversions/registry.ts (comment)", "packages/spec/src/conversions/types.ts", "packages/spec/src/conversions/conversions.test.ts", "packages/spec/src/conversions/stored.test.ts", "packages/spec/src/conversions/conversion-conflict-channel-retirement.test.ts (new pin)", "packages/spec/src/migrations/entries/semantic/18.conversion-conflict-channel-removed.ts (new D3 entry)", "packages/spec/vitest.repo-tests.json", "scripts/cross-package-test-inputs.mjs", "PR B: docs/adr/0078-no-silently-inert-metadata.md, docs/adr/0087-metadata-protocol-upgrade-contract.md" ], "deviations": [ "File surface beyond the claim, all to keep the removal honest: cli meta.ts + data-migration-plugins.ts (comments only, justified the inert engine by the removed guard) and content/docs/deployment/cli.mdx (decline row for a refused rename + two sentences); stored-migration.ts is the StoredFlowCanonicalization declaration behind 'the contracts conflicts arrays'; cross-package-test-inputs.mjs + vitest.repo-tests.json declare the new tree pin's radius. Stated in the PR body.", "Hypothesis 1 refinement: protocol.ts had four consumer branches of conflicts (save door, stored pass, duplicatePackage, importUnmanagedPackage), not two; the 409 the card cites at :27853 is the unmanaged-import one. All four removed; zero producers confirmed, so no fork.", "Hypothesis 2: ledger row deleted outright (the ledger's rule), not tombstoned; the error catalog's 409 row is the generated references mdx entry (content/docs/api/error-catalog.mdx never listed it).", "Hypothesis 3: declaration-map did not move (only api-surface and export-origins did); check:generated proved exactly 3 artifacts stale and only those were regenerated.", "Hypothesis 4: ADR-0087's D2/D3 registries live in code (packages/spec/src/conversions, migrations/entries), so the D3 entry rides PR A; PR B holds only the docs/adr lines.", "Hypothesis 5: #23986's protocol.ts hunks (~6612-6700, ~23025-23115) are disjoint from this PR's; each lands independently, second merges main. Its new test stub carries conflicts: [] as an untyped arrow and should keep compiling as a dead key.", "No changeset entry for @objectstack/runtime: dispatcher-error-vocabulary.ts is read only by the gate script, not imported by runtime src, so it does not ship in dist. cli edits are comments only.", "Four tests that pinned the removed branches through test doubles were deleted with the branches (named in the PR body).", "Zero label writes: the dispatch's write budget lists git push, two pr_create and one report comment only.", "Commit trailers use AGENTS.md's model-free pair (Claude-Session + Co-authored-by: Claude), not the harness reminder's model-named Co-Authored-By; AGENTS.md is the binding instruction and the pre-push hook refuses a model identifier.", "Fetched objectui read-only via add_repo (anonymous proxy read, nothing attached) for the ledger rule's cross-repo consumer check; clone deleted afterwards. Fetched one historical commit (621a4876) into the shared object store for a gate fixture." ], "mcp_calls": "4 GitHub MCP reads — issue_read get (#24001), issue_read get_comments (#24001), pull_request_read get_files (#23986), pull_request_read get_check_runs (#24045); plus 1 claude-code-remote add_repo (objectstack-ai/objectui, read; answered read_available, nothing attached). No MCP write tool.", "api_writes": "3 via the fleet-write relay (POST /repos/objectstack-ai/objectstack/dispatches, executed as objectstack-fleet[bot]): pr_create #24045 (+ assignees os-bill), pr_create #24046 (+ assignees os-bill), issue comment on #24001 (this report). Both PR bodies read back byte-identical (9915 / 3342 bytes). git push is not counted.", "open_questions": [ { "question": "The ledger's 'Retiring a code' rule asks that no consumer in objectui OR cloud reads the literal before a row is deleted. objectui is measured clean (pin f8267df9 and HEAD 360e27a: 0 hits for all 7 spellings, control defineStack 38/37 files). cloud is private and was NOT MEASURED from this session.", "options": ["A: the seat (or a cloud-scoped session) greps cloud for FLOW_CONVERSION_CONFLICT, OS_METADATA_CONVERSION_CONFLICT, ConversionConflictNotice, ConversionConflictDetail, CONVERSION_CONFLICT_CODE, reservedNodeTypes, reportConflict before the contract review clears", "B: proceed on the startup-stage axis — no producer can raise the code, so any cloud branch on it is already dead code that TS2305 / an excess-property error will surface at its next pin bump"], "recommendation": "A, because it is one grep and the ledger header states it as the precondition; B is the fallback if cloud is unreachable, and the changeset already flags the out-of-repo population as NOT MEASURED." } ], "out_of_scope_findings": [ "carrier: PR #23986 (or whichever of #23986 / #24045 lands second) · its new save-flow test stub returns conflicts: [] — harmless after #24045 lands (dead key), worth dropping on that merge · noted, not filed" ] }Generated by Claude Code
objectstack-fleet commentedon Oct 16, 2026
ACCEPT → PR #24045 comment
6225442604(head6f0bca9671; contract review PASS6225384741), ready with auto-merge in this act. Governed half: PR #24046, seat record6225232800, waiting on an authorised approval. ·domain:specseat 2 · sessionsession_01LFqdRsuM5nkqoJdHd5ztVk· 2026-10-16T21:56ZGenerated by Claude Code
objectstack-fleet commentedon Oct 16, 2026
Landed · PR #24045 →
a65a59be41(Fixes #24001) ·domain:specseat 2 ·os-bill· sessionsession_01LFqdRsuM5nkqoJdHd5ztVk· 2026-10-16T22:30Za65a59be41on parente246f06119origin/maingit merge-base --is-ancestor a65a59be41 origin/main→ exit 0git diff e246f06119 a65a59be41, and the reviewed head6f0bca9671over its merge base2b274600b1, sharegit patch-id --stable47875ebf. The squash tree2842018630equalsgit merge-tree --write-tree e246f06119 6f0bca9671.gh-readonly-queue/main/pr-24045-*ref remainsmerge_grouprun ona65a59be41issuccess(CI, Lint & Type Check, Spec Liveness Check, Governed Surface Guard, Closing-Target Claim Guard)completedbyFixes #24001;pm:dispatchedis cleared in this act6222477086· report6224904559· contract review PASS6225384741· ACCEPT6225442604What now holds on
main: the ADR-0087 conversion-conflict channel is gone from the published surface:CONVERSION_CONFLICT_CODE,ConversionConflictNoticeandConversionConflictDetail;onConflictandreservedNodeTypesoptions;reportConflict;conflictsarrays;FLOW_CONVERSION_CONFLICTledger row.The retirement is registered as the D3 semantic entry
conversion-conflict-channel-removed.Still open, the governed half: PR #24046 adds the ADR-0078 amended line and the ADR-0087 dated note (seat record
6225232800). Review is requested fromos-zhuangandhotlong, and the PR is labelledneeds-user-decision. Its order condition, this PR merged first, is now met. It lands on an authorised approval.Carried: before cloud's next
@objectstack/specpin bump, whoever holds objectstack-ai/cloud greps the seven retired spellings. A hit is a cloud-side deletion, never a reason to restore the row (ACCEPT6225442604).The cloud dev session
session_01WdZxJadrrYettvjrqiWeAVis archived in this act.Generated by Claude Code