You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
migrate: an os migrate value-shapes step stores null for '[]' and '""' already stored on optional multi-value columns (#29343 ruling A, data half) #29653
Filing gate: ② execution step 3 of ruling A on #29343 (record 6591577985). Filed by domain:server seat 4. ⛔ Not a claim. Suggested-grade: p3, the same as #29343.
What happens
Once #29343's door PR lands, a cleared optional multi-value field is stored as null. Rows written before that keep what the old door stored. The #29343 dev measured this on SQLite through the REST doors at origin/main322cf906 (os-dev-report 6591387317): [] is stored as the JSON text '[]' and '' as '""'. These rows then differ from newly cleared ones: = null, grouping and the read shape split them. Under the $empty table's multi_value row, '""' also does not read as empty.
Scope note for the seat that takes this card. ⛔ Not a claim.
The maintainer ruled at 2026-11-03T08:17Z, letter A on round 2 of #29343 (record 6598733139). Under that ruling, the door's 'emptyList' arm never reaches a readonly: true column.
This data step must exclude readonly columns the same way. sys_activity.changed_fields is today the only readonly optional multi-value column. There, a stored [] means "stamped, nothing changed" (ADR-0139 E6), and rewriting it to NULL would withhold the row from every non-system reader. Read the column set from blankAsNullColumns after PR #29837 lands, so the exclusion comes from the one rule rather than a second list.
Claim: PM loop round 1
Session: session_01Utp6CZMkHvuDeVYgTD73qF (seat) · dev card thread session_01Utp6CYyGh7z9Ki2krSKBC6
Account: os-bill
Branch: claude/project-thread-uz1jzf (the card thread's designated push branch, the recorded platform exception to claude/issue-<n>-<slug>)
Worktree: objectstack-issue-29653
Domain: domain:server
Seat: domain:server#4
File surface: the os migrate value-shapes step beside #29431's blank-single-values (PR #29615's files in packages/cli and the driver helpers it uses), its tests, one changeset. ⛔ packages/spec/**, docs/adr/**, .claude/**, repo-root AGENTS.md, ui/**, skills/** (stop on breach; explain in the report)
Container & model: M, mode:thread, model: default judgment tier (opus) — dispatch-gates --tier: no path-derived mandate, effort: default
Clause-②: no — a new opt-in migration step; nothing a caller sends is refused, and rows are rewritten only on --apply
Metadata-protocol: none
Responsibility: optional multi-value columns keep '[]' / '""' written before #29343's door stored null | none: old rows split from new null rows on = null, grouping and the read shape (os-dev-report 6591387317) | any deployment with multi-value rows cleared before #29343 landed
Thread-read: 6600631790
Premise: holds (Blocked-by #29343 is closed; the dev confirms the door now stores null first)
Serial constraints cleared: seats 2, 3 and 5 confirmed no overlap; no card in flight edits the migrate steps.
Dispatch order: /mnt/project-files/server-seat4/dispatch-29653.md (project shared folder). Ruling section: ruling A on #29343 (record 6591577985) step 3; triage 6600631790 (unblocked, p3), dispatched on the maintainer's 「并发都到5」. Fixes #29653.
Status: done. Draft PR #30508 carries Fixes #29653, head 2ae51bb5.
What it does:
Premise measured first, holds. On SQLite through the engine at origin/mainc5800818: the door stores null for a cleared optional multi-value column (engine.update with [], all four pinned types), while rows planted below the door store the JSON text '[]' and '""'. Before the run, $null: true finds only the row cleared today, $empty: true misses the stored '', and the read shapes are null, [] and ''.
New command os migrate blank-multi-values, a data step of its own beside blank-single-values. Columns = the 'emptyList' arm of blankAsNullColumns (@objectstack/core), so required, lifecycle and readonly columns (ruling record 6598733139, sys_activity.changed_fields) are out by the door's own rule, no second list. A blank = what the door's blankStorageForm(value, 'emptyList') stores as null: [] and exactly ''. Dry run by default; --apply, --yes, --force, --object, --max-records, --json as the sibling.
Shared walk.cleanBlankSingleValues' body moved unchanged into an exported walkBlankColumns(engine, logger, options, spec); both commands call it. The sibling's suite passes unchanged.
Deviations: the card title names os migrate value-shapes; this follows #29431's vehicle (server seat ruling 6588116815: value-shapes documents that it rewrites nothing), and the binding text of ruling A on #29343 (record 6591577985, step 3) is only "an os migrate data step … like #29431" (maintainer: 「另开一张清理已存 '[]' 的 migrate 卡」). The Claim's file surface wording says "the os migrate value-shapes step beside blank-single-values"; the files sit beside it as a sibling command. blank-single-values.ts is edited (the walk extracted), inside the Claim's surface (PR #29615's files).
{
"issue": 29653,
"status": "done",
"branch": "claude/project-thread-uz1jzf",
"pr": "https://github.com/objectstack-ai/objectstack/pull/30508",
"session": "session_01Utp6CYyGh7z9Ki2krSKBC6",
"premise_still_valid": true,
"summary": "New os migrate blank-multi-values rewrites the '[]' and '\"\"' still stored on optional multi-value columns to null, the form the #29343 door stores today. Columns come from blankAsNullColumns' emptyList arm (no required, lifecycle or readonly column), blanks from the door's blankStorageForm. The walk is the sibling blank-single-values' one, extracted unchanged into walkBlankColumns. Premise measured on SQLite: the door stores null; legacy rows split from it on $null, $empty and the read shape.",
"tests": "blank-multi-values.integration.test.ts (new, ObjectQL + SQLite SqlDriver): 6 passed (premise, red-before, column set, dry run, --apply incl. out-of-scope byte-identity and re-run zero, --object). Sibling blank-single-values 6 passed unchanged. Ablation via scripts/ablation-replace.mjs (committed first): isBlankMultiValue reduced to the empty list gives 2 of 6 red; restored, blob == HEAD, git diff HEAD empty. cli typecheck exit 0. cli unit project: 388/390 files on first run, the 2 published-subpath pins refused for an unbuilt cli dist, both green after pnpm --filter @objectstack/cli build (3 files 81 tests incl. migrate-confirmation-exit.pin). one-shot-family integration 164 passed; json-stdout-purity e2e (OS_TEST_TIERS=nightly) 101 passed. After git merge origin/main + install + cli closure build: 4 files 228 tests passed at 2ae51bb5.",
"gates": "dispatch-gates --commands derived 92 families vs merge base c58008187; exit recorded before any pipe: 89 exit 0, 3 exit 3 PREREQUISITE NOT MET (check-plugin-teardown-shape --self-test: fixture commit outside the shallow clone; spec check:skill-examples: client SDK not built; check:dual-build-cjs-loads: studio dist absent); check:i18n, check:i18n-coverage, check:i18n-walk-parity first exit 3 (cli unbuilt), exit 0 after the cli build. --ran: 92 derived, 89 run, 3 NOT-MEASURED, exit 0. pnpm lint exit 0. CI check-runs on #30508: not yet reported.",
"dogfood_battery": "n/a — no `!` in the PR title and no (narrowing) arm",
"line_budget": "source +348 new (blank-multi-values.ts) +37 -5 (blank-single-values.ts), tests +188 new +9 roster lines (3 files), docs +24, changeset +14; 8 files, +620 -5",
"files_changed": ".changeset/29653-migrate-blank-multi-values.md, content/docs/deployment/cli.mdx, packages/cli/src/commands/migrate/{blank-multi-values.ts, blank-multi-values.integration.test.ts, blank-single-values.ts}, packages/cli/src/utils/schema-migrate.one-shot-family.integration.test.ts, packages/cli/test/{json-stdout-purity.e2e.test.ts, migrate-confirmation-exit.pin.test.ts}",
"deviations": "vehicle is a sibling command (blank-multi-values), not a step inside value-shapes, per server seat ruling 6588116815 on #29431 and the binding text of ruling 6591577985 step 3; Postgres not covered, as the sibling step is not; json-stdout-purity e2e run with OS_TEST_TIERS=nightly (its tier)",
"mcp_calls": "0 MCP GitHub calls; GitHub reads went through gh api REST (issue, comments, pulls, PR files)",
"api_writes": "2 through the relay: pr_create #30508 (draft, no assignee, no labels, read-back identical) and this comment. Plus git pushes to claude/project-thread-uz1jzf (not REST)",
"open_questions": [],
"security_findings": "none",
"out_of_scope_findings": []
}
Activity
objectstack-fleet commentedon Nov 3, 2026
triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U
Path: none
Triage: p3 ·
pm:blockedkept · 2026-11-03T00:55Z⛔ Not a claim.
os migrate value-shapesstep storesnullfor'[]'and'""'already stored on optional multi-value columns. p3, as suggested.Blocked-by: #29343.Generated by Claude Code
objectstack-fleet commentedon Nov 3, 2026
domain:server#3 · os-warren · session_01JQwxbYyp6wSRcywGFK2L4A
Scope note for the seat that takes this card. ⛔ Not a claim.
The maintainer ruled at 2026-11-03T08:17Z, letter A on round 2 of #29343 (record 6598733139). Under that ruling, the door's
'emptyList'arm never reaches areadonly: truecolumn.This data step must exclude readonly columns the same way.
sys_activity.changed_fieldsis today the only readonly optional multi-value column. There, a stored[]means "stamped, nothing changed" (ADR-0139 E6), and rewriting it to NULL would withhold the row from every non-system reader. Read the column set fromblankAsNullColumnsafter PR #29837 lands, so the exclusion comes from the one rule rather than a second list.objectstack-fleet commentedon Nov 3, 2026
triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U
Path: none
Triage: unblocked · p3 kept ·
pm:blocked→pm:queue· 2026-11-03T10:00Z⛔ Not a claim.
Blocked-by: #29343is closed. Theos migrate value-shapesdata step proceeds.Generated by Claude Code
objectstack-fleet commentedon Nov 5, 2026
domain:server#4 · os-bill · session_01Utp6CZMkHvuDeVYgTD73qF
Claim: PM loop round 1
Session:
session_01Utp6CZMkHvuDeVYgTD73qF(seat) · dev card threadsession_01Utp6CYyGh7z9Ki2krSKBC6Account:
os-billBranch:
claude/project-thread-uz1jzf(the card thread's designated push branch, the recorded platform exception toclaude/issue-<n>-<slug>)Worktree:
objectstack-issue-29653Domain:
domain:serverSeat:
domain:server#4File surface: the
os migrate value-shapesstep beside #29431'sblank-single-values(PR #29615's files inpackages/cliand the driver helpers it uses), its tests, one changeset. ⛔packages/spec/**,docs/adr/**,.claude/**, repo-rootAGENTS.md,ui/**,skills/**(stop on breach; explain in the report)Container & model:
M,mode:thread,model: default judgment tier (opus) — dispatch-gates --tier: no path-derived mandate,effort: defaultClause-②: no — a new opt-in migration step; nothing a caller sends is refused, and rows are rewritten only on
--applyMetadata-protocol: none
Responsibility:
optional multi-value columns keep '[]' / '""' written before #29343's door stored null | none: old rows split from new null rows on = null, grouping and the read shape (os-dev-report 6591387317) | any deployment with multi-value rows cleared before #29343 landedThread-read: 6600631790
Premise: holds (Blocked-by #29343 is closed; the dev confirms the door now stores null first)
Serial constraints cleared: seats 2, 3 and 5 confirmed no overlap; no card in flight edits the migrate steps.
Dispatch order:
/mnt/project-files/server-seat4/dispatch-29653.md(project shared folder). Ruling section: ruling A on #29343 (record 6591577985) step 3; triage 6600631790 (unblocked, p3), dispatched on the maintainer's 「并发都到5」.Fixes #29653.Posted 2026-11-05T12:20Z.
wip(cli): blank-multi-values rosters, docs and changeset (#29653)
test(cli): pin blank-multi-values red-before on $null / $empty / read…
objectstack-fleet commentedon Nov 5, 2026
domain:server#4 · os-bill · session_01Utp6CZMkHvuDeVYgTD73qF
os-dev-report
Status: done. Draft PR #30508 carries
Fixes #29653, head2ae51bb5.What it does:
origin/mainc5800818: the door storesnullfor a cleared optional multi-value column (engine.updatewith[], all four pinned types), while rows planted below the door store the JSON text'[]'and'""'. Before the run,$null: truefinds only the row cleared today,$empty: truemisses the stored'', and the read shapes arenull,[]and''.os migrate blank-multi-values, a data step of its own besideblank-single-values. Columns = the'emptyList'arm ofblankAsNullColumns(@objectstack/core), sorequired, lifecycle andreadonlycolumns (ruling record 6598733139,sys_activity.changed_fields) are out by the door's own rule, no second list. A blank = what the door'sblankStorageForm(value, 'emptyList')stores asnull:[]and exactly''. Dry run by default;--apply,--yes,--force,--object,--max-records,--jsonas the sibling.cleanBlankSingleValues' body moved unchanged into an exportedwalkBlankColumns(engine, logger, options, spec); both commands call it. The sibling's suite passes unchanged.Deviations: the card title names
os migrate value-shapes; this follows #29431's vehicle (server seat ruling 6588116815:value-shapesdocuments that it rewrites nothing), and the binding text of ruling A on #29343 (record 6591577985, step 3) is only "anos migratedata step … like #29431" (maintainer: 「另开一张清理已存 '[]' 的 migrate 卡」). The Claim's file surface wording says "theos migrate value-shapesstep besideblank-single-values"; the files sit beside it as a sibling command.blank-single-values.tsis edited (the walk extracted), inside the Claim's surface (PR #29615's files).{ "issue": 29653, "status": "done", "branch": "claude/project-thread-uz1jzf", "pr": "https://github.com/objectstack-ai/objectstack/pull/30508", "session": "session_01Utp6CYyGh7z9Ki2krSKBC6", "premise_still_valid": true, "summary": "New os migrate blank-multi-values rewrites the '[]' and '\"\"' still stored on optional multi-value columns to null, the form the #29343 door stores today. Columns come from blankAsNullColumns' emptyList arm (no required, lifecycle or readonly column), blanks from the door's blankStorageForm. The walk is the sibling blank-single-values' one, extracted unchanged into walkBlankColumns. Premise measured on SQLite: the door stores null; legacy rows split from it on $null, $empty and the read shape.", "tests": "blank-multi-values.integration.test.ts (new, ObjectQL + SQLite SqlDriver): 6 passed (premise, red-before, column set, dry run, --apply incl. out-of-scope byte-identity and re-run zero, --object). Sibling blank-single-values 6 passed unchanged. Ablation via scripts/ablation-replace.mjs (committed first): isBlankMultiValue reduced to the empty list gives 2 of 6 red; restored, blob == HEAD, git diff HEAD empty. cli typecheck exit 0. cli unit project: 388/390 files on first run, the 2 published-subpath pins refused for an unbuilt cli dist, both green after pnpm --filter @objectstack/cli build (3 files 81 tests incl. migrate-confirmation-exit.pin). one-shot-family integration 164 passed; json-stdout-purity e2e (OS_TEST_TIERS=nightly) 101 passed. After git merge origin/main + install + cli closure build: 4 files 228 tests passed at 2ae51bb5.", "gates": "dispatch-gates --commands derived 92 families vs merge base c58008187; exit recorded before any pipe: 89 exit 0, 3 exit 3 PREREQUISITE NOT MET (check-plugin-teardown-shape --self-test: fixture commit outside the shallow clone; spec check:skill-examples: client SDK not built; check:dual-build-cjs-loads: studio dist absent); check:i18n, check:i18n-coverage, check:i18n-walk-parity first exit 3 (cli unbuilt), exit 0 after the cli build. --ran: 92 derived, 89 run, 3 NOT-MEASURED, exit 0. pnpm lint exit 0. CI check-runs on #30508: not yet reported.", "dogfood_battery": "n/a — no `!` in the PR title and no (narrowing) arm", "line_budget": "source +348 new (blank-multi-values.ts) +37 -5 (blank-single-values.ts), tests +188 new +9 roster lines (3 files), docs +24, changeset +14; 8 files, +620 -5", "files_changed": ".changeset/29653-migrate-blank-multi-values.md, content/docs/deployment/cli.mdx, packages/cli/src/commands/migrate/{blank-multi-values.ts, blank-multi-values.integration.test.ts, blank-single-values.ts}, packages/cli/src/utils/schema-migrate.one-shot-family.integration.test.ts, packages/cli/test/{json-stdout-purity.e2e.test.ts, migrate-confirmation-exit.pin.test.ts}", "deviations": "vehicle is a sibling command (blank-multi-values), not a step inside value-shapes, per server seat ruling 6588116815 on #29431 and the binding text of ruling 6591577985 step 3; Postgres not covered, as the sibling step is not; json-stdout-purity e2e run with OS_TEST_TIERS=nightly (its tier)", "mcp_calls": "0 MCP GitHub calls; GitHub reads went through gh api REST (issue, comments, pulls, PR files)", "api_writes": "2 through the relay: pr_create #30508 (draft, no assignee, no labels, read-back identical) and this comment. Plus git pushes to claude/project-thread-uz1jzf (not REST)", "open_questions": [], "security_findings": "none", "out_of_scope_findings": [] }Report taken 2026-11-05T13:47Z.
objectstack-fleet commentedon Nov 5, 2026
domain:server#4 · os-bill · session_01Utp6CZMkHvuDeVYgTD73qF
Landed · PR #30508 · card closed
b13fc7480;Fixes #29653closed this card. Seat record 6660268924 on head2ae51bb5(not BREAKING, not governed).mainsourcepackages/cli/src/commands/migrate/blank-multi-values.ts:57export function blankMultiValueColumns(schema: unknown): Array<{ name: string; type: string }> {os migrate blank-multi-values(dry run) and then--applyonce.The card's label
pm:dispatchedand theos-billassignee come off with this comment.Posted 2026-11-05T15:37Z.