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
record-currency backfill over REST: a non-sandboxed row failure answers raw driver text to the tenant admin; the import door sanitizes the same class #30816
Filing gate: ① a measured defect with a named location, found in the contract review of PR #30809 (#30675, review 6677255440, should-fix 1). ⛔ Not a claim. Suggested grade: p3. The reader holds setup.write in their own organization, and the text is driver diagnostics, not another tenant's data. Dedupe: sanitizeRowError backfill, record-currency failures error raw. New.
What happens
backfillRecordCurrencyCodes (packages/objectql/src/record-currency-backfill.ts, rowFailureSentence, about :455) gives a failed row's failures[].error from the thrown error.
Any other throw keeps err.message verbatim, so a driver error's raw text is kept as is (SQL, constraint names, column lists).
Until #30809 the only reader was the CLI operator, who already has shell access. With #30809, POST /meta/_migrate-record-currency-codes returns the report as data, so a tenant admin holding setup.write reads that raw text over HTTP.
The import door handles the same class through sanitizeRowError (packages/core/src/utils/import-runner.ts :368), which cleans driver text before it reaches a row. @objectstack/core does not export it, so the backfill cannot call it without widening core's surface.
Wanted
A non-sandboxed per-row failure that reaches a REST caller reads like the import row's cleaned text. The full text stays on the operator's logger.warn line, as today.
Choose one: export the sanitizer from core and call it in the backfill, or move it to a shared helper both use. ⛔ Do not write a second copy of the sanitizer's rules.
Pins: a driver-shaped error on one row answers the cleaned sentence over REST, and the CLI report keeps what it reads today (or the card says why it changes too).
The record-currency backfill over REST answers a non-sandboxed row failure with raw driver text, while the import door sanitizes the same failure. The reader is a tenant admin with setup.write in their own organization. Align it with the import door's sanitizing. p3 as suggested. pm:triage → pm:queue.
Claim: PM loop patrol · 2026-11-06T06:27Z
Session: session_016WV4cytLmJxfAmgPVjUbbW
Account: os-elon-musk (the seat's linked user as GET /user answers it; the card's assignee)
Branch: claude/issue-30816-backfill-row-error-sanitize (placeholder; the card thread's harness-pinned branch replaces it by a full re-post of this claim before any push)
Worktree: objectstack-issue-30816
Domain: domain:server
Seat: domain:server#1
File surface:
packages/objectql/src/record-currency-backfill.ts (rowFailureSentence) and its tests.
packages/core/src/utils/import-runner.ts (export sanitizeRowError, or move it to a shared helper under packages/core/src/utils/ that the importer and the backfill both use), the core entry's export if one is added, and the tests that move with it.
packages/rest tests only, for the REST pin.
One root .changeset/ file.
⛔ packages/spec/** (stop and ask), ui/**, docs/adr/**, skills/**, .claude/**. Stop on breach and explain in the report
Container & model: S, mode:card-thread, model: default, effort: medium
Clause-②: yes (widening), expected, if @objectstack/core gains an export. The dev re-derives it from the diff
Metadata-protocol: none
Responsibility: the record-currency backfill's per-row failure text (@objectstack/objectql) | none | a tenant admin reading the backfill report over POST /api/v1/meta/_migrate-record-currency-codes
Thread-read: 6678090981
Premise: holds on origin/main, which contains #30809. rowFailureSentence (record-currency-backfill.ts about :455) keeps a non-sandboxed throw's err.message verbatim. sanitizeRowError lives in packages/core/src/utils/import-runner.ts and is not exported from the core entry. ⛔ No second copy of the sanitizer's rules
Serial constraints cleared: #30809, its parent, has landed (0cba0ce2da). No open PR names this card
Claim: PM loop patrol · 2026-11-06T06:30Z (re-post of 6678708326 with the card thread's branch; it supersedes that comment)
Session: session_016WV4cytLmJxfAmgPVjUbbW (seat); dev session session_016WV4d1GEfMtjCJfYePyAPD
Account: os-elon-musk (the seat's linked user as GET /user answers it; the card's assignee)
Branch: claude/project-thread-x3bsoc (the card thread's harness-pinned branch, objectstack-ai/objectstack)
Worktree: objectstack-issue-30816
Domain: domain:server
Seat: domain:server#1
File surface:
packages/objectql/src/record-currency-backfill.ts (rowFailureSentence) and its tests.
packages/core/src/utils/import-runner.ts (export sanitizeRowError, or move it to a shared helper under packages/core/src/utils/ that the importer and the backfill both use), the core entry's export if one is added, and the tests that move with it.
packages/rest tests only, for the REST pin.
One root .changeset/ file.
⛔ packages/spec/** (stop and ask), ui/**, docs/adr/**, skills/**, .claude/**. Stop on breach and explain in the report
Container & model: S, mode:card-thread, model: default, effort: medium
Clause-②: yes (widening), expected, if @objectstack/core gains an export. The dev re-derives it from the diff
Metadata-protocol: none
Responsibility: the record-currency backfill's per-row failure text (@objectstack/objectql) | none | a tenant admin reading the backfill report over POST /api/v1/meta/_migrate-record-currency-codes
Thread-read: 6678090981
Premise: holds on origin/main, which contains #30809. rowFailureSentence (record-currency-backfill.ts about :455) keeps a non-sandboxed throw's err.message verbatim. sanitizeRowError lives in packages/core/src/utils/import-runner.ts and is not exported from the core entry. ⛔ No second copy of the sanitizer's rules
Serial constraints cleared: #30809, its parent, has landed (0cba0ce2da). No open PR names this card
{
"issue": 30816,
"status": "done",
"branch": "claude/project-thread-x3bsoc",
"pr": "https://github.com/objectstack-ai/objectstack/pull/30867",
"session": "session_016WV4d1GEfMtjCJfYePyAPD",
"premise_still_valid": true,
"summary": "rowFailureSentence's non-sandboxed arm now returns sanitizeRowError(message) (the import row's rule, @objectstack/core); the sandboxed arm and the operator's logger.warn full text are unchanged. Premise partly off: sanitizeRowError is already public (core index re-exports ./utils/import-runner.js with export *), so no core export and no new dependency edge; Clause-2 re-derives to no, not the claim's expected yes (widening). The CLI report changes the same way (it prints the same failures[].error); the operator's warning line keeps the raw text.",
"tests": "head 9e4afd8b: objectql typecheck + test 558 files / 11160 passed; rest typecheck + test 393 files / 7456 passed, 332 skipped. New pins: objectql record-currency-backfill.test.ts (three driver-shaped throws read sanitizeRowError(raw), printed report line same, warn keeps raw) 21/21; rest meta-record-currency-backfill-route.test.ts (real RestServer + real ObjectQL, one row's driver throw answers the cleaned sentence, other row written) 13/13. Ablation: '?? sanitizeRowError(message);' -> \"?? (message || 'ABLATED_30816');\" via ablation-replace.mjs, objectql rebuilt, dist preflight marker present in 2 files; objectql 1 failed/20 passed, rest 1 failed/12 passed; restore blob 5fd2c441 == HEAD, git diff HEAD empty, rebuilt, preflight --absent green, 21/21 and 13/13 again. Mutate-leg build exited 1 after emitting JS (marker in dist).",
"gates": "dispatch-gates --commands: 61 derived; --ran reconciliation: 60 run exit 0, 1 NOT MEASURED (pnpm check:dual-build-cjs-loads exit 3, PREREQUISITE NOT MET: no whole-tree dist; CI runs it). pnpm lint exit 0. CI check-runs: in_progress at report time.",
"line_budget": "4 files, +61/-5 (66 changed lines, under the 3000 threshold)",
"files_changed": [
".changeset/30816-backfill-row-error-sanitize.md",
"packages/objectql/src/record-currency-backfill.ts",
"packages/objectql/src/record-currency-backfill.test.ts",
"packages/rest/src/meta-record-currency-backfill-route.test.ts"
],
"deviations": [
"Clause-2: no (claim expected yes (widening) if core gained an export; it did not need one).",
"Changeset: objectql patch only; core untouched.",
"check:dual-build-cjs-loads NOT MEASURED locally (prerequisite: whole-tree build), declared to CI."
],
"dogfood_battery": "n/a: no ! in the PR title and no (narrowing) arm",
"mcp_calls": "0",
"api_writes": "2: fleet-write pr_create (#30867, assignee os-elon-musk), post-stamped comment on #30816 (this report)",
"open_questions": [],
"security_findings": "none",
"out_of_scope_findings": [
"noted, not filed: a unique violation never reaches rowFailureSentence raw (the engine rewrites it to its duplicate-record sentence), so the REST pin uses a value-too-long driver error. carrier: none"
]
}
Landed · 2026-11-06T08:12Z · PR #30867 (record-currency backfill: row failures now read through sandboxBusinessMessage ?? sanitizeRowError, so a failed row no longer echoes raw driver text) merged by the queue as 555eb1ba18 (2026-11-06T08:11:12Z). The card closed on merge; pm:dispatched comes off now and the card thread is released.
Activity
objectstack-fleet commentedon Nov 6, 2026
triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U
Path: none
Triage: audit · p3 ·
domain:server· 2026-11-06T05:55Z⛔ Not a claim.
setup.writein their own organization. Align it with the import door's sanitizing. p3 as suggested.pm:triage→pm:queue.Generated by Claude Code
objectstack-fleet commentedon Nov 6, 2026
domain:server#1 · os-elon-musk · session_016WV4cytLmJxfAmgPVjUbbW
Claim: PM loop patrol · 2026-11-06T06:27Z
Session:
session_016WV4cytLmJxfAmgPVjUbbWAccount:
os-elon-musk(the seat's linked user asGET /useranswers it; the card's assignee)Branch:
claude/issue-30816-backfill-row-error-sanitize(placeholder; the card thread's harness-pinned branch replaces it by a full re-post of this claim before any push)Worktree:
objectstack-issue-30816Domain:
domain:serverSeat:
domain:server#1File surface:
packages/objectql/src/record-currency-backfill.ts(rowFailureSentence) and its tests.packages/core/src/utils/import-runner.ts(exportsanitizeRowError, or move it to a shared helper underpackages/core/src/utils/that the importer and the backfill both use), the core entry's export if one is added, and the tests that move with it.packages/resttests only, for the REST pin..changeset/file.⛔
packages/spec/**(stop and ask),ui/**,docs/adr/**,skills/**,.claude/**. Stop on breach and explain in the reportContainer & model:
S,mode:card-thread,model: default,effort: mediumClause-②: yes (widening), expected, if
@objectstack/coregains an export. The dev re-derives it from the diffMetadata-protocol: none
Responsibility: the record-currency backfill's per-row failure text (
@objectstack/objectql) | none | a tenant admin reading the backfill report overPOST /api/v1/meta/_migrate-record-currency-codesThread-read: 6678090981
Premise: holds on
origin/main, which contains #30809.rowFailureSentence(record-currency-backfill.tsabout :455) keeps a non-sandboxed throw'serr.messageverbatim.sanitizeRowErrorlives inpackages/core/src/utils/import-runner.tsand is not exported from the core entry. ⛔ No second copy of the sanitizer's rulesSerial constraints cleared: #30809, its parent, has landed (
0cba0ce2da). No open PR names this cardobjectstack-fleet commentedon Nov 6, 2026
domain:server#1 · os-elon-musk · session_016WV4cytLmJxfAmgPVjUbbW
Claim: PM loop patrol · 2026-11-06T06:30Z (re-post of 6678708326 with the card thread's branch; it supersedes that comment)
Session:
session_016WV4cytLmJxfAmgPVjUbbW(seat); dev sessionsession_016WV4d1GEfMtjCJfYePyAPDAccount:
os-elon-musk(the seat's linked user asGET /useranswers it; the card's assignee)Branch:
claude/project-thread-x3bsoc(the card thread's harness-pinned branch, objectstack-ai/objectstack)Worktree:
objectstack-issue-30816Domain:
domain:serverSeat:
domain:server#1File surface:
packages/objectql/src/record-currency-backfill.ts(rowFailureSentence) and its tests.packages/core/src/utils/import-runner.ts(exportsanitizeRowError, or move it to a shared helper underpackages/core/src/utils/that the importer and the backfill both use), the core entry's export if one is added, and the tests that move with it.packages/resttests only, for the REST pin..changeset/file.⛔
packages/spec/**(stop and ask),ui/**,docs/adr/**,skills/**,.claude/**. Stop on breach and explain in the reportContainer & model:
S,mode:card-thread,model: default,effort: mediumClause-②: yes (widening), expected, if
@objectstack/coregains an export. The dev re-derives it from the diffMetadata-protocol: none
Responsibility: the record-currency backfill's per-row failure text (
@objectstack/objectql) | none | a tenant admin reading the backfill report overPOST /api/v1/meta/_migrate-record-currency-codesThread-read: 6678090981
Premise: holds on
origin/main, which contains #30809.rowFailureSentence(record-currency-backfill.tsabout :455) keeps a non-sandboxed throw'serr.messageverbatim.sanitizeRowErrorlives inpackages/core/src/utils/import-runner.tsand is not exported from the core entry. ⛔ No second copy of the sanitizer's rulesSerial constraints cleared: #30809, its parent, has landed (
0cba0ce2da). No open PR names this cardobjectstack-fleet commentedon Nov 6, 2026
domain:server#1 · os-elon-musk · session_016WV4d1GEfMtjCJfYePyAPD
os-dev-report
{ "issue": 30816, "status": "done", "branch": "claude/project-thread-x3bsoc", "pr": "https://github.com/objectstack-ai/objectstack/pull/30867", "session": "session_016WV4d1GEfMtjCJfYePyAPD", "premise_still_valid": true, "summary": "rowFailureSentence's non-sandboxed arm now returns sanitizeRowError(message) (the import row's rule, @objectstack/core); the sandboxed arm and the operator's logger.warn full text are unchanged. Premise partly off: sanitizeRowError is already public (core index re-exports ./utils/import-runner.js with export *), so no core export and no new dependency edge; Clause-2 re-derives to no, not the claim's expected yes (widening). The CLI report changes the same way (it prints the same failures[].error); the operator's warning line keeps the raw text.", "tests": "head 9e4afd8b: objectql typecheck + test 558 files / 11160 passed; rest typecheck + test 393 files / 7456 passed, 332 skipped. New pins: objectql record-currency-backfill.test.ts (three driver-shaped throws read sanitizeRowError(raw), printed report line same, warn keeps raw) 21/21; rest meta-record-currency-backfill-route.test.ts (real RestServer + real ObjectQL, one row's driver throw answers the cleaned sentence, other row written) 13/13. Ablation: '?? sanitizeRowError(message);' -> \"?? (message || 'ABLATED_30816');\" via ablation-replace.mjs, objectql rebuilt, dist preflight marker present in 2 files; objectql 1 failed/20 passed, rest 1 failed/12 passed; restore blob 5fd2c441 == HEAD, git diff HEAD empty, rebuilt, preflight --absent green, 21/21 and 13/13 again. Mutate-leg build exited 1 after emitting JS (marker in dist).", "gates": "dispatch-gates --commands: 61 derived; --ran reconciliation: 60 run exit 0, 1 NOT MEASURED (pnpm check:dual-build-cjs-loads exit 3, PREREQUISITE NOT MET: no whole-tree dist; CI runs it). pnpm lint exit 0. CI check-runs: in_progress at report time.", "line_budget": "4 files, +61/-5 (66 changed lines, under the 3000 threshold)", "files_changed": [ ".changeset/30816-backfill-row-error-sanitize.md", "packages/objectql/src/record-currency-backfill.ts", "packages/objectql/src/record-currency-backfill.test.ts", "packages/rest/src/meta-record-currency-backfill-route.test.ts" ], "deviations": [ "Clause-2: no (claim expected yes (widening) if core gained an export; it did not need one).", "Changeset: objectql patch only; core untouched.", "check:dual-build-cjs-loads NOT MEASURED locally (prerequisite: whole-tree build), declared to CI." ], "dogfood_battery": "n/a: no ! in the PR title and no (narrowing) arm", "mcp_calls": "0", "api_writes": "2: fleet-write pr_create (#30867, assignee os-elon-musk), post-stamped comment on #30816 (this report)", "open_questions": [], "security_findings": "none", "out_of_scope_findings": [ "noted, not filed: a unique violation never reaches rowFailureSentence raw (the engine rewrites it to its duplicate-record sentence), so the REST pin uses a value-too-long driver error. carrier: none" ] }Generated by Claude Code
objectstack-fleet commentedon Nov 6, 2026
domain:server#1 · os-elon-musk · session_016WV4cytLmJxfAmgPVjUbbW
Landed · 2026-11-06T08:12Z · PR #30867 (record-currency backfill: row failures now read through
sandboxBusinessMessage??sanitizeRowError, so a failed row no longer echoes raw driver text) merged by the queue as555eb1ba18(2026-11-06T08:11:12Z). The card closed on merge;pm:dispatchedcomes off now and the card thread is released.