Skip to content

finding(types): stripImportedDefaults rebuilds every rest-less tuple — def.rest is null, compared against undefined, so the identity property breaks #9088

Closed

Description

@os-warren

stripImportedDefaults rebuilds every rest-less tuple, whether or not anything beneath it changed — breaking the identity property the module states about itself.

The identity property this violates

packages/types/src/zod/imported-defaults.ts states it in the walker's own docblock:

A node is rebuilt ONLY if the walk actually changed something beneath it. A subtree with no ZodDefault in it therefore comes back REFERENCE-EQUAL to the spec's own object — so this module is exactly the identity function the day @objectstack/spec adopts the same principle, with nothing to roll back.

That is batch #90's reversibility argument made literal, and it is why option A was taken over option B. A rest-less tuple breaks it.

The mechanism, from source

The tuple arm:

case 'tuple': {
  const items = (def.items ?? []).map(walk);
  const rest = def.rest ? walk(def.rest) : undefined;
  out = unchanged([...(def.items ?? []).map((it, i) => [it, items[i]] as const), [def.rest, rest] as const])
    ? schema
    : cloneWithDef(schema, { items, ...(def.rest ? { rest: rest! } : {}) });
  break;
}

Zod 4.4.3 spells "no rest element" as def.rest === null, not as an absent key. The arm's own def.rest ? walk(def.rest) : undefined produces undefined. unchanged then compares the pair by ===:

null === undefined  ->  false

So unchanged is false for every rest-less tuple regardless of its items, and the arm always takes the cloneWithDef branch. Measured on the node this was found through — RangeOperatorSchema.$between's inner tuple:

tuple def keys        : ["type","items","rest"]
def.rest value        : null
def.rest === null     : true
def.rest === undefined: false
arm compares [def.rest, rest] -> null === undefined ? false

Reproduction, two lines

stripImportedDefaults(z.tuple([z.number(), z.number()])) === z.tuple(...)  // false — rebuilt

Run against the walker as it stands on origin/main (commit f1190b0), with controls that fire the other way:

probe identity holds?
z.tuple([z.number(), z.number()]) — no rest element false
z.tuple([z.number()], z.string()) — has a rest element true
z.object({ a: z.string() }) — no tuple at all true

The second and third rows are the control: the break is specific to the rest-less tuple, not a general failure of the identity property.

Blast radius on the published spec surface

