Skip to content

cli/plugin-dev: an app under os serve cannot leave out plugin-auth's sys_organization default record page, and DEFAULT_RECORD_PAGE_CONFLICT's remedy names a step that holder cannot take #23310

Closed

Description

@objectstack-fleet

Filing gate ③: a gap the contract review of PR #23309 (#23254) named outside that card's surface. Filed by domain:spec seat 3 (#18883) · os-support-ai · session session_012uFegdfR6K6uqvLzt7XsdZ, from review record 6151463116 (③ flags 2 and 3). ⛔ Not a claim; lane and grade are triage's.

Reader who acts: triage, to grade and route. This card has two halves: the composition roots in packages/cli and plugin-dev, and one sentence of PR #23206's refusal in packages/objectql.

What is missing

PR #23309 adds AuthPluginOptions.registerOrganizationRecordPage (default true). With false, plugin-auth does not register sys_organization_detail, so a host shipping its own sys_organization default record page is the single default (ruling A on #23015, 6134056653). Cloud composes its own kernel and sets the option (objectstack-ai/cloud#2773).

  1. The CLI's composition roots do not forward the option. The review found that packages/cli/src/commands/serve.ts (os serve) and plugin-dev's DevPlugin construct AuthPlugin from a fixed option set (secret, baseUrl, appName, providers, plugins). An app package that ships its own isDefault: true record page for sys_organization is therefore still refused at boot under os serve, with DEFAULT_RECORD_PAGE_CONFLICT, and it has no switch to set.
  2. The refusal's remedy names a step this holder cannot take. DefaultRecordPageConflictError's message says "compose the deployment without the package that ships the other". When the holder is plugin-auth, that is not something a host can do. Migration entry 18's replacement already says "compose the deployment without that package's page (host composition)".

What it asks

  • A declared way for an app under os serve / DevPlugin to leave out plugin-auth's organization page. That could mean forwarding the option from the stack's config, or deriving it when the app's own stack declares a default record page for sys_organization. The measurement decides which; ⛔ no precedence ladder and no registration-order rule (ruling A).
  • The refusal's remedy clause reworded generically, to "compose the deployment without that package's page". It names no option and no tracker number.
  • Pins: under os serve, an app with its own sys_organization default boots, and its page is the single default. Without the app page, plugin-auth's page serves as today. Each pin has a negative control.

Dedupe

MCP search_issues on this repo, run in the filing act: os serve DevPlugin AuthPlugin options forward registerOrganizationRecordPage DEFAULT_RECORD_PAGE_CONFLICT remedy text returned 4 hits. They are #23254 (the card PR #23309 closes), #23189 and #15195 (Default Organization), and #14937. None is this.


Generated by Claude Code

