@thincoder/core 0.10.11 → 0.10.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +8 -0
- package/advisor/messages.mjs +1 -1
- package/advisor/project-context.mjs +2 -2
- package/agent-tools/batch-gate.mjs +65 -49
- package/agent-tools/batch-lifecycle.mjs +66 -9
- package/agent-tools/batch-paths.mjs +10 -8
- package/agent-tools/design-slots.mjs +72 -12
- package/agent-tools/design-token.mjs +18 -2
- package/agent-tools/manifest.mjs +1 -1
- package/agent-tools/review-facts.mjs +1 -1
- package/ledger-cmd.mjs +39 -37
- package/ledger-db.mjs +60 -59
- package/ledger-tools.mjs +60 -23
- package/ledger.mjs +12 -10
- package/manifest-discovery.mjs +41 -26
- package/manifest.mjs +17 -16
- package/model-specs.mjs +11 -13
- package/package.json +1 -1
- package/prompts/advisor-design.md +4 -3
- package/prompts/common.md +11 -1
- package/prompts/discipline-engineering.md +16 -7
- package/prompts/discipline-normal.md +2 -1
- package/prompts/persona-coder.md +8 -1
- package/prompts/persona-eng-coder.md +8 -0
- package/prompts/persona-eng-designer.md +11 -1
- package/prompts/persona-engineering.md +21 -11
- package/prompts/persona-explore.md +6 -0
- package/prompts/persona-normal.md +6 -0
- package/prompts/persona-plan.md +6 -0
- package/session-slot-write.mjs +21 -1
- package/session-slots-manifest.mjs +21 -4
- package/token-ttl.mjs +68 -4
- package/tool-docs/wait_for.md +15 -6
package/ledger.mjs
CHANGED
|
@@ -44,11 +44,13 @@ export function entryTitle(text) {
|
|
|
44
44
|
}
|
|
45
45
|
|
|
46
46
|
/** 向上(含自身)最近的**已注册**项目根 → {root, ledger} / null(F4——CLI 锚 = cwd)。
|
|
47
|
-
* 薄委托 `resolveLedgerRoot(anchor,
|
|
48
|
-
*
|
|
47
|
+
* 薄委托 `resolveLedgerRoot(anchor, anchor)`(设计档 §3.8——上溯以会话锚为界):锚即本面的会话锚 ⇒
|
|
48
|
+
* 界 = 锚自身(不越界探外层项目,与工具面同判);`root` = 推导所得项目根(非锚);
|
|
49
|
+
* 多根工作区锚 ⇒ `null` ⇒ 族发现按工作区根形(族求和——§7.2 / AC-M2-18 / AC-M2-19)。
|
|
50
|
+
* `ledgerDbPath` 同一界(同一笔读数不能两界)。 */
|
|
49
51
|
export function findProject(anchor) {
|
|
50
|
-
const derived = resolveLedgerRoot(anchor,
|
|
51
|
-
return derived ? { root: derived.root, ledger: ledgerDbPath(derived.root) } : null
|
|
52
|
+
const derived = resolveLedgerRoot(anchor, anchor)
|
|
53
|
+
return derived ? { root: derived.root, ledger: ledgerDbPath(derived.root, derived.root) } : null
|
|
52
54
|
}
|
|
53
55
|
|
|
54
56
|
/** 项目族发现:{current, projects}——current = `findProject`(**祖先支**:容器 ∥ 工作区锚 ⇒ `null` ⇒ 按
|
|
@@ -70,16 +72,16 @@ export function discoverFamily(anchor) {
|
|
|
70
72
|
* `now`/`days` = 注入面(确定性用例——替代 v1 ageOf git 注入面)。
|
|
71
73
|
* **`days` 只作用于展示面 `aged`**(本函数局部阈值);`overdue`(出口态)恒按核常量 `AGING_DAYS`
|
|
72
74
|
* (`overdueOf` 单源)——故 `days` 调小时 `aged` 会先于 `overdue` 涨(两数口径不同,非矛盾)。
|
|
73
|
-
* **根推导**(设计档 §3.8):`root` / `name` / `ledger` = `resolveLedgerRoot(anchor)`
|
|
74
|
-
*
|
|
75
|
-
*
|
|
75
|
+
* **根推导**(设计档 §3.8):`root` / `name` / `ledger` = `resolveLedgerRoot(anchor, anchor)` 推导所得项目根
|
|
76
|
+
* (界 = 本面会话锚 ⇒ 命中即根 = 锚自身;多根工作区锚 ⇒ 无根)——与行集读取同一单源;无根 ⇒ `ledger` = `null`
|
|
77
|
+
* (不落兜底根——该态下 `root` / `name` 回落锚、行集为空,且该 scan 不进族枚举(`discoverFamily` 只列已注册子目录))。
|
|
76
78
|
* `inflightExecutors`(F-LX1 · sync 零变——K-LX2):在途且 executor 非空行集原样携带
|
|
77
79
|
* {executor, updated_at, created_at}——判活解析由 `resolveExecutorStates` async 单源负责,本函数零探测。 */
|
|
78
80
|
export function buildScan({ cwd, days = AGING_DAYS, now = Date.now() } = {}) {
|
|
79
81
|
const anchor = resolve(cwd)
|
|
80
|
-
const derived = resolveLedgerRoot(anchor)
|
|
82
|
+
const derived = resolveLedgerRoot(anchor, anchor) // 界 = 会话锚(本面锚即会话锚——与工具面同判)
|
|
81
83
|
const root = derived ? derived.root : anchor
|
|
82
|
-
const rows = ledgerQuery({ cwd: anchor, now }) // `now` 透传(两读数同时钟——`overdue` 的行键由核同一 `now` 算)
|
|
84
|
+
const rows = ledgerQuery({ cwd: anchor, boundary: anchor, now }) // `now` 透传(两读数同时钟——`overdue` 的行键由核同一 `now` 算)
|
|
83
85
|
const pending = rows.filter((r) => PENDING_STATUSES.includes(r.status))
|
|
84
86
|
const poolEntries = pending.filter((r) => r.kind === "requirement")
|
|
85
87
|
const techEntries = pending.filter((r) => r.kind === "tech_todo")
|
|
@@ -98,7 +100,7 @@ export function buildScan({ cwd, days = AGING_DAYS, now = Date.now() } = {}) {
|
|
|
98
100
|
.filter((r) => r.status === "在途" && r.executor)
|
|
99
101
|
.map((r) => ({ executor: r.executor, updated_at: r.updated_at ?? null, created_at: r.created_at ?? null }))
|
|
100
102
|
return {
|
|
101
|
-
name: basename(root), root, ledger: derived ? ledgerDbPath(root) : null,
|
|
103
|
+
name: basename(root), root, ledger: derived ? ledgerDbPath(root, root) : null,
|
|
102
104
|
pool: poolEntries.length, tech: techEntries.length, aged: aged.length,
|
|
103
105
|
overdue: pending.filter((r) => r.overdue != null).length, // 待处置(§3.7——机判单源 = 行集 `overdue` 键,行值与 `now` 均同源)
|
|
104
106
|
agedKeys: aged.map((r) => normalizeEntry(r.title)), agedTitles: aged.map((r) => entryTitle(r.title)),
|
package/manifest-discovery.mjs
CHANGED
|
@@ -2,15 +2,18 @@
|
|
|
2
2
|
* manifest-discovery.mjs — **发现 ∕ 归属族**出档(2026-09-29 structure-split-2 · 台账 #620):自 `manifest.mjs`
|
|
3
3
|
* 全量迁出——`MANIFEST_REL` · 测试注入位(`_setProjectRootForTest` / `_resetProjectRootForTest`)·
|
|
4
4
|
* `scanChildren`(两条梯表共用 walk 内核)· `discoverProjects`(项目梯)· `discoverRepos`(仓梯)·
|
|
5
|
-
* `owningProject
|
|
6
|
-
*
|
|
5
|
+
* `owningProject`(归属形 = 判据本体)· `projectRootView`(三态报明)· `resolveProjectRoot`(归属形薄委托);
|
|
6
|
+
* **结构拆分零语义**(面不变 ∕ 判据不变,只换宿主档;切点 ∕ 缝单源 = 批档 `docs/batches/2026-09-29-structure-split-2.md` §2.2-C)。
|
|
7
|
+
* 拆分后判据变更(2026-10-25「判据本体单源 + 不向下取根」):`projectRootView` 取根臂收为**仅归属命中**
|
|
8
|
+
* (界 = 目标所在盘根),`discoverProjects` 的 `self` 只供报明、不进 `root`(项目梯无 `unique`——≥1 即
|
|
9
|
+
* `workspace`,1 ∥ 2 ∥ 更多同判;仓梯 `discoverRepos` 的 `unique` 保留)。
|
|
7
10
|
*
|
|
8
|
-
* 缝 = 同名再出口:宿主 `manifest.mjs`
|
|
11
|
+
* 缝 = 同名再出口:宿主 `manifest.mjs` 转口本档八名导出(消费者 import 面零改);宿主自用四名
|
|
9
12
|
* (`MANIFEST_REL` ∥ `discoverProjects` ∥ `owningProject` ∥ `resolveProjectRoot`)随 import。
|
|
10
13
|
* 零环:本档不引宿主(方向单行);档外依赖 = `node:fs` ∥ `node:path`;机制详述 = `docs/core/design/MANIFEST.md` §2.2 / §2.9。
|
|
11
14
|
*/
|
|
12
15
|
import { existsSync, readdirSync, statSync } from "node:fs"
|
|
13
|
-
import { dirname, join, resolve } from "node:path"
|
|
16
|
+
import { dirname, join, parse, resolve } from "node:path"
|
|
14
17
|
|
|
15
18
|
/** 数据档文件名(**每个项目一份**——项目根 = 带档目录;**git 非前提**。2026-09-17 / 2026-09-21 用户裁定)。 */
|
|
16
19
|
export const MANIFEST_REL = "PROJECT-MANIFEST.json"
|
|
@@ -41,14 +44,14 @@ function scanChildren(anchor, isHit) {
|
|
|
41
44
|
/**
|
|
42
45
|
* **项目发现**(项目梯五级——KD-M1-23 / 设计 `docs/core/design/MANIFEST.md` §2.2;**git 非前提**,
|
|
43
46
|
* 2026-09-21 用户裁定):① 锚自身带 `MANIFEST_REL` ⇒ 锚;② 锚含 `.git` ⇒ 锚(缺档 = 建档机会);
|
|
44
|
-
* ③
|
|
45
|
-
*
|
|
46
|
-
*
|
|
47
|
+
* ③ 直接子目录中**带档**者非空 ⇒ `workspace`(只看此级;1 ∥ 2 ∥ 更多同判——下辖项目 = 多根工作区,
|
|
48
|
+
* 常态、非错误态,项目梯无 `unique` 态);④ 零带档才看含 `.git` 的**裸仓**(≥1 ⇒ `workspace`,同判);
|
|
49
|
+
* ⑤ 均无 ⇒ `none`(⇒ 建档流,落点 = 会话锚)。
|
|
47
50
|
* `candidates` 一律**按名排序**(`self` / `none` ⇒ `[]`);`matched` ∈ `manifest` / `git` / `null`
|
|
48
51
|
* 记命中(或工作区)出自哪一级。**纯 fs**(只判存在性——不解析档内容)· **不抛** · **不向上** · **不递归**。
|
|
49
52
|
* **覆盖位**(`_setProjectRootForTest` 在场)⇒ **头部短路**(测试注入面——先于真判据,同 `discoverRepos`)。
|
|
50
53
|
* @param {string} [cwd] 会话锚(缺省 → 进程 cwd)
|
|
51
|
-
* @returns {{kind:'self'|'
|
|
54
|
+
* @returns {{kind:'self'|'none'|'workspace', root:string|null, candidates:string[], matched:'manifest'|'git'|null}}
|
|
52
55
|
*/
|
|
53
56
|
export function discoverProjects(cwd) {
|
|
54
57
|
if (_projectRootOverride) return { kind: "self", root: resolve(_projectRootOverride), candidates: [], matched: null }
|
|
@@ -56,11 +59,9 @@ export function discoverProjects(cwd) {
|
|
|
56
59
|
if (existsSync(join(anchor, MANIFEST_REL))) return { kind: "self", root: anchor, candidates: [], matched: "manifest" }
|
|
57
60
|
if (existsSync(join(anchor, ".git"))) return { kind: "self", root: anchor, candidates: [], matched: "git" }
|
|
58
61
|
const withManifest = scanChildren(anchor, (d) => existsSync(join(d, MANIFEST_REL)))
|
|
59
|
-
if (withManifest.length
|
|
60
|
-
if (withManifest.length === 1) return { kind: "unique", root: withManifest[0], candidates: [...withManifest], matched: "manifest" }
|
|
62
|
+
if (withManifest.length >= 1) return { kind: "workspace", root: null, candidates: withManifest, matched: "manifest" }
|
|
61
63
|
const bareRepos = scanChildren(anchor, (d) => existsSync(join(d, ".git")))
|
|
62
|
-
if (bareRepos.length
|
|
63
|
-
if (bareRepos.length === 1) return { kind: "unique", root: bareRepos[0], candidates: [...bareRepos], matched: "git" }
|
|
64
|
+
if (bareRepos.length >= 1) return { kind: "workspace", root: null, candidates: bareRepos, matched: "git" }
|
|
64
65
|
return { kind: "none", root: null, candidates: [], matched: null }
|
|
65
66
|
}
|
|
66
67
|
|
|
@@ -88,22 +89,32 @@ export function discoverRepos(cwd) {
|
|
|
88
89
|
}
|
|
89
90
|
|
|
90
91
|
/**
|
|
91
|
-
*
|
|
92
|
-
*
|
|
92
|
+
* **归属形单点 = 判据本体**(KD-M1-30 · 2026-10-23 用户裁定 · 2026-10-25「判据本体真单源」):
|
|
93
|
+
* 自 `target`(目录 = 自身;文件 = 其所在目录)沿**祖先链**上溯,取最近带 `MANIFEST_REL` 的目录
|
|
94
|
+
* ⇒ 该目录;无 ⇒ `null`(不向下、不猜——发现梯是另问,交调用方处置)。
|
|
93
95
|
* 会话落在项目内层子目录时,这一路上溯正是它归到自己项目根的通路(用户 2026-10-23 23:24
|
|
94
96
|
* 「本来就该爬到项目根啊」);**发现梯(`discoverProjects`)仍纯向下**——从工作区容器只找直接
|
|
95
97
|
* 子目录,不把容器挂到外层项目上。**纯 fs** · **不跨兄弟** · **无全局优先级**。
|
|
98
|
+
* **界(`boundary`)由调用方定——两面两界**:取根面(`projectRootView`)传**目标所在盘根**(向上
|
|
99
|
+
* 无界——目标由调用方指名);台账面(`resolveLedgerRoot`)传**会话锚**(越界即停——用户
|
|
100
|
+
* 2026-10-25 19:09「不能跑到工作目录以外去」)。界比较按**段归一**(`isInsideOrEqual`:盘根形带
|
|
101
|
+
* 尾分隔符,`edge + sep` 直比会假阴)。
|
|
96
102
|
* **覆盖位**(`_setProjectRootForTest` 在场)⇒ **头部短路**:直接返回覆盖值(不查档存在性)。
|
|
97
103
|
* @param {string} [target] 目标路径(目录 / 文件)
|
|
104
|
+
* @param {string} [boundary] 上溯上界(缺省 → 进程 cwd)
|
|
98
105
|
* @returns {string|null} 带档目录绝对路径 / null
|
|
99
106
|
*/
|
|
100
|
-
export function owningProject(target) {
|
|
107
|
+
export function owningProject(target, boundary) {
|
|
101
108
|
if (_projectRootOverride) return resolve(_projectRootOverride)
|
|
102
109
|
let dir = resolve(target ?? ".")
|
|
110
|
+
const edge = resolve(boundary ?? process.cwd())
|
|
111
|
+
// 界:target 在界外(含「target 是界的祖先」)⇒ 无归属——界由调用方定,越界不猜。
|
|
112
|
+
if (!isInsideOrEqual(dir, edge)) return null
|
|
103
113
|
const st = statSync(dir, { throwIfNoEntry: false })
|
|
104
114
|
if (st && !st.isDirectory()) dir = dirname(dir)
|
|
105
115
|
for (;;) {
|
|
106
116
|
if (existsSync(join(dir, MANIFEST_REL))) return dir
|
|
117
|
+
if (dir === edge) return null
|
|
107
118
|
const parent = dirname(dir)
|
|
108
119
|
if (parent === dir) return null
|
|
109
120
|
dir = parent
|
|
@@ -119,24 +130,28 @@ function isInsideOrEqual(dir, bound) {
|
|
|
119
130
|
}
|
|
120
131
|
|
|
121
132
|
/** **项目根解析的直读形**(判定单点——设计 `MANIFEST.md` §2.2 `projectRootView` 契约行 / §2.5
|
|
122
|
-
* 「单项目解析律与四处会话级缺省收口」条):`ok
|
|
123
|
-
*
|
|
124
|
-
*
|
|
125
|
-
*
|
|
133
|
+
* 「单项目解析律与四处会话级缺省收口」条):`ok`(**仅归属命中**——判据本体 = `owningProject`,
|
|
134
|
+
* 界 = **目标所在盘根** ⇒ 向上无界;函数体唯一 `ok` 出口)/ `workspace`(归属无命中 ∧
|
|
135
|
+
* `discoverProjects` 报工作区:下辖带档者 ≥1 ∥ 零带档时裸仓 ≥1 ⇒ `root` null + 下辖项目全列
|
|
136
|
+
* **按名排序**——多根工作区常态,非错误态;1 ∥ ≥2 同判)/ `none`(其余,含裸仓锚——
|
|
137
|
+
* **不向下取根** ⇒ 双空);覆盖位在场 ⇒ 头部短路(`ok` + 覆盖值)。
|
|
138
|
+
* **发现读数只供 `workspace` 报明**:`discoverProjects` 的 `self` **不进 `root`**
|
|
139
|
+
* (判据单源 = `owningProject`)。**非抛错 / 零写**;`resolveProjectRoot` 薄委托本函数。
|
|
126
140
|
* @returns {{state:'ok'|'workspace'|'none', root:string|null, candidates:string[]}} */
|
|
127
141
|
export function projectRootView(cwd) {
|
|
128
|
-
const
|
|
142
|
+
const target = resolve(cwd ?? ".")
|
|
143
|
+
const owning = owningProject(target, parse(target).root)
|
|
129
144
|
if (owning) return { state: "ok", root: owning, candidates: [] }
|
|
130
|
-
const d = discoverProjects(
|
|
131
|
-
if (d.root) return { state: "ok", root: d.root, candidates: [] }
|
|
145
|
+
const d = discoverProjects(target)
|
|
132
146
|
if (d.kind === "workspace") return { state: "workspace", root: null, candidates: d.candidates }
|
|
133
147
|
return { state: "none", root: null, candidates: [] }
|
|
134
148
|
}
|
|
135
149
|
|
|
136
|
-
/**
|
|
137
|
-
* 单点见上——#828
|
|
138
|
-
* (祖先带档)⇒
|
|
139
|
-
*
|
|
150
|
+
/** 项目根解析(**归属形**——KD-M1-30 / M1-24):**薄委托** `projectRootView(cwd).root`(判定
|
|
151
|
+
* 单点见上——#828)。带档路径与批前**逐字同**;变更面(设计 §2.2 同条):① 项目树内路径
|
|
152
|
+
* (祖先带档)⇒ 该项目根(子目录归到自己的项目根 = 正常通路);② 祖链无档 ⇒ `null`——
|
|
153
|
+
* **不向下取根**(下辖带档子目录恰一 ∥ 裸仓恰一均 `null`,发现读数不进 `root`)。
|
|
154
|
+
* `none` / `workspace` ⇒ `null`。调用方零改(行为随语义变更——设计 §2.5 键面条 / 错层条)。
|
|
140
155
|
* @returns {string|null} 项目根绝对路径 / null */
|
|
141
156
|
export function resolveProjectRoot(cwd) {
|
|
142
157
|
return projectRootView(cwd).root
|
package/manifest.mjs
CHANGED
|
@@ -21,13 +21,13 @@
|
|
|
21
21
|
* - discoverProjects(cwd) → { kind, root, candidates, matched }:**项目梯**(五级 / git 非前提——KD-M1-23);
|
|
22
22
|
* `discoverRepos(cwd)` 同形态 = **仓梯**(`.git` 视图——`git` 工具经它接线,KD-M1-22)。
|
|
23
23
|
* 两梯共一模块私有 walk 内核 `scanChildren`(单源);`candidates` 按名排序、`matched` 记档位。
|
|
24
|
-
* - owningProject(target) →
|
|
24
|
+
* - owningProject(target, boundary) → 归属形单点(沿祖先链取**最近带档目录**;界由调用方定——KD-M1-30)。
|
|
25
25
|
* - projectView(target) → { state, root, path, manifest?, candidates?, errors?, matched }:**按用点解析**
|
|
26
26
|
* 的读侧单点(归属 ∨ 发现兜底 / 五态 / 非抛错 / **零写**——KD-M1-24)。
|
|
27
|
-
* - resolveProjectRoot(cwd)
|
|
27
|
+
* - resolveProjectRoot(cwd):项目根(**归属形**——KD-M1-30)= `projectRootView(cwd).root`(薄委托;取值规则见下行);
|
|
28
28
|
* projectRootView(cwd) → { state: ok|workspace|none, root, candidates }:项目根直读形(判定单点——§2.2)。
|
|
29
29
|
* - resolveEngineeringManifest(cwd, { writer, init }) → 入口决策树(**非抛错**——KD-M1-20):
|
|
30
|
-
* 两端入口钩子与翻转面(拒翻)共用同一张树(判据单源;§2.8 F1
|
|
30
|
+
* 两端入口钩子与翻转面(拒翻)共用同一张树(判据单源;§2.8 F1)——态码五枚
|
|
31
31
|
* `missing` / `invalid` / `no-project` / `workspace` / `init-failed`(KD-M1-28)。名中 `Engineering` = 历史命名(沿用不改名);消费面 = 两端入口钩子 + 翻转面——**非**「模式拥有本模块」。
|
|
32
32
|
* - manifestFilePath(cwd) → 数据档绝对路径(档路径单源 KD-M1-18——读 / 写 / mtime 门控三处同源)。
|
|
33
33
|
* - initManifest(cwd, { writer = 'subagent' } = {}) → 经写门写 DEFAULT_MANIFEST,缺省拒。
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
* N3 可迁移:本模块不硬编码任何本仓路径(docRoot 由被开发项目声明;机检参数不在 manifest 面——住引擎内置常量)。
|
|
39
39
|
*/
|
|
40
40
|
import { readFileSync, writeFileSync } from "node:fs"
|
|
41
|
-
import { join, resolve } from "node:path"
|
|
41
|
+
import { join, parse, resolve } from "node:path"
|
|
42
42
|
import { DEFAULT_MANIFEST, isValidDocRootValue, validateManifest, fillDefaults } from "./manifest-schema.mjs"
|
|
43
43
|
import { MANIFEST_REL, discoverProjects, owningProject, resolveProjectRoot } from "./manifest-discovery.mjs"
|
|
44
44
|
// #802(KD-M1-36):未知键读面告警的事件面——诊断日志(fire-and-forget,失败静默降级)。
|
|
@@ -50,10 +50,11 @@ export { DEFAULT_MANIFEST, MANIFEST_SCHEMA, isValidDocRootValue, validateManifes
|
|
|
50
50
|
|
|
51
51
|
/**
|
|
52
52
|
* **按用点解析**的读侧单点(KD-M1-24 / M1-30——**非抛错 / 零写 / 无缓存**):两段合成——
|
|
53
|
-
* · **归属(第一段——§⑥ 归属形)**:`owningProject(target)` 沿祖先链取最近带档目录
|
|
54
|
-
* (子优于根 / 不跨兄弟 / 无全局优先级)⇒ 读该档 ⇒ `ok` / `invalid
|
|
55
|
-
*
|
|
56
|
-
*
|
|
53
|
+
* · **归属(第一段——§⑥ 归属形)**:`owningProject(target, target 所在盘根)` 沿祖先链取最近带档目录
|
|
54
|
+
* (子优于根 / 不跨兄弟 / 无全局优先级)⇒ 读该档 ⇒ `ok` / `invalid`。界与 `projectRootView`
|
|
55
|
+
* 同源(目标所在盘根)——同一 target 两面同归属,非会话锚。
|
|
56
|
+
* · **发现兜底(第二段——§⑥ 发现规则,纯向下)**:祖先链无档 ⇒ `discoverProjects(target)` ⇒
|
|
57
|
+
* `self` ⇒ 读其档(带档 ⇒ `ok` / `invalid`;缺档 ⇒ `missing`);`workspace` ⇒
|
|
57
58
|
* `workspace`(+ `candidates`);`none` ⇒ `no-project`。
|
|
58
59
|
* 写侧(建档)**不在**此函数(归入口决策树——KD-M1-25 / M1-29)⇒ 注入器 / 只读消费面不会变写点。
|
|
59
60
|
* `matched` 契约:归属段命中 ⇒ `'manifest'`;发现段 ⇒ `discoverProjects.matched` 逐字;
|
|
@@ -65,7 +66,7 @@ export { DEFAULT_MANIFEST, MANIFEST_SCHEMA, isValidDocRootValue, validateManifes
|
|
|
65
66
|
*/
|
|
66
67
|
export function projectView(target) {
|
|
67
68
|
const anchor = resolve(target ?? ".")
|
|
68
|
-
const owning = owningProject(anchor)
|
|
69
|
+
const owning = owningProject(anchor, parse(anchor).root)
|
|
69
70
|
if (owning) return viewAtRoot(owning, "manifest")
|
|
70
71
|
const d = discoverProjects(anchor)
|
|
71
72
|
if (d.kind === "workspace") return { state: "workspace", root: null, path: null, candidates: d.candidates, matched: d.matched }
|
|
@@ -180,7 +181,7 @@ export function readManifest(cwd) {
|
|
|
180
181
|
|
|
181
182
|
/**
|
|
182
183
|
* 装配钩子入口(模块设计 §2.2)——同 readManifest(cwd)。ok:true 返回补默认值后的 manifest;
|
|
183
|
-
* reason:'missing'
|
|
184
|
+
* reason:'missing' 由调用方走**建档流**(**工程模式会话**口径——梯②⑤ 就地建档,**不拒会话**;
|
|
184
185
|
* KD-M1-29);普通会话 = 装配钩子零 manifest I/O(KD-M1-12)。
|
|
185
186
|
*/
|
|
186
187
|
export function requireManifest(cwd) {
|
|
@@ -205,17 +206,17 @@ export function onManifestInit(fn) {
|
|
|
205
206
|
*
|
|
206
207
|
* 分支(两分支六出口——§2.8 F1 树):
|
|
207
208
|
* 档合法 → { ok:true, manifest, created:false }(manifest = 补默认值后的档内容)
|
|
208
|
-
* 缺档 + init →
|
|
209
|
-
* (抛错 → `init-failed`);工作区(锚自身无档 ∧ 下辖 ≥
|
|
209
|
+
* 缺档 + init → 梯②⑤(锚 = 裸仓 / 无项目)⇒ `initManifest(cwd, { writer })`
|
|
210
|
+
* (抛错 → `init-failed`);工作区(锚自身无档 ∧ 下辖 ≥1 项目——1 ∥ 更多同判)⇒
|
|
210
211
|
* `{ ok:false, code:'workspace', message, candidates }`(**不建 / 不猜**)
|
|
211
212
|
* 缺档 + !init → 梯⑤(无项目)⇒ `{ ok:false, code:'no-project' }`(KD-M1-28;`init:false` 面);
|
|
212
|
-
*
|
|
213
|
+
* 梯②(裸仓可解析、档缺)⇒ `{ ok:false, code:'missing' }`;工作区 ⇒ 同上
|
|
213
214
|
* 档非法 → { ok:false, code:'invalid', message, errors }
|
|
214
215
|
*
|
|
215
216
|
* `writer` 由调用点**显式**传(生产调用点全传 `'main'`):缺省 `'subagent'` 是写门 fail-closed
|
|
216
|
-
* 缺省(KD-M1-3),误用缺省 ⇒「缺档 +
|
|
217
|
+
* 缺省(KD-M1-3),误用缺省 ⇒「缺档 + 梯②⑤」退化为 `init-failed`(拒翻——与 §2.8 F2 /
|
|
217
218
|
* AC-20② 语义相反;T38 反证格)。
|
|
218
|
-
*
|
|
219
|
+
* 态码文案分野(KD-M1-28):无项目 ⇒ 可在锚处落地 / 工作区 ⇒ 报明事实 + 点名项目根;文案族 =
|
|
219
220
|
* 「项目不可解析」(稳定锚句 `/项目不可解析/`)——**仅「档非法」格**(§2.8 F2 拒翻面唯一拒格)。
|
|
220
221
|
* 边界:`readManifest` 的非 ENOENT 读错(权限 / 目录等)由 `projectView` 收为 `invalid`(非抛错
|
|
221
222
|
* 契约——`readManifest` 返回语义零改);本树只承诺上列六出口。
|
|
@@ -236,7 +237,7 @@ export function resolveEngineeringManifest(cwd, { writer = "subagent", init = tr
|
|
|
236
237
|
if (view.state === "workspace") {
|
|
237
238
|
return { ok: false, code: "workspace", candidates: view.candidates, message: workspaceProjectMessage(cwd, view.candidates) }
|
|
238
239
|
}
|
|
239
|
-
//
|
|
240
|
+
// 缺档(梯②⑤):init ⇒ 就地建档(内容 = DEFAULT_MANIFEST,经写门 writer:'main');!init ⇒ 归码。
|
|
240
241
|
if (!init) return { ok: false, code: view.state === "no-project" ? "no-project" : "missing" }
|
|
241
242
|
try {
|
|
242
243
|
const manifest = initManifest(cwd, { writer })
|
package/model-specs.mjs
CHANGED
|
@@ -44,6 +44,14 @@ const MODEL_SPECS = [
|
|
|
44
44
|
["deepseek-v4-flash-vision-exp", { context: 1_000_000, maxOutput: 384_000, thinking: true, prefixMode: true, thinkApi: "type", reasoningEcho: "required", reasoningEffortEnum: ["low", "high", "max"], tempRange: [0, 2], multimodal: true }],
|
|
45
45
|
// Kimi series
|
|
46
46
|
["kimi-k3", { context: 1_000_000, maxOutput: 131_072, thinking: true, partialMode: true, multimodal: true, thinkApi: "effort", reasoningEcho: "required", reasoningEffortEnum: ["low", "high", "max"] }],
|
|
47
|
+
// kimi-k3.1-pro / kimi-k3.1-pro-highspeed(2026-10-23 发布;官方 quickstart 实读 2026-10-25):
|
|
48
|
+
// context = 1_048_576(官方 1M);maxOutput = 131_072(官方 max_completion_tokens 默认档,上限 1_048_576 不取);
|
|
49
|
+
// **思考始终开启**(官方原文「K3.1 Pro 始终开启思考模式」· FAQ「目前关不了」)⇒ thinkAlwaysOn;推理强度走顶层
|
|
50
|
+
// reasoning_effort low/high/max(默认 max)⇒ thinkApi "effort";多轮 / 工具调用须原样回传完整 assistant message
|
|
51
|
+
// ⇒ reasoningEcho "required";partialMode ✓;视觉 ✓(content 必须是对象数组,图走 base64 ∥ ms://,**不接受公网 URL**)。
|
|
52
|
+
// Highspeed = 同规格、输出约 2~3 倍速(官方「同等智能」)—— 分值分行,靠前缀长度降序先命中。
|
|
53
|
+
["kimi-k3.1-pro", { context: 1_048_576, maxOutput: 131_072, thinking: true, thinkAlwaysOn: true, partialMode: true, multimodal: true, thinkApi: "effort", reasoningEcho: "required", reasoningEffortEnum: ["low", "high", "max"] }],
|
|
54
|
+
["kimi-k3.1-pro-highspeed", { context: 1_048_576, maxOutput: 131_072, thinking: true, thinkAlwaysOn: true, partialMode: true, multimodal: true, thinkApi: "effort", reasoningEcho: "required", reasoningEffortEnum: ["low", "high", "max"] }],
|
|
47
55
|
// Kimi For Coding endpoint uses the short model ID "k3" (same specs as kimi-k3) — IK5VGJ
|
|
48
56
|
["k3", { context: 1_000_000, maxOutput: 131_072, thinking: true, partialMode: true, multimodal: true, thinkApi: "effort", reasoningEcho: "required", reasoningEffortEnum: ["low", "high", "max"] }],
|
|
49
57
|
// kimi-for-coding / k3-256k / kimi-for-coding-highspeed(Kimi For Coding 端点三名 · 2026-09-25 批 §14.2 #7-9 · 活测 = §1.4 服务端 200 /models):
|
|
@@ -81,8 +89,7 @@ const MODEL_SPECS = [
|
|
|
81
89
|
["glm-5.3-flashx", { context: 1_000_000, maxOutput: 131_072, thinking: true, thinkAlwaysOn: true, multimodal: true, thinkApi: "type", reasoningEcho: "optional", reasoningEffortEnum: ["low", "high", "max"], tempRange: [0, 1], noUsageStream: true }],
|
|
82
90
|
["glm-5.2", { context: 1_000_000, maxOutput: 128_000, thinking: true, thinkApi: "type", reasoningEcho: "optional", reasoningEffortEnum: ["max", "xhigh", "high", "medium", "low", "minimal", "none"], tempRange: [0, 1], noUsageStream: true }],
|
|
83
91
|
["glm-5", { context: 1_000_000, maxOutput: 128_000, thinking: true, thinkApi: "type", reasoningEcho: "optional", reasoningEffortEnum: ["max", "xhigh", "high", "medium", "low", "minimal", "none"], tempRange: [0, 1], noUsageStream: true }],
|
|
84
|
-
|
|
85
|
-
// glm-4.5-air(智谱轻档 · 2026-09-24 bench 名单批):temperature 0 受理 = **实测**(roster-expand §2.2);其余 = **族沿用 glm-4 行**
|
|
92
|
+
// glm-4.5-air(智谱轻档 · 2026-09-24 bench 名单批):temperature 0 受理 = **实测**(roster-expand §2.2);取值以本行**显式声明**为准
|
|
86
93
|
// (逐名官方口径未取证);枚举 / 视觉面 = **未探**(不声明)。medium 直发实测受理(batch-params-judge §1.5)。
|
|
87
94
|
["glm-4.5-air", { context: 128_000, maxOutput: 32_000, thinking: true, thinkApi: "type", reasoningEcho: "optional", tempRange: [0, 1], noUsageStream: true }],
|
|
88
95
|
// GPT series
|
|
@@ -91,11 +98,10 @@ const MODEL_SPECS = [
|
|
|
91
98
|
["gpt-4.1", { context: 1_000_000, maxOutput: 128_000, thinking: false }],
|
|
92
99
|
["gpt-4o", { context: 128_000, maxOutput: 16_000, thinking: false, multimodal: true }],
|
|
93
100
|
// Qwen series
|
|
94
|
-
// qwen-flash
|
|
101
|
+
// qwen-flash(2026-09-25 批 §14.2 #2-6 · §1.7.1 父侧实测):**尺寸行**——maxOutput 32_768 = **实测**
|
|
95
102
|
// (服务端直报「Range of max_tokens should be [1, 32768]」;131072 / 262144 均 400)。context 未取到 ⇒ 零口径——取兜底值
|
|
96
103
|
// 128_000(与建行前生效值同值,§14.3 兜底语义续效);thinking / 视觉有读数(默认关可开 / 不支持)但不落字段(§14.3 五名口径)。
|
|
97
104
|
["qwen-flash", { context: 128_000, maxOutput: 32_768 }],
|
|
98
|
-
["qwen-vl-max", { context: 128_000, maxOutput: 32_768 }],
|
|
99
105
|
// qwen3.7-max:**实测拒图像**(DashScope 400 "Unexpected item type in content"——真值彩图探针,2026-09-20)
|
|
100
106
|
// ⇒ 无视觉 = **不声明**(T-7 语义单一:multimodal 仅 true / undefined;补探已毕,无需再探)
|
|
101
107
|
["qwen3.7-max", { context: 1_000_000, maxOutput: 131_072, thinking: true, partialMode: true, thinkApi: "effort", reasoningEffortEnum: ["xhigh", "high"], tempRange: [0, 2] }],
|
|
@@ -137,8 +143,6 @@ const MODEL_SPECS = [
|
|
|
137
143
|
["qwen3.6-flash", { context: 1_000_000, maxOutput: 65_536, thinking: true, partialMode: true, multimodal: true, thinkApi: "effort", reasoningEffortEnum: ["none", "minimal", "low", "medium", "high", "xhigh"], tempRange: [0, 2] }],
|
|
138
144
|
// qwen3.6-plus:同形行(共享证据块见 flash 行上)——校验级 maxOutput / 六档枚举、官方口径 context、族沿用机制位。
|
|
139
145
|
["qwen3.6-plus", { context: 1_000_000, maxOutput: 65_536, thinking: true, partialMode: true, multimodal: true, thinkApi: "effort", reasoningEffortEnum: ["none", "minimal", "low", "medium", "high", "xhigh"], tempRange: [0, 2] }],
|
|
140
|
-
// qwen3.6-max-preview:同形行——校验级 maxOutput / 六档枚举、官方口径 context、族沿用机制位;视觉通道实测 ✓ 但纯红图答「黑色」(抽样波动,如实记)。
|
|
141
|
-
["qwen3.6-max-preview", { context: 1_000_000, maxOutput: 65_536, thinking: true, partialMode: true, multimodal: true, thinkApi: "effort", reasoningEffortEnum: ["none", "minimal", "low", "medium", "high", "xhigh"], tempRange: [0, 2] }],
|
|
142
146
|
// qwen3.6-27b:同形行——校验级 maxOutput / 六档枚举、官方口径 context(未探边)、族沿用机制位。
|
|
143
147
|
["qwen3.6-27b", { context: 1_000_000, maxOutput: 65_536, thinking: true, partialMode: true, multimodal: true, thinkApi: "effort", reasoningEffortEnum: ["none", "minimal", "low", "medium", "high", "xhigh"], tempRange: [0, 2] }],
|
|
144
148
|
// qwen3.5-27b(2026-09-24 bench 名单批):context 262_144 = **官方口径(定价页分档佐证——[128K, 256K) 档在售;规格页未逐名核)**;
|
|
@@ -155,8 +159,6 @@ const MODEL_SPECS = [
|
|
|
155
159
|
// always echo); 2026-09-22 re-probe: value / missing field / empty string all 200 — the
|
|
156
160
|
// 2026-09-20 "must be passed back" 400 was NOT reproduced. v2.5 rows aligned 2026-09-22:
|
|
157
161
|
// maxOutput 131_072 = **校验级**.
|
|
158
|
-
["mimo-v2.5-pro", { context: 1_000_000, maxOutput: 131_072, thinking: true, thinkApi: "type", reasoningEcho: "required", tempRange: [0, 1.5] }],
|
|
159
|
-
["mimo-v2.5", { context: 1_000_000, maxOutput: 131_072, thinking: true, multimodal: true, thinkApi: "type", reasoningEcho: "required", tempRange: [0, 1.5] }],
|
|
160
162
|
// MiMo V2.6 series (2026-09-22 launch — three independent rows, each probed individually).
|
|
161
163
|
// maxOutput 131_072 / tempRange [0, 1.5] = **校验级** (400 "at most 131072 completion tokens" /
|
|
162
164
|
// "temperature must be within [0, 1.5]", per model); thinking = **实测** (bare request carries
|
|
@@ -175,10 +177,9 @@ const MODEL_SPECS = [
|
|
|
175
177
|
// minimax-m3(小写前缀行——与上方 MiniMax-M3 行同值,同族两写法):effort 同按**无生效面**处置
|
|
176
178
|
// (**实测**:effort 被忽略;off 路径 = `thinking:{type:"disabled"}` ✓ rc=0——batch-params-judge §1.2 / KD-32④)。
|
|
177
179
|
["minimax-m3", { context: 1_000_000, maxOutput: 128_000, thinking: true, multimodal: true, thinkApi: "type", thinkEnabledValue: "adaptive", tempRange: [0, 2], noUsageStream: true }],
|
|
178
|
-
["minimax-m1", { context: 256_000, maxOutput: 128_000, thinking: false, noUsageStream: true }],
|
|
179
180
|
// MiniMax-M2.7(前缀行——覆盖标准档与 -highspeed · 2026-09-24 bench 名单批):thinking = **实测**(裸请求 rc 在场);off 路径 **未找到**
|
|
180
181
|
// (`thinking:{type:"disabled"}` 不生效——如实,不声明 thinkApi);effort 被忽略 ⇒ **无生效面**(枚举不声明;medium 照发仅口径统一);
|
|
181
|
-
// 尺寸 / noUsageStream =
|
|
182
|
+
// 尺寸 / noUsageStream = 本行**显式声明**(逐名官方口径未取证);视觉面 = **未探**(不声明)。
|
|
182
183
|
["MiniMax-M2.7", { context: 256_000, maxOutput: 128_000, thinking: true, noUsageStream: true }],
|
|
183
184
|
// Grok series (xAI — OpenAI-compatible)
|
|
184
185
|
// grok-4.x: 500K context per xAI Grok 4.6 spec (corrected 2026-08; earlier entries said 1M)
|
|
@@ -220,9 +221,6 @@ const MODEL_SPECS = [
|
|
|
220
221
|
// 答 "Unknown"(对照组明说不识图)⇒ 实测无视觉。尺寸位两级逐条标(AC-2):maxOutput 128_000 =
|
|
221
222
|
// **参考实配**(网关对 max_tokens 不硬拒 ⇒ 上限未证);context 256_000 = **网络口径**(他仓/文档 256K,未本渠道实测)。
|
|
222
223
|
["hy3", { context: 256_000, maxOutput: 128_000, thinking: true, thinkApi: "effort", reasoningEffortEnum: ["none", "minimal", "low", "medium", "high", "xhigh", "max"] }],
|
|
223
|
-
// hy3-preview(在场实测:/models + 401 前验活;能力位**未探针**)——**尺寸行**:仅登记尺寸位,取值 =
|
|
224
|
-
// hy3 **同族沿用**(maxOutput 参考实配 / context 网络口径)。D-11(2026-09-25 收窄现口径):能力位**无族据**一律不声明 ⇒ 该名无族据 ⇒ thinking / 枚举 / 视觉全不声明。
|
|
225
|
-
["hy3-preview", { context: 256_000, maxOutput: 128_000 }],
|
|
226
224
|
// hy4-preview(在场实测:/models + 401;能力位**未探针**)——尺寸行:取值 = hy3 族**同族沿用**
|
|
227
225
|
// (maxOutput 参考实配级取值 / context 网络口径;批次档 §1.2 未给该名尺寸行 ⇒ 上报清单 2,行注即标级)。
|
|
228
226
|
["hy4-preview", { context: 256_000, maxOutput: 128_000 }],
|
package/package.json
CHANGED
|
@@ -54,9 +54,10 @@ Evaluate the design against these dimensions:
|
|
|
54
54
|
each row names the **interaction between components** each evaluates, the business result each asserts, the project's entry (where a user enters the business — a business-observable point), and the business requirement each traces back to.
|
|
55
55
|
**An integration section that starts from a blank "which scenarios do we need" list, with no RTM read, ⇒ 🔴.**
|
|
56
56
|
A missing row's number is fixed in the RTM before its case title is written — `test('1-1 …')`, the same number verbatim.
|
|
57
|
-
**A design missing that section ⇒ 🔴 (design incomplete)**; a change that
|
|
58
|
-
**Only one reason stands: this change
|
|
59
|
-
**
|
|
57
|
+
**A design missing that section ⇒ 🔴 (design incomplete)**; a change that alters no business-observable result an existing case asserts and adds no scenario the product really needs states so, with its reason, in that section.
|
|
58
|
+
**Only one reason stands: this change alters no business-observable result an existing case asserts and adds no scenario the product really needs. Anything else — e.g. the 50–100 case window being full — is still 🔴.**
|
|
59
|
+
**A case grows from exactly two entries**: a business scenario the product really needs, or a problem production really produced — crossing components is not an entry.
|
|
60
|
+
**Why**: no other acceptance run evaluates the business result from a user-visible entry, and the batch's unit-test files are deleted at closeout — a design that never names those scenarios leaves that result with no acceptance at all.
|
|
60
61
|
**A design's acceptance naming a full-suite run ⇒ 🔴 (the release gate written as a round cost)**: the criterion is the changed-face unit test file or files (`node --test <file> [<file> ...]`), or — when the change has no runnable test — the check you actually ran and its result;
|
|
61
62
|
the integration half is reported in the closeout line, not run here.
|
|
62
63
|
Why: acceptance is what the implementing round runs — a suite there turns the release gate into a round cost, and a repeat run proves nothing new.
|
package/prompts/common.md
CHANGED
|
@@ -40,10 +40,20 @@ Where the check found nothing relevant, write "checked, nothing relevant" and na
|
|
|
40
40
|
**Bounds**: the instruction-precedence ladder stays as it is — that one governs conflict, this one governs the look before acting; the check is narrow — whether the how of this work is already written, not a long survey before every move.
|
|
41
41
|
|
|
42
42
|
## Who you are
|
|
43
|
-
Programming is collaborative labor between you and the human.
|
|
44
43
|
The human decides direction and makes the final call. You own the code — the entire project is your code.
|
|
45
44
|
What you confirm is your contract.
|
|
46
45
|
|
|
46
|
+
**The base every role works from**: where a written rule is silent, these decide; where it speaks, these are its reason.
|
|
47
|
+
- **Programming is collaborative labor**: the human expresses intent and decides; you execute. The code is a joint work, not a request pushed down a pipe.
|
|
48
|
+
- **Say more, not less**: an uncertain report is cheap and a wrong decision is dear; when you cannot tell whether it matters, say it and let the human skip it. Silence and a wrong report are the same dishonesty.
|
|
49
|
+
- **The design doc is the spec, not reference material**: it says what should be; code says what is. When they conflict the doc wins — point the gap out, never overwrite its intent with your own habit.
|
|
50
|
+
- **Official sources are authority; guessing is waste**: an unclear API, protocol or framework behavior gets looked up, not inferred from context or a partial example. A guess is right once and misleads every layer under it.
|
|
51
|
+
- **A finished job comes with its account**: what changed, why, what the risk is, what was not done. The human sees only what you say, so a report that does not match the delivery leaves every decision resting on false information.
|
|
52
|
+
- **Delivery transparency**: state item by item what was fully covered, what was simplified and how, what was left out and why. A gap is not the error — not saying it is.
|
|
53
|
+
- **No step is cut for speed**: you are faster than the human already, so speed was never the bottleneck; what breaks work is a decision made in a hurry. No step cut for time, no check skipped on "probably fine".
|
|
54
|
+
- **A related problem is not extra work**: change a signature and you change the call sites; a bug you can see next door gets fixed and reported. That is finishing the job, not over-delivering.
|
|
55
|
+
- **Do not decide for the human, but do not under-inform them**: a scope too wide, an architecture call, a possible clash with intent — lay the options out and let them choose; you prepare the decision, they make it.
|
|
56
|
+
|
|
47
57
|
## When choices conflict
|
|
48
58
|
- Correctness first. Rushing gets paid back in rework, so speed is not the bottleneck.
|
|
49
59
|
- Debatable choices → lay out options. Better approach → recommend with specifics.
|
|
@@ -94,27 +94,28 @@ Judge the **change face** before acting — different faces, different authoriza
|
|
|
94
94
|
The **UAT report** is a **delivery-face document**.
|
|
95
95
|
- **Repeated mechanical review failure**: same review face, same criterion (the failure conclusion block's `criterion=`) reaching ≥3 ⇒ stop re-running; lay the facts and candidate dispositions before the user — no auto re-run, no auto scope-narrowing, no self-rewritten criteria.
|
|
96
96
|
|
|
97
|
-
**Light channel (detail-face ∥ convergence-face controlled bypass — hit one of the three ⇒
|
|
97
|
+
**Light channel (detail-face ∥ convergence-face controlled bypass — hit one of the three ⇒ put it up as a choice, the user picks; bypass ≠ cancellation)**:
|
|
98
|
+
any one of the three named cases — detail / cosmetics · defect fix · problems named on the spot during a walkthrough — is put up as a choice question; it moves only after the pick.
|
|
98
99
|
That means: skip the "Design → Review → Approval" chain — direct edit → live walkthrough → freeze:
|
|
99
100
|
|
|
100
101
|
1. **Detail / cosmetics** — visual ∥ copy ∥ parameters (thresholds ∥ defaults ∥ lengths) ∥ existing-interaction details (order ∥ position ∥ keybindings ∥ hint texts);
|
|
101
102
|
|
|
102
|
-
2. **Defect fix** — **a defect ⇒
|
|
103
|
+
2. **Defect fix** — **a defect ⇒ goes up as item 2** (the implementation contradicts an existing source: requirement ∥ design ∥ record ∥ the user's words on the spot — the work = bringing the implementation back to the source, not adding semantics);
|
|
103
104
|
|
|
104
|
-
3. **Problems named on the spot during a walkthrough** — routed by the first two (detail class
|
|
105
|
+
3. **Problems named on the spot during a walkthrough** — routed by the first two (detail class goes up as item 1; behavior class goes up as item 2 — either way it only settles which item it is routed to; whether to walk is still the user's pick).
|
|
105
106
|
|
|
106
107
|
**One-sentence boundary**: **new mechanism ∥ major change ⇒ full chain**. Everything else falls to the **closeout full chain** as the backstop — a mis-admission gets formalized ∥ caught in review at closeout (the threshold yields to "no leak").
|
|
107
108
|
|
|
108
109
|
**Annotations**: diagnostics / probes = zero-chain (read-only + temp area, no classification).
|
|
109
110
|
**Performance-observation class** = no structural change ∧ before/after readings provable.
|
|
110
|
-
**A light-channel pen = main-agent direct edit** (the
|
|
111
|
+
**A light-channel pen = main-agent direct edit** (the choice question carries "revertable"; big fixes still go to eng-coder).
|
|
111
112
|
|
|
112
|
-
- **Round form**: a light-channel round = one batch record (per-pen entries:
|
|
113
|
+
- **Round form**: a light-channel round = one batch record (per-pen entries: the choice question and the pick · change · walkthrough · freeze) + per-pen ledger rows.
|
|
113
114
|
- **Start-up booking**: at round open, before the first pen, create the round batch record + the round ledger row first — the account precedes the pen; a pen without an account = not established.
|
|
114
115
|
- **One full chain at closeout**: design formalization → independent review (code · record · doc reconciliation) → fixes (if any) → approval → closeout settlement, including the necessary tests.
|
|
115
116
|
**Convergence-face pens**: the red-then-green reproduction pair ∥ the before/after reading pair.
|
|
116
117
|
- **Closeout not landed ⇒ no settlement** — the batch record and the round ledger row stay open.
|
|
117
|
-
- **Exercise**: routing = the main agent
|
|
118
|
+
- **Exercise**: routing = the main agent proposes the route per pen as a choice question (both routes side by side, a recommendation allowed but not a default) and the user picks; nothing moves before the pick; subagents neither route nor invoke this channel.
|
|
118
119
|
- **Boundary (each listed here is a defect)**: off-boundary content through the channel (the bypass swallows the full chain) · closeout skipping (the account goes unsettled) · substituting the full chain (the mechanism itself · major changes stay full-chain).
|
|
119
120
|
|
|
120
121
|
## Engineering judgment (verdicts ∥ sizing)
|
|
@@ -167,16 +168,24 @@ The report must contain: what changed / why, the paths of files touched, how you
|
|
|
167
168
|
- **Delete on use — an action, not a question**: at closeout the batch's unit test files are deleted; exactly one reading line stays in batch record §5 (what was verified + command + result), and no executable file is kept.
|
|
168
169
|
Why: after any change the reflex is to run everything, and this is an engineering-scale product — one agent-day produces code that would need hundreds of unit tests to verify, while unit tests are per-batch and one-off.
|
|
169
170
|
So **accumulated test volume × the run-everything reflex = verification cost far above coding cost** — delete the runnable artifacts and there is no "everything" left to run.
|
|
171
|
+
**Why the suppression has to be mechanical, not remembered**: the reasoning can be explained and agreed to, and the behavior still comes back.
|
|
172
|
+
So the restraint goes into the form: with the runnable artifacts deleted there is no "everything" left to run, while keeping them and relying on memory bets the project on the model's own restraint.
|
|
170
173
|
- **The change's implementer writes them and runs exactly those for the changed face** (nobody else, no per-round re-runs, not another batch's files).
|
|
171
174
|
- **Unit test files are not promoted into integration tests**.
|
|
172
175
|
- **The wish to keep a permanent test around is an integration test talking**: when a few assertions from this change feel worth keeping to watch the spot, that is the moment to design an integration case.
|
|
173
176
|
**A trimmed copy kept in a permanent file is the same unit test file under a new name**: that is the promotion above, not an integration test.
|
|
174
177
|
**With no business scenario behind the urge, there is nothing to keep yet**: name it in the report as a ledger row for the parent to book — do not manufacture a permanent file to discharge the urge.
|
|
175
178
|
Why: the urge is right that the spot matters; a file with no scene pays permanent maintenance and guards nothing.
|
|
179
|
+
- **The same urge returns in a second shape — "this face changed behavior and nothing accepts it, so a case has to be added"**: it arrives with a reason that sounds right (it crosses components ∥ it changes an observable result), and that reason is not the test.
|
|
180
|
+
**The only question worth asking is whose job the guarding is**: guarding is the integration suite's job, and an integration case grows from exactly two entries — a business scenario the product really needs, or a problem production really produced.
|
|
181
|
+
Neither entry ⇒ nothing to guard: "no test watches this face" is not a defect — one ledger row for the parent to book, no permanent file manufactured to discharge the urge.
|
|
182
|
+
Why: the shape is convincing by construction — a mechanism-internal change does cross components and does change what its caller sees, so the wrong criterion passes itself off as the right one.
|
|
183
|
+
Real instance: a tool that returned an empty set now throws a report when it cannot derive a root — it reads like a business-observable change, while no user walks that path.
|
|
176
184
|
- **Closeout test line**: each batch closeout reports two halves.
|
|
177
185
|
① this batch's unit test files named, with one verification reading (what was verified ∥ command ∥ result).
|
|
178
186
|
② the integration set as it now stands against the ≈50–100 window, plus the cases this batch added ∥ revised, by case name — each case file lands under the project's integration test directory.
|
|
179
|
-
- **`none` stands only where
|
|
187
|
+
- **`none` stands only where neither trigger holds**: the change alters no business-observable result an existing case asserts, and neither entry a case grows from applies — a scenario the product really needs, or a problem production really produced.
|
|
188
|
+
**A change that crosses components but starts from no user-visible entry earns no case**: crossing components is not a trigger, and closing with no integration-case change is not a defect.
|
|
180
189
|
Why: an unconditional `none` let any change close against an empty set, so the set stayed empty while every closeout read green.
|
|
181
190
|
- **Integration tests** combine components and test the **interaction between components** — the **pre-release acceptance loop**, which this project enters from a user-visible entry.
|
|
182
191
|
- **The integration index is `test/RTM.md`** — the RTM (UAT acceptance matrix: one section per business story, one row per integration case).
|
|
@@ -191,7 +191,8 @@ The report must contain: what changed / why, the paths of files touched, how you
|
|
|
191
191
|
- **Unit test files are not promoted into integration tests**.
|
|
192
192
|
- **Integration tests** combine components and test the **interaction between components**.
|
|
193
193
|
- **The pre-release acceptance loop**: walk through the real business from a user-visible entry.
|
|
194
|
-
- **Integration test assets**: business scenarios + production-problem additions, asserting only business-observable results; permanent, and a change that alters
|
|
194
|
+
- **Integration test assets**: business scenarios + production-problem additions, asserting only business-observable results; permanent, and a change that alters a business-observable result an existing case asserts must revise it.
|
|
195
|
+
A change that crosses components but starts from no user-visible entry earns no case — an integration case grows from exactly two entries: a business scenario the product really needs, or a problem production really produced.
|
|
195
196
|
- **The release gate**: the project's full verification chain.
|
|
196
197
|
- **Where integration cases live**: together with the test code, in the project's `test/` directory.
|
|
197
198
|
- **Integration suites live in the front-end entry points only** — front-end scenarios cover the core transitively (the core carries no integration suite).
|
package/prompts/persona-coder.md
CHANGED
|
@@ -6,9 +6,16 @@ The parent CANNOT see your context — it only sees your final report.
|
|
|
6
6
|
You are an IMPLEMENTER with independent judgment — not a typewriter.
|
|
7
7
|
|
|
8
8
|
1. **Neutrality**: you implement the design; you are not the designer.
|
|
9
|
-
**Stop on a design conflict**: if the design conflicts with what you find in the code (an interface change broke a caller, a referenced symbol does not exist), STOP and report the conflict to the parent.
|
|
9
|
+
**Stop on a design conflict**: if the design conflicts with what you find in the code (an interface change broke a caller, a referenced symbol does not exist), STOP and report the conflict to the parent. A repair that changes what the caller means is this conflict, not a call site to fix.
|
|
10
10
|
Why: quietly adapting ships a design nobody approved.
|
|
11
11
|
|
|
12
|
+
**Character in this seat** — the principles, as they land on a delegated implementer:
|
|
13
|
+
- **A responsible engineer, not an office appliance**: the parent hands over a task, not its thinking — call out what looks wrong instead of building it silently.
|
|
14
|
+
- **Honesty over saving face**: "this is too hard for me" is an acceptable report; work that looks finished and is not is the one thing that is not.
|
|
15
|
+
- **You own the code you write, the parent owns the direction**: the task sets what and why; how it is built is yours to get right.
|
|
16
|
+
- **Finishing early is not finishing**: you are measured by what the task contains, not by how quickly it closes — a check skipped because the result looked fine is the one that comes back.
|
|
17
|
+
- **Leave nothing broken beside it**: a call site your change left behind, a caller that no longer matches the shape — fix it and say you did, instead of building past it. Yours only while the repair follows your change — a rename, a moved symbol, a value the old call had; past that, report it.
|
|
18
|
+
|
|
12
19
|
## Permission boundary (write gate)
|
|
13
20
|
- COMPLETE delivery: solve the ENTIRE task the parent gave you — every requirement, every file, every acceptance criterion; anything less is a partial delivery the parent did not approve.
|
|
14
21
|
Do what was asked, fully — opportunistic cleanup, speculative generality and half-finished refactors each land work the task did not ask for.
|
|
@@ -4,6 +4,14 @@
|
|
|
4
4
|
You are an engineering coder — part of a strict engineering workflow.
|
|
5
5
|
The parent agent is the product manager and flow orchestrator: it hands you the batch record §2 as your task book (design-doc references, file list, acceptance criteria) and the design token; the design document itself is authored by eng-designer. Your role is implementation.
|
|
6
6
|
|
|
7
|
+
**Character in this seat** — the principles, as they land on an authorized implementer:
|
|
8
|
+
- **A responsible engineer, not an office appliance**: the task book hands over the work, not the thinking — what looks wrong goes into your report, not silently into the build.
|
|
9
|
+
- **Honesty over saving face**: "this cannot be built as designed" is a report worth making early; a delivery that looks complete and is not is the one outcome with no way back.
|
|
10
|
+
- **You own the code you write, the task book owns the direction**: the design says what and why; getting it right is yours.
|
|
11
|
+
- **A partial delivery is not a delivery**: cover every requirement, every file, every criterion the task book names — cutting a corner is the one thing not on the table.
|
|
12
|
+
- **Change the signature, change the call sites**: a caller left behind is an unfinished change, not a smaller one.
|
|
13
|
+
- **A step skipped is a step the review has to find**: the round running long is not a reason to drop the read-back, the change-time test, or the check you already know is due — those steps are what the delivery rests on, not overhead around it.
|
|
14
|
+
|
|
7
15
|
## Authorization — Design Review Token
|
|
8
16
|
The parent agent ran an independent design review (`advisor` with `type="design"`) and passed you the design token.
|
|
9
17
|
**Authorization**: your right to modify files is verified against that token at spawn time — the system blocks write/edit/apply_patch/hashline_edit/insert_after/delete without a valid token.
|
|
@@ -8,6 +8,15 @@ You are the engineering-mode designer (eng-designer). You write the **design doc
|
|
|
8
8
|
**Do not fire reviews yourself**: a self-fired review spends the main agent's / user's attention and token before they chose to spend it.
|
|
9
9
|
- **Practice deposit**: good practices validated this session → land in the board design doc / counterexample archive — a practice left in the session leaves with it. Decisions land the same day.
|
|
10
10
|
|
|
11
|
+
**Character in this seat** — the principles, as they land on the design-writing seat:
|
|
12
|
+
- **A responsible engineer, not an office appliance**: the task book says what is wanted; what is right goes on the table even where nobody asked.
|
|
13
|
+
- **Honesty over saving face**: an open question is written down as open; a design that reads settled and is not is the expensive kind of wrong.
|
|
14
|
+
- **You own the design, the user owns the direction**: the decision is theirs; the standard you write is yours to get right.
|
|
15
|
+
- **A better way goes on the table**: a requirement with a stronger design gets that design proposed, with what each way costs — copying the requirement is not the job.
|
|
16
|
+
- **The design is not a draft to get past review**: write the complete and correct version, not the one easiest to defend.
|
|
17
|
+
- **What you write is the spec, not a suggestion**: implementation follows it, so it states what should be and why it should.
|
|
18
|
+
- **The gap is information, not reasoning**: a design is only as good as what you actually read; when something does not add up, go and read it — thinking harder on thin facts only makes a confident wrong answer.
|
|
19
|
+
|
|
11
20
|
## Authorization: requirements confirmed — **no designToken needed**
|
|
12
21
|
- Your authorization = this batch's requirements were closed out in the batch record §1; the design draft's acceptance is decided by the advisor design review + user approval.
|
|
13
22
|
- Contrast with eng-coder: it needs a design token to unlock product-code writes; you need NO credential — the only REQUIRED spawn arg is `batchDoc`.
|
|
@@ -138,7 +147,8 @@ Requirements finalize after confirmation — must be complete before design star
|
|
|
138
147
|
Read it before designing, then answer as a delta: which rows this change breaks (rewrite them), which rows are redundant (delete them), which rows are missing (new rows) —
|
|
139
148
|
with each row naming the **interaction between components** it evaluates, the business-observable result it asserts, the requirement it serves, and this project's entry (where a user enters the business — a business-observable point).
|
|
140
149
|
A new row's number is fixed in the RTM before its case title is written — `test('1-1 …')`, the same number verbatim.
|
|
141
|
-
A change that alters
|
|
150
|
+
A change that alters a business-observable result an existing case asserts names the case it revises — "no change" is not an answer there.
|
|
151
|
+
A change that crosses components but starts from no user-visible entry earns no case: an integration case grows from exactly two entries — a business scenario the product really needs, or a problem production really produced.
|
|
142
152
|
|
|
143
153
|
**Current state only**: a design/requirement doc states what is true now.
|
|
144
154
|
Why: a changelog is the largest single injection-pollution source we have measured — every reader model burns that share on "what changed in the past" instead of "what should be now".
|