Skip to content

scripts/backfill-line-number.ts and scripts/backfill-owner-id.ts fail on 17.6.0 before writing anything: the query door refuses their request bodies (filters: [] and sort: 'id asc') #1999

Description

@objectstack-fleet

Filing gate: ① product defect with reach measured. Class (a). reach: named producers. Both scripts were run report-only against a fresh @objectstack/* 17.6.0 boot:

  • scripts/backfill-line-number.ts → Backfill failed: query crm_opportunity_line_item → 400: Invalid query request
  • scripts/backfill-owner-id.ts → Backfill failed: cannot read sys_user (400)

Release-text exception too: the pending, unreleased .changeset/line-item-line-number-writer.md tells operators to run the first script, so the next release would ship an instruction that fails.

Who acts on it: the repo:hotcrm seat, which dispatches a dev. Found by the seat's dev while writing #1836's backfill (session_01ER8ntXZhYebyQ66aXWdjfT). ⛔ Not a claim; the first-touch grade is owed.

Measured

  • On 17.6.0, POST /api/v1/data/OBJECT/query refuses two body shapes the scripts send:
    • an empty filters: [] (query.filters min_items);
    • a string sort: 'id asc' (query.sort invalid_shape).
  • The new scripts/backfill-contact-mailing-address.ts (PR feat(contact): one structured mailing_address replaces five flat mailing_* fields (#1836) #1997) uses the accepted shapes, sort: [{ field: 'id', order: 'asc' }] with no empty filters, and runs green on the same boot. It is the in-repo reference.

Done when

  • Both scripts run report-only and --apply green on a fresh 17.6.0 boot.
  • A test or a probe keeps their query bodies inside the installed query schema, so the next schema tightening fails at verify rather than at an operator's terminal.
  • The changeset text stays true.

Duplicate check

All hotcrm issues, open and closed: 748 issues over 19 REST pages. Title and body were grepped for backfill-(line-number|owner-id): 1 hit, #716 (closed). It concerns demo_bootstrap ownership claims, not these query shapes.

Dedupe words: backfill-line-number backfill-owner-id filters min_items sort invalid_shape query 17.6.0


Generated by Claude Code

Activity

  1. objectstack-fleet commented on Oct 3, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop round R72
    Session: session_01ER8ntXZhYebyQ66aXWdjfT
    Account: hotlong (the seat's linked user as GET /user answers it; always the card's assignee)
    Branch: claude/issue-1999-backfill-query-shapes
    Worktree: hotcrm-issue-1999
    Domain: repo:hotcrm (single-lane repo, no domain:* taxonomy)
    Seat: repo:hotcrm#1
    File surface: scripts/backfill-line-number.ts, scripts/backfill-owner-id.ts; one test or probe that keeps every scripts/backfill-*.ts query body inside the installed query schema; .changeset/line-item-line-number-writer.md only if its text becomes false; one .changeset/1999-*.md (stop on breach; explain in the report)
    Container & model: S, mode:subagent, model: default (dispatch-gates --tier --repo objectstack-ai/hotcrm answers "no path-derived mandate … the tier stays the PM's per-card judgment call")
    Clause-②: no. These are operator scripts; they touch no published schema and no accept set.
    Thread-read: none
    Serial constraints cleared: #1998 touches only src/sales/mappings/**, which is disjoint. No open PR exists.

    Seat's first-touch grade: p2 bug, dispatched directly (pm:dispatched). The pending changeset tells operators to run a script that fails on 17.6.0, so this is the release-text exception.


    Generated by Claude Code

  2. objectstack-fleet commented on Oct 3, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report

    {
      "issue": 1999,
      "status": "done",
      "branch": "claude/issue-1999-backfill-query-shapes",
      "pr": "https://github.com/objectstack-ai/hotcrm/pull/2002",
      "session": "session_01ER8ntXZhYebyQ66aXWdjfT — subagent of the repo:hotcrm seat (container CLAUDE_CODE_REMOTE_SESSION_ID=cse_01ER8ntXZhYebyQ66aXWdjfT)",
      "premise_still_valid": true,
      "summary": "Reproduced both failures on a fresh 17.6.0 boot at f44ab642, exactly as the card says. The 17.6.0 REST query door parses the body with FindDataRequestSchema (@objectstack/spec/api), which refuses exactly two shapes: filters: [] (min_items) and sort: 'id asc' (invalid_union, reported as invalid_shape). Both scripts now send the reference script's shapes: sort as [{ field: 'id', order: 'asc' }] and no filters key. Nothing else they select or write changed. On fresh boots, line-number did report 12, --apply 12/12, and the rerun found 0; the 19 rows under the 5 touched parents read back with their original numbers in creation order. Owner-id on an org with the legacy owner field did report 3 divergences plus 1 orphan, --apply 3/3, and the rerun found no divergence. On an upgraded org it says 'already upgraded' for each object. New test/backfill-query-bodies.test.ts runs every scripts/backfill-*.ts with fetch stubbed and checks all 16 query bodies they send against the installed schema. The ablation (line-number sort back to 'id asc') turned it red, and it was restored. Draft PR #2002 is open and assigned to hotlong. Worktree removed.",
      "tests": "pnpm verify (OS_VERIFY_LOCK_SLOT=hotcrm-issue-1999 bash /home/user/objectstack/scripts/pm/os-verify-lock.sh -c 'pnpm verify') at HEAD b721702e (git rev-parse --short HEAD recorded in the same log): 'Test Files  177 passed (177)' / 'Tests  3791 passed | 1 skipped (3792)' / 'os-verify-lock: VERDICT command-exit 0 · held the lock 184s (3m04s) · waited 0s'. Stages: validate '✓ Validation passed', tsc --noEmit, lint, '✓ i18n lint gate: 0 `i18n/missing-*` issues', '✓ source hygiene clean', '✓ source token ratchet clean', '✓ Build complete'. || New test alone, at 2b74bb67: 'Tests  4 passed (4)', VERDICT command-exit 0. A scratch copy, deleted afterwards (git status empty), printed the captured bodies: mailing-address 1 (crm_contact), line-number 2 (both line items), owner-id 13 (sys_user plus 12 objects). || Ablation from committed 2b74bb67 via objectstack scripts/ablation-replace.mjs. Predicted direction: red. Observed: red. On disk: 'ok mutation landed: anchor 1 -> 0, blob 66b88b75f87f -> 8ca770eed240'. Run: '× scripts/backfill-line-number.ts sends only query bodies the door accepts', refused ['query.sort: invalid_union'] for body {fields,skip:0,sort:'id asc',top:200}, 'Tests  1 failed | 3 passed (4)', VERDICT command-exit 1. Restore: 'ok restored: blob == HEAD (66b88b75f87f) and `git diff HEAD` is empty'. No build/dist step applies; the test imports scripts/*.ts source directly. || Repro at f44ab642 (fresh 17.6.0 boot, port 4819, --artifact from a scratch cwd with no objectstack.config.ts; the log says 'No objectstack.config.ts found — booting from artifact'): line-number exit 1 'Backfill failed: query crm_opportunity_line_item → 400: Invalid query request'; owner-id exit 1 'Backfill failed: cannot read sys_user (400)'. Door 400 fields: query.filters min_items + query.sort invalid_shape; sys_user: query.filters min_items only. || Schema matrix (FindDataRequestSchema.safeParse({object, query:{...body, object}})): the old bodies pass on 17.0.0-rc.2 and are refused on 17.5.0 and 17.6.0; the new bodies pass on all three. top: 2000 is accepted. Paging with the array sort on 17.6.0: 73 line items in pages of 10 = 73 unique ids, in the same order as one page. || Behaviour, line-number at 9b0d597e: line_number nulled via SQLite on 12 rows across 3 opportunities and 2 quotes. report exit 0 '7 without a line number, under 3 parent(s)' / '5 ... under 2 parent(s)'; --apply exit 0 'Backfilled 7/7' and 'Backfilled 5/5'; rerun --apply exit 0, 0 and 0. DB read-back: 0 of 19 rows differ from the original numbering. || Behaviour, owner-id at 9b0d597e: on the upgraded artifact it reports 'no `owner` column — already upgraded' for each of 12 objects and 'No divergence', exit 0. On a scratch artifact (not committed) with legacy owner on crm_lead and crm_account, plus a second user via auth admin create-user: report exit 0 'Scanned 30 record(s) across 2 object(s)', 3 divergences ((none) to admin, (none) to rep2, admin to rep2), 1 orphan SKIPPED; --apply 'Backfilled 3/3'; rerun 'No divergence to backfill'. DB read-back owner_id = owner on all 3. The base f44ab642 script on the same DB: 'cannot read sys_user (400)'. || PR checks at report time (b721702e): Check Changeset success, Quality Checks success, Label Pull Request success, link-check success. Build and Test (22.x), Playwright and Analyze Code are in_progress: NOT MEASURED, reason: CI convergence is the seat's to read.",
      "token_ratchet": "node scripts/check-source-token-ratchet.mjs exit 0 before and after; output byte-identical (diff empty). src/sales rows, verbatim before = after: 'business semantics          47   5,740   225,673    56,418    59,000' · 'interaction layer           25   3,373   111,870    27,968    31,000' · 'authored total             117  10,409   399,528    99,882   107,000'. No ceiling touched.",
      "files_changed": [
        "scripts/backfill-line-number.ts (+7/-2)",
        "scripts/backfill-owner-id.ts (+12/-4)",
        "test/backfill-query-bodies.test.ts (new, 139 lines)",
        ".changeset/1999-backfill-query-shapes.md (new, 'hotcrm': patch)"
      ],
      "deviations": [
        "Hypothesis 5's suggested route (export the bodies) was replaced by a fetch-stub probe. Exporting means importing a script whose main() runs when it loads. That needs an isMainModule guard, and test/script-main-guard.test.ts then requires a symlinked green and red spawn per guarded script, which a backfill script cannot provide without a live server. The probe needs no refactor of the scripts and checks the bodies they actually send.",
        "The probe repeats the 17.6.0 REST door's wrapping ({ object, query: { ...body, object } }) next to the spec schema. If @objectstack/rest changes that wrapping, the probe would have to follow.",
        "Owner behaviour used a scratch-built artifact: the current tree plus the legacy owner lookup on crm_lead and crm_account, built from a git-archive copy outside the worktree and deleted afterwards. No older hotcrm release was built. Rows were set up through REST where it allowed; through SQLite where it refused (the owner_id-null rows and the ghost-owner row, which REST refuses with 400).",
        "Line-number rows without a number were produced by a direct SQLite UPDATE (a storage-level system write) on the boot DB.",
        "Downloaded (npm pack, into scratch only; nothing added to the repo) @objectstack/spec and @objectstack/rest at 17.0.0-rc.2 and 17.5.0, to compare the schemas.",
        "Two temporary files existed in the worktree during measurement and were deleted before any later commit, with git status empty afterwards: scripts/.base-owner-probe.ts (a copy of the base script, used to run it on the legacy DB) and test/zz-scratch-count-1999.test.ts (the body counter).",
        "AGENTS.md §3 (tests pin only this repo's own facts): the new test checks this repo's own operator scripts against the platform's published request schema. It holds no platform rule of its own and no roster. Stated in the PR's Acceptance notes."
      ],
      "mcp_calls": "0 — no MCP tool was called",
      "api_writes": "3 — all through the fleet relay (scripts/pm, run from /home/user/objectstack, each one POST /repos/objectstack-ai/objectstack/dispatches executed as objectstack-fleet[bot]): (1) pr_create, POST /repos/objectstack-ai/hotcrm/pulls (draft, #2002; read-back: 9134 bytes sent, 9134 stored, identical); (2) label-write --assign hotlong, POST /repos/objectstack-ai/hotcrm/issues/2002/assignees (read-back: assignees `hotlong`; labels `ci/cd` came from the labeler, not this run); (3) this os-dev-report comment, POST /repos/objectstack-ai/hotcrm/issues/1999/comments via post-stamped.mjs. Plus git push of the branch (not REST).",
      "open_questions": [],
      "out_of_scope_findings": [
        "carrier: 承接者:无 · noted, not filed · scripts/backfill-contact-mailing-address.ts allContacts() doc comment says the older backfill scripts 'use' the two refused spellings. After this PR that is stale. Outside the claim's file surface; recorded in the PR's Acceptance notes.",
        "carrier: 承接者:无 · noted, not filed · backfill-owner-id.ts detects an upgraded org by regex on the 400 message text (/unknown|no such|not a field/i), not on code INVALID_FIELD + field owner. It works on 17.6.0 (measured: 'Unknown field 'owner' on object ...'), so this is no class (a) defect. Recorded in the PR's Acceptance notes.",
        "carrier: 承接者:无 · noted, not filed · backfill-owner-id.ts reads sys_user as one request (top: 2000). An org with more than 2000 users would list a real owner beyond the first 2000 as SKIPPED: the row is skipped, never written wrong. Not tested. Recorded in the PR's Acceptance notes."
      ]
    }

    Generated by Claude Code

  3. objectstack-fleet commented on Oct 3, 2026

    @objectstack-fleet
    ContributorAuthor

    ACCEPT: PR #2002 at b721702e. Both backfill scripts run on 17.6.0. repo:hotcrm seat, session_01ER8ntXZhYebyQ66aXWdjfT, 2026-10-03T09:54Z. Report: the dev's os-dev-report on this card.

    Probes taken by the seat itself:

    • Ancestry and checks: f44ab642 is an ancestor of b721702e, and git merge-tree against today's main 5b1f79b3 (fix(contact-import): the shipped contacts.csv imports all 50 rows ("HR" maps to the hr department) #2001) is clean. CI 9/9 success. Governed check: 0 of 4 paths, NOT governed; 192 lines.
    • Read line by line: each script's request bodies drop filters: [] and swap sort: 'id asc' for sort: [{ field: 'id', order: 'asc' }]. That is the shape scripts/backfill-contact-mailing-address.ts already uses. What the scripts select and write is unchanged.

    The dev's measurements, accepted:

    • Reproduced on a fresh 17.6.0 boot: query crm_opportunity_line_item → 400 and cannot read sys_user (400). The door names exactly query.filters min_items and query.sort invalid_shape. The old bodies pass FindDataRequestSchema on 17.0.0-rc.2 and are refused on 17.5.0 / 17.6.0; the new ones pass on all three.
    • Behaviour after the fix:
      • backfill-line-number: report shows 12, --apply writes 12/12, the rerun finds 0, and 0 of 19 rows changed their original numbering;
      • backfill-owner-id: on a legacy-owner org, 3 divergences are backfilled and the rerun finds none; on an upgraded org it reports "already upgraded".
    • New test: test/backfill-query-bodies.test.ts runs every scripts/backfill-*.ts with fetch stubbed and checks all 16 bodies they send against the installed schema. An ablation back to sort: 'id asc' goes red, and the restore is proven.
    • Gates: pnpm verify VERDICT command-exit 0 (177 files); tokens unchanged.

    Noted, not blocking (in the PR's Acceptance notes):

    • The allContacts() doc comment in backfill-contact-mailing-address.ts is now stale.
    • Owner-id detects an upgraded org by message regex.
    • The sys_user read is a single request (top: 2000).

    Landing:

    • Authority: 「授权你执行pr合并」 (2026-10-03, about 04:52Z), on a p2 bug card the seat filed under the release-text exception.
    • Path: ready → auto-merge → queue.

    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

No one assigned

    Labels

    bugSomething isn't workingpriority:p2Medium: important, M3

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions