You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
docs(sweep): run 4 — rc.1 catch-up, close the run-2 coverage gap (#4600)
* docs(sweep): run 4 — rc.1 catch-up, and close the run-2 coverage gap
The sweep log holds run 1 (watermark a641d10) and run 3 (a version-number-only
pass) — no run 2 was ever recorded, so the 362 changesets added a641d10..0f9faa2
were never swept with removal fingerprints. This run's delta is a641d10..HEAD
(435 new changesets, ~48 breaking), against a tree now at 17.0.0-rc.1.
Fixed drift:
- permissions/authorization.mdx — gate 1 still taught the api.requireAuth:false
opt-out; #3963 retired it outright (tombstoned, always-deny).
- permissions/explain.mdx, ui/forms.mdx — three more passages describing the
requireAuth knob as configurable.
- kernel/services-checklist.mdx — partially updated at change time: the
narrative documented the workflow-slot retirement (#4451) while the page
still claimed 16 services, listed workflow in the architecture diagram, and
carried its live summary-table row. Now 15 (matches the 15-member enum),
row dropped, table and section numbering re-aligned.
Everything else the new fingerprints matched was already correct at change
time — flows.mdx (#4343 script convergence), query-syntax (#4286 removals,
having enforcement), error-catalog (ADR-0114 fieldErrors tombstone),
bulkActionDefs (#4457) — and fourteen fingerprints hit nothing at all. Run 4
appended to docs/v17-docs-sweep.md with the coverage-gap note and the
second-order-drift method lesson.
Verified: pnpm docs:build passes; check:release-notes, doc-authoring,
role-word, org-identifier, nul-bytes green.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LXvaYR7TiJBCxYwjn51owH
* chore: empty changeset for the docs-only sweep PR
The Check Changeset gate counts changesets added by the PR itself; an
empty-frontmatter changeset is the sanctioned releases-nothing declaration.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LXvaYR7TiJBCxYwjn51owH
---------
Co-authored-by: Claude <noreply@anthropic.com>
Copy file name to clipboardExpand all lines: content/docs/kernel/services-checklist.mdx
+21-22Lines changed: 21 additions & 22 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -14,7 +14,7 @@ the code wins. See [Plugins & Packages](/docs/plugins/packages) for the full
14
14
package catalog.
15
15
</Callout>
16
16
17
-
The ObjectStack protocol defines **16 kernel services** registered via the `CoreServiceName` enum (the never-implemented `graphql` entry was removed in v17). Each service maps to a set of protocol methods governed by its per-domain contract (`DataProtocol`, `MetadataProtocol`, ...) — the transitional `ObjectStackProtocol` composition alias was dissolved in v17 (ADR-0076 D9); capability availability comes from the runtime discovery `services` registry.
17
+
The ObjectStack protocol defines **15 kernel services** registered via the `CoreServiceName` enum (v17 removed the never-implemented `graphql` entry and retired the never-filled `workflow` slot, #4451). Each service maps to a set of protocol methods governed by its per-domain contract (`DataProtocol`, `MetadataProtocol`, ...) — the transitional `ObjectStackProtocol` composition alias was dissolved in v17 (ADR-0076 D9); capability availability comes from the runtime discovery `services` registry.
18
18
19
19
**Key architecture principle**: the kernel guarantees only **data** and **metadata**, and even those are filled by packages (`@objectstack/objectql`, `@objectstack/metadata`) rather than baked in — the kernel's own contribution is an in-memory fallback for the `core` slots that have one (`metadata`, `cache`, `queue`, `job`, `i18n` — **not**`auth`). Everything else — including **auth** and **automation** — is delivered by plugins. `@objectstack/objectql` is an example kernel implementation to get the basic API running; production kernels will be rebuilt as separate plugins.
20
20
@@ -50,7 +50,7 @@ The ObjectStack protocol defines **16 kernel services** registered via the `Core
| 5 |**ui**|`optional`| 5 | ❌ Nothing fills this slot |`@objectstack/metadata-protocol` — `/ui/view` is served by its `protocol` service, not by a `ui` service |
`cache`, `queue`, and `job` are `core` services: like `i18n`, the kernel auto-injects an in-memory fallback when no plugin registers them (see `CORE_FALLBACK_FACTORIES` in `packages/core/src/fallbacks/`). The `optional` services (`file-storage`, `search`) stay disabled until a plugin provides them.
Copy file name to clipboardExpand all lines: content/docs/permissions/authorization.mdx
+1-1Lines changed: 1 addition & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -48,7 +48,7 @@ site — the file you read when behavior surprises you.
48
48
49
49
| # | Gate | What it decides | Enforcement site | Failure direction |
50
50
|---|---|---|---|---|
51
-
| 1 | **Anonymous deny** | No identity → HTTP 401. **Uniform across every HTTP surface that reaches object data** (#2567): REST `/data` and the metadata endpoints (`/meta`) — the raw-hono standard `/data` routes left the matrix when that duplicate surface was deleted in v17 (#4073), and the dispatcher GraphQL endpoint left when the GraphQL surface was removed (`/graphql` now 404s) — one shared decision, so a caller denied on `/data` can't read the same rows through a sibling door. **Default-on** (ADR-0056 D2): serving the whole data plane publicly requires an explicit `api.requireAuth: false` opt-out, which logs a boot warning. Narrower public surfaces do **not** need it — each derives its own authorization from a declaration rather than from the deployment posture: control plane (`/auth`, `/health`, `/discovery`) is allow-listed; public form submission carries a `publicFormGrant` (ADR-0056 Option A); share-links validate their token then read as SYSTEM; and an anonymous **GET** of the book/doc read surface is admitted so `book.audience: 'public'` works under the secure default, with the ADR-0046 §6.7 audience gate — `'public'` only, fail-closed — doing the authorizing (#3963). | `packages/core/src/security/anonymous-deny.ts` `shouldDenyAnonymous` — called by `rest-server.ts` `enforceAuth` and the dispatcher `handleMetadata`/`handleAI` (default in `packages/spec/src/api/rest-server.zod.ts`); a source-enumerating ratchet in `authz-conformance.test.ts` fails CI if a new surface ships ungated | fail-closed |
51
+
| 1 | **Anonymous deny** | No identity → HTTP 401. **Uniform across every HTTP surface that reaches object data** (#2567): REST `/data` and the metadata endpoints (`/meta`) — the raw-hono standard `/data` routes left the matrix when that duplicate surface was deleted in v17 (#4073), and the dispatcher GraphQL endpoint left when the GraphQL surface was removed (`/graphql` now 404s) — one shared decision, so a caller denied on `/data` can't read the same rows through a sibling door. **Unconditional** (#3963, closing out ADR-0056 D2): the `api.requireAuth: false` opt-out was retired in v17 — the key is tombstoned, so authoring it is a parse error, and anonymous callers are denied on every data surface with no deployment-level escape hatch. Narrower public surfaces do **not** need it — each derives its own authorization from a declaration rather than from the deployment posture: control plane (`/auth`, `/health`, `/discovery`) is allow-listed; public form submission carries a `publicFormGrant` (ADR-0056 Option A); share-links validate their token then read as SYSTEM; and an anonymous **GET** of the book/doc read surface is admitted so `book.audience: 'public'` works under the secure default, with the ADR-0046 §6.7 audience gate — `'public'` only, fail-closed — doing the authorizing (#3963). | `packages/core/src/security/anonymous-deny.ts` `shouldDenyAnonymous` — called by `rest-server.ts` `enforceAuth` and the dispatcher `handleMetadata`/`handleAI` (default in `packages/spec/src/api/rest-server.zod.ts`); a source-enumerating ratchet in `authz-conformance.test.ts` fails CI if a new surface ships ungated | fail-closed |
52
52
| 2 |**Public-form grant**| An anonymous form submission carries a declaration-derived `publicFormGrant` authorizing ONLY create + read-back on the form's declared target object — never anything else (ADR-0056 Option A). No guest-portal configuration needed (anonymous principals hold the `guest` position). |`packages/plugins/plugin-security/src/security-plugin.ts` (ObjectQL middleware) | scope-limited allow |
53
53
| 3 |**Object CRUD**|`allowRead/Create/Edit/Delete` (+ the destructive lifecycle class `allowTransfer/Restore/Purge`, gated ahead of the M2 operations — #1883) resolved across the caller's permission sets. |`packages/plugins/plugin-security/src/permission-evaluator.ts``checkObjectPermission`| fail-closed 403 |
54
54
| 4 |**OWD / sharing**| Org-wide default (`private` / `public_read` / `public_read_write` / `controlled_by_parent`; **unset or unknown ⇒ `private`, fail-closed** — ADR-0090 D1) plus the external dial (`externalSharingModel`, ADR-0090 D11), manual record shares, criteria sharing rules (owner-type rules were removed from the authoring surface in v17 rather than left declared-but-skipped — [Sharing Rules](/docs/permissions/sharing-rules#recipient-types)), business-unit hierarchy widening (ADR-0057 D5: scope-depth hierarchy lives on `sys_business_unit`, not positions). |`packages/plugins/plugin-sharing/src/sharing-service.ts` + `sharing-rule-service.ts`| fail-closed to owner-only |
- Neither route calls `enforceAuth`, so they work even when the project is configured with `requireAuth: true`.
235
+
- Neither route calls `enforceAuth`, so they work under the always-on anonymous-deny default (there is no `requireAuth` knob to configure since v17).
235
236
- The execution context handed to ObjectQL is `{ publicFormGrant: { object }, permissions: ['guest_portal'], anonymous: true }` with no `userId`. The Security plugin honors `publicFormGrant` first — a create + read-back grant scoped to exactly the declared object — so authorization holds even without a `guest_portal` profile. `permissions: ['guest_portal']` is retained for back-compat.
236
237
- No CSRF or auth header is needed; embed the form on any domain.
0 commit comments