Skip to content

Commit c53d4f8

Browse files
committed
Merge remote-tracking branch 'origin/main' into claude/issue-24486-cloud-adr-0028-citation
2 parents e27d6d3 + 6b42b6b commit c53d4f8

226 files changed

Lines changed: 3080 additions & 149 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
---
2+
'@objectstack/plugin-approvals': patch
3+
---
4+
5+
fix(plugin-approvals): the approval request page's highlights strip no longer shows the target object's API name
6+
7+
Clause-②: no
8+
9+
- **The strip draws no Object chip.** `sys_approval_request_detail` no longer lists `object_name` on its highlights strip, so a request about an announcement no longer shows `showcase_announcement` there. `object_name` holds the target object's API name, and `sys_approval_request` declares no field that holds that object's label.
10+
- **The page still names the target object, by its label.** The Details tab draws the `record_id` / `object_name` pointer pair as a card of the target record. The card heads the record with its object's label (`Announcement`), translated into the reader's locale and read from the object's definition when the page draws, so a relabelled object shows its new label. Where the reader may not read the target record, or the platform deleted it, the card says so and the page names no object.
11+
- **The object's `highlightFields` drops `object_name` too.** The page's Details tab is a bare `record:details` node, which draws the object's `highlightFields` minus the strip. A change to the strip alone would have moved `object_name` into that tab as a row showing the API name.
12+
- **Unchanged:** `object_name` stays a declared, required field: the approvals machinery queries on it, and it is the type half of the pointer pair. The request list views still show their Object column.
13+
14+
A patch: one entry fewer in one platform object's field list and in its page. No export, type, accepted value, served key or stored column changes.
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
---
2+
'@objectstack/formula': minor
3+
'@objectstack/spec': patch
4+
---
5+
6+
feat(formula): `current_user.hasCapability(name)` — a page predicate can ask whether the viewer holds a system capability, from the same list the action gate reads
7+
8+
Clause-②: yes (widening)
9+
10+
- **The predicate.** The CEL standard library registers `hasCapability` beside `can`, receiver-only, so the one spelling is `current_user.hasCapability('<name>')` (the `user` / `ctx.user` / `os.user` aliases work too). It answers `true` when the name is in the acting subject's held system capabilities and `false` when it is not. A name no action declares is just a string: there is no registry lookup.
11+
- **The data.** `EvalContext` gains `systemPermissions` (type `EvalSystemPermissions`, a list of capability names): the `systemPermissions` array of the published `/auth/me/permissions` response, unchanged — the list an action's `requiredPermissions` is checked against (ADR-0066 D4). `PermissionBinding` gains the same field, optional. Pass it beside `permissions`:
12+
13+
```ts
14+
celEngine.evaluate(expr, { user, permissions: toEvalPermissions(me.objects), systemPermissions: me.systemPermissions });
15+
```
16+
17+
- **Loud, like `can`.** With no `systemPermissions` on the context the call fails (`ok: false`, `kind: 'runtime'`) rather than answering; an empty list is a real answer and evaluates to `false`. A non-list, a non-string or empty name, or a receiver that is not the acting subject fails the same way. A bare `hasCapability(name)` does not resolve.
18+
- **The authoring gate.** The visibility-predicate rule's function-existence check reads the evaluation environment, so a page `visibleWhen` calling `current_user.hasCapability(…)` now passes `os validate`, `os lint` and `os build`, where before it was refused as an unknown function (`visibility-predicate-unknown-function`). An invented sibling (`hasCapabilities`) is still refused.
19+
- **`can` points at it.** `current_user.can(object, verb)` with a verb outside the object-permission vocabulary still fails, and its message now names `current_user.hasCapability('<name>')` for a capability question.
20+
- **Docs.** The page component `visibleWhen` describe names `current_user.hasCapability('<name>')` as the way to gate a component on a capability: `visibleWhen` hides, `requiredPermissions` refuses.
21+
- **Hosts.** A host that evaluates page predicates supplies the list for the predicate to answer; one that does not makes it fail, and a failing page `visibleWhen` renders the component.
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
---
2+
'@objectstack/service-automation': minor
3+
---
4+
5+
fix(service-automation): a `runAs: 'user'` flow now sees the acting user's organization members in `sys_user`, as the same user's own request does
6+
7+
A `runAs: 'user'` flow's data nodes ran without `current_user.org_user_ids`, the peer list the request path resolves for every user. The shipped `sys_user_org_members` policy (`id in current_user.org_user_ids`) therefore dropped out, and a `get_record` on `sys_user` returned the acting user's own row only, while the same user's REST read returned their organization's members too.
8+
9+
Run setup now seeds the peer list through the resolver the request path uses (`resolveUserAuthzGrants` from `@objectstack/core`), and every data node passes it on:
10+
11+
- It is the members of the run's organization (`tenantId`) plus the acting user. A run with no organization gets the acting user alone, which is what an organization-less request gets. A user who belongs only to other organizations is never in it, even one who shares another organization with the acting user.
12+
- It is seeded for every trigger shape: the record-change shape (`userId` and `tenantId` only) and the REST and action doors' shape (positions and permission sets already resolved). For the second shape only the peer list is taken from the resolver; the forwarded positions and permission sets stay exactly as they were, so an agent's narrowed ceiling is not re-broadened.
13+
- A `subflow` or `map` child and a resumed leg keep the list their run was seeded with.
14+
- If the resolver fails, the run proceeds without the list, as before, and the `[runAs]` warning now says which half degraded. Policies that read `org_user_ids` then drop out: the run sees less, never more.
15+
- A run suspended before this release resumes without the list and keeps today's answer (its own `sys_user` row) until it ends.
16+
17+
A `runAs: 'system'` flow is unchanged. The exported `RunIdentityContext` type gains an optional `org_user_ids` member.
18+
19+
Clause-②: yes (widening: the exported RunIdentityContext / RunDataContext type gains the optional org_user_ids member, the key ExecutionContext already declares; no accepted input moves)
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
---
2+
'@objectstack/spec': patch
3+
---
4+
5+
Clause-②: no
6+
7+
fix(spec): the object-extension refusals for `hooks` and `listViews` say what `defineStack()` does with a hook or view on another package's object
8+
9+
`ObjectExtensionSchema` refuses `hooks` and `listViews` on an `objectExtensions` entry. Both refusals used to tell the author to declare a top-level hook, or a top-level `view`, "bound to the target object instead". For an object the stack does not define, `defineStack()` refuses both at build, an extended object included, so the route the refusal named could not be taken.
10+
11+
- **`hooks`** now reads: a hook follows the ownership of its object, so declare it as a top-level hook in the stack that defines the object; `defineStack()` refuses a top-level hook bound to an object the stack does not define, an extended one included. The refusal is the recorded decision of ADR-0130 §1.5 ("the split must follow hook ownership").
12+
- **`listViews`** now reads: declare the views as a top-level `view` in the stack that defines the target object; `defineStack()` refuses a top-level `view` whose `list` or `form` data source is an object the stack does not define, an extended one included.
13+
- **Unchanged.** What `defineStack()` accepts and refuses, every error code, status and issue path. Only the refusal text moves, with its mirror in the object-extensions guide.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.

0 commit comments

Comments
 (0)