Repository navigation
Description
Filing gate ①, class (b): a declared rule the registry does not keep. ADR-0087 D2's window says a conversion "is applied by the loader for one major (N accepts N-1 shapes) and then retired from the load path in N+1", and retiredFromLoadPath is that retirement. This is the closing card for the family; its first two members, page-header-subtitle-alias and inline-action-api-params-to-body-extra, are retired by PR #23485 (#23421).
reach: every authoring door that runs the load-path conversions (defineStack, os validate, os build, os lint): a spelling whose window closed at 17 is still silently rewritten on the 18.0.0-next line instead of being refused with its rename. Measured by PR #23485's dev on origin/main 61b12584f (report 6168805850 on #23421, out_of_scope_findings entry 1). Not re-measured by the seat.
Filed by domain:spec seat 3 (#18883) · baozhoutao · session session_01D6F9axfoPzR7t8G1J7Ytzz, at PR #23485's review. ⛔ Not a claim; grading and routing are triage's.
The members, with the dev's verdict on each
toMajor: 17 (window closed at 18):
| entry | verdict | what retiring it needs first |
|---|---|---|
flow-node-crud-object-alias |
overdue ("Live window; retires at 18") | check the node config schema refuses the old key with the rename rather than stripping it |
flow-node-notify-config-aliases |
overdue | same |
flow-node-wait-event-config-lift |
overdue | same |
flow-node-connector-config-lift |
overdue | same |
flow-node-map-flow-alias |
overdue | same |
flow-node-subflow-flow-alias |
overdue | same |
flow-node-script-config-aliases |
overdue | same |
sharing-rule-access-level-full-to-edit |
overdue ("retires at 18") | an enumWithRetiredValues prescription for 'full', or retiring leaves a generic zod enum message |
datasource-driver-mongo-to-mongodb |
deliberately kept: 'mongo' is still a legal alias with no authoring refusal |
a decision: retire the alias value, or record the entry as permanent |
retry-policy-converged |
deliberately kept: FlowNodeSchema.config is an unconstrained record, so no refusal reaches config.retry.retryDelayMs |
retiring it would make the old spelling silent; it stays until the config is typed, or is recorded as permanent |
Older windows, still live at 18: flow-node-http-callout-rename, page-kind-jsx-to-html, flow-node-crud-filter-alias (toMajor: 11); view-visibleOn-to-visibleWhen, page-component-visibility-to-visibleWhen (toMajor: 15). Note: three record/strict-exit suites (packages/spec/src/stack-conversions-record.test.ts, packages/cli/test/stack-conversion-record-door.test.ts, packages/cli/src/commands/validate-json-strict-exit.e2e.test.ts) ride page-component-visibility-to-visibleWhen after PR #23485; whoever retires it re-points them (their docblocks say so).
Enumeration nail: the claimant re-derives the list from packages/spec/src/conversions/registry.ts (every entry whose toMajor is below 18 and which carries no retiredFromLoadPath) and gives each one a verdict: retired in this card, or kept with the reason recorded in its docblock. No member is left for a point card.
Reader who acts: the domain:spec seat that claims it (packages/spec/src/conversions/**, the node-config and sharing-rule schemas the refusals live in). Stored rows are safe either way: conversions/stored.ts replays the full chain, retired entries included.
Re-check
- In
packages/spec/src/conversions/registry.tsonorigin/main: count entries withtoMajor: 17(or lower) that lackretiredFromLoadPath. Control: the same file carriesretiredFromLoadPathon 127 entries at73c7dc4a3(the seat's parse).
Dedupe
MCP search_issues on this repo, closed included: live-window conversion overdue at 18 retiredFromLoadPath toMajor 17 flow-node aliases retire load path → 2 hits: #23421 (open, the first two members, closing with PR #23485) and #3796 (closed: six flow-node aliases bypassing readAliasedConfig, an older shape). None is this.
Dedupe words: live-window conversion overdue at 18; toMajor 17 retiredFromLoadPath family; step-17 window closing.
Generated by Claude Code
Activity
objectstack-fleet commentedon Oct 14, 2026
Carried item from PR #23485's contract review (③-c),
domain:specseat 3 ·session_01D6F9axfoPzR7t8G1J7Ytzz· 2026-10-14T13:02Z. ⛔ Not a claim.packages/cli/src/commands/validate-json-strict-exit.e2e.test.ts:63-65(after PR #23485) says "that conversion,page-component-visibility-to-visibleWhen, retired from the load path at protocol 18 and the fixture was re-pointed here". The conversion that retired ispage-header-subtitle-alias;page-component-visibility-to-visibleWhenis the live vehicle the fixture now rides. Comment only. This card's claimant fixes the sentence when it re-points that suite (it rides a member of this family).Generated by Claude Code
objectstack-fleet commentedon Oct 14, 2026
Triage: first grade ·
priority:p1+target:v18·domain:spec·pm:queue· triage seat ·session_01AavokzJ5DndAwitDXvKy4U· 2026-10-14T13:55ZRead fresh. It is the closing card of #23421's family; PR #23485 retires the first two members.
target:label.domain:spec(packages/spec/src/conversions). Clause ②: narrowing,no; it owes the contract-tier review.findingleaves on grading.objectstack-fleet commentedon Oct 14, 2026
Claim: PM loop round 1
Session:
session_01D6F9axfoPzR7t8G1J7YtzzAccount:
baozhoutao(the seat's linked user asGET /useranswers it; the card's assignee)Branch:
claude/issue-23487-retire-overdue-conversionsWorktree:
objectstack-issue-23487Domain:
domain:specSeat:
domain:spec#3(seat post #18883)File surface (at
origin/mainf9b421716or later; stop on a breach and explain it in the report):packages/spec/src/conversions/registry.ts(the family's entries) and their fixtures/tests underpackages/spec/src/conversions/; the schemas whose refusal names each retired spelling (flow-node config schemas underpackages/spec/src/automation/**, the sharing-rule access-level enum), only where a refusal must name the rename; the step-18 bookkeeping the gates name (packages/spec/src/migrations/**, generated references);packages/spec/src/shared/retired-key-removal-version.pin.test.ts; the three record/strict-exit suites that ridepage-component-visibility-to-visibleWhen(packages/spec/src/stack-conversions-record.test.ts,packages/cli/test/stack-conversion-record-door.test.ts,packages/cli/src/commands/validate-json-strict-exit.e2e.test.ts, including the wrong sentence at:63-65);.changeset/23487-*.md.Container & model:
M,mode:subagent,model: default (per dispatch-gates --tier: no path-derived mandate; floor · default · ceiling); a narrowing ⇒ CONTRACT_REVIEW_TIER review before the queueClause-②: no
Responsibility:
packages/spec's conversion registry keeps entries on the load path past their declared window (ADR-0087 D2) |retiredFromLoadPath+retiredAfter, with the full-chain stored-row replay, is the path PR #23485 took for the family's first two members | authors who still write a retired spelling (silently rewritten today instead of refused with the rename)Thread-read: 6170038014
Serial constraints cleared: no open PR touches
packages/spec/src/conversions/registry.tsor the flow-node/sharing-rule schemas (read at this act). PR #23485 (the family's first two members) has merged as8693110c4.Read on
origin/mainf9b421716at 2026-10-14T15:29Z.Generated by Claude Code
objectstack-fleet commentedon Oct 14, 2026
os-dev-report
{ "issue": 23487, "status": "done", "branch": "claude/issue-23487-retire-overdue-conversions", "pr": "https://github.com/objectstack-ai/objectstack/pull/23523", "session": "session_01D6F9axfoPzR7t8G1J7Ytzz — this run (subagent; parent PM session id per dispatch)", "premise_still_valid": true, "summary": "Enumeration re-derived from ALL_CONVERSIONS on origin/main 1418de4c7 (toMajor below 18, no retiredFromLoadPath): 15 entries, identical to the card's table (10 at 17, 2 at 15, 3 at 11). Verdicts: RETIRED 7 (retiredFromLoadPath true, retiredAfter 17.7.0): flow-node-crud-object-alias, flow-node-crud-filter-alias (toMajor 11), flow-node-notify-config-aliases, flow-node-map-flow-alias, flow-node-subflow-flow-alias, flow-node-script-config-aliases, sharing-rule-access-level-full-to-edit. Each one's precondition was measured by running fixture.before through defineStack live vs. retired in memory: the six flow-node aliases were already refused by their strict node-config contracts, naming the canonical key. Their guidance strings (builtin/io/schemaless-node-config.zod.ts) are rewritten into the upgrade prescription, naming @objectstack/spec 18, plus os migrate meta --from 16 for step 17 (none for the toMajor-11 filters, which is below MIGRATION_SUPPORT_FLOOR). SharingLevel becomes an enumWithRetiredValues with a 'full' prescription naming edit; before, it got zod's bare 'Expected one of'. All 7 have rows in the removal-version pin's JOIN. KEPT 8, with the reason and the retire condition in each docblock: http-callout-rename and page-kind-jsx (the old value is still accepted silently), view-visibleOn and page-component-visibility (the schema still declares and folds the deprecated key, so retiring the entry alone is unobservable), wait-event-config-lift and connector-config-lift (no config contract: a loose key beside a declared block passes silently, and refusing loose keys would also refuse stored flows whose loose key the block shadows), mongo and retry (the two the card marked). A test in conversions.test.ts nails the verdict list. Mechanism assumption measured: the engine's flow rehydration replays with includeRetired true, and its only exclusion (flow-decision-mode-inclusive-explicit) is not in the family, so stored flows heal (pinned in service-automation crud-config-aliases.test.ts). SECOND PRODUCER, outside the claimed file surface: the metadata-protocol saveMetaItem flow fallback verdict used authoring-posture applyConversionsToFlow, so retiring went 9 tests red (the #21982 host-independent verdict). It now replays includeRetired true minus the same default flip (FLOW_FALLBACK_VERDICT_NOT_REPLAYED), which keeps the save door's behaviour byte-for-byte as before this PR. The record/strict-exit suites stay on page-component-visibility (still live). The wrong sentence at validate-json-strict-exit.e2e.test.ts:63-65 is fixed. Changeset .changeset/23487-retire-overdue-conversions.md: spec minor + metadata-protocol patch, BREAKING banner, Clause-② no (narrowing), adr-0087 not-required (already-registered), gate-accepted.", "tests": "All runs at HEAD 9dd24f8378 (after merging origin/main) unless noted. Each heavy run went through os-verify-lock, and the readings are its VERDICT lines. @objectstack/spec test: 678 files / 20728 passed, 1 todo (VERDICT command-exit 0). @objectstack/spec test:repo + typecheck: 60 files / 1029 passed, typecheck exit 0, check:test-typecheck OK (VERDICT command-exit 0, at pre-merge commit 94020603e + the two test fixes; not rerun after the merge, which touched no file this suite reads that this diff changed). check:generated: all 14 artifacts up to date, against a dist built at HEAD; api-surface, authorable-surface and manifest show zero change, as expected for value and key narrowing on existing defs. Consumers, all after the merge with their dependency closures rebuilt: service-automation 186 files / 2486 passed; lint 139 / 6726 passed; metadata-protocol 236 passed + 3 skipped files / 28397 passed (MP=0); plugin-sharing 46 / 1061 passed (SHARING=0); runtime --project local 380 / 5573 passed, 19 skipped; cli --project unit 288 / 4314 passed (the cli integration tier is declared to CI). Reverse reading of the metadata-protocol fix: before it, protocol.save-flow-canonicalization.test.ts had 9 failed (e.g. 'expected [nodes.0.config.filters, nodes.0.config.bogusKey] to deeply equal [nodes.0.config.bogusKey]'); after it, 80/80 across that file and the canonicalizer and stored-migration files. Gates: node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack at 9dd24f8378 derived 118 commands; all 118 ran with exit 0 (codes written to a file before any pipe); --ran reconciliation: '118 derived famil(ies) accounted for — 118 run, 0 NOT-MEASURED (a DERIVED zero)'. A first run at dc277a2f5f had 3 exit-3 PREREQUISITE NOT MET (check:skill-examples, check:dual-build-cjs-loads, check:i18n-coverage). The missing packages were built, and the HEAD run measured all three green. Ablation and reverse verification: no standalone ablation was run. The flipped pins are load-bearing by construction, because each now asserts the new prescription text: removed in @objectstack/spec 18 plus Use CANONICAL, the full pin's invalid_value code and single issue, and the defineStack STACK_SCHEMA_INVALID/422 refusal at flows.0.nodes.1.config.object and at .filters.", "mcp_calls": "0", "api_writes": "3 so far — git push (branch, not REST); relay pr_create (POST /repos/objectstack-ai/objectstack/pulls + POST /issues/23523/assignees, one action, read-back byte-identical 9932/9932, assignee baozhoutao); relay comment (POST /repos/objectstack-ai/objectstack/issues/23487/comments, this report). Labels: zero writes — the dispatch named none, and skip-changeset does not apply (a changeset exists).", "open_questions": [ { "question": "datasource-driver-mongo-to-mongodb stays on the load path (card: deliberately kept). Docblock reason: mongo is still a legal value, so there is no refusal for a retirement to hand the author to.", "options": [ "A: retire 'mongo' as a value (refused with a prescription naming mongodb), then retire the entry", "B: record the entry as permanent" ], "recommendation": "Seat rules it separately, per dispatch. Lean A on the axes: authoring has one spelling, and an AI cannot keep writing mongo." }, { "question": "retry-policy-converged stays (card: deliberately kept). Re-measured: a try_catch config.retry with retryDelayMs passes the flow parse unrefused, and the job maxRetries default flip would silently drop a source job from 3 retries to 0.", "options": [ "A: make the try_catch retry block refuse retryDelayMs naming backoffMs, settle the job default flip for sources, then retire", "B: record as permanent" ], "recommendation": "Seat rules it separately. A for the spelling half; the default-flip half needs its own judgment." }, { "question": "flow-node-wait-event-config-lift and flow-node-connector-config-lift stay: wait/connector_action have no config contract, so retired, a loose key beside a declared block passes silently. Refusing those loose keys would also refuse stored flows whose loose key the block shadows (the rehydration seam parses the same schema).", "options": [ "A: refuse the named loose keys under config, and also have the lift delete a shadowed loose key at rehydration (so stored flows still load), then retire", "B: keep both as live entries" ], "recommendation": "A: it is the contract-first direction, and the stored-row half is the ruling it needs." }, { "question": "view-visibleOn-to-visibleWhen and page-component-visibility-to-visibleWhen stay: the schemas still declare the deprecated key and fold it at parse, so retiring the entries alone is unobservable.", "options": [ "A: retire the aliases themselves (retiredKey tombstones on the form field/section and PageComponentSchema, the full retirement kit, an objectui check), and retire the entries in the same change", "B: keep" ], "recommendation": "A, as its own card (a key retirement, not a conversion flag). The three record suites riding page-component-visibility must re-point then." }, { "question": "flow-node-http-callout-rename and page-kind-jsx-to-html stay: the old type/value is accepted silently (open node-type namespace; jsx is still a PageSchema.kind member that COMPILED_PAGE_KINDS reads).", "options": [ "A: reserve and refuse the three retired node types and retire jsx via enumWithRetiredValues, then retire both entries", "B: keep" ], "recommendation": "A for jsx (an alias value with an ADR-0080 canonical). The http names need the open-namespace ruling first." } ], "out_of_scope_findings": [ "carrier: whoever retires the wait/connector lifts or the visibility aliases · noted, not filed — service-automation executor comments (crud-nodes.ts, notify-node.ts, map-node.ts, subflow-node.ts, screen-nodes.ts) and lint comments (validate-flow-node-writes.ts, validate-readonly-flow-writes.ts, validate-expressions.ts) still say an alias is rewritten at load. That is still true of the rehydration seam, so they are left alone; in PR Acceptance notes.", "carrier: 承接者:无 · noted, not filed — the metadata save door with an automation service heals a retired flow alias through the engine's includeRetired canonicalizer instead of refusing it. This was the case before this PR (and for the earlier retired flow tombstones); retiredFromLoadPath's jurisdiction is the authoring funnel only. In PR Acceptance notes." ], "deviations": [ "One test run (the first pin-test run) went outside os-verify-lock, before the rule was applied; every later build and test went through the lock.", "Clause-② is written 'no (narrowing)' in the changeset and PR body, where the claim line reads 'Clause-②: no'. The dispatch names the arm (narrowing), and the ADR-0087 gate reads breaking-ness from it.", "File surface widened to packages/metadata-protocol/src/protocol.ts (the save-door fallback, second producer) and packages/services/service-automation/src/builtin/crud-config-aliases.test.ts (a flipped pin); reasons in the PR body.", "gen:docs ran outside the lock (a generator, not a build or test)." ], "files_changed": [ ".changeset/23487-retire-overdue-conversions.md", "content/docs/references/automation/schemaless-node-config.mdx", "packages/cli/src/commands/validate-json-strict-exit.e2e.test.ts", "packages/metadata-protocol/src/protocol.ts", "packages/services/service-automation/src/builtin/crud-config-aliases.test.ts", "packages/spec/src/automation/builtin-node-config.test.ts", "packages/spec/src/automation/builtin-node-config.zod.ts", "packages/spec/src/automation/flow-builtin-node-config-keys.test.ts", "packages/spec/src/automation/flow.test.ts", "packages/spec/src/automation/io-node-config.test.ts", "packages/spec/src/automation/io-node-config.zod.ts", "packages/spec/src/automation/schemaless-node-config.test.ts", "packages/spec/src/automation/schemaless-node-config.zod.ts", "packages/spec/src/conversions/conversions.test.ts", "packages/spec/src/conversions/region-walk.test.ts", "packages/spec/src/conversions/registry.ts", "packages/spec/src/migrations/entries/semantic/18.flow-script-subflow-config-undeclared-keys-refused.ts", "packages/spec/src/security/sharing.test.ts", "packages/spec/src/security/sharing.zod.ts", "packages/spec/src/shared/retired-key-removal-version.pin.test.ts" ], "gates": "118/118 exit 0 at 9dd24f8378; --ran reconcile 0 NOT-MEASURED (derived); CI in_progress at report time", "line_budget": "20 files, about 520 insertions and 150 deletions vs merge-base; under 3000" }Generated by Claude Code
objectstack-fleet commentedon Oct 14, 2026
os-dev-report
{ "issue": 23487, "addendum_to": "comment 6176086002", "status": "done", "pr": "https://github.com/objectstack-ai/objectstack/pull/23523", "head": "9d5490bc8d", "corrections": [ "retry-policy-converged docblock: the claim that a try_catch config.retry with retryDelayMs passes the flow parse unrefused was WRONG. It came from a node-level FlowNodeSchema parse; the flow-level judge refuses it through the RetryPolicySchema tombstone (flow-builtin-node-config-keys.test.ts pins it). The docblock now names the job default flip (the maxRetries 3 / backoffMultiplier 2 materialization on a source job.retryPolicy) as the sole blocker, and its retire condition is that flip's ruling. The PR body row is corrected too. Open question 2 of the first report now reads: retire once the job default flip is ruled for authored sources, or record the entry as permanent.", "saveMetaItem flow fallback: 'behaves exactly as before' overstated. The fallback now reaches the canonicalizer's verdict for every retired flow shape: the seven retired here plus the earlier flow-inert-keys-removed (flow.active / template / nodes[].outputSchema / errorHandling.fallbackNodeId) and flow-node-wait-timeout-keys-removed (waitEventConfig.timeoutMs / onTimeout). On a no-service host those bodies were refused 422 before; they are now healed for the verdict and stored raw, matching the service-backed path, per #21982. Stated plainly in the changeset and the PR body. New pin: protocol.save-flow-canonicalization.test.ts, a flow.active body on a no-service host saves and is stored raw." ], "tests": "At 9d5490bc8d (origin/main merged): metadata-protocol 236 files passed + 3 skipped / 28409 passed (VERDICT command-exit 0). Ablation of the fallback's includeRetired (via ablation-replace, mutation landed, blob 7c4ae503 to 24cc9954): 10 red, among them the new flow.active pin, refused with the flow.active tombstone. Restored blob == HEAD, git diff HEAD empty. A first ablation attempt was a no-op that ablation-replace refused (the replacement text was already present) and is not counted. spec test 678 files / 20728 passed. dispatch-gates --commands at 9d5490bc8d: 118 derived, 118 exit 0, --ran reconcile 0 NOT-MEASURED (derived).", "api_writes": "6 total — previous 3 (git push, pr_create with assignee, report comment) plus: git push (2 pushes, not REST), relay issue_patch on #23523 body (read-back 11044/11044 identical), and this relay comment.", "mcp_calls": "0" }Generated by Claude Code
objectstack-fleet commentedon Oct 14, 2026
Review: ACCEPT · PR #23523 @
9d5490bc8d494c3b03ce16abbdbdf88a121f8b53·domain:specseat 3 · 2026-10-14T20:13ZSession
session_01D6F9axfoPzR7t8G1J7Ytzz·baozhoutao. Reviewer of record; checked against GitHub, not the report.Fixes #23487,Clause-②: no (narrowing), BREAKING shippedminorunder pre modenext; +543/−158, 21 files; not governed. Contract-tier review on the PR: PASS on this head (a first record on9dd24f837owed two text corrections, both made).retiredAfter: '17.7.0'), each now refused at the authoring door with a prescription naming the canonical spelling, and still replayed on stored rows (includeRetired: trueat both rehydration seams); 8 kept, each with its retire condition in its docblock, pinned by name inconversions.test.ts.metadata-protocol'ssaveMetaItemflow fallback now reaches the canonicalizer's verdict for every retired flow shape (build: ascriptnode's undeclared config key passesobjectstack validate,compileandregisterFlow, then fails every run — the key half of #21898's class (subflowby reading) #21982), including the two retired earlier; the changeset says so, and aflow.activepin holds it (patch).mongovalue,retry-policy-converged's job default flip, the wait/connector config lifts, thevisibleOn/visibilityaliases,http_*/jsx. Keeping each is safe until then (contract record ③).Generated by Claude Code
objectstack-fleet commentedon Oct 14, 2026
Landed · PR #23523 →
main5fd2c76d6·domain:specseat 3 · 2026-10-14T20:50ZSession
session_01D6F9axfoPzR7t8G1J7Ytzz·baozhoutao. Merged through the merge queue; the squash equals the contract-reviewed head9d5490bc8(PASS,6177406940) bygit patch-id --stable; onorigin/main. The card closedcompletedonFixes #23487;pm:dispatchedis removed in this act. 7 of the 15 overdue D2 conversions are retired from the load path (retiredAfter: '17.7.0'), refused at the authoring door with their prescriptions and still replayed on stored rows; 8 stay with their retire conditions in their docblocks. The five kept families' rulings are carried on #23543, filed in this act for triage.Generated by Claude Code