diff --git a/.claude/skills/pm-dispatch/SKILL.md b/.claude/skills/pm-dispatch/SKILL.md index 8c4c6c9e662..b5acebdf4d9 100644 --- a/.claude/skills/pm-dispatch/SKILL.md +++ b/.claude/skills/pm-dispatch/SKILL.md @@ -39,7 +39,7 @@ PM 的工作是循环:选卡 → 认领 → 派发 → 收集 → 复核 → 报 ## 优先级 -- 优先序:维护者裁决 > `AGENTS.md` > 红线 > 核心条款 > 细则 > 座位判断。 +- 优先序:维护者裁决 > 北极星 > `AGENTS.md` > 红线 > 核心条款 > 细则 > 座位判断。 - 核心条款住 `references/core-rules.md`,是本文的子集;细则是本文其余各节与其它 references。 - 一条规则在本文与核心条款一处改动,另一处同 PR 同改。 - 红线与各节的禁止行都在四轴权衡之外,⛔ 不因更合理的理由被推翻。 @@ -251,6 +251,7 @@ PM 的工作是循环:选卡 → 认领 → 派发 → 收集 → 复核 → 报 | `domain:skills` | governed 面全量(含本文件;统一定义见「governed 面统一定义」行);非门禁的 `scripts/pm/**`(PM 循环工具);governed 面的治理执行文件:`.github/CODEOWNERS` + SUBJECT 是 governed 面本身的门禁/审计(现为 `scripts/pm/check-governed-merges.mjs`) | | `domain:spec` | `packages/spec` 整包:schema 形状、`contracts/**`、退役行为半边、strictness 台账;describe/JSDoc/墓碑散文/错误 guidance 与 alias 表;`packages/spec/scripts/**`、`packages/spec/docs/**` 及按锚定规则的例外归本域的工具链(域边界枚举与席内分派见 `references/lanes/spec.md`) | | `domain:cli` | `packages/cli`、`runtime`、`verify`、`packages/qa`、`types`、`packages/rest`、`packages/mcp`、`packages/observability`、`packages/client*`、`cloud-connection`、`create-objectstack`、`packages/adapters/*`、`plugin-hono-server`、`plugin-dev` | +| `domain:cloud` | 云服务旅程,停放(加 `status:parked`,sweep 免扫)待 cloud PM 迁移,本仓不派 | | (无固定归属,按落点分诊) | `packages/apps/*`、`packages/console`(dist 由脚本生成 ⛔ 不手改;UI 缺陷走 `repo:objectui`)、`examples/*`(归它演练的子系统)、`docs/audits/**` | - 表未覆盖的包首次分诊时归类并走 PR 更新本表;新增或退役 `domain:*` 必须同批改本表。 @@ -354,14 +355,13 @@ PM 的工作是循环:选卡 → 认领 → 派发 → 收集 → 复核 → 报 - 先修复:正文被 sanitizer 截断的卡不可派发,评论修复指令后跳过。 - 停摆指令判据必须比其它分类更硬(双读取),事后证伪同处公开作废。 - 决策箱勤务:落卡入箱时校验/补全四棱块与速读;存量卡低频子轮回填,语言按不变量。 -- 原生 issue 类型 Bug/Feature/Task 是分诊的固定产出。 -- 分诊席是 `type` 字段的唯一权威生产者;立单者可预填,分诊校正。 -- 判据:违背已声明契约 ⇒ `Bug`,扩大接受集/公开面 ⇒ `Feature`,其余 ⇒ `Task`。 +- `type`(Bug/Feature/Task)是分诊固定产出,分诊席唯一权威生产;立单者可预填,分诊校正。 +- 判据:违背已声明契约 ⇒ `Bug`,扩大接受集/公开面越出已声明 ⇒ `Feature`,其余 ⇒ `Task`。 - `Bug` 无具名落点或复现路径不入 `pm:queue`(标记补复现)。 - ⛔ 不回填存量 backlog 的 type;新卡即时打、存量卡下次碰到补。 -- 路由是分诊的技术判断,⛔ 永不升级哪个仓的问题。 +- 定级按 `docs/NORTH-STAR.md`「优先级」第 1、2 条;正文首行 `Path: P | <清单区> | none`。 +- 路由是分诊的技术判断,⛔ 永不升级哪个仓的问题;父单是协调节点,永不派发。 - 父单已有子结构的:父单队列标签即可,分诊逐个展开路由、补 `Blocked-by:` 排序。 -- 父单是协调节点,永不派发。 - 每张留一条英文审计评论(`Triage: lands in …; rationale: …`),可选带 `Size/model suggestion:` 行。 - 查重/shadow 检查先按文件/机制查本仓与姊妹仓 open 卡(含 `pm:dispatched`),再跟引用与关键词。 - 同文件同缺陷 = 同一发现,不分车道:证据搬到先卡,后卡关 `duplicate_of`,⛔ 不并排派发。 @@ -449,16 +449,16 @@ PM 的工作是循环:选卡 → 认领 → 派发 → 收集 → 复核 → 报 - 并行纪律四条(常规,非豁免):① 认领申报文件面到区域级,拿不准就串行。 - ② 开 PR 前合一次 main;③ 兄弟卡落地后再合一次;④ 冲突交合并队列仲裁,⛔ 不手动排序。 - 文件面不相交只保证文本可合并;跨文件语义耦合由队列 CI 逮住,⛔ 不读作不可能冲突。 -- 阻塞解除后给延后单重新定价:派发前一单时带必答项。 -- 必答项:你的改动让 #X 变简单、变难、变得不必要还是无影响。 +- 阻塞解除后延后单重定价:前一单派发词必答 #X 变简单、变难、不必要或无影响。 - 派发后一单前用该回答重读它的选项与成本,⛔ 不沿用立单时那份。 - 在飞卡衍生三分:不修它验收过不过;in-scope ⇒ 父卡 sub-issue,认领席自有、优先级继承。 - 该 sub-issue 带父卡域与优先级直接派发,唯一绕过分诊;sweep 事后扫,重复关 `duplicate`。 - 阻塞项无主 ⇒ 被挡席认领做掉,不限大小;在该卡走完整认领、尊重其热文件串行队。 - 阻塞项在飞 ⇒ 等:`pm:blocking` 在其车道排最前、等待者写该卡;p0/p1 优先级沿链传递。 +- 取卡前置 = `docs/NORTH-STAR.md`「优先级」第 3 条:产品仓开放 P0/P1 每次取卡现读。 - 取卡全序:`priority:p0` > `pm:blocking` > `target:` 板上项 > p1 > p2 > p3 > 无级;同级先 `Bug` 再卡龄。 - `pm:blocking` 级内先按解锁扇出(从 `Blocked-by:` 反向索引现算,⛔ 扇出数不落标签)。 -- 全序每级取既有信号现读/现算,零逐卡维护;优先是排序不是豁免;无级卡轮报记分诊缺口。 +- 全序每级取既有信号现读/现算,零逐卡维护;优先非豁免;无级/缺 `Path:` 轮报记分诊缺口。 - 解锁那一刻 PM 自己的判断最不可信:裁决收窄或关掉了那张卡是假设不是前提。 - 该假设以机制假设身份进派发令,被证伪就在同一张卡公开更正。 @@ -602,7 +602,7 @@ PM 的工作是循环:选卡 → 认领 → 派发 → 收集 → 复核 → 报 - 判决 ESCALATE:见 升级与决策 节。 - **ACCEPT 之后的路径分叉**:翻 ready / 挂 auto-merge / 入队前先取一次 PR 的路径面。 - 路径面用 `get_files` 取,⛔ 不看报告自述;动手之前先分,不是事后对照。 -- governed 面统一定义:`docs/adr/**` + `.claude/**`(全量,含 agents/hooks/settings)+ `skills/**`。 +- governed 面统一定义:`docs/adr/**` + `.claude/**`(全量)+ `skills/**` + `docs/NORTH-STAR.md`。 - governed 面同含 `AGENTS.md` + `CLAUDE.md`;`GOVERNED_REPOS` 各仓同治理待遇,执行席恒随落地仓车道。 - 路径面命中规则层 ⇒ ACCEPT 换终局四件套,混合 diff ⛔ 不按比例判;要拆让 dev 单独开 PR。 - ① 复核结论照常写在 issue 上;技能面 hunk 须由契约复审档的席复核,档外席先交 skills 席。 diff --git a/.claude/skills/pm-dispatch/references/core-rules.md b/.claude/skills/pm-dispatch/references/core-rules.md index 69fdb28b8f1..325f5c8ba4e 100644 --- a/.claude/skills/pm-dispatch/references/core-rules.md +++ b/.claude/skills/pm-dispatch/references/core-rules.md @@ -86,7 +86,7 @@ - 设计卡、契约形状提案、碰迁移形状或删已发布能力的进决策箱;无出处说明书脱节不进。 - 立卡限三类:可复现缺陷、契约违背、元数据陷阱;截断卡先发修复指令再跳过,不可派发。 - 三类边界:缺陷问错不问缺、文档同判;元数据须他人再作者化;引向更糟的警告在类外。 -- 类型字段由分诊席唯一生产,违背已声明契约是缺陷、扩大接受面是功能、其余是任务。 +- 类型字段由分诊席唯一生产,违背已声明契约是缺陷、扩出已声明是功能、其余是任务。 - 缺陷卡无具名落点或复现路径不入队列 ⛔ 不回填存量;每张卡留一条英文审计评论。 - 路由是分诊的技术判断 ⛔ 永不升级哪个仓的问题;父单是协调节点、永不派发。 - 发版板判据二元:不修它当前候选版能不能发 ⛔ 不做渐变,拆票时标签随工作走。 diff --git a/.claude/skills/pm-dispatch/references/lanes/skills.md b/.claude/skills/pm-dispatch/references/lanes/skills.md index 936e086114c..bcc4eedc71f 100644 --- a/.claude/skills/pm-dispatch/references/lanes/skills.md +++ b/.claude/skills/pm-dispatch/references/lanes/skills.md @@ -6,8 +6,7 @@ - 两个技能根:`.claude/skills/**`(含 pm-dispatch 本体)与 `skills/**`(发布目录,恒英文)。 - PM 循环工具与指令架构文件的归属见 SKILL.md 域车道表 `domain:skills` 行,⛔ 不另抄。 -- 受管面的治理执行文件:`.github/CODEOWNERS` 治理路由半边。 -- 同含 SUBJECT 是受管面本身的门禁与审计脚本。 +- 受管面治理执行文件:`.github/CODEOWNERS` 路由半边 + SUBJECT 是受管面本身的门禁/审计脚本。 - 全量判据在 SKILL.md 域车道表;受管面定义与两层分档见 SKILL.md 〈复核〉,⛔ 不另抄。 - QA 管理循环执行归本席;qa-run 记录是协议载体不是工作。 - 契约复核归派发席席内、决裁勤务归项目总监席(`director.md`);本席保留 skill 与治理文本。 @@ -22,6 +21,7 @@ - 棘轮逐行付账,⛔ re-wrap 筹行;砍点逐条核幸存,被砍内容若在别处无家,砍掉就是丢规则。 - 首触定级每轮;决策形状 ⇒ 决策箱带四棱块,⛔ 永不自裁。 - 唯一例外:本车道 finding 自分诊,全仓轮跳过。 +- 自分诊问北极星「仪器为车队服务」的那一问:答不出 ⇒ 即刻 p3 或不做,⛔ 不入队。 - 内部指令面中文,机器判据恒英文;认领前重读全线程;标签写 read-modify-write 加回读。 - QA 波次由维护者手动触发,⛔ 不自启。 diff --git a/.claude/skills/pm-dispatch/references/lanes/spec.md b/.claude/skills/pm-dispatch/references/lanes/spec.md index 35b32247c19..c6afe898db6 100644 --- a/.claude/skills/pm-dispatch/references/lanes/spec.md +++ b/.claude/skills/pm-dispatch/references/lanes/spec.md @@ -4,9 +4,9 @@ ## 范围 -- `packages/spec` 整包唯一契约,语义、文本、机器三面同席。 +- `packages/spec` 整包唯一契约,契约、辅助、机器三面同席。 - 含 schema 形状、`contracts/**`、退役行为半边、strictness 台账。 -- 含 describe 与 JSDoc、墓碑散文、错误 guidance 与 alias 表。 +- 含 describe/JSDoc、墓碑散文、错误 guidance、alias 表;其重生成的 references 产物归源 PR。 - 含 `packages/spec/scripts/**`、`packages/spec/docs/**`。 - 同含围着 spec 契约转的工具链:门禁、生成器、lint 规则、报错散文、references 管线。 - 一般开发工具面留 devx;`packages/spec` 恒归本席,不论谁需要它。 @@ -14,23 +14,23 @@ ## 席内分派参考 -- 语义与文本按合法元数据集合变没变分:改动前过校验的输入改动后同判 ⇒ 文本面。 -- 文本面的 changeset 恒 patch,默认 sweep-first;否则语义面。 -- 放宽接受集或扩大公开面的卡,不论多小,即条款②;收窄仍是语义面,不触条款②。 +- 契约面 = 「改动前后同一份输入的接受/拒绝结果变了」;判定逐字节不变 ⇒ 辅助面。 +- 契约面五形任一命中:收紧、放宽、公开导出面增删、declared ≠ enforced、退役。 +- 辅助面的 changeset 恒 patch,默认 sweep-first;第二刀问「它误导了 AI 吗」。 +- 误导 ⇒ P2 保留;不误导 ⇒ 关 not planned,或搭下一个触碰它的 PR 的 Acceptance notes。 +- 放宽接受集或扩大公开面的卡,不论多小,即条款②;收窄仍是契约面,不触条款②。 - 收窄不触发条款②,但按 `yes` 申报恒不是错误;⛔ 个案裁决不改本行。 -- 机器面改围契约的机器,与文本面不交,⛔ 不碰 `packages/spec/src/**/*.zod.ts` 与 strictness 台账。 -- 产物随源走:describe 与 JSDoc 改动重生成的 references 产物归触发它的源 PR。 +- 机器面改围契约的仪器,与辅助面不交,⛔ 不碰 `packages/spec/src/**/*.zod.ts` 与 strictness 台账。 +- 机器面卡只按北极星「仪器为车队服务」的那一问评级。 - 改元数据格式或接受面的照旧归 `domain:spec`;`/meta` 路由本体在 `packages/rest` 归 `domain:cli`。 -- 拿不准 FLAG 回分诊,⛔ 不自设第二套判据。 -- 档位随面走的现行表在 SKILL.md 模型分档,单源,⛔ 不另抄。 +- 拿不准 FLAG 回分诊,⛔ 不自设判据;档位随面走,表在 SKILL.md 模型分档,⛔ 不另抄。 ## 常设承诺 - findings 首触定级归分诊席,本席只供证据。 - 门禁强制的跨车道 ledger 追加整类预批(`error-code-ledger.zod.ts`),三条全中即免本席签字。 -- ①:码的存在已在归属卡裁过。 -- ②:纯增量 —— 不动 schema 形状、既有条目与 ledger 机制,只落追加方自己的包分节。 -- ③:兜底不变 —— 条款②路径肢照命中,入队前仍过契约复核。 +- ①:码的存在已在归属卡裁过;②:兜底不变,条款②路径肢照命中,入队前仍过契约复核。 +- ③:纯增量 —— 不动 schema 形状、既有条目与 ledger 机制,只落追加方自己的包分节。 - 出类(新 ledger 字段、重构、别道条目、准入或拒收语义)⇒ 本席卡,不论谁需要它。 - 分支信息测试(原文不译):Does this defect give a consumer a branch it could act on differently? No ⇒ widen the existing member's comment/message; yes ⇒ new code under the pre-approved class. diff --git a/AGENTS.md b/AGENTS.md index f781c23df02..8de80cf4cf4 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -4,6 +4,7 @@ Primary AI instruction file for this repo — and the human contributors' source Read natively by Claude Code, GitHub Copilot (coding agent + CLI), and other agents — no separate `.github/copilot-instructions.md` mirror needed. When any other instruction file in this repo (including `.claude/skills/**`) conflicts with this one, **AGENTS.md wins**. +`docs/NORTH-STAR.md` (先做什么: goals, priority) outranks it; `content/docs/concepts/north-star.mdx` = architecture. > **v5.0 breaking rename: `project` → `environment`** everywhere (CLI `-e`, `/api/v1/environments/:id`, header `X-Environment-Id`, `OS_ENVIRONMENT_ID`, DB column `environment_id` [control-plane tables; on the metadata tables since deprecated in favour of `organization_id`, ADR-0006 v4]). No aliases. See ADR-0006. "Project" now only means the npm/monorepo sense. @@ -19,7 +20,6 @@ script's own header is the authority on detail. ## Communication 语言规则分两件事:**和维护者说话用什么语言**,与**留在 GitHub 上的产物用什么语言**。 -一条规则一个通道,互不重叠。 - **在 Claude Code 中与维护者对话一律使用中文**(对话回复、轮次报告等聊天通道里的内容)。 - **GitHub 产物一律使用英文**:issue 与 PR 的标题、正文、评论。 @@ -255,8 +255,8 @@ localStorage / auth gotchas. 14. **⛔ A governed surface is confirmed and merged by the maintainer, by hand — or confirmed by an authorized approval and then landed by the owning seat; before that approval no AI seat merges, queues, or arms auto-merge on a PR whose diff touches one.** The governed surfaces are `docs/adr/**`, `.claude/**` (agents, hooks and settings — - not only skills), `skills/**`, `AGENTS.md` and `CLAUDE.md` — the file you are reading is one — and a mixed diff - is governed whole on a single path hit. The register is the `GOVERNED_SURFACES` table in + not only skills), `skills/**`, `AGENTS.md`, `CLAUDE.md` and `docs/NORTH-STAR.md` — the file you are reading is + one — and a mixed diff is governed whole on a single path hit. The register is the `GOVERNED_SURFACES` table in `scripts/pm/check-governed-merges.mjs`; adding a surface is an edit *there*, never here, and `pnpm check:pm-governed-prose` reds per-PR when this paragraph names fewer surfaces than the register — or more. When it reds, name the surface here. diff --git a/docs/adr/PRIORITIZATION.md b/docs/adr/PRIORITIZATION.md index ca5e0923148..22dc06e2fce 100644 --- a/docs/adr/PRIORITIZATION.md +++ b/docs/adr/PRIORITIZATION.md @@ -1,146 +1,5 @@ # ADR Prioritization Review -> ⚠️ **STALE (noted 2026-07-16):** this review predates ADR-0050 onward — the directory now -> reaches ADR-0097, so everything from 0050 up is outside its scope, and several statuses it -> records for 0001–0049 have since moved. Treat it as a historical snapshot, not current -> state. The `Status:` header of each ADR file (kept current per the hygiene rule below) is -> the authority; this document is retained for its method and its ranked-plan rationale. -> -> **Status-hygiene rule (adopted 2026-07-16):** when a PR lands the implementation of an ADR, -> the same PR (or an immediate follow-up) must flip that ADR's `Status:` line to -> `Accepted — implemented` with one line of evidence (key file + test). An ADR left -> `Proposed` after its code ships misleads every later reader — this is the same -> no-silently-stale discipline as ADR-0078, applied to the ADRs themselves. +Superseded: what to do first is set by `docs/NORTH-STAR.md` (「优先级」); this review is retired. -> **Date:** 2026-06-12 -> **Scope:** All 49 ADRs in `docs/adr/`, cross-checked against actual code on `main`. -> **Method:** Every unfinished ADR was read in full and its `Status:` header was -> verified against the shipped code (git log + source grep), not taken at face -> value. This document records the calibrated status and a ranked next-step plan. - ---- - -## 0. Headline finding — the `Status:` headers are systematically stale - -The single most important result of this sweep: a large fraction of ADRs marked -**Proposed** or **Draft** are in fact **substantially or fully shipped** on the -framework (backend) side. What remains for most of them is the **ObjectUI** -surface (sibling `../objectui` repo) or **cloud** control-plane work — neither of -which is owned by this repo. - -Consequence: prioritizing off the headers alone overstates the remaining -framework workload and hides where the real gaps are. The headers should be -refreshed (see §4). - ---- - -## 1. Status calibration — header vs. real (framework side) - -| ADR | Header | Real framework status | Remaining (and where) | -|---|---|---|---| -| 0034 transactional writes | Proposed | **Shipped** (v8.0.0 — ambient `AsyncLocalStorage` tx, batch `$ref`) | UI wiring (objectui) | -| 0032 unified expression layer | Proposed | **Shipped** (CEL, no silent-swallow, build-time validate) | designer builders (objectui) | -| 0039 concurrent durable pause | Proposed | Track A **shipped** (incl. A2 `map` node) | Track B deferred by design | -| 0042 approval SLA escalation | Proposed | **Shipped** (jobs-backed scanner, `system:sla`) | — | -| 0043 actionable approval links | Proposed | **Shipped** (single-use tokens, GET-confirm/POST-exec) | v1 non-goals only | -| 0044 approval send-back | Proposed | **Shipped** (`returned` status, typed back-edges) | designer (objectui) | -| 0041 flow trigger family | Proposed | **Shipped** (trigger-api HMAC + queue) | rename deprecation stubs (S) | -| 0015 datasource federation | Proposed | **Shipped** (3 gates + REST + CLI) | Studio UI, extra drivers | -| 0023 OpenAPI→connector | Proposed | **Shipped** (library) | CLI, examples | -| 0024 MCP connectors | Proposed | **Shipped** (library) | examples | -| 0036 app = REST + MCP | Proposed | **Shipped** framework (api-key, `/api/v1/mcp`) | cloud Integrations page | -| 0007 settings | Draft | **Shipped** backend (sys_setting, resolver, 7 manifests) | entire UI (objectui) | -| 0033 AI authoring | Accepted | A–C **shipped** | Phase D = enterprise/cloud | -| 0019 app = consumer unit | Proposed | **Shipped** (schema-enforced) | Console fills field | -| 0029 kernel object ownership | Proposed | **Substantially shipped** (K0/K1/K2/D7) | K3 (waits on 0030/storage) + K4 cleanup | - -> Note on 0029: `sys` being a **shared** namespace with single-owner-per-object -> enforcement (not a reserved namespace) is the **intended** K0 design, not a gap. - ---- - -## 2. Genuinely unbuilt framework gaps (the real candidate work) - -| ADR | What | Real status | Effort | Value | -|---|---|---|---|---| -| **0025 install side** | plugin package install / registry / consent | build/sign/publish shipped; **install half missing** | L | high | -| **0027 authoring lifecycle** | openDraft→stage→diff→publish(seal)→promote→rollback orchestrator | package absent; only contract stubs | L | high | -| **0013 bidirectional messaging** | Slack inbound receiver / sessions / multi-account | **~zero code** (messaging is outbound-only) | L | high | -| **0010-nl-to-flow** | natural language → runnable Flow | **not started** (substrate ready) | L | high | -| **0028 namespace isolation** | `(namespace,type,name)` identity + physical-name derivation | **still the old prefix model** | L | med | -| **0026 client-UI plugin dist** | `runtime:'ui'` variant + iframe sandbox | unbuilt, **blocked on 0025** | L | med | -| 0046 package docs as metadata | `src/docs` → `manifest.docs` | unbuilt, but P0/P1 cheap | S–M | med | -| 0010 protection L4 / unlock | `frozenPaths` evaluator + unlock RBAC | L3 + audit shipped; **no escape hatch** | M | med | -| 0017 view Phase 5 | view RLS backend + designer | RLS still **client-enforced**; designer in objectui | S (backend) | med | -| 0063/0064 (supersedes 0040) | blueprint object-count scale gate | tool-scoping **shipped** (ADR-0064, #2181 — tools = skills' tools, no global fall-through; affinity is a load error); blueprint scale gate still **not implemented** | S | med | -| 0029 K4 | remove migration-era empty barrels | cleanup only | S | low-med | - ---- - -## 3. Recommended next-step priority - -### P0 — GA blockers (not ADRs, but they gate launch) -From `docs/launch-readiness.md`: **P0-5** (realtime/feed are in-memory only, no -cluster coordination) and **P1-2** (execution logs / job runs / event log grow -unbounded). Decide single-instance vs HA and land retention/coordination -**before** any new feature ADR. These outrank everything below for GA. - -### P1 — Complete the distribution loop: `0025 install` + `0027 lifecycle` -Recent momentum is almost entirely in distribution (package-install command, -local-manifest-source, marketplace-nav, cloud-connection). The build/publish half -already shipped; the install / registry / promotion half is the natural join, and -it is the keystone that unblocks **0026** and subsumes **0016**'s deferred cloud -publish. Highest value-to-effort coherent line. - -### P1.5 — Distribution safety prerequisites -- **0029 K4** finish (small): drop the empty re-export barrels so the - plugin-owned architecture is clean before third-party packages arrive. -- **0028 namespace isolation** (large): its hard prerequisite (0029) is now - largely satisfied, so it is **no longer blocked**. Needed before opening up - multi-package third-party co-install, otherwise silent table-name collisions. - -### P2 — Outward differentiator: `0013 Slack bidirectional messaging` -The only one of the five integration ADRs with essentially zero code, and the -only outward-facing headline gap ("operate ObjectStack from Slack"). ADR-0022 -already routes the human-notification story into it. Promote to P1 if -conversational Slack is a near-term product goal. - -### P3 — Cheap, high-leverage fill-ins (interleave) -- **0046 package docs** (S) — directly feeds AI grounding. -- **0010 L4 + unlock escape hatch** (M) — without it a lock can never be lifted. -- **0017 view RLS backend** + **0040 tool-scoping enforcement** — both are - security-shaped (today: client-enforced / advisory); worth elevating near GA. - -### P4 — Explicitly deferred -0039 Track B (token-tree rewrite, demand-gated), 0031 BPMN XML plugin, 0026 -(waits on 0025), 0010-nl-to-flow (high "wow" but pure net-new — after the -distribution loop). - ---- - -## 4. Status-header corrections to apply - -These ADR headers should be updated to reflect shipped reality (framework side). -Listed here rather than edited in place, since changing an ADR's recorded status -is a governance act best ratified deliberately. - -| ADR | Current header | Suggested | -|---|---|---| -| 0007 | Draft | Accepted — backend implemented; UI pending (objectui) | -| 0032 | Proposed | Accepted — implemented (designer pending, objectui) | -| 0034 | Proposed | Accepted — implemented (v8.0.0) | -| 0041 | Proposed | Accepted — Tier 1 implemented | -| 0042 | Proposed | Accepted — implemented | -| 0043 | Proposed | Accepted — implemented | -| 0044 | Proposed | Accepted — engine + model implemented (designer pending) | -| 0015 | Proposed | Accepted — backend/REST/CLI implemented (UI + drivers pending) | -| 0023 | Proposed | Accepted — library implemented (CLI/examples pending) | -| 0024 | Proposed | Accepted — library implemented (examples pending) | -| 0036 | Proposed | Accepted — framework implemented (cloud surfacing pending) | -| 0039 | Proposed | Accepted — Track A implemented; Track B deferred | -| 0029 | Proposed | Accepted — K0/K1/K2/D7 implemented; K3/K4 remaining | - ---- - -_Generated from a five-cluster ADR sweep; file/commit evidence captured in the -review session. Treat this as a planning input, not a frozen contract._ +One rule this file adopted stays in force until it has another home (ADR-0110 cites it as the PRIORITIZATION status-hygiene rule): a PR that lands an ADR's implementation flips that ADR's `Status:` line to `Accepted — implemented` with one line of evidence (key file + test). diff --git a/scripts/pm/check-governed-merges.mjs b/scripts/pm/check-governed-merges.mjs index 20b77f92ee1..9cef48e0cb6 100644 --- a/scripts/pm/check-governed-merges.mjs +++ b/scripts/pm/check-governed-merges.mjs @@ -861,7 +861,9 @@ export const EXIT_TEST_NOT_GOVERNED = 0; * The governed surfaces, in report order — the 2026-08-18 unified definition * (see header). `prefix` entries match path prefixes; `exact` entries match * one repo-relative path byte-for-byte (the repo-ROOT instruction files, not - * `examples/AGENTS.md`, not template copies). One path hit governs a whole + * `examples/AGENTS.md`, not template copies — and `docs/NORTH-STAR.md`, the + * maintainer's North Star, joined 2026-09-18 on his word as the law above + * `AGENTS.md`; the PM skill cites it by section). One path hit governs a whole * PR — 「混合 diff 一条命中即整 PR 分叉」; proportion is never a question. * The register is repo-agnostic: it applies in all of `GOVERNED_REPOS`. */ @@ -871,6 +873,7 @@ export const GOVERNED_SURFACES = Object.freeze([ Object.freeze({ id: 'skills-catalog', prefix: 'skills/', glob: 'skills/**', what: 'the published skills catalog' }), Object.freeze({ id: 'agents-md', exact: 'AGENTS.md', glob: 'AGENTS.md', what: 'the repo-root agent instruction file' }), Object.freeze({ id: 'claude-md', exact: 'CLAUDE.md', glob: 'CLAUDE.md', what: 'the repo-root Claude instruction file' }), + Object.freeze({ id: 'north-star', exact: 'docs/NORTH-STAR.md', glob: 'docs/NORTH-STAR.md', what: "the maintainer's North Star — the law above AGENTS.md" }), ]); /** @@ -881,10 +884,12 @@ export const GOVERNED_SURFACES = Object.freeze([ * own source, and "looks like a path" there means "carries a separator". The * three `prefix` rows above have one and reach dispatch-gates already — the * `skills/**` row is one of the three specimens that motivated reading a hint - * AS WRITTEN. The two `exact` rows do not: a repo-root FILE carries no - * separator, so an `AGENTS.md` or `CLAUDE.md` card derived this gate not at all - * while the same card is GOVERNED by it (draft-only PR, maintainer merge) — - * the loudest possible thing to learn late. + * AS WRITTEN. The two repo-ROOT `exact` rows do not: a repo-root FILE carries + * no separator, so an `AGENTS.md` or `CLAUDE.md` card derived this gate not at + * all while the same card is GOVERNED by it (draft-only PR, maintainer merge) + * — the loudest possible thing to learn late. The `docs/NORTH-STAR.md` row is + * `exact` WITH a separator: it reaches dispatch-gates as written and declares + * no hint (the self-test pins that an exact row with a separator has none). * * `/**` is the form that reaches one: the extractor accepts it, and * `collapseHint` reduces it back to that single path. `examples/AGENTS.md` and @@ -3223,15 +3228,16 @@ async function selfTest() { // ── the governed predicate: the 2026-08-18 unified list, exactly ────────── battery('the governed predicate: the 2026-08-18 unified list, exactly'); const ids = (paths) => governedPathsIn(paths).map((s) => s.id); - assert('all-five-surfaces-declared-in-order', GOVERNED_SURFACES.map((s) => s.id).join(',') === 'adr,claude-tree,skills-catalog,agents-md,claude-md', GOVERNED_SURFACES.map((s) => s.id).join(',')); + assert('all-six-surfaces-declared-in-order', GOVERNED_SURFACES.map((s) => s.id).join(',') === 'adr,claude-tree,skills-catalog,agents-md,claude-md,north-star', GOVERNED_SURFACES.map((s) => s.id).join(',')); assert('adr-prefix', ids(['docs/adr/0001-x.md']).join() === 'adr'); assert('whole-claude-tree-not-only-skills', ids(['.claude/hooks/guard-main-checkout.sh', '.claude/agents/os-dev.md', '.claude/settings.json']).join() === 'claude-tree'); assert('published-skills-catalog-is-governed', ids(['skills/objectstack-ui/SKILL.md']).join() === 'skills-catalog'); assert('root-agents-md-exact', ids(['AGENTS.md']).join() === 'agents-md'); assert('root-claude-md-exact', ids(['CLAUDE.md']).join() === 'claude-md'); + assert('north-star-exact', ids(['docs/NORTH-STAR.md']).join() === 'north-star'); // Near misses, each load-bearing: prefixes need their trailing slash; the // exact entries are the repo-root files only (see header). - assert('near-misses-stay-out', ids(['docs/adrs/z.md', '.claude-x/y.md', 'skillsx/a.md', 'examples/AGENTS.md', 'packages/create-objectstack/src/templates/AGENTS.md', 'apps/CLAUDE.md.bak']).length === 0, JSON.stringify(ids(['examples/AGENTS.md']))); + assert('near-misses-stay-out', ids(['docs/adrs/z.md', '.claude-x/y.md', 'skillsx/a.md', 'examples/AGENTS.md', 'packages/create-objectstack/src/templates/AGENTS.md', 'apps/CLAUDE.md.bak', 'docs/north-star.md', 'docs/NORTH-STAR.md.bak', 'examples/docs/NORTH-STAR.md']).length === 0, JSON.stringify(ids(['examples/AGENTS.md']))); assert('a-mixed-diff-groups-by-surface', ids(['docs/adr/0001.md', 'AGENTS.md', 'package.json']).join() === 'adr,agents-md'); // ── the dispatch-gates declaration (#9979) ─────────────────────────────── @@ -3241,7 +3247,10 @@ async function selfTest() { // shows up only as a dev dispatched on a root-file card who is not told that // the card is GOVERNED. battery('the dispatch-gates declaration (#9979)'); - const rootExacts = GOVERNED_SURFACES.filter((s) => s.exact).map((s) => s.exact); + // Only the SEPARATOR-LESS exact rows need a hint; an exact row that carries a + // separator (`docs/NORTH-STAR.md`) reaches dispatch-gates as written. + const rootExacts = GOVERNED_SURFACES.filter((s) => s.exact && !s.exact.includes('/')).map((s) => s.exact); + assert('an-exact-row-with-a-separator-declares-no-hint', GOVERNED_SURFACES.filter((s) => s.exact && s.exact.includes('/')).every((s) => !ROOT_FILE_WATCH_HINTS.includes(`${s.exact}/**`)) && GOVERNED_SURFACES.some((s) => s.exact === 'docs/NORTH-STAR.md')); assert('every-exact-root-row-declares-a-watch-hint', rootExacts.every((f) => ROOT_FILE_WATCH_HINTS.includes(`${f}/**`)), JSON.stringify(rootExacts)); assert('the-declaration-names-no-file-this-register-does-not-govern', ROOT_FILE_WATCH_HINTS.every((h) => rootExacts.includes(h.replace(/\/\*+$/, ''))), JSON.stringify(ROOT_FILE_WATCH_HINTS)); assert('both-root-instruction-files-are-declared', ROOT_FILE_WATCH_HINTS.join(',') === 'AGENTS.md/**,CLAUDE.md/**', ROOT_FILE_WATCH_HINTS.join(',')); @@ -4581,13 +4590,13 @@ async function selfTest() { const liftedHead = renderTestVerdict(liftedTest).split('\n')[0]; assert( '⭐ the-test-head-no-longer-reports-a-post-lift-zero-as-if-nothing-had-hit-the-register', - liftedHead === 'governed-surface predicate: 0 of 4 path(s) hit the register after 1 generated-artifact lift(s) (5 surfaces, repo-agnostic).', + liftedHead === 'governed-surface predicate: 0 of 4 path(s) hit the register after 1 generated-artifact lift(s) (6 surfaces, repo-agnostic).', liftedHead, ); const plainHead = renderTestVerdict(testVerdict(['packages/spec/src/ui/view.zod.ts'])).split('\n')[0]; assert( 'and-a-verdict-with-no-lift-keeps-its-head-line-byte-for-byte', - plainHead === 'governed-surface predicate: 0 of 1 path(s) hit the register (5 surfaces, repo-agnostic).', + plainHead === 'governed-surface predicate: 0 of 1 path(s) hit the register (6 surfaces, repo-agnostic).', plainHead, ); diff --git a/scripts/pm/check-governed-prose.mjs b/scripts/pm/check-governed-prose.mjs index 5575ba2476f..7b6f26d8d20 100644 --- a/scripts/pm/check-governed-prose.mjs +++ b/scripts/pm/check-governed-prose.mjs @@ -46,7 +46,7 @@ * correct prose. Recognising a governed prefix inside free bilingual prose is * the intractability #9491 hit and cut, and this check does not re-attempt it: * it inverts the assertion instead — the REGISTER is the thing enumerated, the - * prose is only searched. Containment covers all five entries; over-claim + * prose is only searched. Containment covers all six entries; over-claim * covers the three glob-shaped ones. That boundary is the honest claim, and it * is stated here rather than implied by the code. * diff --git a/scripts/pm/ensure-pm-labels.sh b/scripts/pm/ensure-pm-labels.sh index df3cd1d67be..9be245e956c 100644 --- a/scripts/pm/ensure-pm-labels.sh +++ b/scripts/pm/ensure-pm-labels.sh @@ -422,6 +422,26 @@ for D in engine services devx spec cli skills; do gh label create "domain:$D" -R objectstack-ai/objectstack -c bfd4f2 -d "Domain lane — seat card indexed by label:pm:seat" 2>/dev/null || true done +# domain:cloud is a PARKING label, not a lane: no seat, never dispatched in this +# repo. Cloud-service journeys found in objectstack / objectui keep it until the +# cloud PM migrates them — maintainer ruling 2026-09-18, verbatim: 「云服务旅程 +# 混在 objectstack / objectui 里的 ⇒保留 domain:cloud 标签 等 cloud 项目经理迁移」. +# The object already exists in objectstack (auto-created, so `--reconcile` is +# what aligns it) and is absent in objectui; the roster makes both. SKILL.md's +# domain table carries the matching row (北极星「现在不做」). +gh label create domain:cloud -R objectstack-ai/objectstack -c bfd4f2 -d "Cloud-service journey parked for the cloud PM to migrate — not dispatched in this repo (云服务旅程,本仓不派)" 2>/dev/null || true +gh label create domain:cloud -R objectstack-ai/objectui -c bfd4f2 -d "Cloud-service journey parked for the cloud PM to migrate — not dispatched from objectui (云服务旅程,本仓不派)" 2>/dev/null || true +# status:parked is the other half of parking: the backlog sweep's disjunct ③ +# (有 domain:* 无 pm-state) and check-half-states.mjs's H13 read it as the +# exemption (H13_EXEMPT_LABELS; SKILL.md 排除 `status:parked`), so a card that +# carries domain:cloud WITHOUT it is listed and "cured" with a pm state every +# fire, against the ruling above. The object exists in objectstack (auto-created) +# and was absent in objectui; the roster makes both. Colour matches `tracking`, +# the other sweep-exempt label. Descriptions differ per repo on purpose: the +# check:pm-label-desc-cap dry run wants one distinct description per parsed line. +gh label create status:parked -R objectstack-ai/objectstack -c cfd3d7 -d "Parked — exempt from the PM sweep and half-state patrol until its owner migrates it (e.g. cloud PM)" 2>/dev/null || true +gh label create status:parked -R objectstack-ai/objectui -c cfd3d7 -d "Parked in objectui — exempt from the PM sweep until the cloud PM migrates it (with domain:cloud)" 2>/dev/null || true + # objectui workload streams — maintainer rulings 2026-08-21, quoted verbatim: # 「B:两车道」→「现在本身就有 domain:devx」→「不要搞出那么多车道名称」→「也有 # domain:spec」「其他就是 domain:ui ?」, naming finalized 「按 domain:ui 定稿」.