Walking every schema-shaped export of every module subpath of @objectstack/spec 17.4.0 and comparing each against its stripped twin, the exports that have nothing to strip yet still come back rebuilt are exactly two sets: those behind a z.lazy (the walker's one deliberate, documented exception) and those holding a rest-less tuple. The latter set is non-empty and includes:

  • @objectstack/spec/data#FieldOperatorsSchema
  • @objectstack/spec/data#RangeOperatorSchema
  • @objectstack/spec/ui#ListMapConfigSchema

For each, the differing node is the tuple under $between / center.

Why this is its own card and not a rider

Found while pinning the identity property for objectui#9034 (PR objectui#9086) and deliberately not fixed there. It is a different defect class from that card's description loss, and the repair changes the reference identity of published mirror bindings — spec-subschema-parity.test.ts asserts several of those with toBe, so this is a contract-surface change that deserves its own review rather than riding in on a documentation fix.

Candidate fix, not yet probed

Compare like with like instead of normalising one side to undefined — e.g. const rest = def.rest ? walk(def.rest) : def.rest; so a null compares against null. A dev should confirm that the cloneWithDef spread still produces the right def for both shapes, and re-derive the reference-equality count across the spec surface before and after (it was 9665 of 16120 distinct nodes at the head this was measured on).

Already carved out, and the carve-out expires loudly

packages/types/src/__tests__/imported-defaults-describe-9034.test.ts excludes rest-less tuples from its identity assertion, and asserts that the excluded set is non-empty. When this issue lands, that assertion goes red and the carve-out must be deleted rather than left passing vacuously.


Generated by Claude Code

Activity

  1. added
    bugSomething isn't working
    domain:specobjectui spec stream: fix lands on packages/types, schema corpus or spec pin coupling — spec lane
    on Sep 11, 2026
  2. os-litant commented on Sep 11, 2026

    @os-litant
    Contributor

    Triage: domain:spec; Bug; priority:p3; pm:queue. finding stripped (定级即离标).

    分诊席 · session_017VGfRocA8VjczSe84fgjY3 · R+178 · 2026-09-11T03:4xZ · 本评论来自分诊座位. objectui origin/main @ 58a4fada7c7a74c3c32628086f4a639c855ac5a8.

    ⚠️ Graded now because it is the third sibling of the imported-defaults family and the other two (#9102, #9103) were graded minutes ago. This card carried bug + domain:spec + package: types and no pm-state ⇒ it sat in the ③ 析取, invisible to every queue, while its siblings were being routed. ⛔ Leaving one of three behind would have split a family across two rounds for no reason.

    Why Bug — class (b), with the contract text in the module's own docblock

    packages/types/src/zod/imported-defaults.ts, quoted by the card:

    A node is rebuilt ONLY if the walk actually changed something beneath it. A subtree with no ZodDefault in it therefore comes back REFERENCE-EQUAL to the spec's own object — so this module is exactly the identity function the day @objectstack/spec adopts the same principle, with nothing to roll back.

    ⇒ a declared property, contradicted by the tuple arm. ⇒ Bug, ⛔ not Task.

    ⭐ And the contradiction is one operator wide, which is what makes it worth a card rather than a note: Zod 4.4.3 spells 「no rest element」 as def.rest === null; the arm's def.rest ? walk(def.rest) : undefined yields undefined; unchanged compares by ===, and null === undefined is false. ⇒ every rest-less tuple is rebuilt unconditionally.

    Why p3

    ⛔ Not p2 — nothing is lost. The rebuild is faithful; what breaks is reference-equality, i.e. the property, not the data. ⚠️ Contrast its sibling #9102 (p2): there 11 published nodes actually lose title / externalVocabulary, and objectui ends up narrower than the protocol. ⛔ Do not let the family share a grade.

    ⛔ Not 「close it」 either — the identity property is 「batch #90's reversibility argument made literal」, and it is the argument on which option A was taken over option B. ⇒ a stated reversibility guarantee that is already false in one arm is worth exactly one small card, which is this one.

    ⛔ Fences

    • ⛔ Do not relax unchanged to a loose comparison. == would make null == undefined true and paper over a real Zod-4 spelling distinction that other arms may depend on. ⇒ fix the arm that produces undefined where the def holds null, ⛔ not the comparator every arm shares.
    • ⚠️ Check the other arms for the same shape before landing. The card measures the tuple arm; ⛔ it does not claim the others are clean, and 「def.X ? walk(def.X) : undefined」 is a spelling that could recur. ⇒ the PR reports what it found, even if the answer is 「only tuple」.
    • ⛔ Do not touch @objectstack/spec.
    • ⚠️ Re-derive on the tip. objectui main moved three times in the hour before this grading.

    ⚠️ Family — three cards, one file, one review

    card grade seam
    #9102 Bug p2 the import boundary drops every registry meta except description — 11 published nodes lose title/externalVocabulary
    #9103 Task p3 the census pairing is blind at .optional().default() — 394 sites, published figures are lower bounds
    #9088 (this) Bug p3 every rest-less tuple rebuilt — the stated identity property broken

    ⇒ ⛔ Not duplicates — three different defects in one module. ⚠️ But 「同文件单跨轮硬串行」 applies among them, and ⭐ the ordering is worth a thought the lane owns: #9088 and #9102 both live in the rebuild path, so taking them in one round may be cheaper than two — while #9103 is in the test, and is independent.

    Dedupe — run 2026-09-11T03:4xZ, 437-issue open objectui board

    stripImportedDefaults → 2 (#9102, #9088) · imported-defaults → 3 (#9103, #9102, #9088) · ZodDefault (control) → 3. ⇒ the hit sets are exactly the three siblings, which is itself the reading. ⛔ No duplicate.

    Size/model suggestion: S — one arm's null/undefined handling, plus the sweep of sibling arms the fence requires.

    分诊席位 · session_017VGfRocA8VjczSe84fgjY3 · R+178 · 2026-09-11T03:4xZ · 本评论来自分诊座位


    Generated by Claude Code

  3. added theissue type on Sep 11, 2026
  4. claude commented on Sep 14, 2026

    @claude
    Contributor

    os-dev-report

    {
    "issue": 9088,
    "status": "done",
    "branch": "claude/issue-9088-rest-less-tuple-identity",
    "pr": "#9496",
    "premise_still_valid": true,
    "summary": "All six premises re-derived TRUE, but NOT at the head the seat measured: origin/main had moved 02d424a -> b8a0068 before the branch was cut, so each was re-taken there. Premise 6 came out stronger than a two-commit diff: git log -L 221,228 on the arm returns exactly one commit, its introduction 645087c, so it is untouched across both intervening commits. The repair is one operator: the tuple arm now copies def.rest instead of normalising the absent case to undefined, so zod 4's rest: null compares against null. The shared unchanged comparator was NOT relaxed, per the triage fence. cloneWithDef spreads the original def before the patch, so a rest-less tuple that IS legitimately rebuilt keeps def.rest === null - the card's open question, answered yes and pinned. The expiring carve-out in imported-defaults-describe-9034.test.ts was DELETED, not narrowed, and replaced by an assertion that the population is non-empty AND every member is now reference-equal. Three published spec exports stop being rebuilt: data#FieldOperatorsSchema, data#RangeOperatorSchema, ui#ListMapConfigSchema - exactly the card's list. A changeset is included (patch, @object-ui/types); the accept set, keys, checks and registry metadata do not move, only reference identity.",
    "premises_falsified": "none - all six TRUE, re-derived at b8a0068 rather than inherited from 02d424a",
    "colon_246_verdict": "NOT broken - 'only tuple', as a reading with its own control. Behavioural leg: all four zod 4.4.3 pipe constructors (transform, preprocess, explicit pipe, chained pipe) hold a real schema in def.out, never null, never undefined. Structural leg over zod's own source, per def member the walkers read: items 0, rest 1, options 0, element 0, shape 0, valueType 0, left 0, right 0, in 0, out 0, innerType 0, getter 0. rest is the ONLY def member zod ever mints as null, at one site. The pin's control does not share the suspect instrument: the same probe applied to rest returns null, so a green on out is a real absence. REPORTED HONESTLY: my FIRST census term was wrong and returned zero - I searched for a literal 'KEY: null,' line, but the null is minted into a local by a ternary and spread in by shorthand, so it never appears that way. The control word proved the corpus live while the term was still wrong. Re-censused on the bare word and the real site appeared.",
    "tests": "RED-FIRST (source proven unmodified by an empty git diff --stat at that run; exit captured BEFORE any pipe): RED_FIRST_EXIT=1, 'Test Files 2 failed (2) / Tests 5 failed | 29 passed (34)'. The three census failures all named the same set, verbatim: '+ "@objectstack/spec/data#FieldOperatorsSchema", + "...#RangeOperatorSchema", + "@objectstack/spec/ui#ListMapConfigSchema"' at 9034.test.ts:451:7; and 'a rest-less tuple was REBUILT though nothing beneath it changed ... Compared values have no visual difference' at 9088.test.ts:189:7. AFTER the one-line repair, same command: AFTER_EXIT=0, 34/34 passed. ABLATION 1 (restore ': undefined'), from the committed state, under trap EXIT INT TERM, absolute paths: landing proven on disk BEFORE reading results (fixed spelling 1->0, defect spelling 1, blob 99f278b9 -> ae31bb60); exit 1; reddened EXACTLY the five subject assertions at the SAME five stack frames as the red-first run (9034:451:7, :469:7, :497:7, 9088:189:7, :281:75) - subject, not neighbour; restoration proven by git diff HEAD naming no file. ABLATION 2 (surgical: '...(def.rest ? {rest: rest!} : {})' -> 'rest: rest ?? undefined'): landing proven (1->0, mutant 1, blob 2696d179); exit 1 with EXACTLY ONE failing test, 'a REST-LESS tuple that is legitimately rebuilt keeps def.rest === null' at :236:7, identity assertions staying GREEN - it varies only its own claim. Ablation 2 FALSIFIED the proving-removal note I had first written beside that assertion (it described a no-op under the repair); the note in the file is corrected to the mutation actually verified. Proving removals are recorded beside each assertion, not only in prose. CENSUS, two rules, one instrument run on the ablated (before) and repaired (after) tree; neither record figure cited as a baseline. RULE A (terminating at reference equality, the 9034 rule): before 13603 nodes / 7620 refEq / 0.5602; after 13512 / 7560 / 0.5595. RULE B (exhaustive, fixed denominator): before 33556 / 24492 / 0.7299; after 33556 / 24523 / 0.7308. Rule A's ratio goes DOWN and that is the rule working as designed - a node that becomes reference-equal takes its subtree out of the count. The two rules agree on the delta: A's notReferenceEqual falls by 31 (5983->5952), B's refEq rises by 31 (24492->24523), denominator byte-identical at 33556. restlessTupleRoots 23 in both. The moved set is NAMED and diffed, not counted. GATES, derived by enumerating 38 workflow files and extracting reachable invocations, not asserted: packages/types vitest 186 files / 4282 tests exit 0; packages/types type-check exit 0; packages/types lint 0 errors; targeted eslint over the 3 touched files exit 0; changeset presence/fixed/no-major/overwrite/claims all 0; control-bytes 0; new-cross-file-line-citations 0; test-path-roots 0; vi-mock x3 all 0; shell-escape-residue 0; unreferenced-sources 0; type-check-coverage 0; lint-coverage 0; spec-symbols, self-import, phantom-deps, unused-deps, entry-guard all 0; installed-pin-claims, published-tsconfig-exclude, side-effects-array all 0; workspace build 43/43 exit 0; dist-completeness, esm-specifiers, published-dist all 0; 6 consumer test files naming the three affected exports, 122 tests, exit 0. Final state re-verified at HEAD 57739e6. apps/console occurs 0 times in every verbose log (objectui#3378 guard). NOT MEASURED, reported as such and never as red: check:readme-exports and check:spec-floors both exited 1 against an unbuilt tree, saying so themselves ('produced no build output to judge' / 'the population COLLAPSED - this run proves nothing'); after turbo run build (43/43) BOTH return 0, and only the re-run is reported. A broader consumer run over core|fields|plugin-list|components TIMED OUT at 560s (exit 124) - NOT MEASURED, neither green nor red; narrowed to the 6 test files that actually name the affected exports, which pass. The same discipline caught two of my OWN errors: type-check exit 2 on a control I wrote with an incompatible input type, and an eslint error for an unused eslint-disable (no-console is not enabled here). Both fixed and re-run. LINT NARROWING declared with three pieces of evidence: (i) population from eslint's own config; (ii) --format json reports 257 files linted in packages/types, 0 errors, 285 warnings, ALL pre-existing and 0 on any file this diff touches; (iii) invariance - eslint.config.js declares no parserOptions.project and no projectService, so type-aware linting is off and this diff cannot move an untouched file's verdict. The repo-wide pnpm lint farm is CI's run.",
    "mcp_calls": "2 - both search_issues, for the out-of-scope dedupe plus its control word. Everything else went over repo-scoped REST (card read, comments, issue create, PR create, read-backs) or ran locally. CHANNEL SWITCH DECLARED: the REST search endpoint returned 403 in this container although repo-scoped REST reads return 200, so dedupe moved to MCP.",
    "open_questions": [
    {
    "question": "The dispatch order contains a direct instruction conflict about the contract-review label, and I did not resolve it silently. The Clause-2 section says needs:contract-review 'must be hung on the PR when it appears'; the PR-shape section says 'Do not add or remove any label.' Which governs?",
    "options": [
    "A - I hang no label (what I did): treat the explicit prohibition as the stronger instruction, state in the PR body that the label applies and that the seat must hang it.",
    "B - I hang needs:contract-review on the PR: treat the specific Clause-2 instruction as overriding the generic label-hygiene rule."
    ],
    "recommendation": "A, because the failure modes are asymmetric in the direction that matters. If I withhold the label the seat can hang it in one action, and nothing can land meanwhile - the PR is draft and clause 2 clears only on a same-form PASS at the landing head. If I hang it against an explicit prohibition, the norm violation is not recoverable by anyone. The seat's own recorded asymmetry (a carrier left hung can never cause a review to be skipped) argues for the label existing, not for me being the one to create it. ACTION NEEDED: the seat should hang needs:contract-review on objectui#9496."
    }
    ],
    "out_of_scope_findings": [
    "filed as objectui#9491: WalkableDef declares rest?: z.ZodType, which does not admit the null zod 4 actually mints - the inaccurate declaration is the ROOT CAUSE of this card (the arm was written : undefined because the type said so, and tsc agreed). Not repaired here: node-derivation.ts is outside the declared file surface and the type is shared by two walkers. Successor: objectui#9491; the hazard is also recorded in a comment beside the repair.",
    "noted, not filed: zod's $ZodFunction.input() builds a tuple def as rest: args[1], so def.rest can be undefined there rather than null - a third spelling. The repair handles it correctly (undefined === undefined), and the walker's function arm returns as-is so it is unreachable from this module anyway. Successor: none - no PR or person reaches this path; recorded so a future widening of the function arm does not rediscover it.",
    "noted, not filed: check:spec-floors is wired to workflow_dispatch + nightly cron + push-on-gate-wiring only, so it never runs on a pull request. Measured green here post-build, but a PR-time regression in it would be invisible until the nightly. Successor: none identified; this is an observation about gate wiring, not a defect."
    ]
    }

    Report posted by the objectui domain:spec developer seat. Generated by Claude Code, session session_01L5xpA5q533BgTTNADibEFt.


    Generated by Claude Code

  5. claude commented on Sep 14, 2026

    @claude
    Contributor

    Addendum to the report above — one field is now stale, recorded rather than rewritten.

    My report's open_questions[0] ends with "ACTION NEEDED: the seat should hang needs:contract-review on objectui#9496." That action is already done, and not by me.

    Measured on the PR's own event stream after posting:

    labeled: package: types        by: github-actions[bot]  2026-09-14T11:20:21Z
    labeled: tests                 by: github-actions[bot]  2026-09-14T11:20:21Z
    labeled: needs:contract-review by: claude[bot]          2026-09-14T11:20:35Z
    

    ⇒ Clause ② is carried on the PR as well as on the card. ⛔ I made no label call at any point, so all three are another actor's state: the first two are the repository's own labeler workflow, the third is an actor under the shared identity. Per the standing rule I have left every one of them alone and am reporting rather than correcting.

    ⚠️ The instruction conflict itself still stands and is still worth a ruling, because it will recur on the next clause-② card: the Clause ② section says the label "must be hung on the PR when it appears", while the PR-shape section says "⛔ Do not add or remove any label." I acted on the prohibition. The outcome here was benign only because another actor covered the action — that is luck, not a resolution.

    Nothing else in the report changes: draft PR objectui#9496, status: done, all six premises TRUE, :246 measured clean.


    Generated by Claude Code

  6. claude commented on Sep 14, 2026

    @claude
    Contributor

    os-dev-report

    {
    "issue": 9088,
    "status": "done",
    "round": 2,
    "branch": "claude/issue-9088-rest-less-tuple-identity",
    "pr": "#9496",
    "head": "d8b47e5c19236c5e5549b1792513ffee5bf2a180",
    "premise_still_valid": true,
    "summary": "Round-1 contract-review FAIL addressed. Three of the four items are implemented; item 4(b) does NOT reproduce and is left unimplemented with its measurement on the PR, per the standing rule against silent reinterpretation. Items 1+2: registry-meta-carry-9102.test.ts carried a SECOND rest-less-tuple carve-out with no expiry assertion. I reproduced the reviewer's blindness proof exactly (34/34 green with the defect restored, same blobs 42765e66a0 -> ab718d1714), deleted the exclusion, replaced it with a non-empty-AND-reference-equal assertion matching the 9034 pin, and rewrote the helper docblock to match the tree (one exception, lazy). Verified by re-ablation: the file went from 34/34-blind to exit 1 with 2 failures at :833:7 and :857:7. Item 3: the :246 structural census is restated over the full 176-file zod/v4 tree; 'at one site' corrected to 6 locations (3 logical sites x 2 module formats) naming core/api.{js,cjs}, the file the old 2-file corpus excluded and where zod's tuple factory actually lives. Item 4(a)(c)(d) corrected in the body. The repair to imported-defaults.ts itself is unchanged and was confirmed correct by the reviewer.",
    "item_4b_rejected_with_measurement": "The reviewer's e7c9e6156f is a SHALLOW-CHECKOUT ARTEFACT, not a defect in the PR. Measured both legs in one worktree: at git rev-parse --is-shallow-repository = true (depth 204), git log -L 221,228:... b8a006883d returns e7c9e61; after git fetch --unshallow (depth 10222, is-shallow=false) the SAME command at the SAME rev returns 645087c — the reading I originally published. On full history all four cited commits are ancestors of the cut point (each merge-base --is-ancestor exit 0, which is self-validating and needs no control leg), and --diff-filter=A independently names 645087c as the commit that ADDED the file. At depth 204 the same ancestry queries answered exit 1 for 645087c and 6732df4 — the classic shallow false negative: a missing object truncates an ancestry path, it never invents one. ROOT CAUSE AND A SHARED-STATE DISCLOSURE: git worktree isolates the working tree and HEAD but SHARES .git/, including the shallow marker, so one shallow fetch in any worktree silently shallows every sibling. /home/user/objectui read is-shallow=false at the start of this card and true by round 2. I ran git fetch --unshallow, so the shared store is full again (10131 -> 10222 refs) — disclosed rather than left for someone to trip over. Premise 6's row now carries TWO legs, the second with its precondition stated, so the claim is reproducible instead of depending on an unstated checkout depth.",
    "my_own_sweep": "NOT adopted from the reviewer — re-derived. Counting rule: three independent terms, git grep over all tracked files, reported as FILES not lines, union at the end, with a same-subject control (stripImportedDefaults, 23 files) proving the instrument live. Term 'rest-?less|restlessTuple|hasRestlessTuple' (case-insensitive) = 5 files; bare '9088' = 7; 'def.rest' = 7. UNION = 9 files, versus the reviewer's bound of 5. The four extra: two incidental digit matches (plugin-gantt/CHANGELOG.md, a schema-catalog fixture) and — the one that mattered — packages/types/src/strict-authoring-face.ts, THE SIBLING WALKER, plus its measurement script; neither is reachable by the reviewer's two terms. VERDICT on the sibling: clean, and for a structural reason rather than luck — its tuple arm is out = cloneWithDef(schema, {...}) UNCONDITIONALLY, with no unchanged and no identity comparison, so there is no null-versus-undefined pair to get wrong; its rest handling is the same safe spread. So no third site exists, but that now rests on a measurement of the sibling rather than on a sweep whose terms could not see it.",
    "errors_i_caught_in_my_own_work_this_round": "Two, both from the adversarial re-read the seat asked for, neither caught by any gate. (1) Checking the sibling walker I ran grep -c and printed '0 = no identity comparison'. grep -c counts LINES and the real count was 1 — the word 'unchanged' inside a prose quotation in that file's docblock. The substantive conclusion held; the number I nearly published was wrong. (2) My first objectui#3378 apps/console extractor returned 0 DISTINCT FILES, which would have been a vacuous '0 under apps/console'. I rebuilt it and self-tested on a seeded 4-line log over 2 files (1 under apps/console); it returned exactly 2 and 1 before being pointed at anything real. Applied to the run: 186 distinct collected files — matching the reported file count exactly — of which 0 under apps/console.",
    "declared_file_surface_breach": "packages/types/src/tests/registry-meta-carry-9102.test.ts is NOT on the declared file surface. Edited here anyway, pre-authorised by the dispatching seat as a mandated consequence, and declared in the PR body. WHAT CHANGED: one exclusion deleted from one filter, one replacement it() added, one helper docblock rewritten; no other test, file or assertion touched. WHY UNAVOIDABLE: the card's deliverable is that a rest-less tuple keeps its identity, and a live carve-out that provably suppresses that exact defect means shipping the fix beside a control that can only come back green. NOTHING was skipped, disabled or quarantined: the file gains an assertion (34 -> 35 tests) and gains the ability to fail (34/34-blind -> 2-red under the identical ablation).",
    "tests": "Re-run at the PUSHED head d8b47e5, after the final main merge, so no reading predates the head it describes. packages/types suite: 186 files / 4283 tests, exit 0 (4282 -> 4283, the new assertion). packages/types type-check: exit 0. eslint over all four touched files: exit 0, no output. check-changeset-presence, check-changeset-claims, check-control-bytes, check-new-cross-file-line-citations, check-test-path-roots, check-vi-mock-specifiers: exit 0 each. ABLATION, 9102 pin, BEFORE my repair (reproducing the reviewer): leg 1 unmutated exit 0 34/34; mutation proven on disk before reading anything (fixed 1->0, defect=1, blob 42765e66a0 -> ab718d1714, matching the reviewer's blobs); leg 2 ablated STILL exit 0, STILL 34/34 — blind. ABLATION, same mutation, AFTER my repair: exit 1, 2 failed / 33 passed of 35, at frames registry-meta-carry-9102.test.ts:833:7 (restored identity assertion) and :857:7 (new replacement). Both ablations ran from the committed state under trap EXIT INT TERM with absolute paths; restoration proven each time by git diff HEAD naming no file. FULL-TREE CENSUS (item 3), my own rule, corpus = all 176 files of zod/v4 (88 .js + 88 .cjs): per member shape 0, options 4, items 0, element 0, rest 6, valueType 0, left 0, right 0, in 71, out 0, innerType 2, getter 0; read in context the three non-zero non-rest members are false friends (options = a local, innerType = a value Set, in = the CJS for (var k in mod) keyword), so rest is the only def member zod mints as null and out is zero — the same verdict as the narrow corpus gave, now over the corpus that could have contradicted it. The exact minting statement occurs at 6 locations: classic/schemas.{js,cjs}, mini/schemas.{js,cjs}, core/api.{js,cjs}. NOT MEASURED this round: the repo-wide pnpm lint farm and the full root pnpm test farm (CI shards both); the build-dependent gates (readme-exports, spec-floors and the dist/esm family) — measured green post-build in round 1, not re-run here because nothing in this round's diff is built output; CI convergence at the new head, which is the seat's to read.",
    "mcp_calls": "0 this round — the round-1 total of 2 is unchanged. All GitHub I/O this round went over repo-scoped REST (review read, PR body PATCH, read-backs, this comment).",
    "open_questions": [
    {
    "question": "Item 4(b) is rejected with a measurement rather than implemented. Does the seat accept the rejection, and should the shallow-checkout hazard be filed so the next review does not repeat it?",
    "options": [
    "A - accept the rejection as measured, and file a card for the hazard (git worktree shares .git/shallow, so one shallow fetch silently shallows every sibling worktree and makes git log -L and merge-base --is-ancestor return false negatives).",
    "B - accept the rejection and leave the hazard unfiled, since git fetch --unshallow has already restored the shared store.",
    "C - reject my rejection: require the body to quote e7c9e61."
    ],
    "recommendation": "A. The measurement is unambiguous and reproducible in both directions from one worktree, and exit-0 ancestry answers are self-validating. B under-serves the next round: the shared store can be re-shallowed by any agent at any time and the failure is silent, direction-specific and reads as a confident wrong answer rather than an error — exactly the shape that costs a review round. C is refused by measurement: at full depth the cited instrument returns 645087c, and --diff-filter=A independently agrees."
    }
    ],
    "out_of_scope_findings": [
    "filed in round 1 as objectui#9491: WalkableDef declares rest?: z.ZodType, which does not admit the null zod 4 mints — the root cause of this card. Unchanged this round; node-derivation.ts remains untouched.",
    "noted, not filed (RAISED TO THE SEAT INSTEAD, see open_questions): git worktree shares .git/, including the shallow marker, so one shallow fetch silently shallows every sibling worktree. It produced a false review finding this round (item 4(b)) and cost a round trip. Successor: whoever the seat assigns — I have restored the shared store to full depth but nothing prevents a re-shallowing.",
    "noted, not filed: packages/types/src/strict-authoring-face.ts, the sibling walker, cannot carry this defect because it never compares for identity — it rebuilds every node unconditionally. Recorded so a future change that gives it an identity fast-path knows it must handle zod's null rest spelling. Successor: none today; no PR or person is touching that arm."
    ]
    }

    Round-2 report from the objectui domain:spec developer seat. Generated by Claude Code, session session_01L5xpA5q533BgTTNADibEFt.


    Generated by Claude Code

  7. claude commented on Sep 14, 2026

    @claude
    Contributor

    os-dev-report

    {
    "issue": 9088,
    "status": "done",
    "round": 3,
    "branch": "claude/issue-9088-rest-less-tuple-identity",
    "pr": "#9496",
    "head": "d8b47e5c19236c5e5549b1792513ffee5bf2a180",
    "head_unchanged": true,
    "code_changed_this_round": false,
    "premise_still_valid": true,
    "summary": "Round-2 review FAILed on four record- and instrument-accuracy items having found NO substantive defect. Items 1, 2 and 3 are addressed by PR-body edits plus one re-taken measurement; item 4 is untouched because the seat holds the re-run. ⛔ No code changed and the head sha is still d8b47e5, verified by reading it back from the API after the body PATCH, so the seat's re-run stays attached to the reviewed head. I worked from a DETACHED worktree at that exact sha so the branch ref could not move.",
    "item_1_the_two_section_7_numbers_as_they_now_read": "§7 row now reads: '| packages/types vitest (186 files, 4283 tests) | 0 |'. Re-measured at d8b47e5 from the repository root with --reporter=verbose: Test Files 186 passed (186), Tests 4283 passed (4283), exit 0. The body no longer contradicts itself — §12 already said 4283.",
    "item_2_the_two_section_7_numbers_as_they_now_read": "§7 row now reads: '| targeted eslint over the 4 touched code files (--format json: 4 entries, 0 errors, 0 warnings) | 0 |'. The count is read from eslint's own JSON output, not asserted: 4 entries, 0 errors, 0 warnings each — imported-defaults.ts, imported-defaults-describe-9034.test.ts, imported-defaults-rest-less-tuple-9088.test.ts, registry-meta-carry-9102.test.ts. The declared breach is what made it four.",
    "item_3_reading_both_rules_plus_positive_control": "RETRACTED the path-prefix instrument at all three sites (§3, §8, §12) and re-took the reading in a new §13. ON THE packages/types RUN AT d8b47e5: Rule A (path prefix '^apps/console/') = 0; Rule B (project tag '|@object-ui/console|') = 0; POSITIVE CONTROL on the same log by the same rule shape, '|unit|' distinct files = 186, which also matches the reported file count exactly. Both rules agree at 0, but only Rule B's 0 is a reading. NEGATIVE CONTROL — I did not merely adopt the reviewer's rule, I caught the broken instrument in the act by running a console test on purpose: vitest run --reporter=verbose apps/console/src/components/FormPage.fieldSpec.test.ts emits '|@object-ui/console| src/components/FormPage.fieldSpec.test.ts' — project-relative, no prefix — and in that log the string 'apps/console' occurs 0 times while the tag occurs 2 times. Applying both rules to THAT log: Rule A = 0 (fails to detect console tests that demonstrably ran), Rule B = 1 (detects them). Mechanism confirmed: apps/console is registered as a project in the root vitest.config.mts by absolute path at :457, so the reporter tags it by package name and prints the file project-relative. ⇒ 0 console files collected, now paired with a control that demonstrably fires.",
    "clause2_carrier_gate_exit_codes": "AS REQUESTED, --pair 9088: EXIT 2. Verbatim: 'PR #9088 is not open, or names no card this file can derive ... ⛔ Not a clearance — the pair could not be formed, so nothing about it was judged.' CAUSE: --pair takes a PR number, and 9088 is the CARD; the script's own usage text says 'a PR number goes to --pair'. Reported rather than quietly substituted. CORRECT INVOCATION, --pair 9496: EXIT 0. Verbatim: '✓ check-clause2-carriers: PR #9496 / card #9088 — the clause-② declaration is readable in the fixed spelling and both carriers agree, and its diff carries no widening tell.' Both run from /home/user/objectstack with PM_SWEEP_REPO=objectstack-ai/objectui.",
    "correction_to_my_own_round_2_disclosure": "The reviewer's precision note is right and the truth is worse than it put it. My round-2 disclosure said grep -c printed 0 and blamed line-counting. Measured: the command returned 1, and the '0' beside it was a HARDCODED echo label I had written before seeing the output — not a measurement at all. Blaming grep -c was also arithmetically impossible, since line-counting can only make it under-count a multi-hit line, never turn 1 into 0. The real gap was PATTERN SCOPE: 'unchanged' matched a prose quotation in the file's docblock. Correctly scoped: grep -c 'const unchanged' = 0, grep -c 'unchanged(' = 0, and the file's only === anywhere is def.type === 'lazy' at :163. §12 now states this.",
    "item_4_not_acted_on": "Untouched by instruction. ⛔ No timeout-minutes change, ⛔ no empty commit, ⛔ no close/reopen, ⛔ nothing skipped, disabled or quarantined. The seat holds the single permitted re-run at this head; if it cancels again it becomes an ambient CI-capacity card of its own and is not absorbed into this PR.",
    "section_6_untouched": "The reviewer declined to publish any number about §6 because its own Rule-B reimplementation failed its own calibration (delta 0 for a change already proven true by direct probe). §6 is therefore UNVERIFIED, NOT REFUTED. I have changed nothing about it and added nothing to it, as instructed.",
    "tests": "All at d8b47e5, from a detached worktree at that exact sha. packages/types suite from the repository root with --reporter=verbose: 186 files / 4283 tests, exit 0. eslint --format json over the 4 touched code files: exit 0, 4 entries, 0 errors, 0 warnings. Guard instrument: see item_3 above — two rules, one positive control (|unit| = 186) and one negative control (a deliberate console run where Rule A reads 0 and Rule B reads 1). check-clause2-carriers --pair 9496: exit 0. NOT MEASURED this round, each with a reason: the full gate farm and the build-dependent gates (measured green in earlier rounds; nothing in round 3 changes code, so no build output can have moved); CI convergence at this head, which is the seat's to read and whose one cancelled shard the seat is re-running.",
    "mcp_calls": "0 this round; the series total remains 2, both from round 1. All GitHub I/O this round went over repo-scoped REST.",
    "open_questions": [
    {
    "question": "The dispatch asked for check-clause2-carriers --pair 9088, but --pair takes a PR number, so that invocation exits 2 and judges nothing. Should the dispatch template be corrected so future rounds ask for the PR number?",
    "options": [
    "A - correct the template to --pair PRNUMBER (and note that the card number is derived by the script, not passed).",
    "B - leave it; the reviewer and I both know to substitute the PR number."
    ],
    "recommendation": "A. Exit 2 is explicitly 'not a clearance', but it is a non-zero exit that a future reader skimming for a green could easily misfile as a carrier failure on card 9088 rather than as a malformed invocation. The script already refuses loudly and correctly; the cost is entirely in the instruction that produces the refusal. This is the same class as the apps/console lineage in §13 — a defective instruction propagating through dispatch templates faster than it is caught."
    }
    ],
    "out_of_scope_findings": [
    "filed in round 1 as objectui#9491: WalkableDef declares rest?: z.ZodType, which does not admit the null zod 4 mints — the root cause of this card. Untouched since.",
    "noted, not filed (already the seat's, per its own message): the apps/console path-prefix guard instruction is defective and reached three agents through the dispatch template; the seat records os-dev.md:288 and objectstack#18181 as the tracking surface. §13 records the lineage and the remedy (project-tag rule plus a firing positive control).",
    "noted, not filed: I wrote angle-bracket-shaped placeholders into a GitHub comment this round, against my own stated discipline. The read-back showed delta 0 and all four intact, so nothing was lost and ⛔ no rewrite was made — but the survival was luck, not compliance. Successor: none; recorded so the next round spells placeholders as words rather than relying on the sanitizer being lenient."
    ]
    }

    Round-3 report from the objectui domain:spec developer seat. Generated by Claude Code, session session_01L5xpA5q533BgTTNADibEFt.


    Generated by Claude Code

  8. claude commented on Sep 14, 2026

    @claude
    Contributor

    os-dev-report

    {
    "issue": 9088,
    "status": "done",
    "round": 4,
    "branch": "claude/issue-9088-rest-less-tuple-identity",
    "pr": "#9496",
    "head": "d8b47e5c19236c5e5549b1792513ffee5bf2a180",
    "head_unchanged": true,
    "code_changed_this_round": false,
    "premise_still_valid": true,
    "summary": "Round-3 review FAILed on ONE record-accuracy item, confirming again that this PR has no substantive defect. §2 published 'exactly twice: :223 and :246' with NO sha stated anywhere in the section — true at the merge-base, false at the head, and falsified by this diff's own 28-line comment insertion at :221-:248, which removed the :223 occurrence and pushed def.out from :246 to :274. I reproduced that before taking the fix, then applied the reviewer's three replacement strings VERBATIM by line index, each guarded by an assertion that the target line still read exactly what the review quoted. ⛔ No code changed; head is still d8b47e5, verified by reading it back from the API after the PATCH, so the spent Test (shard 1/4) re-run stays attached to the head it cleared.",
    "the_three_edited_lines_as_they_now_read": {
    "line_26": "## 2. The def.out verdict — :246 at b8a006883d, :274 at this head",
    "line_28": "At b8a006883d the shape def.X ? walk(def.X) : undefined recurs exactly twice: :223 (def.rest, this card) and :246 (def.out, not named by the card). ⚠️ At this head it occurs once, at :274 — the tuple occurrence is gone by the repair, and the 28-line comment block this diff inserts at :221-:248 shifted def.out from :246 to :274.",
    "line_30": "Verdict on def.out (:246@b8a006883d = :274@Head): NOT broken. "Only tuple" — as a reading.",
    "note": "Read back from the GitHub API after the PATCH and confirmed stored byte-identical to what was sent; taken verbatim, not paraphrased."
    },
    "my_own_reproduction_before_taking_the_fix": "Detached worktree at d8b47e5, non-shallow. grep -nE 'def\\.[a-zA-Z]+ \\? walk\\(def\\.[a-zA-Z]+\\) : undefined' — at b8a0068: 2 occurrences, :223 (def.rest) and :246 (def.out); at this head: 1 occurrence, :274 (def.out). At the head, :223 and :246 are comment lines inside the block this diff inserts, whose bounds :221 and :248 I resolved directly. Finding confirmed independently, not adopted.",
    "my_adversarial_pass_over_the_rest_of_the_record": "⛔ I did not accept 'the finding is localised' on assertion. I re-resolved EVERY line-number-shaped citation the body publishes, each at its stated sha. Head-relative: imported-defaults.ts:221 and :248 (block bounds) OK, :274 = the def.out line OK, strict-authoring-face.ts:163 = if (def.type === 'lazy') { OK, vitest.config.mts:457 = the console project registration OK. b8a0068-bound: :223 OK, :246 OK, :156-157 and :295 (premise 2's docblock) OK, imported-defaults-describe-9034.test.ts:163 (premise 3's predicate) OK — §1's rows are sha-bound by that table's own column header. After the edit, grep -nF ':246' returns exactly lines 26, 28, 30, all inside sha-bound phrasing. The reviewer's localisation holds: no second stale citation exists.",
    "clause2_carrier_gate": "PM_SWEEP_REPO=objectstack-ai/objectui node scripts/pm/check-clause2-carriers.mjs --pair 9496 run from /home/user/objectstack: EXIT 0. Verbatim: '✓ check-clause2-carriers: PR #9496 / card #9088 — the clause-② declaration is readable in the fixed spelling and both carriers agree, and its diff carries no widening tell.'",
    "tests": "⛔ No code changed this round, so nothing was re-run that could only have re-measured an unchanged tree. What WAS measured: the census-shape grep at both shas (2 at b8a0068, 1 at head), the head resolution of :221/:223/:246/:248/:274, and the full citation audit above. PR body PATCH read back: delta +58 bytes, which is the documented unconditional footer append, with no footer accumulation (session-URL 1, bare 1) and content otherwise byte-identical. Head sha read back from the API and confirmed unchanged. NOT MEASURED, with reasons: the test and gate farm — nothing in this round's diff is code, so a re-run could not differ from round 3's readings at the same sha; CI convergence, which the seat reports met at 13:11:46Z (36/36, 0 not-green, Test (shard 1/4) attempt 2 a genuine success).",
    "mcp_calls": "0 this round; the series total remains 2, both from round 1. All GitHub I/O went over repo-scoped REST.",
    "open_questions": [],
    "out_of_scope_findings": [
    "filed in round 1 as objectui#9491: WalkableDef declares rest?: z.ZodType, which does not admit the null zod 4 mints — the root cause of this card. Untouched since.",
    "noted, not filed: this series produced the same defect class twice in the same document — a line citation published without the sha it was measured at (round 2 item 4(a), a test frame; round 3, §2's heading and two lines). Both were caught by review, neither by any gate, and the second was falsified by the PR's own insertion. Successor: none today — a gate would have to resolve citations against a stated sha, which is a real tool and not a rider on this card.",
    "noted, not filed: §6's reference-equality census has now been declined by two independent reviewers, each because their own reimplementation failed its own calibration (delta 0 for a change already proven true by direct probe). It is UNVERIFIED, NOT REFUTED, and I have added nothing to it in response, as instructed. Successor: whoever re-derives objectui#9103's population, which the triage note already says must be re-derived after this lands rather than inherited."
    ]
    }

    Round-4 report from the objectui domain:spec developer seat. Generated by Claude Code, session session_01L5xpA5q533BgTTNADibEFt.


    Generated by Claude Code

  9. claude commented on Sep 14, 2026

    @claude
    Contributor

    os-dev-report

    {
    "issue": 9088,
    "status": "done",
    "round": 5,
    "branch": "claude/issue-9088-rest-less-tuple-identity",
    "pr": "#9496",
    "new_head": "c41d8e8926420041d197d9bb792c44d86f587234",
    "previous_head": "d8b47e5c19236c5e5549b1792513ffee5bf2a180",
    "premise_still_valid": true,
    "summary": "Round-4 review FAILed on three items, again finding NO substantive defect. All three were stale claims in the SHIPPED pin file imported-defaults-rest-less-tuple-9088.test.ts, and all three are fixed. ROOT CAUSE ACCEPTED: round 3's sweep declared its population as 'every line citation the body publishes', so a stale claim living in the diff was outside it BY CONSTRUCTION — I audited the record and shipped the artefact unaudited. The head moved as expected because all three fixes are in tracked source.",
    "the_three_repaired_lines_as_they_now_read": {
    "item_1_minting_census": "Zod 4.4.3 spells "no rest element" as def.rest === null — a real, OWN key holding null. Measured over the whole shipped zod@4.4.3/v4 tree (176 files, 88 .js + 88 .cjs), the statement that mints it, const rest = hasRest ? _paramsOrRest : null, occurs at 6 locations — 3 logical sites x 2 module formats: classic/schemas.{js,cjs}, mini/schemas.{js,cjs} and core/api.{js,cjs}, the last being where zod's tuple factory lives. [followed by a pinned-corpus warning recording that the old 2-file corpus excluded core/api.cjs]",
    "item_2_census_hits": "That census had TWO hits at b8a006883d — the tuple arm's def.rest at :223 and the pipe arm's def.out at :246 — and a verdict on the second read off the first would be worthless. At this head ONE remains: the tuple hit is gone, removed by this card's own repair, and def.out now sits at :274.",
    "item_3_pins_list_citation": "5. The :246@b8a006883d = :274@Head verdict, which is the triage fence's census answered as a measurement rather than read off the tuple result. (The def.out site moved because the repair's own comment block was inserted above it; a quoted line is only a measurement against a stated sha.)"
    },
    "tree_sweep_confirmation": "YES — I grepped the TREE, not the body, and not only the three sites named. Population: every file this branch touches (46 paths via git diff --name-only from the branch point, a superset of the 5 I authored). Four independent terms, reported as file:line: (1) site-count wording 'one site|1 site|single site|6 locations|3 logical sites'; (2) census-count wording 'two hits|2 hits|has two|recurs|exactly twice|census has'; (3) bare ':NNN' citations; (4) 'classic/schemas|core/api|mini/schemas'. CONTROL that fires: 'objectui#9088' hits 5 files. RESULT: exactly the three named sites, NO FOURTH. Two near-hits ruled out by READING them rather than by pattern — registry-meta-carry-9102.test.ts:966 ('one site was widened') is about objectui#9102's own subject, not zod's minting; and the changeset carries no count or citation claim at all.",
    "my_own_edit_falsified_this_body_and_i_re_measured": "⭐ Adding lines to the pin file moved every frame the PR body quotes for it — the same population trap one level down, caught by looking rather than by being told. ⛔ I did not compute the new numbers; I re-ran BOTH ablations from the committed state under trap EXIT INT TERM with the landing proven on disk first. ablation 1 subject identity :189:7 -> :205:7; ablation 1 deep-clean control :283:75 -> :299:75; ablation 2 clone rest spelling :236:7 -> :252:7. Ablation 1 at the new head: exit 1, 7 failing frames (9034:451:7/:469:7/:497:7, 9088:205:7/:299:75, 9102:833:7/:857:7) — matching the reviewer's count of 7. Ablation 2: exit 1, exactly one failing test at :252:7, identity assertions green. Both restorations proven by git diff HEAD naming no file. All four citation sites in the body are updated and bound.",
    "reviewer_disclosed_misses_i_took": "(1) WRONG ZOD IN THE CORPUS PROBE: I printed the resolved zod path and version before counting and self-tested the corpus at 176 = 88 .js + 88 .cjs before reading any result; the resolved path is zod@4.4.3, not the zod@3.25.76 also in the store. (2) THE BYTE-COUNT TRAP, AND IT FIRED ON ME LIVE THIS ROUND: my round-5 PR comment read back with sent chars 4820 and stored chars 4820 — IDENTICAL counts — while the strings DIFFERED. String comparison with a first-differing-index localisation put it at index 4763: GitHub inserted a newline before the rule line and stripped the trailing newline, and the two offset each other exactly. Content intact, nothing eaten, no repair made. A count comparison would have passed this falsely; this round I had already stopped using one. (3) 'A self-test that fails tells you something is wrong, not which thing' — noted against my own series: on the apps/console extractor the instrument was the broken half (a console run proved it could not fire); on the grep -c label neither was — the number was real and my printed label was a hardcoded echo.",
    "tests": "Re-run at the PUSHED head c41d8e8 after the final main merge, so no reading predates the head it describes: packages/types 186 files / 4283 tests exit 0; type-check exit 0; eslint over the 4 touched code files exit 0 with no output; check-changeset-presence exit 0; check-control-bytes exit 0. objectui#3378 guard, BOTH rules on that run: path-prefix 0, project-tag 0, positive control |unit| = 186 distinct files, matching the collected-file count exactly. Ablations as above. PR body read back by STRING comparison: first difference at index 37633, the very end — the documented appended bare footer, everything before identical. NOT MEASURED: the full gate and test farm, and CI convergence at the new head, which is the seat's to read.",
    "clause2_carrier_gate": "PM_SWEEP_REPO=objectstack-ai/objectui node scripts/pm/check-clause2-carriers.mjs --pair 9496 from /home/user/objectstack: EXIT 0 — '✓ PR #9496 / card #9088 — the clause-② declaration is readable in the fixed spelling and both carriers agree, and its diff carries no widening tell.'",
    "mcp_calls": "0 this round; series total remains 2, both from round 1. All GitHub I/O over repo-scoped REST.",
    "open_questions": [],
    "out_of_scope_findings": [
    "filed in round 1 as objectui#9491: WalkableDef declares rest?: z.ZodType, which does not admit the null zod 4 mints — the root cause of this card. Untouched since.",
    "noted, not filed: this series failed three times on a claim whose line number or count was falsified by the PR's own diff — twice in the body, once in the shipped file. Every instance was caught by review, none by any gate. The generalisable defect is that a citation carries no sha and nothing checks it. Successor: a gate resolving citations against a stated sha is a real tool, not a rider on this card; the PM records objectui#9471 as a sibling that failed on the same population-scope shape.",
    "noted, not filed: the GitHub comment sanitizer can leave char AND byte counts identical while changing the string (measured live this round: 4820/4820, differing at index 4763, an inserted newline offsetting a stripped trailing newline). Any read-back check built on counts passes this falsely. Successor: none needed here — recorded so the next seat compares strings, not lengths.",
    "noted, not filed: §6's reference-equality census has now been declined by three independent reviewers on the same calibration ground. It is UNVERIFIED, NOT REFUTED, and untouched. Successor: whoever re-derives objectui#9103's population after this lands."
    ]
    }

    Round-5 report from the objectui domain:spec developer seat. Generated by Claude Code, session session_01L5xpA5q533BgTTNADibEFt.


    Generated by Claude Code

  10. claude commented on Sep 14, 2026

    @claude
    Contributor

    Delivered — landed on main

    PR #9496 merged. Closing this card completed. Readings taken 2026-09-14T15:02Z.

    Reading 1 — the merge queue's own timeline

    added_to_merge_queue 14:41:58Z → removed_from_merge_queue 15:01:35Z → merged 15:01:35Z. ⛔ Not an auto_merge field read (it is consumed by the enqueue and reads null afterwards), ⛔ not a check_suite rollup.

    Reading 2 — the content on origin/main, located by SYMBOL

    ⛔ Not by head-sha ancestry, ⛔ not by the merged boolean. Store re-fetched and proved non-shallow (is-shallow-repository = false, 15:02:01Z) before any ancestry call.

    Landing commit 8700d6d93700828eff4d6a8f145add8a0f1ac412
    Title fix(types): compare def.rest like with like so a rest-less tuple keeps its identity (#9496)
    Parent count: 1 — via git show -s --format='%p' <sha> | wc -w, ⇒ a squash, which is this repository's only reachable method.

    ref packages/types/src/zod/imported-defaults.ts
    origin/main :251 — const rest = def.rest ? walk(def.rest) : def.rest; — the false arm now yields def.rest itself, so null is compared against null
    merge-base 8fa7d69af2 (the control) :223 — const rest = def.rest ? walk(def.rest) : undefined; — the old form, whose false arm yielded undefined against a null original

    ⭐ The control fires: the two refs read differently, so the origin/main reading is evidence of this change rather than of a grep that matches everywhere.

    The old behaviour is gone

    A rest-less tuple compared null (the original) against undefined (the rebuilt), read unequal, and was needlessly cloned — losing reference identity. That comparison is now like-with-like.

    Gate record

    • ① round-5 contract review PASS at the exact landing head — 5665421318; the head it declares and the live head.sha were compared as strings and are character-identical.
    • ② --pair 9496 exit 0, captured before any pipe. ⛔ That 0 is silent on the clause-② independence limb — and this shift finally established why: check-clause2-carriers.mjs:2127-2132 declares that a verdict on a PENDING pair's PR thread is invisible to C4, and every verdict in this series lives on the PR thread. ⇒ C4 was never going to fire. Independence rests on the maintainer's ruling 「新起的子代理算干净」, judged by independent measurement.
    • ③ 37 of 37 check-runs green at the landing head (total_count == returned), 0 not-green, 0 running, legacy combined status success. ⚠️ The count moves 36 → 37 at undraft (Governed Surface Queue Guard starts on the pull_request event) — a ③ reading taken while the PR was a draft does not survive the undraft.
    • Carrier — needs:contract-review was discharged against the PASS with the discharge posted before the removal, and is removed from this card in the same stroke as pm:dispatched. ⚠️ Why the order matters: the queue guard's carrier leg reads the label, not the verdict, and six of eleven measured enqueues had the carrier stripped with no PASS on record — one of them landed a real defect (objectui#8164). ⛔ A silent strip is indistinguishable from that; a recorded discharge is not.

    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

    Labels

    bugSomething isn't workingdomain:specobjectui spec stream: fix lands on packages/types, schema corpus or spec pin coupling — spec lanepackage: typespriority:p3

    Type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions