atlas-project-harness 0.2.0-beta.22 → 0.2.0-beta.24
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 +36 -0
- package/DESIGN.md +4 -0
- package/README.md +6 -5
- package/package.json +1 -1
- package/rings/e2e/reference.md +12 -7
- package/rings/prd/reference.md +4 -3
- package/scripts/__pycache__/e2e_console.cpython-312.pyc +0 -0
- package/scripts/__pycache__/gen_e2e_scripts.cpython-312.pyc +0 -0
- package/scripts/__pycache__/make_review_inputs.cpython-312.pyc +0 -0
- package/scripts/e2e_console.py +296 -14
- package/scripts/gen_e2e_scripts.py +189 -52
- package/scripts/make_review_inputs.py +41 -3
- package/shared/gates.md +8 -5
- package/shared/independent-review.md +1 -0
- package/templates/e2e/console/app.js +2 -2
- package/templates/e2e/e2e-index.md +5 -5
- package/templates/prd/domain.md +5 -3
- package/tests/__pycache__/test_atlas_check.cpython-312-pytest-9.1.1.pyc +0 -0
- package/tests/__pycache__/test_atlas_verify_playground.cpython-312-pytest-9.1.1.pyc +0 -0
- package/tests/__pycache__/test_e2e_console.cpython-312-pytest-9.1.1.pyc +0 -0
- package/tests/__pycache__/test_gen_e2e_scripts.cpython-312-pytest-9.1.1.pyc +0 -0
- package/tests/__pycache__/test_gen_e2e_scripts.cpython-312.pyc +0 -0
- package/tests/__pycache__/test_map_anchors.cpython-312-pytest-9.1.1.pyc +0 -0
- package/tests/__pycache__/test_map_anchors.cpython-312.pyc +0 -0
- package/tests/__pycache__/test_validators.cpython-312-pytest-9.1.1.pyc +0 -0
- package/tests/__pycache__/test_validators.cpython-312.pyc +0 -0
- package/tests/fixtures/verify_playground/product/e2e/reviews/2026-01-01-fixture/inputs/MANIFEST.json +13 -0
- package/tests/fixtures/verify_playground/product/e2e/reviews/2026-01-01-fixture/review.json +6 -9
- package/tests/test_atlas_check.py +64 -0
- package/tests/test_atlas_verify_playground.py +2 -0
- package/tests/test_e2e_console.py +173 -27
- package/tests/test_gen_e2e_scripts.py +194 -0
- package/tests/test_map_anchors.py +1 -1
- package/tests/test_validators.py +325 -0
- package/validators/__pycache__/validate_e2e_index.cpython-312.pyc +0 -0
- package/validators/__pycache__/validate_prd.cpython-312.pyc +0 -0
- package/validators/validate_e2e_index.py +88 -9
- package/validators/validate_prd.py +67 -0
- package/skills/atlas-release/SKILL.md +0 -126
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,42 @@
|
|
|
4
4
|
|
|
5
5
|
---
|
|
6
6
|
|
|
7
|
+
## [v0.2.0-beta.24] - 2026-10-30
|
|
8
|
+
|
|
9
|
+
### 🧭 E2E 容忍前提措辞 + PRD 派生字段默认语义(issue #47,D176)
|
|
10
|
+
|
|
11
|
+
* **新增(E2E 文本期门)**:`validate_e2e_index.py` 新增「容忍前提措辞」WARN——`step`/`expected` 注释尾巴与 `precondition` 命中 `存量` / `可能停在` / `视情况` / `随机` / `取决于历史` ⇒ WARN;行内 `容忍: <理由>` 豁免;本项**刻意读注释**(契约 §5.5 唯一例外),代码部分不扫(业务文案不误报)。
|
|
12
|
+
* **新增(PRD 门)**:`validate_prd.py` 新增「派生字段默认语义」WARN——字段规范表可选列 `派生/重置`(表头前缀匹配;模板默认带列,存量无列 = N/A)所声明的字段须在 §六 有一行含该字段名且「采用的默认值」非空;独立 check 行,不并入参数 4 聚合。
|
|
13
|
+
* **契约 / 模板**:`rings/e2e/reference.md` §5.5 + §8.2;`rings/prd/reference.md` §3 字段规范 / §六 / §7 附加机器检查;`templates/prd/domain.md` 字段表可选列。
|
|
14
|
+
* **测试**:`tests/test_validators.py` 180 → 182;变异 M160a–d 四段协议(摘词表 / 改扫代码 / 恒 N/A / 只认列)全咬、还原逐字节一致。
|
|
15
|
+
* **设计**:`DESIGN.md` D176。
|
|
16
|
+
|
|
17
|
+
## [v0.2.0-beta.23] - 2026-10-30
|
|
18
|
+
|
|
19
|
+
### 🧭 登记测试有效性与 CRAP 候选观测面(D175)
|
|
20
|
+
|
|
21
|
+
* **新增**:`shared/gates.md` §3 新增两个候选观测面缺口行:「测试 ⇔ 生产代码变异(变异得分)」「实现代码 ⇔ 覆盖×复杂度(CRAP)」,§4 新立「候选观测面(非门)」小节登记。来源 = ub-mode(Uncle Bob)变异测试 / CRAP 分数思想。
|
|
22
|
+
* **非门**:候选形态 WARN/N-A,不建 FAIL 门、不进 `atlas_check`、不装工具进 Atlas 依赖;升格条件 = 真实仓**副本**试跑信噪比证据。与 M 系列变异钉正交(M 向判据注入脏数据,变异测试篡改生产代码考测试)。
|
|
23
|
+
* **试跑收口(同日)**:go/no-go 已过——三工具原生支持六语言(文章「Python 生态、TS 需换 StrykerJS」有误);Python 夹具三工具全通;cn-console TS 副本与 nanwang Java 副本 crapper/dryer/mutator 均实测通过(Java 变异 84.6%、~6.6s/变异体);全部跑在一次性 /tmp 副本(原目录只读)。**已拍板采纳为 WARN 级观测面**:crapper/dryer 全仓扫描(按第一方范围圈定)+ mutator 按批 `--changed` 触发,仍非门。
|
|
24
|
+
* **同步面**:`DESIGN.md` D175、`docs/map/gates.md` 与 `docs/map/atlas-map.html` 行数锚(149 → 152 行)。
|
|
25
|
+
|
|
26
|
+
### 🧷 评审重审范围收敛到「真正变化的内容」(D174)
|
|
27
|
+
|
|
28
|
+
* **改进**:控制台评审陈旧度从「HEAD 指针 + 整目录 `scripts_hash`」改为**逐用例内容指纹**。只改一条 test ⇒ 只有该条需重审;同文件块外代码变化 ⇒ 该文件其余用例需重审;共享脚本(spec / config / setup / prepare 的静态 import 闭包)或应用代码内容变化 ⇒ 全部需重审。commit 与提交账本本身不再作废评审。
|
|
29
|
+
* **指纹形状**:逐用例快照落 `prov.fp = {script, block, rest, shared, app}`;应用代码读**工作区内容**(git 已跟踪 + 未忽略新文件,排除 E2E 环 / `.atlas` / `node_modules` / `*.md`);未被引用的探针脚本不参与;相对 import 解析不出 ⇒ 保守回退全部非 spec 脚本。
|
|
30
|
+
* **兼容**:旧账本条目(无 `fp`)沿用 D128 的 HEAD + 全局散列口径(fail-closed),重新评审提交后升级。
|
|
31
|
+
* **测试**:`tests/test_e2e_console.py` 25 → 28。
|
|
32
|
+
* **契约 / 设计**:`rings/e2e/reference.md` §10.1、`DESIGN.md` D174、`shared/gates.md`、`docs/innovations/e2e-console.md` §5、`docs/map` 行数与锚。
|
|
33
|
+
|
|
34
|
+
### 🛡️ E2E 审查门输入指纹 + 页面级覆盖就绪(issue #48 / #49)
|
|
35
|
+
|
|
36
|
+
* **修复(#48)**:`gen_e2e_scripts.py` 的独立审查门在读取最新报告 `status` 之外,核对 `inputs/MANIFEST.json` 与本次待生成分片的 `sha256`;分片在审查后变化 ⇒ `stale`,`--apply` 拒绝写盘。`basis: auto-baseline` 的报告不再与真审同权,只在 `origin: adopt` / `e2e.review.mode: auto-baseline` 显式通道放行(WARN)。
|
|
37
|
+
* **修复(#49)**:页面表新增可选 `覆盖就绪` 列(`是/否/—`);`是` 让「实现中」页参与 AC 反向覆盖与 AC×覆盖维度对账,缺列 / `—` 回落 `实现状态 == 已实现`;零挂靠 AC 无页归属,反向覆盖门仍要求域内全部页覆盖就绪(避免误报),有页级用例的 AC 与维度门按页级 ready。`validators/validate_e2e_index.py` 的两道追溯门从「域全已实现」改为页级 ready;模板 / 契约同步。
|
|
38
|
+
* **测试**:`tests/test_gen_e2e_scripts.py` 118 → 124;`tests/test_validators.py` 168 → 180;`tests/test_atlas_check.py` 48 → 49。
|
|
39
|
+
* **契约 / 设计**:`rings/e2e/reference.md` §3.2 / §8.2 / §12.6、`shared/independent-review.md` §4、`templates/e2e/e2e-index.md`、`DESIGN.md` D173、`shared/gates.md` 计数。
|
|
40
|
+
|
|
41
|
+
---
|
|
42
|
+
|
|
7
43
|
## [v0.2.0-beta.22] - 2026-10-30
|
|
8
44
|
|
|
9
45
|
### 🧭 FAIL 修复指引试点(RFC-20261030-01)
|
package/DESIGN.md
CHANGED
|
@@ -646,6 +646,10 @@ adapters:
|
|
|
646
646
|
| D170 | **Go 结构适配器(API / 测试清单 / 模型)(Batch D3b)**(2026-10-29;`adapters/api.py`、`adapters/tests.py`、`adapters/models.py`) | ① **病灶**:Go 后端的 `api` / `tests` / `models` 事实只能 agent 手写,结构↔代码对账缺口大。② **定案**:`api.py` 识别 gin/echo/chi/net/http 常见注册(`r.GET`、`http.HandleFunc("GET /x")`、`mux.HandleFunc("/x")`);无动词记 `ANY`,`_test.go` 不扫。`tests.py` 盘点 `*_test.go` + `go.mod`,命令 `go test ./...`;其它配置族冲突置 null + WARN。`models.py` 解析 Go struct 的 `gorm`/`json`/`db` tag(主键/自增/非空/唯一/size/column、`TableName()`),不猜表名。③ **被否**:Go AST/JavaParser(行级正则足够);按 `.Any` 猜具体动词(记 ANY);内置 Go AC extractor(v1 用 `extractor_command` 外部适配器,避免再铺一套测试标记 parser);Go 内嵌 struct/接口纳入 v1(边界明示)。④ **钉**:`tests/test_adapter_api.py` 9 条(Go 路由/注释忽略);`tests/test_tools.py` 31 条(Go 命令/配置冲突);`tests/test_adapter_models.py` 12 条(Go struct/tag/TableName/_test.go 排除);变异 **M-GO1/M-GO2/M-GO3** 均咬,逐字节还原一致。⑤ **边界**:Go AC 门需 `extractor_command`(无内置 Go AC extractor);Go 内嵌 struct/接口/多 backend app 逐 app 归属不在 v1;Kotlin/TestNG 不在 v1。 |
|
|
647
647
|
| D171 | **真实仓烟测修复:`.scratch` / MyBatis-Plus / NestJS-Midway**(2026-10-29;`adapters/_lib.py`、`adapters/_jpa.py`、`adapters/api.py`) | ① **病灶(真实仓复现)**:Java 仓 `.scratch/` 下的影子测试被当测试源(182→166 的重复事实);MyBatis-Plus `@TableName` 实体不被 JPA 解析器识别(0 张表),且 getter 的 `return id;` 被误当字段(`type=return`、重复行);NestJS/Midway `@Controller` + `@Get` 控制器产出 0 端点。② **定案**:共享忽略集补 `.scratch`/`target`/`.gradle`/`.idea`;`_jpa.py` 支持 `@TableName`/`@TableId`/`@TableField`、普通基类字段合并(仅 MyBatis entity)、跳过 `return/throw/...` 行;`api.py` 新增 `@Controller(prefix)` + `@Get/@Post/.../@All` 路由(无动词 `ANY`)。③ **被否**:把 `.scratch` 当合法测试源;继续只认 JPA(真实仓是 MyBatis-Plus);用裸 `@Get` 全仓扫描(只处理含 `@Controller` 的 TS/JS 文件)。④ **钉**:`tests/test_tools.py` 33 条(`.scratch` / `.atlas` 排除);`tests/test_adapter_models.py` 14 条(MyBatis 表/基类字段/getter 不产 `return` 行);`tests/test_adapter_api.py` 10 条(NestJS 控制器);变异 **M-REAL1..3** 均咬,逐字节还原。真仓烟测:nanwang AC 1/1 PASS、MyBatis 数据模型生成;cn-console AC 1/1 PASS、API 51 条、测试 20 条、`atlas check --fast` 无失败。⑤ **边界**:`.scratch` 是项目约定(不保证别名);MyBatis XML/注解 SQL 不产模型;NestJS DTO `class` 未纳入 TS 模型(真实 core 无 DTO 类,暂不铺)。 |
|
|
648
648
|
| D172 | **api 适配器运行时 schema 只认构造调用(AST)**(2026-10-29;issue #46) | ① **病灶**:`SCHEMA_MARKERS` 按原始文本匹配 `.py`,任何文件里的 `APIRouter(`/`FastAPI(` 字面量——适配器自身注释、自身正则源码、测试夹具字符串——都被当成框架事实 ⇒ 输出 `spec_entry="/openapi.json"` + `items=0` 的**假阳性指针**(仓内无描述文件,且 `refresh_structure`/`validate_structure` 会把它当合法指针接线)。issue 上报的另一半「`_lib.IGNORE_DIRS` 未排除 `.atlas/.trellis`」已随 D171 落地(带回归钉)。② **定案**:判定改走 AST——`ast.Call` 的 `func` 为 `Name`/`Attribute` 且名字 ∈ {`FastAPI`,`APIRouter`}(含 `from fastapi import FastAPI as App` 的别名展开);注释/文档字符串/字符串字面量天然不是 `Call`。文本预筛(不含标记名不解析)控开销;解析失败(py2/非法源码)WARN 跳过该文件,**不回退文本匹配**(回退即把缺陷带回;跑不起来的文件不构成运行时 schema 证据)。测试文件(`tests?/`、`test_*.py`、`*_test.py`、`conftest.py`)整类不作描述源判定——夹具里真起一个 app 也不是产品接口面。共享忽略集补 `.adapter-out`。③ **被否**:按路径豁免扫描器自身(挡不住把适配器源码拷进项目的形态);把源码枚举根限定 `apps[].path`(生产本就按 `--app` 调用,根级 `path: .` 的 app 触发面不变;§3.5「整项目」只约束**描述文件**探测);语法错误回退文本正则;`openapi_url=None` 等框架细节(登记边界不铺)。④ **钉**:`tests/test_adapter_api.py` +3(真构造调用仍产指针 / 别名构造 / 注释+字符串+夹具+适配器源码拷贝不产指针)+ `.adapter-out` 夹具入既有排除钉。⑤ **同步面**:`shared/stack-profile.md` §3.5、`adapters/api.py` 注释、map 行数锚。 |
|
|
649
|
+
| D173 | **E2E 审查门输入指纹 + 页面级覆盖就绪(issue #48 / #49)**(2026-10-30;`scripts/gen_e2e_scripts.py`、`validators/validate_e2e_index.py`) | ① **病灶**:审查门只读最新报告 `status`,旧 PASS 可为新分片放行;baseline 报告与真审同权;AC 覆盖门以「域内页面全已实现」为前提,长期「实现中」的增量页整域跳过。② **定案**:报告 `inputs/MANIFEST.json` 对本次待生成分片逐一核对 `sha256`,不匹配判 `stale`;baseline 只在 `origin: adopt` / `e2e.review.mode: auto-baseline` 显式通道放行;页面表加可选 `覆盖就绪` 列(`是/否/—`),`是` 让实现中页参与 AC 反向覆盖与维度门,缺列回落 `实现状态 == 已实现`;零挂靠 AC 无页归属,反向覆盖门仍要求域内全部页覆盖就绪(避免误报),有页级用例的 AC 与维度门按页级 ready。③ **被否**:用 mtime 判陈旧(checkout/编辑器保存会误伤);只按报告 `scope` 字符串匹配用例 ID(多页增量无法精确);强制整页全量复审(成本过高)。④ **钉**:`tests/test_gen_e2e_scripts.py` +6(stale / 缺 manifest / baseline 非同权 / stale 自愈 / 输入清单边界 / 同日真报告复用基线);`tests/test_validators.py` +12(覆盖就绪参与/跳过/词表/维度 + mixed-page 2 + `已实现+否` 1 + mixed 零挂靠 1 + 备注列/全 `—` 混合 2 + 模板表头 1 + 多表头 1);`tests/test_atlas_check.py` +1(manifest cases_dir override);⑤ **边界**:`覆盖就绪` 是项目显式 opt-in,不替代 `实现状态`;测试分片以外的输入变更不纳入本指纹。 |
|
|
650
|
+
| D174 | **评审陈旧度改为逐用例内容指纹(用户 2026-10-30 拍板;`scripts/e2e_console.py`、`templates/e2e/console/app.js`、`tests/test_e2e_console.py`;契约 §10.1)** | ① **病灶**:D128 的 `scripts_hash` 是**整目录一个摘要** + `head_sha` 全局比较 ⇒ 改一条用例、提交一次账本都会把全部已审用例翻成 STALE。v3 现场:16:54 提交的 16 条,16:59 一次 commit 后全部 `HEAD变动`;工作区改一个 spec 又全部 `脚本变动`——「审过的还得全审」把重审成本推到不可用。② **定案**:评审指纹从「提交指针 + 目录摘要」改为**内容指纹**,逐用例落 `prov.fp = {script, block, rest, shared, app}`:`block` = 该 `test(...)` 行到下一个 `test(` 行的原文(只改一条 test ⇒ 只作废该条);`rest` = 同文件用例块之外的原文(imports / 文件内 helper 变化 ⇒ 该文件全部用例作废);`shared` = 从 spec / `playwright.config.ts` / `*.setup.ts` / `atlas-prepare.mjs` 出发**静态 import 闭包**可达的非 spec 脚本聚合散列(未被引用的探针不参与;相对 import 解析不出 ⇒ 保守回退全部非 spec);`app` = 应用代码**工作区内容**散列(git 已跟踪 + 未忽略新文件,排除 E2E 环 / `.atlas` / `node_modules` / `*.md`)——commit 与提交账本本身不再触发重审,只有内容真变才触发;用例换脚本文件或当前脚本里找不到 ⇒ 作废。旧账本条目(无 `fp`)沿用 D128 的 HEAD + 全局散列口径(fail-closed,重提交后升级)。③ **被否**:只做「按 spec 文件」而不区分单条(v3 最大文件装 33/58 条,仍不可用);按 mtime 判陈旧(checkout / 编辑器保存误伤);逐个脚本算应用哈希再全量比较(成本高且不解决连坐);未引用的探针也算共享(改探针会误伤全部用例);放弃代码变动校验但不引入内容指纹(丢「代码变了要复验」防线)。④ **钉与变异**:`tests/test_e2e_console.py` 25 → **28**——改写 `test_case_review_state_lifecycle`(HEAD / 全局散列变化仍 fresh;块 / rest / 共享 / 应用各自作废;换文件 / 找不到 / 旧条目回退)+ 新增 `test_case_fingerprints_slice_per_case_and_share_rest` / `test_shared_scripts_import_closure_ignores_unreferenced_probes` / `test_app_fingerprint_content_not_commits`(真实 git 靶场:commit 不失效、src 内容变才失效);变异 **M156**(摘 `fp` 分支 ⇒ lifecycle + submit 两钉红)/ **M157**(`rest` 恒空 ⇒ 切片钉红)/ **M158**(共享闭包改回全部非 spec ⇒ 探针钉红)/ **M159**(应用指纹退回 `head_sha` ⇒ 提交不失效钉红),四段协议还原逐字节一致(sha256 复核)。⑤ **边界**:块内文本按行切分(用例间夹层归前一条),「这条断言是否等价」仍归人;应用指纹只覆盖 git 工作区(非 git 项目记 null,跳过该维度);`e2e-index.md` 的用例定义变化不在本指纹(另行处理);旧账本条目在下一次评审提交前仍按 D128 口径显示 stale。 |
|
|
651
|
+
| D175 | **登记「测试有效性 / CRAP」候选观测面(用户 2026-10-30 拍板;`shared/gates.md` §3/§4)** | ① **病灶**:对账平面索引缺「测试有效性」与「复杂度×覆盖组合」两面——现行套件(含 M 系列变异钉)证明「判据/实现坏了测试会红」,未证明「测试能杀死生产代码变异」;覆盖率与复杂度单看各有盲区。② **定案**:按「少建投机硬门」先登记缺口不建门——§3 新增「测试 ⇔ 生产代码变异(变异得分)」「实现代码 ⇔ 覆盖×复杂度(CRAP)」两行候选观测面(❌ 缺口、**非门**),§4 另立「候选观测面(非门)」小节;来源 = ub-mode(Uncle Bob)思想;升格条件 = 真实仓**副本**试跑信噪比证据(原目录只读),升格形态 WARN/N-A、不设 profile 开关。③ **被否**:直接装 Crapper/Dryer/Mutator 进 Atlas 依赖并建 FAIL 门(投机硬门;三工具为 Python 生态,候选烟测仓 cn-console / nanwang 均无 Python);把变异测试写成 M 系列的「工具化对偶」(两者**正交**:M 系列向判据注入脏数据,变异测试篡改生产代码考测试)。④ **钉**:纯文档登记,无新机器判据;行数锚同步(`docs/map/gates.md` / `atlas-map.html`,149 → 152 行)。⑤ **边界**:试跑批(语言 go/no-go 最小夹具 → 真仓副本信噪比报告 → 升格/搁置/退役)另行确认后执行;本登记不构成任何门的取证。**试跑收口(2026-10-30 同日,用户拍板「跑吧」)**:go/no-go 已过——三工具原生支持 Clojure/Java/Go/TypeScript/Rust/Python(②③里「Python 生态、需换 StrykerJS / PIT」系转述 ub-mode 文章的错误说法,实测推翻);Python 夹具三工具全通(CRAP 公式手算核对 17.2、重复对 score=1.00 指名、kill/survive/uncovered 三态正确);cn-console TS 副本:crapper 10.7s 全仓 248 函数(vendor `cn-cdn` 霸榜信噪比注意点,第一方 69 函数最高 CC=8)、dryer 0.8 阈值零重复、mutator kill 1/1(3.7s;薄胶水文件 0 变异位;绿基线套件 8/18,本仓单测仅 9 条);nanwang Java 副本:crapper 1.2s 3086 函数(65 个 CC≥10,榜首 `DmSqlScriptParser.parse` CC=41)、dryer 咬出真实仓储层重复对(0.80–0.81)、mutator 实测 `PeriodUtil` 13 位点 11 杀 2 活(84.6%,`currentForecastPeriod` 2 存活 ⇒ 测试虚;**~6.6s/变异体**——mvn 冷启动,须 `-Pskip-frontend` + `mvnw`(系统 mvn 3.6.1 过旧),成本证实只可窄域按批、不可全仓常开)。安装障碍:本机 npm `allow-remote=none` 拦 lockfile remote 依赖 ⇒ 经用户拍板在一次性 /tmp 副本 `--allow-remote=all --ignore-scripts` 覆盖。**升格建议(待拍板):crapper/dryer 全仓扫描作 WARN 观测 + mutator 按批 `--changed` 触发,仍非门。已拍板采纳(2026-10-30 同日):按建议采纳为 WARN 级观测面——crapper/dryer 全仓扫描按第一方范围圈定(vendor 霸榜实测教训)+ Dryer 阈值 0.8(非默认 0.82)+ mutator 按批 `--changed`;仍非门、不进 `atlas_check`、不装进 Atlas 依赖,仅登记为采用者操作侧可选观测动作。** |
|
|
652
|
+
| D176 | **#47 落地:E2E 容忍前提措辞 WARN + PRD 派生字段默认语义 WARN(用户 2026-10-30 拍板「要做」;`validators/validate_e2e_index.py`、`validators/validate_prd.py`、`rings/e2e/reference.md` §5.5/§8.2、`rings/prd/reference.md` §3/§六/§7、`templates/prd/domain.md`)** | ① **病灶**:应然资产没有为「用户可编辑 + 系统派生/重置」字段定义默认/重置语义时,字段行为天然无 AC;E2E 用例把「实现现在恰好是什么」写成合法前提(step 注释「存量行可能停在 X」+ expected 仅 visible),旧状态长期为绿;PRD §六 虽要求默认值,但无机制强制。② **定案**:两条独立 WARN(不建 FAIL 门,不并入参数 4 聚合)——**A 容忍前提措辞**:`step`/`expected` 注释尾巴 + `precondition` 全文命中词表(存量 / 可能停在 / 视情况 / 随机 / 取决于历史)⇒ WARN,行内 `容忍: <理由>` 豁免;本项**刻意读注释**(§5.5「机器忽略 `#` 之后」的唯一例外,契约已写明),代码部分不扫(业务文案不误报)。**B 派生字段默认语义**:PRD 字段规范表可选列 `派生/重置`(表头前缀匹配、不绑列位置;模板默认带列,存量无列 = opt-in N/A),列非空的字段须在 §六 有一行含字段名且「采用的默认值」非空,缺 ⇒ WARN 逐字段指名(`—` / `无` / 空视为未声明)。③ **被否**:升 FAIL(首版证据不足,`3509 §B36` 过早严判教训);按 `FN-*` 小节定位字段表(仓库无该结构 ⇒ 0 命中空门,评审抓出);把 WARN 并入参数 4 聚合(会被参数 4 升 FAIL,与 WARN 首版冲突);issue 建议 ③「共享靶场前置复位约定」不进 v1(先让声明与用例两端可见)。④ **钉**:`tests/test_validators.py` 180 → **182**;变异 **M160a**(摘词表匹配)/ **M160b**(改扫代码不扫注释)/ **M160c**(判据恒 N/A)/ **M160d**(只认列不查 §六)四段协议全咬、还原逐字节一致。⑤ **边界**:容忍理由「够不够」、派生默认值的业务正确性均归独立审查;`precondition` 说谎(语义)仍不查;列存在但全 `—` ⇒ PASS(声明过、零派生)。 |
|
|
649
653
|
---
|
|
650
654
|
|
|
651
655
|
## 13. 待实现事项
|
package/README.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# Atlas — 践行 Project Harness 的全流程 AI 编程工作流
|
|
2
2
|
|
|
3
3
|
<p align="left">
|
|
4
|
-
<img src="https://img.shields.io/badge/version-0.2.0--beta.
|
|
4
|
+
<img src="https://img.shields.io/badge/version-0.2.0--beta.24-blue.svg" alt="Version" />
|
|
5
5
|
<img src="https://img.shields.io/badge/license-Apache--2.0-blue.svg" alt="License" />
|
|
6
6
|
<img src="https://img.shields.io/badge/tests-passing-success.svg" alt="Tests" />
|
|
7
7
|
<a href="https://sunwenzhe-git.github.io/atlas/"><img src="https://img.shields.io/badge/docs-VitePress-green.svg" alt="Docs" /></a>
|
|
@@ -313,10 +313,11 @@ Atlas 随包自带了一个**纯 Python 标准库编写的本地轻量级可视
|
|
|
313
313
|
* 向 `<资产根>/e2e/reviews/console/events.jsonl`(默认 `product/e2e/reviews/console/events.jsonl`)追加一条不可篡改的事件快照;
|
|
314
314
|
* 派生人读的 `ledger.md` 评审账本;
|
|
315
315
|
* 原子回写总索引 `<资产根>/e2e/e2e-index.md`(默认 `product/e2e/e2e-index.md`)的状态列。
|
|
316
|
-
5.
|
|
317
|
-
*
|
|
318
|
-
*
|
|
319
|
-
*
|
|
316
|
+
5. **评审指纹与陈旧度(内容一变,勾就作废;无关改动不连坐)**:
|
|
317
|
+
* 逐用例快照绑定内容指纹 `prov.fp = {script, block, rest, shared, app}`——**人审的到底是哪一版,账本自己说得出**;
|
|
318
|
+
* 只改一条 test ⇒ 只作废该条;改同文件块外代码 ⇒ 该文件其余用例作废;共享脚本(spec/config/setup/prepare 的静态 import 闭包)或应用代码内容变 ⇒ 全部作废;commit 与提交账本本身不作废评审;
|
|
319
|
+
* 指纹**对运行期产物免疫**(`test-results/`、trace、截图一律不入指纹),不会跑一轮就假漂移;
|
|
320
|
+
* 控制台按当前指纹实时复算 `review_state` 四态:`fresh`(有效)/ `stale`(上述内容已变 ⇒ 标红「需重审」、禁勾、不计已评审)/ `legacy`(旧账本无指纹,不冒充已核验)/ `unreviewed`;
|
|
320
321
|
* 重新执行一条用例会**自动清空它的旧勾选**——杜绝「上次审过」挂在新的执行结果上;
|
|
321
322
|
* 顶栏单列「需重审」计数,「只看未评审」筛选同样把 stale/legacy 一并捞出来。
|
|
322
323
|
|
package/package.json
CHANGED
package/rings/e2e/reference.md
CHANGED
|
@@ -73,8 +73,10 @@ product/e2e/
|
|
|
73
73
|
|
|
74
74
|
`e2e-index.md` 含三张表。**页面表**(E1 起,页 ↔ 路由 ↔ **实现状态**的唯一真相源,生成器 URL 的唯一来源)列(顺序固定):
|
|
75
75
|
|
|
76
|
-
| 页面 | 路由 | 域 | 实现状态 |
|
|
77
|
-
|
|
76
|
+
| 页面 | 路由 | 域 | 实现状态 | 覆盖就绪(可选) |
|
|
77
|
+
|---|---|---|---|---|
|
|
78
|
+
|
|
79
|
+
**`覆盖就绪`(可选第 5 列,2026-10-30,issue #49)**:`是` / `否` / `—`(空同 `—`)。`是` ⇒ 即使 `实现状态` 为 `实现中` / `未开始`,该页也参与 AC 反向覆盖与 AC×覆盖维度对账;`否` ⇒ 显式不参与(含 `已实现` 页);缺列 / `—` ⇒ 回落到 `实现状态 == 已实现`(存量项目行为不变)。**出现该列即切页级作用域(即使全 `—`);只有缺列才保留旧域级判据。`—` 只是逐页值的回落,不是作用域开关。** 该列只影响追溯门的作用域,不改变 testid 双向集合门与 `实现状态` 的判据。
|
|
78
80
|
|
|
79
81
|
(`页面` = slug;`路由` **以 `/` 开头**且全表唯一,**可含 hash 段**(如 `/console/#/app/agent/detail`——hash 路由应用的壳前缀与 `#` 都属**路径形态**;`#` 必须紧邻 `/`,否则会被 `.atlas-case` 的行内注释语义吞掉,见 §5.5);**宿主注入的 query(如 tenant)不进 `路由`**,由 `e2e.app_base_url` 承载(见 §5.5「宿主注入型 base query 的转发」);`域` = 域级 PRD 的域 slug;`实现状态` ∈ `已实现` / `实现中` / `未开始`。主表引用的每个 `页面` 必须在页面表里。)
|
|
80
82
|
|
|
@@ -247,7 +249,7 @@ testid:
|
|
|
247
249
|
- 首个 token = **动词**,必须取自下方词表;否则**校验器 FAIL**(`validate_e2e_index.py`)。
|
|
248
250
|
- 第二个 token = **`data-testid`**(`refresh` / `goto` 除外,见词表)。
|
|
249
251
|
- 其余为**值**(可含空格;是**渲染后可见文案**或数值)。
|
|
250
|
-
- `#`
|
|
252
|
+
- `#` 之后是**中文说明**,供人阅读,**机器忽略** —— **唯一例外** = 「容忍前提措辞」文本期门(§8.2,2026-10-30 issue #47):该门**刻意读注释**(容忍性假设天然写在注释里),只读不执行,且行内 `容忍: <理由>` 显式豁免。
|
|
251
253
|
- **可选步骤锚** `after:<N>`(2026-09-25 补,`3509 §B57`):写在 `expected` 行行首,表示「这条断言在分片里**第 N 条 `step` 执行完之后**立刻取样」(N 从 1 起、按 `step` 书写顺序编号)。不带锚的 `expected` 仍是**终态**断言。用途:把「先准备、再提交」型用例的**中途态**变成证据(如「先打开覆盖层再取消」里的「打开」;因为终态回到初态、本身无法作为证据)。约束:锚不得与 `initial:` / `unchanged:` 叠写;N 必须是正整数且 ≤ `step` 条数(否则**校验器 FAIL**,该项为「步骤锚合法」);带锚的断言**不属豁免通道**,必须像无前缀断言一样参与零步基线(即不得在初始态成立)。**发射面(2026-10-23,`DESIGN.md` D136)**:锚按 **step 序号**计数,生成器内部「动作槽位」必须与 step 严格 1:1——一条 step 发射多行语句(如 `refresh` 的先等后刷)时须合并为一个槽位,否则后续 `after:N` 整体前移(实测 `after:9` 落到「打开面板」之前,面板未开必红)。
|
|
252
254
|
|
|
253
255
|
> **为何中文降为注释**(2026-09-23 定):`step` / `expected` 必须机器可解析——散文格式下机器只能抽出 testid、抽不出「做什么 / 断言什么」,生成器退化为存在性断言;**不设**「中文 `step` + 结构化 `actions`」两字段(同一信息两处正文 = 漂移,`shared/single-source.md` §2)。语义由 `## <ID> <标题>` + `intent` + 注释承载。
|
|
@@ -330,7 +332,7 @@ testid:
|
|
|
330
332
|
- **零变化承诺**:项目未声明 `e2e.targets` 且无用例钉名 ⇒ 生成物与未加本字段时逐字节一致(出厂测试钉住)。
|
|
331
333
|
- **`覆盖维度:`(可选,2026-10-21 补,`DESIGN.md` D130)**:**E2E 通道 C01-C14 场景维度列表**。行形态 `- <维度ID>`(多条表示覆盖多个场景,取值见 §5.2 闭集)。
|
|
332
334
|
- **为何要它**:既有「AC 反向覆盖门」只能回答「每条 AC 有没有至少一条用例指向」,**无法回答每条 AC 的异常/边界/权限/会话/状态转换是否覆盖**;导致用例可能生成大量表面正向用例,而真正易错的异常分支全部落空。
|
|
333
|
-
- **对账规则(`validate_e2e_index.py` 的「AC × 覆盖维度」门)**:域级 PRD 验收标准表可选声明第 4 列「适用覆盖维度」(如 `C01, C02
|
|
335
|
+
- **对账规则(`validate_e2e_index.py` 的「AC × 覆盖维度」门)**:域级 PRD 验收标准表可选声明第 4 列「适用覆盖维度」(如 `C01, C02`);校验器对「覆盖就绪页且已有用例挂靠」的 AC 聚合用例维度进行差集比对;缺维度 ⇒ **WARN**(先 WARN 后 FAIL,不产生假阻断)。未声明第 4 列的项目按 `N/A` 兜底,不报假缺口。**无 `覆盖就绪` 第 5 列的旧 4 列表沿用「域内页面全 `已实现` 才参与」的域级判据;出现该列后按页级 ready 判(即使全 `—` 也按页级)。** **第 4 列 = E2E 通道;后端列 `后端适用覆盖维度` 由 `validate_ac_alignment.py` 另查(D153),本门不读、不并集。**
|
|
334
336
|
- **断言数 ≥ 1**:`expected` 至少一行断言动词。
|
|
335
337
|
- `intent` = **可证伪的一句话声明**(这条用例证明什么);不得写成"页面显示正确"这类模糊表述。
|
|
336
338
|
|
|
@@ -589,6 +591,7 @@ testid:
|
|
|
589
591
|
| 瞬时断言 | `expected` 仅断言 toast / "成功提示" / "弹窗关闭" → **WARN** |
|
|
590
592
|
| 持久化未复断言 | 步骤出现**提交性控件**(`save` / `submit` / `confirm` / `delete` / `remove` / `bind` 的 testid)却无 `刷新` 步骤或无刷新后复断言 → **WARN**(2026-09-23 起**无条件适用**:写必须刷新后复断言;例外 ① 校验被拒、例外 ② 鉴权由校验器执行,其余例外语义判不了、不进校验器)。**本项只判形态(用例里是否含 `refresh` 步骤),不构成 §5.6 R2 的证明** —— R2 的真正判据是 R9 的运行期零步基线(断言必由 `step` 派生) |
|
|
591
593
|
| "或"式步骤 | `step` 含 `或` / `或者` / `e.g.` / `等` 二选一表达 → **WARN** |
|
|
594
|
+
| 容忍前提措辞 | `step` / `expected` 的**注释尾巴**或 `precondition` 全文命中容忍性措辞(`存量` / `可能停在` / `视情况` / `随机` / `取决于历史`)→ **WARN**。本项**刻意读注释**(§5.5「机器忽略 `#` 之后」的唯一例外):容忍性假设天然写在注释/散文里,只扫代码会漏;代码部分不扫(业务文案含这些词不误报)。行内 `容忍: <理由>` 显式豁免;理由够不够是语义项、归独立审查(2026-10-30,issue #47 / `DESIGN.md` D176) |
|
|
592
595
|
| 文案来源 | `expected` 出现 i18n key 形态(`t(` / 点号路径)、全大写下划线枚举、组件名 → **WARN** |
|
|
593
596
|
| `initial:` 带理由 | 带 `initial:` 前缀的 `expected` 行,其**行尾中文说明**(`#` 之后)为空 ⇒ **WARN**(契约 §5.6 R9 要求「`initial:` 必须配**显式理由**」;本项只判「有没有」——「够不够」是语义项,按 §6.0 `C-new` 不进文本期门。2026-09-25 补,依据 `3509 §B36`) |
|
|
594
597
|
| 断言数 | 单例 `expected` 条数 < 1 → **FAIL** |
|
|
@@ -598,8 +601,8 @@ testid:
|
|
|
598
601
|
|
|
599
602
|
| 项 | 判定 |
|
|
600
603
|
|---|---|
|
|
601
|
-
| AC 反向覆盖 | 追溯链末段「AC → 用例」(`DESIGN.md` §5.2「功能 → 规则 → AC → E2E
|
|
602
|
-
| AC × 覆盖维度 | **E2E 场景维度对账(2026-10-21,`DESIGN.md` D130;2026-10-26 D153
|
|
604
|
+
| AC 反向覆盖 | 追溯链末段「AC → 用例」(`DESIGN.md` §5.2「功能 → 规则 → AC → E2E 用例,双向强制」):**域内页面全部覆盖就绪**的域(`覆盖就绪: 是`,或缺列/`—` 且 `实现状态=已实现`;显式 `否` 不参与),其域级 PRD §五 定义的每个 AC 必须被索引主表 ≥ 1 条 `关联AC` 指向(或登记于不可验清单,见下);零挂靠 ⇒ **WARN** + 逐域清单。`实现中` / `未开始` 且未显式 `覆盖就绪: 是` 的域**不参与**(用例尚未长出,不是缺口)——分级沿用 §8.1 testid 门先例;2026-10-30 issue #49 把「域全已实现」改为页级 opt-in,避免长期「实现中」的增量页整域绕过。覆盖关系为**派生量**(§3.2),不落手工表。**豁免落点已定形**(2026-10-12,`3509 §B201-3`):域级 PRD §五「不可验 AC 清单」(PRD 环契约 §五,小节标题固定)登记当前 UI 无观测面的 AC,本门从零挂靠清单中**减去**它;清单自洽(幽灵豁免引用了不存在的 AC)由 `validate_prd.py` 参数 4 检 FAIL。**升 FAIL 通道就绪**:级别改 FAIL 的唯一前置 = 三域残留逐条裁决清零(补用例 / 登记不可验,归 P9,随各域 B124 走查批)——先让数据能过、再上严判(`3509 §B36` 过早 FAIL 被量推翻的教训) |
|
|
605
|
+
| AC × 覆盖维度 | **E2E 场景维度对账(2026-10-21,`DESIGN.md` D130;2026-10-26 D153 明确通道边界;2026-10-30 D173 页级覆盖就绪)**:域级 PRD §五 验收标准表第 4 列可选声明「适用覆盖维度」(`C01-C14` E2E 通道闭集,如 `C01, C02`);对覆盖就绪页上已有用例挂靠的 AC,比对分片 `覆盖维度:` 聚合结果(只采信覆盖就绪页上的用例声明)。适用维度未被任一用例覆盖 ⇒ **WARN** + 缺口列表;发现未知维度词 ⇒ **WARN**;未声明第 4 列的项目 ⇒ **N/A** 兜底(按需启用,零误报)。先 WARN 后 FAIL。**本门只查第 4 列 E2E;后端列 `后端适用覆盖维度` 归 `validate_ac_alignment`(D153),不并集。** |
|
|
603
606
|
|
|
604
607
|
> 语义判不了的项("没有它什么 bug 会漏"、去重 intent、"这个断言是否真的异源")**不进校验器**,写在 §10 的执行纪律里由 agent 执行。依据:Autonoma 用 regex 判"句子意思"的代价是 **680 次重试 / $11 / 零用例**(`research/e2e-open-source-survey.md` §1.7 A12)。
|
|
605
608
|
>
|
|
@@ -673,7 +676,7 @@ testid:
|
|
|
673
676
|
| 只读输入 | `product/e2e/e2e-index.md` + `product/e2e/cases/*.md`;格式解析**复用** `validate_e2e_index.py`,不写第二份 |
|
|
674
677
|
| 执行 | 一次一条(**并发 = 1**)、node 单轨(`<e2e.node_modules>/.bin/playwright test -c playwright.config.ts <file>.spec.ts:<line> --headed`(慢动作经 `ATLAS_SLOWMO` 注入配置的 `launchOptions.slowMo`;F11,2026-10-14),可执行解析与 `atlas_check`「E2E 真跑」门同一规则(含**浏览器就绪判据**,2026-10-20,`DESIGN.md` D124:`ATLAS_PLAYWRIGHT_CHANNEL` 未设时,playwright 自算的 chromium 可执行路径必须**存在**——npm 装包不自动下载浏览器,缺 ⇒ 起跑前诚实拒绝并点名 `npx playwright install chromium`);缺或不可达 ⇒ 服务端诚实拒绝,不起注定失败的子进程;「跑完留窗 + 结果哨兵」由 `atlas-hold.ts` 承载,2026-10-12 迁移批;**持窗模式向运行器传 `--timeout=0`(2026-10-21,`DESIGN.md` D126)**——Playwright 默认 test timeout(30s)**计入 fixture teardown**,留窗等待会在约 30s 处被判超时并强制关窗(浏览器「跑完仍自动关闭」的真因;哨兵此时已写 `exitstatus:0`,界面还会误示「已保留」);控制台的 wall-clock `--timeout` 是唯一超时真相源(到点 kill 并如实报「超时」),自动关窗模式不传该旗标、保留运行器原生 30s 兜底);**用例执行前数据准备钩子(硬,2026-10-18,`DESIGN.md` D110;v3 现场实证移植批)**:项目自带 `product/e2e/scripts/atlas-prepare.mjs` ⇒ 每条用例执行前先跑它(`node`,cwd = 项目根,180s 上限、**不占**用例超时窗——在计时起点之前;运行时 env 必带 `ATLAS_CASE_ID` = 当前用例 ID 且同步注入 `NODE_PATH`(与真跑子进程依赖解析环境一致,2026-10-20,`DESIGN.md` D125);项目脚本可据此只准备该用例依赖的数据,不读该变量的存量脚本行为不变——2026-10-20,`DESIGN.md` D121);失败/超时/起不动 ⇒ **诚实拒绝执行该条并在 UI 显式分流为「前置失败」**(`done` 事件完整形状 + `prep_failed` 标记,UI 呈现为 warn 级 pill 与「与用例脚本本身无关」通告,消除误导;失败原文进「输出」面板),不静默跑注定偏移的用例(共享状态型靶场的残留实体会让 count 类断言系统性偏移);地址 = `e2e.app_base_url`(E1 单段;来源下拉随 E1 删除,`#155`——meta 行保留 base_url 展示)。**已提交视图(2026-10-21,`DESIGN.md` D127)**:控制台「已提交」= 事件流中**所有 submit 快照按序累积合并**(后提交覆盖同名用例),不是最后一条事件;单次提交只携带页面草稿(差量),避免部分提交抹掉历史用例。**blocked / skipped 用例执行按钮禁用**(title 带索引状态原因;服务端同判诚实拒绝,`#158`——生成物为 `test.skip` 本无 node id,不得误报「重跑生成」);**验收执行器(2026-10-25,`RFC-20261025-02` / `DESIGN.md` D150;backfill = 执行层②,2026-10-26 附录 B v2 / `DESIGN.md` D151 随评审通过落刀)**:真跑可经 `scripts/atlas_verify.py` 起跑(步序 pre → run → **backfill** → report 留档;**全批只跑一次真跑**);**backfill(仅全链绿批,run 后、留档前)**:claim(`scripts/write_claim.py`,task=`verify-backfill`,粒度 = 整文件 `product/e2e/e2e-index.md`)→ 复用 `e2e_console.writeback` **同一函数**回填索引 `状态` 列(签名/行为零改动;`sys.path[0]` 装配态同目录解析 = 与控制台同副本同版本)→ 写后复检账本基线(events.jsonl 字节/行数 + 尾 submit (ts, prov)——尾 submit 变 ⇒ 撞窗 FAIL,出路 = 人工经 console 重提交)→ release;**机器标记锚 = 执行器留档**(report.json 回填章 + README 声明行),索引行与校验器词表零改动;**评审账本 `events.jsonl` 永不写入**(人签字载体;console 无「导入执行器结果」通道,人工评审 = console 逐条执行解锁);写前三断言(draft 键集 ⊆ 索引 ID / 留档键集 = 改动集 / 报告含章)不过 ⇒ exit 非 0;**批级 `ATLAS_CASE_ID` 语义 = 显式串 `verify-batch`(非用例 ID——逐用例分段准备仍归控制台逐条执行,D121 不变;不读该变量的存量脚本行为逐字节不变)** |
|
|
675
678
|
| **桩披露(2026-10-12,§5.8)** | 含 `mock:` 行的用例卡片渲染 **MOCKED 徽标**(分片静态事实)+ 展开区 mock 清单;执行输出的 `[atlas-mock]` 命中行随日志流呈现(运行时事实)——人工走查者必须能看见「这条绿是桩撑的」 |
|
|
676
|
-
| **评审指纹与陈旧度(2026-10-21,`DESIGN.md` D128)** | 账本快照与每条提交绑定 **HEAD 提交与脚本散列指纹**(`prov: {head_sha, scripts_hash, git_dirty, actor_type}`)。`scripts_hash` 白名单覆盖 `scripts/` 下源码及 `atlas-prepare.mjs`(**候选顺序 = Runner 实际执行面:`product/e2e/scripts/` 优先**),排除运行时产物(`test-results/`、trace、png 等)——否则跑一轮就脏一次。控制台按当前工作区指纹实时重算 `review_state`(`fresh` / `stale` / `legacy` / `unreviewed`):代码或脚本变动 ⇒ **`stale`**,旧账本无指纹 ⇒ **`legacy`**;**两者同等按「需重审」处理**(剔除已评审、禁用复选框、顶栏单列计数、纳入「只看未评审」筛选),**读不到当前指纹时按 `legacy` 而非 `fresh`**(fail-closed,不冒充已核验);重新执行该用例自动清空旧评审态。`actor_type` ∈ `human \| agent`,由环境变量 **`ATLAS_ACTOR_TYPE`** 声明(缺省 `human`;自动化跑请显式设 `agent`)——它是**操作者自述、不是密码学证明**,故本环只如实暴露该字段,收口阻断仍由门与 `shared/closeout.md` 承担。提交另记 `reviewed_scope`(本次签字覆盖的用例集),消费者 = 人读账本 `ledger.md` 的「本次评审范围」行与控制台顶栏(不写不读 = 死字段,禁止)。**当前无 git / 生成脚本未落盘** ⇒ 相应维度记 `null
|
|
679
|
+
| **评审指纹与陈旧度(2026-10-21,`DESIGN.md` D128)** | 账本快照与每条提交绑定 **HEAD 提交与脚本散列指纹**(`prov: {head_sha, scripts_hash, git_dirty, actor_type}`)。`scripts_hash` 白名单覆盖 `scripts/` 下源码及 `atlas-prepare.mjs`(**候选顺序 = Runner 实际执行面:`product/e2e/scripts/` 优先**),排除运行时产物(`test-results/`、trace、png 等)——否则跑一轮就脏一次。控制台按当前工作区指纹实时重算 `review_state`(`fresh` / `stale` / `legacy` / `unreviewed`):代码或脚本变动 ⇒ **`stale`**,旧账本无指纹 ⇒ **`legacy`**;**两者同等按「需重审」处理**(剔除已评审、禁用复选框、顶栏单列计数、纳入「只看未评审」筛选),**读不到当前指纹时按 `legacy` 而非 `fresh`**(fail-closed,不冒充已核验);重新执行该用例自动清空旧评审态。`actor_type` ∈ `human \| agent`,由环境变量 **`ATLAS_ACTOR_TYPE`** 声明(缺省 `human`;自动化跑请显式设 `agent`)——它是**操作者自述、不是密码学证明**,故本环只如实暴露该字段,收口阻断仍由门与 `shared/closeout.md` 承担。提交另记 `reviewed_scope`(本次签字覆盖的用例集),消费者 = 人读账本 `ledger.md` 的「本次评审范围」行与控制台顶栏(不写不读 = 死字段,禁止)。**当前无 git / 生成脚本未落盘** ⇒ 相应维度记 `null`,不得用空串哈希冒充「匹配」**逐用例内容指纹(2026-10-30,`DESIGN.md` D174,用户拍板)**:上述「HEAD + 目录摘要」改为**按内容**判定——逐用例快照落 `prov.fp = {script, block, rest, shared, app}`:`block` = 该 `test(...)` 行到下一个 `test(` 行的原文(只改一条 test ⇒ 只作废该条);`rest` = 同文件用例块之外的原文(imports / 文件内 helper 变化 ⇒ 该文件全部用例作废);`shared` = 从 spec / `playwright.config.ts` / `*.setup.ts` / `atlas-prepare.mjs` 出发**静态 import 闭包**可达的非 spec 脚本聚合散列(未被引用的探针不参与;相对 import 解析不出 ⇒ 保守回退全部非 spec);`app` = 应用代码**工作区内容**散列(git 已跟踪 + 未忽略新文件,排除 E2E 环 / `.atlas` / `node_modules` / `*.md`)——commit 与提交账本本身不再触发重审,只有内容真变才触发;用例换脚本文件或当前脚本里找不到 ⇒ 作废。旧账本条目(无 `fp`)沿用 D128 的 HEAD + 全局散列口径(fail-closed,重提交后升级) |
|
|
677
680
|
| **评审维度与执行状态正交** | 页面 `localStorage` 草稿 = 人的勾选;索引 `状态` 列(`red` / `green` / `blocked` / `skipped`;E0 历史态 `prototype-pass` 见 §5.4)= 执行结果。**两者不得互相推导**;「人工 review 通过」只在**执行通过**后解锁 |
|
|
678
681
|
| 提交(唯一写盘点) | 点「提交」才一次性落两处:① 账本 `product/e2e/reviews/console/events.jsonl` 追加**一条快照**(append-only,唯一真相源;派生人读 `ledger.md`);② 回写索引 `状态` 列(先预览、确认后写)。不提交 ⇒ 服务端不知道任何过程 |
|
|
679
682
|
| 运行时产物落点 | 账本与人读件**只落 `product/e2e/reviews/console/`**;控制台本体与静态资源**不落** `product/`(`.atlas/` 才是包的落点,且 `install.sh` 会整包刷新)。界面文案**面向用户**(去黑话:headful →「执行时弹出浏览器窗口」,`#156`);说明/提示样式与表头视觉区分(`#157`) |
|
|
@@ -757,6 +760,8 @@ testid:
|
|
|
757
760
|
|---|---|---|
|
|
758
761
|
| 人工评审(console 账本) | **不阻断** | 审查意见是给评审者的**输入** |
|
|
759
762
|
| **脚本生成(§7.1)** | **阻断** | 报告**存在**(`product/e2e/reviews/` 下**日期前缀最大的审查报告目录**,排除 `<日期>-acceptance-*` / `<日期>-first-run` / `<日期>-verify` 留痕;共享契约 §4)**且** `review.json` 的 `status != "FAIL"`(无 `Critical`) |
|
|
763
|
+
| **报告输入指纹(2026-10-30,issue #48)** | **阻断** | 最新报告的 `inputs/MANIFEST.json` 必须覆盖本次待生成分片,且各分片 `sha256` 与当前文件一致;分片在审查后变化 ⇒ `stale`(不得放行;`origin: adopt` / `e2e.review.mode: auto-baseline` 显式通道除外)。指纹只证明「审查输入=当前分片」,**不证明每个用例都被审过**;逐用例覆盖由 `review.json` 的 `scope` / `expected` 与 §12.2 维度承担 |
|
|
764
|
+
| **baseline 报告(2026-10-30,issue #48)** | **阻断** | `basis: auto-baseline` 的报告不是真审;只有 `origin: adopt` 或 `e2e.review.mode: auto-baseline` 的显式通道放行(WARN),其余项目不得以 baseline 通过 |
|
|
760
765
|
| 报告缺失 | —— | **缺失 = 未审**,**不是「通过」** |
|
|
761
766
|
|
|
762
767
|
- **两层分开**:「**存在性**」挂在写盘动作(§7.1 前置检查);「**严重性**」由审查器自身退出码承载(`status == "FAIL"` ⇒ 非零)。
|
package/rings/prd/reference.md
CHANGED
|
@@ -145,7 +145,7 @@ product/prd/
|
|
|
145
145
|
| 三 | 功能详细说明 | 每个功能一节,六件套见下 |
|
|
146
146
|
| 四 | 业务规则(Rule Set) | 规则 ID / 内容 / **所属功能** / 触发条件 / 优先级 / 影响范围 |
|
|
147
147
|
| 五 | 验收标准 | GWT **三列**(`AC ID` | 场景 | 回指规则),每条回指规则 ID;末附**结构类 AC 清单**(见下) |
|
|
148
|
-
| 六 | Assumptions & Defaults |
|
|
148
|
+
| 六 | Assumptions & Defaults | 未证实但按此推进的假设,逐条带默认值;字段规范表声明了 `派生/重置` 的字段必须在此外登记默认值(机器门见 §7 附加检查) |
|
|
149
149
|
| 七 | 变更记录 | 版本 / 日期 / **变更内容及原因** / **影响** / **结论与后续**(5 列;legacy 3 列过渡见 §7 附加机器检查) |
|
|
150
150
|
|
|
151
151
|
### 开户最小集(`origin: adopt` 的**首轮开户**;2026-09-27 补,依据 `3509 §B85`)
|
|
@@ -172,7 +172,7 @@ product/prd/
|
|
|
172
172
|
1. **功能描述**:用户在何处完成什么、解决什么问题。
|
|
173
173
|
2. **用户流程**:正常路径 + **全部异常路径**(分支树或 Mermaid)。
|
|
174
174
|
3. **状态机**:状态名 / 进入条件 / 退出条件 / 用户可见表现。**无状态流转时写「不适用」并给一句理由。**
|
|
175
|
-
4. **字段规范**(业务语义):字段名 / 类型 / 是否必填 / 长度限制 / 校验规则 /
|
|
175
|
+
4. **字段规范**(业务语义):字段名 / 类型 / 是否必填 / 长度限制 / 校验规则 / 错误提示文案;可选第 7 列 **`派生/重置`**(列出现 = 本项目启用该声明):用户可编辑且由系统派生/重置的字段在此写明派生规则或重置触发点,并须在 §六 登记默认值(`validate_prd.py`「派生字段默认语义」门,2026-10-30 issue #47 / D176)。
|
|
176
176
|
技术表结构(列、约束、关系、枚举取值)**一律引用 `structure/*/data-models.md`,不在此重复**。
|
|
177
177
|
5. **文案规范**:六类场景齐全——空状态 / 加载中 / 操作成功 / 操作失败 / 权限不足 / 网络异常。
|
|
178
178
|
6. **异常处理**:异常场景 / 触发条件 / 处理方式 / 用户反馈。
|
|
@@ -306,7 +306,7 @@ product/prd/
|
|
|
306
306
|
|
|
307
307
|
缺失信息只有三个合法出口:
|
|
308
308
|
1. 写**建议默认值**:`建议默认值:<具体值>` —— 必须给出具体值,不能是"待定"。
|
|
309
|
-
2. 进 **Assumptions & Defaults**:写清假设内容 + 采用的默认值 + 影响面 +
|
|
309
|
+
2. 进 **Assumptions & Defaults**:写清假设内容 + 采用的默认值 + 影响面 + 何时需要澄清。**用户可编辑且系统会派生/重置的字段必须走这里**(字段规范表 `派生/重置` 列与 §六 的登记义务,见 §3 字段规范与 §7 附加机器检查)。
|
|
310
310
|
3. 进 **待决策登记表**(全局 `prd.md` 置顶一节):当该事项**不是信息缺失,而是产品方尚未决定**时使用。每行必须含 **议题 / 现状取证 / 建议默认值 / 影响面 / 决策人**。这是**结构性待定**,不属于占位符。
|
|
311
311
|
|
|
312
312
|
**门控规则(重要)**:待决策登记表非空时,**只产出全局 `prd.md` 与追溯总表,不产出域级 PRD**——产品定位、功能范围、产品形态未定之前写域级细节等于写完就废。域级 PRD 在相关待决策清零后逐域补。
|
|
@@ -402,6 +402,7 @@ product/prd/
|
|
|
402
402
|
|---|---|---|
|
|
403
403
|
| 变更记录形态 | 域级 §七 表头含 `影响`(及 `变更内容及原因` 列)⇒ 逐行检查:`影响` 单元格空 ⇒ 该行点名 FAIL;仅含 `变更说明`(legacy 3 列)⇒ WARN(**下次真实变更时迁移 5 列**,不单跑迁移轮——「只重验受影响项」同精神);§七 表头两种都不像 ⇒ FAIL;节在但无表 ⇒ WARN | FAIL / WARN |
|
|
404
404
|
| 可无项显式(§六) | §六 整节不出现(开户最小集)⇒ 跳过;出现且含 `无` / `不适用(理由:…)` ⇒ PASS;空表 / 空节且无显式结论 ⇒ **WARN 首版** | WARN |
|
|
405
|
+
| 派生字段默认语义(§六) | 字段规范表出现可选列 `派生/重置`(按表头单元格前缀匹配,不绑列位置)时:该列非空(`—` / `无` / 空 = 未声明)的每个字段名,§六 表须有一行「假设内容」含该字段名且「采用的默认值」非空 ⇒ 否则 **WARN** 逐字段指名;全部域都无该列 ⇒ N/A(opt-in,向后兼容)。独立 check 行,不并入参数 4 聚合(2026-10-30,issue #47 / `DESIGN.md` D176) | WARN |
|
|
405
406
|
|
|
406
407
|
- **翻转触发器(显式)**:可无项检查连续两个收口周期「真实遗漏 ≥1 且误报 0」⇒ 升 FAIL;出现误报 ⇒ 维持 WARN 并细分判据。统计落 **per-域收口留痕 README** 追加一行「可无项空表:N / 误报:N」(与「手工项」行同格式,`rings/e2e/reference.md` §10 执行纪律 5 先例),由采用项目收口评审填写。
|
|
407
408
|
- **边界(边界句,防执行者自行发挥)**:5 列仅**域级** §七;全局 `十一` 修订记录默认 4 列**不扩**(`不适用(理由:…)` 语义不动)。
|
|
Binary file
|
|
Binary file
|
|
Binary file
|