Skip to content

fix(changeset): date the pending client entry's closing register — all three 'not addressed here' clauses had been answered - #18765

Merged
os-support-ai merged 1 commit into
mainfrom
claude/issue-18652-changeset-anonymous-null-clause
Sep 18, 2026
Merged

os-support-ai merged 1 commit into
mainfrom
claude/issue-18652-changeset-anonymous-null-clause

Conversation

@os-support-ai

@os-support-ai os-support-ai commented Sep 17, 2026

Copy link
Copy Markdown
Collaborator

Fixes #18652

.changeset/client-get-session-envelope-and-refresh-read.md is pending release
input
, not a note: changeset version copies it verbatim into
packages/client/CHANGELOG.md, which is in @objectstack/client's published
files[] and ships in the npm tarball. AGENTS.md's release-owned table states the
deadline in its own words — "Your PR's input is its changeset, on a hard,
unwatched deadline: the release that consumes it deletes that input and publishes
the sentence."

⚠️ This PR corrects a pending changeset it did not author — read this first

check:empty-changeset's real scan reds on this PR by design and asks for
exactly this paragraph. Its own text names the two classes and their opposite
remedies; this is the DELIBERATE CORRECTION class, and the gate says "this
gate stays red either way, and staying red is what puts the decision in front of a
person instead of routing around it."

  • The note: .changeset/client-get-session-envelope-and-refresh-read.md,
    introduced by 5de93728a (PR fix(client): auth.me / auth.refreshToken deliver the SessionResponse envelope they declare, and refreshToken reads session.token #17237, merged 2026-09-09T21:43:50Z — confirmed
    at the tree, so there is no open author to defer to).
  • What changed under it: its closing paragraph was an undated, present-tense
    register of what that change left undone, and all three of its clauses had since
    been falsified on origin/main by other cards' landings (readings below).
  • ⛔ Not the collision class. No changeset filename was drawn or overwritten
    here; this PR adds none. ⛔ Do not restore the file from the merge base — that
    republishes three false sentences.
  • I have deliberately NOT applied skip-changeset. It would exempt the
    changeset-check job wholesale (lint.yml's own note on the self-test split
    says so), which is the one label that would silence this refusal. Suppressing it
    is the routing-around the gate forbids, so the label decision is left to a human.

Readings — measured on this checkout, ⛔ not relayed from the citing cards

Each clause, the commit that falsified it, and its ancestry on origin/main
(git merge-base --is-ancestor SHA origin/main, where exit 0 is
self-proving
):

clause, as it read measured now falsified by ancestor?
the anonymous null "would need the published return annotation to widen" the producer moved instead; the annotation is untouched 374d9d3afa (#17881), 2026-09-12 exit 0
SessionUser.image "declared z.string().optional()" image: z.string().nullish().describe('Avatar URL')packages/spec/src/api/auth.zod.ts 0e51278f3 (#18501, for #17235), 2026-09-16 exit 0
auth.login / auth.register "normalize into data but set no success" both run normalizeSessionResponse, which returns { success: true, ...body, data } 01388fe81 (#17791, for #17234), 2026-09-12 exit 0

Clause 1, at the definition rather than a call site.
packages/plugins/plugin-auth/src/anonymous-session-refusal.ts:124
refuseAnonymousSession keys on the answer shape and on nothing else — three
early returns: isGetSessionPath(endpointPath), response.status !== 200, and
body.trim() !== ANONYMOUS_BODY where ANONYMOUS_BODY = 'null' (compared as
text, so '0' / '""' / 'false' are left alone). It never reads how the
caller became anonymous, so never signed in, unknown cookie and revoked
session
all convert alike. ANONYMOUS_SESSION_REFUSAL_STATUS = 401, and it is
wired at auth-manager.ts:5679, the one seam every vendor route passes through.
⇒ the anonymous answer is not a null outside the declared type; it is a
rejection, which a Promise of SessionResponse annotation already permits.

What the diff does, and the one design choice in it

Each clause is kept as what it recorded, anchored to when it was written
("sat outside … when this change was written"), with the landing that answered it
beside it. Two reasons that shape rather than a straight fact-swap:

  1. A fact-swap re-arms the same defect — the census's own header names the cause:
    "prose does not re-measure itself". A dated clause cannot be falsified again.
  2. It is the same rule the card's own fence applies one paragraph up: the
    better-auth 1.7.2 transcript is correct because it is dated and
    attributed. ⛔ That transcript is untouched — verified by needle
    (better-auth 1.7.2 and (anonymous) -> 200 null both still present at lines
    10 and 14).

Scope note — clauses 2 and 3 were outside the card's fence

Card #18652 fenced scope to clause 1 and marked clause 2 not re-measured, in
either direction
; clause 3 it did not mention. I measured both and they are false
too, so fixing clause 1 alone was not available: the sentence enumerates
("Two answers stay outside the declared type"), so a clause-1-only repair
would have had to newly author the surviving false clauses into release input —
strictly worse than what was there. Same defect class, same sentence, same file, no
new verification surface. ⇒ folded in, declared here, and reported separately to
the dispatching seat. Strip the last two rows if the seat disagrees; the diff is
one paragraph.

Tests / gates — the pin question, answered with three readings

NOT MEASURED: nothing in this repo can pin changeset prose, and it is not an
untried idea — the repo has ruled against building it. Three measurements, none of
them my own instrument:

  1. Step 49, check:pm-changeset-deadline-census — its header: "REPORT-ONLY:
    it fails nothing and gates nothing."
    It measures path presence, never
    prose; its own blind-spot list says "window-open means the FILE exists, never
    that the card's sentence about it is still correct."
    Live run on this checkout:
    #18652 → verdict "window-open", assertsPending "pending changeset", inListing true, tally {window-open: 11, consumed: 3}, falsifiedAssertions: [].
    The row is identical before and after this diff (I amend, not delete).
    ⇒ reachable, but structurally unable to fail. Not a pin.
  2. Step 122, check:changeset-gate-self-testslint.yml's own note:
    "The SELF-TEST halves only — the real scans stay in pr-automation.yml's
    changeset-check."
    dispatch-gates scores self-test-only families
    "checker-health only … NOT a PR verdict." Green here and green without this
    diff. Not a pin.
  3. Building one is forbidden right now. changeset-deadline-census.mjs:
    "⛔ This file is deliberately NOT the enforcement half … report-only first, the
    census is the deliverable, expansion only when the census reads zero including
    its blind spot."
    The census reads 3 exposed, not zero. Independently,
    .changeset/** is a ruled scan exemption — "a changeset is that record before
    it is compiled into a CHANGELOG"

    (packages/objectql/src/action-owner-key-single-source.test.ts,
    NOT_A_STALE_MENTION). And the file is consumed and deleted at the next
    release, so a pin reading that path becomes a phantom check by construction.

⭐ The one reachable instrument that does respond to this diff is a third the
roster reading did not name — check-empty-changeset.mjs's real scan — and its
polarity is inverted: it is green without this change and red with it, on the
act, not the prose. That is the human-confirmation gate above, not a pin.

Derived sweepnode scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack at aefbf5927, all 18 derived commands plus
check:changeset-fixed (flagged ⛔ roster under .changeset) run locally:

adr0087 --base 0    no-major --base 0   closing-parity 0    comment-mask-corpus 0
adr0087 --self 0    no-major --self 0   closing-parity 0    driver-memory-census 0
empty-changeset --self 0                release-rehearsal --self 0
changeset-gate-self-tests 0             pm-changeset-deadline-census 0
nul-bytes 0   objectui-changeset 0   published-files 0   refd-timer-probe 0
watch-hint-literal 0   changeset-fixed 0
empty-changeset --base 1  <- THE DESIGNED RED, declared above
  • NOT MEASURED: check:rerun-safety-verdict. dispatch-gates flagged a stale
    tree; the roster delta across it is exactly this one new whole-tree family
    (95b21b33b, ci(rerun-safety): measure the rerun property even when pass 1 is red #18746). It does not exist in this checkout, so pnpm exited 254
    (script-not-found) — ⛔ that is not a red gate and not a pass. It is self-test-only
    and reads only its own fixtures, so it cannot judge this diff either way.
  • No control characters: grep -naP '[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]' over the
    changed file exits 1 (clean), beyond check:nul-bytes.
  • No pnpm lint narrowing claimed, and no build/test: this diff compiles
    nothing and is read by no test. turbo's graph is not consulted because the path
    is in no package.

Does this diff owe a changeset of its own? — measured, ⛔ not assumed

No, and adding one would be a defect. @objectstack/client's published
files[] is ["dist","README.md","CHANGELOG.md"]; .changeset/** is not in it, and
this diff moves no dist byte. The published text that does move is this very
entry — so the amended changeset is the release input. A second changeset would
emit a second CHANGELOG bullet correcting the first, which is the shape AGENTS.md
forbids by name: "Factual error in a released entry → amend that entry in a
dedicated docs-only PR, ⛔ never an erratum in a later entry."
Gate readings
agree: check-changeset-no-major --base 0, check-adr-0087-registration --base 0,
check-empty-changeset --base prints "✓ No empty-frontmatter changeset introduced
by this diff (1 declaring changeset(s) added)"
. ⛔ major does not exist in this
launch window and nothing here is breaking.

Clause-②: no

No key moves, no accept set widens or narrows, no export changes, no error code or
ERROR_CODE_LEDGER entry moves, and no packages/spec path is touched. The diff is
prose inside one pending changeset; zero lines of shipped code change.

⛔ Reported, not touched: the open Version Packages PR

#17076 chore: version packages is OPEN and already renders this entry — at its
head 1c0ce1713 the changeset is absent (contents API 404, against a 200
positive control on .changeset/config.json) and the paragraph is compiled into
packages/client/CHANGELOG.md:506. ⛔ I did not touch that PR, ran no release, and
merged nothing.

But an open Version Packages PR does not mean the window has closed, and the
dispatch order's reading that it does is falsified by the repo's own workflow.

That branch is a derived artefact, regenerated from scratch:

  • release.yml's version-pr job is if: github.event_name == 'schedule' || (… workflow_dispatch && inputs.refresh_version_pr) — ⛔ not push; the file's
    own note: "this job regenerates the PR from scratch, so the newest run's result
    is the one that was wanted anyway"
    , and "renders changesets that are already
    committed on main, so lateness costs nothing."
  • The mechanism, quoted in that file from changesets/action v1: git reset --hard SHApnpm run versiongit push … --force.
  • Corroborated at the object: chore: version packages #17076 was created 2026-09-09 and carries one
    commit, 1c0ce1713, authored by github-actions[bot] at 2026-09-17T18:14:46Z,
    whose parent e77a23f02 is an ancestor of origin/main (exit 0) and only 7
    commits behind it. Created eight days before the commit it holds ⇒ force-rebuilt.

⇒ The window closes when a release consumes the changeset (AGENTS.md's wording),
i.e. when #17076 is merged and published — a human-only act (release.yml:
"TWO LANES, ONE INVARIANT: ONLY A HUMAN PUBLISHES."). Until then this entry is
still amendable at one paragraph, and the next 6-hourly tick re-renders #17076 from
the corrected text with no action on that PR. The deadline is real and this PR is
inside it.


🤖 Generated with Claude Code

https://claude.ai/code/session_01DvvamiacK328idtBYJBxV3


Generated by Claude Code

Landing note added by the dispatching seat (#6024) — clearing a red that was the seat's, not this PR's

The earlier red on The card this PR closes must claim this branch was caused by the claim comment's shape, not by anything in this diff: the seat's claim on #18652 opened **CLAIM · …**, and scripts/check-closing-target-claim.mjs selects a comment by a line beginning Claim: plus a separate Branch: directive line. Fixed on the card (5720097499), measured before and after — check-clause2-carriers --pair 18765 went from EXIT=4 / claim.selected: none to EXIT=0 / 1 comment(s) in the pool, both carriers reading no.

That guard is body- and comment-scoped and re-fires only on a pull_request or merge_group event, so this edit is the event that re-judges it — ⛔ not an empty commit, which the deliverer correctly refused, and ⛔ not a push, since the seat has ruled that all three clauses stay and no further code change is owed.

⚠️ The two remaining reds are by design and are not touched by this edit: check-empty-changeset asks in its own words for a human to confirm the DELIBERATE CORRECTION class, and pr-automation.yml's changeset-check counts only added changesets (this PR amends one and adds zero). The ruling request is on #18652 (5720153848). ⛔ skip-changeset is deliberately NOT applied — it exempts that job wholesale and would silence the refusal that exists to put this decision in front of a person.


Generated by Claude Code

… not present-tense — all three "not addressed here" clauses had been answered

`.changeset/client-get-session-envelope-and-refresh-read.md` is release input:
`changeset version` copies it verbatim into `packages/client/CHANGELOG.md` and
it ships in the npm tarball. Its closing paragraph was an undated present-tense
register of what the change left undone, and every one of its three clauses had
since been falsified on `origin/main`:

- the anonymous `/get-session` `null` "would need the published return
  annotation to widen" — `374d9d3afa` moved the PRODUCER instead:
  `refuseAnonymousSession` converts `200` + literal `null` into the ADR-0112
  `401 UNAUTHENTICATED` refusal, so an anonymous `auth.me()` rejects and the
  annotation needs no widening at all;
- `SessionUser.image` "declared `z.string().optional()`" — `0e51278f3`
  declares it `z.string().nullish()`;
- `auth.login` / `auth.register` "normalize into `data` but set no `success`"
  — `01388fe81` put them on `normalizeSessionResponse`, which returns
  `{ success: true, ...body, data }`.

Each clause is kept as what it recorded, anchored to when it was written, with
the landing that answered it beside it. The dated better-auth 1.7.2 transcript
above is history and is untouched.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DvvamiacK328idtBYJBxV3

Copy link
Copy Markdown
Collaborator Author

Both red checks on this PR are BY DESIGN, and a maintainer ruling is owed. · domain:cli execution seat #6024 · 2026-09-17T19:41Z

Naming them so no reviewer has to re-derive why a red PR is sitting here, and so it is on the record that this seat is ⛔ not going to clear them by routing around them.

red check why it is red
check-empty-changeset (via changeset-check) The gate reds on purpose and asks, in its own words, for a person: "Correcting a pending release note is a decision about a release rather than a refactor — say so on the PR, naming the note and what changed under it, and get it confirmed. That is the existing human path; this gate stays red either way."
Check Changeset pr-automation.yml's changeset-check counts only ADDED changesets (git diff --diff-filter=A). This PR amends one and adds zero, so it is red without the label.

⛔ What this seat will not do

⛔ Not applying skip-changeset. It is the only label that would make CI green, and that is precisely the objection: lint.yml records that a PR carrying it is exempted from the changeset-check job WHOLESALE (job-level if: plus two per-step label reads). Applying it would silence the deliberate refusal that exists to put this decision in front of a person — the routing-around the gate forbids by name. The deliverer refused to apply it; this seat endorses that refusal.

⛔ Not merging a red PR, and ⛔ not merging outside the queue. And ⛔ not supplying, on a gate's behalf, a confirmation the gate asks a person for.

⛔ Neither red is a re-run candidate: "flake" is not in question — both are deterministic verdicts about this diff's shape, and check-empty-changeset is green without the change and EXIT=1 with it. An instrument with that polarity is reporting the act, ⛔ not failing.

What is owed, and where it is recorded

The ruling request is on the card: #18652, comment 5720153848, with the three readings that decide it and this seat's recommendation on each. Card state moved pm:dispatchedneeds-user-decision.

Two questions are the maintainer's: confirm the DELIBERATE CORRECTION class and land it by the gate's own prescribed path, or reject the amendment; whether skip-changeset is applied at all — recommendation: leave it off, and if applied, as a maintainer act with the reason written here.

One question was this seat's and is answered on the card: all three clauses stay in this diff. The paragraph enumerates ("Two answers stay outside the declared type"), so a clause-1-only repair would have to rewrite that sentence and thereby newly author two measured-false clauses into release input. Both survivors were verified on origin/main by this seat, independently of the report: auth.zod.ts:47 is z.string().nullish() inside SessionUserSchema, and normalizeSessionResponse is run by login and register.

⚠️ Separately, the earlier red on The card this PR closes must claim this branch was this seat's fault, not this PR's: the claim comment on #18652 used a format the gate's grammar does not select (it needs a line beginning Claim: plus a separate Branch: directive line). Fixed on the card, measured before and after — --pair 18765 went from EXIT=4 / claim.selected: none to EXIT=0 / 1 comment(s) in the pool. ⚠️ That guard fires only on pull_request and merge_group events, so its red on head aefbf5927 clears on the next PR event, ⛔ not from the card comment.


Generated by Claude Code

hotlong commented Sep 18, 2026

Copy link
Copy Markdown
Contributor

Maintainer confirmation of record — director seat, decision batch #156 item 1 on #18652 · maintainer 「同意」 to A · 2026-09-18T05:37Z

check-empty-changeset.mjs asks, in its own words, for a human to say on the PR that correcting a pending release note is a release decision, naming the note and what changed under it. Recorded here on the maintainer's word:

  • Note: .changeset/client-get-session-envelope-and-refresh-read.md (pending, unreleased).
  • What changes under it: the closing sentence's three clauses — the anonymous /get-session null (now a 401 since fix(plugin-auth)!: an anonymous get-session is refused with the declared 401 envelope, not answered 200 null #17881), SessionUser.image (now nullish, 0e51278f3), and normalizeSessionResponse on login / register (01388fe81) — are replaced by what the tree measures; the dated better-auth transcript above them stays as history. No other release input moves.
  • skip-changeset is applied on the maintainer's authority, because the corrected note is itself the release input and this PR adds none; the label's wider exemption is accepted for this docs-only change and is ⛔ not a precedent for a seat to apply it unasked.

The domain:cli seat drives the PR in from here (ready → queue → two-reading landing).


Generated by Claude Code

@hotlong hotlong added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Sep 18, 2026 — with Claude
@os-support-ai
os-support-ai marked this pull request as ready for review September 18, 2026 05:41
@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 d5ccfb4 Sep 18, 2026
36 of 39 checks passed
@os-support-ai
os-support-ai deleted the claude/issue-18652-changeset-anonymous-null-clause branch September 18, 2026 06:04
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/s skip-changeset PR has no user-facing published change; bypasses the changeset gate tooling

Projects

None yet

3 participants