Skip to content

fix(client): getActiveMember's three anonymous statements say 401 UNAUTHENTICATED on request one, and a pin holds them there - #18810

Merged
os-support-ai merged 2 commits into
mainfrom
claude/issue-18651-getactivemember-retired-anon-statements
Sep 17, 2026
Merged

os-support-ai merged 2 commits into
mainfrom
claude/issue-18651-getactivemember-retired-anon-statements

Conversation

@os-support-ai

Copy link
Copy Markdown
Collaborator

Fixes #18651

Clause-②: no

#17881 (374d9d3afa) landed plugin-auth's refuseAnonymousSession, which converts better-auth's 200 + the literal JSON null on GET /api/v1/auth/get-session into the declared ADR-0112 refusal envelope — HTTP 401, code: UNAUTHENTICATED — before it leaves the process. Three present-tense statements in and around organizations.getActiveMember still described the retired shape, wrong on two axes at once: the CODE (UNAUTHORIZED vs UNAUTHENTICATED) and the REQUEST the refusal arrives on (the second, list-members, vs the first, /get-session itself).

packages/client/src/index.ts changes comments only — verified mechanically: of every line the diff touches in that file, zero are outside a comment.

The three, located by SYMBOL

the statement what it taught what it says now
step 1 of the two-request list the retired VALUE — "the literal null for an anonymous one" the signed-in arm keeps its (measured) tag; the anonymous answer is stated separately from the producer, including that step 2 never reaches the wire
the anonymous bullet of the 2026-09-09 drive's delta list the retired CODE — "still gets 401 UNAUTHORIZED, thrown from the list-members request" RE-ANCHORED, not restamped: the drive's own row stays in the past tense and today's answer is stated from the producer — the disposition #18642 used on this family's sibling statements
the inline comment on the userId read the retired VALUE and the wrong REQUEST an anonymous caller never reaches that line; the | null annotation and the ?? '' fallback are explained as the defensive branch they always were

⭐ The seat's "naming is not teaching" fence SURVIVED contact, and is load-bearing

The repaired prose still contains 200, null and UNAUTHORIZED — it has to, because it names the retired convention as the thing that was CONVERTED and as the drive row that was SUPERSEDED. A "mentions both 200 and null" filter reads the repaired file as defective. So the pin does not count mentions: it matches the three retired SENTENCES and proves it can see them by running the same matchers over a verbatim pre-repair control corpus.

The fence earned its keep on a real near-miss, below.

The complete-set question the card left open — answered with a reading

The card recorded that it had ⛔ not swept for sibling statements. Every anonymous / UNAUTHORIZED / UNAUTHENTICATED hit in packages/client/src was opened, not counted:

⇒ Three is three. Three statements TEACH the retired convention; every other candidate in the package either is already repaired, is true under both wire answers, or names the convention as retired.

The pin — FAILS before, passes after

packages/client/src/organization-get-active-member-anonymous-statements.test.ts. A source-text assertion over the getActiveMember region, located by SYMBOL and never by line number, with its matchers shown FIRING against a verbatim pre-repair control corpus — a matcher that has never fired cannot tell "absent" from "unmatchable", which is how this family's own defect was nearly written off (the filing seat's grep for Anonymous -> null missed the file's Unicode arrow).

Ablation — one-off, fix committed first, mutation proved on disk, restored and proved restored, under a trap … EXIT INT TERM with absolute paths. This pin reads packages/client/src/index.ts as TEXT through readFileSync on ./index.ts; it does not resolve its subject through dist, so no dist preflight applies and the on-disk proof is the grep pair plus the blob hash.

  • Mutation — git checkout HEAD^ -- packages/client/src/index.ts. On-disk proof: corrected-sentence count 1 -> 0, retired-sentence count 0 -> 1, blob 102b25a4d (HEAD) -> 2f920cf4f (mutated). Not a no-op.
  • RED leg — exit 1, Tests 7 failed | 1 passed (8). It fails on all three retired matchers AND on all four "states today's answer" assertions. The one PASS is section 1, which only asserts the region was found — by design, so a red here cannot be mistaken for a broken locator.
  • Restore leg — git checkout HEAD -- packages/client/src/index.ts (point-named HEAD, never a bare git checkout --, which would take the mutation back out of the index). Restored blob 102b25a4d equals the HEAD blob; git diff HEAD on that path is empty.
  • GREEN leg — exit 0, Tests 8 passed (8).

Readings

