Skip to content

refactor(spec)!: retire PageHeaderProps.icon, PageCardProps.actions, RecordDetailsProps.layout (#6946) - #7115

Merged
os-zhuang merged 1 commit into
mainfrom
claude/issue-6946-retire-three-ui-keys
Aug 9, 2026
Merged

refactor(spec)!: retire PageHeaderProps.icon, PageCardProps.actions, RecordDetailsProps.layout (#6946)#7115
os-zhuang merged 1 commit into
mainfrom
claude/issue-6946-retire-three-ui-keys

Conversation

@os-zhuang

@os-zhuangos-zhuang commented Aug 9, 2026

Copy link
Copy Markdown
Contributor

Closes#6946

The ruling

Maintainer ruling 2026-08-09 (decision-inbox round), quoted verbatim and untranslated:

全部接受

Applied to the two objectui cards this one dispatches: objectui#3829 route (c) — retire PageHeaderProps.icon and PageCardProps.actions upstream — and objectui#3818 — retire RecordDetailsProps.layout. All three are the ADR-0049 declared-but-unenforced shape on the SDUI page-component contract: the spec advertised configuration objectui drops on the floor, and the author got a success receipt for it.

Zero-reader self-verification — re-run here, not inherited

The #6926 lesson (a retirement on this same schema family fell to STOP-and-escalate earlier today because an inherited "zero consumers" grep had missed five objectui reads) makes the measurement mine, not the card's. objectui was cloned read-only and checked out at the SHA .objectui-sha pins — 09987b680d53801c79f67d969b14e9bb732b8a22 (3 879 tracked files) — and the reverse lookup re-run there and in this repo, each scan carrying a control probe that must hit alongside the probe that must not (#4878 method).

PageHeaderProps.icon — no read point

probescopeexpectmeasured
/icon/ inside PageHeaderRenderer (components/src/renderers/layout/containers.tsx:900-1596)the renderer that owns page:headerMISS (as a props-bag read)5 hits, all action.icon (:1322, :1338, :1366, :1386) plus one prose comment — zero read the header's own bag
control/recordChrome/same rangeHIT3
control/showStar/same rangeHIT3
control/subtitle/same rangeHIT7
schema\??\.icon|properties\??\.iconobjectui, all non-test sourceMISS on page:header9 hits: statistic, form:button, action:icon, action:group, action:button, action:menu (2), and one builder setternone on page:header
/icon/ in @object-ui/layout's PageHeader.tsxthe other component named PageHeaderMISS as a schema readicon is a React prop from a host (:117, rendered :224-226) with no schema fallback
in-file control — schema-sourced reads in that same filesame fileHITschema?.children (:182), schema?.actions (:194), schema?.properties?.actions (:195) — the fallback icon conspicuously lacks, four lines away
registry inputs for page:headercontainers.tsx registrationno icontitle, subtitle, actions, breadcrumb, recordChrome, showStar, showCopyId

objectui's own apps/console/src/__tests__/registry-inputs-spec-parity.test.ts carries this as a B-class UNPUBLISHED_EXEMPTIONS entry — an independent measurement of the same fact, taken in the other repo:

'page:header.icon': 'Spec declares it; PageHeaderRenderer has NO read point — icon in containers.tsx:822-1570 is only ever per-action (action.icon, :1321/:1365) or a nav item (:604). Wire it, or declare it with a KNOWN GAP per the showSubscriptionToggle precedent: objectui#3829.'

PageCardProps.actions — no read point

probescopeexpectmeasured
whole PageCardRenderer body (containers.tsx:666-721)the renderer that owns page:cardno actionsreads exactly title, bordered, body ?? children, footerno actions, no actions area in the markup
control/footer/, /bordered/same rangeHITboth read and rendered
schema\??\.actions|properties\??\.actionsobjectui, all non-test sourceMISS on page:card16 hits — nav:header-bar, page:header (containers.tsx:987, layout/PageHeader.tsx:194-195), action:group/bar/menu, DetailView, record:quick_actions, one doc comment. Zero on page:card
registry inputs for page:cardcontainers.tsx registrationno actionstitle, bordered, body, footer

objectui's exemption map again:

'page:card.actions': 'Spec declares it; PageCardRenderer (containers.tsx:666-695) renders title/body/footer only and never reads actions. Wire it, or declare it with a KNOWN GAP per the showSubscriptionToggle precedent: objectui#3829.'

RecordDetailsProps.layout — read, and inert anyway

This one is not a zero-read-point key, and the report says so rather than rounding it to the family's shape. plugin-detail/src/renderers/record-details.tsx:104 does read it:

constlayout: 'vertical'|'horizontal'=schema.layout==='inline'||schema.layout==='compact' ? 'horizontal' : 'vertical';

The declared enum is auto | custom. Neither legal value can match, so both take the same vertical branch — the key was accepted, read, and could not change anything, under a .describe() promising "auto uses object highlightFields, custom uses explicit sections". That behaviour is real, but the renderer keys it off whether sections was authored, never off this flag. That is exactly what objectui#3818 names ("delete the layout input + the dead inline|compact branch"), so the ruling is decided on this fact, not despite it — no live verdict, no STOP condition.

probescopeexpectmeasured
schema\??\.layout|properties\??\.layoutobjectui, all non-test sourceone hit on record:details, dead13 hits: record-details.tsx:104 (the dead branch), plugin-form ×6, plugin-view ×2, one builder setter — no other record:details read
controllayout === 'auto' | 'custom'objectui + frameworkMISS0 in both repos
controllayout === 'vertical' | 'horizontal'objectuiHITplugin-form/plugin-view honour their own live layout
registry inputs for record:detailsplugin-detail/src/index.tsx:274declares layoutenum: ['auto','custom'], defaultValue: 'auto'the same enum this spec declares, which is why check:react-declaration-parity (two DECLARATIONS, never a declaration vs an implementation) reported agreement over it
third spelling@object-ui/types/src/record-components.ts:43layout?: 'stacked' | 'inline' | 'compact' — three declarations of one key, none of them the branch the renderer takes

Framework side (this repo, f5a9bc2)

Zero semantic readers of all three. The .icon hits across packages/** are other domains entirely (nav, book, automation entries, connectors, field-group); i18n-resolver walks properties by key-name convention and passes non-translatable props through untouched (control: it names title/subtitle 26×). What this repo does have is authors: four pages wrote page:header.icon and none ever drew one — the showcase's project workspace, and the published mcp / cloud-connection platform pages. They are cleaned up here.

Liveness ledger

No rows exist for these keys, and none should. The gate walks PageSchema's own shape (liveness/page.json — 17 rows: name, label, icon (the page's nav icon, live and untouched), regions, slots, …); PageComponent.properties is z.record(z.string(), z.unknown()), so component props are below the walk and the ledger has never carried one — the page:card.body precedent (#3809/#5775) added none either. Nothing to add under the tombstone route, nothing orphaned. check:liveness PASS confirms both directions.

Implementation

Tombstones (retiredKey()) on all three, so the removal is audible in the two channels an upgrading author hits: the input type becomes never, and the parse raises the prescription itself. Each prescription closes with the #6856 house sentence verbatim (Run `os migrate meta --from 16` to rewrite existing sources automatically.) — pinned class-wide by retired-key-migrate-sentence.test.ts, which passes.

⚠️ Worth stating because it bounds the sweep: the tsc channel does not reach the page carrier.PageComponent.properties is an open z.record(z.string(), z.unknown()), so the four in-repo author sites do not fail to compile — they were found by grep and by the ComponentPropsMap parse that packages/lint's validate-component-props rule runs (component-props-invalid, advisory). The playbook's "let the tombstone find the callers" leans on tsc; on this surface the lint rule is the channel, and the sweep was done by hand accordingly.

Two ADR-0087 D2 conversions, mirroring the two rulings 1:1 rather than merged, because the rationales are genuinely different:

idkeysshape
page-structure-inert-keys-removedpage:header.icon, page:card.actions (objectui#3829)pure strip — no reader, and no lossless rewrite target (a header has no second icon slot; moving a card's action ids into children as components is a page rewrite, not a mechanical one)
record-details-layout-removedrecord:details.layout (objectui#3818)pure strip, as ruledauto, custom and omission were behaviourally identical, so there is no value to carry

Both retiredFromLoadPath: true, both wired into MIGRATIONS_BY_MAJOR[17].conversionIds with the step's rationale extended, toMajor matching the step. Walker reach verified against the current walk.ts (reworked by #7034): mapPageComponents visits regions[].components[], slots.NAME (both the single-component and array forms) and every properties container nested to any depth — all three keys live on component.properties in exactly those positions, and the fixtures exercise the region form, the nested-container form and the named-slot form.

Both strips are scoped by component type, never by key namepage:header.actions and record:highlights.layout are LIVE keys sharing these leaf names, and both fixtures carry them as in-fixture controls.

Registries: three exact-key RETIRED_KEYS_BY_MAJOR[17] entries (ui/PageCardProps:actions, ui/PageHeaderProps:icon, ui/RecordDetailsProps:layout) — the string gate (b) reads by set membership, which this family needs literally given the shared leaf names.

No DEFAULT_CHANGES_BY_MAJOR[17] row is required, and that is measured rather than assumed: authorable-defaults/ui.json drops ui/RecordDetailsProps:layout = "auto" because the key became [RETIRED], and the #4666 ratchet resolved its baseline against upstream and reported it as no change —

🔒 authorable-defaults/ verified against upstream f5a9bc2f3d8e — 1310 default(s) unchanged (#4666).

No D3 SemanticMigration. These are authored/stored page metadata with a D2 conversion that rewrites them, so the EnhancedApiError.fieldErrors disposition (semantic entry instead of a conversion, for response surfaces with no source to rewrite) does not apply.

Ratchet answers — deliberate, per the route table

The brief warned to expect the json-schema.manifest deletion ratchet and the authorable-surface deletion gate to fire. Neither did, and that is the correct reading for this route — the playbook's §2 table makes the expectation route-dependent, and reading it the other way is how a def that was never really deleted gets waved through:

artifactpredicted (tombstone route)measured
authorable-surface/ui.jsonthree lines gain … [RETIRED]; no line vanishes (a retiredKey() is still a property in the walked shape)exactly that — PageCardProps:actions, PageHeaderProps:icon, RecordDetailsProps:layout each + [RETIRED]
json-schema.manifest/ui.jsonbyte-identical — no def is deleted, only a def's key set narrowsbyte-identical; the per-key deletion ratchet never fires
api-surface/, api-surface-signatures.jsonbyte-identical — the snapshot prints type references, blind to key-level narrowing, and no orphaned value schema goes with these keys (z.string() / z.array(z.string()) / an inline z.enum)byte-identical
authorable-defaults/ui.jsonone row leaves with the retired key, authorised by the retirement itselfone row, ratchet green (quoted above)

The [RETIRED] lines are not deleted here: gate (c)'s aging clock starts at the major the RETIRED_KEYS_BY_MAJOR entry is written under, and 17 is that major.

Reverse verification — direction predicted first, then measured

A. Authored key → parse REJECTED with the prescription

Predicted per key: safeParse fails; issues[0].code = invalid_type; expected = never; path = the retired key, as a one-element array; message is the prescription itself (not "unrecognized key"), naming the backticked key and closing with the house sentence. A schema verdict carries no envelope status field — there is nothing of that shape to pin, so the probe reports its absence rather than inventing one.

keysuccesscodeexpectedpathnames keyhouse sentenceenvelope status
page:header.iconfalseinvalid_typenever["icon"]ABSENT (as predicted)
page:card.actionsfalseinvalid_typenever["actions"]ABSENT
record:details.layout = customfalseinvalid_typenever["layout"]ABSENT
record:details.layout = auto (the old default)falseinvalid_typenever["layout"]ABSENT

Full prescription text as an author receives it, e.g.:

record:details property layout was removed in @objectstack/spec 17.0.0 (#6946, ADR-0087 D2) — its declared auto | custom semantics were never implemented: the renderer tests layout only against inline | compact, two values the schema never permitted, so both legal values took the same branch and the key selected nothing. Delete the key — the body is already chosen by what you author: sections renders the explicit groups (the old custom), and omitting it falls back to the object's highlightFields (the old auto). Run os migrate meta --from 16 to rewrite existing sources automatically.

B. Stored old-major row → conversion → converted shape

Predicted: exactly 4 strip notices across a stored stack carrying all three keys in the region form, the nested-container form and the named-slot form; page:header.actions, record:highlights.layout and element:button.icon survive untouched; no other protocol-17 conversion fires on the fixture.

Measured — replaying everytoMajor: 17 conversion over the stored row:

page-structure-inert-keys-removed icon → (removed) @ pages[0].regions[0].components[0].properties.icon
page-structure-inert-keys-removed actions → (removed) @ pages[0].regions[0].components[1].properties.actions
record-details-layout-removed layout → (removed) @ pages[0].regions[0].components[2].properties.layout
record-details-layout-removed layout → (removed) @ pages[1].slots.details.properties.layout
other conversions fired on this fixture: []

page:header keeps actions: ["run"]; record:highlights keeps layout: "horizontal"; element:button keeps icon: "external-link". Fixture disjointness holds in both required directions — every fixture replays through the whole table to exactly its own after, and the retiredFromLoadPath fixtures pass the default load path with zero notices (src/conversions suite, 359 tests green).

C. Untouched sibling props → byte-identical

props bag round-trippedverdict
page:headertitle, subtitle, breadcrumb, actions, recordChrome, showStar, showCopyIdIDENTICAL
page:cardtitle, bordered, children, footerIDENTICAL
record:detailscolumns, sections, fields, hideFieldsIDENTICAL
record:highlightslayout: 'horizontal' (the live same-name sibling)IDENTICAL

Gates, one by one

gateresult
check:livenessPASS
check:empty-statePASS
check:authorable-surface (incl. the #4666 defaults ratchet)PASS
check:docsPASS
check:api-surfacePASS
check:spec-changesPASS
check:upgrade-guidePASS
check:skill-refs / check:skill-docs / check:skill-examplesPASS
check:variant-docs / check:exported-any / check:dual-source-exportsPASS
check:export-origins (new in the Type Check job today)PASS — 4 991 exports across 16 entry points resolve exactly as recorded. Regenerated, never hand-edited; in the event the shards did not move, since no export is added or removed
check-adr-0087-registration --base origin/mainPASS — 1 declared-breaking changeset, each carrying an ADR-0087 disposition (registered page-structure-inert-keys-removed, record-details-layout-removed)
pnpm check:i18nPASS — 9 packages in sync. (No form input was pruned: no *.form.ts declares component props, so no bundle key moved.)
pnpm typecheckPASS — 126/126
pnpm lintPASS
pnpm testPASS after one re-run — see below
@objectstack/dogfood targeted suitePASS — 526 passed, 3 skipped (run regardless of the import graph, per the playbook)
check:react-declaration-paritynot run — it structurally cannot be: its right-hand side is objectui's sdui.manifest.json, produced only by pnpm sdui:manifest driving Playwright chromium over a built objectui at the pin. It is an on-demand gate whose trigger is the pin bump (#5960), and this PR does not move .objectui-sha. It is also the gate this retirement makes less meaningful, not more — see the record:details.layout row above

The one red, and why it is not mine:@objectstack/typessrc/node.test.ts > falls back to the importing package's own resolution when the host does not declare timed out at 5 000 ms in the full parallel run. It is a package-resolution test in a package this diff does not touch, and its siblings in the same file take 3 021 ms and 1 672 ms, so it sits at the edge of that timeout under load. Re-run in isolation: 230/230 pass, 3.32 s. Recorded rather than silently re-run.

CI on this PR: all 26 check runs completed green (one skipped — Console Pin Gate, correct since .objectui-sha does not move here), including both required gates, ESLint and TypeScript Type Check.

Base-branch check (17:49Z)

main moved f5a9bc29136327 (5 commits) after this branch was pushed. The merge is clean, and because packages/spec moved on both sides the AGENTS.md §10 scoped re-check was run on the merged tree rather than assumed: pnpm --filter @objectstack/spec build && check:generatedall 11 generated artifacts up to date, so no jointly-wrong artifact. main's spec commits touch automation/io-node-config.zod.ts and ui/view.zod.ts (.describe() alignment), disjoint from this diff.

The merge was therefore not pushed: it would invalidate a fully green CI run for no measured benefit, and the merge queue rebuilds the PR as merged onto current main and re-runs the subscribing workflows anyway (§7). Verified rather than skipped.

docs/adr statement

This diff touches no docs/adr/** path. The ADR-0087 work here is registry codepackages/spec/src/conversions/registry.ts and packages/spec/src/migrations/registry.ts — with no ADR document edited or added. Full file list: .changeset/, content/docs/references/ui/component.mdx (generated), docs/protocol-upgrade-guide.md (generated), examples/app-showcase/, packages/cli/test/, packages/cloud-connection/src/, packages/mcp/src/, packages/rest/src/, packages/spec/ (src + generated baselines), skills/objectstack-ui/SKILL.md. Per the PM's dispatch note this is the registry-code-only case; the landing mode is the PM's call, and no auto-merge is armed and no queue entry made from here.

content/docs/releases/ is untouched, as a code PR requires.

Sequencing

objectui#3829 (drop the two parity-gate exemptions) and objectui#3818 (delete the layout input and the dead inline|compact branch) are Blocked-by #6946 and proceed on the next .objectui-sha pin bump after this lands. Note for whoever moves that pin: dropping the two UNPUBLISHED_EXEMPTIONS entries is not automatic on the bump — a retiredKey() keeps the key in Object.keys(shape), so those entries stay live until objectui's tombstone recognition narrows specTopLevelKeys (the same trap objectui#3808 hit with the record-picker three, written out in that file's own comment).


Generated by Claude Code

…RecordDetailsProps.layout (#6946)
Maintainer ruling 2026-08-09 (decision-inbox round, 「全部接受」): objectui#3829
route (c) retires `PageHeaderProps.icon` and `PageCardProps.actions` upstream;
objectui#3818 retires `RecordDetailsProps.layout`. All three are the ADR-0049
declared-but-unenforced shape on the SDUI page-component contract.
Re-measured against objectui at the `.objectui-sha` pin (09987b68) rather than
inherited from the cards:
- `page:header.icon` — objectui resolves `icon` only per header ACTION
(`action.icon`); the header's own props bag is never asked for one, and the
registration publishes no `icon` input. `@object-ui/layout`'s `<PageHeader>`
draws an `icon` React prop from a host but gives it no schema fallback, four
lines from the `schema?.actions ?? schema?.properties?.actions` fallback that
does exist.
- `page:card.actions` — the card renderer builds its `<Card>` from `title`,
`bordered`, `children` and `footer`; no actions area, no `actions` input.
- `record:details.layout` — read, but only against `inline`|`compact`, values
its `auto`|`custom` enum never permitted, so both legal values took the same
branch. Declared on both sides with the same enum, which is why the
declaration-parity ratchet reported agreement over it.
The kit: `retiredKey()` tombstones; two ADR-0087 D2 conversions
(`page-structure-inert-keys-removed`, `record-details-layout-removed`) wired
into the protocol-17 D3 chain step, both pure lossless strips; three exact-key
`RETIRED_KEYS_BY_MAJOR[17]` entries; four in-repo pages stop authoring the
header icon; pin tests in both directions; baselines, spec-changes and the
upgrade guide regenerated.
`page:header.actions` and `record:highlights.layout` are LIVE and untouched —
every strip is scoped by component type, never by key name.
Closes#6946
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018SqC353TXUnqdj3VkoTb4N
@vercel

vercelBot commented Aug 9, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
ProjectDeploymentActionsUpdated (UTC)
objectstackIgnoredIgnoredAug 9, 2026 5:22pm

Request Review

@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 3 package(s): @objectstack/cloud-connection, @objectstack/mcp, @objectstack/spec.

112 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:

  • content/docs/ai/actions-as-tools.mdx(via @objectstack/mcp)
  • content/docs/ai/agents.mdx(via @objectstack/mcp, @objectstack/spec)
  • content/docs/ai/connect-mcp.mdx(via @objectstack/mcp)
  • content/docs/ai/index.mdx(via @objectstack/mcp)
  • content/docs/ai/natural-language-queries.mdx(via @objectstack/mcp)
  • content/docs/ai/skills-reference.mdx(via @objectstack/spec)
  • content/docs/ai/skills.mdx(via @objectstack/spec)
  • content/docs/api/client-sdk.mdx(via @objectstack/spec)
  • content/docs/api/environment-routing.mdx(via @objectstack/spec)
  • content/docs/api/error-catalog.mdx(via @objectstack/spec)
  • content/docs/api/error-handling-client.mdx(via @objectstack/spec)
  • content/docs/api/error-handling-server.mdx(via @objectstack/spec)
  • content/docs/api/index.mdx(via @objectstack/mcp, @objectstack/spec)
  • content/docs/automation/approvals.mdx(via @objectstack/spec)
  • content/docs/automation/connectors.mdx(via @objectstack/spec)
  • content/docs/automation/flows.mdx(via @objectstack/spec)
  • content/docs/automation/hook-bodies.mdx(via packages/spec)
  • content/docs/automation/hooks.mdx(via @objectstack/spec)
  • content/docs/automation/index.mdx(via @objectstack/spec)
  • content/docs/automation/webhooks.mdx(via @objectstack/spec)
  • content/docs/automation/workflows.mdx(via @objectstack/spec)
  • content/docs/concepts/architecture.mdx(via @objectstack/spec)
  • content/docs/concepts/design-principles.mdx(via packages/spec)
  • content/docs/concepts/index.mdx(via @objectstack/spec)
  • content/docs/concepts/metadata-driven.mdx(via @objectstack/spec)
  • content/docs/concepts/metadata-lifecycle.mdx(via packages/spec)
  • content/docs/concepts/north-star.mdx(via @objectstack/spec)
  • content/docs/data-modeling/analytics.mdx(via @objectstack/spec)
  • content/docs/data-modeling/drivers.mdx(via @objectstack/spec)
  • content/docs/data-modeling/external-datasources.mdx(via @objectstack/spec)
  • content/docs/data-modeling/field-types.mdx(via @objectstack/spec)
  • content/docs/data-modeling/fields.mdx(via @objectstack/spec)
  • content/docs/data-modeling/formulas.mdx(via @objectstack/spec)
  • content/docs/data-modeling/index.mdx(via @objectstack/spec)
  • content/docs/data-modeling/objects.mdx(via @objectstack/spec)
  • content/docs/data-modeling/queries.mdx(via @objectstack/spec)
  • content/docs/data-modeling/schema-design.mdx(via @objectstack/spec)
  • content/docs/data-modeling/seed-data.mdx(via @objectstack/spec)
  • content/docs/data-modeling/validation-rules.mdx(via @objectstack/spec)
  • content/docs/data-modeling/validation.mdx(via @objectstack/spec)
  • content/docs/deployment/cli.mdx(via @objectstack/spec)
  • content/docs/deployment/environment-variables.mdx(via @objectstack/mcp)
  • content/docs/deployment/tenancy-modes.mdx(via @objectstack/spec)
  • content/docs/deployment/troubleshooting.mdx(via @objectstack/spec)
  • content/docs/deployment/validating-metadata.mdx(via @objectstack/spec)
  • content/docs/getting-started/build-with-claude-code.mdx(via @objectstack/spec)
  • content/docs/getting-started/common-patterns.mdx(via @objectstack/spec)
  • content/docs/getting-started/examples.mdx(via @objectstack/spec)
  • content/docs/getting-started/quick-reference.mdx(via @objectstack/spec)
  • content/docs/getting-started/quick-start.mdx(via @objectstack/spec)
  • content/docs/getting-started/your-first-project.mdx(via @objectstack/spec)
  • content/docs/kernel/cluster.mdx(via @objectstack/spec)
  • content/docs/kernel/contracts/auth-service.mdx(via packages/spec)
  • content/docs/kernel/contracts/cache-service.mdx(via packages/spec)
  • content/docs/kernel/contracts/data-engine.mdx(via @objectstack/spec)
  • content/docs/kernel/contracts/index.mdx(via @objectstack/spec)
  • content/docs/kernel/contracts/metadata-service.mdx(via packages/spec)
  • content/docs/kernel/contracts/storage-service.mdx(via @objectstack/spec)
  • content/docs/kernel/index.mdx(via packages/spec)
  • content/docs/kernel/runtime-services/data-service.mdx(via @objectstack/spec)
  • content/docs/kernel/runtime-services/email-service.mdx(via packages/spec)
  • content/docs/kernel/runtime-services/examples.mdx(via @objectstack/spec)
  • content/docs/kernel/runtime-services/index.mdx(via packages/spec)
  • content/docs/kernel/runtime-services/queue-service.mdx(via packages/spec)
  • content/docs/kernel/runtime-services/sharing-service.mdx(via @objectstack/spec)
  • content/docs/kernel/runtime-services/sms-service.mdx(via packages/spec)
  • content/docs/kernel/runtime-services/storage-service.mdx(via @objectstack/spec)
  • content/docs/kernel/services-checklist.mdx(via @objectstack/spec)
  • content/docs/kernel/services.mdx(via @objectstack/spec)
  • content/docs/permissions/authorization.mdx(via @objectstack/mcp, @objectstack/spec)
  • content/docs/permissions/permission-sets.mdx(via @objectstack/spec)
  • content/docs/permissions/permissions-matrix.mdx(via @objectstack/spec)
  • content/docs/permissions/positions.mdx(via @objectstack/spec)
  • content/docs/permissions/rls.mdx(via @objectstack/spec)
  • content/docs/permissions/sharing-rules.mdx(via @objectstack/spec)
  • content/docs/permissions/system-context.mdx(via packages/mcp, packages/spec)
  • content/docs/plugins/adding-a-metadata-type.mdx(via @objectstack/spec)
  • content/docs/plugins/development.mdx(via @objectstack/spec)
  • content/docs/plugins/index.mdx(via @objectstack/spec)
  • content/docs/plugins/packages.mdx(via @objectstack/mcp, @objectstack/spec)
  • content/docs/protocol/backward-compatibility.mdx(via @objectstack/spec)
  • content/docs/protocol/diagram.mdx(via packages/spec)
  • content/docs/protocol/kernel/config-resolution.mdx(via @objectstack/spec)
  • content/docs/protocol/kernel/http-protocol.mdx(via @objectstack/spec)
  • content/docs/protocol/kernel/i18n-standard.mdx(via @objectstack/spec)
  • content/docs/protocol/kernel/index.mdx(via @objectstack/spec)
  • content/docs/protocol/kernel/lifecycle.mdx(via @objectstack/spec)
  • content/docs/protocol/kernel/metadata-service.mdx(via @objectstack/cloud-connection)
  • content/docs/protocol/kernel/plugin-spec.mdx(via @objectstack/spec)
  • content/docs/protocol/knowledge.mdx(via @objectstack/mcp, @objectstack/spec)
  • content/docs/protocol/objectql/index.mdx(via @objectstack/spec)
  • content/docs/protocol/objectql/query-syntax.mdx(via @objectstack/spec)
  • content/docs/protocol/objectql/schema.mdx(via @objectstack/spec)
  • content/docs/protocol/objectql/security.mdx(via packages/spec)
  • content/docs/protocol/objectql/state-machine.mdx(via @objectstack/spec)
  • content/docs/protocol/objectui/actions.mdx(via @objectstack/spec)
  • content/docs/protocol/objectui/concept.mdx(via @objectstack/spec)
  • content/docs/protocol/objectui/index.mdx(via @objectstack/spec)
  • content/docs/protocol/objectui/layout-dsl.mdx(via @objectstack/spec)
  • content/docs/protocol/objectui/record-alert.mdx(via @objectstack/spec)
  • content/docs/protocol/objectui/widget-contract.mdx(via @objectstack/spec)
  • content/docs/ui/actions.mdx(via @objectstack/spec)
  • content/docs/ui/apps.mdx(via @objectstack/spec)
  • content/docs/ui/create-vs-edit-form.mdx(via @objectstack/spec)
  • content/docs/ui/dashboards.mdx(via @objectstack/spec)
  • content/docs/ui/field-grouping-and-order.mdx(via @objectstack/spec)
  • content/docs/ui/forms.mdx(via @objectstack/spec)
  • content/docs/ui/index.mdx(via @objectstack/spec)
  • content/docs/ui/public-data-collection.mdx(via @objectstack/spec)
  • content/docs/ui/setup-app.mdx(via @objectstack/spec)
  • content/docs/ui/translations.mdx(via @objectstack/spec)
  • content/docs/ui/views.mdx(via @objectstack/spec)

7 release-owned page(s) also reference the affected code. These are read-only:

  • content/docs/releases/implementation-status.mdx(via @objectstack/cloud-connection, @objectstack/mcp, @objectstack/spec)
  • content/docs/releases/index.mdx(via @objectstack/spec)
  • content/docs/releases/v12.mdx(via @objectstack/spec)
  • content/docs/releases/v13.mdx(via @objectstack/spec)
  • content/docs/releases/v16.mdx(via @objectstack/spec)
  • content/docs/releases/v17.mdx(via @objectstack/spec)
  • content/docs/releases/v9.mdx(via @objectstack/spec)

content/docs/releases/ is RELEASE-OWNED (AGENTS.md "Documentation Guardrails"): release
notes are written centrally at release time, and a code PR that edits them is the exact PR
that guardrail exists to stop. They are still audited — read-only. If one of them is actually
wrong, file an issue or open a dedicated docs-only PR; do not edit it here.

Advisory only. To re-verify, run the docs-accuracy-audit workflow scoped to these files:
node scripts/docs-audit/affected-docs.mjs origin/main → pass the list as args.docs.

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

Labels

documentationImprovements or additions to documentationprotocol:systemprotocol:uisize/lteststooling

Projects

None yet

2 participants

@os-zhuang@claude