Skip to content

Commit d246cd7

Browse files
committed
Merge remote-tracking branch 'origin/main' into claude/project-thread-1minft
2 parents 4fdb6f5 + ab085a0 commit d246cd7

60 files changed

Lines changed: 2359 additions & 274 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: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
---
2+
'@objectstack/service-automation': patch
3+
---
4+
5+
fix(service-automation)!: the subflow guards see a `subflow` / `map` call inside a region body (#28846)
6+
7+
Clause-②: no (narrowing)
8+
Metadata-protocol: none
9+
10+
**BREAKING** for a packaged flow that calls a packaged child from inside a `loop` body, a `parallel` branch or a `try_catch` slot.
11+
12+
- **Before.** The ADR-0126 §7.3 guards read a flow's calls from its top-level nodes only. A `subflow` or `map` node inside a region body was invisible to them. A packaged caller was armed onto a disabled packaged child and failed mid-run at that node, and the child could be switched off or removed while an enabled caller still called it.
13+
- **Now.** The guards read calls at every region depth, through the spec's region walk (`collectFlowGraphs`). A packaged caller whose region body calls a disabled packaged child registers but is not armed: it warns, and `/_status` reports `unboundCause: 'disabled_subflow'` naming the child. Switching off or removing a packaged child that an enabled packaged caller calls from a region body is refused with `DELETE_RESTRICTED` (409), naming the caller. Re-arming when the child is enabled or republished `active` works as it does for a top-level call.
14+
- **Not changed.** The save-notice half of the arming gate (#28840) still reads top-level calls only. A region cannot carry a durable pause, so a region-nested call whose child suspends fails the run at the region boundary before anything after it runs. Registration, the save door and `objectstack validate` accept the same flows as before.
15+
- **The fix.** Enable the child, or publish it `active`, and the caller arms. To switch off or remove a child, switch off its callers first, as the refusal names.
16+
- **Who moves.** HotCRM's `campaign_enrollment` calls two active children from loop bodies. It still arms. Switching off or removing those children while it is enabled is now refused, as it already was for a top-level call. Showcase and dogfood calls are all top-level.
17+
18+
<!-- adr-0087: not-required (no-migration-prescription) no metadata key is added, removed, renamed or re-shaped and the save door accepts the same flows: the runtime guards now read calls they already should have read, the remedy is an administrator's enable or a republish named in the warning and the refusal, and no migration could rewrite that choice -->
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
---
2+
'@objectstack/service-analytics': patch
3+
---
4+
5+
fix(service-analytics)!: the draft preview refuses a date bucket over a column that is not a date or datetime, as the published dataset does, instead of serving one null group
6+
7+
Clause-②: no (narrowing) — `queryDataset` with `previewDrafts: true` now refuses `INVALID_FIELD` / 400 at `groupBy.N.dateGranularity` a `timeDimensions` granularity over a field declared neither a date nor a datetime (text, select, number, boolean, …), with the refusal both live faces give the same selection, field for field; it served one `null` group (a `1970` group for a number). Nothing is widened: no export, public member, answer member, error code or status is added.
8+
Metadata-protocol: none
9+
10+
<!-- adr-0087: not-required (no-migration-prescription) No key of any schema is added, removed, renamed or re-shaped, and no export or type of the package root changes: a draft preview that served a group the published dataset refuses is refused with the published refusal, already on the wire. There is nothing for a migration to rewrite and no tombstone. -->
11+
12+
**BREAKING** accept-set narrowing on the draft preview of `queryDataset` (`@objectstack/service-analytics`). The published faces are unchanged.
13+
14+
- **Before.** Measured on real SQLite on `main` `9a9823d9`. The native and ObjectQL faces refused a month bucket over a text, select or boolean column, and a year bucket over a number column, with the engine's `INVALID_FIELD` / 400 at `groupBy.0.dateGranularity`. The draft preview served one `null` group holding the whole total, or one `1970` group for the number.
15+
- **Now.** The preview judges the keys the ObjectQL strategy would hand the engine, with the engine's reading (the field's declared type, classed by the spec's date and datetime sets; no declared type or a `formula` is not judged). It gives the engine's refusal: the same message, `object`, `param`, `path`, `field` and `fields`. It runs after the preview's column-asked-twice refusal, as on the live faces.
16+
- **Unchanged.** A date or datetime bucket is served alike on every face. The live faces and the engine door are untouched.
17+
- **Who sees it.** An author previewing a drafted dataset that buckets a non-date column: the refusal the published dataset gives, instead of a chart it will not serve.
18+
19+
**The remedy.** Group by the column without a granularity, or bucket a date or datetime field.
20+
21+
Also in this change, the `/analytics/sql` dry run reads its time-dimension windows before its column-asked-twice refusal, as `/analytics/query` does. So a selection carrying both an unrecognised `dateRange` and one column asked twice is refused about the `dateRange` (`ANALYTICS_DATE_RANGE_UNRECOGNIZED` / 400) on both. The dry run answered the column refusal.
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
---
2+
'@objectstack/spec': patch
3+
'@objectstack/plugin-auth': patch
4+
'@object-ui/console': patch
5+
'@object-ui/i18n': patch
6+
---
7+
8+
feat(console): the workspace prompt also asks an administrator for a default currency that is still unset, offering the browser region's currency
9+
10+
Clause-②: yes (widening)
11+
Metadata-protocol: none
12+
13+
`@objectstack/spec/shared` gains `REGION_CURRENCY` and `currencyForLocale`, the checked-in CLDR region → currency table and its lookup. They move there from `@objectstack/plugin-auth`, which gives a new organization its creator's currency through them and no longer keeps its own copy. The table and the mapping are unchanged. Neither name was exported from the plugin-auth package entry, so nothing an importer of that package used moves.
14+
15+
The console's one-time workspace prompt (Setup → Localization's keys, asked once per administrator per workspace) now covers `localization.currency` too. While that key has no value on any rung, code-less amounts show as plain numbers; an administrator who may write the namespace is asked once, with the field pre-filled with the currency of the browser's first preferred language (`zh-CN` → CNY, shown as "人民币(CNY)" in Chinese). Confirm writes it through the Settings page's own `PUT /api/settings/localization`; "Not now" writes nothing. When the timezone is still the default as well, it is one dialog with both fields and one write. A browser language with no country region (`es-419`) offers no currency, and the prompt does not ask about it. No settings key, server-side dismissed flag or gate is added: the prompt keeps its existing per-device record, so an administrator already asked about the timezone is not asked again.
16+
17+
`@object-ui/i18n` gains eight `console.workspaceTimezonePrompt.*` strings in every built-in locale.
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
---
2+
'@objectstack/core': patch
3+
'@objectstack/objectql': patch
4+
'@objectstack/metadata-protocol': patch
5+
'@objectstack/plugin-hono-server': patch
6+
'@objectstack/plugin-security': patch
7+
---
8+
9+
fix: a disabled package's objects are no longer granted by `/auth/me/permissions`, and an action that launches into a disabled package is no longer served
10+
11+
Clause-②: yes (narrowing)
12+
Metadata-protocol: none
13+
Skills-docs: none — no file under `skills/**` describes what `/auth/me/permissions` answers for a disabled package, or which actions a disabled package withholds; every taught use of `current_user.can(object, verb)` and of `type: 'flow'` actions stays true.
14+
15+
<!-- adr-0087: not-required (no-migration-prescription) No metadata moves: no spec key, authorable spelling, export or stored shape is removed, renamed or re-shaped, so there is nothing for `objectstack migrate meta` to rewrite. What narrows is two served answers while a package is disabled, and re-enabling the package restores both with no restart; nobody's code or metadata changes. No exported declaration is removed or narrowed (one optional member and one function are added); every package publishes; no ADR-0087 id is named or touched. -->
16+
17+
**BREAKING** (a served-answer narrowing, only while a package is disabled), shipped as `patch`: a non-protocol narrowing takes `patch` and keeps this banner and its ADR-0087 disposition (no authored value is refused). A disabled package is hidden, and refused on the data plane (#28117 ruling A). Two faces still answered as if it were on.
18+
19+
**FROM.** With a package disabled, on `origin/main`:
20+
21+
- `GET /api/v1/auth/me/permissions` still granted the package's objects in its `objects` map (an explicit grant, a plain `'*'`'s coverage or a super-user seed), while `GET /api/v1/data/<object>` answered `404 OBJECT_PACKAGE_DISABLED`. So `current_user.can(<object>, verb)` stayed `true` in the console and in the server's own formulas (`ISecurityService.getEffectiveObjectPermissions`, the same map), and every action gated on it stayed drawn.
22+
- An action of an ENABLED package that launches into the disabled one was still served: on the object it is bound to (`GET /api/v1/meta/object/<name>`'s `actions`, which the console draws) and in `GET /api/v1/meta/action` (list and by name). That is a `type: 'flow'` action whose flow only the disabled package ships (its launch answered `404` "Flow '…' not found"), and an action with a param whose `objectOverride` object belongs to the disabled package (its dialog could not draw the param).
23+
- `GET /api/v1/meta/action` also still listed an enabled package's action bound by `objectName` to the disabled package's object, while that object's own read answered `404 OBJECT_PACKAGE_DISABLED`.
24+
25+
**TO.** While the package is disabled:
26+
27+
- **`@objectstack/core`**: `buildEffectiveObjectPermissions` takes an optional `isObjectPackageDisabled` accessor and, as its last step, leaves out every object it answers `true` for (the `'*'` entry stays). `registryObjectPackageDisabled(registry)` is that accessor over an engine registry: its `isObjectPackageDisabled`, the predicate the data plane asks before it refuses an object. An object the map does not mention answers `current_user.can()` `false`.
28+
- **`@objectstack/plugin-hono-server`** and **`@objectstack/plugin-security`**: `/auth/me/permissions` and `ISecurityService.getEffectiveObjectPermissions` both hand that accessor over, so the two answers stay byte-for-byte the same map.
29+
- **`@objectstack/objectql`**: `SchemaRegistry.isActionWithheldByDisabledPackage(action)` extends #24400's rule (a disabled package's bound actions are withdrawn) to an action bound by `objectName` to an object of a disabled package, and to an action that launches into one: a `type: 'flow'` target that only disabled packages ship (`isFlowOfDisabledPackage`), or a param `objectOverride` object of a disabled package. The served object read leaves such an action out of `actions`, whether it was attached as a bound action or merged into the object by `defineStack()`. The code layer (`getArtifactItem`) keeps what the package ships.
30+
- **`@objectstack/metadata-protocol`**: `GET /meta/action` (the effective served list) and `GET /meta/action/:name` withhold the same actions, through the registry's predicate. The execution list and the per-package list (the package export) keep them.
31+
32+
An action that only names such an object elsewhere (a URL, a label) is unchanged, and so is a flow some enabled package also ships. Re-enabling the package serves every grant and action again on the next request.
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
---
2+
'@object-ui/plugin-grid': patch
3+
'@object-ui/app-shell': patch
4+
---
5+
6+
fix(plugin-grid): the import wizard no longer demands a required field that carries a default
7+
8+
Clause-②: yes (widening)
9+
Metadata-protocol: none
10+
11+
The mapping step held Next with "required field(s) not mapped" for a required field left unmapped even when the field declares a `defaultValue`, static or an expression, which the create fills for a row that leaves the field out. A file without that column could not be imported. The step now treats such a field as satisfied, and leaves the value to the server. The same check spares the preview's blank cell in a mapped column of such a field, which the server also fills with the default. An option marked `default: true` counts as a default when no `defaultValue` is declared, as the create reads it. A required field with no default still blocks, and its blank cell is still marked. The wizard reads only whether a default is declared; it never evaluates one.
12+
13+
`ImportWizardProps['fields']` gains an optional `defaultValue` (passed through as the object schema declares it), and its option objects an optional `default`. The Console's two hosts of the wizard, the object list's Import and the AI chat's spreadsheet import, now pass the field's `defaultValue` through.
14+
15+
What to do: a host that builds the wizard's `fields` itself passes each field's `defaultValue` through to get the same behaviour; without it a defaulted required field is still demanded.

‎.claude/skills/pm-dispatch/references/lanes/triage.md‎

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,14 @@
22
见 triage-duties.md;本文是本席的岗位说明,现值状态恒在座位贴,⛔ 不迁入本文。
33

44
- 由维护者一句召唤到任一项目,默认同总监席项目;只写标签与审计评论,⛔ 无 PR、无认领。
5-
- 范围 = objectstack(`ui/` 在内)每张卡首触(业务理由与定级)与跨车道查重;应用仓无分诊席。
65
- 应用仓业务理由由该项目召唤的总监席复核;第三方应用的总监是其自身维护者。
76
- 每 fire 最旧优先;最旧未路由超 4h 的卡本轮先清。
87
- 补半状态前先确认无人在动,读后新现六态属他席即停手;⛔ 不加第二席、不改 fire 频率。
8+
- 推维护者仅限需其出手,通道照 SKILL.md;⛔ 无进度表与聊天轮报,余只进座位贴轮次记录。
9+
- 即推:①安全发现(机制只在会话给);②p0 点名升级后一轮仍无认领,或分诊已自派止血;
10+
- ③`main` 或合并队列红逾 2h 且无修复 PR 在飞。余下轮末合为一推,每轮至多一推:
11+
- ④人工地板待裁,点名决策卡与所需一字;⑤新发版阻塞、RC 复测回退、Version PR 只待其合;
12+
- ⑥车道不动:p1 卡在无席车道逾 4h;点名升级逾 6h 无答且回收需其一句;open PR 逾 6h 未更新,
13+
先敲其席(无信箱按名)过下轮无答且回收需其一句;待裁或被具名 `Blocked-by:`、`status:parked`
14+
卡、所骑栈阻者与信箱、Version PR 不算。⑦席位或子代理被拒、需人做的动作,⛔ 不代做。
15+
- 不推:定级、治半状态、解锁、契约复核(PASS/FAIL 归车道)、门铃答复、健康绿读数。

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

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,7 @@
77
- 查重缓存住席内:新会话全量拉,其后 `since` 增量;⛔ 不建分支、不共享、不依赖备份。
88
- 每日一 fire 跑两仓全量对账并归集日频职责;选层按 fire 时刻 ⛔ 不用计数器,简报写明层。
99
- 每条枚举比对返回数与 `totalCount`,不等 ⇒ 报 `sweep INCOMPLETE` 点名缺口,⛔ 永不报干净。
10-
- 复审:每轮先跑 `check-owed-reviews.mjs`(open PR 含 draft,读交接/认领/hold 行),欠审同轮认领后接。
11-
- 隔离子代理达档跑同形记录、署本席;本席也被配额拒 ⇒ PR 写一次留标,⛔ 永不降档审。
10+
- 复审每轮先跑 `check-owed-reviews.mjs`,照 contract-review.md 接;配额拒 ⇒ PR 留标,⛔ 不降档审。
1211
- 每轮比对自审记录 `Head-sha` 与现 head,越过即过期,纯重生成/只动散文面例外(判已提交树)。
1312
- 自审 FAIL 过期 ⇒ 同轮达档重审新 head,逐条复查 must-fix,delta commit 当改动审。
1413
- 自审 PASS 过期 ⇒ PR 记一条 PASS 不再管辖、欠 delta 复审,归本席或新交接行。
@@ -92,11 +91,9 @@
9291
- 不呈:实现细节、不升级类、记账类、p3 排序、CI 重跑、分支清理、patch 依赖、既裁执行。
9392
- 不呈四门同立:无产品可见行为变化、无契约变化、可回滚、有门禁兑底;呈裁卡注判据。
9493
- 例外一:`platform-readings.md` 增量抬上限到落地行数,免决策卡,记 `ruledRaises` 引常设裁决。
95-
- 例外二:一小时内两次红未触包的门禁,任一席位可先翻 report-only,三条硬条件缺一不可:
96-
- ①只翻 report-only,不删门不跳测;②同笔送待决策汇总入下批,附两红 run;③不同意即翻回。
94+
- 例外二:AGENTS.md 报告态翻转,须①不删门不跳测;②同笔附两红 run 入下批待决;③否即翻回。
9795
- 条件:席位验收评论逐条核实、去重计数(候选/落地/已有/拒收)、一事一行、不计重排。
9896
- 机械边界测试(条款②判据):改动扩大接受集或公开面 ⇒ 是;拉回已声明契约 ⇒ 否。
9997
- 回翻条款:实施中发现契约终究要动 ⇒ dev 停手,卡回决策箱,⛔ 永不静默重裁。
10098
- 请示纪律:方向性授权覆盖整条执行链一并做完,⛔ 不逐项回问。
101-
- 汇报只在里程碑、真阻塞、被问到时;中间状态与限流/重试类细节只进座位贴和触发器。
102-
- 人工地板项(发版、天花板、契约扩大)仍需明确字句,但攒批不逐项弹。
99+
- 推送维护者只照 `lanes/triage.md` 推送清单;中间状态与限流/重试细节只进座位贴和触发器。

0 commit comments

Comments
 (0)