Skip to content

GET /auth/config serves nine features keys the spec does not declare, and nothing pins the feature registry to the schema #29473

Closed

Description

@objectstack-fleet

domain:spec#2 · os-steve · session_01ADHkmSduNGC2SZXszyrNut

Filing gate: ① an out-of-scope finding (class b, carrier: the seat) that the #29344 dev reported and the seat's contract review confirmed on PR #29455's head 0d814466 (record 6581701011). ⛔ Not a claim. No grade: triage sets it.

What was measured

PR #29455 declares features.sso on AuthFeaturesConfigSchema (packages/spec/src/api/auth-endpoints.zod.ts), the response schema of GET /api/v1/auth/config. The same response carries nine more features keys the server serves (plugin-auth getPublicConfig(), auth-manager.ts) that the schema does not declare. A client that parses the response through GetAuthConfigResponseSchema loses them, because a plain object schema strips unknown keys:

  • booleans, all classified in PUBLIC_AUTH_FEATURES (packages/spec/src/kernel/public-auth-features.ts): multiOrgEnabled, degradedTenancy, oidcProvider, deviceAuthorization, admin
  • non-flag values, all listed in PUBLIC_AUTH_CONFIG_NON_FLAG_KEYS: tenancyPosture, audiencePosture, termsUrl, privacyUrl

deviceAuthorization has a live reader (ui/apps/console/src/pages/auth/DeviceAuthPage.tsx:77). Also undeclared, at the top level of GetAuthConfigResponseSchema: devSeedAdmin (auth-manager.ts:4634, dev-only).

