Skip to content

Commit 5a7ad6a

Browse files
committed
Merge remote-tracking branch 'origin/main' into claude/project-thread-ybjm3h
2 parents e6ddd60 + 8faba89 commit 5a7ad6a

104 files changed

Lines changed: 3832 additions & 3365 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: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
---
2+
'@objectstack/sdui-parser': patch
3+
---
4+
5+
feat(sdui-parser)!: one parser body: the renderer copy's additions join `@objectstack/sdui-parser` (#25712)
6+
7+
Clause-②: yes (narrowing: `validateTree` now also judges the nodes held in a manifest entry's declared `slots`, so a caller whose manifest carries `slots` gets diagnostics on slot-held nodes it did not get before)
8+
Metadata-protocol: none
9+
10+
Two copies of this parser existed: this package, which the save gate runs, and `@object-ui/sdui-parser`, which the renderer runs. `check:sdui-lockstep` held them to one grammar and one code set, and they drifted everywhere else. This change makes this package the one body. The renderer moves onto it and the second copy is deleted in follow-up changes under the same card.
11+
12+
**Added (from the renderer's copy).**
13+
14+
- Node-slot validation (objectui#11170). `ManifestComponent.slots` lists the positions besides `children` where a renderer reads nodes, such as `trigger`, `items[].content` and `regions[].components`. `validateTree` descends each one the way it descends `children`. `manifestFromConfigs` gains a `slotsFor` option that writes the list, and a manifest built without it carries none, so the walk follows `children` alone.
15+
- The retired `body` child-list key (objectui#6771). Before, `body` drew the bare `unknown-prop`. Now the message names `children`. A `body` child list under a component that takes no children draws `not-a-container`, the code the `children` spelling draws. Both remain warnings. Exported as `checkRetiredBodyDialect` and `RETIRED_CHILD_LIST_KEY`.
16+
- html-tier provenance (objectui#4000). `parseJsx` stamps every element it builds with an enumerable symbol-keyed marker, `Symbol.for('@object-ui/sdui-parser.html-tier-node')`. `JSON.stringify` and `Object.keys` do not see it. Exported as `HTML_TIER_NODE`, `isHtmlTierNode` and `markHtmlTierNode`. The registry key keeps its original package name on purpose, so a node either copy stamped reads the same.
17+
- More exports:
18+
- `acceptsChildren`, `CHILD_LIST_KEY`, `SDUI_BASE_PROPS`, `SduiBaseProp` and `SduiBasePropScope`;
19+
- `assertFullyLoaded`, the manifest generators' guard against lazy stubs, with `RegistryConfigLike.lazy`;
20+
- `NodeSlotDeclarationLike`.
21+
- The generated `.d.ts` header gains `/* eslint-disable */` and names this package.
22+
23+
**Renamed, with the old names kept.** `ParsedSchemaNode` is the parsed node and `ManifestValidationResult` is `validateTree`'s result. These are the names the renderer's copy took so it would not collide with `@object-ui/types`' `SchemaNode` or the spec's `ValidationResult` (objectui#6349, objectui#3161). `SchemaNode` and `ValidationResult` stay exported as `@deprecated` aliases of them, so nothing exported is removed.
24+
25+
**Unchanged.**
26+
27+
- Every `type-mismatch` and `member-type-mismatch` is still an `error`. The renderer's copy graded them `error` only beside an `enum` arm; this package's rule is the one kept.
28+
- `unconsumed-widget-option` is still emitted as an inline literal.
29+
- The grammar, the 25 diagnostic codes and the containment predicate.
30+
31+
**BREAKING** (a narrowing of `validateTree` for a manifest that carries `slots`), shipped as `patch` because no metadata protocol kind moves. The save gate's verdicts do not move, and that was measured: the manifest that `objectstack validate`, `build`, `lint` and `serve` read is the tracked `sdui.manifest.json`, which `@objectstack/console` ships. It carries `slots` on 0 of its 106 entries, because its generator calls `manifestFromConfigs` without `slotsFor`. So no save that was accepted before is refused now. The walk has work only for a caller that builds its manifest with `slotsFor`, and today that is the renderer, whose own copy already walks the slots.
32+
33+
Migration, for a TypeScript caller: none is required. To move off the deprecated names, change `SchemaNode` to `ParsedSchemaNode` and `ValidationResult` to `ManifestValidationResult`.
34+
35+
`body-dialect.ts` and `provenance.ts` moved in from the MIT-licensed `@object-ui/sdui-parser` and keep that licence. Each carries the notice, and the package now ships `LICENSE-MIT`.
36+
37+
<!-- adr-0087: not-required (no-migration-prescription) No metadata moves: no spec key, authorable spelling, object definition, stored row or stored shape is added, removed, renamed or re-shaped, so there is nothing for `objectstack migrate meta` to rewrite. What narrows is `validateTree`, a function of this library, for a manifest that carries the new `slots` key: nodes held in those positions are now judged. No manifest the save gate reads carries that key (the tracked `sdui.manifest.json`: 0 of 106 entries), so no stored or authored page changes verdict there. A caller who builds a slotted manifest gets diagnostics on slot-held nodes, and the repair is the page author's per diagnostic, which no ledger entry can derive. The other categories are closed on facts: the package publishes (not unpublished); no ADR-0087 id is named or touched (not registered or already-registered); and nothing exported is removed or narrowed, since the two renamed types stay exported as deprecated aliases (not runtime-interface-only, type-surface-only or runtime-export-retired). -->
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
---
2+
'@object-ui/plugin-grid': patch
3+
---
4+
5+
fix(plugin-grid): a bulk action's `confirmText` fills each param hole with that param's display value
6+
7+
Clause-②: no
8+
Metadata-protocol: none
9+
10+
A bulk action's `confirmText` holes may name the action's params by `name` (`{{ tier }}`), and the protocol states what such a hole shows: the param's display value. The bulk dialog filled `{{ count }}` only, so a param hole printed empty. It now fills each param root by that rule. An option-bearing param shows the chosen option's label, and a multi-value param shows its labels joined with ', '. A `lookup` or user param shows the picked record's display name (its id until the name has resolved; the sentence updates when the name arrives). Any other param shows the entered value itself, so the template engine's formatters apply (`{{ amount | currency:EUR }}`, `{{ due | date:long }}`). An empty param prints empty, and `{{ count }}` still wins over a param named `count`. The default sentence and the place of the confirm step are unchanged.
11+
12+
What to do: nothing.
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
---
2+
'@object-ui/app-shell': patch
3+
'@object-ui/i18n': patch
4+
---
5+
6+
fix(app-shell): the record create and update toasts name the saved record
7+
8+
Clause-②: no (adds or rewords message keys; no key is removed, so `TranslationKeys` only widens; no exported runtime contract changes)
9+
Metadata-protocol: none
10+
11+
A user entering several records in a row saw "Task created successfully" after each save and could not tell which record was just written. The Console's record-form save toasts now carry the saved record's display name (ADR-0079), for example `Task "Quarterly review" created` and `Task "Quarterly review" updated`. This covers the record-form overlay on a list and the child-record form opened over a parent record's page.
12+
13+
- **`@object-ui/app-shell`:** the name comes from the same display-name resolver the record page title and lookups use, read through the saved object's declared name field. A record with nothing nameable (the resolver would only answer `Record #ID`) keeps the object-label toast it showed before.
14+
- **`@object-ui/i18n`:** two new keys under `form.` in all ten packs, `createdNamed` and `updatedNamed`, each with `{{object}}` (the object label) and `{{title}}` (the record's name). The existing `form.createSuccess` / `form.updateSuccess` strings are unchanged and remain the toast for a record with no name.
15+
16+
Settings saves and flow-completion toasts are unchanged.
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
---
2+
'@object-ui/app-shell': patch
3+
---
4+
5+
fix(app-shell): the permission matrix sets and shows each object's read and write record scope
6+
7+
Clause-②: no
8+
Metadata-protocol: none
9+
10+
ADR-0084 declares a record-scope column for the permission matrix, but Setup → Permission Sets and Studio → Access had no control for an object permission's `readScope` / `writeScope`. The only way to set them was `PUT /api/v1/meta/permission/:name`.
11+
12+
- **Pickers.** Every object row, in both the Setup table and the Studio Access matrix, now has a **Read scope** and a **Write scope** picker. Each lists "Not set" and the five `ObjectAccessScopeSchema` values: own, own and reports, my unit, my unit and below, whole org. A picked value saves and reloads unchanged. This holds at the environment door and at the package door, where the slice merge keeps it. "Not set" removes the key.
13+
- **Hierarchy values.** "Own and reports", "My unit" and "My unit and below" carry the hint "requires enterprise; otherwise owner-only" and stay selectable. The open runtime resolves them to the owner alone. No hierarchy resolver is installed there.
14+
- **View All / Modify All.** The spec refuses `readScope` beside View All or Modify All, and `writeScope` beside Modify All, because those bits already grant org-wide access. Ticking View All now disables the read-scope picker and removes `readScope`. Ticking Modify All disables both pickers and removes both scopes. The **All** bulk button does the same. Before this change, both paths saved a row the server refuses. Effective access does not change, because the resolvers answer `org` on those bits before they read a scope. "CRUD", "R" and "None" are unchanged.
15+
16+
What to do: nothing. No spec key, stored shape or API changes.
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
---
2+
'@object-ui/permissions': patch
3+
---
4+
5+
fix(permissions)!: the console stops offering New, Edit and Delete to a user whose `/me/permissions` row omits the Create, Edit or Delete bit, such as an auditor or a read-only finance user
6+
7+
Clause-②: yes (narrowing) — the console no longer offers Create / Edit / Delete when `/me/permissions` serves an object row that omits the bit. That is exactly when the server refuses it, because the spec grants only on `=== true` (permission.zod.ts:196, :218). The anonymous default and the no-provider fail-open are unchanged.
8+
Metadata-protocol: none
9+
10+
<!-- adr-0087: not-required (no-migration-prescription) A console permission verdict: no key of any metadata schema is added, removed, renamed or re-shaped, and no export, type or error code changes. The client now reads a served row with the spec's own objectPermissionGrants, so there is nothing for `objectstack migrate meta` to rewrite and no tombstone. -->
11+
12+
**BREAKING** (a narrowing of what the console offers) in `MePermissionsProvider` (`@object-ui/permissions`).
13+
14+
- **Before.** `check` (behind `usePermissions().can`) and `checkField`'s object-level fallback read a served object row with `bit !== false`, so a bit the row left out counted as granted. The server serves only the bits a set grants: a read-only set `'*': { allowRead: true }` is served as `{ allowRead: true }` on each object it covers, and an auditor's row as `{ allowRead: true, viewAllRecords: true }`. Those users were offered New on object lists, and Edit and Delete on records. They filled in the form, and the server refused the save with `403`.
15+
- **Now.** A served row grants an operation only through `objectPermissionGrants` from `@objectstack/spec/security`, the fold the server's permission evaluator decides from. A bit grants only when it is `true`. Modify All Records also grants edit, delete and transfer, and View All Records also grants read. Nothing grants create but `allowCreate: true`. `check` also matches the object key case-insensitively, as `checkField` already did.
16+
- **Unchanged.** An anonymous session (`authenticated` not `true`) keeps its permissive default. A tree with no permission provider keeps the fail-open `can`. An object the response does not mention is still denied for a signed-in user. A row that carries the bit as `true` grants exactly as before.
17+
- **Who sees it.** A user whose permission sets grant read but not Create, Edit or Delete on an object. The console now hides or disables those actions, matching the server's answer. A user whose sets grant the bit sees no change.
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
---
2+
'@objectstack/cli': patch
3+
'@objectstack/service-storage': patch
4+
---
5+
6+
fix(cli,service-storage): the Console document's `connect-src` names the store the server presigns browser uploads to
7+
8+
Clause-②: yes (widening)
9+
Metadata-protocol: none
10+
11+
With S3 or an S3-compatible store (R2, MinIO), the Console uploads a file by `PUT`ting it straight to the URL `POST /api/v1/storage/upload/presigned` answers, on the store's host. The Console document's content-security-policy did not name that host, so the browser refused every such upload with `TypeError: Failed to fetch`.
12+
13+
- **`@objectstack/service-storage`.** `S3StorageAdapter.getPresignedUploadOrigin()` answers the origin every presigned upload URL carries. It signs a probe upload with the same client options as every real presign, so a virtual-hosted bucket (`BUCKET.ENDPOINT-HOST`), a region-templated AWS host and a path-style endpoint come out exactly as the upload URL carries them. Signing is local and uses fixed probe credentials, so it never reaches the network or the AWS credential chain. `SwappableStorageService.getPresignedUploadOrigin()` answers the active adapter's origin, or `undefined` for an adapter without one (the local adapter's uploads go to the server itself).
14+
- **`@objectstack/cli`.** The Console mount reads that origin off the kernel's `storage` service on every document and adds it to `connect-src`, after the error-reporting origin and before `OS_CONSOLE_CSP_CONNECT_SRC`. A storage settings change that swaps the adapter is followed on the next document, with no restart. Local storage, no storage service, or a store whose endpoint the presigner refuses adds nothing. The last case logs one `warn` that names the remedy. `OS_CONSOLE_CSP_CONNECT_SRC` still adds an operator's extra sources, and a deployment that named its store there as a stop-gap can drop it.
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
---
2+
'@objectstack/core': patch
3+
---
4+
5+
fix(core): one declaration serves both module formats, so the export map hands each condition its own `types`
6+
7+
Clause-②: no
8+
Metadata-protocol: none
9+
10+
`@objectstack/core` used to emit two separate declarations of every class, `dist/index.d.ts` and `dist/index.d.cts`, and its export map served the ESM-kind `index.d.ts` to both conditions, so a TypeScript consumer resolving `require` was told the package is ESM (attw `FalseESM` on `.` and `./logger`). Serving the `.d.cts` to `require` was not possible while the two files declared `ObjectKernel` twice: its `private plugins` member makes the two copies incompatible types for any program that reaches core through both resolution modes.
11+
12+
Core's declaration build now runs once, for the ESM format. `dist/index.d.ts` and `dist/logger.d.ts` carry the declarations, as before, and `dist/index.d.cts` and `dist/logger.d.cts` are one-line re-exports of them, so both conditions hand out the same classes. `exports` now gives types per condition, `{ import: { types, default }, require: { types, default } }`, on both subpaths. No subpath is added or removed, no JavaScript file changes, and the `dist` file names are unchanged.
13+
14+
A CommonJS consumer compiling with `module: node16` (or, measured on TypeScript 5.6, under `nodenext` too) used to get TS1479 at its own `import ... from '@objectstack/core'`. That diagnostic now sits inside core's `.d.cts`, where `skipLibCheck` silences it. Nothing else for a consumer to do.

‎.claude/agents/os-dev.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ model: opus
4949
- 把作者引向运行时会兑现却让事情更糟的元数据的警告不在 (c) 内,记为边界不扩类。
5050
- 其余 ⛔ 不立卡:只读推断、观察、休眠、零拉动、死代码、未演练漂移、抛光、命名。
5151
- 它们进 PR `## Acceptance notes`;报告 `out_of_scope_findings` 逐条 `class:`+`reach:`+证据,或 `carrier:`。
52-
- `carrier:` = 卡号或人,⛔ 非下个碰 X 的 PR;无则「承接者:无」;皆无 ⇒ 只进 Acceptance notes。
52+
- `carrier:` = 卡号或人,⛔ 非下个 PR;涉 cloud 写 `carrier: cloud`;无则 `none`;皆无只进该节。
5353
- 同族发现 ⛔ 不开单点卡,报告点名并入该族收口卡;收口卡定义住 pm-dispatch 报告契约。
5454
- dev ⛔ 不查重、不扫 open issues、不拉板,只附 3–5 个查重词;查询与命中数由立卡席写。
5555
- GitHub 写一律经 `scripts/pm/` 写工具;云容器里经 `fleet-write` 中继落为 `objectstack-fleet[bot]`。

‎.claude/skills/pm-dispatch/references/cross-repo-coordination.md‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
# 多仓协调
22

3-
分诊席每次 fire 路由与查重前读本文;执行席跨仓认领、派发或转移时读本文。
4-
53
- 产品依赖方向固定:`objectstack`(后端与 `ui/` 前端,`packages/spec` 唯一契约)→ `cloud`、`hotcrm`。
64
- 多车道仓 `objectstack`:中央分诊是 `domain:*`/type/定级的唯一生产者。
75
- 单车道仓 `cloud`、`objectos`、`hotcrm`、`www.objectos.ai`;未来新仓默认此类。
@@ -45,3 +43,5 @@
4543
- 该评论点名席位与步骤;无既有卡承载且请求自身即立卡门 ①②④ 时才立新卡。
4644
- 跨不可达仓的卡立卡或首触按仓拆:该仓部分由可达席立卡,或挂 `domain:cloud`+`status:parked`。
4745
- 本卡只留本仓活,不读他仓;拆不开先立该仓前置卡;依赖即 `pm:blocked`+`Blocked-by: owner/repo#N`。
46+
- 开发中涉 cloud 车道者由席位同拆:报告 `open_questions`/`out_of_scope_findings`、复核/落地所见。
47+
- ⛔ 不记而弃、不并入本仓 PR、不留 `carrier: none`;停放卡加 `repo:cloud`,出处行与一行判据。

‎.claude/skills/pm-dispatch/references/execution-duties.md‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,7 @@
175175

176176
- 你是记录在案的复核人:对 GitHub 核验,⛔ 不对报告的自述核验。
177177
- 逐项判据展开在 `references/review-checklist.md`,每份报告对着它过。
178+
- 报告 `open_questions`/`out_of_scope_findings` 涉 cloud 车道者,按 `cross-repo-coordination.md` 立 cloud 卡。
178179
- 改到已有 `.changeset/*.md` 的 PR ⛔ 不打 `skip-changeset`;确认取同 head 达档 PASS 或维护者原话。
179180
- 报告在草稿 PR 时点到达,CI 收敛读数只属于复核侧:gate `in_progress` 是诚实读数。
180181
- 绿色输出≠ 该绿证明了被测风险:拒收断言、全绿方向与时序、pin 翻转、边界后收益。

0 commit comments

Comments
 (0)