Skip to content

fix(client): normalizeSessionResponse's JSDoc records the data.user.image gap as closed, not tracked - #18855

Merged
os-support-ai merged 3 commits into
mainfrom
claude/issue-18510-normalize-session-response-stale-gap
Sep 18, 2026
Merged

os-support-ai merged 3 commits into
mainfrom
claude/issue-18510-normalize-session-response-stale-gap

Conversation

@os-support-ai

@os-support-ai os-support-ai commented Sep 18, 2026 •

Copy link
Copy Markdown
Collaborator

Fixes #18510

Clause-②: no

The JSDoc block above normalizeSessionResponse says what the lift compensates for, so it names the cards that opened and closed each compensation. One clause was still in the present tense:

… with one gap that is NOT this: `data.user.image` served `null` against a declared
`string | undefined` (#17235, tracked separately).

⚠️ Quoted in a fence, not a blockquote, deliberately: this PR must not become a delivering
reference for the card that sentence names.

Both halves went false when PR #18501 widened SessionUserSchema.image to z.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 in auth-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-1517 had already drifted to :1520-1531 by 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:

"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/client ships dist, README.md, CHANGELOG.md. ⭐ dist is six files — index.js, index.mjs, index.d.ts, index.d.mts and a .map beside each bundle. This package emits no *.cjs and no *.d.cts, so a *.d.cts probe 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:

probe index.js index.mjs index.d.ts index.d.mts index.js.map index.mjs.map
NEG no longer residue (block-unique) 0 0 0 0 0 0
NEG data.user.image 0 0 0 0 0 0
NEG tracked separately 0 0 0 0 0 0
POS {@link normalizeSessionResponse} 3 3 3 3 0 0
POS set-auth-token 4 4 3 3 0 0
  • The block's own text ships nowhere — the negative probes are zero across all six while the positive controls land, so this is a discrimination, not a dead probe.
  • But comment text from this file DOES reach the published types. {@link normalizeSessionResponse} appears 3× in each .d.ts, carried there by the JSDoc of the exported auth.login / auth.register / auth.me that 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.
  • And the published bytes DO move. index.js, index.mjs, index.d.ts and index.d.mts are byte-identical across the change (sha256, with the HEAD build re-run as a reproducibility control). Both .map files differ: neither carries sourcesContent (pnpm check:sourcemap-no-sources-content is why), so no comment text ships inside them either — the position table shifts because the rewritten comment is two lines longer.

⇒ skip-changeset would have been a false declaration. This carries a patch changeset 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:

  • red before — on the unfixed source, exactly ② failed (1 failed | 4 passed), reporting #17235.
  • green after — 5 passed, inside a suite of 47 passed (47) files / 550 passed tests.
  • locator control ① — the extractor must find this block (asserts its anchors #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.
  • negative control ③ — the pre-fix sentence, copied verbatim from the base, must still be reported; and the past-tense form must not be.

⚠️ ③ earned its keep on its first run: the past-tense sentence originally drafted for this fix opened "the one gap that was still open when this was written", and still open is 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/client tiers by path (tests/integration/** is excluded from the unit config and has its own config), so a new src/*.test.ts lands in the unit tier; the vitest-tiers.ts content-based mechanism is packages/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 --noEmit clean; check:test-typecheck reports the test layer compiles under tsconfig.test.json, 0 files / 0 errors, which is what covers the new pin file.
  • node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack derived 59 gate commands from the real change set (re-derived after merging origin/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, at 52b7812953. ⚠️ dispatch-gates.mjs does not name this family; it was run anyway.
  • ⛔ NOT MEASURED: pnpm check:dual-build-cjs-loads. It refuses with PREREQUISITE NOT MET … ⛔ This is NOT a pass: nothing was measured (exit 3) because 34 packages have no dist — its prerequisite is a repo-wide pnpm 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.

  1. The card's own reach measurement is wrong, in attribution and in count. It records the literal data.user.image as appearing in "3 past-tense comments inside packages/spec's own test files plus this one line in packages/client". At origin/main it appears in 2 past-tense comments inside packages/client's own test file (auth-login-register-envelope.test.ts:33 and :310), zero in any packages/spec test 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.
  2. A comment-only diff moves published bytes whenever the package emits source maps. The shortcut "it is only a comment, so nothing publishes" is measurably false for any package shipping a dist with .map files: 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 to packages/client/CHANGELOG.md rather than staying in a PR nobody greps.
  3. Container hazard, for sibling agents on this box, not a repo defect. pnpm check:type-check-debt runs a turbo build; when that build is SIGKILLed under memory pressure mid-DTS, it leaves packages/spec/dist with zero .d.ts files, after which unrelated packages' typecheck fails with a pile of TS7016 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, the packages/spec/dist row). ⚠️ Counter-intuitive recovery, measured here: raising --max-old-space-size made 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 domain:cli execution seat in session session_01DvvamiacK328idtBYJBxV3 (https://claude.ai/code/session_01DvvamiacK328idtBYJBxV3). ⚠️ 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.


Generated by Claude Code

…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>
@github-actions github-actions Bot added documentation Improvements or additions to documentation tests tooling labels Sep 18, 2026
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

⚠️ 1 changed file(s) yielded no anchor (packages/client/src/index.ts), so the pages documenting them are NOT COVERED by this run — this is not a clean bill of health for those files. Nothing else in this diff resolved to a documentable surface (no symbol, route or SDK anchor derived from 1 changed package(s)).

What this run could not see
  • 1 changed file(s) yielded no anchor (packages/client/src/index.ts) — pages documenting those are invisible to this run
  • a page that states a rule by its inputs shares no identifier with the emitter that implements the rule, so an emitter-only diff cannot list it — not on this run and not on any run. Measured on fix(driver-sql): emit varchar(maxLength) for a text field a declared index keys on #11430: content/docs/protocol/objectql/types.mdx documents the text-family column mapping by the ObjectQL type names it maps FROM (text / textarea / html) while the diff changed createColumn; it went unlisted, and it was the page that diff falsified, in four places. No shared token exists to detect this on, so a rule your change carries has to be re-read by hand in the pages that restate it.

Coarse fallback — 15 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): node scripts/docs-audit/affected-docs.mjs --json c018f41c3e9fb0ed4a3e31994fd71dbd7dfc8f5c → packageMentionDocs.

@os-support-ai
os-support-ai marked this pull request as ready for review September 18, 2026 00:58
@os-support-ai
os-support-ai added this pull request to the merge queue Sep 18, 2026
Merged via the queue into main with commit be7aeb8 Sep 18, 2026
54 checks passed
@os-support-ai
os-support-ai deleted the claude/issue-18510-normalize-session-response-stale-gap branch September 18, 2026 01:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation domain:cli size/m tests tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

client: normalizeSessionResponse's JSDoc will state a false present-tense gap the moment PR #18501 lands

2 participants