Skip to content

Commit d6195b9

Browse files
committed
Merge origin/main into claude/issue-24581-ceremony-open
#24588 (step 1) has landed. The drop refusal, os dev's way-on line and their pins from #24635 said "18.0 does not upgrade; keep a v17 database on 17.x": with the ceremony open they name its steps again, and the refusing class and its pin stay deleted. Claude-Session: https://claude.ai/code/session_014UATXWqAXqkaZkbG92ox6V Co-authored-by: Claude <noreply@anthropic.com>
2 parents a3064ef + 7c509c2 commit d6195b9

42 files changed

Lines changed: 2523 additions & 327 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎.changeset/24536-cel-env-reuse.md‎

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
---
2+
'@objectstack/formula': patch
3+
---
4+
5+
perf(formula): a CEL evaluation reuses one environment instead of building the stdlib on every call, and compiles reuse the canonical parse environment
6+
7+
Clause-②: no (an internal cache: no accept set moves, no evaluation result moves, no exported signature changes; owes the seat's review of record before the queue)
8+
9+
- **`celEngine.evaluate` reuses one environment.** It used to build a new cel-js `Environment` and register the whole stdlib into it on every call, which objectql's formula fields reach once per row per field. The stdlib now reads `now()`, the timezone and the permission binding of `current_user.can` / `current_user.hasCapability` from a per-evaluation slot. `evaluate` saves the slot, sets it and restores it in a `finally`, so a nested or a thrown evaluation leaves the outer binding as it was. Evaluations also run a bounded per-source cache of parsed programs, keyed on the source after its row-dependent rewrites.
10+
- **`celEngine.compile` reuses the canonical parse environment** that `parseCelToAst` already shares.
11+
- Results, error kinds and error messages are unchanged. `registerStdLib`, `registerPermissionPredicate` and `registerCapabilityPredicate` keep their signatures and their behaviour.
12+
- Measured on one source evaluated 20,000 times: about 142 µs per evaluation before, about 3 µs after. A 25-row read of an object with three formula fields built 78 environments before and builds none after.
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
---
2+
'@objectstack/service-storage': minor
3+
---
4+
5+
fix(service-storage): the single-shot upload commit refuses a file whose bytes the storage backend does not hold
6+
7+
Clause-②: no (narrowing)
8+
9+
<!-- adr-0087: not-required (no-migration-prescription) What narrows is the single-shot upload commit door: a completion naming a file whose bytes the storage backend does not hold, or holds at another size than the upload declared, used to answer 200 and commit the row, and is now refused 409 with the row left pending. Nothing migrates: no spec key, authorable spelling, export or stored shape is removed, renamed or re-shaped, and no stored row is read, rewritten or converted, so there is nothing for `objectstack migrate meta` to rewrite. A refused client finishes the upload by sending its bytes, not by rewriting code or metadata. -->
10+
11+
**What was wrong.** `POST /api/v1/storage/upload/complete` set the `sys_file` row to `committed` without asking the storage backend. A presigned upload whose byte `PUT` failed, or was never sent, therefore committed with the size it declared. The download doors serve any `committed` file, so `GET /api/v1/storage/files/:fileId/url` handed out a signed URL, and fetching it failed with `500`.
12+
13+
**What the commit door does now.** Before it commits, it asks the backend through two members every adapter implements: `exists(key)`, and `getInfo(key).size` compared with the size the upload declared. When the backend holds no bytes for the file, or holds a different number of bytes, the door answers `409` with the standard code `RESOURCE_CONFLICT`. The row stays `pending`, so nothing is served for it. This is the answer the chunked completion already gives an upload that does not hold its declared bytes.
14+
15+
**What changes for you.** Nothing, if your client sends the bytes before it completes, as the SDK's `storage.upload` and the console's upload provider do. A client that completes first now receives the `409`: send the file to its upload URL (start a new upload if that URL has expired), then complete again. If the storage adapter reports a fault while the door asks, the door answers `500`. The local adapter does not report an unreadable storage root as a fault: it reports it as holding no bytes, so on the local adapter the door answers `409`.
16+
17+
The `eTag` a completion may carry is still stored as sent and not compared: no adapter reports the stored object's ETag.
18+
19+
**The local adapter's download link.** `GET /api/v1/storage/_local/raw/:token` answers `404` `FILE_NOT_FOUND` when no file is stored under the link's key. Before, it answered `500` `INTERNAL` ("Download failed"). Every other read failure still answers `500`.
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
---
2+
'@objectstack/cli': patch
3+
---
4+
5+
fix(cli): `os migrate apply --allow-destructive`'s organization-ownership refusal says what 18.0 supports for a v17 database, and names no step of the command 18.0 refuses
6+
7+
Clause-②: no
8+
9+
- **`os migrate apply --allow-destructive` on a v17-shaped database.** When the run would drop `organization_id` from a table the organization-ownership ceremony owns, and the ceremony has not verified on the database, the refusal now says that 18.0 supports fresh installs only and does not upgrade a v17 database: keep a v17 database on a 17.x release until the 18.x release that carries the upgrade path, whose ceremony drops these columns itself. The v18 boot refusal and `os migrate organization-ownership`'s own refusal say the same. Before, it told the operator to run `os migrate organization-ownership --out PLAN` and then `--apply --plan-file PLAN`, which 18.0 refuses on every database (`NOT_IMPLEMENTED`). The `--json` refusal's `detail` no longer names that command either: it reads "No run of the organization-ownership ceremony is recorded on this database.", or names the last unverified run with its date and blocking count.
10+
- **`os migrate organization-ownership --help`** shows what the command answers in 18.0: exit `1` with `NOT_IMPLEMENTED`, nothing read or written, and the same refusal as JSON. Before, it showed six plan and apply examples that 18.0 refuses.
11+
- **`os dev` on a v17-shaped development database.** When it does not upgrade the database in place (the ceremony's plan is refused, or the database is not a local SQLite file), it now ends with the same position: keep a v17 development database on a 17.x release until the 18.x release that carries the upgrade path, and upgrade it there. Before, it told the developer to run `os migrate organization-ownership --dev` and then the same command with `--apply`.
12+
13+
Nothing else changes. The refusals still hold back the whole run, and their message code (`refused_organization_ownership_unmigrated`), `tables`, `marker`, exit code `1` and every flag are as before.
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
---
2+
'@objectstack/service-automation': patch
3+
---
4+
5+
The flow inspector's Error Variable help for a Try / Catch node describes the caught error in words
6+
7+
Clause-②: no (help text only: the `try_catch` descriptor's `configSchema` accepts exactly what it accepted before, and the value bound to the error variable is unchanged)
8+
9+
- The `errorVariable` description no longer names a TypeScript type (`TryCatchErrorValue`). It now says what the bound value carries, in plain language: the id of the Try / Catch node (`nodeId`), the failure message (`message`), the platform error code when the failing step reported one (`code`), and, for a failure inside a loop, the zero-based pass number (`iteration`) and the item being processed (`item`). The default variable `$error` is named.
10+
- The old text also left out `code`, which the engine has bound since the classified-code change; an author reading the inspector had no way to learn that a catch region can branch on it.
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 status mirror writes only a value the field declares, so a recalled record whose status field is a select goes back to where it stood before it entered approval
6+
7+
Clause-②: no
8+
9+
**The rule:** when `approvalStatusField` is an option field (a `select`) whose options do not declare the status, a recall or the dead-run sweep writes the value the field held when the flow started (the request's submit snapshot), else the field's declared default, else empty, and every other transition writes nothing and logs a `warn` naming the object, field and value.
10+
11+
- **Before.** Each status was written verbatim. The engine checks a `readonly` field's value for shape only, and the spec advises a readonly status field, so a select that did not declare `recalled` ended up holding it after a recall. An app whose submit gate admits only the select's own values (for example `not_required` or empty) then never re-entered approval. On an editable select the engine refused the undeclared value, and the field kept reading `pending` with no request pending.
12+
- **Now.** A recalled record, or one released by the dead-run sweep, reads its submit-time value again, so the app's own start condition decides whether it re-enters approval. A gate that admits that value re-admits the record at once, because the restore is itself an update.
13+
- **Send-back keeps the field.** A select that does not declare `returned` keeps reading `pending` through the revise window. The run is still alive there (ADR-0044), and a restored pre-approval value would re-admit the start condition and open a second, parallel approval of the same record.
14+
- **Unchanged.** A status the select declares is written as before. A field with no declared value set (text, or any type that is not an option type) gets every status verbatim, as before. The write's context is unchanged.
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
---
2+
"@objectstack/console": minor
3+
---
4+
5+
Console (objectui) refreshed to `12dc7b47c340`. Frontend changes in this range:
6+
7+
Derived from the changesets objectui declared over the range — 28 releasing of 28 changesets added across 32 non-merge commits; omitted: 4 commits carrying no changeset (they ship no package code).
8+
9+
- **minor** — Setup lists the sharing rules installed packages declare again, read-only, with Disable / Enable and Clone (objectui#12982). (objectui `12dc7b47c`)
10+
- **minor** — `list-view` publishes the keys of its `@objectstack/spec` row that the renderer honours on a page node (objectui#13047). (objectui `a244a172a`)
11+
- **minor** — **BREAKING** — An import undo that leaves rows unreverted now says so in the Import Wizard (objectui#13015). (objectui `a928aaa61`)
12+
- **minor** — A `type: 'form'` action placed at `record_related` and fired from a related-list row now opens the clicked row's edit form (`/forms/NAME?recordId=ROW_ID&recordObject=CHILD`), as i… (objectui `9f1dd79fe`)
13+
- **minor** — A field group whose `visibleWhen` cannot be evaluated is now hidden, header and members, on the form and on the record detail page (objectui#13055). (objectui `fb85637e1`)
14+
- **minor** — The AI build chat's pending-drafts bar no longer covers the composer's input (objectui#12978). (objectui `51269f0fd`)
15+
- **minor** — Bound record blocks draw an authored empty state when their binding answers no row (objectui#12932, the renderer half of objectstack-ai/objectstack#24266). (objectui `c2191654a`)
16+
- **minor** — Publish `optionListDefault` (and its parameter type `OptionListFieldLike`) from the package entry: the reading of an option list's `default: true` that create forms seed from (obj… (objectui `b9e188762`)
17+
- **minor** — Build `@objectstack/*` from objectstack `main` `f4755a68a7` (objectui#12971). (objectui `8aa8e3e1e`)
18+
- **minor** — Two Cloud SDUI widgets are retired: `cloud:onboarding-next`, the Welcome page's next-step block, and `cloud:plan-status`, the pricing page's current-plan marker (objectui#12954).… (objectui `30083da91`)
19+
- **minor** — Every app now has a report index at `/apps/APP/reports` (objectui#13020). It lists the reports the app's package ships, by their localized labels, each linking to its `report/NAME… (objectui `47508f3bb`)
20+
- **minor** — A record page that shows the same unfiltered related list both as a `record:reference_rail` card and in a `page:tabs` count badge now reads that list once on open, not twice. The… (objectui `d0b9648ef`)
21+
- **patch** — Studio's RLS policy editor now gives a predicate the runtime cannot lower the server's verdict: an error that holds Save and autosave (objectui#13061). A `USING` or `CHECK` clause… (objectui `2a75c83b2`)
22+
- **patch** — A master-detail edit form now applies its line rules to the header record however late that record loads (objectui#13062). (objectui `bc98626ed`)
23+
- **patch** — A deep link to an object read by name always leaves the "Opening your console…" splash (objectui#13052). (objectui `1ce071187`)
24+
- **patch** — A kanban card move is announced to screen readers when its write answers, not when the card is dropped (objectui#13054). (objectui `083e80735`)
25+
- **patch** — An `app` page that declares a `record` binding now reads that row, and its components' `visibleWhen` predicates read it as `record` (objectui#12931, the renderer half of objectsta… (objectui `a23a33d6f`)
26+
- **patch** — One page open asks the server for one object document once (objectui#13044). The metadata provider's by-name object read now goes through the adapter's `getObjectSchema`, so the p… (objectui `65fe4c285`)
27+
- **patch** — A record page no longer asks `POST /api/v1/security/explain` for a verdict nothing on screen uses (objectui#13045). (objectui `50ba1bb0a`)
28+
- **patch** — Charts and dataset widgets read their object's metadata through the data source, so the widgets of one dashboard ask for one object's metadata once (objectui#13039). (objectui `988aa9fa1`)
29+
- **patch** — The Undo of an `operation: 'update'` action covers the `patch` of the declared action its `name` names, and no action renderer forwards a page action row's own `patch` (objectui#1… (objectui `61ed5ada6`)
30+
- **patch** — A list view draws a `referenceVia` pointer column's record when its columns do not show the type half (objectui#13036). (objectui `fe11eb12e`)
31+
- **patch** — A record link in an assistant answer opens that record inside the console (objectui#13037). (objectui `633b8f18f`)
32+
- **patch** — The chat's step line no longer shows the agent's tool-loading step, and no longer counts it (objectui#13038). (objectui `912bfd4a6`)
33+
- **patch** — An assistant answer reads well in the narrow assistant panel (objectui#13032). Headings inside a chat answer render at chat size (15–16px, bold, set apart by weight and spacing in… (objectui `6f877f1df`)
34+
- **patch** — The console's pending-approvals read now asks for one page of requests and takes the count from the route's `total` (objectui#13027). (objectui `d14ba9636`)
35+
- **patch** — A record page of a `trackHistory` object reads its audit history when the History tab is shown (objectui#13010). (objectui `acefe6fa6`)
36+
- **patch** — A record page reads its timeline, comments, user list and foot-of-page attachments when they are shown, not on every open (objectui#13010, part 2). (objectui `29c19cc1a`)
37+
38+
⚠️ 1 of these carries a breaking change: 1 by the author's own breaking annotation in the changeset body — objectui declares no `major` inside a launch window (`scripts/check-changeset-no-major.mjs`). Each is marked **BREAKING** in the list above — read them before compiling the release record.
39+
40+
**In this console build, declared nowhere** — objectui merged 4 commits in this range with no `.changeset/*.md`. The code is inside the pin above and ships here, but nothing upstream declared them, so they appear in no objectui CHANGELOG and in no entry above. Listed by subject rather than counted, because a count cannot tell a dependency bump from a form-behaviour change (objectstack#6174); the upstream gate that would prevent this is objectui#3387.
41+
42+
- _(no changeset)_ fix(ci): read transient jobs-API failures, re-run attempts and stale shards without false reds in the aggregate Test gate (objectui#13064) (#13077) (objectui `90a4fc49b`)
43+
- _(no changeset)_ tooling(pin): keep one pinned @objectstack build per machine and copy it into each new checkout (objectui#12972) (#13035) (objectui `f9401e6af`)
44+
- _(no changeset)_ tooling(pin): commit the pin's packed manifests so a lockfile-only resolution needs no build (objectui#13008) (#13031) (objectui `b014f5eea`)
45+
- _(no changeset)_ tooling: publish computes each @objectstack/* floor from .objectstack-sha (objectui#12958) (#13024) (objectui `4484a1104`)
46+
47+
Clause-②: no
48+
49+
<!-- adr-0087: not-required (no-migration-prescription)
50+
This diff moves `.objectui-sha` and the artefacts that travel with it: this console
51+
changeset, the re-recorded `scripts/sdui-manifest.record.json` and the regenerated
52+
`sdui.manifest.json`, and the re-recorded `packages/sdui-parser/objectui-lockstep.json`.
53+
It adds, removes or renames no ObjectStack-authorable key: no Zod shape, no spec
54+
declaration and no stored `sys_metadata` shape moves in it, so `objectstack migrate meta`
55+
has nothing here to rewrite, and this body carries no FROM/TO prescription of its own.
56+
The range carries one objectui change its author annotated breaking, and the digest
57+
marked it. It is answered against this tree: objectui `a928aaa61` (objectui#13015)
58+
makes `failures` a required member of `@object-ui/types`' `ImportJobUndoResult`, so a
59+
custom objectui `DataSource`'s `undoImportJob` answer must carry it, and widens
60+
`@object-ui/i18n`'s `TranslationKeys` with the `grid.import.undoPartial` family. No
61+
package in this tree imports or depends on any `@object-ui/*` package, and
62+
`@objectstack/console` publishes objectui's built SPA and exports no objectui type. The
63+
route side of that shape is this tree's own: `UndoImportJobResponseSchema` already
64+
requires `failures`, and `client.data.undoImportJob` already returns it. -->
65+
66+
objectui range: `4016370af3c9...12dc7b47c340`

‎.objectui-sha‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
4016370af3c9c9dafec2bc5299afd8e8079701b8
1+
12dc7b47c340d9bd80b35406d890c2d27c8017dc

0 commit comments

Comments
 (0)