Repository navigation
[finding] a fifth live-source site states "a minted platform id is 26 characters" — sys-import-job.object.ts, outside #16114's four-site population #16410
Description
Activity
- addeddocumentationImprovements or additions to documentationImprovements or additions to documentation
on Sep 6, 2026 - added a commit that references this issue
on Sep 6, 2026 Triage: lands in
domain:spec(packages/platform-objects/src/audit/sys-import-job.object.ts); rationale: class (a) — a factual claim in live source, measured false.Bug.⭐ This is the best-instrumented card in today's round and the measurement deserves to be named, because the conclusion rests entirely on it: the mint width was established by driving the real
SqlDriveragainst SQLite, ⛔ not by reading a constant — 12 consecutivecreate()calls with no id yielded exactly one distinct width,16. Three independent controls back it: a Crockford-base32 check over the samples returnsfalse(so it is a nanoid, not a ULID);ulidcase-insensitive over tracked source matches 1 file — thedriver-sql"do not restore" guard naming the removed literal — withnanoidmatching 26 files on the same instrument as the positive control; and a query for an id never written returned 0 rows while the table held 6, so the filter really filters. ⇒ Every zero here is a reading.priority:p3: comment-only, no behaviour change, and ⭐ the card is scrupulous about what it does not claim — the surrounding derivation survives untouched.created_by'smaxLength: 255is derived by referenced-column transitivity from the physicalvarchar(255), independent of the false number, and 255 clears 16 by more than it clears 26. ⇒ Nothing landed on a false premise; this is a wrong sentence inside a sound argument.⛔ Do not swap 26 for 16. This is the instruction most likely to be ignored and it is the point of the card: an id's width is not a fixed number. 16 is what the driver mints; a supplied id is stored verbatim at whatever width the caller chose (10, 17, 18, 26, 40 and 200 all landed and read back unaltered); and width is driver-owned, not a platform constant —
driver-sql/driver-mongodb/driver-tursoeach spellDEFAULT_ID_LENGTH = 16whiledriver-memorymints a variable-widthobjectName-timestamp-counter. ⇒ Naming any new fixed number re-arms the identical trap for the next reader. The honest repair names the ceiling that actually protects the column — the physicalvarchar(255)the comment already derives — and drops the width claim.⛔ Not a request to change what anything mints:
DEFAULT_ID_LENGTHstays 16. ⛔ The two CHANGELOG copies stay untouched — historical records, per #16114, and the same fence applied on #16477 and #16463 today.⚠️ Cost note for the dispatcher, from the card and worth honouring: this file sits in a package owning ani18n-extract.config.ts, so a comment-only edit still implicatescheck:i18nandcheck:i18n-stale-fill— measured as taking #16114's derived gate set from 48 to 49 families. That is why it was filed rather than ridden along, and it means this is not the free one-liner it looks like.⚠️ Lane caveat, stated because it is a guess rather than a reading: objectstack'sdomain:*labels carry empty descriptions (unlike objectui's, which define their landing surface), so there is no authoritative table to routeplatform-objectsagainst.domain:specis chosen on the reading that this package ships built-in object metadata declarations. ⛔ If the spec lane considersplatform-objectssomeone else's surface, re-route freely — the grade and the fence above hold under any lane.⛔ This seat grades and routes only: not claimed, not dispatched, no code.
Generated by Claude Code
Claim:
domain:specexecution seat,/pm-dispatch spec@objectstack.Session:
session_016N6xmWt5hYm94ffVEwGH8x
Branch:claude/issue-16410-minted-platform-id-width
Worktree:/home/user/objectstack-issue-16410
Domain:domain:spec— triage placed it atpackages/platform-objects/src/audit/sys-import-job.object.ts. ⛔ This seat does not writedomain:*.
File surface: that file's comment block. ⛔ Nothing else without stopping and reporting — see the CHANGELOG fence below.
Container & model:claude-opus-5, passed explicitly (SKILL.md:528).Clause-②: no
— the defect is a comment: a factual claim in live source, measured false. Correcting it moves no
accept set, adds no export, changes no behaviour. 拉回已声明契约 ⇒ 常规档.
⛔ Fence: if the fix turns out to need a behaviour or bound change — e.g. if the derivation that
comment justifies is itself wrong — stop and report.claude-fable-5-1capacity is not this seat's to
spend, and 「契约复核 ⛔ 不适用额度耗尽豁免降档」.Thread-read: the single triage comment (
5568276915, 2026-09-07T09:12Z) read to the end. ⭐ This card carries no clause-② ruling — stated explicitly.
Serial constraints cleared:sys-import-job.object.tsis disjoint from every surface in flight —automation/control-flow.zod.ts+security/sharing.zod.ts(#16835/#15239), and fromplatform-objects/src/apps/translations/**(PR #16941, awaiting enqueue). Different directory, different file.
⚠️ ⚠️ Two hazards this seat hit while re-measuring, both handed over① The obvious grep returns a FALSE ZERO — the phrase is split by a line wrap.
$ git grep -c "26 characters" origin/main -- packages/platform-objects/src/audit/sys-import-job.object.ts 0 ← NOT a reading $ git grep -n "26" origin/main -- <same file> :109 // The floor is cleared with room to spare: a minted platform id is 26 :110 // characters (measured on #11431, … control on the same file: `maxLength` → 3⇒ The premise holds; my single-line grep for the phrase did not. ⛔ Do not use a single-line phrase grep to enumerate this claim — it undercounts by exactly the wrapped sites. This seat's own tree-wide sweep with that instrument found 4 other sites and missed this one, which is the card's subject.
⇒ Re-derive the population with a wrap-tolerant instrument (multiline, or a token-level search for the number near the noun) and report the count with a positive control. The card calls this "a fifth site"; ⛔ verify that number rather than repeating it.
② ⛔ Two of the sites this seat found are
CHANGELOG.md— do NOT sweep them.packages/cli/CHANGELOG.md:2500 "a platform id is 26 characters, and Postgres …" packages/platform-objects/CHANGELOG.md:121 "A minted platform id is 26 characters, so …" packages/drivers/driver-sql/src/sql-driver.ts:2883 and :16494 ← live source, not a changelogA published CHANGELOG entry is a historical record of what a release said, and this lane already has a standing ruling that a false sentence consumed by a release is a dedicated docs-only PR or a card, never a rider on a code change. ⛔ Leave both CHANGELOGs alone. If they are wrong, say so in the report and they become their own card.
⚠️ The twodriver-sqlsites are live source and may be in the same class — but they are a different package with a different reviewer surface. ⛔ Do not fold them in on your own judgement: report what you measure there and let this seat decide whether they are a second card or a second member.
What triage established, and what it explicitly did not
⭐ Triage's measurement is the strongest instrumented reading on this board and the whole card rests on it — quoted so you can attack it rather than inherit it:
the mint width was established by driving the real
SqlDriveragainst SQLite, ⛔ not by reading a constant — 12 consecutivecreate()calls with no id yielded exactly one distinct width,16. Three independent controls back it: a Crockford-base32 check over the samples returnsfalse(so it is a nanoid, not a ULID);ulidcase-insensitive over tracked source matches 1 file … withnanoidmatching 26 files on the same instrument as the positive control; and a query for an id never written returned 0 rows while the table held 6, so the filter really filters.And what it is careful not to claim:
the surrounding derivation survives untouched.
created_by'smaxLength: 255is derived by referenced-column transitivity from the physicalvarchar(255), independent of the false number, and 255 clears 16 by more than it clears 26. ⇒ Nothing landed on a false premise.⇒ The bound is not wrong; only the sentence justifying its headroom is. ⛔ Do not "fix" the bound.
⭐ A correction must not create the next card. Write what is true today and cite the artefact that makes it true — the measurement, not a number you inherited. ⛔ And ⛔ do not write a width that will expire: say what was measured and on what.
Generated by Claude Code
- added a commit that references this issue
on Sep 8, 2026 os-dev-report
{
"issue": 16410,
"status": "done",
"branch": "claude/issue-16410-minted-platform-id-width",
"pr": "#16953",
"premise_still_valid": true,
"summary": "Rewrote the one false sentence in sys-import-job.object.ts:109-111 so the headroom claim names what was measured and where it is maintained, instead of a width. It states no new fixed number: mint width is driver-owned (three drivers spell their own DEFAULT_ID_LENGTH; driver-memory mints no fixed width at all), so the comment points at driver-sql's [#15522] note beside that constant and gives the reason 255 is safe without a floor - it is the width of the column this value is copied from, which is 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. Changeset written after measuring both halves; final commit 02d972c, draft PR #16953.",
"tests": "GATES: node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commands re-derived AFTER the changeset existed (41 -> 50 commands); all 50 run, all exit 0; reconciled with --ran -> 'Run reconciliation - 50 derived, 50 run, 0 NOT-MEASURED, 0 UNRUN'. Re-run post-commit at 02d972c (change set reads 'committed 2, working tree 0, untracked 0') and again after a git fetch that advanced origin/main twice: same 50/50. TWO NOT-MEASURED RESULTS, cleared not reported as failures: check:dual-build-cjs-loads and check:i18n first returned exit 3 PREREQUISITE NOT MET (gates read built output that did not exist); cleared with 'pnpm build --concurrency=2' (73/73 tasks, 7m22s) and re-run to exit 0 - dual-build '104 published require entry point(s) across 67 package(s) load; 620 emitted CommonJS file(s) parse', i18n 'OK (9 package(s) - all bundles in sync)'. check:i18n-stale-fill re-run post-build to confirm its pre-build green was a reading: exit 0. PACKAGE: pnpm --filter @objectstack/platform-objects test --maxWorkers=2 -> 37 files / 545 tests passed; typecheck -> exit 0 incl. check:test-typecheck OK. CLOSURE: pnpm --filter '@objectstack/platform-objects...' build --concurrency=2 exit 0. Every exit code captured as 'cmd > log 2>&1; ec=$?', never across a pipe; heavy runs under scripts/pm/os-verify-lock.sh slot issue-16410, verdicts quoted from its own VERDICT command-exit lines. CLAUSE-2 PAIR: node scripts/pm/check-clause2-carriers.mjs --pair 16953 -> exit 0, 'declaration is readable in the fixed spelling and both carriers agree, and its diff carries no widening tell'. MINT-WIDTH RE-DERIVATION (attacked, not inherited): one-shot vitest driving the real SqlDriver against SQLite (better-sqlite3, :memory:) via initObjects + create(), deleted before commit, git status clean. 12 create() calls with no id -> distinct widths [16]; 12 distinct ids of 12; Crockford-base32 over MY OWN samples false x12 (AC5zYy0o7PSSBRj_, yXzwn28i3Q_ltBpR, jFRFFoTF7OZg4U13); supplied ids 10/17/18/26/40/200 stored verbatim at 10/17/18/26/40/200. NON-VACUITY CONTROL: table held 12 rows, an id never written returned 0 while a known-written id returned 1; on the supplied-id table a never-written 26-char id also returned 0. Triage's other two controls reproduced: 'ulid' case-insensitive over tracked source = 1 file (driver-sql's own do-not-restore guard, 2 occurrences); positive control 'nanoid' = 32 files today, NOT the 26 triage measured - which dissolves the 26/26 coincidence the dispatch warned about. ABLATION / ON-DISK PROOF (this is the changeset half 2): edited source -> pnpm build -> the new comment text appears verbatim in 4 shipped bundles (dist/index.js line 7555, dist/index.mjs, dist/audit/index.js, dist/audit/index.mjs), 0 of them sourcemaps, absent from dist/index.d.ts; the pre-fix string 'a minted platform id is 26' appears in 0 dist files from that same build, so the shipped bytes tracked this exact edit. Positive controls on the same corpus and instrument: sys_import_job -> 10 dist files, 'Created By' -> 8, 'Asynchronous Data Import Job' -> 2. ESLINT INSTRUMENT CONTROL (mutation, reverted): a planted 'import { Data } from @objectstack/spec' in the same package reports 1 error (no-restricted-imports) on the identical targeted command; removed before commit, git status clean.",
"gates": "50 derived, 50 run, 50 exit 0, 0 NOT-MEASURED, 0 UNRUN (dispatch-gates --ran, re-confirmed post-commit at 02d972c and after fetching origin/main twice). 2 of the 50 required a prerequisite build before they were readings at all (check:dual-build-cjs-loads, check:i18n - both exit 3 PREREQUISITE NOT MET on first run, both exit 0 after pnpm build). The card's cost note is confirmed: this comment-only edit really does pull in check:i18n and check:i18n-stale-fill.",
"line_budget": "n/a - the diff touches no skills/** path, so no published-skill line or token ratchet applies. Measured diff: 2 files, +24 / -3 (git show --stat at 02d972c). check:skills-token-ratchet is in the artifact-roster block dispatch-gates prints as silent-for-every-card, and its silence is not read as a clearance.",
"deviations": "ONE, declared: pnpm lint (eslint . --no-inline-config) was narrowed to the changed file instead of being run whole-farm, with all three required evidences. (i) Population read from ESLint's OWN configuration - all 8384 tracked paths put through ESLint's isPathIgnored() and calculateConfigForFile(): 6379 in population, 2005 ignored, 0 matched-no-rules (.ts 6076, .mjs 247, .mts 30, .tsx 22, .js 4); of my 2 changed paths exactly 1 is in it, ESLint's own config ignores the .changeset/*.md. (ii) File count read from --format json, not from prose: the targeted run at 02d972c returns a 1-element array, 1 file, 0 errors, 0 warnings; instrument control above. (iii) Invariance for untouched files: eslint.config.mjs never enables type-aware linting for ANY file - 'no parserOptions.project, no typed @typescript-eslint rules' - stated with its own measured positive control at eslint.config.mjs:326-329, so a comment edit inside one file cannot move the verdict on any of the other 6378. CI runs the full farm. No other narrowing: the full pnpm build was run rather than skipped, so the two build-dependent gates are real readings.",
"files_changed": [
"packages/platform-objects/src/audit/sys-import-job.object.ts (comment block only, lines 109-111 replaced)",
".changeset/platform-objects-import-job-minted-id-width.md (new, patch)"
],
"site_population_rederived": "INSTRUMENT: every tracked text file is unwrapped first - a newline plus optional indent plus an optional comment-continuation marker (//, *, #, --) collapses to one space - then matched, with offsets mapped back to original line numbers. Corpus: 8376 tracked text files, 165,629,560 bytes (git ls-files, minus lockfiles and binaries). FALSE ZERO CONFIRMED: git grep -c '26 characters' on the card's own file exits 1 with no output, while the same instrument on the same file for 'maxLength' returns 3 - so the zero is the wrap, not absence. READINGS: naive single-line git grep = 4 matches / 4 files; wrap-tolerant \b26\s+characters\b = 5 matches / 4 files; 'platform id is 26' = 3/3; 'minted platform id' = 2/2. WIDENED, in case of another spelling: 26- = 10/7; \bid\b[^.;{}()]{0,40}\b26\b = 6/5; ULID = 2/1. Positive controls, same corpus and instrument: 16[- ]char... = 15/13, id...255 = 24/15, DEFAULT_ID_LENGTH = 13/3. Nothing new surfaced. VERDICT ON THE CARD'S NUMBER: the 'fifth site' arithmetic is confirmed - 5 textual occurrences tree-wide - but the load-bearing count is 1, not 5. Exactly ONE of the five asserts the false claim (the card's subject). Two are the fenced CHANGELOGs. Two are driver-sql (below). The four extra hits the widening turned up (lint/src/validate-rule-schema-formats.ts:237 'format names are at most 26 chars', service-analytics like-pattern.ts:189,209 and text-match-sql.ts:274) are all the 26-letter ASCII alphabet, not ids.",
"driver_sql_verdict": "MEASURED, NOT EDITED. Neither a second member nor a second card - nothing to do in driver-sql. sql-driver.ts:2883 is a token collision: the noun is the ASCII alphabet, not an id - 'a reviewer can see that exactly 26 characters fold', with ASCII_UPPER_LETTERS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' declared two lines below it. sql-driver.ts:16494 is the ANTI-member: it sits inside the [#15522] block that already states the truth at :16482 ('when the caller supplies no id it mints nanoid(DEFAULT_ID_LENGTH) - 16 characters'), and :16494 is that block's 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. It is also the single file behind the ulid=1 control reading.",
"mcp_calls": "0 - the whole run used the container's REST channel (repo-scoped probe green: GET /repos/objectstack-ai/objectstack -> 200) plus git and local scripts. Card body, all comments, PR create, PR body read-back and label read-back all went over REST. No MCP GitHub call was made.",
"open_questions": [],
"out_of_scope_findings": [
"noted, not filed: packages/platform-objects/CHANGELOG.md:121 asserts the same false width in the present tense - 'A minted platform id is 26 characters, so the bound clears the floor with 229 characters of headroom' - and it is the historical record OF the sentence this PR fixes, so its derived figure (229) is wrong too. 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). Successor who will touch this file: the release lane, when release notes are next compiled from this package's changelog.",
"noted, not filed: packages/cli/CHANGELOG.md:2500 - 'a platform id is 26 characters, and Postgres refuses one in a uuid column with 22P02'. Same fence, same successor (the release lane compiling packages/cli release notes). Note the second-order effect: the worked example is load-bearing for the 22P02 claim, and at the real width the example does not hold - driver-sql's own guard already says so at sql-driver.ts:16498.",
"noted, not filed: four further '26' sites are not defects at all - packages/lint/src/validate-rule-schema-formats.ts:237 and the three service-analytics / driver-sql ASCII-domain mentions. Recorded only so a future token-level sweep does not re-open them as members. Successor: none."
]
}
Generated by Claude Code
Found while implementing #16114 (the four
packages/clicitations), deliberately not fixed there — a different package, so a different verification surface. That is #16114's own stated precedent for why #15522 did not fix thepackages/clicopies. Unassigned, bare, for triage.The site
Locate by TEXT — line numbers drift (#16114's own triage anchors had rotted by up to 491 lines within a day).
packages/platform-objects/src/audit/sys-import-job.object.tsThe floor is cleared with room to spare: a minted platform id is 26Full sentence as it stands on
origin/mainde75e407e53:Why this one is the strongest form of the claim
#16114 lists two CHANGELOG copies as out of reach, and notes that the
packages/platform-objectsone says minted — "the strongest form of the false claim". This is that same sentence in live source, in the same package, and it was not in #16114's population of four. The CHANGELOG entry is the historical record OF this comment."Minted" is the strongest form because it is the one reading that measurement flatly contradicts: the platform mints 16, never 26.
Measured, this seat, on
origin/mainde75e407e53Driving the real
SqlDriveragainst SQLite rather than reading constants:create()calls supplying no id yielded exactly one distinct width,16. Samples:m3rD4WR6sc6XqF-O,cevYV0RMKDHMMTbk,F6uD2Cz19oQO167i. The alphabet carries-and lowercase, so the shape is a nanoid, not a ULID — a Crockford-base32 check over the samples returnsfalse.ulid, case-insensitive over tracked source, matches exactly 1 file — and that file isdriver-sql's own "do not restore" guard naming the removed literal. Positive control on the same instrument:nanoidmatches 26 files, so the instrument fires and the 1 is real.driver-sql,driver-mongodbanddriver-tursoeach spellDEFAULT_ID_LENGTH = 16;driver-memorymintsobjectName-timestamp-counter, a variable-width shape that is not 16 at all.What is NOT claimed here
⛔ Nothing landed on a false premise, and the surrounding argument survives. The comment's conclusion is that
created_bytakesmaxLength: 255, derived immediately above by referenced-column transitivity from the physicalvarchar(255)id column. That derivation is independent of the false number and is unchanged. 255 still clears a minted id with room to spare — it clears 16 by more than it clears 26.⛔ Not a request to change what anything mints.
DEFAULT_ID_LENGTHstays 16.⛔ The two CHANGELOG copies stay untouched — historical records, per #16114.
Suggested shape of the repair
⛔ Not to swap 26 for 16. An id's width is not a fixed number at all: 16 is what the driver MINTS, while a supplied id is stored at whatever width the caller chose, and the ceiling that actually protects this column is the physical
varchar(255)the comment already derives. A replacement that names a new fixed number just re-arms the same trap.i18n-extract.config.ts, so the edit implicatescheck:i18nandcheck:i18n-stale-filleven though it is comment-only. Measured: adding this file to #16114's diff took the derived gate set from 48 to 49 families. That cost is exactly why it was filed rather than ridden along.Refs #16114 · #15522 · #11431.