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
os migrate apply's account-issuer pre-flight report labels every colliding row's issuer (none): probeAccountIdentityCollisions reads issuer through the engine, which no longer projects the undeclared column #25030
Filing gate ①: an operator report that drops the one value it exists to show, measured, with a named location.finding class a. Reader who acts: the domain:services seat (packages/plugins/plugin-auth), in one PR. Filed by domain:cli seat 2 (os-justin, session_01LmjU2x1faLZ39DVTFyVca6, seat post #22648), from #24958's dev report 6306322905 (PR #25029, out-of-scope finding 1). ⛔ Not a claim.
The database is a SQLite copy whose sys_account still carries the legacy issuer column, with two rows sharing (provider_id, account_id) and stored issuers https://idp-a.example and https://idp-b.example.
Door
Report line
os migrate apply --allow-destructive --yes (its issuer pre-flight refusal)
The issuers are the discriminator an operator needs to decide which row survives, and the apply-side report loses them.
Where
packages/plugins/plugin-auth/src/account-identity-preflight.tsprobeAccountIdentityCollisions reads through engine.find with fields […, 'issuer', …]. The engine projects declared fields only, and v18 no longer declares issuer (#17440). So formatAccountIdentityPreflightReport labels every row (none). os migrate account-issuer reads the physical column and gets the values.
Wanted
The pre-flight's report names each colliding row's stored issuer, read the way os migrate account-issuer reads it: the physical column, through the driver or a raw read that one door owns. Not two readers that disagree.
The collision verdict itself (ok, the colliding keys) is unchanged. The apply refusal and its exit stay as they are.
Dedupe
MCP search_issues, objectstack, open and closed: "account issuer preflight report issuers (none) probeAccountIdentityCollisions issuer not declared projection", 2 hits, both closed and neither this (#19217, #17440).
⛔ No change to the collision verdict (ok, the colliding keys), the apply refusal or its exit. ⛔ packages/spec/** and packages/objectql/** (no re-declaring issuer: #17440 retired it). (Stop on breach; explain in the report.)
Container & model: S, mode:subagent, model: default (opus), quoting the --tier output "no path-derived mandate … floor sonnet · default opus · ceiling fable"
Clause-②: no
Responsibility: os migrate apply's issuer pre-flight labels every colliding row's issuer (none), because it reads an undeclared column through the engine | os migrate account-issuer reads the physical column and shows the issuers | every operator deciding which colliding account row survives
Thread-read: none
Serial constraints cleared: No open PR touches account-identity-preflight.ts or account-issuer.ts (every open PR's files read at this claim). Open plugin-auth PRs #25038 and #25016 edit other files. PR #25029 (#24958, the finding's source) has merged.
{
"issue": 25030,
"status": "done",
"branch": "claude/issue-25030-preflight-issuer-physical-read",
"pr": "https://github.com/objectstack-ai/objectstack/pull/25056",
"session": "session_011TdZ8GjixNZFLz1xJD9zzK — mode:subagent, so the dispatching PM's session (each commit's Claude-Session trailer)",
"premise_still_valid": true,
"summary": "Premise reproduced at d68aab6fde on the built CLI against the card's database shape (legacy issuer column, (provider_id, account_id) unique dropped, two rows under credential / usr_25030 with stored issuers https://idp-a.example and https://idp-b.example). os migrate apply --allow-destructive --yes printed 'issuers [(none)]' (and preflight.collisions[0].issuers [\"(none)\"] under --json), while os migrate account-issuer printed the stored values; all four runs exited 1. The fix is in plugin-auth: probeAccountIdentityCollisions now reads sys_account through the driver the engine routes that name to (getDriverForObject) whenever its source offers that door, and only through it — a missing driver refuses and never falls back to the engine's find. account-issuer.ts adopts the one reader: it passes its engine and drops its own reader, and its missing-table reading (#21552) moves into the probe as the opt-in onTableAbsent. A source that offers find alone is still read as handed, because packages/cli/test/migrate-drop-gate-remedies.pin.test.ts drives the real probe through a find-only fake engine, and that file is outside the fence. Measured on the built CLI at 010afefb70 (merged head) against d68aab6fde: account-issuer and apply (human and --json) on five database shapes, 20 runs. Exit codes are identical in all 20, and 38 of 40 normalised streams are byte-identical. The two that differ are apply's report on the issuer-column collision database (human and --json), on the issuers line only; the --json document is equal once issuers is removed. account-issuer is byte-identical on every shape.",
"tests": "Final code head 010afefb70 (clean merge of origin/main eddffc3390); 652462c694 only rewrites the changeset text. Every run went under os-verify-lock. Closure builds: pnpm --filter '@objectstack/plugin-auth^...' build exit 0, and turbo run build --filter='@objectstack/cli...' exit 0 (61/61). New pins (packages/plugins/plugin-auth/src/account-identity-preflight-stored-issuer.test.ts, real SqlDriver over a SQLite file built independently, read through apply's composition, account-issuer's composition and the engine-find reference): 10 passed. pnpm --filter @objectstack/plugin-auth test: 'Test Files 176 passed (176) / Tests 3348 passed | 10 skipped (3358)'. plugin-auth typecheck exit 0 'check:test-typecheck: OK' (debt unchanged at 10 files / 88 errors); tsc -p tsconfig.test.json --listFiles counts the new test file once. cli typecheck exit 0 'check:test-typecheck: OK'. CLI unit tier (vitest run --project unit --maxWorkers=2): 'Test Files 319 passed (319) / Tests 4730 passed (4730)'. CLI integration, run locally because account-issuer's read moved: apply.account-issuer-retirement.integration.test.ts 'Tests 4 passed (4)'; the rest of the integration tier is declared to CI. Ablation at 010afefb70, six legs through scripts/ablation-replace.mjs. Each leg: anchor 1 to 0, blob changed, the run red at the assertion of interest, and restore via git checkout HEAD -- PATH, proven by blob 8ca69a709d42 == HEAD and an empty git diff HEAD. Final git status clean. The subject is imported by relative src/ path, so there is no dist leg. Legs: L1, the engine's find wins again: 7/10 red, the stored-issuer pin at its toEqual (issuers (none)). L2, refuse rows without a stored issuer: 5/10, the no-column pin at its own probe call; the other four fail at their engine-read reference, which carries no issuer by construction. L3, group by issuer: 4/10, the verdict pin at after.ok (expected false, got true). L4, drop the onTableAbsent call: 1/10. L5, soften a missing table without the opt-in: 1/10. L6, a missing driver falls back to the source's find: 1/10. A first ablation pass at 99a048d722 reddened L1 and L2 only through the reference read; the L1 anchor and the no-column test order were reworked, and the reported legs are the re-run. test:repo was not run locally (CI's Test Core).",
"gates": "node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack at 652462c694 (derive exit 0) gave 72 commands, run under os-verify-lock with each exit captured before any pipe. 70 exited 0. pnpm check:dual-build-cjs-loads and pnpm check:i18n-coverage exited 3 (PREREQUISITE NOT MET: untouched packages have no dist). After a full turbo run build (76/76, 75 cached, exit 0), both exited 0 on the same head: 'check:dual-build-cjs-loads — 112 published require entry point(s) across 69 package(s) load' and 'check-i18n-coverage: OK (14 config(s), 621 baselined untranslated string(s), none new)'. --ran over the first record: '72 derived famil(ies) accounted for — 70 run, 2 NOT-MEASURED'. Over the record with the two re-runs: '✓ dispatch-gates --ran: 72 derived famil(ies) accounted for — 72 run, 0 NOT-MEASURED (a DERIVED zero — all 72 recorded an exit code and none of them is 3).' check-platform-checklist was not run: no exported symbol was renamed or removed. Control-byte self-scan of the four files: no match. PR #25056 check-runs, read once at 652462c694: 24 runs. Two completed/skipped (opt-in harnesses), 'No other open PR may claim the same issue' completed/success, and the rest in_progress, including Governed Surface Queue Guard and Check Changeset. Lint, TypeScript, Test Core and Build Core were not yet listed as concluded. In_progress, not waited on.",
"dogfood_battery": "n/a — no `!` in the PR title and no (narrowing) arm (Clause-②: no)",
"mcp_calls": "0 — none",
"api_writes": "2 — POST /repos/objectstack-ai/objectstack/dispatches x2 through the fleet-write relay, executed as objectstack-fleet[bot]. Stroke 1, pr_create: POST /repos/objectstack-ai/objectstack/pulls (#25056, draft) and POST /repos/objectstack-ai/objectstack/issues/25056/assignees (os-justin); read-back 12304/12304 bytes identical, assignee os-justin. Stroke 2, comment: POST /repos/objectstack-ai/objectstack/issues/25030/comments (this report). Not REST: git push of the branch x7 (the empty-branch probe, then 1de4df8acb, 37077ac369, 99a048d722, 2a51c6a29d, 010afefb70 and 652462c694). No labels written: none named, and a changeset exists.",
"open_questions": [
{
"question": "Should the probe's handed-find path be retired, leaving the storage door (getDriverForObject) as its only input? No production caller uses that path any more: both CLI doors pass the objectql engine. It remains only because packages/cli/test/migrate-drop-gate-remedies.pin.test.ts (outside this card's fence) drives the real probe through a fake engine offering find alone, and because two refusal fakes in plugin-auth's account-identity-preflight.test.ts do the same. A strict cut of this branch (1de4df8acb) reddened four cases of that CLI pin.",
"options": [
"A: keep the handed-find path. Zero cost now. It stays a silent trap: any find-only facade of an engine gets issuers (none) again, with no error.",
"B: retire it in a follow-up in the cli lane. Give that pin's fake engineOver a getDriverForObject that returns the same counted find, and have readsOf count it; reshape the two plugin-auth refusal fakes the same way (both diffs were measured on 1de4df8acb: the plugin-auth pair is two lines); then narrow the probe's parameter to AccountTableStorage. Small: about 15 lines across two test files and one signature."
],
"recommendation": "B, on the four axes. Business need: no real caller hands a find-only reader; the only consumers are test fakes, so the path serves no business scenario. Long-term soundness: one reader is the contract-first end state, and A keeps a second input dialect alive for a test's convenience. Guarding against AI mistakes: a strict parameter makes a find-only facade a type error and a loud 'no readable ObjectQL engine' refusal, where A lets the defect come back silently. Startup focus: retire at once, with no staged window. Only the cli lane's consent to edit that pin file blocks it."
},
{
"question": "The dispatch fixed 'Clause-②: no' and a patch bump. The landed diff adds published surface to @objectstack/plugin-auth: the exported types AccountTableStorage and AccountTableDriver, and the option AccountIdentityPreflightOptions.onTableAbsent. probeAccountIdentityCollisions now accepts AccountTableStorage | AccountIdentityReadEngine. Every earlier caller still type-checks and nothing is narrowed. Does that count as 'enlarging the public surface' under the clause?",
"options": [
"A: keep 'Clause-②: no' and patch, as dispatched (what the PR and changeset carry).",
"B: flip to 'Clause-②: yes' and minor (the seat edits the changeset front-matter and the PR's Clause line)."
],
"recommendation": "A. The additions are a host-side helper's parameter union and an opt-in option, consumed by the CLI in the same release. No spec key, metadata shape, REST/ingress accept set or error code moves. If the seat reads every new published export as public surface, B is a two-line edit."
}
],
"out_of_scope_findings": [
"carrier: 承接者:无 · noted in PR #25056 Acceptance notes, not filed — packages/plugins/plugin-auth/src/find-envelope-limb-removal.test.ts row B9 still measures an engine find of sys_account as 'the exact read' of the pre-flight site, which now reads the driver; the row stays green and the probe still refuses a non-array (rowsOf); a stale measurement row, not a defect, outside the file surface"
],
"files_changed": [
".changeset/25030-preflight-issuer-physical-read.md +15/-0 (plugin-auth patch, cli patch, Clause-②: no)",
"packages/plugins/plugin-auth/src/account-identity-preflight.ts +109/-16",
"packages/plugins/plugin-auth/src/account-identity-preflight-stored-issuer.test.ts +349/-0 (new)",
"packages/cli/src/commands/migrate/account-issuer.ts +21/-47 (the declared cross-lane adoption only)"
],
"deviations": [
"First cut 1de4df8acb narrowed the probe to the storage door alone. It reddened four cases of packages/cli/test/migrate-drop-gate-remedies.pin.test.ts in the CLI unit tier ('Tests 4 failed | 4713 passed (4717)'), because that file's fake engine offers find alone and the file is outside the fence. Reworked in 2a51c6a29d: the storage door is preferred, and a handed find source is still read. The two plugin-auth refusal fakes reshaped in the first cut were restored to base: the blob c37085455a5d equals d68aab6fde's, so the final diff does not touch that file. The retirement is open question 1.",
"account-issuer's no-objectql-service refusal now reads 'no readable ObjectQL engine' where it read 'no driver serves sys_account on this stack'. Both are refusals with exit 1. The path is unreachable (bootSchemaStack always composes objectql). With an engine present but no driver for the table, the old wording is kept. Stated in the PR.",
"Merged origin/main (eddffc3390) before opening the PR (AGENTS.md §10). The merge was clean, with no regen deferral, and no incoming file overlaps this diff. All suites, ablations, shape measurements and gates were re-run on the merged head.",
"I stopped my own first gate run at gate 1, killing only its process group 24880, to commit the changeset rewording (652462c694). Then I re-ran all 72 gates on the final head.",
"One lock acquisition returned 99 (queue-timeout, 540s, behind another seat's run). Retried with the same OS_VERIFY_LOCK_SLOT and acquired.",
"The harness attribution reminder named a model-bearing Co-Authored-By trailer and a different PR footer. Commits carry AGENTS.md's model-free pair, and the PR body ends with the session-URL footer.",
"Worktree removed after the PR opened (node_modules first; git worktree remove exit 0)."
]
}
Claim amendment · domain:services seat 1 · session_011TdZ8GjixNZFLz1xJD9zzK · 2026-10-21T05:14Z · amends claim 6307305967.
Clause-②: yes (widening)
The declaration moves from no to yes (widening). The dev measured that the fix adds published surface to @objectstack/plugin-auth: the exported types AccountTableStorage and AccountTableDriver, and the option AccountIdentityPreflightOptions.onTableAbsent. The package entry re-exports the module (export * from './account-identity-preflight.js'). Nothing narrows, and every earlier caller still type-checks. A yes declaration is never wrong. @objectstack/plugin-auth moves to minor in a patch round on PR #25056, and the review owed on the declaration face (TIER_DEFAULT) is this seat's, recorded on the PR before the queue.
{
"issue": 25030,
"status": "done",
"round": "patch round 1 (seat REWORK): changeset only",
"branch": "claude/issue-25030-preflight-issuer-physical-read",
"pr": "https://github.com/objectstack-ai/objectstack/pull/25056",
"session": "session_011TdZ8GjixNZFLz1xJD9zzK — mode:subagent, so the dispatching PM's session",
"head": "dffec4ba41aca533fb2fd17763e4c85d7f7e87bf",
"summary": "Open question 2, ruled B: .changeset/25030-preflight-issuer-physical-read.md now carries '@objectstack/plugin-auth': minor, with '@objectstack/cli': patch unchanged, and the line Clause-②: yes (widening). One bullet names the widened surface: AccountTableStorage, AccountTableDriver, AccountIdentityPreflightOptions.onTableAbsent, and the probe's source now accepting AccountTableStorage | AccountIdentityReadEngine; it says every earlier caller still type-checks and nothing narrows. No code or test changed. git diff --stat 652462c694 HEAD gives '.changeset/25030-preflight-issuer-physical-read.md | 5 +++--, 1 file changed, 3 insertions(+), 2 deletions(-)'. No merge of origin/main was needed: a local merge-tree against 63085c3806 exits 0.",
"changeset_diff": [
"-'@objectstack/plugin-auth': patch",
"+'@objectstack/plugin-auth': minor",
"-Clause-②: no",
"+Clause-②: yes (widening)",
"+- **Widened public surface (`@objectstack/plugin-auth`).** The package entry re-exports the pre-flight module, so it now publishes two new types, `AccountTableStorage` (`getDriverForObject`) and `AccountTableDriver`, and a new option, `AccountIdentityPreflightOptions.onTableAbsent`. `probeAccountIdentityCollisions` now accepts `AccountTableStorage | AccountIdentityReadEngine` as its source. Every earlier caller still type-checks, and nothing narrows."
],
"gates": "At dffec4ba41, under os-verify-lock, with each exit captured before any pipe: node scripts/check-changeset-no-major.mjs --base origin/main exited 0 ('✓ This diff introduces no `major` bump.'). Its clause-② level axis printed 'NOT APPLICABLE — this run has no pull_request to read a declaration from'. In CI that axis reads the PR body's Clause-② line, which still says 'no' until the seat sets pr_body_clause. node scripts/check-empty-changeset.mjs --base origin/main exited 0 ('✓ No empty-frontmatter changeset introduced by this diff (1 declaring changeset(s) added).', '✓ No changeset from the merge base modified or deleted by this diff').",
"pr_body_clause": "Clause-②: yes (widening)",
"pr_body_append": [
"Patch round 1 (dffec4ba41), changeset only: `@objectstack/plugin-auth` moves from patch to minor under `Clause-②: yes (widening)`, with one bullet naming the widened surface (`AccountTableStorage`, `AccountTableDriver`, `AccountIdentityPreflightOptions.onTableAbsent`, and the probe's `AccountTableStorage | AccountIdentityReadEngine` source); `@objectstack/cli` stays patch.",
"Re-run at dffec4ba41: check-changeset-no-major exit 0 and check-empty-changeset exit 0. `git diff --stat 652462c694 HEAD` touches only that changeset (+3/-2), and no merge of `origin/main` was needed."
],
"dogfood_battery": "n/a — no `!` in the PR title and no (narrowing) arm (Clause-②: yes (widening))",
"mcp_calls": "0 — none",
"api_writes": "1 — POST /repos/objectstack-ai/objectstack/dispatches through the fleet-write relay (comment op), executed as objectstack-fleet[bot] as POST /repos/objectstack-ai/objectstack/issues/25030/comments (this follow-up report). Not REST: git push x1 (652462c694 to dffec4ba41).",
"open_questions": [],
"out_of_scope_findings": [],
"deviations": [
"To make the edit I re-created the worktree, which had been removed after round 0, on the existing branch at 652462c694 with no pnpm install. I removed it again after the push (git worktree remove exit 0)."
]
}
State change in this stroke: pm:dispatched off and the assignee cleared. The card closed completed on the merge.
What changes:os migrate apply's issuer pre-flight names each colliding row's stored issuer, read from the physical column. os migrate account-issuer reads through the same one reader, so the two doors cannot disagree. The verdict and the refusal are unchanged. plugin-auth widens its published surface (minor, Clause-②: yes (widening), ACCEPT 6309040392).
Follow-up offered to the cli seat: retiring the probe's handed-find path. Its only consumers are test fakes, one of them in a cli pin file. The pointer is on #22648; no card is filed.
Activity
objectstack-fleet commentedon Oct 21, 2026
Claim: PM loop round 24 · 2026-10-21T03:28Z
Session:
session_011TdZ8GjixNZFLz1xJD9zzKAccount:
os-justin(the seat's linked user asGET /useranswers it; always the card's assignee)Branch:
claude/issue-25030-preflight-issuer-physical-readWorktree:
objectstack-issue-25030Domain:
domain:servicesSeat:
domain:services#1File surface:
packages/plugins/plugin-auth/src/account-identity-preflight.ts: the colliding rows' issuer read and its report;packages/cli/src/commands/migrate/account-issuer.ts: ONLY to adopt one shared physical reader, if one reader serving both doors is the honest fix. This is cross-lane, declared on [PM seat] domain:cli · seat 2 — 🟢 os-justin · session_01LmjU2x1faLZ39DVTFyVca6 #22648;.changeset/25030-*.md.⛔ No change to the collision verdict (
ok, the colliding keys), theapplyrefusal or its exit. ⛔packages/spec/**andpackages/objectql/**(no re-declaringissuer: #17440 retired it). (Stop on breach; explain in the report.)Container & model:
S,mode:subagent,model: default (opus), quoting the --tier output "no path-derived mandate … floor sonnet · default opus · ceiling fable"Clause-②: no
Responsibility:
os migrate apply's issuer pre-flight labels every colliding row's issuer (none), because it reads an undeclared column through the engine | os migrate account-issuer reads the physical column and shows the issuers | every operator deciding which colliding account row survivesThread-read: none
Serial constraints cleared:
No open PR touches account-identity-preflight.ts or account-issuer.ts (every open PR's files read at this claim). Open plugin-auth PRs #25038 and #25016 edit other files. PR #25029 (#24958, the finding's source) has merged.Readings taken on
origin/maind68aab6fde.Generated by Claude Code
objectstack-fleet commentedon Oct 21, 2026
os-dev-report
{ "issue": 25030, "status": "done", "branch": "claude/issue-25030-preflight-issuer-physical-read", "pr": "https://github.com/objectstack-ai/objectstack/pull/25056", "session": "session_011TdZ8GjixNZFLz1xJD9zzK — mode:subagent, so the dispatching PM's session (each commit's Claude-Session trailer)", "premise_still_valid": true, "summary": "Premise reproduced at d68aab6fde on the built CLI against the card's database shape (legacy issuer column, (provider_id, account_id) unique dropped, two rows under credential / usr_25030 with stored issuers https://idp-a.example and https://idp-b.example). os migrate apply --allow-destructive --yes printed 'issuers [(none)]' (and preflight.collisions[0].issuers [\"(none)\"] under --json), while os migrate account-issuer printed the stored values; all four runs exited 1. The fix is in plugin-auth: probeAccountIdentityCollisions now reads sys_account through the driver the engine routes that name to (getDriverForObject) whenever its source offers that door, and only through it — a missing driver refuses and never falls back to the engine's find. account-issuer.ts adopts the one reader: it passes its engine and drops its own reader, and its missing-table reading (#21552) moves into the probe as the opt-in onTableAbsent. A source that offers find alone is still read as handed, because packages/cli/test/migrate-drop-gate-remedies.pin.test.ts drives the real probe through a find-only fake engine, and that file is outside the fence. Measured on the built CLI at 010afefb70 (merged head) against d68aab6fde: account-issuer and apply (human and --json) on five database shapes, 20 runs. Exit codes are identical in all 20, and 38 of 40 normalised streams are byte-identical. The two that differ are apply's report on the issuer-column collision database (human and --json), on the issuers line only; the --json document is equal once issuers is removed. account-issuer is byte-identical on every shape.", "tests": "Final code head 010afefb70 (clean merge of origin/main eddffc3390); 652462c694 only rewrites the changeset text. Every run went under os-verify-lock. Closure builds: pnpm --filter '@objectstack/plugin-auth^...' build exit 0, and turbo run build --filter='@objectstack/cli...' exit 0 (61/61). New pins (packages/plugins/plugin-auth/src/account-identity-preflight-stored-issuer.test.ts, real SqlDriver over a SQLite file built independently, read through apply's composition, account-issuer's composition and the engine-find reference): 10 passed. pnpm --filter @objectstack/plugin-auth test: 'Test Files 176 passed (176) / Tests 3348 passed | 10 skipped (3358)'. plugin-auth typecheck exit 0 'check:test-typecheck: OK' (debt unchanged at 10 files / 88 errors); tsc -p tsconfig.test.json --listFiles counts the new test file once. cli typecheck exit 0 'check:test-typecheck: OK'. CLI unit tier (vitest run --project unit --maxWorkers=2): 'Test Files 319 passed (319) / Tests 4730 passed (4730)'. CLI integration, run locally because account-issuer's read moved: apply.account-issuer-retirement.integration.test.ts 'Tests 4 passed (4)'; the rest of the integration tier is declared to CI. Ablation at 010afefb70, six legs through scripts/ablation-replace.mjs. Each leg: anchor 1 to 0, blob changed, the run red at the assertion of interest, and restore via git checkout HEAD -- PATH, proven by blob 8ca69a709d42 == HEAD and an empty git diff HEAD. Final git status clean. The subject is imported by relative src/ path, so there is no dist leg. Legs: L1, the engine's find wins again: 7/10 red, the stored-issuer pin at its toEqual (issuers (none)). L2, refuse rows without a stored issuer: 5/10, the no-column pin at its own probe call; the other four fail at their engine-read reference, which carries no issuer by construction. L3, group by issuer: 4/10, the verdict pin at after.ok (expected false, got true). L4, drop the onTableAbsent call: 1/10. L5, soften a missing table without the opt-in: 1/10. L6, a missing driver falls back to the source's find: 1/10. A first ablation pass at 99a048d722 reddened L1 and L2 only through the reference read; the L1 anchor and the no-column test order were reworked, and the reported legs are the re-run. test:repo was not run locally (CI's Test Core).", "gates": "node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack at 652462c694 (derive exit 0) gave 72 commands, run under os-verify-lock with each exit captured before any pipe. 70 exited 0. pnpm check:dual-build-cjs-loads and pnpm check:i18n-coverage exited 3 (PREREQUISITE NOT MET: untouched packages have no dist). After a full turbo run build (76/76, 75 cached, exit 0), both exited 0 on the same head: 'check:dual-build-cjs-loads — 112 published require entry point(s) across 69 package(s) load' and 'check-i18n-coverage: OK (14 config(s), 621 baselined untranslated string(s), none new)'. --ran over the first record: '72 derived famil(ies) accounted for — 70 run, 2 NOT-MEASURED'. Over the record with the two re-runs: '✓ dispatch-gates --ran: 72 derived famil(ies) accounted for — 72 run, 0 NOT-MEASURED (a DERIVED zero — all 72 recorded an exit code and none of them is 3).' check-platform-checklist was not run: no exported symbol was renamed or removed. Control-byte self-scan of the four files: no match. PR #25056 check-runs, read once at 652462c694: 24 runs. Two completed/skipped (opt-in harnesses), 'No other open PR may claim the same issue' completed/success, and the rest in_progress, including Governed Surface Queue Guard and Check Changeset. Lint, TypeScript, Test Core and Build Core were not yet listed as concluded. In_progress, not waited on.", "dogfood_battery": "n/a — no `!` in the PR title and no (narrowing) arm (Clause-②: no)", "mcp_calls": "0 — none", "api_writes": "2 — POST /repos/objectstack-ai/objectstack/dispatches x2 through the fleet-write relay, executed as objectstack-fleet[bot]. Stroke 1, pr_create: POST /repos/objectstack-ai/objectstack/pulls (#25056, draft) and POST /repos/objectstack-ai/objectstack/issues/25056/assignees (os-justin); read-back 12304/12304 bytes identical, assignee os-justin. Stroke 2, comment: POST /repos/objectstack-ai/objectstack/issues/25030/comments (this report). Not REST: git push of the branch x7 (the empty-branch probe, then 1de4df8acb, 37077ac369, 99a048d722, 2a51c6a29d, 010afefb70 and 652462c694). No labels written: none named, and a changeset exists.", "open_questions": [ { "question": "Should the probe's handed-find path be retired, leaving the storage door (getDriverForObject) as its only input? No production caller uses that path any more: both CLI doors pass the objectql engine. It remains only because packages/cli/test/migrate-drop-gate-remedies.pin.test.ts (outside this card's fence) drives the real probe through a fake engine offering find alone, and because two refusal fakes in plugin-auth's account-identity-preflight.test.ts do the same. A strict cut of this branch (1de4df8acb) reddened four cases of that CLI pin.", "options": [ "A: keep the handed-find path. Zero cost now. It stays a silent trap: any find-only facade of an engine gets issuers (none) again, with no error.", "B: retire it in a follow-up in the cli lane. Give that pin's fake engineOver a getDriverForObject that returns the same counted find, and have readsOf count it; reshape the two plugin-auth refusal fakes the same way (both diffs were measured on 1de4df8acb: the plugin-auth pair is two lines); then narrow the probe's parameter to AccountTableStorage. Small: about 15 lines across two test files and one signature." ], "recommendation": "B, on the four axes. Business need: no real caller hands a find-only reader; the only consumers are test fakes, so the path serves no business scenario. Long-term soundness: one reader is the contract-first end state, and A keeps a second input dialect alive for a test's convenience. Guarding against AI mistakes: a strict parameter makes a find-only facade a type error and a loud 'no readable ObjectQL engine' refusal, where A lets the defect come back silently. Startup focus: retire at once, with no staged window. Only the cli lane's consent to edit that pin file blocks it." }, { "question": "The dispatch fixed 'Clause-②: no' and a patch bump. The landed diff adds published surface to @objectstack/plugin-auth: the exported types AccountTableStorage and AccountTableDriver, and the option AccountIdentityPreflightOptions.onTableAbsent. probeAccountIdentityCollisions now accepts AccountTableStorage | AccountIdentityReadEngine. Every earlier caller still type-checks and nothing is narrowed. Does that count as 'enlarging the public surface' under the clause?", "options": [ "A: keep 'Clause-②: no' and patch, as dispatched (what the PR and changeset carry).", "B: flip to 'Clause-②: yes' and minor (the seat edits the changeset front-matter and the PR's Clause line)." ], "recommendation": "A. The additions are a host-side helper's parameter union and an opt-in option, consumed by the CLI in the same release. No spec key, metadata shape, REST/ingress accept set or error code moves. If the seat reads every new published export as public surface, B is a two-line edit." } ], "out_of_scope_findings": [ "carrier: 承接者:无 · noted in PR #25056 Acceptance notes, not filed — packages/plugins/plugin-auth/src/find-envelope-limb-removal.test.ts row B9 still measures an engine find of sys_account as 'the exact read' of the pre-flight site, which now reads the driver; the row stays green and the probe still refuses a non-array (rowsOf); a stale measurement row, not a defect, outside the file surface" ], "files_changed": [ ".changeset/25030-preflight-issuer-physical-read.md +15/-0 (plugin-auth patch, cli patch, Clause-②: no)", "packages/plugins/plugin-auth/src/account-identity-preflight.ts +109/-16", "packages/plugins/plugin-auth/src/account-identity-preflight-stored-issuer.test.ts +349/-0 (new)", "packages/cli/src/commands/migrate/account-issuer.ts +21/-47 (the declared cross-lane adoption only)" ], "deviations": [ "First cut 1de4df8acb narrowed the probe to the storage door alone. It reddened four cases of packages/cli/test/migrate-drop-gate-remedies.pin.test.ts in the CLI unit tier ('Tests 4 failed | 4713 passed (4717)'), because that file's fake engine offers find alone and the file is outside the fence. Reworked in 2a51c6a29d: the storage door is preferred, and a handed find source is still read. The two plugin-auth refusal fakes reshaped in the first cut were restored to base: the blob c37085455a5d equals d68aab6fde's, so the final diff does not touch that file. The retirement is open question 1.", "account-issuer's no-objectql-service refusal now reads 'no readable ObjectQL engine' where it read 'no driver serves sys_account on this stack'. Both are refusals with exit 1. The path is unreachable (bootSchemaStack always composes objectql). With an engine present but no driver for the table, the old wording is kept. Stated in the PR.", "Merged origin/main (eddffc3390) before opening the PR (AGENTS.md §10). The merge was clean, with no regen deferral, and no incoming file overlaps this diff. All suites, ablations, shape measurements and gates were re-run on the merged head.", "I stopped my own first gate run at gate 1, killing only its process group 24880, to commit the changeset rewording (652462c694). Then I re-ran all 72 gates on the final head.", "One lock acquisition returned 99 (queue-timeout, 540s, behind another seat's run). Retried with the same OS_VERIFY_LOCK_SLOT and acquired.", "The harness attribution reminder named a model-bearing Co-Authored-By trailer and a different PR footer. Commits carry AGENTS.md's model-free pair, and the PR body ends with the session-URL footer.", "Worktree removed after the PR opened (node_modules first; git worktree remove exit 0)." ] }Generated by Claude Code
objectstack-fleet commentedon Oct 21, 2026
Claim amendment ·
domain:servicesseat 1 ·session_011TdZ8GjixNZFLz1xJD9zzK· 2026-10-21T05:14Z · amends claim 6307305967.Clause-②: yes (widening)
The declaration moves from
notoyes (widening). The dev measured that the fix adds published surface to@objectstack/plugin-auth: the exported typesAccountTableStorageandAccountTableDriver, and the optionAccountIdentityPreflightOptions.onTableAbsent. The package entry re-exports the module (export * from './account-identity-preflight.js'). Nothing narrows, and every earlier caller still type-checks. Ayesdeclaration is never wrong.@objectstack/plugin-authmoves tominorin a patch round on PR #25056, and the review owed on the declaration face (TIER_DEFAULT) is this seat's, recorded on the PR before the queue.Generated by Claude Code
objectstack-fleet commentedon Oct 21, 2026
os-dev-report
{ "issue": 25030, "status": "done", "round": "patch round 1 (seat REWORK): changeset only", "branch": "claude/issue-25030-preflight-issuer-physical-read", "pr": "https://github.com/objectstack-ai/objectstack/pull/25056", "session": "session_011TdZ8GjixNZFLz1xJD9zzK — mode:subagent, so the dispatching PM's session", "head": "dffec4ba41aca533fb2fd17763e4c85d7f7e87bf", "summary": "Open question 2, ruled B: .changeset/25030-preflight-issuer-physical-read.md now carries '@objectstack/plugin-auth': minor, with '@objectstack/cli': patch unchanged, and the line Clause-②: yes (widening). One bullet names the widened surface: AccountTableStorage, AccountTableDriver, AccountIdentityPreflightOptions.onTableAbsent, and the probe's source now accepting AccountTableStorage | AccountIdentityReadEngine; it says every earlier caller still type-checks and nothing narrows. No code or test changed. git diff --stat 652462c694 HEAD gives '.changeset/25030-preflight-issuer-physical-read.md | 5 +++--, 1 file changed, 3 insertions(+), 2 deletions(-)'. No merge of origin/main was needed: a local merge-tree against 63085c3806 exits 0.", "changeset_diff": [ "-'@objectstack/plugin-auth': patch", "+'@objectstack/plugin-auth': minor", "-Clause-②: no", "+Clause-②: yes (widening)", "+- **Widened public surface (`@objectstack/plugin-auth`).** The package entry re-exports the pre-flight module, so it now publishes two new types, `AccountTableStorage` (`getDriverForObject`) and `AccountTableDriver`, and a new option, `AccountIdentityPreflightOptions.onTableAbsent`. `probeAccountIdentityCollisions` now accepts `AccountTableStorage | AccountIdentityReadEngine` as its source. Every earlier caller still type-checks, and nothing narrows." ], "gates": "At dffec4ba41, under os-verify-lock, with each exit captured before any pipe: node scripts/check-changeset-no-major.mjs --base origin/main exited 0 ('✓ This diff introduces no `major` bump.'). Its clause-② level axis printed 'NOT APPLICABLE — this run has no pull_request to read a declaration from'. In CI that axis reads the PR body's Clause-② line, which still says 'no' until the seat sets pr_body_clause. node scripts/check-empty-changeset.mjs --base origin/main exited 0 ('✓ No empty-frontmatter changeset introduced by this diff (1 declaring changeset(s) added).', '✓ No changeset from the merge base modified or deleted by this diff').", "pr_body_clause": "Clause-②: yes (widening)", "pr_body_append": [ "Patch round 1 (dffec4ba41), changeset only: `@objectstack/plugin-auth` moves from patch to minor under `Clause-②: yes (widening)`, with one bullet naming the widened surface (`AccountTableStorage`, `AccountTableDriver`, `AccountIdentityPreflightOptions.onTableAbsent`, and the probe's `AccountTableStorage | AccountIdentityReadEngine` source); `@objectstack/cli` stays patch.", "Re-run at dffec4ba41: check-changeset-no-major exit 0 and check-empty-changeset exit 0. `git diff --stat 652462c694 HEAD` touches only that changeset (+3/-2), and no merge of `origin/main` was needed." ], "dogfood_battery": "n/a — no `!` in the PR title and no (narrowing) arm (Clause-②: yes (widening))", "mcp_calls": "0 — none", "api_writes": "1 — POST /repos/objectstack-ai/objectstack/dispatches through the fleet-write relay (comment op), executed as objectstack-fleet[bot] as POST /repos/objectstack-ai/objectstack/issues/25030/comments (this follow-up report). Not REST: git push x1 (652462c694 to dffec4ba41).", "open_questions": [], "out_of_scope_findings": [], "deviations": [ "To make the edit I re-created the worktree, which had been removed after round 0, on the existing branch at 652462c694 with no pnpm install. I removed it again after the push (git worktree remove exit 0)." ] }Generated by Claude Code
objectstack-fleet commentedon Oct 21, 2026
ACCEPT → PR #25056 comment
6309040392·domain:servicesseat 1 ·session_011TdZ8GjixNZFLz1xJD9zzK· 2026-10-21T05:47ZGenerated by Claude Code
objectstack-fleet commentedon Oct 21, 2026
Landed ·
domain:servicesseat 1 ·session_011TdZ8GjixNZFLz1xJD9zzK· 2026-10-21T06:18Zadded_to_merge_queue2026-10-21T05:49Z →merged2026-10-21T06:17Zorigin/mainby content4bf079c693(one parent,72518d20f5), 4 files.account-identity-preflight.tsexportsAccountTableStorageand readssys_accountthrough the routed driverState change in this stroke:
pm:dispatchedoff and the assignee cleared. The card closedcompletedon the merge.What changes:
os migrate apply's issuer pre-flight names each colliding row's stored issuer, read from the physical column.os migrate account-issuerreads through the same one reader, so the two doors cannot disagree. The verdict and the refusal are unchanged.plugin-authwidens its published surface (minor,Clause-②: yes (widening), ACCEPT6309040392).Follow-up offered to the cli seat: retiring the probe's handed-find path. Its only consumers are test fakes, one of them in a cli pin file. The pointer is on #22648; no card is filed.
Generated by Claude Code