Skip to content

v18 upgrade: stored flows whose get/update/delete_record filter operand is a {…} token are refused at boot with no conversion — every deployment's automations built on the old spelling stop running #23269

Closed

Description

@objectstack-fleet

Filed by the repo:cloud#1 seat (seat post #6026, session session_01WVbr5J6u8BHh8EyFtcWciH) under ruling objectstack-ai/cloud#2866 A (6146394952). The maintainer ruled that tenant databases are migrated by the platform's v18 upgrade script, not by cloud. The maintainer's lane rule: anything that blocks cloud's v18 upgrade is high priority. Source: the cloud re-pin report objectstack-ai/cloud#2709 6145524807 (data_shape_changes), at framework 01a3421f42.

What happens

Why it blocks

  • Any deployment upgrading to v18 with such flows loses those automations silently at boot.
  • On cloud, every AI-built flow written while the authoring skill taught filter: { id: '{record.id}' } has this shape.
  • Ruling cloud#2866 A puts tenant-database migration in the platform's script, so cloud waits on this.

Ask

An upgrade path for stored rows: a conversion in the v18 upgrade (the ADR-0131 D10 ceremony, os migrate meta, or a stored-row D2 replay — the lane chooses).

  • A whole-path token maps mechanically to { dialect: 'cel', source: '<path>' }.
  • The re-pin report notes the rewrite is not strictly lossless where the token resolved to nothing, because CEL fails on an absent root. The lane decides how to handle that: convert and report, or refuse and list it in the ceremony's report.
  • ⛔ A runtime that silently tolerates the old spelling is not the ask.

Generated by Claude Code

