Skip to content

Commit 79ca88b

Browse files
committed
Merge remote-tracking branch 'origin/main' into claude/project-thread-1nvx81
2 parents fe7fb7e + aa00362 commit 79ca88b

51 files changed

Lines changed: 2765 additions & 265 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/spec': patch
3+
---
4+
5+
fix(spec): the liveness ledger grades `field.settledWhen` live
6+
7+
Clause-②: no
8+
Metadata-protocol: none
9+
10+
The liveness ledger shipped in `@objectstack/spec` (`liveness/field.json`) graded a deadline field's `settledWhen` as `planned`, with a note saying no reader existed. The console has read it for some time: while the predicate holds for a record, that record's deadline shows no overdue wording and no overdue colour, in the grid, list, gallery, kanban, tree, record detail and approval snapshot. The row is now `live` and names that reader. Nothing about what you can write, or what it does, has changed.
11+
12+
The `dueLike` row's note is corrected the same way: it said the grid did not carry the key yet, and it does.
13+
14+
`object.tenancy` already had correct rows (`tenancy.enabled` and `tenancy.tenantField`, both live), so it is unchanged.
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
---
2+
'@object-ui/i18n': patch
3+
---
4+
5+
feat(i18n): the Studio option editor's lifecycle `kind` picker has its labels
6+
7+
Clause-②: no
8+
Metadata-protocol: none
9+
10+
- Studio's picklist option editor can now set an option's lifecycle `kind` (`open` / `won` / `lost`, the key `SelectOption.kind` already publishes), so a select built in Studio can be chosen as the object's Lifecycle field (`stageField`) instead of the save being refused for options that declare no kind. The picker is drawn only on a single-value `select` / `radio` field, the one shape the spec lets carry a kind. The `studio` namespace gains its labels (`designer.field.optKind`, `designer.field.optKind.unset` / `.open` / `.won` / `.lost`), the malformed-option reason `designer.field.optMalformed.kindNotValid`, and the lifecycle-field hint `designer.field.hint.stageKinds`, in `en` and `zh`. No export changes.
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
---
2+
'@object-ui/app-shell': patch
3+
---
4+
5+
fix(app-shell): Studio's group-title, Description, Help text, nav "Link to object" and nav "Label" inputs have accessible names
6+
7+
Clause-②: no
8+
Metadata-protocol: none
9+
10+
Five Studio inputs were anonymous to screen readers and automated accessibility checks. The form designer's inline group-title input is now named "Group name", the label the group inspector gives the same value. The field inspector's Description and Help text textareas, and the Interfaces nav-item inspector's "Link to object" picker and "Label" input, are now tied to the labels already drawn above them, so each is announced by its label and clicking the label focuses it. Nothing changes visually and nothing changes in what is saved.
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
---
2+
'@object-ui/app-shell': patch
3+
---
4+
5+
fix(app-shell): a `type: 'api'` action declaring `opensInNewTab` + `newTabUrl` opens the tab and sends no request
6+
7+
Clause-②: no
8+
Metadata-protocol: none
9+
10+
The spec documents `newTabUrl` as the zero-roundtrip target of a new-tab action: on click the console pre-opens a tab and navigates it to `newTabUrl` (with `{recordId}` substituted), and no action request is sent. The console's server-action handler did this, but its `type: 'api'` handlers never read the pair. A `type: 'api'` action declaring both therefore opened no tab and POSTed to its `target` instead, from the record header, its more-menu and the list toolbar.
11+
12+
What changes:
13+
14+
- On the record page (header row and the more-menu) and on every surface the shared console runtime serves (the list toolbar and the console's root action provider), a `type: 'api'` action with `opensInNewTab: true` and a `newTabUrl` now takes that path: the record id resolves the way that surface resolves it, the pre-opened tab goes to `newTabUrl`, and nothing is sent to `target`. A list launch with several rows selected is refused before the tab opens, as for a `script` action.
15+
- A `type: 'api'` action without `newTabUrl` sends its request to `target` as before.
16+
17+
What to do: nothing. An api action that declares the pair now does what it declares.
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
---
2+
'@objectstack/spec': patch
3+
---
4+
5+
docs(spec): `IEmailService.sendTemplate` and `renderTemplate` list `TEMPLATE_INVALID` in their Errors
6+
7+
Clause-②: no
8+
Metadata-protocol: none
9+
10+
`@objectstack/plugin-email` already refuses a stored template whose hole the authoring rules refuse (rule `email-template-hole-grammar`), throwing `TEMPLATE_INVALID: email template NAME (locale=LOCALE): HOLE_AND_RULE` from both methods. The contract's Errors lists now name that code beside `TEMPLATE_NOT_FOUND`, `TEMPLATE_INACTIVE` and `MISSING_VARIABLES`, so a channel or app author reading `IEmailService` knows the failure is permanent until the template is re-published. Documentation only: no type or schema changes.
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
---
2+
'@objectstack/lint': minor
3+
---
4+
5+
fix(lint)!: the view and object publish doors refuse a list-view chart whose dataset, dimension or measure does not resolve
6+
7+
Clause-②: no (narrowing) — a list view whose `chart.dataset` names no declared dataset, or whose `chart.dimensions` / `chart.values` names a dimension or measure its dataset does not declare, is refused at publish (`PUT /api/v1/meta/view`, `PUT /api/v1/meta/object`); it published `200` before. `os validate` / `os build` already refused it on the shapes they walked, and still do; they now also report it where they skipped it: an `objects[].listViews` chart in a stack that declares no datasets, reports, views or pages, and a `views[]` entry in the flattened list overlay or ViewItem `config` shape. Nothing is widened.
8+
Metadata-protocol: narrowed
9+
10+
<!-- adr-0087: not-required (no-migration-prescription) No key of any schema is added, removed, renamed or re-shaped: an existing author-time rule now also runs at the view and object publish doors. There is no mechanical rewrite to prescribe, because only the author knows which declared dataset or measure the chart meant. -->
11+
12+
**BREAKING** accept-set narrowing at the runtime publish door: `validateChartBindings` (`@objectstack/lint`) joins the reference-integrity suite's `view` and `object` writes.
13+
14+
- **Why.** A Studio or MCP author who mistyped a dataset name, or named a measure the dataset lacks, got a saved view whose chart rendered empty or broken, with nothing saying why, while the CLI refused the same file.
15+
- **Before.** Measured on the real `PUT /api/v1/meta/view` route over a real `sys_metadata` store: a chart list view naming `no_such_dataset`, or a `values` entry naming no measure of its dataset, answered `200` and was stored, as a view item (`config`), as a flattened list overlay and as a container `listViews` member alike. `os validate` / `os build` skipped the same two cases the door now reports: an object's `listViews` chart in a stack with no datasets, reports, views or pages, and the flattened overlay and ViewItem `config` shapes.
16+
- **Now.** Each is refused `422 INVALID_METADATA` with the verdict `os validate` gives: `chart-dataset-unknown` at `chart.dataset`, `chart-measure-unknown` at `chart.values[i]`, and `chart-dimension-unknown` at `chart.dimensions[i]`. The rule's list-view walk now opens the two standalone view shapes the door carries (the flattened list overlay and the ViewItem `config`), and an object's own `listViews` is judged on an object write. A draft save is not gated, as for every author-time rule.
17+
- **Who moves.** No view or object in `examples/**` or `packages/platform-objects` is refused: measured at the door's own snapshot shape, the two chart list views in the showcase app bind declared datasets and measures.
18+
19+
**The remedy.** Bind a dataset the stack or package declares, and name its declared dimensions and measures (a measure name such as `amount_sum`, never the base field `amount`), or declare the missing dimension or measure on the dataset.

‎content/docs/data-modeling/analytics.mdx‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -285,6 +285,13 @@ and list-view charts to it **by name**. Presentations reference a dataset by its
285285
`name` string — the shipped presentation schemas carry no inline/anonymous
286286
dataset shape, so even a one-off single-object KPI is a small named dataset.
287287

288+
A list-view chart's binding must resolve. A `dataset` no package declares, or a
289+
`dimensions` or `values` entry the dataset does not declare, is refused at
290+
publish, for a view and for an object's own `listViews` alike, and fails
291+
`os validate` (`chart-dataset-unknown`, `chart-dimension-unknown`,
292+
`chart-measure-unknown`). A `values` entry names a dataset **measure**, never
293+
the base field it aggregates.
294+
288295
A list-view chart draws the rows of its dataset's base `object`, never the
289296
list's own records: the list's filter does not reach the dataset query. So a
290297
list view's chart must bind a dataset whose `object` is the object the list

‎content/docs/kernel/runtime-services/email-service.mdx‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,3 +31,4 @@ services.email.sendTemplate(input: SendTemplateInput): Promise<SendEmailResult>
3131
- `TEMPLATE_NOT_FOUND`
3232
- `TEMPLATE_INACTIVE`
3333
- `MISSING_VARIABLES`
34+
- `TEMPLATE_INVALID`: the stored template has a hole the authoring rules refuse (a second formatter, or a `currency` argument that is not a literal ISO 4217 code). It is permanent: retrying fails until the template is re-published without that hole. `renderTemplate` raises it too.

‎docs/audits/README.md‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,10 @@ Liveness is judged by **code consumption**, not browser observation (an unreacti
1313
| object | `2026-06-objectschema-property-liveness.md` | ~half dead |
1414
| view | `2026-06-viewschema-property-liveness.md` | list-family healthy; chart/form-variants broken |
1515
| app | `2026-06-appschema-property-liveness.md` | nav core healthy; aspirational tail |
16-
| page | `2026-06-pageschema-property-liveness.md` | drift breaks layouts |
16+
| page | `archive/2026-06/2026-06-pageschema-property-liveness.md` | drift breaks layouts |
1717
| dashboard | `2026-06-dashboardschema-property-liveness.md` | ADR-0021 half-done |
1818
| report | `2026-06-reportschema-property-liveness.md` | dataset live; chart dead |
19-
| dataset | `2026-06-datasetschema-property-liveness.md` | live; Studio under-covers |
19+
| dataset | `archive/2026-06/2026-06-datasetschema-property-liveness.md` | live; Studio under-covers |
2020
| action | `2026-06-actionschema-property-liveness.md` | disabled-CEL ignored; form/shortcut dead |
2121
| flow | `2026-06-flowschema-property-liveness.md` | enum out of sync; runAs unenforced |
2222
| agent | `2026-06-agentschema-property-liveness.md` | autonomy + access-control aspirational |
@@ -25,7 +25,7 @@ Liveness is judged by **code consumption**, not browser observation (an unreacti
2525
| hook | `2026-06-hookschema-property-liveness.md` | **healthy** (near-total) |
2626
| validation | `2026-06-validationschema-property-liveness.md` | **healthy** (all 6 types enforced) |
2727
| security/identity (role, permission, policy, sharing) | `2026-06-security-identity-property-liveness.md` | **policy 100% dead** |
28-
| system/integration (email/i18n/theme/job/webhook/portal) | `2026-06-system-integration-property-liveness.md` | email + portal dead |
28+
| system/integration (email/i18n/theme/job/webhook/portal) | `archive/2026-06/2026-06-system-integration-property-liveness.md` | email + portal dead |
2929

3030
## Cross-cutting patterns (in priority order)
3131

docs/audits/2026-06-ask-build-agent-development-assessment.md renamed to docs/audits/archive/2026-06/2026-06-ask-build-agent-development-assessment.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
**Type**: development assessment / landscape (NOT an ADR — this routes work, it does not decide).
44
**Scope**: every code touchpoint for the two kernel agents across `@objectstack/service-ai` (OSS `ask`), `@objectstack/service-ai-studio` (cloud `build`), `@objectstack/spec` (agent/skill/tool schemas), and `../objectui` (chat surface).
5-
**Frames**: [ADR-0040](../adr/0040-unified-assistant-and-agent-binding.md), [ADR-0063](../adr/0063-two-kernel-agents-skills-are-the-extension-primitive.md), [ADR-0064](../adr/0064-tool-scoping-to-agent.md).
5+
**Frames**: [ADR-0040](../../../adr/0040-unified-assistant-and-agent-binding.md), [ADR-0063](../../../adr/0063-two-kernel-agents-skills-are-the-extension-primitive.md), [ADR-0064](../../../adr/0064-tool-scoping-to-agent.md).
66
**Method**: four parallel read-only inventories. File:line references below are accurate as of this worktree.
77

88
> **Outcome (see §5):** D2 resolved to **two distinct agents bound by surface**; ADR-0040's unified-assistant core is reversed.
@@ -101,7 +101,7 @@ D2 resolved **against** the "one assistant, two tiers" option §4 floated. Ratio
101101

102102
**Resolution: two distinct agents (`ask` / `build`), bound by surface.** ADR-0040's unified-assistant core is reversed; "user never picks a roster" is kept but re-grounded as *surface binding*. See:
103103

104-
- **[ADR-0063](../adr/0063-two-kernel-agents-skills-are-the-extension-primitive.md)** (revised) — two agents bound by surface; skills-only third-party extension; `surface` affinity; naming; supersedes ADR-0040 core + §3.
105-
- **[ADR-0064](../adr/0064-tool-scoping-to-agent.md)** — tool scoping: an agent's tools = its skills' tools (resolves ADR-0040 §4).
104+
- **[ADR-0063](../../../adr/0063-two-kernel-agents-skills-are-the-extension-primitive.md)** (revised) — two agents bound by surface; skills-only third-party extension; `surface` affinity; naming; supersedes ADR-0040 core + §3.
105+
- **[ADR-0064](../../../adr/0064-tool-scoping-to-agent.md)** — tool scoping: an agent's tools = its skills' tools (resolves ADR-0040 §4).
106106

107107
Implementation (split personas, make `build` canonical, finish `ask` rename, withdraw tenant agents, `surface` field, surface-binding in objectui) is consolidated in the follow-up issue. D4 (guardrail floor) remains deferred.

0 commit comments

Comments
 (0)