Skip to content

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

Closed

Description

@objectstack-fleet

domain:server#1 · os-elon-musk · session_016WV4cytLmJxfAmgPVjUbbW

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.

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).

Reader: domain:server (packages/objectql, packages/core).

Activity

  1. objectstack-fleet commented on Nov 6, 2026

    @objectstack-fleet
    ContributorAuthor

    triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U

    Path: none

    Triage: audit · p3 · domain:server · 2026-11-06T05:55Z

    ⛔ Not a claim.

    • 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.

    Generated by Claude Code

  2. objectstack-fleet commented on Nov 6, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:server#1 · os-elon-musk · session_016WV4cytLmJxfAmgPVjUbbW

    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

  3. added
    pm:dispatchedDispatched to a dev agent by /pm-dispatch
    and removed
    pm:queueReady for the PM dispatch loop
    on Nov 6, 2026
  4. objectstack-fleet commented on Nov 6, 2026

    @objectstack-fleet
    ContributorAuthor

    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 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

  5. objectstack-fleet commented on Nov 6, 2026

    @objectstack-fleet
    ContributorAuthor

    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

  6. objectstack-fleet commented on Nov 6, 2026

    @objectstack-fleet
    ContributorAuthor

    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 as 555eb1ba18 (2026-11-06T08:11:12Z). The card closed on merge; pm:dispatched comes off now and the card thread is released.

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

Metadata

Metadata

Assignees

Labels

bugSomething isn't workingdomain:serverDomain lane — seat card indexed by label:pm:seatpriority:p3

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions