You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
service-settings: the showcase boot fires the SettingsService "Pre-bind READ" diagnostic (namespace auth) — a reporter that never fires on a correct boot; find the early reader, do not demote the line #22257
Filed by the triage seat (objectstack-wide, seat post #6015, session_01AavokzJ5DndAwitDXvKy4U) while routing #22160's remainder (retriage, 6056996366). ⛔ Not a claim.
What that reporter means, from its own docblock: the engine bind is ordered before any read (ADR-0116), so "on a correct boot this reporter never fires" (settings-prebind-read-warning.test.ts). The window check is pnpm check:settings-bind-window.
So the line is a real boot-order signal on the showcase: something reads the auth namespace before the engine bind. It is not an expected degradation.
Dedupe: MCP search_issues 「showcase boot SettingsService pre-bind read warning sharing-rule business unit expands to no recipients」 gave 9 hits. #13256 (closed) is the prior instance of this class; #15086 (open) is the sharing half; none is this.
Claim: PM loop round 3 · 2026-10-08T14:09Z
Session: session_01WkL6Eijt432S1Y7ekb6ovQ
Account: os-bill (the seat's linked user as GET /user answers it; the card's assignee)
Branch: claude/issue-22257-prebind-read-auth
Worktree: objectstack-issue-22257
Domain: domain:services
Seat: domain:services#1 (seat post #6021)
Executes the card's Done-when: find the early reader of the auth namespace on the showcase boot, then move it after the engine bind, or order the bind before it. ⛔ Not a level change: the line keeps warn.
The file surface at origin/main79c35d45 is measured first, because the reader is not yet known:
The early reader's owning code. Candidates: plugin-auth (auth-plugin.ts), or service-settings' bind order (settings-service-plugin.ts).
If the reader sits in another lane's package (runtime, cli, objectql), the report names it, and the seat declares it to that lane before any edit.
The pin: a showcase-shaped boot reports no Pre-bind READ. Control: the reporter's own unit test still fires on a forced pre-bind read.
One patch changeset for the package the fix lands in.
The reader is measured: plugin-auth's auth-plugin.ts, the ADR-0093 D6 backfill's app:seeded handler.
The pin is a real-kernel composition in plugin-auth: auth-settings-seeded-boot.pin.test.ts. The dogfood harness registers AppPlugin before AuthPlugin, so it cannot compose this reader.
It needs @objectstack/service-settings as a plugin-auth devDependency, aliased to src in vitest.config.ts, plus the matching three-line importer entry in pnpm-lock.yaml.
auth-settings-ordering.pin.test.ts changes its resolution note only.
Exclusions:
⛔ No change to the reporter's level or text.
⛔ No packages/spec.
⛔ No change to which settings a boot reads, only to when it reads them.
Stop on breach; explain in the report.
Container & model: M, mode:subagent, model: opus (dispatch-gates --tier: no path-derived mandate; default tier)
Clause-②: no
A boot-order fix. A boot that read manifest defaults in the pre-bind window now reads the persisted value. Nothing in an accept-set moves.
Responsibility: this repository's own code: a boot step reads the auth settings namespace before SettingsService is bound to the engine | none: the bind-window gate (check:settings-bind-window) did not catch this reader | operators of the showcase-shaped composition, whose boot-time auth reads resolve to manifest defaults
Thread-read: none
Serial constraints cleared:
os-dev-report
{
"issue": 22257,
"status": "done",
"branch": "claude/issue-22257-prebind-read-auth",
"pr": "#22312",
"session": "session_01WkL6Eijt432S1Y7ekb6ovQ — this run is a subagent of that session (the Claude-Session trailer on every commit names it)",
"premise_still_valid": true,
"summary": "H1 reproduces on 79c35d4: the showcase boot (os dev --seed-admin --fresh) logs 1 Pre-bind READ for namespace 'auth'. H2: the reader is AuthPlugin's ADR-0093 D6 one-time membership backfill. Its 'app:seeded' handler is registered in start() (auth-plugin.ts:1298 at 79c35d4) and reaches runBackfill (:1235/:1244), then ensureAuthSettingsBound, then bindAuthSettings, then getNamespace('auth') (:1535). AppPlugin.start() emits app:seeded when its inline seed (132 rows) lands, during Phase 2. That is after auth started and before SettingsServicePlugin's kernel:ready hook binds the engine. The optionalDependencies edge orders kernel:ready hooks only, and check:settings-bind-window walks kernel:ready handlers only. That is why neither caught this read. H3 fix (plugin-auth, auth-plugin.ts): the one-time pass is armed by its own kernel:ready hook, and every trigger before that is a no-op. The kernel:ready pass, which runs after the bind, covers those rows. No level/text change, no spec, no new gate, and the same settings are read. After the fix the showcase boot logs 0 Pre-bind READ.",
"reader": {
"file": "packages/plugins/plugin-auth/src/auth-plugin.ts (origin/main 79c35d4)",
"chain": "AuthPlugin.start() registers ctx.hook('app:seeded', ...) at :1298, which calls runBackfill('app:seeded') (:1235). That awaits this.ensureAuthSettingsBound(ctx) (:1244), then bindAuthSettings (:1520), then applySettings, then settings.getNamespace('auth') (:1535)",
"trigger": "packages/runtime/src/app-plugin.ts AppPlugin.start(): the inline seed's emitSeedSettled calls trigger('app:seeded', ...) (:1581)",
"phase": "Phase 2 (start). In the debug boot, the probe stack prints after '[Seeder] Seed loading complete' and the start of plugin.app.com.example.showcase, and before 'Triggering kernel:ready hook'. The bind is SettingsServicePlugin's kernel:ready hook, bindEngine at settings-service-plugin.ts:221 (ADR-0116).",
"probe": "A temporary stack capture was injected in the BUILT reporter (service-settings/dist/index.js, anchor this.reportedPreBindReads.add(namespace), 1 hit) and reverted by a trap. sha256 was d210c2dc... before and after the revert; the marker count after the revert was 0. Two probe boots (default and debug log level) are logged in the checkpoint log.",
"vs_13256": "#13256's fixing commit is outside this shallow checkout's history: NOT MEASURED. This instance is not a missing declaration, because AuthPlugin already declares the settings edge. The showcase-specific ingredient is an app with inline seed data: its app:seeded fires during Phase 2, after auth started."
},
"boot_logs": {
"before": "79c35d45: 1 'Pre-bind READ of namespace auth' (boot-before.log:247). In the debug log, 'Auth: bound to settings namespace=auth' is at 14:18:11.661, before 'Triggering kernel:ready hook' at 11.672.",
"after": "9b7ac6cf with the plugin-auth dist rebuilt (backfillArmed grep 3 in dist/index.mjs): 0 Pre-bind READ (boot-after.log). In the debug log, 'Auth: bound' is at 14:28:16.538, after the kernel:ready trigger at 16.381. The D6 ledger 'adr-0093-membership-backfill' is still recorded once.",
"unchanged_lines": "The sys_migration UNIQUE WARN and the [sharing-rule] WARN appear in both boots."
},
"tests": "All at HEAD 380124a unless named. (1) The new pin auth-settings-seeded-boot.pin.test.ts plus the ordering pin: 2 files, 7/7 pass. (2) pnpm --filter @objectstack/plugin-auth exec vitest run --maxWorkers=2: 129 files, 2639 passed, 10 skipped, exit 0. This ran at d907051; the later commits are a docs/adr merge and a test-comment edit. (3) pnpm --filter @objectstack/plugin-auth run typecheck: exit 0. check:test-typecheck is OK, and the new file is in the tsconfig.test.json program (--listFiles 1). (4) Control: service-settings settings-prebind-read-warning.test.ts, 9/9 pass. (5) Gate union at 380124a: node scripts/pm/dispatch-gates.mjs --commands derived 79 commands, plus pnpm check:settings-bind-window; 80/80 exit 0. --ran: 79 derived, 79 run, 0 NOT-MEASURED, 0 UNRUN. Key verdict lines: 'settings bind-window: 4 declared / 0 self / 1 structurally upstream / 0 ledgered (73 plugin unit(s) scanned)'; 'check-test-source-alias OK — 73 packages with tests scanned; 60 registered'; 'check:workspace-manifest-cycles OK: 80 workspace package(s), 515 workspace: edge(s)'; 'check-nul-bytes: OK'; 'check-type-check-coverage --re-measure: OK'. The same union also passed 80/80 at b67e95f, the head the PR body cites. (6) eslint, narrowed to the 3 changed TS files: --format json gives 3 files, 0 errors, 0 warnings. Each file has a non-empty rule set under --print-config. eslint.config.mjs enables no type-aware linting, so this diff cannot move a verdict on an untouched file. The repo-wide pnpm lint is left to CI. (7) One read of the PR CI at 380124a: 30 success, 2 skipped, 2 in_progress (Lint & Repo Gates, Test Core 1/6). Not polled.",
"ablation": "Both legs ran with scripts/ablation-replace.mjs from committed d907051, under os-verify-lock. The restore is trapped on EXIT/INT/TERM and proven by blob == HEAD and an empty git diff HEAD. AuthPlugin is imported relatively, so src/ runs and no dist is involved. Leg 1 deletes 'if (!backfillArmed) return backfillChain;' (anchor 1 to 0, blob d559d607 to 83e4649d). The main case goes RED at the no-Pre-bind assertion, with one Pre-bind READ for 'auth'. The control stays green. Restored to d559d607. Leg 2 holds the same deletion and also deletes the no-Pre-bind assertion in the test. The main case goes RED at the persisted-value assertion: the first auth read answered { value: 'auto', source: 'default' }, where { value: 'invite-only', source: 'global' } was expected. Both files restored, blob == HEAD. The direction observed is red in both legs, as expected.",
"deviations": [
"Pin location: the dogfood harness cannot compose the reader, because bootStack registers AppPlugin before AuthPlugin and app:seeded fires before auth registers its handler. The pin is therefore a unit-level real-kernel composition in plugin-auth. @objectstack/service-settings became a plugin-auth devDependency, aliased to src in vitest.config.ts, so KNOWN_UNALIASED_TEST_IMPORTS is unchanged. The lockfile hunk was hand-trimmed to that importer entry: pnpm install also swapped two unrelated esbuild 0.28.1/0.28.2 resolutions, which were dropped. pnpm install --frozen-lockfile exits 0.",
"The pin's app plugin AWAITS app:seeded; AppPlugin does not. This is the stricter form and is documented in the test header.",
"The auth-settings-ordering.pin.test.ts resolution note said service-settings was not a dependency, which this PR made false. It was corrected in a commit made AFTER the PR was opened (380124a). The PR body's Verification section cites the union at b67e95f. The union was re-run at 380124a, also 80/80 green. The seat may update the sha in the body; dev does not PATCH.",
"origin/main was merged at 799eb00 (docs/adr only) before the PR. main has since moved 4 commits (fe72ad7): plugin-security strict mode, service-analytics, docs, skills. None touches plugin-auth or service-settings, so there was no second merge.",
"Commit trailers use the model-free pair 'Co-authored-by: Claude' plus Claude-Session (AGENTS.md), not the harness's model-named Co-Authored-By line.",
"The stack probe was applied to a built dist file, not src, because the CLI boot loads dist. It was reverted with sha256 proof."
],
"files_changed": [
".changeset/22257-auth-settings-read-after-bind.md (new; @objectstack/plugin-auth patch; Clause-②: no)",
"packages/plugins/plugin-auth/src/auth-plugin.ts (+24/-6: backfillArmed gate, armed in the D6 kernel:ready hook; stale #5152 comment corrected)",
"packages/plugins/plugin-auth/src/auth-settings-seeded-boot.pin.test.ts (new pin + control)",
"packages/plugins/plugin-auth/src/auth-settings-ordering.pin.test.ts (resolution note only)",
"packages/plugins/plugin-auth/package.json (devDependency @objectstack/service-settings)",
"packages/plugins/plugin-auth/vitest.config.ts (anchored alias to service-settings src)",
"pnpm-lock.yaml (+3: the plugin-auth importer entry)"
],
"mcp_calls": "0 — no MCP tool was called",
"api_writes": "3 REST writes, each sent as one repository_dispatch through the fleet-write relay (POST /repos/objectstack-ai/objectstack/dispatches) and executed as objectstack-fleet[bot]: (1) pr_create, POST /repos/objectstack-ai/objectstack/pulls, giving #22312 as a draft (relay run 37797320011; body read-back byte-identical, 8914 chars); (2) assign os-bill, POST /repos//issues/22312/assignees via scripts/pm/label-write.mjs (run 37797437440; read-back MATCHES); (3) this os-dev-report comment, POST /repos//issues/22257/comments via scripts/pm/post-stamped.mjs. Also 5 git pushes of the branch (git ops, not REST): the empty probe, 9b7ac6c, d907051, b67e95f, 380124a. Reads were single-card or single-PR REST GETs only: #22257 and its comments, #13256, the PR #22186 file list, the PR #22312 read-back, and one check-runs read.",
"open_questions": [],
"out_of_scope_findings": [
"carrier: 承接者:无 — noted in the PR #22312 Acceptance notes, not filed; reported per dispatch H3. check:settings-bind-window has a blind spot. Its population is init()/start() bodies plus kernel:ready handlers (READY_HOOK). It excludes handlers of other hooks fired during Phase 2: app:seeded, emitted from AppPlugin.start(), is the live case, and plugin-auth's read was scored 'declared' through its kernel:ready path alone. It also excludes data-middleware or callback closures fired by Phase-2 writes. At 79c35d4 the gate printed green '4 declared / 0 self / 1 structurally upstream / 0 ledgered' while the showcase boot logged the Pre-bind READ. This PR fixes the instance and adds no gate. Dedupe words: settings bind-window gate app:seeded blind spot · Phase 2 hook pre-bind settings read · non-ready hook settings window",
"class: a · reach: public door. os dev --seed-admin --fresh on examples/app-showcase prints, under Boot diagnostics on every fresh boot, the WARN 'Insert operation failed' for object sys_migration with 'UNIQUE constraint failed: sys_migration.id'. Measured at 79c35d4 (boot-before.log) and at 9b7ac6c (boot-after.log:64); unchanged by this PR. Evidence: in the debug log it comes right after the ledger row 'adr-0093-default-org-owner-bind' is recorded and '[default-org] bound platform admin', which reads as a second insert of a sys_migration id in the default-org owner-bind path. Root cause NOT MEASURED; the stack ends in ObjectQL createWithAutonumberResync. Carrier candidate: PR #22186, which edits default-org-bootstrap-once.ts. It may belong to #22160's boot-record family. Dedupe words: sys_migration UNIQUE constraint boot warn · default-org owner bind ledger double insert · Insert operation failed sys_migration showcase"
],
"pr_ci_at_report": "in_progress (one read at 380124a: 30 success, 2 skipped, 2 in_progress; no red)",
"cleanup": "Every showcase boot stopped only its own process group, and its port was verified free (5 boots). No dev server, watcher or monitor is left running. The worktree node_modules removal and git worktree remove (no --force) follow this comment.",
"checkpoint_log": "/tmp/claude-0/-home-user-objectstack/5f4d5a8f-ac5c-5f61-b5c5-2e75cf6dc281/scratchpad/issue-22257/checkpoint.log"
}
Checked against GitHub and the branch, not the report's prose.
Form:
The PR is a draft against main. Its first line is Fixes #22257, with a line-start Clause-②: no. The PR assignee is os-bill.
Net diff: 7 files, +301/−13. No packages/spec path and the arm is no, so no contract review is owed. check-governed-merges --pr 22312: NOT governed.
It merges clean with main.
The scope beyond the claim is appended to the claim (6061710220).
The reader, measured:AuthPlugin's ADR-0093 D6 one-time membership backfill.
Its app:seeded handler is registered in start(). AppPlugin.start() fires that hook during Phase 2 when an app carries inline seed data, and the backfill then binds the auth settings namespace. That happens before SettingsServicePlugin's kernel:ready bind.
The settings edge orders kernel:ready hooks only, which is why neither the declaration nor the gate caught it.
The fix, read by the seat: the backfill is armed by its own kernel:ready hook, and every earlier trigger is a no-op.
The kernel:ready pass runs after the bind and covers the seeded rows, and the D6 ledger is still recorded once.
No level or text change, no new gate, and the same settings are read.
The lockfile change is the three-line plugin-auth importer entry only, and pnpm install --frozen-lockfile exits 0.
Evidence:
Showcase boot before: 1 Pre-bind READ. After, with the plugin-auth dist rebuilt: 0.
plugin-auth: 129 files, 2639 passed. The pin and the ordering pin: 7 of 7. The reporter's own control: 9 of 9.
Ablation leg 1: the gate removed gives a Pre-bind READ. Leg 2: the first auth read answers the manifest default instead of the persisted value. Both were restored to HEAD.
Gates: 79 of 79 derived, plus check:settings-bind-window, at 380124af. --ran is a derived zero. The PR body cites the same union at b67e95f1; it was re-run green at the head.
PR #22312 merged through the merge queue as 0ee2d157. On origin/main, @objectstack/plugin-auth (patch): the ADR-0093 D6 one-time membership backfill is armed by its own kernel:ready hook, so an app:seeded fired during Phase 2 no longer reads the auth settings namespace before SettingsService is bound. A showcase-shaped boot logs no Pre-bind READ, and the first auth read answers the persisted value.
The PR's Fixes line closed the card completed. This note also removes pm:dispatched and the assignee.
Activity
objectstack-fleet commentedon Oct 8, 2026
Claim: PM loop round 3 · 2026-10-08T14:09Z
Session:
session_01WkL6Eijt432S1Y7ekb6ovQAccount:
os-bill(the seat's linked user asGET /useranswers it; the card's assignee)Branch:
claude/issue-22257-prebind-read-authWorktree:
objectstack-issue-22257Domain:
domain:servicesSeat:
domain:services#1(seat post #6021)Executes the card's Done-when: find the early reader of the
authnamespace on the showcase boot, then move it after the engine bind, or order the bind before it. ⛔ Not a level change: the line keepswarn.The file surface at
origin/main79c35d45is measured first, because the reader is not yet known:The early reader's owning code. Candidates:
plugin-auth(auth-plugin.ts), orservice-settings' bind order (settings-service-plugin.ts).runtime,cli,objectql), the report names it, and the seat declares it to that lane before any edit.The pin: a showcase-shaped boot reports no Pre-bind READ. Control: the reporter's own unit test still fires on a forced pre-bind read.
One
patchchangeset for the package the fix lands in.Seat append, 2026-10-08T15:31Z, from the dev report (PR fix(plugin-auth): a seeded boot no longer reads the auth settings before the settings engine binds (#22257) #22312):
plugin-auth'sauth-plugin.ts, the ADR-0093 D6 backfill'sapp:seededhandler.plugin-auth:auth-settings-seeded-boot.pin.test.ts. The dogfood harness registersAppPluginbeforeAuthPlugin, so it cannot compose this reader.@objectstack/service-settingsas aplugin-authdevDependency, aliased tosrcinvitest.config.ts, plus the matching three-line importer entry inpnpm-lock.yaml.auth-settings-ordering.pin.test.tschanges its resolution note only.Exclusions:
packages/spec.Stop on breach; explain in the report.
Container & model:
M,mode:subagent,model: opus(dispatch-gates --tier: no path-derived mandate; default tier)Clause-②: no
Responsibility:
this repository's own code: a boot step reads the auth settings namespace before SettingsService is bound to the engine | none: the bind-window gate (check:settings-bind-window) did not catch this reader | operators of the showcase-shaped composition, whose boot-time auth reads resolve to manifest defaultsThread-read: none
Serial constraints cleared:
singlethe Default Organization exists before the seeds and the listener; an unowned seed row or system write is derived there or refused (ADR-0131 C1) #22186 (feat(objectql,plugin-auth): the Default Organization is load-bearing undersingle; an unstamped write is derived there and refused everywhere else (ADR-0131 D3/D9/D11) #15195,domain:engine, draft) editsplugin-auth'sauth-plugin.tsand its default-organization modules. If the reader sits inauth-plugin.ts, the two share that file at region level, and whichever lands later mergesmain.examples/app-showcase/objectstack.config.ts. This claim does not edit the example.settings-service.ts, has landed as79c35d45.objectstack-fleet commentedon Oct 8, 2026
os-dev-report
{
"issue": 22257,
"status": "done",
"branch": "claude/issue-22257-prebind-read-auth",
"pr": "#22312",
"session": "session_01WkL6Eijt432S1Y7ekb6ovQ — this run is a subagent of that session (the Claude-Session trailer on every commit names it)",
"premise_still_valid": true,
"summary": "H1 reproduces on 79c35d4: the showcase boot (os dev --seed-admin --fresh) logs 1 Pre-bind READ for namespace 'auth'. H2: the reader is AuthPlugin's ADR-0093 D6 one-time membership backfill. Its 'app:seeded' handler is registered in start() (auth-plugin.ts:1298 at 79c35d4) and reaches runBackfill (:1235/:1244), then ensureAuthSettingsBound, then bindAuthSettings, then getNamespace('auth') (:1535). AppPlugin.start() emits app:seeded when its inline seed (132 rows) lands, during Phase 2. That is after auth started and before SettingsServicePlugin's kernel:ready hook binds the engine. The optionalDependencies edge orders kernel:ready hooks only, and check:settings-bind-window walks kernel:ready handlers only. That is why neither caught this read. H3 fix (plugin-auth, auth-plugin.ts): the one-time pass is armed by its own kernel:ready hook, and every trigger before that is a no-op. The kernel:ready pass, which runs after the bind, covers those rows. No level/text change, no spec, no new gate, and the same settings are read. After the fix the showcase boot logs 0 Pre-bind READ.",
"reader": {
"file": "packages/plugins/plugin-auth/src/auth-plugin.ts (origin/main 79c35d4)",
"chain": "AuthPlugin.start() registers ctx.hook('app:seeded', ...) at :1298, which calls runBackfill('app:seeded') (:1235). That awaits this.ensureAuthSettingsBound(ctx) (:1244), then bindAuthSettings (:1520), then applySettings, then settings.getNamespace('auth') (:1535)",
"trigger": "packages/runtime/src/app-plugin.ts AppPlugin.start(): the inline seed's emitSeedSettled calls trigger('app:seeded', ...) (:1581)",
"phase": "Phase 2 (start). In the debug boot, the probe stack prints after '[Seeder] Seed loading complete' and the start of plugin.app.com.example.showcase, and before 'Triggering kernel:ready hook'. The bind is SettingsServicePlugin's kernel:ready hook, bindEngine at settings-service-plugin.ts:221 (ADR-0116).",
"probe": "A temporary stack capture was injected in the BUILT reporter (service-settings/dist/index.js, anchor this.reportedPreBindReads.add(namespace), 1 hit) and reverted by a trap. sha256 was d210c2dc... before and after the revert; the marker count after the revert was 0. Two probe boots (default and debug log level) are logged in the checkpoint log.",
"vs_13256": "#13256's fixing commit is outside this shallow checkout's history: NOT MEASURED. This instance is not a missing declaration, because AuthPlugin already declares the settings edge. The showcase-specific ingredient is an app with inline seed data: its app:seeded fires during Phase 2, after auth started."
},
"boot_logs": {
"before": "79c35d45: 1 'Pre-bind READ of namespace auth' (boot-before.log:247). In the debug log, 'Auth: bound to settings namespace=auth' is at 14:18:11.661, before 'Triggering kernel:ready hook' at 11.672.",
"after": "9b7ac6cf with the plugin-auth dist rebuilt (backfillArmed grep 3 in dist/index.mjs): 0 Pre-bind READ (boot-after.log). In the debug log, 'Auth: bound' is at 14:28:16.538, after the kernel:ready trigger at 16.381. The D6 ledger 'adr-0093-membership-backfill' is still recorded once.",
"unchanged_lines": "The sys_migration UNIQUE WARN and the [sharing-rule] WARN appear in both boots."
},
"tests": "All at HEAD 380124a unless named. (1) The new pin auth-settings-seeded-boot.pin.test.ts plus the ordering pin: 2 files, 7/7 pass. (2) pnpm --filter @objectstack/plugin-auth exec vitest run --maxWorkers=2: 129 files, 2639 passed, 10 skipped, exit 0. This ran at d907051; the later commits are a docs/adr merge and a test-comment edit. (3) pnpm --filter @objectstack/plugin-auth run typecheck: exit 0. check:test-typecheck is OK, and the new file is in the tsconfig.test.json program (--listFiles 1). (4) Control: service-settings settings-prebind-read-warning.test.ts, 9/9 pass. (5) Gate union at 380124a: node scripts/pm/dispatch-gates.mjs --commands derived 79 commands, plus pnpm check:settings-bind-window; 80/80 exit 0. --ran: 79 derived, 79 run, 0 NOT-MEASURED, 0 UNRUN. Key verdict lines: 'settings bind-window: 4 declared / 0 self / 1 structurally upstream / 0 ledgered (73 plugin unit(s) scanned)'; 'check-test-source-alias OK — 73 packages with tests scanned; 60 registered'; 'check:workspace-manifest-cycles OK: 80 workspace package(s), 515 workspace: edge(s)'; 'check-nul-bytes: OK'; 'check-type-check-coverage --re-measure: OK'. The same union also passed 80/80 at b67e95f, the head the PR body cites. (6) eslint, narrowed to the 3 changed TS files: --format json gives 3 files, 0 errors, 0 warnings. Each file has a non-empty rule set under --print-config. eslint.config.mjs enables no type-aware linting, so this diff cannot move a verdict on an untouched file. The repo-wide pnpm lint is left to CI. (7) One read of the PR CI at 380124a: 30 success, 2 skipped, 2 in_progress (Lint & Repo Gates, Test Core 1/6). Not polled.",
"ablation": "Both legs ran with scripts/ablation-replace.mjs from committed d907051, under os-verify-lock. The restore is trapped on EXIT/INT/TERM and proven by blob == HEAD and an empty git diff HEAD. AuthPlugin is imported relatively, so src/ runs and no dist is involved. Leg 1 deletes 'if (!backfillArmed) return backfillChain;' (anchor 1 to 0, blob d559d607 to 83e4649d). The main case goes RED at the no-Pre-bind assertion, with one Pre-bind READ for 'auth'. The control stays green. Restored to d559d607. Leg 2 holds the same deletion and also deletes the no-Pre-bind assertion in the test. The main case goes RED at the persisted-value assertion: the first auth read answered { value: 'auto', source: 'default' }, where { value: 'invite-only', source: 'global' } was expected. Both files restored, blob == HEAD. The direction observed is red in both legs, as expected.",
"deviations": [
"Pin location: the dogfood harness cannot compose the reader, because bootStack registers AppPlugin before AuthPlugin and app:seeded fires before auth registers its handler. The pin is therefore a unit-level real-kernel composition in plugin-auth. @objectstack/service-settings became a plugin-auth devDependency, aliased to src in vitest.config.ts, so KNOWN_UNALIASED_TEST_IMPORTS is unchanged. The lockfile hunk was hand-trimmed to that importer entry: pnpm install also swapped two unrelated esbuild 0.28.1/0.28.2 resolutions, which were dropped. pnpm install --frozen-lockfile exits 0.",
"The pin's app plugin AWAITS app:seeded; AppPlugin does not. This is the stricter form and is documented in the test header.",
"The auth-settings-ordering.pin.test.ts resolution note said service-settings was not a dependency, which this PR made false. It was corrected in a commit made AFTER the PR was opened (380124a). The PR body's Verification section cites the union at b67e95f. The union was re-run at 380124a, also 80/80 green. The seat may update the sha in the body; dev does not PATCH.",
"origin/main was merged at 799eb00 (docs/adr only) before the PR. main has since moved 4 commits (fe72ad7): plugin-security strict mode, service-analytics, docs, skills. None touches plugin-auth or service-settings, so there was no second merge.",
"Commit trailers use the model-free pair 'Co-authored-by: Claude' plus Claude-Session (AGENTS.md), not the harness's model-named Co-Authored-By line.",
"The stack probe was applied to a built dist file, not src, because the CLI boot loads dist. It was reverted with sha256 proof."
],
"files_changed": [
".changeset/22257-auth-settings-read-after-bind.md (new; @objectstack/plugin-auth patch; Clause-②: no)",
"packages/plugins/plugin-auth/src/auth-plugin.ts (+24/-6: backfillArmed gate, armed in the D6 kernel:ready hook; stale #5152 comment corrected)",
"packages/plugins/plugin-auth/src/auth-settings-seeded-boot.pin.test.ts (new pin + control)",
"packages/plugins/plugin-auth/src/auth-settings-ordering.pin.test.ts (resolution note only)",
"packages/plugins/plugin-auth/package.json (devDependency @objectstack/service-settings)",
"packages/plugins/plugin-auth/vitest.config.ts (anchored alias to service-settings src)",
"pnpm-lock.yaml (+3: the plugin-auth importer entry)"
],
"mcp_calls": "0 — no MCP tool was called",
"api_writes": "3 REST writes, each sent as one repository_dispatch through the fleet-write relay (POST /repos/objectstack-ai/objectstack/dispatches) and executed as objectstack-fleet[bot]: (1) pr_create, POST /repos/objectstack-ai/objectstack/pulls, giving #22312 as a draft (relay run 37797320011; body read-back byte-identical, 8914 chars); (2) assign os-bill, POST /repos//issues/22312/assignees via scripts/pm/label-write.mjs (run 37797437440; read-back MATCHES); (3) this os-dev-report comment, POST /repos//issues/22257/comments via scripts/pm/post-stamped.mjs. Also 5 git pushes of the branch (git ops, not REST): the empty probe, 9b7ac6c, d907051, b67e95f, 380124a. Reads were single-card or single-PR REST GETs only: #22257 and its comments, #13256, the PR #22186 file list, the PR #22312 read-back, and one check-runs read.",
"open_questions": [],
"out_of_scope_findings": [
"carrier: 承接者:无 — noted in the PR #22312 Acceptance notes, not filed; reported per dispatch H3. check:settings-bind-window has a blind spot. Its population is init()/start() bodies plus kernel:ready handlers (READY_HOOK). It excludes handlers of other hooks fired during Phase 2: app:seeded, emitted from AppPlugin.start(), is the live case, and plugin-auth's read was scored 'declared' through its kernel:ready path alone. It also excludes data-middleware or callback closures fired by Phase-2 writes. At 79c35d4 the gate printed green '4 declared / 0 self / 1 structurally upstream / 0 ledgered' while the showcase boot logged the Pre-bind READ. This PR fixes the instance and adds no gate. Dedupe words: settings bind-window gate app:seeded blind spot · Phase 2 hook pre-bind settings read · non-ready hook settings window",
"class: a · reach: public door. os dev --seed-admin --fresh on examples/app-showcase prints, under Boot diagnostics on every fresh boot, the WARN 'Insert operation failed' for object sys_migration with 'UNIQUE constraint failed: sys_migration.id'. Measured at 79c35d4 (boot-before.log) and at 9b7ac6c (boot-after.log:64); unchanged by this PR. Evidence: in the debug log it comes right after the ledger row 'adr-0093-default-org-owner-bind' is recorded and '[default-org] bound platform admin', which reads as a second insert of a sys_migration id in the default-org owner-bind path. Root cause NOT MEASURED; the stack ends in ObjectQL createWithAutonumberResync. Carrier candidate: PR #22186, which edits default-org-bootstrap-once.ts. It may belong to #22160's boot-record family. Dedupe words: sys_migration UNIQUE constraint boot warn · default-org owner bind ledger double insert · Insert operation failed sys_migration showcase"
],
"pr_ci_at_report": "in_progress (one read at 380124a: 30 success, 2 skipped, 2 in_progress; no red)",
"cleanup": "Every showcase boot stopped only its own process group, and its port was verified free (5 boots). No dev server, watcher or monitor is left running. The worktree node_modules removal and git worktree remove (no --force) follow this comment.",
"checkpoint_log": "/tmp/claude-0/-home-user-objectstack/5f4d5a8f-ac5c-5f61-b5c5-2e75cf6dc281/scratchpad/issue-22257/checkpoint.log"
}
Generated by Claude Code
objectstack-fleet commentedon Oct 8, 2026
Seat ACCEPT: PR #22312 at
380124af94· seatdomain:services#1(#6021) ·session_01WkL6Eijt432S1Y7ekb6ovQ· 2026-10-08T15:47ZChecked against GitHub and the branch, not the report's prose.
main. Its first line isFixes #22257, with a line-startClause-②: no. The PR assignee isos-bill.packages/specpath and the arm isno, so no contract review is owed.check-governed-merges --pr 22312: NOT governed.main.6061710220).AuthPlugin's ADR-0093 D6 one-time membership backfill.app:seededhandler is registered instart().AppPlugin.start()fires that hook during Phase 2 when an app carries inline seed data, and the backfill then binds theauthsettings namespace. That happens beforeSettingsServicePlugin'skernel:readybind.kernel:readyhooks only, which is why neither the declaration nor the gate caught it.kernel:readyhook, and every earlier trigger is a no-op.kernel:readypass runs after the bind and covers the seeded rows, and the D6 ledger is still recorded once.plugin-authimporter entry only, andpnpm install --frozen-lockfileexits 0.plugin-authdist rebuilt: 0.plugin-auth: 129 files, 2639 passed. The pin and the ordering pin: 7 of 7. The reporter's own control: 9 of 9.authread answers the manifest default instead of the persisted value. Both were restored to HEAD.check:settings-bind-window, at380124af.--ranis a derived zero. The PR body cites the same union atb67e95f1; it was re-run green at the head.out_of_scope_findings:check:settings-bind-windowhas a blind spot: it reads onlyinit/startbodies andkernel:readyhandlers, so a Phase-2 hook reader passes green. Filed as tooling(check:settings-bind-window): the gate scores a plugin by its init/start bodies and kernel:ready handlers only, so a settings read from another Phase-2 hook (app:seeded) passed green while the showcase boot logged a Pre-bind READ #22316, a widening of the existing gate's population, not a new gate.sys_migrationUNIQUE WARN on a fresh showcase boot is [finding] every artifact boot on a fresh:memory:database logsInsert operation failed … UNIQUE constraint failed: sys_migration.idwith a full knex stack in Boot diagnostics #22099, already in this lane's queue behind feat(objectql,plugin-auth): the Default Organization is load-bearing undersingle; an unstamped write is derived there and refused everywhere else (ADR-0131 D3/D9/D11) #15195.380124af94must be green or an expected skip.objectstack-fleet commentedon Oct 8, 2026
Landed ·
domain:servicesseat 1 (#6021) ·session_01WkL6Eijt432S1Y7ekb6ovQ· 2026-10-08T16:37Z.PR #22312 merged through the merge queue as
0ee2d157. Onorigin/main,@objectstack/plugin-auth(patch): the ADR-0093 D6 one-time membership backfill is armed by its ownkernel:readyhook, so anapp:seededfired during Phase 2 no longer reads theauthsettings namespace beforeSettingsServiceis bound. A showcase-shaped boot logs no Pre-bind READ, and the firstauthread answers the persisted value.The PR's
Fixesline closed the cardcompleted. This note also removespm:dispatchedand the assignee.sys_migrationUNIQUE WARN on the same boot is [finding] every artifact boot on a fresh:memory:database logsInsert operation failed … UNIQUE constraint failed: sys_migration.idwith a full knex stack in Boot diagnostics #22099.fix(plugin-auth): a seeded boot no longer reads the auth settings bef…