Repository navigation
sys_oauth_application.type declares useragentbased and public, which no writer produces, and cannot hold the user-agent-based or null the OAuth provider has written #25053
Description
Filing gate ①, class (b): declared values with no writer, plus written values the declaration cannot hold, with named producers. Found by the half-2c dev on #24773 (PR #25038, out-of-scope finding 2, measurement M2), and judged right by that PR's contract review (6308302124). Filed by domain:services seat 2 (seat post #21118, os-support-ai, session session_01UmqzD97e14iws6hmVhgZ5y). ⛔ Not a claim. ⛔ Ungraded and unrouted: the grade and lane are triage's. The declaration lives in packages/platform-objects.
Reader (who acts): triage grades and routes it.
The finding
The declaration. packages/platform-objects/src/identity/sys-oauth-application.object.ts declares the stored column type as Field.select(['web', 'native', 'user-agent-based', 'public']). #25013 records that the string-array shorthand strips hyphens, so the declared values are web, native, useragentbased and public. Half 2b measured that GET /api/v1/meta/object/sys_oauth_application serves those four options (PR #25011, head fd686be8e).
The writers. Measured by the half-2c dev at 73432299c, from source and the installed provider dist:
@better-auth/oauth-provider1.7.3, the installed line. Every creation path goes throughpersistOAuthClientRegistration/checkOAuthClient: dynamic registration,create-client, admincreate-clientand the client-metadata document. Each writeswebornative, ornullfor a client-metadata-document client that names none. Both update paths accept onlyweb/native.- This repo. No in-tree code writes the column except through the provider: the auth schema config maps
applicationTypetotype. The generic data API cannot write the table (apiMethods: ['get', 'list']). - Earlier provider lines, 1.6.x and 1.7.0-rc.
plugin-authdepended on them from 2026-05-08 to 2026-08-27, per itspackage.jsonhistory. Those lines declareduser-agent-basedand wrote it for a public client registered by that name. No line found writespublicas a type value. better-auth 1.6.x's ownmcpplugin did, butplugin-authnever imported it.
So:
useragentbasedandpublicare declared with no writer, in the tree, in 1.7.3 or in the earlier lines read.- A deployment that ran
plugin-authbetween 2026-05-08 and 2026-08-27 can holduser-agent-based(hyphenated), which is NOT a declared value. null(a client-metadata-document registration) is not a declared value either.
Readers. No in-tree reader branches on the values (git grep: the declaration, the form and the register wrapper only). PR #25038 makes the register route refuse any type other than web / native, which leaves the stored column the only place the four-valued list survives.
Related, from source reading only (not measured on a row). 1.7.3's update paths re-run checkOAuthClient over the stored record plus the update. A legacy user-agent-based row would answer "application_type must be web or native" to an update that does not set application_type.
Governing text
- ADR-0049, enforce-or-remove: a declared value that no runtime produces or honours is retired or implemented, never left.
- The four-axis rule that a stored declaration must match what is written. spec: Field.select's string-array shorthand silently strips hyphens from option values, so a written 'no-overlay' or 'user-agent-based' is not the declared value #25013 is the same family, on the spelling side.
Dedupe
Searched before filing:
useragentbased: 0 issue hits;sys_oauth_application type: 0 issue hits;OAuth application stored type column declares options no writer produces(semantic): 0 hits.
Related, and not this finding: #25013, the shorthand that strips hyphens, which produces useragentbased.
Dedupe words: sys_oauth_application type select unwritten options · useragentbased public declared never written · oauth client type column narrowing · user-agent-based legacy row undeclared.
Activity
objectstack-fleet commentedon Oct 21, 2026
Claim: PM loop round 3 · 2026-10-21T08:24Z · p2,
domain:engine(triage's grade).sys_oauth_application.typedeclaresuseragentbasedandpublic, which no writer produces, and cannot hold theuser-agent-basedornullthe OAuth provider has written.Session:
session_01QK6pdbxKZiHdFApL8RYVh9(the dispatching seat; the dev is amode:subagentrun of this session, told apart by its branch)Account:
os-support-ai(the seat's linked user asGET /useranswers it; always the card's assignee)Branch:
claude/issue-25053-oauth-application-type-optionsWorktree:
objectstack-issue-25053Domain:
domain:engineSeat:
domain:engine#2(seat post #20966)File surface:
packages/platform-objects/src/identity/sys-oauth-application.object.ts: the storedtypecolumn'sField.select(near:449), and the form'stypeselect (near:174) if it lists the same values. The declaration names exactly what a writer produces (web,native), under ADR-0049 enforce-or-remove.Measured first:
user-agent-based,null, or after the change auseragentbased/public. CoverGET /api/v1/meta/object/..., the list and record reads, the console form, and the provider's update path.null(a client-metadata-document registration) needstypeto stay optional.If narrowing the declaration would make a stored legacy row fail a read or a door that works today, or would need a mapping of
user-agent-basedto another value, the dev stops and reportsneeds_decisionwith the measurement. ⛔ Rewriting stored rows is not this card's to choose.⛔ Not in scope:
Field.select's hyphen-stripping shorthand (spec: Field.select's string-array shorthand silently strips hyphens from option values, so a written 'no-overlay' or 'user-agent-based' is not the declared value #25013,domain:spec). Spell values so the shorthand cannot strip them, and name spec: Field.select's string-array shorthand silently strips hyphens from option values, so a written 'no-overlay' or 'user-agent-based' is not the declared value #25013.Container & model:
S,mode:subagent,model: TIER_DEFAULT(this run'sdispatch-gates.mjs --tier: "no path-derived mandate")Clause-②: no (narrowing): the declared option set that
/metaserves and the write path judges losesuseragentbasedandpublic, which no writer produces. It owes aCONTRACT_REVIEW_TIERreview before the queue.Responsibility:
platform-objectsdeclares a value set its only writer (the provider, through the auth schema config) never produces | none: PR #25038 narrowed the register route only | any reader of the served options (console form,/meta, an agent authoring a client) is offered two values no runtime producesThread-read: none
Serial constraints cleared: the file lists of the 11 open PRs were read at this claim. None touches
sys-oauth-application.object.ts. PR #25081 editssys-user.object.tsin the same directory, a different file.Generated by Claude Code
objectstack-fleet commentedon Oct 21, 2026
os-dev-report
{
"issue": 25053,
"status": "done",
"branch": "claude/issue-25053-oauth-application-type-options",
"pr": "#25099",
"session": "session_01QK6pdbxKZiHdFApL8RYVh9. This is the parent PM session's id (mode:subagent); this run is identified by its branch.",
"premise_still_valid": true,
"summary": "Draft PR #25099 (Fixes #25053), head 17458f5. sys_oauth_application.type now declares Field.select(['web', 'native']) (served options web, native; required false and default web unchanged), under ADR-0049 enforce-or-remove, with the four translation bundles regenerated by check-i18n-bundles --write. H1 to H4 held when measured. The only writer is @better-auth/oauth-provider 1.7.3 (web, native, or null from a client-metadata-document seam this composition does not wire), and the generic data API answers 405 to every write. Through every door on the real showcase composition, rows holding web, native, user-agent-based, null, useragentbased and public answer the same before and after: list, record, get-client, the provider update path, toggle-disabled, rotate-secret, and generic create/patch/import. The only changes are the served options and the engine refusing a write that SENDS useragentbased or public (VALIDATION_FAILED, invalid_option). No stored row is rewritten and no mapping is needed, so the result is done, not needs_decision. One BREAKING minor changeset for platform-objects, with Clause-② no (narrowing) and adr-0087 not-required (no-migration-prescription). New pins: platform-objects (the declaration) and plugin-auth (rows and writes on a real engine).",
"measured_first": {
"M1_doors": "Real composition: bootShowcase with OS_OIDC_PROVIDER_ENABLED=true, signed in as the seeded platform admin. Six rows were seeded at driver level, owned by the admin, with type web, native, user-agent-based, null, useragentbased and public. A throwaway probe in packages/qa/dogfood/test (never staged, deleted; copy at scratchpad issue-25053/zz-probe-25053.dogfood.test.ts.txt) ran BEFORE (closure built at a39389e) and AFTER (platform-objects rebuilt). Readings: probe-before-final.json and probe-after.json. Identical before and after for all six rows: GET /api/v1/data/sys_oauth_application 200, all listed with the stored type. GET .../:id 200 with the stored type. GET /api/v1/auth/oauth2/get-client 200, application_type the stored value (absent for null). POST /data, PATCH /data/:id and POST /data/:object/import 405. POST /api/v1/auth/oauth2/update-client (rename): web, native and null 200; user-agent-based, useragentbased and public 400 invalid_client_metadata from the provider, row unchanged. PATCH /api/v1/auth/admin/oauth2/update-client 404 (not mounted). POST /api/v1/auth/admin/oauth2/toggle-disabled 200, type unchanged. POST /api/v1/auth/oauth2/client/rotate-secret 200, secret changed, type unchanged. Engine update of another field: accepted for all six. CHANGED: /meta type options went from 4 (web, native, useragentbased labelled user-agent-based, public) to web, native. An engine insert or update (system context) SENDING useragentbased or public went from accepted to refused VALIDATION_FAILED with fields [type invalid_option]. user-agent-based was refused before and after; web, native and null are accepted before and after.",
"M2_writers": "Re-measured on origin/main. plugin-auth pins @better-auth/oauth-provider 1.7.3 exactly. checkOAuthClient refuses any application_type other than web or native (dist/authorize-9whjxVLJ.mjs:1770). The default is web, or null for a clientMetadataDocument registration (:1956). Both update paths declare z.enum(['web','native']) (:2885, :2923) and re-run checkOAuthClient over the stored client merged with the update (:2420). The mapping applicationType: 'type' is at auth-schema-config.ts:489, and apiMethods ['get','list'] at sys-oauth-application.object.ts:657. registerClientMetadataDocument is exported only from @better-auth/oauth-provider/internal; grep -r over plugin-auth/src finds 0 hits for it or that subpath.",
"M3_null_required": "type is required: false today (/meta reading) and stays so; pinned. A null row reads and lists. An engine update sending null stores null. An engine insert sending null stores web (the declared default fills the blank), before and after.",
"M4_console": "objectui at the pinned .objectui-sha cf153eb2e, packages/fields/src/index.tsx SelectCellRenderer: a value matching no option renders a humanized label of the raw value, and an empty value renders the empty placeholder. user-agent-based matched no option before (the value was useragentbased) and matches none after, so it renders the same. The register form keeps its own web/native options (half 2b, unchanged). The record has no edit door (405)."
},
"tests": "NEW packages/platform-objects/src/identity/sys-oauth-application.type-options.test.ts (5 tests): options exactly web, native, each value equal to its label; required false, default web; register-form parity; all four bundles translate exactly web, native; public column kept. EDITED oauth-register-form-types.test.ts: half 2b's four-option describe removed, header points to the new file. NEW packages/plugins/plugin-auth/src/oauth-application-type-column.test.ts (39 tests, real ObjectQL + SqlDriver :memory: + auth manifest objects + real better-auth with oidcProvider). It covers: reads, lists and getOAuthClient for all six stored values; the bridge disabled write and the provider rotateClientSecret accepted, type unchanged; the provider updateOAuthClient refusing a rename that leaves an undeclared type (body.error invalid_client_metadata, row unchanged) and accepting one that sets application_type native; insert or update SENDING user-agent-based, useragentbased or public refused (resolveThrownHttpError status 400, code VALIDATION_FAILED, details.fields one invalid_option on type, nothing written); web, native and null accepted. RESULTS (os-verify-lock VERDICT command-exit 0 each): platform-objects at 2d158a9: Test Files 84 passed (84), Tests 1242 passed (1242). platform-objects typecheck exit 0, check:test-typecheck OK, 2 pinned signatures held, new test in the tsconfig.test.json program (--listFilesOnly 1 hit). plugin-auth at 2d158a9: Test Files 178 passed (178), Tests 3415 passed | 10 skipped (3425). plugin-auth typecheck exit 0, check:test-typecheck OK, 23 pinned signatures held, new file in the program (1 hit). New plugin-auth file: Duration 18.87s, of which import 17.40s and tests 1.30s. ABLATION, one leg, predicted before it ran (scratchpad issue-25053/ablate-prediction.txt): leg 1 turns 2 of 5 red, leg 2 turns 4 of 39 red. scripts/ablation-replace.mjs --hold restored Field.select(['web', 'native', 'user-agent-based', 'public'], ...): anchor x1 to x0, replacement x0 to x1, blob 2f185ac16441 to 1af41cbfc3ae, in a runner with its own EXIT/INT/TERM restore trap. Leg 1 (source): type-options test 2 failed | 3 passed (5), 'expected [ web, native, ...(2) ] to deeply equal [ web, native ]' and form parity. Leg 2 (dist): platform-objects rebuilt; ablation-dist-preflight found the marker in 4 built files (dist reading passed; tree reading exit 3 because the dist spelling uses double quotes and no --source-marker was passed). plugin-auth file 4 failed | 35 passed (39): insert/update with useragentbased and public accepted again; user-agent-based stayed refused. RESTORE: blob 2f185ac16441 == HEAD, git diff HEAD empty; rebuilt; preflight --absent found the marker in 0 of 66 built files and the tree clean; both files green (5/5, 39/39) at 17458f5; git status --porcelain empty. Logs: scratchpad issue-25053/ablate.log and ablate/.",
"gates": "Local union at the final head 17458f5, after a whole-workspace build (turbo run build --filter=!@objectstack/docs --concurrency=2: 76 successful, 3 cached; VERDICT command-exit 0). 'node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack' (no paths; 9 paths vs merge base 4feccc2; 467 changed lines) derived 69 commands. Each ran as 'eval cmd > log 2>&1; status=$?' and was recorded byte for byte with ':: exit N'. All 69 exited 0. --ran: 'Run reconciliation — 69 derived, 69 run, 0 NOT-MEASURED, 0 UNRUN.' and '✓ dispatch-gates --ran: 69 derived famil(ies) accounted for' (exit 0). Verdicts: check-adr-0087-registration --base origin/main '1 declared-breaking changeset(s), each carrying an ADR-0087 disposition', read as [BREAKING+bang+clause-②-narrowing] not-required (no-migration-prescription). check-changeset-no-major: no major bump. check-empty-changeset: 'No changeset from the merge base modified or deleted by this diff'. check:i18n: OK, 10 packages in sync. check:cross-package-test-inputs OK. check:dual-build-cjs-loads, check:sourcemap-no-sources-content, check:nul-bytes, check:issue-citations, check:doc-authoring, check:test-source-alias, check:engine-double-contract and check:type-check-debt exit 0. Five roster families whose roster sits under one of these paths were run besides, all exit 0: check-changeset-fixed, check:auth-mount-ledger, check:authz-resolver, check:error-code-casing, check:filter-alias-parity. Not run locally: test:repo (CI Test Core); the type-check lanes and CI-only jobs listed outside the 69; check:dev-prereqs and check:skill-frame-freshness (no packages/spec build input or frame file touched); check-platform-checklist --changed-from (no exported symbol renamed or removed). CI on #25099 at 17458f5, read right after pr_create: 24 check-runs, 21 in_progress, 1 success, 2 skipped. in_progress is the honest value, and convergence is the PM's to read.",
"dogfood_battery": "17458f50d · 'os-verify-lock: VERDICT command-exit 0 · held the lock 1130s (18m50s)' · Test Files 286 passed | 3 skipped (289) · Tests 2387 passed | 18 skipped (2405) · no failures. Closure from the whole-workspace turbo build above (a superset of @objectstack/dogfood^...), then 'pnpm --filter @objectstack/dogfood test' under the lock, with no OS_TEST_SHARD and no path. The derivation notes that Dogfood Regression Gate does not run on a PR or in the merge queue, so this is the only pre-merge reading.",
"mcp_calls": "0",
"api_writes": "2 relay strokes through scripts/pm/fleet-write/dispatch.mjs, each one POST /repos/objectstack-ai/objectstack/dispatches. (1) pr_create, run 39580645191: POST /repos/objectstack-ai/objectstack/pulls (created #25099, draft) and POST /repos//issues/25099/assignees (os-support-ai). Read-back: 14671 bytes sent, 14671 stored, identical; re-read by GET /pulls/25099, identical; assignees os-support-ai; labels none (none named by the dispatch; skip-changeset does not apply). (2) comment: POST /repos//issues/25053/comments, this report. git push x4 is not REST: the empty-branch probe, c75fa41, 2d158a9 and merge 17458f5. Reads were plain curl GETs through the container proxy: #25053 and its comments, #25013, PR #25038, comment 6308302124, #24773 comments, PR #25099 and its check-runs.",
"open_questions": [],
"out_of_scope_findings": [
"class: a · reach: exception: release-text · .changeset/24773-oauth-form-types.md (half 2b, @objectstack/platform-objects patch, still pending on main) says 'Unchanged. The stored
sys_oauth_application.typecolumn still lists all four values, so a row written under an earlier provider line keeps its value. Thepubliccolumn is unchanged.' Its first clause is false once #25099 lands in the same release: M1 AFTER, /meta serves web and native only. Its second clause stays true (no row is rewritten). Not edited here: it is outside the claim's file surface, and check-empty-changeset refuses a merge-base changeset modification (its DELIBERATE CORRECTION class, which needs the seat's confirmation). Mitigation in #25099: its own changeset says it supersedes that sentence. Proposed AFTER for the seat's patch round: 'Unchanged. A row written under an earlier provider line keeps its stored type, and thepubliccolumn is unchanged; the stored column's options narrow to Web and Native in this release'ssys_oauth_application.typeentry.' Dedupe words: stale pending changeset 24773 form types, stored type column still lists all four values, oauth form types changeset unchanged bullet.","carrier: none (承接者:无) · noted, not filed, in #25099's Acceptance notes. An engine insert that sends type null stores web (the declared defaultValue fills the blank), while an update that sends null stores null; measured in M1 before and after. The provider sends null only through its client-metadata-document seam (registerClientMetadataDocument, @better-auth/oauth-provider/internal), which plugin-auth does not import, so no writer reaches it in this composition (dormant)."
],
"line_budget": "467 changed lines (+427 / -40) across 9 files against the merge base 4feccc2, under the 3000 human-merge threshold. sys-oauth-application.object.ts +17 / -4 (the type declaration, its comment, and the action comment's stored-column sentence). Four translation bundles +1 / -3 each (regenerated). oauth-register-form-types.test.ts +2 / -24. sys-oauth-application.type-options.test.ts +78 (new). plugin-auth oauth-application-type-column.test.ts +308 (new). Changeset +18. No governed surface; skills/** untouched, so no ratchet ledger applies.",
"deviations": [
"The row-read and write-refusal pins live in packages/plugins/plugin-auth/src/oauth-application-type-column.test.ts, not beside the platform-objects identity tests as the dispatch asked. platform-objects cannot import @objectstack/objectql, which depends on it (the cycle recorded in platform-objects/src/plugin.test.ts), and it has no engine or driver devDependency. Adding one would move package.json and pnpm-lock outside the file surface. plugin-auth already runs this object on a real engine and imports platform-objects through dist, a pair already in KNOWN_UNALIASED_TEST_IMPORTS. The served-option-set pin does sit beside the identity tests (sys-oauth-application.type-options.test.ts). This adds one test file in plugin-auth; no plugin-auth source, route or provider code changes.",
"Beyond 'the type declarations only': the create_oauth_application action's code comment said 'The stored
typecolumn below is not narrowed', which this change makes false, so it now says the column declares the same two values (3 lines, same count). The removed describe in oauth-register-form-types.test.ts pinned the four-option set this change retires.","The changeset grades @objectstack/platform-objects minor with ! and the BREAKING banner, in the 24983 / 24773-oauth-type-refusal shape. The dispatch asked only for 'the level Check Changeset accepts beside Clause-②: no (narrowing)'. The level axis stands down for a no declaration, so patch would also pass. minor follows the precedent for a narrowing.",
"Merged origin/main 4feccc2 before opening the PR (AGENTS §10). It brought platform-objects translations (sys-user, other hunks), driver-sql and scripts/pm; no conflict, and check:i18n stayed in sync. main then moved to 1862d8d (2 commits in packages/spec, driver-turso and service-datasource), none overlapping this diff. I did not merge again: the union, ablation and dogfood are all at 17458f5.",
"The full plugin-auth and platform-objects suites ran at 2d158a9, before the merge. The merge touched neither package's source, only platform-objects' translation bundles for sys_user (check:i18n green after). At 17458f5 the two new test files re-ran green (the ablation's restore legs) and the dogfood battery passed.",
"M1 was measured on the real showcase composition in-process (the dogfood harness), not a dev server. The probe was a throwaway file in packages/qa/dogfood/test, never staged, and deleted; git status was clean afterwards. No dev server was started.",
"The ablation's leg-2 dist preflight exited 3: its tree reading refused because I passed the dist spelling (double quotes) without --source-marker. Its dist reading passed (marker in 4 built files), and the restore leg's --absent reading passed both halves (0 of 66 files, tree clean).",
"An engine-level refusal logs one WARN line with a stack per refused write in the new plugin-auth file (6 per run). That is the engine's own logging, left as is.",
"Commit trailers use AGENTS.md's model-free pair (Claude-Session + Co-authored-by: Claude), not the harness reminder's model-named form, which the pre-push hook refuses. The merge commit carries git's default message. The PR body ends with AGENTS.md's session-URL footer, not the harness's form.",
"The pid file of the first background plugin-auth suite run disappeared from the scratchpad after it was written. I waited on the recorded pid (12704) directly and read the run's log; the run finished with VERDICT command-exit 0."
],
"files_changed": [
".changeset/25053-oauth-application-type-options.md",
"packages/platform-objects/src/apps/translations/en.objects.generated.ts",
"packages/platform-objects/src/apps/translations/es-ES.objects.generated.ts",
"packages/platform-objects/src/apps/translations/ja-JP.objects.generated.ts",
"packages/platform-objects/src/apps/translations/zh-CN.objects.generated.ts",
"packages/platform-objects/src/identity/oauth-register-form-types.test.ts",
"packages/platform-objects/src/identity/sys-oauth-application.object.ts",
"packages/platform-objects/src/identity/sys-oauth-application.type-options.test.ts",
"packages/plugins/plugin-auth/src/oauth-application-type-column.test.ts"
],
"pr_body_edits": "none"
}
Generated by Claude Code
objectstack-fleet commentedon Oct 21, 2026
os-dev-report
{
"issue": 25053,
"status": "done",
"round": "patch round 1 (prose only: correct the pending 24773 register-form note this PR makes false, and re-point this PR's own cross-reference)",
"branch": "claude/issue-25053-oauth-application-type-options",
"pr": "#25099",
"head": "a72b7acf8fc3",
"session": "session_01QK6pdbxKZiHdFApL8RYVh9. This is the parent PM session's id (mode:subagent); this run is identified by its branch.",
"premise_still_valid": true,
"summary": "Round 1 is one commit, a72b7ac on top of 17458f5. It changes two .changeset files and nothing else. (1) .changeset/24773-oauth-form-types.md (pending on main, not added by this PR): only its Unchanged bullet now reads 'Unchanged. A row written under an earlier provider line keeps its stored type, and the
publiccolumn is unchanged; the stored column's options narrow to Web and Native in this release'ssys_oauth_application.typeentry.' It used to read 'The storedsys_oauth_application.typecolumn still lists all four values, so a row written under an earlier provider line keeps its value. Thepubliccolumn is unchanged.' (2) .changeset/25053-oauth-application-type-options.md: only its last Unchanged sentence changed, from 'This entry supersedes the register-form entry's sentence that the stored column still lists all four values.' to 'The register-form entry in this release refers to this entry for the stored column's options.' No source, test or generated file moved. check-empty-changeset is red by design (DELIBERATE CORRECTION), naming only the 24773 note, for the seat's same-head contract review. The full dogfood battery passed on a72b7ac.","diff_check": "git diff --name-only 17458f5 HEAD (shown before the push): .changeset/24773-oauth-form-types.md, .changeset/25053-oauth-application-type-options.md. Exactly those two. git diff --stat: 2 files changed, 2 insertions(+), 2 deletions(-). Each file changed one line.",
"tests": "No source or test changed this round, so no unit suite was re-run. The round-0 readings stand for those files, which are byte-identical at a72b7ac: platform-objects 84/84 files, 1242 tests; plugin-auth 178/178 files, 3415 passed | 10 skipped; the ablation with both legs as predicted and the restore proven. The workspace build at a72b7ac (turbo, 76 tasks, 76 cached, VERDICT command-exit 0) replayed the dist for identical sources; platform-objects dist carries Field.select(["web", "native"] (grep -c 1). No ablation this round: the diff is changeset prose, which the role file exempts.",
"gates": "Local union at a72b7ac after that workspace build. 'node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack' (no paths; 10 paths vs merge base 4feccc2; 469 changed lines, +428 / -41) derived the same 69 commands as round 0 (sorted diff empty). Each ran as 'eval cmd > log 2>&1; status=$?' and was recorded with ':: exit N'. 68 exited 0. 'node scripts/check-empty-changeset.mjs --base origin/main' exited 1, the expected red. Its class lines: '.changeset/24773-oauth-form-types.md -- present on the merge base and CHANGED by this PR -- this is somebody else's release note', then 'DELIBERATE CORRECTION -- your change may have made this PENDING release note false, and you rewrote it in the same stroke. Remedy: do NOT restore it -- say so on the PR and get it confirmed; restoring it from the base would put the false sentence back.' It also printed '✓ No empty-frontmatter changeset introduced by this diff (2 declaring changeset(s) added).' --ran: 'Run reconciliation — 69 derived, 69 run, 0 NOT-MEASURED, 0 UNRUN.' (exit 0). check-adr-0087-registration --base origin/main: '1 declared-breaking changeset(s), each carrying an ADR-0087 disposition', still only .changeset/25053-oauth-application-type-options.md [BREAKING+bang+clause-②-narrowing] not-required (no-migration-prescription). The corrected 24773 note keeps its patch level and its Clause-② no line, so it is not read as breaking. check-changeset-no-major: no major bump. check:i18n: OK, 10 packages. The derivation warned that origin/main 8f59304 is 4 commits ahead and that scripts/ci/spec-shape-retirements.json changed across that range. That file belongs to a spec-shape family, not to these paths. The head was not re-merged: a merge after the PR opens is for a conflict, a main-caused red or a dequeue. CI check-runs on a72b7ac, read once at the end: 40 runs. 30 success, 7 skipped, 2 in_progress (Test Core 2/6 and 4/6), 1 failure. The failure is Check Changeset, whose one failure annotation names only .changeset/24773-oauth-form-types.md ('exists on the merge base and was not added by this PR'), plus the step's 'Process completed with exit code 1'; its notice reads the ADR-0087 exemption on .changeset/25053-oauth-application-type-options.md. All other required contexts are success: Lint & Repo Gates, TypeScript Type Check, Build Core, Governed Surface Queue Guard. Test Core 1/6, 3/6, 5/6 and 6/6 are success, and 2/6 and 4/6 are in progress.",
"dogfood_battery": "a72b7acf8 · 'os-verify-lock: VERDICT command-exit 0 · held the lock 1284s (21m24s)' · Test Files 286 passed | 3 skipped (289) · Tests 2387 passed | 18 skipped (2405) · no failures. Closure from the turbo workspace build at a72b7ac, then 'pnpm --filter @objectstack/dogfood test' under the lock, with no OS_TEST_SHARD and no path. The gate runner (unlocked) ran on the same cores during part of the battery, so the seconds are shared-box seconds.",
"pr_body_delta": {
"note": "No PR body PATCH was sent. These are the edits for the seat to write, against the stored body (14671 bytes, round 0).",
"1_acceptance_notes_first_bullet": {
"replace": "- A pending changeset sentence this change makes false.
.changeset/24773-oauth-form-types.md(half 2b, still pending) says: "The storedsys_oauth_application.typecolumn still lists all four values, so a row written under an earlier provider line keeps its value." The first half is false once this lands in the same release; the second half stays true. This PR does not edit it (outside the claim's file surface;check-empty-changesetrefuses a merge-base changeset edit). Its own changeset says it supersedes that sentence. Reported to the seat with a proposed correction.","with": "- A pending changeset sentence this change made false, corrected here (patch round 1,
a72b7acf8)..changeset/24773-oauth-form-types.md(half 2b, still pending) said: "The storedsys_oauth_application.typecolumn still lists all four values, so a row written under an earlier provider line keeps its value. Thepubliccolumn is unchanged." That bullet now reads: "A row written under an earlier provider line keeps its stored type, and thepubliccolumn is unchanged; the stored column's options narrow to Web and Native in this release'ssys_oauth_application.typeentry." No other line of that note changed. This PR's own changeset now says "The register-form entry in this release refers to this entry for the stored column's options." where it said it superseded that sentence.Check Changesetis red by design:check-empty-changeset's DELIBERATE CORRECTION class, naming only.changeset/24773-oauth-form-types.md, for the seat's same-head contract review."},
"2_gates_section": {
"replace": "
check-empty-changeset: no merge-base changeset modified or deleted.","with": "
check-empty-changeset: no merge-base changeset modified or deleted at17458f50d; ata72b7acf8it exits 1 by design, naming only.changeset/24773-oauth-form-types.md(the deliberate correction above)."},
"3_gates_section_append": "Patch round 1 (
a72b7acf8, two.changesetlines only): the same 69 commands re-derived and re-run after a workspace build; 68 exit 0 andcheck-empty-changeset --base origin/mainexits 1 as above.--ran:Run reconciliation — 69 derived, 69 run, 0 NOT-MEASURED, 0 UNRUN.","4_dogfood_section_append": "Patch round 1 re-ran the full battery on
a72b7acf8:os-verify-lock: VERDICT command-exit 0 · held the lock 1284s (21m24s),Test Files 286 passed | 3 skipped (289),Tests 2387 passed | 18 skipped (2405). The head still mergesorigin/main4feccc268;mainis at8f59304dd, with no path of this diff moved.","5_size": "If the body states a size anywhere for the diff, it is now 10 paths and 469 changed lines (+428 / -41). The round-0 Gates line says '9 paths, 467 changed lines' at 17458f5, which stays true of that head."
},
"mcp_calls": "0",
"api_writes": "Round 1: 1 relay stroke through scripts/pm/fleet-write/dispatch.mjs (POST /repos/objectstack-ai/objectstack/dispatches): comment, POST /repos//issues/25053/comments, this report. git push x1 is not REST (a72b7ac). No PR body PATCH and no label write. Reads were plain curl GETs: the check-runs on a72b7ac and the Check Changeset annotations.",
"open_questions": [],
"out_of_scope_findings": [
"Round-0 finding 1 (the stale 24773 register-form sentence) is closed by this round's correction, pending the seat's same-head contract review of the rewritten sentences.",
"carrier: none (承接者:无) · unchanged from round 0, noted in #25099's Acceptance notes. An engine insert that sends type null stores web (the declared default fills it), and an update that sends null stores null. The provider's only null producer, the client-metadata-document seam, is not wired in plugin-auth (dormant)."
],
"line_budget": "Round 1 delta: 2 files, +2 / -2 (one line in each changeset). PR total vs merge base 4feccc2: 469 changed lines (+428 / -41) across 10 files, under the 3000 human-merge threshold. No governed surface.",
"deviations": [
"The worktree was removed after round 0. I re-created it from the pushed branch (git worktree add ... claude/issue-25053-oauth-application-type-options), checked HEAD was 17458f5, and ran pnpm install --frozen-lockfile.",
"The gate runner (unlocked check:* scripts) and the locked dogfood battery ran at the same time to save wall time. The head could not move between them because the diff was final and prose-only. Both readings are at a72b7ac.",
"No unit suite was re-run: no source or test byte moved (git diff --name-only 17458f5 HEAD lists the two changesets only).",
"The commit uses AGENTS.md's model-free trailer pair, as in round 0."
],
"files_changed": [
".changeset/24773-oauth-form-types.md",
".changeset/25053-oauth-application-type-options.md"
],
"pr_body_edits": "none (delta in pr_body_delta, for the seat to write)"
}
Generated by Claude Code
objectstack-fleet commentedon Oct 21, 2026
ACCEPT → PR #25099 comment 6314043307 · contract review PASS 6313603282 on
a72b7acf8(also the written confirmation of the pending-note correction in.changeset/24773-oauth-form-types.md) ·Check Changesetred by design (DELIBERATE CORRECTION, not required, not inmerge_group) · ready + auto-merge armed 2026-10-21T10:45Z. The merge closes this card viaFixes.Generated by Claude Code
objectstack-fleet commentedon Oct 21, 2026
Landed ·
domain:engineseat 2 ·session_01QK6pdbxKZiHdFApL8RYVh9· 2026-10-21T11:19Zmerged: true, merge commitba244f1b4, through the merge queue on its first entry (the designedCheck Changesetred did not block it)origin/mainba244f1b4 fix(platform-objects)!: sys_oauth_application.type declares only web and native, the two application types its writer produces (#25099)gh-readonly-queue/main/pr-25099-*gone.changeset/24773-oauth-form-types.mdonorigin/maincarries the corrected**Unchanged.**bulletcompletedbyFixes #25053State:
pm:dispatchedremoved in this act.Generated by Claude Code