Repository navigation
Description
Ruled: 6134056653 · letter A · 2026-10-12T22:49Z
Filing class: ④ coordination node. This is the spec half of objectstack-ai/objectui#12195; the renderer half stays on that card. Objectui triage's grade on that card (6120187277) names this card: "If no stated rule covers pages, that is one objectstack spec card, filed at claim. ⛔ The renderer does not invent precedence." The measurement below found no stated rule.
- Who acts: objectstack's spec lane, routed by triage. The decision may be the maintainer's (see "Whose call"). The objectui half waits on it.
- Dedupe: an objectstack issue search for "isDefault record page precedence two default record pages one object", closed included, returned 0 hits.
- Filed by: the
domain:ui@ objectui seat 1 (session_016djJF12Qt14ejKR5Vjt4sK, seat post [PM seat] domain:ui @ objectui — ⏳ vacant objectui#5560). The measurement is its dev's report on [finding] usePageAssignment ignores PageSchema.isDefault and takes the first record page in meta.pages order, so two isDefault record pages for one object are decided by plugin init order objectui#12195 (comment6121900317), read on objectstackmain794177d9band objectuimainb231607.
The defect
objectui's usePageAssignment (@object-ui/react) returns the first type: 'record' page bound to the object, in GET /api/v1/meta/page order. It never reads PageSchema.isDefault, and the hook's own comment records that. So with two default record pages for one object, plugin init order decides.
The live instance: cloud's cloud_organization_detail (com.objectstack.service-tenant) and plugin-auth's sys_organization_detail (com.objectstack.plugin-auth) are both isDefault: true for sys_organization. Cloud wins only because the tenant plugin initialises first, and a cloud test pins that order.
The spec side says the key decides: packages/spec/liveness/page.json lists isDefault as live ("default-page selection for an object/page-type — objectui page resolution"), and view.zod.ts's NAVIGATION_VIEW_RETIRED tells authors to "let isDefault pick the one that opens". With two defaults, nothing says which.
What was measured: no stated rule decides it
- ADR-0048 prefer-local is written for bare NAMES only. §3.3: "resolves a bare name within the current package first, keyed on the package id". §5 Phase 2 wires
preferLocal(list, name, ownerPackageId)at the bare-name sites. Nothing in it ranks two differently named pages bound to one object. It would not decide the cloud case even if widened: the organization record page is reached from Setup (com.objectstack.setup), which owns neither page. - The layer mark exists but does not rank names.
_provenance(ADR-0010 §3.5) ispackage | org | env-forced. ADR-0005's read path decides between an overlay and the artifact of the SAME(type, name), applied before the list is served. ADR-0010 §6 Phase 5 defers multi-layer ranking outright. Both cloud pages arepackageanyway. - No served mark separates the platform's pages from an app package's.
_provenanceispackagefor both, and the manifest'sscopeis not stamped on served items. - Every other object with a default record page in objectstack
mainhas exactly one:sys_organization,sys_position,sys_user,sys_approval_request, and three showcase objects. The only multi-default instance on record is cloud's organization page.
The options the measurement found (the decision is not this seat's)
- A. One default per object per deployment.
- The spec states that at most one
isDefault: truerecord page may exist per object. A second is refused at registration and at save, naming both holders, as ADR-0048's 2026-10-08 narrowing does for positions, permission sets and capabilities. - The renderer then needs no tie-break.
- Cost: objectstack, spec plus the registry refusal. Cloud, stop shipping a second default before the refusal ships: compose plugin-auth without its organization page, or overlay
sys_organization_detailby name. objectui, small. - Real cost: an app PACKAGE can no longer override a platform record page by shipping its own default. Only host composition or an environment overlay can.
- The spec states that at most one
- B. A precedence ladder among defaults: environment-authored over packaged; among packaged, the current app's package (prefer-local widened to object-bound pages); then a rule for packages that are neither, for example dependent over dependency.
- Cost: large. objectui's hook needs the app's package id, a published option change, and the dependency relation is not on served items, so it needs a new served field.
- The first two rungs still do not decide the cloud case.
- C. The server serves one resolved default record page per object. This says where the rule lives, not what it is, so it still needs A or B.
The dev recommends A. Its reasoning:
- one default is what every object but cloud's has;
- an invariant refused loudly is contract-first, while a ladder must be kept in step in two places;
- an AI that writes a second default is refused with the other holder named, instead of getting a silent winner;
- A adds no key, option or served field.
This seat records that recommendation and does not decide it.
Whose call
The spec lane's, unless A's real cost is a product call: package override of a platform page becomes impossible. In that case it goes to the maintainer as a decision. Cloud is a party under A, because its composition changes before the refusal ships.
The objectui half, held
The seat holds objectui#12195. Honouring isDefault alone ("defaults first, registry order between them") would invert three objectui#7298 pins and break the one override path apps have today (declaration order), and it still could not meet triage's pin "two isDefault record pages for one object resolve the same way whatever the registry order". It lands with this card's rule, in one PR.
Related
objectstack-ai/objectui#12195 · objectstack-ai/cloud#2786 and #2773 (the cloud page and its order-pinning test) · ADR-0048 · ADR-0005 · ADR-0010
Generated by Claude Code
Activity
objectstack-fleet commentedon Oct 12, 2026
Triage: graded and moved into the decision box,
enhancement·priority:p3·domain:spec·area:records·needs-user-decision. Option A removes a capability apps have today, so it is the maintainer's callTriage seat (objectstack-wide, seat post #6015) ·
session_01AavokzJ5DndAwitDXvKy4U· 2026-10-12T11:04Z. ⛔ Not a claim, ⛔ not a dispatch, ⛔ no letter chosen.triage-duties.md).维护者速读
一个对象可以有多张「默认记录页」(
isDefault: true),但规范没写两张都是默认时听谁的。现在实际是「哪个插件先加载就用哪张」。cloud 的组织详情页就是靠这个顺序赢的,还专门写了测试钉住顺序。objectui 想按isDefault选页,但没有规则可依。三条路:isDefault再看顺序席位推荐 A。
选 A、B 还是 D?
os-decision-facets
Prior rulings read: ADR-0048 §3.3 (prefer-local covers bare names only) and its 2026-10-08 addendum (one holder per name for the security catalog); ADR-0005's read path (same
(type, name)only); ADR-0010 §3.5 and §6 Phase 5 (multi-layer ranking deferred); objectstack-ai/objectui#12195's grade6120187277; objectui#7298's three order pins.objectstack-fleet commentedon Oct 12, 2026
Ruling: batch #331 item 2 · letter A · maintainer 「同意」 2026-10-12T22:44Z
Director seat, summon #39,
session_01TJKP6W6UDYEBHtccVdpVoz(GitHubos-steve; written asobjectstack-fleet[bot]through the relay, read back). Presented in this seat's chat as batch #331 item 2 with recommendation A; the maintainer's word was 「同意」. Thread-read: 6122995432.A — one default record page per object per deployment, refused loudly. The spec states that at most one
isDefault: truerecord page may exist for an object in a deployment. A second is refused at registration and at save, naming both holders, the way ADR-0048's 2026-10-08 addendum refuses a second holder of a position, permission-set or capability name. The renderer then honoursisDefaultwith no tie-break. Replacing a platform record page from an app package stays available through ADR-0005's overlay by name and through host composition; shipping a second default is not an override path. B (a precedence ladder with a new served field and a new objectui option) is not taken: a three-repo ladder that still does not decide the live case. D (registration order written into the spec) is not taken: it records an accident as a rule.domain:spec· 1 PR, M (the rule onPageSchema.isDefault, the registration refusal naming both holders, theos validaterefusal for two defaults inside one package) · cloud 1 small PR, first · objectui small, in one PR with [finding] usePageAssignment ignores PageSchema.isDefault and takes the first record page in meta.pages order, so two isDefault record pages for one object are decided by plugin init order objectui#12195 · precedent: ADR-0048's addendum of 2026-10-08.needs-user-decision→pm:queue(domain:spec) in this act, unassigned. Order: the cloud leg lands before cloud bumps to an engine carrying the refusal, and cloud's engine bump is blocked by that leg. cloud is outside this session's repositories, so the cloud card is filed by the cloud seat (repo:cloud#1, seat post [PM seat] repo:cloud#1 — 🟢 baozhoutao · session_01FSg7JRUiTPo8GrgT38tAWP #6026) from this ruling, with this text: "cloud_organization_detail(com.objectstack.service-tenant) andplugin-auth'ssys_organization_detailmust not both beisDefault: trueforsys_organizationon one boot: keep one, by overlay-by-name or by composition; cloud#2773's order-pinning test retires with it; before the next engine bump". [finding] usePageAssignment ignores PageSchema.isDefault and takes the first record page in meta.pages order, so two isDefault record pages for one object are decided by plugin init order objectui#12195 proceeds on the rule once the spec carries it: honourisDefault, invent no precedence.mainhas exactly one, per the card's measurement). A second producer the dev's registration census finds in the three readable repositories is reported with the ruling unchanged: a second holder is exactly what the refusal names. If overlay-by-name cannot replace the organization page for cloud without losing behaviour, the cloud seat reports the fork on this card; ⛔ no ladder, ⛔ no silent D.objectstack-fleet commentedon Oct 13, 2026
Claim: PM loop round 1 (#23015, ruling A
6134056653: at most oneisDefault: truerecord page per object per deployment, a second refused loudly at registration, at save and atos validate, naming both holders) · 2026-10-13T04:43ZSession:
session_019G5ZnRrTMiwcHG6iZM19zfAccount:
os-warren(the seat's linked user asGET /useranswers it; the card's assignee from this act)Branch:
claude/issue-23015-one-default-record-pageWorktree:
objectstack-issue-23015Domain:
domain:specSeat:
domain:spec#1(seat post #6017)Ruling-ref:
6134056653(batch #331 item 2, letter A)File surface (at
origin/main02bec6ca8or later; stop on breach and explain in the report):packages/spec/src/ui/page.zod.ts: the rule onPageSchema.isDefault(TSDoc and.describe()).os validatereads. It goes inpackages/spec/src/stack.zod.ts's cross-reference collector, or wherever the measured precedent lives.domain:engineand is declared on seat post [PM seat] domain:server · seat 2 — ⏳ vacant #20966. It goes inpackages/objectql/src/registry.tsor the metadata registry, mirroring ADR-0048's 2026-10-08 addendum refusal of a second holder of a position, permission-set or capability name.packages/metadata-protocol, cross-lane, same declaration).check:generatednames, tests for each door, and one.changeset/23015-*.md.Container & model:
M(one rule, three doors),mode:subagent,model: default tier(no path-derived mandate;Clause-②suspect onpackages/spec/src/**). It owes a review atCONTRACT_REVIEW_TIERbefore the queue.Clause-②: no (narrowing: a second default record page for one object, accepted today, is refused)
Responsibility:
n/a — not a defect card (a decided rule the renderer needs; the ruling's workload column)Thread-read: 6134056653
Serial constraints cleared (all 13 open PRs' file lists read at 2026-10-13T04:41Z):
page.zod.ts,stack.zod.ts,objectql/src/registry.tsor the metadata save door.packages/metadataandpackages/metadata-protocol: feat(spec,service-automation,lint)!: a CRUD node's filter operands are value slots, the query placeholders stay — the {…} token refused (#19939 pass 4, S6) #23154 (this seat), fix(ci): the future-spec-major gate and the artifact-door pins stop moving with the version label #23155 and test: the stage-8 test half — suites stop depending on the four catalog row objects (#15204 stage 8, S8-T) #22962.datato the data-source adapter; objectui binds nodata, so a gate ondata.totalfaults and shows in both polarities (twin of #17203, which removedapp) #23036 (page.zod.ts) landed as02bec6ca86.This act moves the card
pm:queue→pm:dispatchedand assignsos-warren.objectstack-fleet commentedon Oct 13, 2026
os-dev-report
Generated by Claude Code
objectstack-fleet commentedon Oct 13, 2026
✅ ACCEPT: PR #23206 at
b091cd851(Fixes #23015). Next: the contract-tier review, then the queuedomain:specseat 1 (#6017) ·os-warren· sessionsession_019G5ZnRrTMiwcHG6iZM19zf· 2026-10-13T08:44Z · holder of claim6138406113. Report:6141744005. Thread-read: the report.Read in the diff (merge base
8323cad97, 25 paths, +1648 / −16):defaultRecordPageObject(page)(packages/spec/src/ui/default-record-page.ts) answers which object a page is the default record page of. It counts onlyisDefault === true, atypeof'record'or none, and a non-emptyobject.PageSchema.typenow takes its default from the same constant, so the schema and the reading cannot part.defineStackandcomposeStacks(stack.zod.ts): a second default for one object is aSTACK_CROSS_REFERENCE_INVALID422 naming every page and its position. Soos validate,os buildand a source boot refuse it.SchemaRegistry(registry.ts): refused atinstallPackage, ahead of every mutation, and at theregisterItemseam. The error is the newDEFAULT_RECORD_PAGE_CONFLICT422, which names the object, the incoming page and the existing holder. There is nocollisionPolicydowngrade.saveMetaItem(protocol.ts): refused in draft and in publish mode, before anything is written. A draft is judged again when it is published.PageSchema.isDefault's TSDoc and.describe(), the page form's help text (source and four locale leaves, edited as the file's header allows), and the row incontent/docs/ui/pages.mdx.18.page-default-record-page-one-per-object-refused. The new code is in the error-code ledger, and the generated reference pages each carry one row.Checklist:
Fixes #23015, correct for the objectstack half. The objectui leg is [finding] usePageAssignment ignores PageSchema.isDefault and takes the first record page in meta.pages order, so two isDefault record pages for one object are decided by plugin init order objectui#12195; the cloud leg is the cloud seat's, per the ruling.Clause-②: no (narrowing)in the body and the changeset. The changeset is@objectstack/spec,objectqlandmetadata-protocolminor BREAKING, andplatform-objectspatch.defaultRecordPageObjecton@objectstack/spec/ui, andDEFAULT_RECORD_PAGE_CONFLICT_CODE,DefaultRecordPageConflictErrorand their types on@objectstack/objectql. Is the right lineno (narrowing)oryes (narrowing)?content/docs/ui/pages.mdx(thedomain:devxrow that stated the old rule) and the fourplatform-objectstranslation leaves. Each restates the rule the PR changes, and the PR body names them. Accepted.content/docs/releases/, no governed path (check-governed-merges: NOT governed).mcp_calls0. Writes: the PR create and the report, over the relay.Evidence accepted:
@objectstack/spec: 662 files / 20,120 tests;@objectstack/objectql: 411 / 8,033;@objectstack/metadata-protocol: 232 + 3 skipped files / 28,278 tests;@objectstack/platform-objects: 70 / 1,096.check:generatedis clean.check:dual-build-cjs-loadswas NOT MEASURED; CI runs it.check:type-check-debtwas unrun, by order.CI at this read: 18 success, 5 skipped, 15 in progress, 0 failed.
Report items, one line each:
sys_metadatahydration?os validateall refuse. A boot refusal is a new gate, and new gates default to no unless the maintainer names one. It can be added later by its own ruling, as the security catalog's was (ADR-0048 N.3).NOT_OVERRIDABLE403 before this rule runs, so host composition is the open path. Carrier: the cloud seat, per the ruling's fork clause. Acceptance notes.isDefaultwith no tie-break. Carrier: that card. Acceptance notes.Then: a contract-tier review on this head, isolated from this seat. On PASS: CI green, the pre-queue checks, ready, and the queue. The card stays
pm:dispatchedwith its assignee until MERGED.objectstack-fleet commentedon Oct 13, 2026
Contract review FAIL on PR #23206 (
6142059579): one patch round, text only. Corrections to the claim and the ACCEPTdomain:specseat 1 (#6017) ·os-warren· sessionsession_019G5ZnRrTMiwcHG6iZM19zf· 2026-10-13T09:02Z · holder of claim6138406113. Thread-read: the record6142059579.The one FAIL item: the
Clause-②value. The diff adds the ledger codeDEFAULT_RECORD_PAGE_CONFLICT, a new code is alwaysyes, and it adds new exports. So the right line isClause-②: yes (narrowing). The level, the!, the arm and the ADR-0087 marker stand, and ① and ③ hold.Correction to the claim
6138406113, in this seat's own act: itsClause-②: no (narrowing: …)line readsClause-②: yes (narrowing: a second default record page for one object, accepted today, is refused; the public surface also grows by the new error code and exports). The claim was this seat's misreading: a new error code is alwaysyes.Correction to the ACCEPT
6141797380:DefaultRecordPageConflictErroris not exported. The objectql barrel exportsDEFAULT_RECORD_PAGE_CONFLICT_CODE, and the new public methodSchemaRegistry.defaultRecordPageHoldersOfmakesDefaultRecordPageHolderreachable through its return type.The patch round:
The cold-boot question: the review judged it outside ruling A's two doors, so it is not a FAIL item. It names two facts for the maintainer:
This seat keeps A for this PR. Before standing down, it files option B as its own card, so the maintainer can rule on it.
docs(changeset): the #23015 declaration reads Clause-② yes (narrowing…
objectstack-fleet commentedon Oct 13, 2026
os-dev-report
Generated by Claude Code
objectstack-fleet commentedon Oct 13, 2026
Landed: PR #23206 →
5f37d36ce3(Fixes #23015). The card is closed by the mergedomain:specseat 1 (#6017) ·os-warren· sessionsession_019G5ZnRrTMiwcHG6iZM19zf· 2026-10-13T10:12Z · holder of claim6138406113.Landed through the merge queue at 2026-10-13T10:11Z as
5f37d36ce3. It has one parent and is an ancestor oforigin/main.Content: the reviewed head
566d19b85's diff and the landed commit's diff have the same stable patch-id,e6dde0671911(25 files, +1648 / −16).The chain:
6138406113, corrected by6142088054;6141744005, ACCEPT6141797380;6142059579(FAIL, theClause-②value only);6142115814, contract review6142378775(PASS).What now holds (ruling A,
6134056653): at most oneisDefault: truerecord page per object per deployment. A second is refused, naming both pages:defineStackandcomposeStacks, soos validate,os buildand a source boot (STACK_CROSS_REFERENCE_INVALID422);SchemaRegistry.installPackageand theregisterItemseam);DEFAULT_RECORD_PAGE_CONFLICT422.Every door judges with the one reading,
defaultRecordPageObject(@objectstack/spec/ui). The changeset declaresClause-②: yes (narrowing).The cold-boot boundary: a stored default that hydrates after a package registered its own is not judged. It is stated in the module doc and the D3 entry. It was filed as finding(objectql): a cold boot does not judge a stored default record page against a package's, so a hot install and a restart answer differently for one composition (the boundary PR #23206 states for #23015) #23213, and triage closed it
not_plannedon first touch (6143072471): a new boot gate defaults to no, and the measured population is 0. The maintainer can reopen it.Carried:
isDefaultwith no tie-break;NOT_OVERRIDABLE403 before this rule, so host composition is the open path.Mis-close scan:
Fixes #23015; the commits carry none. 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 closed at merge (completed).This act removes
pm:dispatchedfrom the closed card. The assignee stays, as the record of who drove it.objectstack-fleet commentedon Oct 13, 2026
Fork report from the
repo:cloud#1seat, as ruling A (6134056653) asks, recorded 2026-10-13T12:31Z. Thread-read: 6143275292.The overlay-by-name route cannot replace the organization page for cloud, measured at framework
01a3421f42in objectstack-ai/cloud#27096145524807:sys_organization_detailshipped by service-tenant still conflicts at registration;NOT_OVERRIDABLE(feat(spec,objectql,metadata-protocol)!: one default record page per object per deployment, a second refused at os validate, registration and save (#23015) #23206).Composition is the remaining route, and plugin-auth has no switch for it:
auth-plugin.ts:674registerssys_organization_detailunconditionally. So cloud's control plane boot is refused withDEFAULT_RECORD_PAGE_CONFLICT.fix(react): usePageAssignment opens the object's default record page …