fix(devx): re-pin the publish smoke to the declared first-run contract - #14255

Merged
baozhoutao merged 1 commit into
mainfrom
claude/issue-14000-smoke-declared-contract
Sep 1, 2026
Merged

fix(devx): re-pin the publish smoke to the declared first-run contract#14255
baozhoutao merged 1 commit into
mainfrom
claude/issue-14000-smoke-declared-contract

Conversation

@baozhoutao

Copy link
Copy Markdown
Contributor

Fixes#14000

Re-pins the packed-tarball smoke to the first-run contract the platform actually declares, per the maintainer-approved ruling (option A, director batch #23, comment 5494456135). No auth or audience runtime code is touched — option B is excluded by the ruling, and the product behaviour under test is correct as it stands.

What was wrong

scripts/publish-smoke.sh asserted that the first POST /auth/sign-up/email after objectstack dev --fresh returns 200. That expectation was authored before #11739/#11767 made invite_only the default audience posture, and it is not the first account that reaches the probe:

objectstack dev --fresh seeds a dev admin in-process at boot (maybeSeedDevAdmin, plugin-auth) through the real signUpEmail pipeline, sharing the isHumanUserRow predicate with the audience gate's bootstrap bypass. That creation is the zero-user one the bypass admits. The smoke's own sign-up is therefore the second self-serve account, which invite_only refuses with SELF_REGISTRATION_CLOSED + 403 — correctly. The release candidate had never once passed this gate with the posture default aboard (~7 days red, measured in the issue thread).

The probe sequence

#probebeforeafter
1GET /auth/get-session (anonymous)200200
2GET /auth/config (anonymous)200; in pack mode features.audiencePosture must be invite_only
3POST /auth/sign-in/email (seeded dev admin)ran later, only to drive CRUD200 — the packed install's proof the bootstrap bypass fired
4POST /auth/sign-up/email (uninvited second account)expected 200 — the stale half403 + envelope code == SELF_REGISTRATION_CLOSED
5POST /auth/organization/invite-member (as the admin)200, status == "pending" — the operator path
6POST /auth/sign-up/email (the invitee)200 — admitted by the invitation carve-out
7POST /auth/sign-in/email (probe user)200200
8GET /auth/get-session (signed in)200, is the probe userunchanged
9–12REST CRUD as the admin201/200/200/200unchanged; reuses the session from probe 3 instead of signing in a second time
13error/fatal log scancleanunchanged

Ruling points 1, 2 and 3 are probes 3, 4 and 5–6. Behaviour is pinned throughout — an HTTP status plus a code this repo owns and publishes. No vendor-internal symbol is asserted anywhere, which is the wiring shape that made #11767's breakage possible.

Two decisions worth reviewing

The operator path is the invitation carve-out, not admin/create-user. The ruling names either. POST /auth/admin/create-user needs better-auth's admin plugin, and a scaffolded project does not get it by default — admin: pluginConfig.admin ?? scimEffective (auth-manager.ts), and the blank template declares no auth config at all — so that route would answer 501 NOT_IMPLEMENTED on the very artifact under test. The organization plugin is on by default (organization: pluginConfig.organization ?? true), and ADR-0081's ensureDefaultOrganization exists precisely so invite-member has an active org on a single-org install. So the carve-out is the operator path a fresh install actually ships.

The posture is read from the artifact, not hard-coded — because the two smoke modes install different products.pack smokes this repo's tree; registry smokes the last published release, whose contract this tree does not define. @objectstack/plugin-auth latest is 17.2.0, published 2026-08-23; #11767 landed 2026-08-25. Hard-coding the RC's posture would have turned the weekly registry canary red — and auto-filed a "fresh install is broken" issue — over a release behaving exactly as its own contract declares.

So the script reads features.audiencePosture off the public /auth/config and asserts that enforcement matches what the artifact advertises. In pack mode the advertised posture must additionally beinvite_only, which is where the ruling's closed-by-default pin bites: widening the default reds the RC before any behaviour probe can report the widening as a cheerful 200. The legacy open-registration branch is reachable only by registry mode against a pre-#11739 release and retires itself the first time a published release carries the posture.

Ruling point 4 — option C's direct bootstrap probe: declined, and why

Folding in a --no-seed-admin variant was conditioned on being cheap. It is not, and it is also redundant:

  • Not cheap.--no-seed-admin is a real flag, but exercising it means a secondobjectstack dev --fresh boot — the slowest step in the job — plus restructuring machinery that is single-boot throughout: one SERVER_PID, one DEV_TMPDIR (whose per-run uniqueness is what lets the script prove the server it probes is its own), one SERVER_LOG that the closing error-scan reads, and a cleanup trap keyed on all three.
  • Redundant. Probe 3 already proves the bypass fired. The seeded admin's account can only exist because the audience gate admitted its zero-user signUpEmail; if the bypass stops firing (the feat(spec,auth)!: one declared audience posture for self-registration — invite_only|email_domain|open, default invite_only #11767 defect), the seed never lands and probe 3 fails — naming the real defect directly rather than leaving it to be inferred from a sign-up refusal downstream. C's marginal information is only that the bypass admits a self-serve first account rather than the seed's first account.

Landing window — when this fix reaches the tested tree

⚠️ This lands on main, but pack-smoke tests the release branch. publish-smoke.yml's pack-smoke job runs on workflow_run after each Release run and checks out changeset-release/main when an open release PR exists, so merging this does not turn the RC green by itself. The fix reaches the tested tree at the next release-branch re-cut (the next Release run that re-cuts changeset-release/main from a main containing this commit).

⛔ Judge the result by the commit status on the release-branch head, never by the check-run attached to a main SHA — the card's own trap, measured biting three seats, and it will bite this PR's reviewers the same way if they read it the other way.

Verification

See the report comment on #14000 for the full measurement record, including what was measured locally and what is left to CI.

skip-changeset: this PR publishes nothing from any package — the diff is one CI driver script.


Generated by Claude Code

The packed-tarball smoke asserted that the first POST /auth/sign-up/email
after `objectstack dev --fresh` returns 200 — an expectation authored
before #11739/#11767 made `invite_only` the default audience posture.
It is not the first account that reaches that probe. `--fresh` seeds a dev
admin in-process at boot through the real signUpEmail pipeline, and THAT
creation is the zero-user one the bootstrap bypass admits. The smoke's own
sign-up is the SECOND self-serve account, which invite_only refuses with
SELF_REGISTRATION_CLOSED + 403 — correctly. The release candidate had
therefore never once passed this gate with the posture default aboard.
Per the maintainer-approved ruling (option A, director batch #23):
- assert the seeded admin can SIGN IN, which is the packed install's
proof that the bootstrap bypass really fired;
- assert the uninvited second self-serve sign-up is REFUSED, pinning
both the 403 and the envelope code so an accidental widening of the
unauthenticated surface reds the RC instead of shipping;
- obtain the non-admin probe user through the operator path (the
invitation carve-out) before the existing session/CRUD probes.
Behaviour only — no vendor-internal symbol is pinned, and no auth or
audience runtime code is touched.
The posture is READ from the artifact's own public /auth/config rather
than hard-coded, because the two smoke modes install different products:
`registry` smokes the last PUBLISHED release, and plugin-auth 17.2.0
(2026-08-23) predates #11767 (2026-08-25). In `pack` mode the advertised
posture must BE invite_only; in both modes enforcement must match what
the artifact advertises.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WLJQhde67SeTccsmnBVarV
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/mskip-changesetPR has no user-facing published change; bypasses the changeset gate

Projects

None yet

2 participants

@baozhoutao@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

fix(devx): re-pin the publish smoke to the declared first-run contract - #14255

Merged
baozhoutao merged 1 commit into
mainfrom
claude/issue-14000-smoke-declared-contract
Sep 1, 2026
Merged

fix(devx): re-pin the publish smoke to the declared first-run contract#14255
baozhoutao merged 1 commit into
mainfrom
claude/issue-14000-smoke-declared-contract

Conversation

@baozhoutao

Copy link
Copy Markdown
Contributor

Fixes#14000

Re-pins the packed-tarball smoke to the first-run contract the platform actually declares, per the maintainer-approved ruling (option A, director batch #23, comment 5494456135). No auth or audience runtime code is touched — option B is excluded by the ruling, and the product behaviour under test is correct as it stands.

What was wrong

scripts/publish-smoke.sh asserted that the first POST /auth/sign-up/email after objectstack dev --fresh returns 200. That expectation was authored before #11739/#11767 made invite_only the default audience posture, and it is not the first account that reaches the probe:

objectstack dev --fresh seeds a dev admin in-process at boot (maybeSeedDevAdmin, plugin-auth) through the real signUpEmail pipeline, sharing the isHumanUserRow predicate with the audience gate's bootstrap bypass. That creation is the zero-user one the bypass admits. The smoke's own sign-up is therefore the second self-serve account, which invite_only refuses with SELF_REGISTRATION_CLOSED + 403 — correctly. The release candidate had never once passed this gate with the posture default aboard (~7 days red, measured in the issue thread).

The probe sequence

#probebeforeafter
1GET /auth/get-session (anonymous)200200
2GET /auth/config (anonymous)200; in pack mode features.audiencePosture must be invite_only
3POST /auth/sign-in/email (seeded dev admin)ran later, only to drive CRUD200 — the packed install's proof the bootstrap bypass fired
4POST /auth/sign-up/email (uninvited second account)expected 200 — the stale half403 + envelope code == SELF_REGISTRATION_CLOSED
5POST /auth/organization/invite-member (as the admin)200, status == "pending" — the operator path
6POST /auth/sign-up/email (the invitee)200 — admitted by the invitation carve-out
7POST /auth/sign-in/email (probe user)200200
8GET /auth/get-session (signed in)200, is the probe userunchanged
9–12REST CRUD as the admin201/200/200/200unchanged; reuses the session from probe 3 instead of signing in a second time
13error/fatal log scancleanunchanged

Ruling points 1, 2 and 3 are probes 3, 4 and 5–6. Behaviour is pinned throughout — an HTTP status plus a code this repo owns and publishes. No vendor-internal symbol is asserted anywhere, which is the wiring shape that made #11767's breakage possible.

Two decisions worth reviewing

The operator path is the invitation carve-out, not admin/create-user. The ruling names either. POST /auth/admin/create-user needs better-auth's admin plugin, and a scaffolded project does not get it by default — admin: pluginConfig.admin ?? scimEffective (auth-manager.ts), and the blank template declares no auth config at all — so that route would answer 501 NOT_IMPLEMENTED on the very artifact under test. The organization plugin is on by default (organization: pluginConfig.organization ?? true), and ADR-0081's ensureDefaultOrganization exists precisely so invite-member has an active org on a single-org install. So the carve-out is the operator path a fresh install actually ships.

The posture is read from the artifact, not hard-coded — because the two smoke modes install different products.pack smokes this repo's tree; registry smokes the last published release, whose contract this tree does not define. @objectstack/plugin-auth latest is 17.2.0, published 2026-08-23; #11767 landed 2026-08-25. Hard-coding the RC's posture would have turned the weekly registry canary red — and auto-filed a "fresh install is broken" issue — over a release behaving exactly as its own contract declares.

So the script reads features.audiencePosture off the public /auth/config and asserts that enforcement matches what the artifact advertises. In pack mode the advertised posture must additionally beinvite_only, which is where the ruling's closed-by-default pin bites: widening the default reds the RC before any behaviour probe can report the widening as a cheerful 200. The legacy open-registration branch is reachable only by registry mode against a pre-#11739 release and retires itself the first time a published release carries the posture.

Ruling point 4 — option C's direct bootstrap probe: declined, and why

Folding in a --no-seed-admin variant was conditioned on being cheap. It is not, and it is also redundant:

  • Not cheap.--no-seed-admin is a real flag, but exercising it means a secondobjectstack dev --fresh boot — the slowest step in the job — plus restructuring machinery that is single-boot throughout: one SERVER_PID, one DEV_TMPDIR (whose per-run uniqueness is what lets the script prove the server it probes is its own), one SERVER_LOG that the closing error-scan reads, and a cleanup trap keyed on all three.
  • Redundant. Probe 3 already proves the bypass fired. The seeded admin's account can only exist because the audience gate admitted its zero-user signUpEmail; if the bypass stops firing (the feat(spec,auth)!: one declared audience posture for self-registration — invite_only|email_domain|open, default invite_only #11767 defect), the seed never lands and probe 3 fails — naming the real defect directly rather than leaving it to be inferred from a sign-up refusal downstream. C's marginal information is only that the bypass admits a self-serve first account rather than the seed's first account.

Landing window — when this fix reaches the tested tree

⚠️ This lands on main, but pack-smoke tests the release branch. publish-smoke.yml's pack-smoke job runs on workflow_run after each Release run and checks out changeset-release/main when an open release PR exists, so merging this does not turn the RC green by itself. The fix reaches the tested tree at the next release-branch re-cut (the next Release run that re-cuts changeset-release/main from a main containing this commit).

⛔ Judge the result by the commit status on the release-branch head, never by the check-run attached to a main SHA — the card's own trap, measured biting three seats, and it will bite this PR's reviewers the same way if they read it the other way.

Verification

See the report comment on #14000 for the full measurement record, including what was measured locally and what is left to CI.

skip-changeset: this PR publishes nothing from any package — the diff is one CI driver script.


Generated by Claude Code

The packed-tarball smoke asserted that the first POST /auth/sign-up/email
after `objectstack dev --fresh` returns 200 — an expectation authored
before #11739/#11767 made `invite_only` the default audience posture.
It is not the first account that reaches that probe. `--fresh` seeds a dev
admin in-process at boot through the real signUpEmail pipeline, and THAT
creation is the zero-user one the bootstrap bypass admits. The smoke's own
sign-up is the SECOND self-serve account, which invite_only refuses with
SELF_REGISTRATION_CLOSED + 403 — correctly. The release candidate had
therefore never once passed this gate with the posture default aboard.
Per the maintainer-approved ruling (option A, director batch #23):
- assert the seeded admin can SIGN IN, which is the packed install's
proof that the bootstrap bypass really fired;
- assert the uninvited second self-serve sign-up is REFUSED, pinning
both the 403 and the envelope code so an accidental widening of the
unauthenticated surface reds the RC instead of shipping;
- obtain the non-admin probe user through the operator path (the
invitation carve-out) before the existing session/CRUD probes.
Behaviour only — no vendor-internal symbol is pinned, and no auth or
audience runtime code is touched.
The posture is READ from the artifact's own public /auth/config rather
than hard-coded, because the two smoke modes install different products:
`registry` smokes the last PUBLISHED release, and plugin-auth 17.2.0
(2026-08-23) predates #11767 (2026-08-25). In `pack` mode the advertised
posture must BE invite_only; in both modes enforcement must match what
the artifact advertises.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WLJQhde67SeTccsmnBVarV
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/mskip-changesetPR has no user-facing published change; bypasses the changeset gate

Projects

None yet

2 participants

@baozhoutao@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(devx): re-pin the publish smoke to the declared first-run contract - #14255

Merged
baozhoutao merged 1 commit into
mainfrom
claude/issue-14000-smoke-declared-contract
Sep 1, 2026
Merged

fix(devx): re-pin the publish smoke to the declared first-run contract#14255
baozhoutao merged 1 commit into
mainfrom
claude/issue-14000-smoke-declared-contract

Conversation

@baozhoutao

Copy link
Copy Markdown
Contributor

Fixes#14000

Re-pins the packed-tarball smoke to the first-run contract the platform actually declares, per the maintainer-approved ruling (option A, director batch #23, comment 5494456135). No auth or audience runtime code is touched — option B is excluded by the ruling, and the product behaviour under test is correct as it stands.

What was wrong

scripts/publish-smoke.sh asserted that the first POST /auth/sign-up/email after objectstack dev --fresh returns 200. That expectation was authored before #11739/#11767 made invite_only the default audience posture, and it is not the first account that reaches the probe:

objectstack dev --fresh seeds a dev admin in-process at boot (maybeSeedDevAdmin, plugin-auth) through the real signUpEmail pipeline, sharing the isHumanUserRow predicate with the audience gate's bootstrap bypass. That creation is the zero-user one the bypass admits. The smoke's own sign-up is therefore the second self-serve account, which invite_only refuses with SELF_REGISTRATION_CLOSED + 403 — correctly. The release candidate had never once passed this gate with the posture default aboard (~7 days red, measured in the issue thread).

The probe sequence

#probebeforeafter
1GET /auth/get-session (anonymous)200200
2GET /auth/config (anonymous)200; in pack mode features.audiencePosture must be invite_only
3POST /auth/sign-in/email (seeded dev admin)ran later, only to drive CRUD200 — the packed install's proof the bootstrap bypass fired
4POST /auth/sign-up/email (uninvited second account)expected 200 — the stale half403 + envelope code == SELF_REGISTRATION_CLOSED
5POST /auth/organization/invite-member (as the admin)200, status == "pending" — the operator path
6POST /auth/sign-up/email (the invitee)200 — admitted by the invitation carve-out
7POST /auth/sign-in/email (probe user)200200
8GET /auth/get-session (signed in)200, is the probe userunchanged
9–12REST CRUD as the admin201/200/200/200unchanged; reuses the session from probe 3 instead of signing in a second time
13error/fatal log scancleanunchanged

Ruling points 1, 2 and 3 are probes 3, 4 and 5–6. Behaviour is pinned throughout — an HTTP status plus a code this repo owns and publishes. No vendor-internal symbol is asserted anywhere, which is the wiring shape that made #11767's breakage possible.

Two decisions worth reviewing

The operator path is the invitation carve-out, not admin/create-user. The ruling names either. POST /auth/admin/create-user needs better-auth's admin plugin, and a scaffolded project does not get it by default — admin: pluginConfig.admin ?? scimEffective (auth-manager.ts), and the blank template declares no auth config at all — so that route would answer 501 NOT_IMPLEMENTED on the very artifact under test. The organization plugin is on by default (organization: pluginConfig.organization ?? true), and ADR-0081's ensureDefaultOrganization exists precisely so invite-member has an active org on a single-org install. So the carve-out is the operator path a fresh install actually ships.

The posture is read from the artifact, not hard-coded — because the two smoke modes install different products.pack smokes this repo's tree; registry smokes the last published release, whose contract this tree does not define. @objectstack/plugin-auth latest is 17.2.0, published 2026-08-23; #11767 landed 2026-08-25. Hard-coding the RC's posture would have turned the weekly registry canary red — and auto-filed a "fresh install is broken" issue — over a release behaving exactly as its own contract declares.

So the script reads features.audiencePosture off the public /auth/config and asserts that enforcement matches what the artifact advertises. In pack mode the advertised posture must additionally beinvite_only, which is where the ruling's closed-by-default pin bites: widening the default reds the RC before any behaviour probe can report the widening as a cheerful 200. The legacy open-registration branch is reachable only by registry mode against a pre-#11739 release and retires itself the first time a published release carries the posture.

Ruling point 4 — option C's direct bootstrap probe: declined, and why

Folding in a --no-seed-admin variant was conditioned on being cheap. It is not, and it is also redundant:

  • Not cheap.--no-seed-admin is a real flag, but exercising it means a secondobjectstack dev --fresh boot — the slowest step in the job — plus restructuring machinery that is single-boot throughout: one SERVER_PID, one DEV_TMPDIR (whose per-run uniqueness is what lets the script prove the server it probes is its own), one SERVER_LOG that the closing error-scan reads, and a cleanup trap keyed on all three.
  • Redundant. Probe 3 already proves the bypass fired. The seeded admin's account can only exist because the audience gate admitted its zero-user signUpEmail; if the bypass stops firing (the feat(spec,auth)!: one declared audience posture for self-registration — invite_only|email_domain|open, default invite_only #11767 defect), the seed never lands and probe 3 fails — naming the real defect directly rather than leaving it to be inferred from a sign-up refusal downstream. C's marginal information is only that the bypass admits a self-serve first account rather than the seed's first account.

Landing window — when this fix reaches the tested tree

⚠️ This lands on main, but pack-smoke tests the release branch. publish-smoke.yml's pack-smoke job runs on workflow_run after each Release run and checks out changeset-release/main when an open release PR exists, so merging this does not turn the RC green by itself. The fix reaches the tested tree at the next release-branch re-cut (the next Release run that re-cuts changeset-release/main from a main containing this commit).

⛔ Judge the result by the commit status on the release-branch head, never by the check-run attached to a main SHA — the card's own trap, measured biting three seats, and it will bite this PR's reviewers the same way if they read it the other way.

Verification

See the report comment on #14000 for the full measurement record, including what was measured locally and what is left to CI.

skip-changeset: this PR publishes nothing from any package — the diff is one CI driver script.


Generated by Claude Code

The packed-tarball smoke asserted that the first POST /auth/sign-up/email
after `objectstack dev --fresh` returns 200 — an expectation authored
before #11739/#11767 made `invite_only` the default audience posture.
It is not the first account that reaches that probe. `--fresh` seeds a dev
admin in-process at boot through the real signUpEmail pipeline, and THAT
creation is the zero-user one the bootstrap bypass admits. The smoke's own
sign-up is the SECOND self-serve account, which invite_only refuses with
SELF_REGISTRATION_CLOSED + 403 — correctly. The release candidate had
therefore never once passed this gate with the posture default aboard.
Per the maintainer-approved ruling (option A, director batch #23):
- assert the seeded admin can SIGN IN, which is the packed install's
proof that the bootstrap bypass really fired;
- assert the uninvited second self-serve sign-up is REFUSED, pinning
both the 403 and the envelope code so an accidental widening of the
unauthenticated surface reds the RC instead of shipping;
- obtain the non-admin probe user through the operator path (the
invitation carve-out) before the existing session/CRUD probes.
Behaviour only — no vendor-internal symbol is pinned, and no auth or
audience runtime code is touched.
The posture is READ from the artifact's own public /auth/config rather
than hard-coded, because the two smoke modes install different products:
`registry` smokes the last PUBLISHED release, and plugin-auth 17.2.0
(2026-08-23) predates #11767 (2026-08-25). In `pack` mode the advertised
posture must BE invite_only; in both modes enforcement must match what
the artifact advertises.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WLJQhde67SeTccsmnBVarV
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/mskip-changesetPR has no user-facing published change; bypasses the changeset gate

Projects

None yet

2 participants

@baozhoutao@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(devx): re-pin the publish smoke to the declared first-run contract - #14255

Merged
baozhoutao merged 1 commit into
mainfrom
claude/issue-14000-smoke-declared-contract
Sep 1, 2026
Merged

fix(devx): re-pin the publish smoke to the declared first-run contract#14255
baozhoutao merged 1 commit into
mainfrom
claude/issue-14000-smoke-declared-contract

Conversation

@baozhoutao

Copy link
Copy Markdown
Contributor

Fixes#14000

Re-pins the packed-tarball smoke to the first-run contract the platform actually declares, per the maintainer-approved ruling (option A, director batch #23, comment 5494456135). No auth or audience runtime code is touched — option B is excluded by the ruling, and the product behaviour under test is correct as it stands.

What was wrong

scripts/publish-smoke.sh asserted that the first POST /auth/sign-up/email after objectstack dev --fresh returns 200. That expectation was authored before #11739/#11767 made invite_only the default audience posture, and it is not the first account that reaches the probe:

objectstack dev --fresh seeds a dev admin in-process at boot (maybeSeedDevAdmin, plugin-auth) through the real signUpEmail pipeline, sharing the isHumanUserRow predicate with the audience gate's bootstrap bypass. That creation is the zero-user one the bypass admits. The smoke's own sign-up is therefore the second self-serve account, which invite_only refuses with SELF_REGISTRATION_CLOSED + 403 — correctly. The release candidate had never once passed this gate with the posture default aboard (~7 days red, measured in the issue thread).

The probe sequence

#probebeforeafter
1GET /auth/get-session (anonymous)200200
2GET /auth/config (anonymous)200; in pack mode features.audiencePosture must be invite_only
3POST /auth/sign-in/email (seeded dev admin)ran later, only to drive CRUD200 — the packed install's proof the bootstrap bypass fired
4POST /auth/sign-up/email (uninvited second account)expected 200 — the stale half403 + envelope code == SELF_REGISTRATION_CLOSED
5POST /auth/organization/invite-member (as the admin)200, status == "pending" — the operator path
6POST /auth/sign-up/email (the invitee)200 — admitted by the invitation carve-out
7POST /auth/sign-in/email (probe user)200200
8GET /auth/get-session (signed in)200, is the probe userunchanged
9–12REST CRUD as the admin201/200/200/200unchanged; reuses the session from probe 3 instead of signing in a second time
13error/fatal log scancleanunchanged

Ruling points 1, 2 and 3 are probes 3, 4 and 5–6. Behaviour is pinned throughout — an HTTP status plus a code this repo owns and publishes. No vendor-internal symbol is asserted anywhere, which is the wiring shape that made #11767's breakage possible.

Two decisions worth reviewing

The operator path is the invitation carve-out, not admin/create-user. The ruling names either. POST /auth/admin/create-user needs better-auth's admin plugin, and a scaffolded project does not get it by default — admin: pluginConfig.admin ?? scimEffective (auth-manager.ts), and the blank template declares no auth config at all — so that route would answer 501 NOT_IMPLEMENTED on the very artifact under test. The organization plugin is on by default (organization: pluginConfig.organization ?? true), and ADR-0081's ensureDefaultOrganization exists precisely so invite-member has an active org on a single-org install. So the carve-out is the operator path a fresh install actually ships.

The posture is read from the artifact, not hard-coded — because the two smoke modes install different products.pack smokes this repo's tree; registry smokes the last published release, whose contract this tree does not define. @objectstack/plugin-auth latest is 17.2.0, published 2026-08-23; #11767 landed 2026-08-25. Hard-coding the RC's posture would have turned the weekly registry canary red — and auto-filed a "fresh install is broken" issue — over a release behaving exactly as its own contract declares.

So the script reads features.audiencePosture off the public /auth/config and asserts that enforcement matches what the artifact advertises. In pack mode the advertised posture must additionally beinvite_only, which is where the ruling's closed-by-default pin bites: widening the default reds the RC before any behaviour probe can report the widening as a cheerful 200. The legacy open-registration branch is reachable only by registry mode against a pre-#11739 release and retires itself the first time a published release carries the posture.

Ruling point 4 — option C's direct bootstrap probe: declined, and why

Folding in a --no-seed-admin variant was conditioned on being cheap. It is not, and it is also redundant:

  • Not cheap.--no-seed-admin is a real flag, but exercising it means a secondobjectstack dev --fresh boot — the slowest step in the job — plus restructuring machinery that is single-boot throughout: one SERVER_PID, one DEV_TMPDIR (whose per-run uniqueness is what lets the script prove the server it probes is its own), one SERVER_LOG that the closing error-scan reads, and a cleanup trap keyed on all three.
  • Redundant. Probe 3 already proves the bypass fired. The seeded admin's account can only exist because the audience gate admitted its zero-user signUpEmail; if the bypass stops firing (the feat(spec,auth)!: one declared audience posture for self-registration — invite_only|email_domain|open, default invite_only #11767 defect), the seed never lands and probe 3 fails — naming the real defect directly rather than leaving it to be inferred from a sign-up refusal downstream. C's marginal information is only that the bypass admits a self-serve first account rather than the seed's first account.

Landing window — when this fix reaches the tested tree

⚠️ This lands on main, but pack-smoke tests the release branch. publish-smoke.yml's pack-smoke job runs on workflow_run after each Release run and checks out changeset-release/main when an open release PR exists, so merging this does not turn the RC green by itself. The fix reaches the tested tree at the next release-branch re-cut (the next Release run that re-cuts changeset-release/main from a main containing this commit).

⛔ Judge the result by the commit status on the release-branch head, never by the check-run attached to a main SHA — the card's own trap, measured biting three seats, and it will bite this PR's reviewers the same way if they read it the other way.

Verification

See the report comment on #14000 for the full measurement record, including what was measured locally and what is left to CI.

skip-changeset: this PR publishes nothing from any package — the diff is one CI driver script.


Generated by Claude Code

The packed-tarball smoke asserted that the first POST /auth/sign-up/email
after `objectstack dev --fresh` returns 200 — an expectation authored
before #11739/#11767 made `invite_only` the default audience posture.
It is not the first account that reaches that probe. `--fresh` seeds a dev
admin in-process at boot through the real signUpEmail pipeline, and THAT
creation is the zero-user one the bootstrap bypass admits. The smoke's own
sign-up is the SECOND self-serve account, which invite_only refuses with
SELF_REGISTRATION_CLOSED + 403 — correctly. The release candidate had
therefore never once passed this gate with the posture default aboard.
Per the maintainer-approved ruling (option A, director batch #23):
- assert the seeded admin can SIGN IN, which is the packed install's
proof that the bootstrap bypass really fired;
- assert the uninvited second self-serve sign-up is REFUSED, pinning
both the 403 and the envelope code so an accidental widening of the
unauthenticated surface reds the RC instead of shipping;
- obtain the non-admin probe user through the operator path (the
invitation carve-out) before the existing session/CRUD probes.
Behaviour only — no vendor-internal symbol is pinned, and no auth or
audience runtime code is touched.
The posture is READ from the artifact's own public /auth/config rather
than hard-coded, because the two smoke modes install different products:
`registry` smokes the last PUBLISHED release, and plugin-auth 17.2.0
(2026-08-23) predates #11767 (2026-08-25). In `pack` mode the advertised
posture must BE invite_only; in both modes enforcement must match what
the artifact advertises.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WLJQhde67SeTccsmnBVarV
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/mskip-changesetPR has no user-facing published change; bypasses the changeset gate

Projects

None yet

2 participants

@baozhoutao@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

fix(devx): re-pin the publish smoke to the declared first-run contract - #14255

Merged
baozhoutao merged 1 commit into
mainfrom
claude/issue-14000-smoke-declared-contract
Sep 1, 2026
Merged

fix(devx): re-pin the publish smoke to the declared first-run contract#14255
baozhoutao merged 1 commit into
mainfrom
claude/issue-14000-smoke-declared-contract

Conversation

@baozhoutao

Copy link
Copy Markdown
Contributor

Fixes#14000

Re-pins the packed-tarball smoke to the first-run contract the platform actually declares, per the maintainer-approved ruling (option A, director batch #23, comment 5494456135). No auth or audience runtime code is touched — option B is excluded by the ruling, and the product behaviour under test is correct as it stands.

What was wrong

scripts/publish-smoke.sh asserted that the first POST /auth/sign-up/email after objectstack dev --fresh returns 200. That expectation was authored before #11739/#11767 made invite_only the default audience posture, and it is not the first account that reaches the probe:

objectstack dev --fresh seeds a dev admin in-process at boot (maybeSeedDevAdmin, plugin-auth) through the real signUpEmail pipeline, sharing the isHumanUserRow predicate with the audience gate's bootstrap bypass. That creation is the zero-user one the bypass admits. The smoke's own sign-up is therefore the second self-serve account, which invite_only refuses with SELF_REGISTRATION_CLOSED + 403 — correctly. The release candidate had never once passed this gate with the posture default aboard (~7 days red, measured in the issue thread).

The probe sequence

#probebeforeafter
1GET /auth/get-session (anonymous)200200
2GET /auth/config (anonymous)200; in pack mode features.audiencePosture must be invite_only
3POST /auth/sign-in/email (seeded dev admin)ran later, only to drive CRUD200 — the packed install's proof the bootstrap bypass fired
4POST /auth/sign-up/email (uninvited second account)expected 200 — the stale half403 + envelope code == SELF_REGISTRATION_CLOSED
5POST /auth/organization/invite-member (as the admin)200, status == "pending" — the operator path
6POST /auth/sign-up/email (the invitee)200 — admitted by the invitation carve-out
7POST /auth/sign-in/email (probe user)200200
8GET /auth/get-session (signed in)200, is the probe userunchanged
9–12REST CRUD as the admin201/200/200/200unchanged; reuses the session from probe 3 instead of signing in a second time
13error/fatal log scancleanunchanged

Ruling points 1, 2 and 3 are probes 3, 4 and 5–6. Behaviour is pinned throughout — an HTTP status plus a code this repo owns and publishes. No vendor-internal symbol is asserted anywhere, which is the wiring shape that made #11767's breakage possible.

Two decisions worth reviewing

The operator path is the invitation carve-out, not admin/create-user. The ruling names either. POST /auth/admin/create-user needs better-auth's admin plugin, and a scaffolded project does not get it by default — admin: pluginConfig.admin ?? scimEffective (auth-manager.ts), and the blank template declares no auth config at all — so that route would answer 501 NOT_IMPLEMENTED on the very artifact under test. The organization plugin is on by default (organization: pluginConfig.organization ?? true), and ADR-0081's ensureDefaultOrganization exists precisely so invite-member has an active org on a single-org install. So the carve-out is the operator path a fresh install actually ships.

The posture is read from the artifact, not hard-coded — because the two smoke modes install different products.pack smokes this repo's tree; registry smokes the last published release, whose contract this tree does not define. @objectstack/plugin-auth latest is 17.2.0, published 2026-08-23; #11767 landed 2026-08-25. Hard-coding the RC's posture would have turned the weekly registry canary red — and auto-filed a "fresh install is broken" issue — over a release behaving exactly as its own contract declares.

So the script reads features.audiencePosture off the public /auth/config and asserts that enforcement matches what the artifact advertises. In pack mode the advertised posture must additionally beinvite_only, which is where the ruling's closed-by-default pin bites: widening the default reds the RC before any behaviour probe can report the widening as a cheerful 200. The legacy open-registration branch is reachable only by registry mode against a pre-#11739 release and retires itself the first time a published release carries the posture.

Ruling point 4 — option C's direct bootstrap probe: declined, and why

Folding in a --no-seed-admin variant was conditioned on being cheap. It is not, and it is also redundant:

  • Not cheap.--no-seed-admin is a real flag, but exercising it means a secondobjectstack dev --fresh boot — the slowest step in the job — plus restructuring machinery that is single-boot throughout: one SERVER_PID, one DEV_TMPDIR (whose per-run uniqueness is what lets the script prove the server it probes is its own), one SERVER_LOG that the closing error-scan reads, and a cleanup trap keyed on all three.
  • Redundant. Probe 3 already proves the bypass fired. The seeded admin's account can only exist because the audience gate admitted its zero-user signUpEmail; if the bypass stops firing (the feat(spec,auth)!: one declared audience posture for self-registration — invite_only|email_domain|open, default invite_only #11767 defect), the seed never lands and probe 3 fails — naming the real defect directly rather than leaving it to be inferred from a sign-up refusal downstream. C's marginal information is only that the bypass admits a self-serve first account rather than the seed's first account.

Landing window — when this fix reaches the tested tree

⚠️ This lands on main, but pack-smoke tests the release branch. publish-smoke.yml's pack-smoke job runs on workflow_run after each Release run and checks out changeset-release/main when an open release PR exists, so merging this does not turn the RC green by itself. The fix reaches the tested tree at the next release-branch re-cut (the next Release run that re-cuts changeset-release/main from a main containing this commit).

⛔ Judge the result by the commit status on the release-branch head, never by the check-run attached to a main SHA — the card's own trap, measured biting three seats, and it will bite this PR's reviewers the same way if they read it the other way.

Verification

See the report comment on #14000 for the full measurement record, including what was measured locally and what is left to CI.

skip-changeset: this PR publishes nothing from any package — the diff is one CI driver script.


Generated by Claude Code

The packed-tarball smoke asserted that the first POST /auth/sign-up/email
after `objectstack dev --fresh` returns 200 — an expectation authored
before #11739/#11767 made `invite_only` the default audience posture.
It is not the first account that reaches that probe. `--fresh` seeds a dev
admin in-process at boot through the real signUpEmail pipeline, and THAT
creation is the zero-user one the bootstrap bypass admits. The smoke's own
sign-up is the SECOND self-serve account, which invite_only refuses with
SELF_REGISTRATION_CLOSED + 403 — correctly. The release candidate had
therefore never once passed this gate with the posture default aboard.
Per the maintainer-approved ruling (option A, director batch #23):
- assert the seeded admin can SIGN IN, which is the packed install's
proof that the bootstrap bypass really fired;
- assert the uninvited second self-serve sign-up is REFUSED, pinning
both the 403 and the envelope code so an accidental widening of the
unauthenticated surface reds the RC instead of shipping;
- obtain the non-admin probe user through the operator path (the
invitation carve-out) before the existing session/CRUD probes.
Behaviour only — no vendor-internal symbol is pinned, and no auth or
audience runtime code is touched.
The posture is READ from the artifact's own public /auth/config rather
than hard-coded, because the two smoke modes install different products:
`registry` smokes the last PUBLISHED release, and plugin-auth 17.2.0
(2026-08-23) predates #11767 (2026-08-25). In `pack` mode the advertised
posture must BE invite_only; in both modes enforcement must match what
the artifact advertises.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WLJQhde67SeTccsmnBVarV
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/mskip-changesetPR has no user-facing published change; bypasses the changeset gate

Projects

None yet

2 participants

@baozhoutao@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(devx): re-pin the publish smoke to the declared first-run contract - #14255

Merged
baozhoutao merged 1 commit into
mainfrom
claude/issue-14000-smoke-declared-contract
Sep 1, 2026
Merged

fix(devx): re-pin the publish smoke to the declared first-run contract#14255
baozhoutao merged 1 commit into
mainfrom
claude/issue-14000-smoke-declared-contract

Conversation

@baozhoutao

Copy link
Copy Markdown
Contributor

Fixes#14000

Re-pins the packed-tarball smoke to the first-run contract the platform actually declares, per the maintainer-approved ruling (option A, director batch #23, comment 5494456135). No auth or audience runtime code is touched — option B is excluded by the ruling, and the product behaviour under test is correct as it stands.

What was wrong

scripts/publish-smoke.sh asserted that the first POST /auth/sign-up/email after objectstack dev --fresh returns 200. That expectation was authored before #11739/#11767 made invite_only the default audience posture, and it is not the first account that reaches the probe:

objectstack dev --fresh seeds a dev admin in-process at boot (maybeSeedDevAdmin, plugin-auth) through the real signUpEmail pipeline, sharing the isHumanUserRow predicate with the audience gate's bootstrap bypass. That creation is the zero-user one the bypass admits. The smoke's own sign-up is therefore the second self-serve account, which invite_only refuses with SELF_REGISTRATION_CLOSED + 403 — correctly. The release candidate had never once passed this gate with the posture default aboard (~7 days red, measured in the issue thread).

The probe sequence

#probebeforeafter
1GET /auth/get-session (anonymous)200200
2GET /auth/config (anonymous)200; in pack mode features.audiencePosture must be invite_only
3POST /auth/sign-in/email (seeded dev admin)ran later, only to drive CRUD200 — the packed install's proof the bootstrap bypass fired
4POST /auth/sign-up/email (uninvited second account)expected 200 — the stale half403 + envelope code == SELF_REGISTRATION_CLOSED
5POST /auth/organization/invite-member (as the admin)200, status == "pending" — the operator path
6POST /auth/sign-up/email (the invitee)200 — admitted by the invitation carve-out
7POST /auth/sign-in/email (probe user)200200
8GET /auth/get-session (signed in)200, is the probe userunchanged
9–12REST CRUD as the admin201/200/200/200unchanged; reuses the session from probe 3 instead of signing in a second time
13error/fatal log scancleanunchanged

Ruling points 1, 2 and 3 are probes 3, 4 and 5–6. Behaviour is pinned throughout — an HTTP status plus a code this repo owns and publishes. No vendor-internal symbol is asserted anywhere, which is the wiring shape that made #11767's breakage possible.

Two decisions worth reviewing

The operator path is the invitation carve-out, not admin/create-user. The ruling names either. POST /auth/admin/create-user needs better-auth's admin plugin, and a scaffolded project does not get it by default — admin: pluginConfig.admin ?? scimEffective (auth-manager.ts), and the blank template declares no auth config at all — so that route would answer 501 NOT_IMPLEMENTED on the very artifact under test. The organization plugin is on by default (organization: pluginConfig.organization ?? true), and ADR-0081's ensureDefaultOrganization exists precisely so invite-member has an active org on a single-org install. So the carve-out is the operator path a fresh install actually ships.

The posture is read from the artifact, not hard-coded — because the two smoke modes install different products.pack smokes this repo's tree; registry smokes the last published release, whose contract this tree does not define. @objectstack/plugin-auth latest is 17.2.0, published 2026-08-23; #11767 landed 2026-08-25. Hard-coding the RC's posture would have turned the weekly registry canary red — and auto-filed a "fresh install is broken" issue — over a release behaving exactly as its own contract declares.

So the script reads features.audiencePosture off the public /auth/config and asserts that enforcement matches what the artifact advertises. In pack mode the advertised posture must additionally beinvite_only, which is where the ruling's closed-by-default pin bites: widening the default reds the RC before any behaviour probe can report the widening as a cheerful 200. The legacy open-registration branch is reachable only by registry mode against a pre-#11739 release and retires itself the first time a published release carries the posture.

Ruling point 4 — option C's direct bootstrap probe: declined, and why

Folding in a --no-seed-admin variant was conditioned on being cheap. It is not, and it is also redundant:

  • Not cheap.--no-seed-admin is a real flag, but exercising it means a secondobjectstack dev --fresh boot — the slowest step in the job — plus restructuring machinery that is single-boot throughout: one SERVER_PID, one DEV_TMPDIR (whose per-run uniqueness is what lets the script prove the server it probes is its own), one SERVER_LOG that the closing error-scan reads, and a cleanup trap keyed on all three.
  • Redundant. Probe 3 already proves the bypass fired. The seeded admin's account can only exist because the audience gate admitted its zero-user signUpEmail; if the bypass stops firing (the feat(spec,auth)!: one declared audience posture for self-registration — invite_only|email_domain|open, default invite_only #11767 defect), the seed never lands and probe 3 fails — naming the real defect directly rather than leaving it to be inferred from a sign-up refusal downstream. C's marginal information is only that the bypass admits a self-serve first account rather than the seed's first account.

Landing window — when this fix reaches the tested tree

⚠️ This lands on main, but pack-smoke tests the release branch. publish-smoke.yml's pack-smoke job runs on workflow_run after each Release run and checks out changeset-release/main when an open release PR exists, so merging this does not turn the RC green by itself. The fix reaches the tested tree at the next release-branch re-cut (the next Release run that re-cuts changeset-release/main from a main containing this commit).

⛔ Judge the result by the commit status on the release-branch head, never by the check-run attached to a main SHA — the card's own trap, measured biting three seats, and it will bite this PR's reviewers the same way if they read it the other way.

Verification

See the report comment on #14000 for the full measurement record, including what was measured locally and what is left to CI.

skip-changeset: this PR publishes nothing from any package — the diff is one CI driver script.


Generated by Claude Code

The packed-tarball smoke asserted that the first POST /auth/sign-up/email
after `objectstack dev --fresh` returns 200 — an expectation authored
before #11739/#11767 made `invite_only` the default audience posture.
It is not the first account that reaches that probe. `--fresh` seeds a dev
admin in-process at boot through the real signUpEmail pipeline, and THAT
creation is the zero-user one the bootstrap bypass admits. The smoke's own
sign-up is the SECOND self-serve account, which invite_only refuses with
SELF_REGISTRATION_CLOSED + 403 — correctly. The release candidate had
therefore never once passed this gate with the posture default aboard.
Per the maintainer-approved ruling (option A, director batch #23):
- assert the seeded admin can SIGN IN, which is the packed install's
proof that the bootstrap bypass really fired;
- assert the uninvited second self-serve sign-up is REFUSED, pinning
both the 403 and the envelope code so an accidental widening of the
unauthenticated surface reds the RC instead of shipping;
- obtain the non-admin probe user through the operator path (the
invitation carve-out) before the existing session/CRUD probes.
Behaviour only — no vendor-internal symbol is pinned, and no auth or
audience runtime code is touched.
The posture is READ from the artifact's own public /auth/config rather
than hard-coded, because the two smoke modes install different products:
`registry` smokes the last PUBLISHED release, and plugin-auth 17.2.0
(2026-08-23) predates #11767 (2026-08-25). In `pack` mode the advertised
posture must BE invite_only; in both modes enforcement must match what
the artifact advertises.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WLJQhde67SeTccsmnBVarV
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/mskip-changesetPR has no user-facing published change; bypasses the changeset gate

Projects

None yet

2 participants

@baozhoutao@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(devx): re-pin the publish smoke to the declared first-run contract - #14255

Merged
baozhoutao merged 1 commit into
mainfrom
claude/issue-14000-smoke-declared-contract
Sep 1, 2026
Merged

fix(devx): re-pin the publish smoke to the declared first-run contract#14255
baozhoutao merged 1 commit into
mainfrom
claude/issue-14000-smoke-declared-contract

Conversation

@baozhoutao

Copy link
Copy Markdown
Contributor

Fixes#14000

Re-pins the packed-tarball smoke to the first-run contract the platform actually declares, per the maintainer-approved ruling (option A, director batch #23, comment 5494456135). No auth or audience runtime code is touched — option B is excluded by the ruling, and the product behaviour under test is correct as it stands.

What was wrong

scripts/publish-smoke.sh asserted that the first POST /auth/sign-up/email after objectstack dev --fresh returns 200. That expectation was authored before #11739/#11767 made invite_only the default audience posture, and it is not the first account that reaches the probe:

objectstack dev --fresh seeds a dev admin in-process at boot (maybeSeedDevAdmin, plugin-auth) through the real signUpEmail pipeline, sharing the isHumanUserRow predicate with the audience gate's bootstrap bypass. That creation is the zero-user one the bypass admits. The smoke's own sign-up is therefore the second self-serve account, which invite_only refuses with SELF_REGISTRATION_CLOSED + 403 — correctly. The release candidate had never once passed this gate with the posture default aboard (~7 days red, measured in the issue thread).

The probe sequence

#probebeforeafter
1GET /auth/get-session (anonymous)200200
2GET /auth/config (anonymous)200; in pack mode features.audiencePosture must be invite_only
3POST /auth/sign-in/email (seeded dev admin)ran later, only to drive CRUD200 — the packed install's proof the bootstrap bypass fired
4POST /auth/sign-up/email (uninvited second account)expected 200 — the stale half403 + envelope code == SELF_REGISTRATION_CLOSED
5POST /auth/organization/invite-member (as the admin)200, status == "pending" — the operator path
6POST /auth/sign-up/email (the invitee)200 — admitted by the invitation carve-out
7POST /auth/sign-in/email (probe user)200200
8GET /auth/get-session (signed in)200, is the probe userunchanged
9–12REST CRUD as the admin201/200/200/200unchanged; reuses the session from probe 3 instead of signing in a second time
13error/fatal log scancleanunchanged

Ruling points 1, 2 and 3 are probes 3, 4 and 5–6. Behaviour is pinned throughout — an HTTP status plus a code this repo owns and publishes. No vendor-internal symbol is asserted anywhere, which is the wiring shape that made #11767's breakage possible.

Two decisions worth reviewing

The operator path is the invitation carve-out, not admin/create-user. The ruling names either. POST /auth/admin/create-user needs better-auth's admin plugin, and a scaffolded project does not get it by default — admin: pluginConfig.admin ?? scimEffective (auth-manager.ts), and the blank template declares no auth config at all — so that route would answer 501 NOT_IMPLEMENTED on the very artifact under test. The organization plugin is on by default (organization: pluginConfig.organization ?? true), and ADR-0081's ensureDefaultOrganization exists precisely so invite-member has an active org on a single-org install. So the carve-out is the operator path a fresh install actually ships.

The posture is read from the artifact, not hard-coded — because the two smoke modes install different products.pack smokes this repo's tree; registry smokes the last published release, whose contract this tree does not define. @objectstack/plugin-auth latest is 17.2.0, published 2026-08-23; #11767 landed 2026-08-25. Hard-coding the RC's posture would have turned the weekly registry canary red — and auto-filed a "fresh install is broken" issue — over a release behaving exactly as its own contract declares.

So the script reads features.audiencePosture off the public /auth/config and asserts that enforcement matches what the artifact advertises. In pack mode the advertised posture must additionally beinvite_only, which is where the ruling's closed-by-default pin bites: widening the default reds the RC before any behaviour probe can report the widening as a cheerful 200. The legacy open-registration branch is reachable only by registry mode against a pre-#11739 release and retires itself the first time a published release carries the posture.

Ruling point 4 — option C's direct bootstrap probe: declined, and why

Folding in a --no-seed-admin variant was conditioned on being cheap. It is not, and it is also redundant:

  • Not cheap.--no-seed-admin is a real flag, but exercising it means a secondobjectstack dev --fresh boot — the slowest step in the job — plus restructuring machinery that is single-boot throughout: one SERVER_PID, one DEV_TMPDIR (whose per-run uniqueness is what lets the script prove the server it probes is its own), one SERVER_LOG that the closing error-scan reads, and a cleanup trap keyed on all three.
  • Redundant. Probe 3 already proves the bypass fired. The seeded admin's account can only exist because the audience gate admitted its zero-user signUpEmail; if the bypass stops firing (the feat(spec,auth)!: one declared audience posture for self-registration — invite_only|email_domain|open, default invite_only #11767 defect), the seed never lands and probe 3 fails — naming the real defect directly rather than leaving it to be inferred from a sign-up refusal downstream. C's marginal information is only that the bypass admits a self-serve first account rather than the seed's first account.

Landing window — when this fix reaches the tested tree

⚠️ This lands on main, but pack-smoke tests the release branch. publish-smoke.yml's pack-smoke job runs on workflow_run after each Release run and checks out changeset-release/main when an open release PR exists, so merging this does not turn the RC green by itself. The fix reaches the tested tree at the next release-branch re-cut (the next Release run that re-cuts changeset-release/main from a main containing this commit).

⛔ Judge the result by the commit status on the release-branch head, never by the check-run attached to a main SHA — the card's own trap, measured biting three seats, and it will bite this PR's reviewers the same way if they read it the other way.

Verification

See the report comment on #14000 for the full measurement record, including what was measured locally and what is left to CI.

skip-changeset: this PR publishes nothing from any package — the diff is one CI driver script.


Generated by Claude Code

The packed-tarball smoke asserted that the first POST /auth/sign-up/email
after `objectstack dev --fresh` returns 200 — an expectation authored
before #11739/#11767 made `invite_only` the default audience posture.
It is not the first account that reaches that probe. `--fresh` seeds a dev
admin in-process at boot through the real signUpEmail pipeline, and THAT
creation is the zero-user one the bootstrap bypass admits. The smoke's own
sign-up is the SECOND self-serve account, which invite_only refuses with
SELF_REGISTRATION_CLOSED + 403 — correctly. The release candidate had
therefore never once passed this gate with the posture default aboard.
Per the maintainer-approved ruling (option A, director batch #23):
- assert the seeded admin can SIGN IN, which is the packed install's
proof that the bootstrap bypass really fired;
- assert the uninvited second self-serve sign-up is REFUSED, pinning
both the 403 and the envelope code so an accidental widening of the
unauthenticated surface reds the RC instead of shipping;
- obtain the non-admin probe user through the operator path (the
invitation carve-out) before the existing session/CRUD probes.
Behaviour only — no vendor-internal symbol is pinned, and no auth or
audience runtime code is touched.
The posture is READ from the artifact's own public /auth/config rather
than hard-coded, because the two smoke modes install different products:
`registry` smokes the last PUBLISHED release, and plugin-auth 17.2.0
(2026-08-23) predates #11767 (2026-08-25). In `pack` mode the advertised
posture must BE invite_only; in both modes enforcement must match what
the artifact advertises.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WLJQhde67SeTccsmnBVarV
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/mskip-changesetPR has no user-facing published change; bypasses the changeset gate

Projects

None yet

2 participants

@baozhoutao@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

fix(devx): re-pin the publish smoke to the declared first-run contract - #14255

Merged
baozhoutao merged 1 commit into
mainfrom
claude/issue-14000-smoke-declared-contract
Sep 1, 2026
Merged

fix(devx): re-pin the publish smoke to the declared first-run contract#14255
baozhoutao merged 1 commit into
mainfrom
claude/issue-14000-smoke-declared-contract

Conversation

@baozhoutao

Copy link
Copy Markdown
Contributor

Fixes#14000

Re-pins the packed-tarball smoke to the first-run contract the platform actually declares, per the maintainer-approved ruling (option A, director batch #23, comment 5494456135). No auth or audience runtime code is touched — option B is excluded by the ruling, and the product behaviour under test is correct as it stands.

What was wrong

scripts/publish-smoke.sh asserted that the first POST /auth/sign-up/email after objectstack dev --fresh returns 200. That expectation was authored before #11739/#11767 made invite_only the default audience posture, and it is not the first account that reaches the probe:

objectstack dev --fresh seeds a dev admin in-process at boot (maybeSeedDevAdmin, plugin-auth) through the real signUpEmail pipeline, sharing the isHumanUserRow predicate with the audience gate's bootstrap bypass. That creation is the zero-user one the bypass admits. The smoke's own sign-up is therefore the second self-serve account, which invite_only refuses with SELF_REGISTRATION_CLOSED + 403 — correctly. The release candidate had never once passed this gate with the posture default aboard (~7 days red, measured in the issue thread).

The probe sequence

#probebeforeafter
1GET /auth/get-session (anonymous)200200
2GET /auth/config (anonymous)200; in pack mode features.audiencePosture must be invite_only
3POST /auth/sign-in/email (seeded dev admin)ran later, only to drive CRUD200 — the packed install's proof the bootstrap bypass fired
4POST /auth/sign-up/email (uninvited second account)expected 200 — the stale half403 + envelope code == SELF_REGISTRATION_CLOSED
5POST /auth/organization/invite-member (as the admin)200, status == "pending" — the operator path
6POST /auth/sign-up/email (the invitee)200 — admitted by the invitation carve-out
7POST /auth/sign-in/email (probe user)200200
8GET /auth/get-session (signed in)200, is the probe userunchanged
9–12REST CRUD as the admin201/200/200/200unchanged; reuses the session from probe 3 instead of signing in a second time
13error/fatal log scancleanunchanged

Ruling points 1, 2 and 3 are probes 3, 4 and 5–6. Behaviour is pinned throughout — an HTTP status plus a code this repo owns and publishes. No vendor-internal symbol is asserted anywhere, which is the wiring shape that made #11767's breakage possible.

Two decisions worth reviewing

The operator path is the invitation carve-out, not admin/create-user. The ruling names either. POST /auth/admin/create-user needs better-auth's admin plugin, and a scaffolded project does not get it by default — admin: pluginConfig.admin ?? scimEffective (auth-manager.ts), and the blank template declares no auth config at all — so that route would answer 501 NOT_IMPLEMENTED on the very artifact under test. The organization plugin is on by default (organization: pluginConfig.organization ?? true), and ADR-0081's ensureDefaultOrganization exists precisely so invite-member has an active org on a single-org install. So the carve-out is the operator path a fresh install actually ships.

The posture is read from the artifact, not hard-coded — because the two smoke modes install different products.pack smokes this repo's tree; registry smokes the last published release, whose contract this tree does not define. @objectstack/plugin-auth latest is 17.2.0, published 2026-08-23; #11767 landed 2026-08-25. Hard-coding the RC's posture would have turned the weekly registry canary red — and auto-filed a "fresh install is broken" issue — over a release behaving exactly as its own contract declares.

So the script reads features.audiencePosture off the public /auth/config and asserts that enforcement matches what the artifact advertises. In pack mode the advertised posture must additionally beinvite_only, which is where the ruling's closed-by-default pin bites: widening the default reds the RC before any behaviour probe can report the widening as a cheerful 200. The legacy open-registration branch is reachable only by registry mode against a pre-#11739 release and retires itself the first time a published release carries the posture.

Ruling point 4 — option C's direct bootstrap probe: declined, and why

Folding in a --no-seed-admin variant was conditioned on being cheap. It is not, and it is also redundant:

  • Not cheap.--no-seed-admin is a real flag, but exercising it means a secondobjectstack dev --fresh boot — the slowest step in the job — plus restructuring machinery that is single-boot throughout: one SERVER_PID, one DEV_TMPDIR (whose per-run uniqueness is what lets the script prove the server it probes is its own), one SERVER_LOG that the closing error-scan reads, and a cleanup trap keyed on all three.
  • Redundant. Probe 3 already proves the bypass fired. The seeded admin's account can only exist because the audience gate admitted its zero-user signUpEmail; if the bypass stops firing (the feat(spec,auth)!: one declared audience posture for self-registration — invite_only|email_domain|open, default invite_only #11767 defect), the seed never lands and probe 3 fails — naming the real defect directly rather than leaving it to be inferred from a sign-up refusal downstream. C's marginal information is only that the bypass admits a self-serve first account rather than the seed's first account.

Landing window — when this fix reaches the tested tree

⚠️ This lands on main, but pack-smoke tests the release branch. publish-smoke.yml's pack-smoke job runs on workflow_run after each Release run and checks out changeset-release/main when an open release PR exists, so merging this does not turn the RC green by itself. The fix reaches the tested tree at the next release-branch re-cut (the next Release run that re-cuts changeset-release/main from a main containing this commit).

⛔ Judge the result by the commit status on the release-branch head, never by the check-run attached to a main SHA — the card's own trap, measured biting three seats, and it will bite this PR's reviewers the same way if they read it the other way.

Verification

See the report comment on #14000 for the full measurement record, including what was measured locally and what is left to CI.

skip-changeset: this PR publishes nothing from any package — the diff is one CI driver script.


Generated by Claude Code

The packed-tarball smoke asserted that the first POST /auth/sign-up/email
after `objectstack dev --fresh` returns 200 — an expectation authored
before #11739/#11767 made `invite_only` the default audience posture.
It is not the first account that reaches that probe. `--fresh` seeds a dev
admin in-process at boot through the real signUpEmail pipeline, and THAT
creation is the zero-user one the bootstrap bypass admits. The smoke's own
sign-up is the SECOND self-serve account, which invite_only refuses with
SELF_REGISTRATION_CLOSED + 403 — correctly. The release candidate had
therefore never once passed this gate with the posture default aboard.
Per the maintainer-approved ruling (option A, director batch #23):
- assert the seeded admin can SIGN IN, which is the packed install's
proof that the bootstrap bypass really fired;
- assert the uninvited second self-serve sign-up is REFUSED, pinning
both the 403 and the envelope code so an accidental widening of the
unauthenticated surface reds the RC instead of shipping;
- obtain the non-admin probe user through the operator path (the
invitation carve-out) before the existing session/CRUD probes.
Behaviour only — no vendor-internal symbol is pinned, and no auth or
audience runtime code is touched.
The posture is READ from the artifact's own public /auth/config rather
than hard-coded, because the two smoke modes install different products:
`registry` smokes the last PUBLISHED release, and plugin-auth 17.2.0
(2026-08-23) predates #11767 (2026-08-25). In `pack` mode the advertised
posture must BE invite_only; in both modes enforcement must match what
the artifact advertises.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WLJQhde67SeTccsmnBVarV
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/mskip-changesetPR has no user-facing published change; bypasses the changeset gate

Projects

None yet

2 participants

@baozhoutao@claude