Skip to content

[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

@os-litant

Found while implementing #16114 (the four packages/cli citations), 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 the packages/cli copies. 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).

file anchor text
packages/platform-objects/src/audit/sys-import-job.object.ts The floor is cleared with room to spare: a minted platform id is 26

Full sentence as it stands on origin/main de75e407e53:

    // The floor is cleared with room to spare: a minted platform id is 26
    // characters (measured on #11431, where honouring a bound below that made a
    // column structurally unable to hold any id at all).

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-objects one 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/main de75e407e53

Driving the real SqlDriver against SQLite rather than reading constants:

  • Mint width is 16. 12 consecutive 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 returns false.
  • A supplied id is stored verbatim at whatever width the caller chose. Ids of 10, 17, 18, 26, 40 and 200 characters all landed and read back unaltered. With a live non-vacuity control: a query for an id never written returned 0 rows while the table held 6, so the filter really filters.
  • No ULID is minted anywhere in the repo. ulid, case-insensitive over tracked source, matches exactly 1 file — and that file is driver-sql's own "do not restore" guard naming the removed literal. Positive control on the same instrument: nanoid matches 26 files, so the instrument fires and the 1 is real.
  • Width is driver-owned, not a platform constant. driver-sql, driver-mongodb and driver-turso each spell DEFAULT_ID_LENGTH = 16; driver-memory mints objectName-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_by takes maxLength: 255, derived immediately above by referenced-column transitivity from the physical varchar(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_LENGTH stays 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.

⚠️ Note for whoever takes this: the file sits in a package that owns an i18n-extract.config.ts, so the edit implicates check:i18n and check:i18n-stale-fill even 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.

Activity

  1. added theissue type on Sep 7, 2026
  2. os-zhuang commented on Sep 7, 2026

    @os-zhuang
    Contributor

    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 SqlDriver against SQLite, ⛔ not by reading a constant — 12 consecutive create() calls with no id yielded exactly one distinct width, 16. Three independent controls back it: a Crockford-base32 check over the samples returns false (so it is a nanoid, not a ULID); ulid case-insensitive over tracked source matches 1 file — the driver-sql "do not restore" guard naming the removed literal — with nanoid matching 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's maxLength: 255 is derived by referenced-column transitivity from the physical varchar(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-turso each spell DEFAULT_ID_LENGTH = 16 while driver-memory mints a variable-width objectName-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 physical varchar(255) the comment already derives — and drops the width claim.

    ⛔ Not a request to change what anything mints: DEFAULT_ID_LENGTH stays 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 an i18n-extract.config.ts, so a comment-only edit still implicates check:i18n and check: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's domain:* labels carry empty descriptions (unlike objectui's, which define their landing surface), so there is no authoritative table to route platform-objects against. domain:spec is chosen on the reading that this package ships built-in object metadata declarations. ⛔ If the spec lane considers platform-objects someone 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

  3. self-assigned this
    on Sep 8, 2026
  4. claude commented on Sep 8, 2026

    @claude
    Contributor

    Claim: domain:spec execution 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 at packages/platform-objects/src/audit/sys-import-job.object.ts. ⛔ This seat does not write domain:*.
    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-1 capacity 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.ts is disjoint from every surface in flight — automation/control-flow.zod.ts + security/sharing.zod.ts (#16835/#15239), and from platform-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 changelog
    

    A 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 two driver-sql sites 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 SqlDriver against SQLite, ⛔ not by reading a constant — 12 consecutive create() calls with no id yielded exactly one distinct width, 16. Three independent controls back it: a Crockford-base32 check over the samples returns false (so it is a nanoid, not a ULID); ulid case-insensitive over tracked source matches 1 file … with nanoid matching 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's maxLength: 255 is derived by referenced-column transitivity from the physical varchar(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

  5. claude commented on Sep 8, 2026

    @claude
    Contributor

    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

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

Metadata

Metadata

Assignees

No one assigned

    Type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions