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-zhuang os-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

probe scope expect measured
/icon/ inside PageHeaderRenderer (components/src/renderers/layout/containers.tsx:900-1596) the renderer that owns page:header MISS (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 range HIT 3
control /showStar/ same range HIT 3
control /subtitle/ same range HIT 7
schema\??\.icon|properties\??\.icon objectui, all non-test source MISS on page:header 9 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.tsx the other component named PageHeader MISS as a schema read icon is a React prop from a host (:117, rendered :224-226) with no schema fallback
in-file control — schema-sourced reads in that same file same file HIT schema?.children (:182), schema?.actions (:194), schema?.properties?.actions (:195) — the fallback icon conspicuously lacks, four lines away
registry inputs for page:header containers.tsx registration no icon title, 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

probe scope expect measured
whole PageCardRenderer body (containers.tsx:666-721) the renderer that owns page:card no actions reads exactly title, bordered, body ?? children, footerno actions, no actions area in the markup
control /footer/, /bordered/ same range HIT both read and rendered
schema\??\.actions|properties\??\.actions objectui, all non-test source MISS on page:card 16 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:card containers.tsx registration no actions title, 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:

const layout: '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.

probe scope expect measured
schema\??\.layout|properties\??\.layout objectui, all non-test source one hit on record:details, dead 13 hits: record-details.tsx:104 (the dead branch), plugin-form ×6, plugin-view ×2, one builder setter — no other record:details read
control layout === 'auto' | 'custom' objectui + framework MISS 0 in both repos
control layout === 'vertical' | 'horizontal' objectui HIT plugin-form/plugin-view honour their own live layout
registry inputs for record:details plugin-detail/src/index.tsx:274 declares layout enum: ['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:43 layout?: '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:

id keys shape
page-structure-inert-keys-removed page: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-removed record: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:

artifact predicted (tombstone route) measured
authorable-surface/ui.json three 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.json byte-identical — no def is deleted, only a def's key set narrows byte-identical; the per-key deletion ratchet never fires
api-surface/, api-surface-signatures.json byte-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.json one row leaves with the retired key, authorised by the retirement itself one 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.

key success code expected path names key house sentence envelope status
page:header.icon false invalid_type never ["icon"] ABSENT (as predicted)
page:card.actions false invalid_type never ["actions"] ABSENT
record:details.layout = custom false invalid_type never ["layout"] ABSENT
record:details.layout = auto (the old default) false invalid_type never ["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 every toMajor: 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-tripped verdict
page:headertitle, subtitle, breadcrumb, actions, recordChrome, showStar, showCopyId IDENTICAL
page:cardtitle, bordered, children, footer IDENTICAL
record:detailscolumns, sections, fields, hideFields IDENTICAL
record:highlightslayout: 'horizontal' (the live same-name sibling) IDENTICAL

Gates, one by one

gate result
check:liveness PASS
check:empty-state PASS
check:authorable-surface (incl. the #4666 defaults ratchet) PASS
check:docs PASS
check:api-surface PASS
check:spec-changes PASS
check:upgrade-guide PASS
check:skill-refs / check:skill-docs / check:skill-examples PASS
check:variant-docs / check:exported-any / check:dual-source-exports PASS
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/main PASS — 1 declared-breaking changeset, each carrying an ADR-0087 disposition (registered page-structure-inert-keys-removed, record-details-layout-removed)
pnpm check:i18n PASS — 9 packages in sync. (No form input was pruned: no *.form.ts declares component props, so no bundle key moved.)
pnpm typecheck PASS — 126/126
pnpm lint PASS
pnpm test PASS after one re-run — see below
@objectstack/dogfood targeted suite PASS — 526 passed, 3 skipped (run regardless of the import graph, per the playbook)
check:react-declaration-parity not 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/types src/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

vercel Bot commented Aug 9, 2026

Copy link
Copy Markdown

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

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
objectstack Ignored Ignored Aug 9, 2026 5:22pm

Request Review

@github-actions

github-actions Bot commented Aug 9, 2026

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 free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

2 participants