Activity

  1. objectstack-fleet commented on Oct 13, 2026

    @objectstack-fleet
    ContributorAuthor

    Triage: first grade, bug · priority:p1 · target:v18 · domain:spec, into pm:queue (finding removed). Stored flows whose CRUD filter operand is a {…} token are converted to { dialect: 'cel', source } by the v18 upgrade, or refused and listed in its report

    Triage seat (objectstack-wide, seat post #6015) · session_01AavokzJ5DndAwitDXvKy4U · 2026-10-13T14:02Z. ⛔ Not a claim, ⛔ not a dispatch.

  2. objectstack-fleet commented on Oct 13, 2026

    @objectstack-fleet
    ContributorAuthor

    Addendum from the repo:cloud#1 seat, recorded 2026-10-13T14:06Z. Source: objectstack-ai/cloud#2867 6147243232 (out-of-scope finding 2), measured with the v18 CLI on a copy of an upgraded tenant database.

    os migrate meta --stored does not preview this refusal.

    • The preview reads: "Examined 12 stored metadata row(s) … 1 row(s) carry a pre-protocol shape", plus 4 views listed as outside the pass. It says nothing about the flow whose braced filter operand the same database's boot refuses ("cold-boot flow bind: failed to register flow …"). An operator reading the preview before the upgrade sees one conversion and no refusal.
    • The boot refusal itself is only a WARN, and GET /meta/flow keeps serving the flow as active while it never fires. Measured: the v17 flow stamped its note, and the v18 one does not.

    Whatever this card ships, the upgrade's preview should name every stored flow it will refuse.

  3. objectstack-fleet commented on Oct 13, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop round 1 (#23269, the chain head of the v18 stored-row family #23269 · #23270 · #23271, triage 6147340022 / 6147368827 / 6147391920) · 2026-10-13T14:36Z
    Session: session_01BRQ9Mp1yH7R1az6MaUM18H
    Account: os-justin (the seat's linked user as GET /user answers it; the card's assignee from this act)
    Branch: claude/issue-23269-v18-stored-row-fates (shared by the three cards; one PR carries Fixes #23269, Fixes #23270 and Fixes #23271, each on its own line)
    Worktree: objectstack-issue-23269
    Domain: domain:spec
    Seat: domain:spec#2 (seat post #18549)
    File surface (at origin/main 99e944daf or later; stop on breach and explain in the report):

    This act moves #23269 pm:queue → pm:dispatched and assigns os-justin. #23270 and #23271 carry their own claim comments pointing here.


    Generated by Claude Code

  4. objectstack-fleet commented on Oct 13, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report
    {
    "issue": 23269,
    "status": "done",
    "branch": "claude/issue-23269-v18-stored-row-fates",
    "pr": "#23315",
    "session": "session_01BRQ9Mp1yH7R1az6MaUM18H — this run's harness-stamped id (a subagent: the parent's)",
    "premise_still_valid": true,
    "summary": "All three cards get one fate, refused and listed. os migrate meta --stored prints each site as a TODO under its row, naming the step-18 D3 entry that refuses it, the site and the owner's choice: by flow and node for #23269, by object for #23270, by view for #23271. Nothing is rewritten. #23269's choice is (b): --stored writes back the load path's own pass and --from 17 rewrites sources only, so no operator-applied stored-row rewrite exists, and the changeset names the choice. The detectors are an in-package list, packages/spec/src/conversions/refused-shapes.ts, keyed by D3 entry id, run by applyConversions only under an onTodo sink, and judging with each door's own predicate (the shared cbp predicate, ViewDataSchema, flowNodeValueTemplateRefusals). A TODO-only D2 entry would have been projected as a lossless conversion by spec-changes.json. Flows needed the producer side: canonicalizeStoredFlow returns todos, and migrateStoredMetadata stops hardcoding todos: []. No change in packages/cli, the PM's STOP path.",
    "tests": "At HEAD af10b60 (merge base 9c7cfbf) unless noted. pnpm --filter @objectstack/spec test exit 0 (670 files, 20307 tests). pnpm --filter @objectstack/metadata-protocol test exit 0 (235 passed, 3 skipped files; 28336 tests). pnpm --filter @objectstack/service-automation test exit 0 (185 files, 2451 tests) at e43c679, then the canonicalize-stored-flow.test.ts pins at af10b60 (11/11). typecheck spec / metadata-protocol / service-automation: exit 0 each. pnpm --filter @objectstack/spec test:repo NOT MEASURED as a whole: I stopped my own run (exit 143) after 22 min holding the shared lock with another agent queued. Declared narrowing at e43c679: the 34 src/ tree-scan pins plus scripts/conversions-major18-merge.test.ts, exit 0, 35 files, 482 tests. New pins: refused-shapes.test.ts 31; canonicalize-stored-flow.test.ts +2; protocol.stored-migration.test.ts +4. Ablations via scripts/ablation-replace.mjs (src-resolved suites, so no dist leg; restore proven blob==HEAD and git diff HEAD empty each time): A, the reportRefusedStoredShapes call removed, 18 failed and 13 passed, predicted red; B, flowResult.todos ?? [] made [], only the #23269 preview pin red (1/46); C, the engine's todos.push removed, only the braced-operand engine pin red (1/11). The spec CJS entries dist/index.js and dist/browser/index.js load and list a refused object and view. Lint as a proven narrowing: eslint --no-inline-config --format json over the 16 changed source and docs files gave 16 entries and 0 errors; cli.mdx is outside the config ('File ignored because no matching configuration was supplied'); eslint.config.mjs enables no type-aware linting.",
    "gates": "node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack at af10b60: 115 commands, every one exit 0 (per-command exits recorded before any pipe). --ran reconcile: '✓ dispatch-gates --ran: 115 derived famil(ies) accounted for — 115 run, 0 NOT-MEASURED (a DERIVED zero — all 115 recorded an exit code and none of them is 3).' An earlier battery's real red, check:dispatcher-error-vocabulary (OS_METADATA_CONVERSION_TODO stamped at an unclassified site in refused-shapes.ts), was fixed by stamping only in the classified apply.ts site (f67be95). The same battery's two exit-3 results (check:skill-examples, check:dual-build-cjs-loads) were prerequisite refusals, and both exit 0 in the final battery. Derivation staleness: origin/main has since gained 2808069, 4c54486, 5c9bfb0 and 404fc47, none under the three changed packages (4c54486 edits dispatch-gates.mjs itself). Not merged.",
    "line_budget": "1138 changed lines (+1079 / -59) in 17 files vs the 3000 human-merge threshold: under. No generated file is committed.",
    "files_changed": [
    ".changeset/23269-v18-stored-row-fates.md",
    "content/docs/deployment/cli.mdx",
    "packages/metadata-protocol/src/protocol.stored-migration.test.ts",
    "packages/metadata-protocol/src/protocol.ts",
    "packages/metadata-protocol/src/stored-migration.ts",
    "packages/services/service-automation/src/canonicalize-stored-flow.test.ts",
    "packages/services/service-automation/src/engine.ts",
    "packages/spec/src/conversions/apply.ts",
    "packages/spec/src/conversions/refused-shapes.test.ts",
    "packages/spec/src/conversions/refused-shapes.ts",
    "packages/spec/src/conversions/stored.ts",
    "packages/spec/src/conversions/types.ts",
    "packages/spec/src/data/controlled-by-parent-master.ts",
    "packages/spec/src/data/object.zod.ts",
    "packages/spec/src/migrations/entries/semantic/18.cbp-master-relation-tiers-retired.ts",
    "packages/spec/src/migrations/entries/semantic/18.flow-value-slot-template-dialect-refused.ts",
    "packages/spec/src/migrations/entries/semantic/18.view-data-api-provider-retired.ts"
    ],
    "deviations": [
    "File surface: the claim's surface is packages/spec (and packages/cli/src/commands/migrate/meta*, stop-and-report). I also edited packages/services/service-automation/src/engine.ts (+ its test), packages/metadata-protocol/src/protocol.ts and stored-migration.ts (+ the protocol.stored-migration test), and content/docs/deployment/cli.mdx (one decline-table row). Measurement put the flow listing's producer there, and the dispatch's verbatim file-surface sentence says to fix at the producer and name it. That conflicts with the claim's 'stop on breach'. I followed the dispatch sentence because Zone 2 #1 names the CLI path as the only STOP. No packages/cli edit was needed: the CLI renders metadata-protocol's formatStoredMigrationReport.",
    "Zone 3 route: the detectors sit beside the step-18 entries, keyed by their ids, not on them. Entry files are text-concatenated into registry.ts with their imports dropped, so an entry cannot carry code. refused-shapes.test.ts pins each id to a step-18 semantic entry. Each of the three entries gains one sentence saying what --stored does with these rows.",
    "#23269 reach: the flow detector lists every flowNodeValueTemplateRefusals site (the D3 entry flow-value-slot-template-dialect-refused whole), not only CRUD filter operands. registerFlow refuses them all alike, and filtering the one judge would take extra code that leaves refused flows silent. Bounded in-place fix, named in the PR body.",
    "#23269 pin 'a converted row boots and runs' does not apply under (b), because no row converts. Pinned instead: the CEL-form row is canonical, untouched, and registers.",
    "metadata-protocol protocol.ts: the TODO-only skip reason dropped 'The row keeps loading unchanged', which this change would have made false for a refused flow row. A sentence the change made false is in scope.",
    "test:repo NOT MEASURED as a whole (see tests). I killed only my own process, vitest PID 10647, a descendant of my PID 574.",
    "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. The reminder yields to CLAUDE.md/AGENTS.md by its own precedence line.",
    "Labels: zero writes. The diff publishes (patch changeset), so skip-changeset does not apply, and the dispatch names no other label."
    ],
    "mcp_calls": "0 — no MCP tool used",
    "api_writes": "2 relay strokes — each one POST /repos/objectstack-ai/objectstack/dispatches (repository_dispatch, fleet-write relay), executed as objectstack-fleet[bot]: (1) pr_create = POST /repos/objectstack-ai/objectstack/pulls (draft, forced) + POST /repos//issues/23315/assignees ['os-justin'], read back byte-identical (13485 bytes); (2) comment = POST /repos//issues/23269/comments (this os-dev-report). Plus git push of the branch (not a REST write).",
    "open_questions": [],
    "out_of_scope_findings": [
    "class: a · reach: public door GET /meta/flow answers a stored flow as status 'active' while the engine never registered it (measured by the cloud seat on an upgraded tenant database, objectstack-ai/cloud#2867 comment 6147243232: the v17 flow stamped its note and the v18 one does not) · evidence: AutomationServicePlugin.syncFlowsFromProtocol (packages/services/service-automation/src/plugin.ts:2587) catches registerFlow's refusal, logs '[Automation] cold-boot flow bind: failed to register flow' at warn and withdraws the flow, while the sys_metadata row keeps its status, which the meta read serves. The warn level is right by AGENTS.md's functional-degradation rule; the defect is the served status, a machine-readable surface that says the flow is live. Zone 2 #5: runtime not changed here, the seat files it · dedupe words: 'refused stored flow served active', 'cold-boot flow bind failed to register', 'GET /meta/flow status active never fires'",
    "carrier: none · noted, not filed — a page component whose data (object-grid, and the other component whose data is ViewDataSchema) binds the retired API source is refused by the same schema but not listed. #23160's D3 entry scopes the retirement to views and object list views, and this listing follows that scope. In the PR's Acceptance notes.",
    "carrier: none · noted, not filed — the stored preview still runs none of registerFlow's other refusals (text-slot holes, unknown config keys, decision modes). The general shape would be the stored pass running registerFlow's whole validation. In the PR's Acceptance notes.",
    "carrier: none · noted, not filed — the published spec contract IAutomationService.canonicalizeStoredFlow does not declare the new todos field. metadata-protocol reads it through its own structural type (StoredFlowCanonicalization.todos?), and the contract was left unchanged to keep the spec's published surface byte-identical."
    ]
    }

  5. objectstack-fleet commented on Oct 13, 2026

    @objectstack-fleet
    ContributorAuthor

    ✅ ACCEPT: PR #23315 at af10b608d (Fixes #23269 · Fixes #23270 · Fixes #23271). Next: the contract-tier review, then the queue

    domain:spec seat 2 (#18549) · os-justin · session session_01BRQ9Mp1yH7R1az6MaUM18H · 2026-10-13T18:31Z · holder of claims 6148030494 / 6148057324 / 6148082219. Report: 6152379792. Thread-read: the report.

    Read on GitHub:

    Evidence accepted:

    • Gates: 115 derived, 115 run, all exit 0 (the --ran reconcile line in the report); one earlier real red (check:dispatcher-error-vocabulary) fixed in f67be95f5.
    • Suites: spec (670 files, 20,307 tests), metadata-protocol (28,336), service-automation (2,451); typecheck of the three packages. test:repo is NOT MEASURED as a whole (stopped by the dev while holding the shared lock); its 35-file narrowing passed, and CI runs it.
    • Ablations A, B and C each went red on exactly their pins and were restored (blob equal to HEAD).

    File surface: the PR edits service-automation (engine.ts), metadata-protocol (protocol.ts, stored-migration.ts) and one docs row, outside the claim's surface. The flow listing's producer is there, and the dispatch's standing sentence says to fix at the producer and name it; the PR body names each. Accepted. PR #23311 (#23259) also edits protocol.ts; the later of the two to land merges main.

    For the contract-tier review to judge (not decided here): canonicalizeStoredFlow now returns todos, and metadata-protocol reads it through its own structural type, while the published IAutomationService.canonicalizeStoredFlow contract is left unchanged. Either that is right, or the contract must declare the field (an additive optional output, which would make Clause-② yes). The review answers which.

    Report items, one line each:


    Generated by Claude Code

  6. objectstack-fleet commented on Oct 13, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report
    {
    "issue": 23269,
    "status": "done",
    "branch": "claude/issue-23269-v18-stored-row-fates",
    "pr": "#23315",
    "head_sha": "086d6f1ad",
    "session": "session_01BRQ9Mp1yH7R1az6MaUM18H — this run's harness-stamped id (a subagent: the parent's)",
    "premise_still_valid": true,
    "summary": "Patch round for contract review record 6152721854, which failed on semver and Clause-② only. Three edits, no change to any door, detector or predicate. (1) IAutomationService.canonicalizeStoredFlow's return declares todos?: ConversionTodoNotice[], the sibling of notices and conflicts, with a one-sentence docblock (packages/spec/src/contracts/automation-service.ts), and StoredFlowCanonicalization.todos?'s docblock now says it restates that member. (2) The changeset is minor for spec, service-automation and metadata-protocol, with Clause-②: yes (widening: ...) naming IAutomationService.canonicalizeStoredFlow(...).todos?, AutomationEngine.canonicalizeStoredFlow(...).todos and StoredFlowCanonicalization.todos?; the wiring paragraph keeps the ConversionTodoNotice.conversionId domain widening. The repository's one reader, scripts/pm/clause2-line.mjs readClause2Line, parses the line as value yes, arm widening. (3) PR body line 4 is Clause-②: yes (widening); lines 1-3 are unchanged. A new public-surface section names the three members, and the sentence saying the contract is not edited is gone. I merged origin/main first (331fa99, no conflict).",
    "tests": "At 086d6f1. Build: turbo closures of service-automation^... and metadata-protocol^..., plus the client... and client-react... closures, 35/35 tasks, exit 0. pnpm --filter @objectstack/spec check:generated exit 0 ('All 14 generated artifacts are up to date', api-surface and export-origins included; nothing regenerated). Reverse verification through scripts/ablation-replace.mjs: the engine's todos widened to ConversionTodoNotice[] | number, then pnpm --filter @objectstack/service-automation exec tsc --noEmit exit 1 as predicted, with src/engine.ts(4364,5): error TS2416: Property 'canonicalizeStoredFlow' in type 'AutomationEngine' is not assignable to the same property in base type 'IAutomationService'. The rebuilt dist/contracts/index.d.ts:3778 carries todos?. Restore proven: blob == HEAD, git diff HEAD empty. typecheck spec / service-automation / metadata-protocol: exit 0 each. Pins, exit 0 each: spec refused-shapes + stored + cbp-master-detail-required-defaulted (61 tests); service-automation canonicalize-stored-flow + engine (175); metadata-protocol protocol.stored-migration + protocol.flow-canonicalizer (60). pnpm --filter @objectstack/spec test:repo measured in full: exit 0, 58 files, 1007 tests.",
    "gates": "node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack at 086d6f1, no paths, no stale-tree warning: 115 commands, each exit code recorded before any pipe. 114 exited 0 on first run. check:dual-build-cjs-loads exited 3 (PREREQUISITE NOT MET: 33 packages with no dist in the recreated worktree); re-run after the battery, whose later gates had built them, it exited 0 ('108 published require entry point(s) across 67 package(s) load'), and that measured exit is the one recorded. The Clause-② gates (node scripts/check-changeset-no-major.mjs --base origin/main, node scripts/check-adr-0087-registration.mjs --base origin/main, both with --self-test) and pnpm --filter @objectstack/spec run check:api-surface: exit 0. --ran: '✓ dispatch-gates --ran: 115 derived famil(ies) accounted for — 115 run, 0 NOT-MEASURED (a DERIVED zero — all 115 recorded an exit code and none of them is 3).'",
    "line_budget": "1158 changed lines (+1097 / -61) in 18 files vs the 3000 human-merge threshold: under. This round's own commit: 3 files, +25 / -9. No generated file committed.",
    "files_changed": [
    ".changeset/23269-v18-stored-row-fates.md",
    "content/docs/deployment/cli.mdx",
    "packages/metadata-protocol/src/protocol.stored-migration.test.ts",
    "packages/metadata-protocol/src/protocol.ts",
    "packages/metadata-protocol/src/stored-migration.ts",
    "packages/services/service-automation/src/canonicalize-stored-flow.test.ts",
    "packages/services/service-automation/src/engine.ts",
    "packages/spec/src/contracts/automation-service.ts",
    "packages/spec/src/conversions/apply.ts",
    "packages/spec/src/conversions/refused-shapes.test.ts",
    "packages/spec/src/conversions/refused-shapes.ts",
    "packages/spec/src/conversions/stored.ts",
    "packages/spec/src/conversions/types.ts",
    "packages/spec/src/data/controlled-by-parent-master.ts",
    "packages/spec/src/data/object.zod.ts",
    "packages/spec/src/migrations/entries/semantic/18.cbp-master-relation-tiers-retired.ts",
    "packages/spec/src/migrations/entries/semantic/18.flow-value-slot-template-dialect-refused.ts",
    "packages/spec/src/migrations/entries/semantic/18.view-data-api-provider-retired.ts"
    ],
    "files_changed_this_round": [
    ".changeset/23269-v18-stored-row-fates.md",
    "packages/metadata-protocol/src/stored-migration.ts",
    "packages/spec/src/contracts/automation-service.ts"
    ],
    "deviations": [
    "This round's commit subject reads fix(spec)!:. The ! reads as breaking, but the change is a widening. It is pushed and was not rewritten. The changeset (minor, no breaking marker, Clause-② yes (widening)) and the PR title carry the level, and the PR title governs the squash.",
    "The reverse verification has no measured control leg. The claim that a contract without todos stays green under the same mutation rests on TypeScript's rule that an extra member is assignable; measuring it would take two more spec rebuilds.",
    "origin/main gained 87e902d, 4d4040c and 37510aa after the 331fa99 merge, none under the three changed packages (two changesets plus objectql/core/security). Not merged.",
    "The worktree was recreated from origin/claude/issue-23269-v18-stored-row-fates at af10b60 and is removed again after this report."
    ],
    "mcp_calls": "0 — no MCP tool used",
    "api_writes": "2 relay strokes — each one POST /repos/objectstack-ai/objectstack/dispatches (repository_dispatch, fleet-write relay), executed as objectstack-fleet[bot]: (1) issue_patch = PATCH /repos//issues/23315 (the PR body), read back identical (17534 bytes), with draft, head 086d6f1, lines 1-4 and one footer confirmed by my own REST read; (2) comment = POST /repos//issues/23269/comments (this os-dev-report). Plus git push of the branch (not a REST write). No label write.",
    "open_questions": [],
    "out_of_scope_findings": []
    }

  7. objectstack-fleet commented on Oct 13, 2026

    @objectstack-fleet
    ContributorAuthor

    ✅ Contract review PASS on the patched head; PR #23315 at 086d6f1ad is ready with auto-merge armed (Fixes #23269 · Fixes #23270 · Fixes #23271)

    domain:spec seat 2 (#18549) · os-justin · session session_01BRQ9Mp1yH7R1az6MaUM18H · 2026-10-13T20:14Z · holder of claims 6148030494 / 6148057324 / 6148082219. Thread-read: 6154171651.

    • Contract review: the first record 6152721854 FAILED on the semver and Clause-② section only (the published IAutomationService contract did not declare the todos the stored pass reads). The patch round (report 6154171651, 3 files, +25 / −9, no door, detector or predicate changed) declared todos? on the contract, made the changeset minor for the three packages and set Clause-②: yes (widening), naming the three members. The second record 6154280528 on 086d6f1ad: PASS.
    • Pre-queue checks on 086d6f1ad:
      • 41 success and 7 skipped, every skip on the expected-skips roster (Auto Label, Check PR Size, the dogfood pair, Console Pin Gate, Temporal Conformance, Packed-tarball smoke); 0 failures.
      • check-governed-merges --pr 23315 on the final file list: not governed, 1158 changed lines.
      • mergeable_state read unknown on six reads; a local git merge-tree of the head into origin/main merges with no conflict.
      • The body's lines 1–3 are the three Fixes lines; line 4 is Clause-②: yes (widening).
    • Landed through the relay in this act: pr_ready + automerge_enable.

    Next: confirm MERGED, the mis-close scan (three cards close; nothing else should), and the landing record.


    Generated by Claude Code

  8. objectstack-fleet commented on Oct 13, 2026

    @objectstack-fleet
    ContributorAuthor

    Landed: PR #23315 → 572ecfb2e (Fixes #23269 · Fixes #23270 · Fixes #23271). The three cards closed completed on the merge

    domain:spec seat 2 (#18549) · os-justin · session session_01BRQ9Mp1yH7R1az6MaUM18H · 2026-10-13T20:45Z · holder of claims 6148030494 / 6148057324 / 6148082219. Thread-read: 6154319725.


    Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions