Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .changeset/27842-disabled-actions-served.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
---
'@objectstack/metadata-protocol': patch
'@objectstack/rest': patch
Expand All @@ -12,4 +12,4 @@

- **Served beside the object** (`@objectstack/metadata-protocol`, `@objectstack/rest`). `GET /api/v1/meta/object/:name` serves `disabledActions` beside `item`: the names in `item.actions` that the deployment's activation ledger switches off. `GET /api/v1/meta/object` serves the same answer keyed by object name. The default cached door carries it too, read live on every call and kept out of the ETag, so a read that carries it is answered in full rather than `304 Not Modified`. The key is absent where no ledger answered (no engine, or an engine with no ledger attached), on a draft read, and on every type other than `object`. `item.actions` is unchanged. The protocol reads the engine's `getDisabledActions` through the kernel's service table by name and imports no engine.
- **The fact it serves** (`@objectstack/objectql`). `ObjectQL.getDisabledActions()` returns the names the engine's activation projection switches off, the same projection both dispatch doors consult before they refuse a call, or `undefined` when no ledger is attached. `listDisabledActions()` is unchanged.
- **The refusal sentence** (`@objectstack/objectql`, `@objectstack/runtime`). A switched-off action is still refused 409 `ACTION_DISABLED` at the REST and MCP doors, and the message now reads: "This action is turned off for this deployment. An administrator can turn it on again under Setup › Packaged automation, or you can use another action." It no longer names the ledger table or the ADR. The engine writes those, with the code and the action's name, to an `info` log line each time it refuses one.
- **The refusal sentence** (`@objectstack/objectql`, `@objectstack/runtime`). A switched-off action is still refused 409 `ACTION_DISABLED` at the REST and MCP doors, and the message now reads: "This action is turned off for this deployment. An administrator can turn it on again under Setup › Packaged Actions, or you can use another action." It no longer names the ledger table or the ADR. The engine writes those, with the code and the action's name, to an `info` log line each time it refuses one.
4 changes: 2 additions & 2 deletions .changeset/27966-flow-disabled-plain-sentence.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
---
'@objectstack/service-automation': patch
'@objectstack/types': patch
Expand All @@ -9,5 +9,5 @@
Clause-②: no
Metadata-protocol: none

- **The flow refusal** (`@objectstack/service-automation`). A packaged flow switched off under Setup › Packaged automation is still refused `FLOW_DISABLED`, at every door that runs it: its trigger, a direct run, and a parent flow that calls it as a subflow. The message now reads: "This flow is turned off for this deployment. An administrator can turn it on again under Setup › Packaged automation, or copy it there under a new name." It no longer names the ledger table or the ADR. The engine writes those, with the code and the flow's name, to an `info` log line each time it refuses one. A flow disabled by its own status (`obsolete` / `invalid`) still reads "Flow '…' is disabled", so the two reasons stay distinguishable.
- **One sentence for both** (`@objectstack/types`, `@objectstack/objectql`). `describeTurnedOffPackagedItem('action' | 'flow')` builds the sentence. The action refusal (`ACTION_DISABLED`) reads from it too, and its wording is unchanged. Only the last clause differs: a flow can be copied under a new name, and an action cannot, so the action sentence still offers another action instead.
- **The flow refusal** (`@objectstack/service-automation`). A packaged flow an administrator switched off is still refused `FLOW_DISABLED`, at every door that runs it: its trigger, a direct run, and a parent flow that calls it as a subflow. The message now reads: "This flow is turned off for this deployment. An administrator can turn it on again in its package's Automations in Studio, or copy it there under a new name." It no longer names the ledger table or the ADR. The engine writes those, with the code and the flow's name, to an `info` log line each time it refuses one. A flow disabled by its own status (`obsolete` / `invalid`) still reads "Flow '…' is disabled", so the two reasons stay distinguishable.
- **One sentence for both** (`@objectstack/types`, `@objectstack/objectql`). `describeTurnedOffPackagedItem('action' | 'flow')` builds the sentence. The action refusal (`ACTION_DISABLED`) reads from it too, and its wording is unchanged. The two sentences differ in two clauses: where an administrator turns the item back on (an action under Setup › Packaged Actions, a flow in its package's Automations in Studio), and what can be done meanwhile (a flow can be copied under a new name, and an action cannot, so the action sentence offers another action instead).
15 changes: 15 additions & 0 deletions .changeset/29374-turned-off-sentence-names-live-pages.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
---
'@objectstack/types': patch
---

fix: the switched-off packaged item sentence names where the switch is now, not the retired Setup › Packaged automation page

Clause-②: no
Metadata-protocol: none

`describeTurnedOffPackagedItem`, the sentence both refusal engines send when an administrator has switched a packaged action or flow off (`ACTION_DISABLED`, `FLOW_DISABLED`), named Setup › Packaged automation as the place to turn it on again. That page is retired: an action's switch is on Setup's Packaged Actions page, and a flow's switch, with New similar beside it, is on the flow in its package's Automations in Studio. The sentence now names each:

- Action: "This action is turned off for this deployment. An administrator can turn it on again under Setup › Packaged Actions, or you can use another action."
- Flow: "This flow is turned off for this deployment. An administrator can turn it on again in its package's Automations in Studio, or copy it there under a new name."

Words only. The envelope codes are unchanged, and a machine reads those, not the sentence.
4 changes: 2 additions & 2 deletions content/docs/data-modeling/analytics.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -145,8 +145,8 @@ It saves an ordinary `dataset` draft in the package, published with the rest of
the package, and the picker selects it. Every dataset written this way counts
its records (a `count` measure), so a report or a chart can bind it at once.
Nothing is derived without the author: there are no implicit datasets. Joins,
filters, date dimensions and derived measures are edited afterwards in
**Setup › Datasets**.
filters, date dimensions and derived measures are edited afterwards on the
dataset's page in Studio's **All metadata** area.

While no dataset reads one of the package's objects, the Studio pickers say so
beside the button, and they list the package's own datasets first.
Expand Down
2 changes: 1 addition & 1 deletion content/docs/permissions/access-recipes.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ definePermissionSet({

Every business app meets this shape: a contract's legal terms after approval, an order's amount after shipping, an invoice after posting, a purchase order's supplier after approval. The answer is a field permission with a **row condition**, `when`, on the permission set that should lose the edit.

**In the permission-set editor** (Setup → Access Control → Permission Sets, then open the set):
**In the permission-set editor** (Studio → **All metadata** → Permission Set, then open the set):

1. Expand the object (`clm_contract`) to show its field rows.
2. On each field row to lock (`governing_law`, `liability_cap`), set **Read** on and **Edit** off.
Expand Down
22 changes: 13 additions & 9 deletions content/docs/permissions/administrator-guide.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -104,19 +104,22 @@ This is the daily 90%. An assignment is one row: **User Position**
they hold it in. The anchor decides *where* the position's depth grants apply
— "sales manager **of East**" sees East's records, not the whole company's.

From **Setup → Access Control → Positions**, open a position and add
assignments from its related list (or create User Position rows directly).
From **Setup → People & Organization → Position Holders**, pick a position
and add its holders. Holders added there carry no business-unit anchor; to
anchor an assignment to a unit, open the user's record page, go to its
**Positions** tab and choose **New**: the assignment form there takes the
position and the business unit.
These writes are governed: tenant-level admins pass; a
[delegated admin](/docs/permissions/delegated-administration) can only assign
allowlisted sets inside their own subtree — self-escalation is structurally
refused.

Two adjacent surfaces complete the picture:

- **Direct grants** — on a permission set's record page
(**Setup → Access Control → Permission Sets**), the **Assigned Users** panel
adds per-user grants without a position. Rows held *via a position* are
shown but removed on the position, not here.
- **Direct grants** — **Setup → People & Organization → Permission Set
Assignment**: pick a permission set, and its **Assigned Users** panel adds
per-user grants without a position. Rows held *via a position* are shown but removed
on the position (Position Holders), not here.
- **Business-unit membership** — from Step 2; independent of the assignment
anchor.

Expand Down Expand Up @@ -148,8 +151,8 @@ One rule of thumb: **capability ships with the apps you install — you rarely
author a permission set by hand.** If you are in this section, you've confirmed
no shipped position covers the need.

The permission-set **matrix editor** (Setup → Access Control → Permission Sets)
is a structured spreadsheet — you never hand-write JSON:
The permission-set **matrix editor** (Studio → **All metadata** → Permission
Set, then open the set) is a structured spreadsheet — you never hand-write JSON:

- **Object grid** — per object: Create / Read / Update / Delete, lifecycle
bits (Transfer / Restore / Purge), and View All / Modify All, with per-row
Expand Down Expand Up @@ -209,7 +212,8 @@ sets can't be edited in place either, but they can be cloned and adjusted
| Users, invitations | Setup → People & Organization → Users / Invitations |
| Business-unit tree | Setup → People & Organization → Business Units |
| Teams | Setup → People & Organization → Teams |
| Positions, permission sets, capabilities | Setup → Access Control |
| Positions, permission sets, capabilities: what they grant, and a position's or set's on/off switch | Studio → All metadata |
| Who holds a position, who holds a permission set | Setup → People & Organization → Position Holders / Permission Set Assignment |
| Sharing rules, record shares | Setup → Access Control |
| Password policy, MFA, lockout, SSO | Setup → Configuration → Authentication |
| Company info, localization, branding | Setup → Configuration |
Expand Down
16 changes: 9 additions & 7 deletions content/docs/permissions/authorization.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ Authorization splits into three concerns that stay decoupled:
1. **Capability** — *what can be done* (`manage_users`, `export_data`).
Defined by the platform (curated `PLATFORM_CAPABILITIES`) or by a package
via [`defineCapability`](#package-capability-declaration-adr-0066-d1); extended
by admins in Setup. A capability is **not** a contract and has no `inputs` — a
by admins in Studio. A capability is **not** a contract and has no `inputs` — a
resource merely *references* one by name (see Requirement, below).
2. **Assignment** — *who holds it* — permission sets and positions, which are
catalog definitions served by name from the environment registry (a
Expand Down Expand Up @@ -248,10 +248,11 @@ only what it owns:
**live** (config); the sets a position distributes are its definition's
`permissionSets`. It owns environment-authored sets and assignments — not
package sets. The set **definition** has one authoritative store, the
metadata layer (ADR-0094 D1, ADR-0131 D3): Setup → Access Control →
Permission Sets opens the catalog list
(`/apps/setup/metadata/permission?scope=environment`), and a create or edit
there is a metadata save (`PUT /api/v1/meta/permission/:name`) into the
metadata layer (ADR-0094 D1, ADR-0131 D3): Studio's **All metadata** area
lists the catalog (`/studio/~all/metadata/permission?scope=environment`;
Setup carries no metadata catalog, and its old
`/apps/setup/metadata/permission` address redirects there), and a create or
edit there is a metadata save (`PUT /api/v1/meta/permission/:name`) into the
environment's definition ledger (`sys_metadata`), served from the registry
beside the packages' sets. No row mirrors it: the `sys_permission_set`
object is no longer registered, so no data route serves one. The save
Expand Down Expand Up @@ -416,8 +417,9 @@ discipline: **resolution-time filtering, fail-closed**, in
No definition carries the switch, and no row does: the `active` column of the
retired catalog row objects (`sys_permission_set.active`,
`sys_position.active`) decides nothing, and neither object is registered any
more (ADR-0131 D3). Setup's active switch on the Positions and Permission Sets
catalog lists writes the ledger row, through the door below.
more (ADR-0131 D3). The on/off switch on a position's or a permission set's
page in Studio's **All metadata** area writes the ledger row, through the door
below.

The ledger row is written through
`POST /api/v1/security/_activation/:type/:name`, with `:type` either
Expand Down
4 changes: 2 additions & 2 deletions content/docs/permissions/capabilities.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ export default defineStack({
| Field | Type | Required | Notes |
|:--|:--|:--|:--|
| `name` | `string` | ✅ | The contract. `^[a-z][a-z0-9_.]*$` — lowercase, digits, `_` and `.` |
| `label` | `string` | optional | Shown in Setup. Defaults to a humanized `name` |
| `label` | `string` | optional | Shown to the administrator who grants it. Defaults to a humanized `name` |
| `description` | `string` | optional | What holding the capability permits |
| `scope` | `'platform' \| 'org'` | optional | Defaults to `'platform'`. `org` = scoped to the caller's organization |
| `packageId` | `string` | optional | Author-declared fallback provenance (ADR-0086 D3). Normally the registry stamps this for you |
Expand Down Expand Up @@ -269,7 +269,7 @@ to store arbitrary JSON on the authorization surface.
## Checklist

- [ ] Name is namespaced and lowercase, and does not shadow a platform capability
- [ ] `label` and `description` are written for the administrator who will grant it in Setup
- [ ] `label` and `description` are written for the administrator who will grant it
- [ ] `scope` is `org` unless the privilege really is platform-wide
- [ ] The declaration is reachable from the stack (`capabilities: [...]`) or a `*.capability.ts` file
- [ ] No other installed package declares the same name — the registry refuses a second holder at boot
Expand Down
2 changes: 1 addition & 1 deletion content/docs/permissions/delegated-administration.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ Setup app ("You don't have access to this app"); read on `sys_user`,
`sys_business_unit` and `sys_business_unit_member`, so the lookups can pick
people and units; and CRUD on `sys_user_position`, the assignment rows
themselves. They may sit on the scope's own set or on any other set the
delegate holds. In Setup's permission set editor, the Delegated Admin Scope
delegate holds. In the permission set editor (Studio's **All metadata** area), the Delegated Admin Scope
block lists the five, marks which ones the set already grants, and adds the
missing ones to the set in one click.

Expand Down
Loading
Loading