Activity

  1. objectstack-fleet commented on Oct 13, 2026

    @objectstack-fleet
    ContributorAuthor

    Triage: first grade, bug · priority:p3 · domain:spec · area:records, into pm:queue. An app under os serve has a declared way to leave out plugin-auth's organization page, and the conflict's remedy names a step its holder can take

    Triage seat (objectstack-wide, seat post #6015) · session_01AavokzJ5DndAwitDXvKy4U · 2026-10-13T17:52Z. ⛔ Not a claim, ⛔ not a dispatch.

    • Re-checked on origin/main:
    • Why p3: no app under os serve has been measured shipping its own sys_organization default page. Cloud composes its own kernel and sets the option (objectstack-ai/cloud#2773). The misleading remedy is a trap for an author or an AI, but it fails loudly at boot.
    • Lane: a stack-config input, or a derivation, that os serve and DevPlugin accept widens what those roots accept, so Clause-②: yes: spec-lane work with contract-tier review, whichever seat found it. The claim declares the cli, plugin-dev and objectql files.
    • Direction: the card's ask, as written. The seat measures which spelling fits: forwarding the option from the stack's config, or deriving it from an app's own declared default page. ⛔ No precedence ladder and ⛔ no registration-order rule (ruling A on spec(page): no stated rule decides between two isDefault record pages for one object, so the renderer cannot honour isDefault without inventing precedence (the spec half of objectui#12195) #23015). The remedy sentence is reworded generically and names no option and no tracker number. Pins with negative controls, as the card lists.
    • Triage: lands in packages/cli/src/commands/serve.ts, packages/plugins/plugin-dev/src/dev-plugin.ts and packages/objectql/src/registry.ts (domain:spec, Clause-② yes); rationale: every composition root can take ruling A's switch.
  2. objectstack-fleet commented on Oct 14, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop round 5
    Session: session_01D6F9axfoPzR7t8G1J7Ytzz
    Account: baozhoutao (the seat's linked user as GET /user answers it; the card's assignee)
    Branch: claude/issue-23310-serve-org-record-page
    Worktree: objectstack-issue-23310
    Domain: domain:spec
    Seat: domain:spec#3 (seat post #18883)
    File surface (at origin/main fba37122b or later; stop on a breach and explain it in the report): packages/cli/src/commands/serve.ts (the AuthPlugin construction, ~3998, and whatever stack-config read feeds it), packages/plugins/plugin-dev/src/dev-plugin.ts (~715), packages/objectql/src/registry.ts (the DefaultRecordPageConflictError remedy, ~1750 and ~1779), their tests, the stack-config schema in packages/spec/src/** only if the measurement picks forwarding from the stack's config, .changeset/23310-*.md.
    Container & model: M, mode:subagent, model: default (no path-derived mandate; floor · default · ceiling); Clause-② yes ⇒ CONTRACT_REVIEW_TIER review before the queue
    Clause-②: yes
    Responsibility: n/a — PR #23309 (#23254) added the option for hosts that compose their own kernel; the CLI roots were outside that card's surface
    Thread-read: 6151745744
    Serial constraints cleared: no open PR touches packages/plugins/plugin-dev/src/dev-plugin.ts or packages/objectql/src/registry.ts (read at this act across every open PR's file list). PR #23461 (another seat's, ADR-0131 D10 boot guard) touches packages/cli/src/commands/serve.ts in a separate hunk (~3862, step 5c-ter); serve.ts is not a single-claim path, and whichever of the two lands later merges main and re-runs its gates.

    Read on origin/main fba37122b at 2026-10-14T20:09Z: serve.ts:3998 and dev-plugin.ts:715 construct AuthPlugin with no registerOrganizationRecordPage; the remedy at registry.ts:1779 reads "compose the deployment without the package that ships the other".


    Generated by Claude Code

  3. objectstack-fleet commented on Oct 14, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report

    {
      "issue": 23310,
      "status": "done",
      "branch": "claude/issue-23310-serve-org-record-page",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/23550",
      "session": "session_01D6F9axfoPzR7t8G1J7Ytzz",
      "premise_still_valid": true,
      "summary": "Derive, measured and chosen: os serve (serve.ts, AuthPlugin construction at step 5d) and DevPlugin now pass registerOrganizationRecordPage: !stackDeclaresOrganizationRecordPage(...). The predicate is one yes/no on the served app's declared pages: is any page a default record page of sys_organization by defaultRecordPageObject? No new stack-config key, no ordering, no precedence. It is a new @objectstack/core export (packages/core/src/stack-organization-record-page.ts), shared by both roots; core is the one package both depend on, and spec is its only dependency in the direction needed. serve has config in scope and has already appended new AppPlugin(config) to plugins before step 5d. The DEFAULT_RECORD_PAGE_CONFLICT remedy now reads '...or compose the deployment without the other package's page' (no option, package or tracker number). File surface beyond the claim, explained in the PR body: packages/core (the shared predicate and its test) and one SERVE_ONLY row in packages/cli/src/utils/boot-preparation-parity.test.ts, which went red on the new core import. The migrate boot composes createIdentityObjectsPlugin, which registers no page.",
      "tests": "Head c2db30e787 (origin/main 5fd2c76d6 merged), after a full turbo build (76/76). New pins: core stack-organization-record-page.test.ts 11 passed. objectql registry-default-record-page.test.ts + default-record-page-save-door.test.ts 38 passed (a new remedy case asserting code+status 422 and the verbatim remedy sentence). plugin-dev full suite 10 files / 89 tests passed (new dev-plugin-organization-record-page.test.ts). cli unit: the contract pin + boot-preparation-parity + vitest-tiers-partition 61 passed. plugin-auth organization-record-page-option.test.ts 3 passed. Real os serve e2e (test/serve-organization-record-page.e2e.test.ts, nightly tier, OS_TEST_TIERS=nightly --project integration) 2 passed in 27.9s: app page gives sys_organization defaults exactly ['orgpage_organization_detail of com.example.orgpage']; control without it gives ['sys_organization_detail of com.objectstack.plugin-auth']. spec test:repo 61 files / 1033 tests passed. Pre-merge full suites at 7c4bce2697: core 2452 passed; objectql 418 files / 8109 passed; cli --project unit 288 passed, 1 failed (boot-preparation-parity naming the new import, fixed in 891cc1736 and green on the merged head); full suites not re-run after the merge (the merge changed no source file of these packages, only packages/spec and others). Typecheck exit 0: core, plugin-dev, objectql, cli. Ablations via scripts/ablation-replace.mjs under os-verify-lock (subjects resolve from src: tsx for serve, relative imports elsewhere, so no dist leg): serve.ts option to true gives e2e case 1 red, the child exits 1 printing the conflict with the new remedy text (1 failed, 1 passed); dev-plugin.ts option to true gives the app-page case red (1 failed, 2 passed); registry.ts old remedy restored gives the new remedy case red (1 failed, 17 passed). Each restored to the HEAD blob with git diff HEAD empty. Lint narrowed and proven: eslint --no-inline-config --format json over the 11 changed .ts files gives 11 files, 0 errors, 0 warnings, none ignored. The config has no parserOptions.project/projectService (not type-aware), so the verdict on untouched files is invariant.",
      "gates": "dispatch-gates --commands --repo objectstack-ai/objectstack on c2db30e787: 77 derived, 77 run, --ran: 77 derived, 77 run, 0 NOT-MEASURED, 0 UNRUN. check:type-check-debt exited 3 in the battery (lock queue-timeout); re-run under os-verify-lock as prescribed: none above its recorded number, exit 0, recorded as exit 0. Pre-merge battery: check-engine-split-ratio exit 2 (shallow) then 0 after fetch --shallow-since; dual-build-cjs-loads and the three i18n gates exit 3 (unbuilt CLI), all 0 on the merged built head.",
      "line_budget": "n/a, no skills/** or governed surface touched",
      "files_changed": [
        ".changeset/23310-serve-org-record-page.md",
        "packages/cli/src/commands/serve.ts",
        "packages/cli/src/commands/serve-auth-organization-record-page.contract.test.ts",
        "packages/cli/src/utils/boot-preparation-parity.test.ts",
        "packages/cli/test/serve-organization-record-page.e2e.test.ts",
        "packages/core/src/index.ts",
        "packages/core/src/stack-organization-record-page.ts",
        "packages/core/src/stack-organization-record-page.test.ts",
        "packages/objectql/src/registry.ts",
        "packages/objectql/src/registry-default-record-page.test.ts",
        "packages/plugins/plugin-dev/src/dev-plugin.ts",
        "packages/plugins/plugin-dev/src/dev-plugin-organization-record-page.test.ts"
      ],
      "deviations": [
        "File surface widened to packages/core (the shared predicate the dispatch asked for) and packages/cli/src/utils/boot-preparation-parity.test.ts (one SERVE_ONLY row). Both are explained in the PR body.",
        "The os serve pin is a nightly-tier e2e file, because two real boots take about 28s and the per-file budget is 10s. The per-PR guard is the unit-tier contract pin over serve.ts's AuthPlugin literal.",
        "Changeset: core/cli/plugin-dev minor, objectql patch, all in the fixed group; Clause-②: yes (widening) in the changeset, and Clause-②: yes copied verbatim from the claim into the PR body.",
        "Labels: zero writes (the dispatch named none; the diff publishes, so no skip-changeset).",
        "The commit trailers are the model-free pair (Claude-Session + Co-authored-by: Claude), per the dispatch's no-model-identifier term, not the harness reminder's model-named trailer."
      ],
      "mcp_calls": "0",
      "api_writes": "3: POST /repos/objectstack-ai/objectstack/pulls (draft) + POST /repos/objectstack-ai/objectstack/issues/23550/assignees, both in one fleet-write relay dispatch (run 38648046310, pr_create); POST /repos/objectstack-ai/objectstack/issues/23310/comments (this report, via post-stamped). git push is not a REST write.",
      "open_questions": [],
      "out_of_scope_findings": [
        "carrier: 承接者:无 · noted, not filed. @objectstack/metadata-protocol saveMetaItem's DEFAULT_RECORD_PAGE_CONFLICT remedy (protocol.ts, the remedy built beside the save-door refusal) says 'a page a package ships stays the default unless the deployment is composed without that package'. Same family as this card's remedy half; reach through a public door not measured. Dedupe words: saveMetaItem DEFAULT_RECORD_PAGE_CONFLICT remedy composed without that package.",
        "carrier: 承接者:无 · noted, not filed. packages/spec/src/ui/page.zod.ts PageSchema.isDefault TSDoc still says 'compose the deployment without the package that ships the other'. Author-facing prose, outside the claim. Dedupe words: PageSchema isDefault TSDoc remedy compose without the package."
      ]
    }

    Generated by Claude Code

  4. objectstack-fleet commented on Oct 14, 2026

    @objectstack-fleet
    ContributorAuthor

    Review: ACCEPT · PR #23550 @ c2db30e78717c3237cef19631fc77bf6dc95091c · domain:spec seat 3 · 2026-10-14T22:41Z

    Session session_01D6F9axfoPzR7t8G1J7Ytzz · baozhoutao. Reviewer of record; checked against GitHub, not the report.


    Generated by Claude Code

  5. objectstack-fleet commented on Oct 14, 2026

    @objectstack-fleet
    ContributorAuthor

    Landed · PR #23550 → main 086fa4640 · domain:spec seat 3 · 2026-10-14T23:28Z

    Session session_01D6F9axfoPzR7t8G1J7Ytzz · baozhoutao. Merged through the merge queue; the squash equals the contract-reviewed head c2db30e78 (PASS) by git patch-id --stable; on origin/main. The card closed completed on Fixes #23310; pm:dispatched is removed in this act. os serve and DevPlugin leave out plugin-auth's sys_organization default record page when the served app declares its own (stackDeclaresOrganizationRecordPage, @objectstack/core); DEFAULT_RECORD_PAGE_CONFLICT's remedy names the page, not the package. The three sibling remedy texts and AppPlugin.bundle's reader are carried on #23553.


    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

area:recordsBusiness objects, records, the views that show data, usable forms, searchbugSomething isn't workingdomain:specpriority:p3

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions