fix(scripts): backfill-line-number and backfill-owner-id send query bodies the 17.6.0 door accepts (#1999) - #2002
Merged
objectstack-fleet[bot] merged 3 commits intoOct 3, 2026
Conversation
…oor accepts
`scripts/backfill-line-number.ts` and `scripts/backfill-owner-id.ts` sent
`filters: []` and `sort: 'id asc'` to `POST /api/v1/data/OBJECT/query`. The
17.6.0 door validates the body against `FindDataRequestSchema` and refuses
both (`query.filters` min_items, `query.sort` invalid_shape), so each script
failed on its first query and wrote nothing. They now send what
`scripts/backfill-contact-mailing-address.ts` sends: `sort` as
`[{ field: 'id', order: 'asc' }]` and no `filters` key. What each script
selects and writes is unchanged.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ER8ntXZhYebyQ66aXWdjfT
…d query schema `test/backfill-query-bodies.test.ts` imports each `scripts/backfill-*.ts` with `fetch` stubbed, so the script's own `main()` sends its real query bodies. The stub judges each body as the 17.6.0 REST query door does (`object` merged in, then `FindDataRequestSchema.safeParse`) and fails the case on any refusal, on a script that sent no body, or on a script that reported a failure. Nothing is exported from the scripts for this, so an inline body added later is caught as well. The next tightening of the query schema turns this red at `pnpm verify` instead of at an operator's terminal (#1999). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01ER8ntXZhYebyQ66aXWdjfT
…17.6.0 (#1999) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01ER8ntXZhYebyQ66aXWdjfT
|
The latest updates on your projects. Learn more about Vercel for GitHub. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #1999
Clause-②: no. These are operator scripts; they touch no published schema and no accept set.
Summary
scripts/backfill-line-number.tsandscripts/backfill-owner-id.tsstopped at their first query on@objectstack/*17.6.0 and wrote nothing. The 17.6.0 REST query door (POST /api/v1/data/OBJECT/query) checks the body againstFindDataRequestSchemafrom@objectstack/spec/api. It refusesfilters: [](min_items) andsort: 'id asc'(invalid_shape). Both scripts now send the shapesscripts/backfill-contact-mailing-address.tssends:sort: [{ field: 'id', order: 'asc' }]and nofilterskey. What each script selects and what it writes are unchanged.A new test,
test/backfill-query-bodies.test.ts, runs everyscripts/backfill-*.tsand checks each query body the script sends against the installed schema. The next time the schema gets stricter,pnpm verifyfails before an operator hits it.Changes
scripts/backfill-line-number.ts{ filters: [], fields, sort: 'id asc', skip, top: 200 }→{ fields, sort: [{ field: 'id', order: 'asc' }], skip, top: 200 }scripts/backfill-owner-id.tssys_userbody{ filters: [], fields: ['id'], top: 2000 }→{ fields: ['id'], top: 2000 }test/backfill-query-bodies.test.ts.changeset/1999-backfill-query-shapes.md'hotcrm': patch.changeset/line-item-line-number-writer.mdis unchanged. Its instructions are true now: report,--apply, and a rerun that reports zero were all measured below.Evidence
All runs used a fresh 17.6.0 boot on port 4819:
objectstack dev --no-watch --no-restart --seed-admin --artifact FILE --database file:DB, started from a scratch cwd with noobjectstack.config.ts(objectstack#21501). The server log saidNo objectstack.config.ts found — booting from artifactand named the artifact passed in.1. Reproduced on
f44ab642(unchanged scripts, report-only), exit 1 for both:The door's 400 bodies list
query.filtersmin_itemsandquery.sortinvalid_shapefor the page queries, andquery.filtersmin_itemsalone forsys_user.2. Only these two shapes are refused. I parsed every body against
FindDataRequestSchema, wrapped as the door wraps it ({ object, query: { ...body, object } }):filterstoo_small,sortinvalid_unionsys_userfilterstoo_smallsys_userNo other part of either body is refused.
top: 2000is accepted. The new bodies also pass on 17.0.0-rc.2, which was the pin whenownerwas removed (9f748ab5). So the owner script still works against the old releases it is meant to run on before an upgrade. Paging with the arraysortis stable on 17.6.0: reading 73 line items in pages of 10 gave the same 73 ids in the same ascending order as one page of 200.3.
backfill-line-number, at9b0d597e. To recreate lines from before the #1828 hook, I nulledline_numberdirectly in SQLite on 12 rows: all lines of one prospecting opportunity, the last 2 of a negotiation one, the last 1 of a closed-won one, all 4 of a draft quote, and the last 1 of an accepted quote.Reading the database afterwards, all 19 rows under those five parents have the same number they had before nulling (
0 of 19differ). The hook numbered each parent's lines in creation order and continued after any number the parent already had.4.
backfill-owner-id, at9b0d597e. On a 17.6.0 org that is already upgraded, the report saysno `owner` column — already upgraded, nothing to readfor each of the 12 objects, thenNo divergence to backfill, exit 0. To test the case the script exists for, I built a scratch artifact (not committed) that adds the oldownerlookup back tocrm_leadandcrm_account, and booted it on a fresh database. I added a second user through/api/v1/auth/admin/create-user. Then I set up four rows, through REST where it allowed and through SQLite where it refused:owneris reassigned to the second user;ownerset andowner_idempty;ownerset andowner_idempty;ownerisghost-user-000, a user that does not exist (REST refuses that value with 400, so it went in through SQLite).The unchanged
f44ab642script still failed on this database:cannot read sys_user (400).Reading the database afterwards,
owner_id = owneron all three rows that differed, and the ghost row is unchanged.5. The probe and its ablation.
test/backfill-query-bodies.test.tsimports eachscripts/backfill-*.tswithfetchstubbed, so each script's ownmain()sends its real requests. Report-only, the door returns no rows, so nothing reaches a write. The stub accepts or refuses each query body exactly as the door does. A case fails if any body is refused, if a script sends no body, or if a script callsconsole.error. It captured 16 bodies: 1 frombackfill-contact-mailing-address.ts, 2 frombackfill-line-number.tsand 13 frombackfill-owner-id.ts(sys_userplus 12 objects).Ablation, from the committed state
2b74bb67, withnode scripts/ablation-replace.mjsfrom objectstack. The predicted direction was red, and the run went red:Why a probe instead of exporting the bodies: each script starts
main()when it loads. Importing it from a test would need anisMainModuleguard, andtest/script-main-guard.test.tsthen requires a symlinked green and red spawn for every guarded script. A backfill script cannot pass the green spawn without a live server. The probe also checks the bodies the scripts actually send, so a body written inline somewhere new is caught too.Verification
OS_VERIFY_LOCK_SLOT=hotcrm-issue-1999 bash /home/user/objectstack/scripts/pm/os-verify-lock.sh -c 'pnpm verify'atb721702e:node scripts/check-source-token-ratchet.mjsgave byte-identical output before and after. Nosrc/file is touched. Thesrc/salesrows are unchanged: business semantics 56,418 / 59,000, interaction layer 27,968 / 31,000, authored total 99,882 / 107,000.Acceptance notes
allContacts()inscripts/backfill-contact-mailing-address.tssays the older backfill scripts use the two refused spellings. After this PR they no longer do, so that sentence is out of date. I left it alone because it is outside this card's declared file surface. Whoever next edits that script can fix it./unknown|no such|not a field/i). It does not check the error'scode: 'INVALID_FIELD'/field: 'owner'. On 17.6.0 the message (Unknown field 'owner' on object ...) still matches; that was measured.sys_userin one request (top: 2000). On an org with more users than that, an owner beyond the first 2000 would be listed as SKIPPED. A row would be skipped, never written wrong. This was not tested here.Generated by Claude Code