Local runs, at fdca8ef2be unless noted. Heavy runs went through scripts/pm/os-verify-lock.sh; ⚠️ every wall-clock absolute below is a SHARED-BOX figure.

run verdict
pnpm --filter '@objectstack/client^...' build --concurrency=2 (dependency closure) exit 0
pnpm --filter @objectstack/client build exit 0 (check-dts-emitted: 1/1 declaration file(s) present)
pnpm --filter @objectstack/client typecheck (tsc --noEmit + check:test-typecheck) exit 0 — test layer compiles, 0 files / 0 errors / 0 pinned signatures
pnpm --filter @objectstack/client test (whole package) exit 0 — Test Files 46 passed (46), Tests 545 passed (545). 46 is the whole on-disk population (tests/integration/** is excluded by this package's config; 1 file there); the new pin is one of the 46
ablation RED / GREEN exit 1 (7 failed | 1 passed) / exit 0 (8 passed)
eslint . --no-inline-config repo-wide exit 0 — 6840 files linted (count read from --format json), 0 errors, 0 warnings. Both changed files are in that population. Ran at fdca8ef2be, the final commit; 101s wall
scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack 59 derived families, 59 run, 0 UNRUN — reconciled back through --ran with exit codes recorded

Every exit code above was captured BEFORE any pipe (cmd > file 2>&1; EXIT=$?).

Gate families — the two that are not a plain green

  • pnpm check:dual-build-cjs-loads — exit 3, its own PREREQUISITE-NOT-MET code: "Run pnpm build first. ⛔ This is NOT a pass: nothing was measured." A repo-wide build is CI's run, not this card's. NOT MEASURED, declared. dispatch-gates --ran classified it the same way from the recorded code.
  • pnpm --filter @objectstack/spec run check:skill-examples — exit 1 on the sweep pass, exit 0 on a clean re-run (258 prose examples type-check across 3 surface(s)). Reported as observed rather than as a single number. This gate does read @objectstack/client TSDoc examples; the changed docblocks carry no marked code block, so the population is unchanged.

Tier reading, BOTH directions

The dispatch warned that packages/cli/vitest-tiers.ts treats new ObjectQL( as a KERNEL signal and that a new pin can move a whole file out of its tier. Measured, and it does not reach this card — see the falsification below.

  • Into packages/cli's tiers: its population is derived by testFilesOnDisk(pkgRoot) walking packages/cli. Measured: 262 files, 49 integration / 213 unit. The new pin is absent; no packages/client path is in that population at all. ⭐ Control lit — a real packages/cli file (src/adr-0048-app-split.test.ts) IS in it, so the enumeration was pointed at something.
  • Inside packages/client: there is no tier partition to move within. packages/client/vitest.config.ts has 0 occurrences of vitest-tiers, integrationTestFiles, unitTestFiles or projects; its only split is exclude: ['tests/integration/**'], and the pin is under src/. Separately, the pin contains 0 occurrences of new ObjectQL(. ⭐ Control lit — new ObjectQL( DOES occur in three sibling files in that same directory (auth-get-session-envelope.test.ts among them), so the grep can find it.
  • pnpm check:tier-file-adoption — exit 0.

The changeset question was MEASURED, not inferred

AGENTS.md:1064-1066 — skip-changeset is for a diff that publishes nothing from any released package. @objectstack/client's files[] is ["dist","README.md","CHANGELOG.md"], and getActiveMember is a member of the exported ObjectStackClient, so its TSDoc is emitted into the shipped artifacts. Measured on the built dist at 13e09a5e3c:

artifact corrected sentence retired sentence lit control (getActiveMember)
dist/index.d.ts 1 0 2
dist/index.d.mts 1 0 2
dist/index.js 1 0 3
dist/index.mjs 1 0 3

⇒ this publishes ⇒ patch changeset, skip-changeset refused by measurement.

⚠️ Four premises falsified

  1. The card's line numbers were already stale. :3818 / :3847 / :3880 at filing are :3833 / :3862 / :3895 at origin/main — a uniform +15 shift. Everything here is located by symbol.
  2. The card's ⛔-unverified :4494 is not a fourth defect. Under that same +15 it resolves to auth.me()'s ⚠️ Anonymous REJECTS docblock — the statement PR fix(client): the anonymous /get-session statements say 401 UNAUTHENTICATED, and the test double stops modelling 200 null #18642 already repaired. It is correct today. The card's open question is closed, and nothing is owed there.
  3. *.d.cts is the wrong second artifact for this package. The dispatch's fence said TSDoc ships into dist/*.d.ts and *.d.cts. @objectstack/client emits no .d.cts and no .cjs: its CJS pair is index.js + index.d.ts and its ESM pair is index.mjs + index.d.mts. A *.d.cts probe here would have measured an absent file and returned a zero about nothing. The measurement above names the four artifacts that exist.
  4. The tier warning does not reach this card. vitest-tiers.ts exists only in packages/cli — it is the single vitest-tiers* file in the repo outside that package's own fixtures and partition pin. packages/client has no tier system, so no pin placed there can move a file between tiers. Measured both directions above rather than argued.

Acceptance notes — out of scope, noted, not filed

Neither meets class (a), (b) or (c), so neither is filed.


Generated by Claude Code

…UTHENTICATED on request one, and a pin holds them there

objectstack#17881 (374d9d3) landed plugin-auth's refuseAnonymousSession,
which converts better-auth's 200 + the literal JSON null on
GET /api/v1/auth/get-session into the declared ADR-0112 refusal envelope --
HTTP 401, code UNAUTHENTICATED -- before it leaves the process. Three
present-tense statements in and around organizations.getActiveMember went on
describing the retired shape, wrong twice over: the CODE (UNAUTHORIZED vs
UNAUTHENTICATED) and the REQUEST the refusal arrives on (the second,
list-members, vs the first, get-session itself).

packages/client/src/index.ts changes COMMENTS ONLY -- verified mechanically:
every changed line in that file, comment leader stripped, is a comment line.

The three, located by SYMBOL and not by line number (the filing card's line
numbers were already 15 lines stale by dispatch):

1. Step 1 of the two-request list, which taught the retired VALUE ("the
   literal null for an anonymous one"). The signed-in arm keeps its
   (measured) tag; the anonymous arm is now stated separately and anchored to
   the producer, including that step 2 never reaches the wire.
2. The anonymous bullet of the 2026-09-09 drive's delta list, which taught
   the retired CODE ("still gets 401 UNAUTHORIZED, thrown from the
   list-members request"). RE-ANCHORED rather than restamped, the disposition
   the sibling delivery used on the same family: the drive's own row is kept
   in the past tense, and today's answer is stated from the producer.
3. The inline comment on the userId read, which taught the retired VALUE and
   the wrong request. It now says an anonymous caller never reaches that
   line, and says why the "| null" annotation and the "?? ''" fallback stay.

The pin is a source-text assertion over the getActiveMember region, located
by symbol, with its matchers shown FIRING against a verbatim pre-repair
control corpus -- a matcher that has never fired cannot tell "absent" from
"unmatchable", which is how this family's own defect was nearly written off.

Co-authored-by: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DvvamiacK328idtBYJBxV3
…measured against the published files[]

skip-changeset is refused here by measurement, not by instinct. Built dist at
13e09a5: the corrected sentence is present once in dist/index.d.ts,
dist/index.d.mts, dist/index.js and dist/index.mjs; the retired sentence is
absent from all four; getActiveMember was carried as the lit control and found
in every one of them. The package's files[] is ["dist","README.md",
"CHANGELOG.md"], so that prose ships.

Recorded because the dispatch's fence named the wrong second artifact: this
package emits NO .d.cts and NO .cjs. Its CJS pair is index.js + index.d.ts and
its ESM pair is index.mjs + index.d.mts, so a *.d.cts probe here would have
measured an absent file and reported a zero about nothing.

Clause-② reads `no` through readClause2Line (kind=declared, value=no, arm=null).

Co-authored-by: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DvvamiacK328idtBYJBxV3
@github-actions github-actions Bot added size/m documentation Improvements or additions to documentation tests tooling labels Sep 17, 2026
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

Nothing in this diff resolved to a documentable surface (no symbol, route or SDK anchor derived from 1 changed package(s)), so this run has no opinion about the docs.

What this run could not see
  • 1 name(s) were too generic to anchor anything (single lowercase words)
  • 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 182bbde36a8d9f4dff53c777c1820baa4cbfee27 → packageMentionDocs.

@os-support-ai
os-support-ai marked this pull request as ready for review September 17, 2026 22:54
@os-support-ai
os-support-ai added this pull request to the merge queue Sep 17, 2026
Merged via the queue into main with commit 55523fd Sep 17, 2026
36 checks passed
@os-support-ai
os-support-ai deleted the claude/issue-18651-getactivemember-retired-anon-statements branch September 17, 2026 23:22
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 size/m tests tooling

Projects

None yet

2 participants