docs(platform-objects): drop the false minted-id width from sys_import_job's bound derivation - #16953
Conversation
…t_job's bound derivation The comment justifying `created_by`'s `maxLength: 255` headroom claimed "a minted platform id is 26 characters". Re-measured on this tree by driving the real SqlDriver against SQLite: twelve create() calls supplying no id yield exactly one distinct width, 16, and a caller-supplied id is stored verbatim at whatever width the caller chose (10/17/18/26/40/200 all landed unaltered). The replacement states no new fixed width, because a fixed width is what expired: mint width is driver-owned, and driver-memory mints no fixed width at all. It points instead at driver-sql's [#15522] note beside DEFAULT_ID_LENGTH, where the claim is measured and maintained, and gives the reason 255 is safe without a floor — it is the width of the column this value is copied from. `maxLength: 255` and the derivation above it are unchanged; no accept set, schema arm, index or export moves. Refs #16410. Claude-Session: https://claude.ai/code/session_016N6xmWt5hYm94ffVEwGH8x Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
📓 Docs Drift Check1 anchor(s) derived from 1 changed package(s); no hand-written page names any of them, so this run has nothing to list — not a clean bill of health. This check sees only pages that NAME a derived anchor: one that documents this change in prose, or enumerates it in an authoring dialect, names none and stays invisible to it on every run. What this run could not see
Coarse fallback — 2 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): Which tree this was computed onThis run read A worktree cut from an older # while this PR is open — GitHub drops the merge commit once it closes
git fetch origin 5eaf4e5de69f32d4fe3b58c0c00e8bcb22db02c4 && git checkout 5eaf4e5de69f32d4fe3b58c0c00e8bcb22db02c4
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 5abca1792ed20dfb9020113e6242f25fbfc47ddb 02d972c4099866382999131bce17643f0703243a && git checkout -B drift-repro 5abca1792ed20dfb9020113e6242f25fbfc47ddb && git merge --no-ff 02d972c4099866382999131bce17643f0703243a
node scripts/docs-audit/affected-docs.mjs --json 5abca1792ed20dfb9020113e6242f25fbfc47ddb |
ACCEPT —
|
| reading | result |
|---|---|
naive single-line git grep |
4 matches / 4 files |
wrap-tolerant \b26\s+characters\b |
5 / 4 — the wrapped site the naive instrument missed |
widened 26[- ](character|char|chars|byte) |
10 / 7 |
| positive controls | 16[- ]char… 15/13 · id…255 24/15 · DEFAULT_ID_LENGTH 13/3 |
⭐ The card's "fifth site" arithmetic is confirmed — and the load-bearing count is 1, not 5. Exactly one of the five asserts the false claim. Two are the fenced CHANGELOGs, two are the driver-sql non-members above, and the four extra hits the widening turned up are all the 26-letter ASCII alphabet.
nanoid as a control reads 32 files today, not the 26 triage measured. The 26/26 collision was already stale.
The fix writes no number, which is the point
The new comment names where the width is maintained — driver-sql's [#15522] note beside DEFAULT_ID_LENGTH — and gives the reason 255 is safe without a floor: it is the width of the column this value is copied from, the referenced-column transitivity the block already derives. maxLength: 255, the derivation above it, DEFAULT_ID_LENGTH, both CHANGELOGs and both driver-sql sites are untouched.
Verified here: platform id is 26 (newline-collapsed) 1 → 0, control maxLength 3 → 3.
⭐ Mint width was attacked, not inherited: a one-shot vitest drove the real SqlDriver against SQLite, 12 create() calls with no id → distinct widths [16], Crockford-base32 false ×12 over its own samples, supplied ids stored verbatim at 10/17/18/26/40/200, and a non-vacuity control (an id never written returned 0 while a known-written one returned 1). Deleted before commit, tree clean.
Gates, clause-②, governed
50 derived, 50 run, all exit 0, 0 NOT-MEASURED, 0 UNRUN — re-confirmed post-commit and after origin/main advanced twice. Two gates first returned exit 3 PREREQUISITE NOT MET and were made into readings by running the full pnpm build (73/73 tasks) rather than declared away. --pair 16953 → exit 0. Governed surface → NOT governed.
pnpm lint scoped to the changed file) with all three evidences, plus an instrument control: a planted import { Data } from '@objectstack/spec' reported 1 error on the identical targeted command, then was reverted — so the clean run is a reading, not a silent pass.
⚠️ The landing decision on the one red — made explicitly, because it deviates from this lane's own rule
Part-of PR must not also close its card is red on this head: commit 02d972c40 carries Refs #16410 in its message, while the PR body carries Fixes #16410. The gate is right — that is a real contradiction.
This lane's enqueue criterion is every check green, ⛔ not the required subset, so enqueueing past this is a deviation and is recorded as one. The basis, with what this seat verified itself separated from what it is crediting to the repo's own text:
Verified here, from .github/workflows/partof-closing-keyword-guard.yml on origin/main: the workflow has no merge_group: trigger — its single merge_group mention is the comment explaining the absence, against 6 pull_request mentions. ⇒ it cannot run in a queue build, so it cannot mechanically gate this merge.
Credited to that same header, ⛔ not verified by this seat (branch protection is not readable by this token): "That also keeps it out of the required-context registry, whose entries must report on queue builds."
Why no action clears it. The gate's edited trigger is load-bearing for a body reword — but this failure is in a commit message, which edited cannot reach. The gate's own text: "BRANCH ALREADY PUSHED — no author action clears this red, and that is expected rather than a problem to solve", and "⛔ The repair is NOT a history rewrite. Amend, rebase and force-push are forbidden in this repository and this gate never asks for one." ⛔ So no amend, no force-push, no close-and-reopen, and ⛔ no new commit pretending to fix it.
What the residue costs. Refs lands as a reference and moves no card — the benign spelling. The card closes on the PR body's Fixes #16410, which is the carrier the contract names. ⇒ the cost is a stray reference trailer in the permanent squash message; the alternative is stranding a correct, fully-verified change forever.
⇒ Enqueueing when the remaining 29 names close green. ⛔ The red is not being called green, not being suppressed, and not being re-run: it is being landed with its reason on the record.
⭐ And the root cause is a dispatch defect, not a dev defect. The claim comment did not carry the standing rule that Fixes / Refs / Part of belong in the PR body only, with commit messages limited to the subject plus Co-Authored-By: and Claude-Session: — a rule this seat's own post already records from an earlier red today. That omission is mine; the dev has been told, and the rule goes into every dispatch from here.
Generated by Claude Code
Fixes #16410
sys_import_job.created_by's bound derivation justified its headroom with a sentence that measurement flatly contradicts: "a minted platform id is 26 characters". The bound is right and the derivation is right — one sentence inside a sound argument was not.Clause-②: no
The defect is a comment. No accept set moves, no export is added, no bound and no behaviour changes.
maxLength: 255is byte-identical, the three-producer referenced-column derivation above it isbyte-identical, and
DEFAULT_ID_LENGTHis untouched. Only the sentence justifying the headroom isrewritten. Fence honoured: nothing here needed a behaviour or bound change, so there was nothing to
stop and report.
Diff: 2 files, +24 / -3 — one comment block in
packages/platform-objects/src/audit/sys-import-job.object.ts, plus its changeset. Final commit02d972c40.The correction names an artefact, not a number
⛔ Not 26 swapped for 16. A restated number is exactly how this sentence came to assert 26, and a mint width is driver-owned:
driver-sql,driver-mongodbanddriver-tursoeach spell their ownDEFAULT_ID_LENGTH(sql-driver.ts:121,mongodb-driver.ts:42,remote-transport.ts:59), whiledriver-memorymints a variable-widthobjectName-timestamp-counterthat is not a fixed width at all.So the comment now (a) says there is no fixed floor to clear, because an id has no fixed width; (b) points at
driver-sql's[#15522]note beside that constant, where the claim is measured and maintained; and (c) gives the reason255is safe without appealing to a floor — it is the width of the column this value is copied from, which is the referenced-column transitivity the block already derives two paragraphs up. That reason cannot expire when the mint changes.The mint width, re-derived here rather than inherited
A one-shot vitest driving the real
SqlDriveragainst SQLite (better-sqlite3,:memory:), throughinitObjects+driver.create()— deleted before the commit; the worktree is clean.create()calls supplying no id, distinct widths[16]— exactly onefalse× 12 (samples carry_,-and lowercase: nanoid, not ULID)Sample ids:
AC5zYy0o7PSSBRj_,yXzwn28i3Q_ltBpR,jFRFFoTF7OZg4U13.Non-vacuity control on the same table: the table held 12 rows; an id never written returned 0 rows while a known-written id returned 1. On the supplied-id table a never-written 26-character id likewise returned 0. So both zeros are readings.
Triage's three controls reproduced, with one number moved:
false— reproduced on my own samples, not its.ulid, case-insensitive over tracked source: 1 file —driver-sql/src/sql-driver.ts, its own "do not restore" guard, 2 occurrences. Positive control on the same instrument:nanoidmatches 32 files today, not the 26 triage measured.nanoidcontrol count and the false width are no longer the same number.⇒ Triage's measurement stands. It survived an attack rather than being inherited.
The site population, re-derived with a wrap-tolerant instrument
⛔ The obvious grep gives a false zero, confirmed here:
Instrument used instead: every tracked text file is unwrapped first — a newline plus optional indent plus an optional comment-continuation marker (
//,*,#,--) collapses to a single space — then matched, with match offsets mapped back to the original file's line numbers. Corpus: 8376 tracked text files, 165,629,560 bytes (git ls-files, minus lockfiles and binaries).git grep -n "26 characters"\b26\s+characters\bplatform id is\s+26\bminted platform idWidened, in case the claim is spelled another way —
\b26[- ](character|char|chars|byte)→ 10 / 7;\bid\b[^.;{}()]{0,40}\b26\b→ 6 / 5;ULID→ 2 / 1. Positive controls on the same corpus and the same instrument:16[- ]char…→ 15 / 13,\bid\b…\b255\b→ 24 / 15,DEFAULT_ID_LENGTH→ 13 / 3. Nothing new surfaced.⭐ The card's "fifth site" arithmetic is confirmed, but the number that matters is 1, not 5. Five textual occurrences of "26 characters" exist tree-wide; exactly one of them asserts the false claim, and it is this card's subject. Triaged one by one:
platform-objects/src/audit/sys-import-job.object.ts:109drivers/driver-sql/src/sql-driver.ts:2883ASCII_UPPER_LETTERSis declared two lines below); "exactly 26 characters fold"drivers/driver-sql/src/sql-driver.ts:16494platform-objects/CHANGELOG.md:121cli/CHANGELOG.md:2500lint/src/validate-rule-schema-formats.ts:237service-analytics/{like-pattern.ts:189,209, text-match-sql.ts:274}Verdict on the two
driver-sqlsites: neither a second member nor a second cardMeasured and not edited, as instructed.
:2883is a token collision: the noun is the ASCII alphabet, not an id.:16494is the more important reading. It sits inside the[#15522]block that already states the truth at:16482— "when the caller supplies no id it mintsnanoid(DEFAULT_ID_LENGTH)— 16 characters" — and:16494is its standing guard: "⛔ Do not restore the number this sentence used to carry. It called a platform id 26 characters long and spelled out a ULID". It quotes the false claim in order to forbid it. Editing it would delete the corrective #15522 landed, and that same block is the artefact this PR now points readers at.⇒ Nothing to do in
driver-sql. No second member, no second card.Changeset: measured in two halves, and the halves disagree
Per the #16941 ruling, half 1 alone would have given the wrong answer here — and it does.
Half 1 — does the changed path match the owning package's
files[]? NO.@objectstack/platform-objectspublishes["dist","README.md","CHANGELOG.md"]; 0 entries mentionsrc. Positive control, same instrument:@objectstack/specpublishes["dist", …, "src/**/*.zod.ts", …]— so a package that does shipsrcis distinguished.Half 2 — does the changed TEXT appear in the published artefact? YES.
After
pnpm build, the new comment appears verbatim in four shipped files, all underfiles: ["dist", …]:0 of the four are sourcemaps, and the text is absent from
dist/index.d.ts— these are the runtime bundles; tsup preserves comments. Positive controls, same corpus and instrument:sys_import_job→ 10 dist files,Created By→ 8,Asynchronous Data Import Job→ 2. Direction control: the pre-fix stringa minted platform id is 26→ 0 dist files, from a dist built out of the edited source — so the shipped bytes tracked this specific edit.⇒ Published bytes move. Changeset required,
patch—.changeset/platform-objects-import-job-minted-id-width.md. ⛔skip-changesetwould have been wrong, and half 1 alone is how one would get there.Gates — derived by name, run, exit codes landed, reconciled
node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commands, re-derived after the changeset existed (it moved 41 commands → 50).All 50 exit 0. Re-run post-commit at
02d972c40(change set readscommitted 2, working tree 0, untracked 0) and re-derived after agit fetchthat advancedorigin/maintwice — same 50/50, and the tool reports none of the seen upstream commits touched what the derivation rests on.PREREQUISITE NOT MET, which is not a failure and not a reading:check:dual-build-cjs-loadsandcheck:i18nboth read built output that did not exist. Cleared withpnpm build --concurrency=2(73/73 tasks, 7m22s) and re-run:pnpm check:dual-build-cjs-loads→ exit 0 — "104 published require entry point(s) across 67 package(s) load; 620 emitted CommonJS file(s) parse".pnpm check:i18n→ exit 0 — "OK (9 package(s) — all bundles in sync, no undeclared authoring keys)".check:i18n-stale-fillre-run post-build to confirm its pre-build green was a reading, not a prerequisite miss: exit 0, "10 bundle set(s) — no new stale fills".The card's cost note is confirmed: this comment-only edit really does pull the i18n families in, and clearing their prerequisite cost a full-tree build.
Every exit code was captured with
cmd > log 2>&1; ec=$?— never across a pipe.Local verification scope
pnpm --filter "@objectstack/platform-objects..." build --concurrency=2, exit 0; later superseded by the fullpnpm buildabove.pnpm --filter @objectstack/platform-objects test --maxWorkers=2→ 37 files / 545 tests passed;pnpm --filter @objectstack/platform-objects typecheck→ exit 0 (tsc --noEmit, the scripts project, andcheck:test-typecheck"OK — test layer compiles"). The public surface is byte-identical in shape, so no import-side package owes a test.scripts/pm/os-verify-lock.shon slotissue-16410; every verdict quoted is the wrapper's ownVERDICT command-exitline.Lint: a declared narrowing, with all three evidences
⛔
pnpm lint(eslint . --no-inline-config) is CI's whole-farm run. Narrowed here, and the narrowing is measured rather than asserted:isPathIgnored()andcalculateConfigForFile(): 6379 in population, 2005 ignored, 0 matched-no-rules (.ts6076,.mjs247,.mts30,.tsx22,.js4). Of my 2 changed paths exactly 1 is in it — ESLint's own config ignores the.changeset/*.md.--format json— the targeted run at02d972c40reports a 1-element array: 1 file, 0 errors, 0 warnings. Instrument control: a plantedimport { Data } from '@objectstack/spec'in the same package reports 1 error (no-restricted-imports) on the identical command; removed before the commit,git statusclean.eslint.config.mjsnever enables type-aware linting for any file, "noparserOptions.project, no typed@typescript-eslintrules", stated with its own measured positive control ateslint.config.mjs:326-329. A comment edit inside one file therefore cannot move the verdict on any of the other 6378: same config bytes, same input bytes.验收备注
Out of scope for this PR, noted rather than filed — the seat decides.
CHANGELOG.mdsites assert the false width in the present tense.platform-objects/CHANGELOG.md:121— "A minted platform id is 26 characters, so the bound clears the floor with 229 characters of headroom" — is the historical record of the very sentence this PR fixes, including a derived figure (229) that is also wrong.cli/CHANGELOG.md:2500says "a platform id is 26 characters, and Postgres refuses one in auuidcolumn with22P02". Fenced by the standing lane ruling: a false sentence already consumed by a release is a dedicated docs-only PR or its own card, never a rider. Who will touch these files: the release lane, when release notes are next compiled from this package's changelog.lint/src/validate-rule-schema-formats.ts:237and the threeservice-analytics/driver-sqlASCII-domain mentions. Named only so a future sweep with a token-level instrument does not re-open them. Successor: none needed.⛔ Nothing else was touched. No
driver-sqledit, no CHANGELOG edit, no bound change, noDEFAULT_ID_LENGTHchange.Generated by Claude Code