Repository navigation
fix(client): normalizeSessionResponse's JSDoc records the data.user.image gap as closed, not tracked - #18855
Merged
os-support-ai merged 3 commits intoSep 18, 2026
Conversation
…s closed The block's job is to say what the lift compensates for, so it names the cards that opened and closed each compensation. One clause was still in the present tense: `data.user.image` served `null` against a declared `string | undefined`, with its card marked "tracked separately". Both halves went false when `SessionUserSchema.image` widened to `z.string().nullish()` and that card closed — the sentence pointed the next reader at a closed card as if it were somewhere to go look. Rewritten in the past tense, naming the widening that closed it and the residue list in `auth-login-register-envelope.test.ts` that is pinned empty. Nothing else in the block moves. A pin beside it holds the relation rather than the wording: for each card on a declared closed roster, the block may cite it but may not carry an open-tracking phrase beside that citation. Located by symbol, never by line. Claude-Session: https://claude.ai/code/session_01DvvamiacK328idtBYJBxV3 Co-authored-by: Claude <noreply@anthropic.com>
… published dist `@objectstack/client` ships `dist`; the four code/type artifacts come out byte-identical across this change, but both source maps move, so the published tarball's bytes move and `skip-changeset` would be a false declaration. Claude-Session: https://claude.ai/code/session_01DvvamiacK328idtBYJBxV3 Co-authored-by: Claude <noreply@anthropic.com>
…stale-gap Claude-Session: https://claude.ai/code/session_01DvvamiacK328idtBYJBxV3 Co-authored-by: Claude <noreply@anthropic.com>
Contributor
📓 Docs Drift Check
What this run could not see
Coarse fallback — 15 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): |
os-support-ai
marked this pull request as ready for review
September 18, 2026 00:58
os-support-ai
enabled auto-merge
September 18, 2026 00:58
os-support-ai
deleted the
claude/issue-18510-normalize-session-response-stale-gap
branch
September 18, 2026 01:26
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #18510
Clause-②: no
The JSDoc block above
normalizeSessionResponsesays what the lift compensates for, so it names the cards that opened and closed each compensation. One clause was still in the present tense:reference for the card that sentence names.
Both halves went false when PR #18501 widened
SessionUserSchema.imagetoz.string().nullish()and #17235 moved to closed. It now reads in the past tense, names the widening that closed it, and points at the residue list inauth-login-register-envelope.test.ts② that is pinned empty. Nothing else in the block moves.⭐ Located by symbol, never by line number: the card's
:1514-1517had already drifted to:1520-1531by the time this was dispatched, and the pin added here locates the block the same way.Premise re-verified independently of the dispatch
Both of triage's sequencing conditions, re-read rather than inherited:
merged_at2026-09-16T17:44:07Z) andSessionUser.imageis declaredz.string().optional(), but every/auth/*session route serves"image": null— no real session body parses asSessionResponse#17235 isclosed/completed(2026-09-16T17:44:08Z).SessionUserSchemais declaredlazySchema(() => z.object({…}))inpackages/spec/src/api/auth.zod.ts, andimageinside it readsz.string().nullish().:111isRegisterRequestSchemaand was not touched."Only comments changed" is NOT "nothing published moves" — measured
The card asserts the function is not exported and its comment reaches no
.d.ts, so it "ships to nobody". That assertion was measured against the built artifacts rather than inherited, and it is half right.@objectstack/clientshipsdist,README.md,CHANGELOG.md. ⭐distis six files —index.js,index.mjs,index.d.ts,index.d.mtsand a.mapbeside each bundle. This package emits no*.cjsand no*.d.cts, so a*.d.ctsprobe here would measure an absent file and return a zero about nothing; the four that exist were probed instead.Built from the same tree before and after the change:
no longer residue(block-unique)data.user.imagetracked separately{@link normalizeSessionResponse}set-auth-token{@link normalizeSessionResponse}appears 3× in each.d.ts, carried there by the JSDoc of the exportedauth.login/auth.register/auth.methat link to it. The card's reason is the load-bearing half: the block does not ship because the function it documents is not exported — not because comments in this file do not ship.index.js,index.mjs,index.d.tsandindex.d.mtsare byte-identical across the change (sha256, with the HEAD build re-run as a reproducibility control). Both.mapfiles differ: neither carriessourcesContent(pnpm check:sourcemap-no-sources-contentis why), so no comment text ships inside them either — the position table shifts because the rewritten comment is two lines longer.⇒
skip-changesetwould have been a false declaration. This carries apatchchangeset for@objectstack/client, and the measurement is recorded in the changeset body rather than left in a PR nobody greps.The pin
packages/client/src/normalize-session-response-jsdoc.pin.test.ts— ⛔ not a pin on the block's wording. It pins one relation: for each card on a declared closed roster (#17234, #17235, #17238, #17881, each with the state that was read), the block may cite it — past tense is the point of citing it at all — but may not carry an open-tracking phrase beside that citation. A card that really is open can still be tracked in those words.Red before, green after, with controls that can fail:
1 failed | 4 passed), reporting#17235.5 passed, inside a suite of47 passed (47)files /550 passedtests.#17234,data.token,SessionResponseSchema, and that it is one whole JSDoc block), and a symbol the file does not declare must yield no block. Without it an extractor returning''would make ② pass while measuring nothing.still openis on the vocabulary — the rewrite would have tripped the pin written to satisfy it. The shipped sentence says "remained", and the control records why.Tier measured in both directions, because adding a pin can move a whole file out of its vitest tier: the unit config's roster is 46 files before the pin file exists and 47 after, and the diff is exactly one added line — this file — with nothing dropped.
packages/clienttiers by path (tests/integration/**is excluded from the unit config and has its own config), so a newsrc/*.test.tslands in the unit tier; thevitest-tiers.tscontent-based mechanism ispackages/cli's and does not reach here.Verification
pnpm --filter @objectstack/client test— 47 passed (47) files, 550 passed tests.pnpm --filter @objectstack/client typecheck—tsc --noEmitclean;check:test-typecheckreports the test layer compiles undertsconfig.test.json, 0 files / 0 errors, which is what covers the new pin file.node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstackderived 59 gate commands from the real change set (re-derived after mergingorigin/main, so the stale-tree warning the first derivation printed is cleared). 58 pass.pnpm lint— the repo-wide union (eslint . --no-inline-config), exit 0, at52b7812953.dispatch-gates.mjsdoes not name this family; it was run anyway.pnpm check:dual-build-cjs-loads. It refuses withPREREQUISITE NOT MET … ⛔ This is NOT a pass: nothing was measured(exit 3) because 34 packages have nodist— its prerequisite is a repo-widepnpm build, which CI performs on a fresh checkout. It is recorded as unmeasured rather than as a pass, and this change cannot move it: the four loadable artifacts are byte-identical above.Acceptance notes
⛔ Noted, not filed — none is a reproducible defect, a contract violation, or a metadata-authoring trap.
data.user.imageas appearing in "3 past-tense comments insidepackages/spec's own test files plus this one line inpackages/client". Atorigin/mainit appears in 2 past-tense comments insidepackages/client's own test file (auth-login-register-envelope.test.ts:33and:310), zero in anypackages/spectest file, plus one changeset line and the target line. The fix is unaffected — the target was the only present-tense occurrence, which is what the card was actually about. Successor: this PR.distwith.mapfiles: a comment whose line count changes shifts every mapping after it. Successor: named — the measurement is written into this PR's changeset body, so it ships topackages/client/CHANGELOG.mdrather than staying in a PR nobody greps.pnpm check:type-check-debtruns a turbo build; when that build is SIGKILLed under memory pressure mid-DTS, it leavespackages/spec/distwith zero.d.tsfiles, after which unrelated packages'typecheckfails with a pile ofTS7016 Could not find a declaration file for module '@objectstack/spec/api'that reads exactly like the caller's own change breaking something (AGENTS.md Multi-agent discipline §9, thepackages/spec/distrow).--max-old-space-sizemade it worse (8192 and 4096 were both killed at exit 137; the cgroup kills before V8's own limit bites), and 3072 completed. Successor: this note.Authored by the⚠️ The attribution lives in this prose line rather than a footer of its own: measured on this PR, a REST create stores the footer block byte-identical, while a REST edit APPENDS its own bare block on top of whatever the body already carries — so a body that arrives at its final text through an edit can only carry one footer by sending none.
domain:cliexecution seat in sessionsession_01DvvamiacK328idtBYJBxV3(https://claude.ai/code/session_01DvvamiacK328idtBYJBxV3).Generated by Claude Code