Skip to content

Commit afd0fc7

Browse files
committed
Merge remote-tracking branch 'origin/main' into claude/project-thread-ybjm3h
2 parents 2b680ef + 601c773 commit afd0fc7

114 files changed

Lines changed: 3064 additions & 1533 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: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
---
2+
'@objectstack/objectql': patch
3+
'@objectstack/types': patch
4+
'@objectstack/rest': patch
5+
---
6+
7+
fix(objectql,types,rest)!: a database NOT NULL refusal on a declared field is the record validator's `ValidationError` at every door, named by the field's label
8+
9+
A field declared `storage: { notNull: true }` without `required` is ADR-0113's engine-populated column: the record validator judges `required` only, so a write with no value for it reaches the driver and the database refuses it. The engine let the driver's error out, and each HTTP door classified it from the driver's text its own way. For the same refused write, the runtime dispatcher's `/data` POST and PATCH answered `500 INTERNAL_ERROR`, the actions door answered `400 VALIDATION_ERROR` with the driver's text and `declaredCode: 'SQLITE_CONSTRAINT_NOTNULL'`, and `RestServer` answered `400 VALIDATION_FAILED` relabelled by a second object read on its own `POST` / `PATCH` only.
10+
11+
Clause-②: yes (narrowing: `@objectstack/types` adds the export `notNullViolationSite` and retires `notNullRefusalSite` and `relabelNotNullRefusal`; the HTTP doors' answer for this refusal moves to the record validator's envelope)
12+
Metadata-protocol: none
13+
14+
<!-- adr-0087: not-required (runtime-export-retired @objectstack/types#notNullRefusalSite, @objectstack/types#relabelNotNullRefusal) No metadata moves: no spec key, authorable spelling, object definition or stored shape is added, removed, renamed or re-shaped, so there is nothing for `objectstack migrate meta` to rewrite. What retires is two function exports of `@objectstack/types`' published entry, whose only consumer was `@objectstack/rest`'s door-side relabel, retired in this same change; no other consumer was found in this repository (its `ui/` and `examples/` included) or in hotcrm. The affected party is a TypeScript caller, and the compiler at that call site delivers the break. -->
15+
16+
**BREAKING** (an export retirement and a wire-answer change), shipped as `patch`: no metadata protocol kind moves.
17+
18+
- **`@objectstack/objectql`.** The write doors' driver exits (single-row and batch insert, the autonumber retry, by-id and predicate update) translate a driver NOT NULL refusal on a field the object's field map holds into the record validator's own `ValidationError` (`code: 'VALIDATION_FAILED'`), built by the validator's own builder with the validator's message context: one field error, `code: 'required'`, the field named by its label (translation bundle, then declared `label`, then API name) in the caller's locale, with the sentence the validator gives the same verb (`required` on insert, `required_cleared` on update). The driver's error rides `cause`, and the doors' log line still carries the database's own diagnosis. Left as the driver threw it: a column no field declares, a refusal the driver attributes to another table, and a NOT NULL code whose column the driver did not name. `required` and `storage.notNull` stay apart (ADR-0113 D1 / D2): no pre-write check reads `storage.notNull`.
19+
- **Every door answers it alike**, because every door already answers that class alike: the dispatcher `/data` POST and PATCH now answer `400 VALIDATION_FAILED` (was `500 INTERNAL_ERROR`), the actions door `400 VALIDATION_FAILED` with the field envelope (was `400 VALIDATION_ERROR` with the driver's text), and `RestServer`'s `POST` / `PATCH` and its `/data/:object/batch` rows answer the validator's envelope and sentence. Import rows, the public form submit and MCP write through the same engine doors and answer the same class through the same arms; they were not driven separately. On `RestServer` the body is now exactly the validator's `required` shape: `fields[0]` carries `label`, there is no `hint`, and a `PATCH` writing null reads the clear-out sentence.
20+
- **`@objectstack/types`.** New export `notNullViolationSite(error)`: the column (and table, where the dialect names it) of a driver's NOT NULL refusal, read from the error's codes (better-sqlite3 `SQLITE_CONSTRAINT_NOTNULL`; libsql `extendedCode` / `rawCode: 1299`; node-postgres `23502` with its `column` / `table` fields; mysql2 `ER_BAD_NULL_ERROR` / `errno: 1048`), then its text (all sql.js gives), then one step down its `cause` chain. An error whose code names another refusal is not read for NOT NULL text. `mapDataError`'s NOT NULL branch is unchanged, and answers the column no field declares.
21+
- **`@objectstack/rest`.** The `/data` create and update doors' NOT NULL relabel (`not-null-refusal-label.ts`) retires: every path it served is an engine write.
22+
23+
Migration, for a TypeScript caller of the retired exports:
24+
25+
- FROM `notNullRefusalSite(answer)` TO `notNullViolationSite(error)`: ask the driver's error, not `mapDataError`'s answer.
26+
- FROM `relabelNotNullRefusal(answer, { message, declaresNotNull })` TO nothing (no replacement): write through the engine, which answers a declared field's NOT NULL refusal as a labelled `ValidationError` itself.
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): the draft preview's failure pane is announced as an alert, drawn by the shared `DataErrorState`
6+
7+
Clause-②: no (one surface swaps its own block for the shared components; no exported type change. If the shared component needs a new prop, the thread reports first and the seat amends this line)
8+
Metadata-protocol: none
9+
10+
The pane a `?preview=draft` tree shows when it has nothing to draw (`PreviewDraftEmptyState`) now uses the shared view states from `@object-ui/components` instead of its own `Empty` block. When the draft overlay read fails, it is `DataErrorState` and is announced to assistive technology as `role="alert"`. When the app is not in the draft yet, or nothing is drafted, it is `DataEmptyState` with `role="status"`. Before, both were the same unlabelled node, so a screen reader said nothing when the preview failed to load. The text, the Retry button and the test ids are unchanged; the title and icon now use the shared components' smaller size.

‎.claude/skills/pm-dispatch/SKILL.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ PM 的工作是循环:选卡 → 认领 → 派发 → 收集 → 复核 → 报
6868
- 批 = 一个上下文里读完的 ≤5 张同族卡,是质量单位,⛔ 不是预算。
6969
- 班 = 一个会话的任期,只以交接或惰性回收结束。
7070
- 席位两形:Routine 席与项目席(会话是车队项目的线程);细则见 `references/seat-lifecycle.md`。
71-
- 项目席唤醒 = PR 订阅事件 + 每项目一个巡查 routine;⛔ 无自绑 cron、无 `send_later` 链。
71+
- 项目席唤醒 = PR 订阅 + 每项目一个自建自绑的巡查 routine,默认每小时;⛔ 无 `send_later` 链。
7272
- 探针先行:fire 的第一动作是一次最便宜的车道盘点查询,⛔ 在它之前不读任何长文本。
7373
- 队列空 + 无在飞 + 无待复核 + 决策箱无新答复 ⇒ 自退。
7474
- 分诊席跑直连会话、默认判断档;直连会话按召唤跑,⛔ 无自醒不常驻;裁决归总监席。

‎.claude/skills/pm-dispatch/references/project-forms.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
- 项目聊天里的长句(「本账户坐 X;Y 的 PR 由本账户复审」)是等价写法。
2929
- 协调者每次开场把指令行与座位贴对照:逐席按 `seat-post-protocol.md` 坐席或接管。
3030
- 坐席即把本账号写进 🟢 行、每席开一条席位线程;⛔ 无花名册文件。
31-
- 首次坐席建本项目的 routine:巡逻每 2–4 小时;总监席加每日摘要与每小时收件箱扫描。
31+
- 首次坐席自建本项目的 routine:巡逻默认每小时;总监席加每日摘要与每小时收件箱扫描。
3232
- 分诊席加每小时裸卡轮;总监与分诊同在一个项目时两者可共用一个 routine。
3333
- 并发上限是维护者在该项目定的姿态;⛔ 不是协议常量,本文不写数字。
3434

‎.claude/skills/pm-dispatch/references/seat-lifecycle.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,4 +93,4 @@
9393

9494
- 权威的墙信号是失败本身:撞墙报文里的重置时刻在那一刻可得、事前查不到,记下来。
9595
- 恢复 playbook 链既有规则:逐个探在飞云卡 → 直接验收兜底或 transcript 复活 → 照常跑轮。
96-
- 项目席巡查 routine 每 2–4 小时跑各车道待命项(含前提过时);撞墙记入存根,⛔ 无 cron 链。
96+
- 项目席巡查 routine 默认每小时跑各车道待命项(含前提过时);撞墙记入存根,⛔ 无 cron 链。

‎.claude/skills/pm-dispatch/references/seat-post-protocol.md‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -55,15 +55,15 @@
5555

5656
## 座位 Routine 创建
5757

58-
- 由维护者在 claude.ai 的 Routines UI 创建,凭据随 Routine 所挂 repo sources 走。
58+
- Routine 席由维护者在 claude.ai 的 Routines UI 创建,凭据随所挂 repo sources 走;项目席自建自绑。
5959
- Routines UI 并无 GitHub 连接器入口。
60-
- 会话内 `create_trigger` 的 Routine 拿不到 GitHub 工具、零产出;⛔ 不把它当座位 Routine 在跑。
60+
- `create_trigger` 开新会话的 Routine 拿不到 GitHub 工具、零产出;⛔ 不把它当座位 Routine 在跑。
6161
- 模型不能经 API 钉住,同样在 UI 钉;Routine 继承环境默认模型,环境默认变了它跟着变。
6262
- 创建后先手动 fire 一轮烟测,判据取 GitHub 上的产出:标签写入、审计评论、座位贴编辑。
6363
- ⛔ 不取会话看起来起来了;零产出即技术性失败。
6464
- 回滚 = `delete_trigger` + 清空座位登记 + 失败注记。
65-
- 档位按职责挑,⛔ 不按重要性挑;档位与 cron 是维护者在 UI 上的可调项。
66-
- 协议文本 ⛔ 不复制其当前值,座位贴才是现状。
65+
- 档位按职责挑,⛔ 不按重要性挑;Routine 席的档位与 cron 是维护者在 UI 上的可调项。
66+
- 项目席巡查默认每小时,放宽须有理由并写座位贴;协议 ⛔ 不复制当前值,座位贴即现状。
6767

6868
## Epic 车道收尾与僵尸回收
6969

0 commit comments

Comments
 (0)