No pin ties the registry or the non-flag list to the schema's keys. The three existing pins are: plugin-auth public-feature-registry.test.ts (served keys ≡ registry), platform-objects feature-gate guard (registry ≡ gates), and spec public-auth-features.test.ts (the registry's names). So a key can be served, classified and read while the contract never declares it, which is how sso (#29344) and cloudManaged (#25292) each needed their own card.

Wanted

  1. Declare each served key on AuthFeaturesConfigSchema (and devSeedAdmin on GetAuthConfigResponseSchema, or rule it out as dev-only), with a describe that says what the producer means, in the spec: declare the console flag features.cloudManaged — a PUBLIC_AUTH_FEATURES entry with a hide-when-on gate semantics, and AuthFeaturesConfigSchema declares it (child of #25083, ruling 6341690661 Q3 A) #25292 / PR feat(spec): declare features.sso on the auth config response #29455 pattern. Each is Clause-②: yes (widening) · Metadata-protocol: added; the names are the served names, so the maintainer is asked only if a rename is proposed.
  2. Add one pin in packages/spec that every key in PUBLIC_AUTH_FEATURES and PUBLIC_AUTH_CONFIG_NON_FLAG_KEYS is a declared key of AuthFeaturesConfigSchema (retired keys excepted), so the next served key cannot be left undeclared.

Reader who acts: the packages/spec api-schema owner (domain:spec). Land after PR #29455, which touches the same schema.

Also seen, for the ui lane, prose only: ui/packages/auth/src/types.ts:284-289 documents features.sso as "wired; when falsy the /sign-in/sso route isn't mounted", but the served value is "usable", so a served false can mean "wired, no provider yet" with the route mounted. The type (sso?: boolean) is right.

Related: #29344 / PR #29455, #25292 / PR #25309.

Activity

  1. objectstack-fleet commented on Nov 2, 2026

    @objectstack-fleet
    ContributorAuthor

    triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U

    Path: none

    Triage: p1 · domain:spec · pm:queue · 2026-11-02T17:07Z

    ⛔ Not a claim.


    Generated by Claude Code

  2. objectstack-fleet commented on Nov 2, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:spec#3 · os-warren · session_01JQwxbahe4v7GBD94QeSnir

    Claim: PM loop round 3 · 2026-11-02T18:28Z
    Session: session_01JQwxbahe4v7GBD94QeSnir (seat); dev = card thread session_01JQwxbaRoocSDkgqwRAGseR
    Account: os-warren
    Branch: claude/project-thread-cxjusk
    Worktree: the card thread's own checkout of objectstack-ai/objectstack
    Domain: domain:spec
    Seat: domain:spec#3
    File surface: packages/spec/src/api/auth-endpoints.zod.ts (AuthFeaturesConfigSchema, and GetAuthConfigResponseSchema only for devSeedAdmin), one spec test pinning the registry keys as declared, the regenerated schema / reference / api-surface artifacts, root .changeset/; ⛔ not ui/**, ⛔ not packages/spec/src/api/protocol.zod.ts (frozen by server seat 5 until 06:00 UTC on 3 November) (stop on breach; explain in the report)
    Container & model: M, mode:thread (platform exception: the seat container pushes only its mailbox branch), model: TIER_DEFAULT (build; the widening is reviewed at CONTRACT_REVIEW_TIER), effort: xhigh asked for p1; the thread runs at the project's default effort because the coordinator cannot set it per thread
    Clause-②: yes
    Metadata-protocol: none (a wire response, not authorable metadata; the card proposed added, the dev confirms against AGENTS.md Post-Task Checklist step 3 and the PR body says why)
    Responsibility: n/a — not a defect card
    Thread-read: 6583289246
    Premise: holds (read on origin/main 390bd2ae: PR #29455 merged, AuthFeaturesConfigSchema at auth-endpoints.zod.ts ~L228 declares sso but not the nine served keys the card lists)
    Serial constraints cleared: PR #29455 (same schema) merged; no other open PR touches auth-endpoints.zod.ts, read over every open non-mailbox PR this patrol.


    Generated by Claude Code

  3. objectstack-fleet commented on Nov 2, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:spec#3 · os-warren · session_01JQwxbaRoocSDkgqwRAGseR
    os-dev-report

    Draft PR #29583 at head d68dd29f. The nine served features keys are declared on AuthFeaturesConfigSchema, one spec test pins the registry plus the non-flag list to the schema's declared keys (retired tombstones excepted), and devSeedAdmin is ruled out as dev-only. Declared Metadata-protocol: added, not the claim's none: the level-axis gate refuses none because this diff moves packages/spec/authorable-surface/api.json (measured, see deviations).

    {
      "issue": 29473,
      "status": "done",
      "branch": "claude/project-thread-cxjusk",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/29583",
      "session": "session_01JQwxbaRoocSDkgqwRAGseR",
      "premise_still_valid": true,
      "summary": "AuthFeaturesConfigSchema (packages/spec/src/api/auth-endpoints.zod.ts) gains nine optional keys with producer-accurate describes and no defaults: booleans multiOrgEnabled, degradedTenancy, oidcProvider, deviceAuthorization, admin; values tenancyPosture (TenancyPostureSchema), audiencePosture (AUDIENCE_POSTURES), termsUrl and privacyUrl (plain strings, as the producer serves the trimmed env value unvalidated). devSeedAdmin is not declared: plugin-auth serves it only under NODE_ENV=development and it carries the seeded admin's email and password; its one reader (console LoginPage) casts the raw response; the reason sits in a TSDoc block on GetAuthConfigResponseSchema. New test block in auth-endpoints.test.ts (38 cases) holds declared keys minus PUBLIC_AUTH_FEATURES_NOT_ADVERTISED equal to PUBLIC_AUTH_FEATURE_NAMES plus PUBLIC_AUTH_CONFIG_NON_FLAG_KEYS, both directions. Producer read on origin/main 390bd2ae: getPublicConfig() features literal serves exactly those 17 keys. The nine names and the devSeedAdmin ruling are listed in the PR's maintainer summary for Warren's nod.",
      "tests": "At d68dd29f: pnpm --filter @objectstack/spec test VERDICT 0, Test Files 799 passed (799), Tests 23700 passed, 1 todo; pnpm --filter @objectstack/spec typecheck VERDICT 0 (tsc, check:scripts-typecheck, check:test-typecheck). At 7d5a57a6 (pre-merge): spec test 794 files / 23587 tests passed; turbo build of @objectstack/client closure then @objectstack/client typecheck VERDICT 0; reverse probe in packages/client typing AuthFeaturesConfig: valid new keys exit 0, deviceAuthorization 'yes' refused TS2322 exit 2, probe deleted. Ablation via scripts/ablation-replace.mjs: deviceAuthorization renamed to deviceAuthorizationAblated (anchor 1 to 0, blob b237957a to 595c0b73), auth-endpoints.test.ts exit 1 with 3 failed (set-equality pin, that flag's boolean case, whole-response parse); restored, blob equals HEAD b237957a, git diff HEAD empty. Scoped eslint over the two changed .ts files exit 0; check-nul-bytes exit 0.",
      "gates": "At d68dd29f after merging origin/main 208d3e2e and turbo build of packages/** (VERDICT 0, 78 tasks): dispatch-gates --commands 103 derived, all 103 exit 0 (stdin closed, exit captured before any pipe); dispatch-gates --ran: 103 run, 0 NOT-MEASURED, 0 UNRUN. At 7d5a57a6 three first exited 3 (prerequisite) and passed once inputs existed: check-plugin-teardown-shape --self-test (after fetching fixture commit 621a4876), check:skill-examples (after building client-react), check:dual-build-cjs-loads (after building every package). Offline with the PR body: check-changeset-no-major --event exit 0 under added, exit 1 under none (authorable-surface baseline moved); check-partof-closing-keyword exit 0. check:generated exit 0 (14 artifacts current) after gen:docs. Local-only: check:skill-frame-freshness exit 0; check:dev-prereqs exit 1, machine state only (35 of 106 packages, ui among them, unbuilt here). CI check-runs: in_progress at report time, read by the seat.",
      "dogfood_battery": "n/a — no `!` in the PR title and no (narrowing) arm",
      "mcp_calls": "0",
      "api_writes": "2 — fleet-write relay repository_dispatch carrying pr_create (PR #29583, 13597 bytes sent and stored identical); post-stamped comment on #29473 (this report). git push is not a REST write.",
      "open_questions": [
        { "question": "devSeedAdmin: keep it undeclared (dev-only) or declare it on GetAuthConfigResponseSchema?", "options": ["A keep undeclared: a published contract would advertise a credential-bearing field no production deployment serves; the one reader never parses through the schema", "B declare an optional { email, password } object with a dev-only describe"], "recommendation": "A, because declaring it adds a password field to the generated public reference and buys no reader" }
      ],
      "deviations": [
        "Metadata-protocol: the claim recorded none; the PR and changeset declare added. AGENTS.md Post-Task Checklist step 3 calls a new key added, and packages/spec/authorable-surface/ records this response schema (api/AuthFeaturesConfig rows, the sso row landed under added). Measured: check-changeset-no-major --base origin/main --event exits 1 under none (Moved: packages/spec/authorable-surface/api.json) and 0 under added. The seat's go-ahead message said to declare what step 3 says.",
        "Clause-②: the claim line reads yes; the PR and changeset read yes (widening), as the dispatch order spelled it.",
        "Labels: none sent. The order named none, the diff publishes (no skip-changeset), and the relay refuses an empty labels array, so the key was omitted.",
        "PR body: the harness attribution comment is line 1 and Fixes #29473 line 3; the PR template's headings are folded into the os-dev order (What changes, Why, Tests, Acceptance notes, Verification, Human Minimum)."
      ],
      "body_amendments": "none",
      "security_findings": "none",
      "out_of_scope_findings": [
        "carrier: ui lane (the card's own prose-only note) · ui/packages/auth/src/types.ts lines 284 to 289 describe features.sso as wired while the served value is usable; the same hand-written mirror is where the nine new keys would be typed for the console · noted, not filed"
      ]
    }
  4. objectstack-fleet commented on Nov 3, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:spec#3 · os-warren · session_01JQwxbahe4v7GBD94QeSnir

    Landed · 2026-11-03T01:11Z

    Reading Value
    PR #29583 MERGED 2026-11-03 01:10:00Z via merge queue, merge commit 4b06a54a on main
    Card #29473 closed completed by Fixes #29473; no other closing keyword in the body

    State change: pm:dispatched removed from #29473 (a stay-behind tail of the stood-down seat). Delivered: AuthFeaturesConfigSchema declares the nine served features keys, and a set-equality pin holds the feature registry to the schema; devSeedAdmin stays undeclared (Warren's approval, PR comment 6591810483).


    Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions