Skip to content

packages/spec/src/type-alias-convention.pin.test.ts serialises the spec lane — its dense sequential M… / Iso… numbering makes any two concurrent schema-adding PRs conflict #19665

Description

@os-warren

Filed by domain:spec execution seat 2, session session_01UDXER3sdqfeVYpEWZs5mZx, 2026-09-22T05:28Z. ⛔ Unlabelled and unrouted on purpose — an execution seat files, triage grades and routes.

This is not a product defect and does not claim to be one. It is a lane-throughput defect with a named landing point, and it has already cost this lane a concrete thing today, which is why it is a card rather than a note.

The collision that happened, bisected rather than asserted

All readings taken 2026-09-22T05:2xZ. Instrument: git merge-tree --write-tree --name-only BASE HEAD (read-only, writes no working tree), against a freshly fetched origin/main @ 8f30c188a364a9cc982059f803914ee9d4826615.

PR #19600 (card #15178, domain:spec, size/xl, parked on a maintainer authorization) head 8dcd6a42ae323931b02e12208bf229da921b9eb3:

CONFLICT (content): Merge conflict in packages/spec/src/type-alias-convention.pin.test.ts

One file, and only that file. Bisected against main:

base merge-tree verdict
1b82c519df (#19226) rc=0 clean
eff0a9622340f59068651f2b82d4afcd177546a8 — parent of the next row rc=0 clean
5ce3705052PR #19638, merged 2026-09-22T04:52:12Z rc=1 CONFLICT

⇒ the conflicting commit is identified, not guessed. And it is this seat's own landing. #19638 is a PR this seat reviewed and enqueued earlier in the same session, on card #17551, and the miss is in this seat's own claim 5769968983 — read back first-hand for this card, not recalled:

File surface: packages/spec/src/contracts/analytics-service.ts (or packages/spec/src/api/analytics.zod.ts — the ruling leaves the placement to this seat, one place), the POST /api/v1/analytics/dataset/query door, their tests, regenerated artefacts, .changeset/.

Two defects there, both this seat's:

  1. That claim carries no Serial constraints cleared: line at all. Sibling claims in this lane on the same day do (e.g. domain:spec#4 on 14 ADR-0049 tombstones tell authors a key was removed in @objectstack/spec 18 — an npm version that does not exist and, under the 2026-09-13 level ruling, will not be the carrier #18048 and on A multi-package artifact serializes its metadata twice — the flattened top level and every packages[i] body carry the same definitions #14512). So no serial census stood between feat(spec): author DatasetSelectionSchema and parse the whole selection at the analytics dataset door #19638 and feat(spec)!: split the translation bundle type — settings is a platform group, not a per-app one (#15178) #19600's open surface — ⛔ this is not a census that ran and missed, it is a census that was not written.
  2. 「regenerated artefacts」 was doing work it cannot do. type-alias-convention.pin.test.ts is 「Generated once … maintained by hand from here on」, so a dev could in good faith read it as covered by that phrase and edit it without the edit ever surfacing as a widening. ⛔ That is the declaration's vagueness, not the dev's error.

It is stated here rather than only on the card because a reader deciding this card's worth should know the collision came from two PRs in the same lane, and that tightening the claim template would not have prevented it — the file is one every spec PR must touch, so the serial queue for it is the whole lane.

Lit control for the instrument (so the rc=1 is not an instrument that only ever says CONFLICT): PR #19643 head c9058f4056193ddeb7535924ba53d577b12d4a2b, same instrument, same base, same act ⇒ rc=0, clean. PR #19598 head cfc103a20a34a6eb35670986a130fa7b3dc266ff ⇒ rc=0, clean.

Why it is structural, in the file's own words

packages/spec/src/type-alias-convention.pin.test.ts is 2349 lines on origin/main @ 8f30c188a3, and its header says what it is:

Generated once from the measured corpus (see ADR-0122's appendix); maintained
by hand from here on — a line leaves when its schema gains a shape, and the
gate refuses a bare alias that is neither pinned here nor paired with an
XParsed.

It is also the registry scripts/check-spec-parsed-alias.mjs reads, so it is not optional and not skippable: every PR that adds a schema must edit it.

The two sides of today's conflict touch the same regions, which is the whole point:

region main side (#19638) PR #19600 side
import block @@ -275,7 @@ -275,7
pin block @@ -345,6 @@ -1251,6
describe body @@ -1683,7 @@ -1683,7
describe body @@ -2268,7 @@ -2268,7

Three of the four regions are byte-identical starts. This is not two PRs unluckily landing near each other — it is two PRs doing the one thing this file requires of everyone.

What makes it collide, said as the thing to delete

The entries are keyed by a dense sequential counter, in two independent series:

  • modules: import type * as M187 from './shared/duration.zod.js';
  • pins: export type Iso651 = Assert<Eq< z.input< typeof M152.… >, z.infer< … > >>;

Two PRs that each add one schema each allocate the next number in both series, at the end of both blocks. Git has nothing to merge on: same line, two different contents. The counter is the construct that permits the error.

Following 「先删容许出错的构造,再让正确形态成唯一拼写,最后才加检查」, in that order:

  1. Delete the counter. Key both series on the thing that is already unique and already stable — the module path and the schema name (M_sharedDuration, Iso_ActionResultDialogTranslation). Two PRs adding different schemas then write different lines.
  2. Make the correct spelling the only one. Keep both blocks sorted by that key, so the insertion point is a function of the name rather than of arrival order, and two concurrent inserts land in different places and auto-merge.
  3. Only then consider a check that the blocks are sorted.

Not proposed, and deliberately so: regenerating the file wholesale, weakening any assertion, changing what scripts/check-spec-parsed-alias.mjs accepts, or changing the exemption set. The assertion set before and after must be identical member-for-member, and that identity is the acceptance condition. A renumbering PR that silently drops one pin is worse than the collisions it fixes.

Materiality, with its limit stated

Commits on origin/main touching this file: 3, dated 2026-09-18, 2026-09-20, 2026-09-22.

⚠️ That is a lower bound, not a rate. This checkout is shallow (git rev-parse --is-shallow-repository ⇒ true; 303 commits reachable; oldest reachable commit dated 2026-09-18), so the window is 4 days and the count cannot see past it. Whoever grades this card should re-take the count on an unshallow clone before treating 3 as the number.

What does not depend on that count: the collision is demonstrated, and its cost is currently being paid — PR #19600 carries an at-tier contract-review PASS pinned to head 8dcd6a42ae, and clearing this conflict moves that head and strands the record.

Duplicate-search words

type-alias-convention.pin.test, check-spec-parsed-alias, ADR-0122, sequential alias counter, serial collision


Generated by Claude Code

Activity

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

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions