@dommaker/harness 1.5.0 → 1.7.0
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 +26 -0
- package/README.md +0 -2
- package/dist/cli/commands/definitions.d.ts.map +1 -1
- package/dist/cli/commands/definitions.js +1 -32
- package/dist/cli/commands/definitions.js.map +1 -1
- package/dist/cli/commands/passes-gate.d.ts +0 -2
- package/dist/cli/commands/passes-gate.d.ts.map +1 -1
- package/dist/cli/commands/passes-gate.js +0 -1
- package/dist/cli/commands/passes-gate.js.map +1 -1
- package/dist/cli/commands/performance.d.ts +0 -4
- package/dist/cli/commands/performance.d.ts.map +1 -1
- package/dist/cli/commands/performance.js +10 -20
- package/dist/cli/commands/performance.js.map +1 -1
- package/dist/cli/commands/report.d.ts +1 -1
- package/dist/cli/commands/report.d.ts.map +1 -1
- package/dist/cli/commands/report.js +2 -55
- package/dist/cli/commands/report.js.map +1 -1
- package/dist/cli/commands/status.d.ts.map +1 -1
- package/dist/cli/commands/status.js +4 -8
- package/dist/cli/commands/status.js.map +1 -1
- package/dist/context/index.d.ts +2 -5
- package/dist/context/index.d.ts.map +1 -1
- package/dist/context/index.js +2 -8
- package/dist/context/index.js.map +1 -1
- package/dist/context/token-budget.d.ts +0 -29
- package/dist/context/token-budget.d.ts.map +1 -1
- package/dist/context/token-budget.js +1 -65
- package/dist/context/token-budget.js.map +1 -1
- package/dist/context/types.d.ts +0 -1
- package/dist/context/types.d.ts.map +1 -1
- package/dist/context/types.js +0 -9
- package/dist/context/types.js.map +1 -1
- package/dist/core/constraints/checker.d.ts +14 -0
- package/dist/core/constraints/checker.d.ts.map +1 -1
- package/dist/core/constraints/checker.js +22 -2
- package/dist/core/constraints/checker.js.map +1 -1
- package/dist/core/constraints/git-evidence.d.ts +6 -3
- package/dist/core/constraints/git-evidence.d.ts.map +1 -1
- package/dist/core/constraints/git-evidence.js +6 -3
- package/dist/core/constraints/git-evidence.js.map +1 -1
- package/dist/core/index.d.ts +1 -2
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +1 -9
- package/dist/core/index.js.map +1 -1
- package/dist/core/spec/validator.d.ts +2 -0
- package/dist/core/spec/validator.d.ts.map +1 -1
- package/dist/core/spec/validator.js +9 -11
- package/dist/core/spec/validator.js.map +1 -1
- package/dist/core/validators/index.d.ts +1 -1
- package/dist/core/validators/index.d.ts.map +1 -1
- package/dist/core/validators/passes-gate.d.ts +1 -15
- package/dist/core/validators/passes-gate.d.ts.map +1 -1
- package/dist/core/validators/passes-gate.js +2 -127
- package/dist/core/validators/passes-gate.js.map +1 -1
- package/dist/failure/index.d.ts +0 -1
- package/dist/failure/index.d.ts.map +1 -1
- package/dist/failure/index.js +1 -7
- package/dist/failure/index.js.map +1 -1
- package/dist/gates/definitions.d.ts.map +1 -1
- package/dist/gates/definitions.js +0 -4
- package/dist/gates/definitions.js.map +1 -1
- package/dist/gates/performance.d.ts +7 -22
- package/dist/gates/performance.d.ts.map +1 -1
- package/dist/gates/performance.js +7 -89
- package/dist/gates/performance.js.map +1 -1
- package/dist/gates/types.d.ts +2 -8
- package/dist/gates/types.d.ts.map +1 -1
- package/dist/index.d.ts +6 -8
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -22
- package/dist/index.js.map +1 -1
- package/dist/knowledge/index.d.ts +0 -1
- package/dist/knowledge/index.d.ts.map +1 -1
- package/dist/knowledge/index.js +1 -3
- package/dist/knowledge/index.js.map +1 -1
- package/dist/monitoring/trace-analyzer.d.ts +25 -10
- package/dist/monitoring/trace-analyzer.d.ts.map +1 -1
- package/dist/monitoring/trace-analyzer.js +147 -116
- package/dist/monitoring/trace-analyzer.js.map +1 -1
- package/dist/types/passes-gate.d.ts +0 -32
- package/dist/types/passes-gate.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/__tests__/passes-gate-check.test.ts +20 -4
- package/src/__tests__/passes-gate.test.ts +5 -99
- package/src/__tests__/performance-gate.test.ts +3 -11
- package/src/__tests__/public-exports.test.ts +68 -16
- package/src/__tests__/public-type-surface.test.ts +359 -0
- package/src/__tests__/trace-analyzer.test.ts +52 -2
- package/src/cli/commands/CONTEXT.md +3 -2
- package/src/cli/commands/__tests__/passes-gate-dead-options.test.ts +158 -0
- package/src/cli/commands/__tests__/passes-gate.test.ts +7 -3
- package/src/cli/commands/__tests__/performance.test.ts +5 -16
- package/src/cli/commands/__tests__/registry.test.ts +46 -3
- package/src/cli/commands/__tests__/report-extra.test.ts +0 -19
- package/src/cli/commands/__tests__/report-false-green.test.ts +46 -0
- package/src/cli/commands/__tests__/report.test.ts +0 -20
- package/src/cli/commands/__tests__/status-analysis-wiring.test.ts +68 -0
- package/src/cli/commands/__tests__/status-extra.test.ts +63 -116
- package/src/cli/commands/__tests__/status.test.ts +66 -148
- package/src/cli/commands/definitions.ts +1 -32
- package/src/cli/commands/passes-gate.ts +0 -3
- package/src/cli/commands/performance.ts +13 -27
- package/src/cli/commands/report.ts +3 -61
- package/src/cli/commands/status.ts +5 -10
- package/src/context/CONTEXT.md +2 -3
- package/src/context/__tests__/token-budget.test.ts +1 -81
- package/src/context/index.ts +2 -7
- package/src/context/token-budget.ts +0 -73
- package/src/context/types.ts +0 -9
- package/src/core/CONTEXT.md +5 -6
- package/src/core/constraints/__tests__/collect-constraints.test.ts +66 -0
- package/src/core/constraints/checker.ts +33 -2
- package/src/core/constraints/git-evidence.ts +6 -3
- package/src/core/index.ts +0 -12
- package/src/core/spec/__tests__/validator.test.ts +24 -0
- package/src/core/spec/validator.ts +9 -10
- package/src/core/validators/__tests__/passes-gate.test.ts +2 -9
- package/src/core/validators/index.ts +0 -2
- package/src/core/validators/passes-gate.ts +3 -152
- package/src/failure/CONTEXT.md +8 -6
- package/src/failure/index.ts +0 -10
- package/src/gates/CONTEXT.md +3 -2
- package/src/gates/__tests__/performance.test.ts +6 -74
- package/src/gates/definitions.ts +0 -4
- package/src/gates/performance.ts +9 -111
- package/src/gates/types.ts +2 -8
- package/src/index.ts +1 -37
- package/src/knowledge/CONTEXT.md +1 -2
- package/src/knowledge/index.ts +0 -1
- package/src/monitoring/CONTEXT.md +2 -2
- package/src/monitoring/trace-analyzer.ts +160 -126
- package/src/types/passes-gate.ts +0 -43
- package/src/utils/__tests__/jsonl-skip-disposition.test.ts +0 -1
- package/dist/cli/commands/analyze-sessions.d.ts +0 -20
- package/dist/cli/commands/analyze-sessions.d.ts.map +0 -1
- package/dist/cli/commands/analyze-sessions.js +0 -290
- package/dist/cli/commands/analyze-sessions.js.map +0 -1
- package/dist/cli/commands/update-user-model.d.ts +0 -30
- package/dist/cli/commands/update-user-model.d.ts.map +0 -1
- package/dist/cli/commands/update-user-model.js +0 -406
- package/dist/cli/commands/update-user-model.js.map +0 -1
- package/dist/cli/session-mining/corrections.d.ts +0 -17
- package/dist/cli/session-mining/corrections.d.ts.map +0 -1
- package/dist/cli/session-mining/corrections.js +0 -58
- package/dist/cli/session-mining/corrections.js.map +0 -1
- package/dist/cli/session-mining/index.d.ts +0 -13
- package/dist/cli/session-mining/index.d.ts.map +0 -1
- package/dist/cli/session-mining/index.js +0 -29
- package/dist/cli/session-mining/index.js.map +0 -1
- package/dist/cli/session-mining/text.d.ts +0 -31
- package/dist/cli/session-mining/text.d.ts.map +0 -1
- package/dist/cli/session-mining/text.js +0 -126
- package/dist/cli/session-mining/text.js.map +0 -1
- package/dist/cli/session-mining/transcript.d.ts +0 -34
- package/dist/cli/session-mining/transcript.d.ts.map +0 -1
- package/dist/cli/session-mining/transcript.js +0 -130
- package/dist/cli/session-mining/transcript.js.map +0 -1
- package/dist/context/compaction.d.ts +0 -57
- package/dist/context/compaction.d.ts.map +0 -1
- package/dist/context/compaction.js +0 -165
- package/dist/context/compaction.js.map +0 -1
- package/dist/core/session/clean-state.d.ts +0 -17
- package/dist/core/session/clean-state.d.ts.map +0 -1
- package/dist/core/session/clean-state.js +0 -192
- package/dist/core/session/clean-state.js.map +0 -1
- package/dist/core/session/index.d.ts +0 -6
- package/dist/core/session/index.d.ts.map +0 -1
- package/dist/core/session/index.js +0 -15
- package/dist/core/session/index.js.map +0 -1
- package/dist/core/session/startup.d.ts +0 -47
- package/dist/core/session/startup.d.ts.map +0 -1
- package/dist/core/session/startup.js +0 -263
- package/dist/core/session/startup.js.map +0 -1
- package/dist/failure/constraint-handler.d.ts +0 -83
- package/dist/failure/constraint-handler.d.ts.map +0 -1
- package/dist/failure/constraint-handler.js +0 -138
- package/dist/failure/constraint-handler.js.map +0 -1
- package/dist/knowledge/lifecycle-hooks.d.ts +0 -62
- package/dist/knowledge/lifecycle-hooks.d.ts.map +0 -1
- package/dist/knowledge/lifecycle-hooks.js +0 -143
- package/dist/knowledge/lifecycle-hooks.js.map +0 -1
- package/dist/types/session.d.ts +0 -113
- package/dist/types/session.d.ts.map +0 -1
- package/dist/types/session.js +0 -6
- package/dist/types/session.js.map +0 -1
- package/src/__tests__/clean-state-extra.test.ts +0 -301
- package/src/__tests__/clean-state.test.ts +0 -169
- package/src/__tests__/constraint-handler.test.ts +0 -132
- package/src/__tests__/passes-gate-extra.test.ts +0 -93
- package/src/__tests__/session-startup.test.ts +0 -334
- package/src/cli/commands/__tests__/analyze-sessions.test.ts +0 -184
- package/src/cli/commands/__tests__/update-user-model.test.ts +0 -268
- package/src/cli/commands/analyze-sessions.ts +0 -335
- package/src/cli/commands/update-user-model.ts +0 -476
- package/src/cli/session-mining/__tests__/transcript.test.ts +0 -118
- package/src/cli/session-mining/corrections.ts +0 -56
- package/src/cli/session-mining/index.ts +0 -13
- package/src/cli/session-mining/text.ts +0 -117
- package/src/cli/session-mining/transcript.ts +0 -125
- package/src/context/__tests__/compaction.test.ts +0 -169
- package/src/context/compaction.ts +0 -201
- package/src/core/session/__tests__/startup.test.ts +0 -281
- package/src/core/session/clean-state.ts +0 -178
- package/src/core/session/index.ts +0 -15
- package/src/core/session/startup.ts +0 -253
- package/src/failure/constraint-handler.ts +0 -171
- package/src/knowledge/__tests__/lifecycle-hooks.test.ts +0 -140
- package/src/knowledge/lifecycle-hooks.ts +0 -202
- package/src/types/session.ts +0 -132
|
@@ -0,0 +1,359 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 已发布类型面全量冻结闸(ADR-0003 类型面补全 / ADR-0022 追记第 4 条)
|
|
3
|
+
*
|
|
4
|
+
* 存在的理由是一起**定级**错误,不是一起删除错误:本仓 breaking 定级长期挂在「这个符号在
|
|
5
|
+
* 不在包根导出面」这句断言上(ADR-0010:5/31、ADR-0019:10、ADR-0022 皆以它定级),而这句话
|
|
6
|
+
* 在删除动作之前没有任何闸可跑,全靠人 grep 记忆。`PassesGateResult`(评审 A2)与
|
|
7
|
+
* `DynamicTask`(二次复审 B1)已在同一处错两次;B1 那次是复审方直接断言「不在包根」,而
|
|
8
|
+
* 实测 v1.6.0 源 `src/index.ts:106` 与已发布 npm 产物 `dist/index.d.ts:38` 都在导出它。
|
|
9
|
+
* 本闸让「在不在公开面上」变成跑一下就有答案的事实。
|
|
10
|
+
*
|
|
11
|
+
* **公开面 = `package.json` 的 exports 映射,不是只有包根。** 本包发布五个入口点
|
|
12
|
+
* (`.` / `./core` / `./presets` / `./context` / `./gates`),`import type { X } from
|
|
13
|
+
* '@dommaker/harness/core'` 与从包根导入同样是对外承诺。入口清单从 exports **派生**而非
|
|
14
|
+
* 硬编码:新增子路径会立刻落进本闸(未登记冻结清单即红),免得重演「公开面的定义比现实窄」
|
|
15
|
+
* 这个 B1 病因——`DynamicTask` 除包根外同时经 `./core` 可达,只冻包根会留同一个洞。
|
|
16
|
+
*
|
|
17
|
+
* 与 `public-exports.test.ts` 的分工:那边钉的是**删完之后**(已删类型 `@ts-expect-error`
|
|
18
|
+
* 负钉 + 活类型正钉 + 四级 barrel 链残留扫描),且它 `import('../index')`。本闸只做源码文本
|
|
19
|
+
* 分析、**刻意不 import 任何入口**——这是它单独立一个文件的原因:类型面一旦被改动,那边的
|
|
20
|
+
* 编译期钉会让整套 suite「failed to run」(实测注入一条 `export type { DynamicTask }` 得
|
|
21
|
+
* 0 tests),拿不到可执行的清单 diff;本闸在那种改动下必须仍然跑得动、报得出是哪个入口的
|
|
22
|
+
* 哪个符号。
|
|
23
|
+
*
|
|
24
|
+
* 清单来源不是手抄:五个入口的 `src` 解析结果与 tsc 产物(各自 exports 的 types 指向,如
|
|
25
|
+
* `dist/core/index.d.ts`)逐项对撞,152/32/1/12/18 全部逐字一致,产物侧同时零 `export *`。
|
|
26
|
+
* 改动入口清单文件时同步改本文件对应条目,diff 即 PR 评审材料;增删符号属公共面 breaking,
|
|
27
|
+
* 须按 ADR-0003/0022 走发布级别裁决。
|
|
28
|
+
*/
|
|
29
|
+
|
|
30
|
+
import * as fs from 'fs';
|
|
31
|
+
import * as path from 'path';
|
|
32
|
+
|
|
33
|
+
const REPO_ROOT = path.join(__dirname, '../..');
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* 入口点合法的导出写法只有三种:
|
|
37
|
+
* ① `export { 值 } from '...'`;② `export type { 类型 } from '...'`;③ 内联值声明
|
|
38
|
+
* `export function|const|let|var`(如 `src/gates/index.ts` 的 5 个 `create*Gate`)——纯值面,
|
|
39
|
+
* 不属类型清单管辖。
|
|
40
|
+
* 清单归类按**说明符自身**而非块形式:`export { getEffectiveGates, type GatesConfig }` 里的
|
|
41
|
+
* `GatesConfig` 按 TS 语义就是类型导出,必须进类型清单(本闸的职责是如实刻画公开面,不是管写法)。
|
|
42
|
+
* 其余行首 `export` 一律记为违禁而非跳过:`export *` / `export type *` 会让按名字扫描静默
|
|
43
|
+
* 漏算;内联 `export interface|type|enum|class|declare` 更必须红——它绕过类型清单,而
|
|
44
|
+
* `enum`/`class` 同时占值面与类型面,按单一分类必错一面。这正是 B1「公开面的定义比现实窄」
|
|
45
|
+
* 那个病因的形态来源。
|
|
46
|
+
*/
|
|
47
|
+
interface EntrySurface {
|
|
48
|
+
types: string[];
|
|
49
|
+
illegal: string[];
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const INLINE_VALUE_DECL_RE = /^export\s+(?:async\s+)?(?:function|const|let|var)\b/;
|
|
53
|
+
|
|
54
|
+
function parseEntrySurface(source: string): EntrySurface {
|
|
55
|
+
const stmtRe = /^export (type )?\{([^}]*)\}[^;]*;/gm;
|
|
56
|
+
const types: string[] = [];
|
|
57
|
+
const illegal: string[] = [];
|
|
58
|
+
const starts = new Set<number>();
|
|
59
|
+
|
|
60
|
+
let match: RegExpExecArray | null = stmtRe.exec(source);
|
|
61
|
+
while (match !== null) {
|
|
62
|
+
starts.add(match.index);
|
|
63
|
+
const isTypeBlock = Boolean(match[1]);
|
|
64
|
+
for (const raw of match[2].split(',')) {
|
|
65
|
+
const spec = raw.trim();
|
|
66
|
+
if (!spec) continue;
|
|
67
|
+
// `A as B` 对外名字是 B;`type A as B` 对外名字是 B 且属类型面
|
|
68
|
+
const isTypeSpec = /^(type|typeof)\s/.test(spec);
|
|
69
|
+
if (isTypeBlock || isTypeSpec) {
|
|
70
|
+
types.push(spec.replace(/^(type|typeof)\s+/, '').split(/\s+as\s+/).pop()!.trim());
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
match = stmtRe.exec(source);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
let offset = 0;
|
|
77
|
+
for (const line of source.split('\n')) {
|
|
78
|
+
if (/^export\b/.test(line) && !starts.has(offset) && !INLINE_VALUE_DECL_RE.test(line)) {
|
|
79
|
+
illegal.push(line.trim());
|
|
80
|
+
}
|
|
81
|
+
offset += line.length + 1;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
return { types, illegal };
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/** exports 子路径 → 承载它的显式清单源文件。形态对不上返回 null,由映射闸 fail-loud。 */
|
|
88
|
+
function sourceFileForSubpath(subpath: string): string | null {
|
|
89
|
+
if (subpath === '.') return 'src/index.ts';
|
|
90
|
+
const rest = subpath.replace(/^\.\//, '');
|
|
91
|
+
return /^[a-z][a-z0-9-]*$/.test(rest) ? `src/${rest}/index.ts` : null;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
const EXPORTS_MAP = JSON.parse(
|
|
95
|
+
fs.readFileSync(path.join(REPO_ROOT, 'package.json'), 'utf-8'),
|
|
96
|
+
).exports as Record<string, { types?: string }>;
|
|
97
|
+
|
|
98
|
+
const ENTRY_SUBPATHS: string[] = Object.keys(EXPORTS_MAP);
|
|
99
|
+
|
|
100
|
+
/** 每个已发布入口的类型面全量清单。增删任一项即公共面 breaking,见文件头。 */
|
|
101
|
+
const PUBLISHED_ENTRY_TYPES: Record<string, string[]> = {
|
|
102
|
+
'.': [
|
|
103
|
+
'AcceptanceCriteria',
|
|
104
|
+
'AcceptanceGateContext',
|
|
105
|
+
'AgentConfig',
|
|
106
|
+
'AgentEvent',
|
|
107
|
+
'AgentState',
|
|
108
|
+
'AgentStatus',
|
|
109
|
+
'ArtifactIntegrityResult',
|
|
110
|
+
'AuditAction',
|
|
111
|
+
'AuditIssue',
|
|
112
|
+
'AuditOptions',
|
|
113
|
+
'AuditReport',
|
|
114
|
+
'AuditRuleName',
|
|
115
|
+
'BatchSpecValidationResult',
|
|
116
|
+
'CSOIssue',
|
|
117
|
+
'CSOValidationResult',
|
|
118
|
+
'CapabilitiesConfig',
|
|
119
|
+
'ChangelogConfig',
|
|
120
|
+
'ChangelogVersionCheck',
|
|
121
|
+
'CheckCacheConfig',
|
|
122
|
+
'CheckConfig',
|
|
123
|
+
'CheckConstraintsOptions',
|
|
124
|
+
'CheckResult',
|
|
125
|
+
'CheckSamplingConfig',
|
|
126
|
+
'CheckType',
|
|
127
|
+
'CheckerVerdict',
|
|
128
|
+
'Checkpoint',
|
|
129
|
+
'CheckpointCheck',
|
|
130
|
+
'CheckpointContext',
|
|
131
|
+
'CheckpointResult',
|
|
132
|
+
'ClassificationResult',
|
|
133
|
+
'CodeStructure',
|
|
134
|
+
'CommandBlacklistRule',
|
|
135
|
+
'CommandGateConfig',
|
|
136
|
+
'CommitFileClassification',
|
|
137
|
+
'CommitInput',
|
|
138
|
+
'CommitVerdict',
|
|
139
|
+
'CompactionConfig',
|
|
140
|
+
'CompactionLevel',
|
|
141
|
+
'CompletionCheckersConfig',
|
|
142
|
+
'ConstCountActual',
|
|
143
|
+
'Constraint',
|
|
144
|
+
'ConstraintCheckResult',
|
|
145
|
+
'ConstraintContext',
|
|
146
|
+
'ConstraintId',
|
|
147
|
+
'ConstraintKind',
|
|
148
|
+
'ConstraintLevel',
|
|
149
|
+
'ConstraintResult',
|
|
150
|
+
'ConstraintTrigger',
|
|
151
|
+
'ConsumptionEvent',
|
|
152
|
+
'ConsumptionMode',
|
|
153
|
+
'ContextAverages',
|
|
154
|
+
'ContextDocsCheck',
|
|
155
|
+
'ContextFilesConfig',
|
|
156
|
+
'ContextSource',
|
|
157
|
+
'ContextSourceType',
|
|
158
|
+
'ContextUsageSnapshot',
|
|
159
|
+
'ContractGateConfig',
|
|
160
|
+
'ContractPresenceContext',
|
|
161
|
+
'ContractPresenceResult',
|
|
162
|
+
'CustomConstraintDefinition',
|
|
163
|
+
'DecayConfig',
|
|
164
|
+
'DecisionRecord',
|
|
165
|
+
'DeclarationInfo',
|
|
166
|
+
'DirCountActual',
|
|
167
|
+
'DocDirCheck',
|
|
168
|
+
'DocFreshnessCheck',
|
|
169
|
+
'DocFreshnessConfig',
|
|
170
|
+
'DocRegexCountCheck',
|
|
171
|
+
'DocsSyncConfig',
|
|
172
|
+
'EffectiveConfigLint',
|
|
173
|
+
'ErrorClassificationRule',
|
|
174
|
+
'ErrorClassifierConfig',
|
|
175
|
+
'EventHandler',
|
|
176
|
+
'ExecutionResult',
|
|
177
|
+
'ExecutionTrace',
|
|
178
|
+
'FailureRecord',
|
|
179
|
+
'FailureRecorderConfig',
|
|
180
|
+
'FallbackStrategy',
|
|
181
|
+
'Gate',
|
|
182
|
+
'GateContext',
|
|
183
|
+
'GateDecision',
|
|
184
|
+
'GateDecisionStatus',
|
|
185
|
+
'GateDefinition',
|
|
186
|
+
'GateResult',
|
|
187
|
+
'GateRunResult',
|
|
188
|
+
'GatesConfig',
|
|
189
|
+
'GovernanceConfig',
|
|
190
|
+
'GrepCountActual',
|
|
191
|
+
'HarnessBootstrap',
|
|
192
|
+
'HookConfig',
|
|
193
|
+
'HookDefinition',
|
|
194
|
+
'HookErrorStrategy',
|
|
195
|
+
'HookExecutionRecord',
|
|
196
|
+
'HookPhase',
|
|
197
|
+
'HookResult',
|
|
198
|
+
'ImportInfo',
|
|
199
|
+
'IndexEntry',
|
|
200
|
+
'IngestOptions',
|
|
201
|
+
'InjectionConfig',
|
|
202
|
+
'InjectionResult',
|
|
203
|
+
'IronLawContext',
|
|
204
|
+
'KnowledgeEntry',
|
|
205
|
+
'KnowledgeOrigin',
|
|
206
|
+
'KnowledgeReference',
|
|
207
|
+
'KnowledgeStore',
|
|
208
|
+
'KnowledgeSubsystem',
|
|
209
|
+
'LintIssue',
|
|
210
|
+
'LintIssueType',
|
|
211
|
+
'MaturityChange',
|
|
212
|
+
'MaturityLevel',
|
|
213
|
+
'MergedConstraintsConfig',
|
|
214
|
+
'PassesGateCheckResult',
|
|
215
|
+
'PassesGateConfig',
|
|
216
|
+
'PassesGateViolation',
|
|
217
|
+
'PerformanceGateConfig',
|
|
218
|
+
'PerformanceThresholds',
|
|
219
|
+
'PhaseFormatResult',
|
|
220
|
+
'PipelineResult',
|
|
221
|
+
'ProjectConfig',
|
|
222
|
+
'QueryBudget',
|
|
223
|
+
'QueryFilter',
|
|
224
|
+
'QueryResult',
|
|
225
|
+
'ReferenceRecord',
|
|
226
|
+
'RenderConstraintsByTriggerOptions',
|
|
227
|
+
'ReviewGateConfig',
|
|
228
|
+
'SchemaLoader',
|
|
229
|
+
'SecurityGateConfig',
|
|
230
|
+
'SessionCheckpoint',
|
|
231
|
+
'SessionEvent',
|
|
232
|
+
'SessionEventType',
|
|
233
|
+
'SessionHandle',
|
|
234
|
+
'SessionMessage',
|
|
235
|
+
'SourceRef',
|
|
236
|
+
'SpecAcceptanceGateConfig',
|
|
237
|
+
'SpecSchemaDefinition',
|
|
238
|
+
'SpecType',
|
|
239
|
+
'SpecValidationError',
|
|
240
|
+
'SpecValidationResult',
|
|
241
|
+
'SpecValidatorConfig',
|
|
242
|
+
'StepMeta',
|
|
243
|
+
'StorageLayer',
|
|
244
|
+
'TaskTestResult',
|
|
245
|
+
'TddChainResult',
|
|
246
|
+
'TestResult',
|
|
247
|
+
'TestingGovernanceConfig',
|
|
248
|
+
'ToolMeta',
|
|
249
|
+
'TraceAnalyzerConfig',
|
|
250
|
+
'TraceAnomaly',
|
|
251
|
+
'TraceCollectorConfig',
|
|
252
|
+
'TraceFilter',
|
|
253
|
+
'TraceSummary',
|
|
254
|
+
'WorkflowMeta',
|
|
255
|
+
],
|
|
256
|
+
'./core': [
|
|
257
|
+
'BatchSpecValidationResult',
|
|
258
|
+
'CSOIssue',
|
|
259
|
+
'CSOValidationResult',
|
|
260
|
+
'CapabilitiesMode',
|
|
261
|
+
'CheckCacheConfig',
|
|
262
|
+
'CheckConfig',
|
|
263
|
+
'CheckConstraintsOptions',
|
|
264
|
+
'CheckResult',
|
|
265
|
+
'CheckSamplingConfig',
|
|
266
|
+
'CheckType',
|
|
267
|
+
'Checkpoint',
|
|
268
|
+
'CheckpointCheck',
|
|
269
|
+
'CheckpointContext',
|
|
270
|
+
'CheckpointResult',
|
|
271
|
+
'Constraint',
|
|
272
|
+
'ConstraintCheckResult',
|
|
273
|
+
'ConstraintContext',
|
|
274
|
+
'ConstraintId',
|
|
275
|
+
'ConstraintKind',
|
|
276
|
+
'ConstraintLevel',
|
|
277
|
+
'ConstraintResult',
|
|
278
|
+
'ConstraintTrigger',
|
|
279
|
+
'ContextFilesResolution',
|
|
280
|
+
'EffectiveConfigLint',
|
|
281
|
+
'IronLawContext',
|
|
282
|
+
'PassesGateConfig',
|
|
283
|
+
'RenderConstraintsByTriggerOptions',
|
|
284
|
+
'SpecSchemaDefinition',
|
|
285
|
+
'SpecType',
|
|
286
|
+
'SpecValidationResult',
|
|
287
|
+
'SpecValidatorConfig',
|
|
288
|
+
'TaskTestResult',
|
|
289
|
+
],
|
|
290
|
+
'./presets': [
|
|
291
|
+
'PresetConfig',
|
|
292
|
+
],
|
|
293
|
+
'./context': [
|
|
294
|
+
'CompactionConfig',
|
|
295
|
+
'CompactionLevel',
|
|
296
|
+
'ContextSource',
|
|
297
|
+
'ContextSourceType',
|
|
298
|
+
'ContextUsageSnapshot',
|
|
299
|
+
'InjectionConfig',
|
|
300
|
+
'InjectionResult',
|
|
301
|
+
'SessionCheckpoint',
|
|
302
|
+
'SessionEvent',
|
|
303
|
+
'SessionEventType',
|
|
304
|
+
'SessionHandle',
|
|
305
|
+
'SessionMessage',
|
|
306
|
+
],
|
|
307
|
+
'./gates': [
|
|
308
|
+
'AcceptanceCriteria',
|
|
309
|
+
'AcceptanceGateContext',
|
|
310
|
+
'CommandBlacklistRule',
|
|
311
|
+
'CommandGateConfig',
|
|
312
|
+
'ContractGateConfig',
|
|
313
|
+
'Gate',
|
|
314
|
+
'GateContext',
|
|
315
|
+
'GateDecision',
|
|
316
|
+
'GateDecisionStatus',
|
|
317
|
+
'GateDefinition',
|
|
318
|
+
'GateResult',
|
|
319
|
+
'GateRunResult',
|
|
320
|
+
'GatesConfig',
|
|
321
|
+
'PerformanceGateConfig',
|
|
322
|
+
'PerformanceThresholds',
|
|
323
|
+
'ReviewGateConfig',
|
|
324
|
+
'SecurityGateConfig',
|
|
325
|
+
'SpecAcceptanceGateConfig',
|
|
326
|
+
],
|
|
327
|
+
};
|
|
328
|
+
|
|
329
|
+
describe('已发布类型面全量冻结(ADR-0022 追记 4)', () => {
|
|
330
|
+
it('exports 的每个子路径都映射到存在的显式清单源文件(新增子路径不得绕过本闸)', () => {
|
|
331
|
+
const unmapped = ENTRY_SUBPATHS.filter((sub) => {
|
|
332
|
+
const rel = sourceFileForSubpath(sub);
|
|
333
|
+
return rel === null || !fs.existsSync(path.join(REPO_ROOT, rel));
|
|
334
|
+
});
|
|
335
|
+
expect(unmapped).toEqual([]);
|
|
336
|
+
});
|
|
337
|
+
|
|
338
|
+
it('冻结清单覆盖全部已发布子路径(新增入口须先登记清单)', () => {
|
|
339
|
+
expect(Object.keys(PUBLISHED_ENTRY_TYPES).sort()).toEqual([...ENTRY_SUBPATHS].sort());
|
|
340
|
+
});
|
|
341
|
+
|
|
342
|
+
for (const sub of ENTRY_SUBPATHS) {
|
|
343
|
+
const rel = sourceFileForSubpath(sub);
|
|
344
|
+
if (rel === null) continue; // 映射闸已负责红,此处不重复报
|
|
345
|
+
const surface = parseEntrySurface(fs.readFileSync(path.join(REPO_ROOT, rel), 'utf-8'));
|
|
346
|
+
|
|
347
|
+
describe(`入口点 ${sub}(${rel})`, () => {
|
|
348
|
+
it('只用白名单写法导出,无被漏算的导出面', () => {
|
|
349
|
+
expect(surface.illegal).toEqual([]);
|
|
350
|
+
});
|
|
351
|
+
|
|
352
|
+
it('类型清单与冻结集逐字一致(增删即 breaking,需发布级别裁决)', () => {
|
|
353
|
+
// 解析塌掉不得退化成空集合假绿
|
|
354
|
+
expect(surface.types.length).toBeGreaterThan(0);
|
|
355
|
+
expect([...surface.types].sort()).toEqual([...PUBLISHED_ENTRY_TYPES[sub]].sort());
|
|
356
|
+
});
|
|
357
|
+
});
|
|
358
|
+
}
|
|
359
|
+
});
|
|
@@ -3,11 +3,15 @@
|
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
5
|
import { describe, it, expect, beforeAll, afterAll } from '@jest/globals';
|
|
6
|
-
import {
|
|
6
|
+
import {
|
|
7
|
+
TraceAnalyzer,
|
|
8
|
+
summarizeTraces,
|
|
9
|
+
detectTraceAnomalies,
|
|
10
|
+
} from '../monitoring/trace-analyzer';
|
|
7
11
|
import { TraceCollector } from '../monitoring/traces';
|
|
8
12
|
import * as fs from 'fs';
|
|
9
13
|
import * as path from 'path';
|
|
10
|
-
import type { ExecutionTrace } from '../types/trace';
|
|
14
|
+
import type { ExecutionTrace, TraceSummary } from '../types/trace';
|
|
11
15
|
|
|
12
16
|
describe('TraceAnalyzer', () => {
|
|
13
17
|
const tempDir = path.join(process.cwd(), 'temp-test-analyzer');
|
|
@@ -127,4 +131,50 @@ describe('TraceAnalyzer', () => {
|
|
|
127
131
|
expect(customAnalyzer).toBeDefined();
|
|
128
132
|
});
|
|
129
133
|
});
|
|
134
|
+
|
|
135
|
+
// ADR-0020:summarize / detectAnomalies 的判定本体住在模块级纯函数上,
|
|
136
|
+
// 类壳只是转发。下面两枚用例直调模块级函数,钉住这个 interface——
|
|
137
|
+
// 经类壳的既有覆盖(上文)删不掉它,反之它也不依赖任何 collector/文件 IO。
|
|
138
|
+
describe('模块级纯函数', () => {
|
|
139
|
+
it('summarizeTraces 不构造 collector 即可汇总,skip 不进 pass/fail 分母', () => {
|
|
140
|
+
const traces: ExecutionTrace[] = [
|
|
141
|
+
{ constraintId: 'pure', level: 'iron_law', timestamp: 1000, result: 'pass' },
|
|
142
|
+
{ constraintId: 'pure', level: 'iron_law', timestamp: 2000, result: 'fail' },
|
|
143
|
+
{ constraintId: 'pure', level: 'iron_law', timestamp: 3000, result: 'skip' },
|
|
144
|
+
];
|
|
145
|
+
|
|
146
|
+
const summaries = summarizeTraces(traces);
|
|
147
|
+
|
|
148
|
+
expect(summaries).toHaveLength(1);
|
|
149
|
+
const summary = summaries[0];
|
|
150
|
+
expect(summary.constraintId).toBe('pure');
|
|
151
|
+
expect(summary.totalChecks).toBe(3);
|
|
152
|
+
expect(summary.skipCount).toBe(1);
|
|
153
|
+
expect(summary.passRate).toBeCloseTo(0.5);
|
|
154
|
+
expect(summary.failRate).toBeCloseTo(0.5);
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
it('detectTraceAnomalies 的阈值经参数传入,默认与自定义各判一次', () => {
|
|
158
|
+
// failRate 6/14 ≈ 0.43 且趋势上升:默认阈值 0.5 不触发,0.3 触发
|
|
159
|
+
const summary: TraceSummary = {
|
|
160
|
+
constraintId: 'param_threshold',
|
|
161
|
+
level: 'iron_law',
|
|
162
|
+
timeRange: { start: 1000, end: 2400 },
|
|
163
|
+
totalChecks: 14,
|
|
164
|
+
passCount: 8,
|
|
165
|
+
failCount: 6,
|
|
166
|
+
ignoreCount: 0,
|
|
167
|
+
passRate: 8 / 14,
|
|
168
|
+
failRate: 6 / 14,
|
|
169
|
+
recentTrend: 'rising',
|
|
170
|
+
};
|
|
171
|
+
|
|
172
|
+
expect(detectTraceAnomalies([summary])).toEqual([]);
|
|
173
|
+
|
|
174
|
+
const anomalies = detectTraceAnomalies([summary], { thresholds: { failRate: 0.3 } });
|
|
175
|
+
const rising = anomalies.find(a => a.type === 'rising_fail_rate');
|
|
176
|
+
expect(rising?.constraintId).toBe('param_threshold');
|
|
177
|
+
expect(rising?.data.threshold).toBe(0.3);
|
|
178
|
+
});
|
|
179
|
+
});
|
|
130
180
|
});
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# cli/commands/
|
|
2
2
|
|
|
3
3
|
## 职责
|
|
4
|
-
CLI 子命令实现:
|
|
4
|
+
CLI 子命令实现:21 个顶层命令 + constraints 治理子命令 report/retire,覆盖约束检查/门禁验证/文档同步/知识管理/失败诊断/发布等。
|
|
5
5
|
|
|
6
6
|
H5(#44)起:
|
|
7
7
|
- **命令定义即注册**:`definitions.ts` 的 `COMMAND_DEFINITIONS` 是命令形状(名称/别名/位置参数/选项/子命令/实现引用)的单一来源;bin/harness.js 遍历本表注册表驱动生成,不再手写 commander 命令块,不再有 index.ts barrel 两处同步(R6)
|
|
@@ -10,7 +10,7 @@ H5(#44)起:
|
|
|
10
10
|
## 核心导出
|
|
11
11
|
- `COMMAND_DEFINITIONS`(definitions.ts)— 全部非门禁命令定义(纯数据模块、零闭包,禁止 import 命令实现;ADR-0010)
|
|
12
12
|
- 命令契约(`src/cli/command-contract.ts`,上层目录)— `CommandResult` / `CommandKind` / `CommandIO` / `processIO` / `captureIO` / `lastJsonOutput` / `log` / `logError`
|
|
13
|
-
- 各命令文件:check / validate / passes-gate / init / report / status / spec / sync-docs / knowledge / sdd / failure / posteval-plan / release /
|
|
13
|
+
- 各命令文件:check / validate / passes-gate / init / report / status / spec / sync-docs / knowledge / sdd / failure / posteval-plan / release / constraints / spec-baseline-check
|
|
14
14
|
- 6 门禁命令实现在 `acceptance` / `command` / `contract` / `performance` / `review` / `security`(其 CLI 元数据在 `src/gates/definitions.ts`,形状同为 `CommandDefinition`,ADR-0007)
|
|
15
15
|
|
|
16
16
|
`constraints` 下挂治理子命令:`constraints report`(使用统计 + 退役候选诊断 + 配置健康 + 注入漂移,`--export` 脱敏)、`constraints retire`(交互选择 + 人确认退役;带 id 直达需显式 `--yes`(#24 人确认闸门),无 `--yes` 报错 + 非零退出码且不落盘;内置落 config.yml retired 元数据,custom 落 custom-constraints.yml 条目 retired 段(studio#82 D6 一处真相)+ KnowledgeStore 沉淀 + 治理注入段同步)。
|
|
@@ -29,6 +29,7 @@ H5(#44)起:
|
|
|
29
29
|
- **definitions.ts 是纯数据模块(ADR-0010 后零闭包)**:禁止 import 任何命令实现/运行时依赖(保 --help/--version 懒加载);子命令别名是数据(条目 `aliases: string[]`,不复印整块),实参编组(缺参闸门/强转/兜底)归各命令模块的具名导出(如 `knowledgeSearchCommand`/`coverageCheck`);实现引用可解析性由 `__tests__/registry.test.ts` 构建/测试期断言
|
|
30
30
|
- 命令选项类型命名规范:XxxOptions
|
|
31
31
|
- **本层是上行数据的注入方(harness#88)**:core 对 cli/gates/monitoring 零值导入,故 `check`/`report` 自己 `new ConstraintChecker(getTraceCollector())`(组合根接线 trace 记录器;用 `constraintChecker`/`getInstance()` 拿到的默认实例不写 trace),`sync-docs` 把 `COMMAND_DEFINITIONS` + `GATE_DEFINITIONS` 组装成 `CapabilityDefinitionSource` 注入 `capabilities-parser` 供能力清单计数
|
|
32
|
+
- **数据已在手就不再构造带 IO 副作用的实例(ADR-0020)**:`status` 按 projectPath 直读出 traces 后,直调 `monitoring/trace-analyzer` 的模块级纯函数 `summarizeTraces()`/`detectTraceAnomalies()`,不再 `new TraceCollector({traceFile})` + `new TraceAnalyzer(c)`——collector 构造函数带 mkdir 副作用,而这条路径上它的读方法从未被调用,实例纯属构造仪式。机器可检:`__tests__/status-analysis-wiring.test.ts`(源形状闸:命令体不得出现 `new TraceCollector`/`new TraceAnalyzer`,也不 import `monitoring/traces`)
|
|
32
33
|
- **projectPath 只在入口兜底一次,并传到每个 IO/执行点(harness#95)**:`-p/--project-path` 的 cwd 兜底唯一落点是命令模块入口(`const projectPath = options.projectPath || process.cwd()`);往下每层只能收参数,**禁止再取一次 `process.cwd()`、也禁止用相对路径默认值**——两者都让 `-p` 半失效:执行/读写位置悄悄回到调用方 cwd,而 acceptance 的「无 tasks.yml 即跳过」本身就是 `passed:true`,于是失效表现为假绿。落地形状:执行/IO 根用**必传形参**表达(`PassesGate.runTests(workDir)`),门禁内的相对子路径锚到 projectPath:`ContractGate` 一直是 `path.join(context.projectPath, contractPath)`,`SpecAcceptanceGate` 的 tasksPath 随 #95 对齐成 `path.resolve(projectPath, 相对值)`(绝对值原样,缺省 `<projectPath>/tasks.yml`)
|
|
33
34
|
- 机器可检:`__tests__/project-path-convention.test.ts` 三道闸——CLI 层 cwd 必须是 `xxx || process.cwd()` 兜底形状、下游层(= src 减 cli)cwd 站点**逐行**冻结(#98,豁免文件内新增行/行变形同样失败)、相对路径默认值冻结(#98 收紧:`xxxPath: '相对值'` 对象字面量之外,参数默认值形/模板字面量/双引号形同罪,扫描域 = 整个下游层);豁免逐条带理由,站点消失却不删条目同样失败
|
|
34
35
|
- 行为可检:`__tests__/project-path-anchoring.test.ts` 前提统一 **cwd ≠ projectPath**、不 mock 任何 IO,断言测试真在 B 执行、证据落 `B/.harness/evidence/`、acceptance 读 `B/tasks.yml`。「根已传入却又取 cwd」这类静态看不出的漂移由它守,冻结表守的是不再新增站点
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* passes-gate 重试选项死旗帜闸(code-review A1)
|
|
3
|
+
*
|
|
4
|
+
* 重试实现原住 `setPasses`,随 ADR-0022 删除后 `PassesGateConfig.maxRetries` /
|
|
5
|
+
* `retryDelay` 整条装配链只剩写入方、全仓无读取方——`harness passes-gate
|
|
6
|
+
* --max-retries N` 是恒不生效选项。ADR-0018 删 performance 幽灵旗帜的判据
|
|
7
|
+
* (只执法有真实现的维度)据此收口。
|
|
8
|
+
*
|
|
9
|
+
* 手法同 #125 的 AC-007:编译期 `@ts-expect-error` 钉字段不存在 + 运行期钉定义表与源形状。
|
|
10
|
+
* `src/agents/types.ts` 的 `maxRetries` 是 AgentLifecycle 自有字段(`lifecycle.ts` 真读取),
|
|
11
|
+
* 不在本闸范围内。
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import * as fs from 'fs';
|
|
15
|
+
import * as path from 'path';
|
|
16
|
+
import { COMMAND_DEFINITIONS, type CommandDefinition } from '../definitions';
|
|
17
|
+
import { GATE_DEFINITIONS } from '../../../gates/definitions';
|
|
18
|
+
import type { PassesGateConfig } from '../../../types/passes-gate';
|
|
19
|
+
import type { PassesGateOptions } from '../passes-gate';
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* 已删旗帜的精确令牌(二次复审 S2 收口)
|
|
23
|
+
*
|
|
24
|
+
* `--max-retries` 的旗帜名 + 它在 commander 里的选项键名(`optionRoutes.flag` 按键路由,
|
|
25
|
+
* 是同一个已删选项的第二个落点)。**只钉这两个令牌**,不钉「retry 这个词」。
|
|
26
|
+
*/
|
|
27
|
+
const DELETED_FLAG_TOKENS = ['--max-retries', 'maxRetries'];
|
|
28
|
+
|
|
29
|
+
interface FlagSite {
|
|
30
|
+
/** 命令位(含父命令前缀,如 'constraints report') */
|
|
31
|
+
slot: string;
|
|
32
|
+
/** 旗帜令牌('-t' / '--test-command')或选项路由键('list') */
|
|
33
|
+
token: string;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/** 递归收集命令位上的旗帜令牌与选项路由键(走法同 registry.test.ts 的 collectRefs) */
|
|
37
|
+
function collectFlagSites(defs: CommandDefinition[], prefix = ''): FlagSite[] {
|
|
38
|
+
return defs.flatMap((def) => {
|
|
39
|
+
const slot = [prefix, def.command].filter(Boolean).join(' ');
|
|
40
|
+
const own: FlagSite[] = [
|
|
41
|
+
...def.options.flatMap((option) =>
|
|
42
|
+
option.flags
|
|
43
|
+
.split(/[\s,]+/)
|
|
44
|
+
.filter((token) => token.startsWith('-'))
|
|
45
|
+
.map((token) => ({ slot, token })),
|
|
46
|
+
),
|
|
47
|
+
...(def.optionRoutes || []).map((route) => ({ slot, token: route.flag })),
|
|
48
|
+
];
|
|
49
|
+
return [...own, ...collectFlagSites(def.children || [], slot)];
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function sitesHoldingDeletedFlag(sites: FlagSite[]): FlagSite[] {
|
|
54
|
+
return sites.filter((site) => DELETED_FLAG_TOKENS.includes(site.token));
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/** 全部命令位:通用命令表 + 门禁命令表(GATE_DEFINITIONS.cli 由 bin 同一引擎生成命令块) */
|
|
58
|
+
const ALL_CLI_SITES = [
|
|
59
|
+
...collectFlagSites(COMMAND_DEFINITIONS),
|
|
60
|
+
...collectFlagSites(GATE_DEFINITIONS.map((gate) => gate.cli)),
|
|
61
|
+
];
|
|
62
|
+
|
|
63
|
+
const passesGateCommand = COMMAND_DEFINITIONS.find(d => d.command === 'passes-gate');
|
|
64
|
+
const cliSource = fs.readFileSync(path.join(__dirname, '..', 'passes-gate.ts'), 'utf-8');
|
|
65
|
+
const validatorSource = fs.readFileSync(
|
|
66
|
+
path.join(__dirname, '..', '..', '..', 'core', 'validators', 'passes-gate.ts'),
|
|
67
|
+
'utf-8',
|
|
68
|
+
);
|
|
69
|
+
|
|
70
|
+
describe('passes-gate 重试选项已删除(A1)', () => {
|
|
71
|
+
it('定义表已注册 passes-gate(前提)', () => {
|
|
72
|
+
expect(passesGateCommand).toBeDefined();
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
it('passes-gate 旗帜面逐字冻结,不含 --max-retries', () => {
|
|
76
|
+
expect((passesGateCommand?.options || []).map(o => o.flags)).toEqual([
|
|
77
|
+
'-t, --test-command <command>',
|
|
78
|
+
'-p, --project-path <path>',
|
|
79
|
+
'--allow-partial',
|
|
80
|
+
'--coverage',
|
|
81
|
+
'--coverage-threshold <n>',
|
|
82
|
+
]);
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
it('采集面确实覆盖三类命令位(前提,防空扫致闸失效)', () => {
|
|
86
|
+
const rendered = ALL_CLI_SITES.map(s => `${s.slot} ${s.token}`);
|
|
87
|
+
expect(rendered).toContain('passes-gate --coverage-threshold'); // 通用表叶子命令的旗帜
|
|
88
|
+
expect(rendered).toContain('constraints report --json'); // children 递归(嵌套命令位)
|
|
89
|
+
expect(rendered).toContain('acceptance --task-id'); // 门禁表命令位(GATE_DEFINITIONS.cli)
|
|
90
|
+
expect(rendered).toContain('check list'); // 选项路由键(commander camelCase 键位)
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
it('已删的 --max-retries 不在任何命令位复活(逐命令逐选项精确冻结)', () => {
|
|
94
|
+
expect(sitesHoldingDeletedFlag(ALL_CLI_SITES)).toEqual([]);
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* 旧闸(A5 引入的全表禁词版)——原样保留,与上面的精确冻结并存。
|
|
99
|
+
* 它宽于「冻结已删选项」这一意图:将来任何命令新增合法的 retries 类选项都会被拦。
|
|
100
|
+
* 收窄(即删掉这条)是二次复审 S2 的应修项,但删除断言属 `no_test_simplification`
|
|
101
|
+
* 铁律拦截范围、而该闸无批准通道,故本轮只加不改,退役动作交人类裁决。
|
|
102
|
+
*/
|
|
103
|
+
it('命令定义表任意层级都不含 retry 旗帜(防换个命令位复活)', () => {
|
|
104
|
+
expect(JSON.stringify(COMMAND_DEFINITIONS)).not.toMatch(/retry/i);
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* 反向验闸(二次复审 S2):把已删旗帜分别挂到「另一条通用命令 / 门禁命令 / 选项路由键」
|
|
109
|
+
* 三处,断言扫描逐字报出——证明换掉的不是空洞,也证明覆盖面真的等于名义上的「任何命令位」。
|
|
110
|
+
* 将来若要在别的命令位做**有真实现**的重试,那是新设计:显式评审后把令牌从
|
|
111
|
+
* DELETED_FLAG_TOKENS 解除(同 ADR-0022 推翻 AC-007 的做法),不靠闸静默放行。
|
|
112
|
+
*/
|
|
113
|
+
it('闸非空洞:复活在别的命令位仍会红(通用命令 / 门禁命令 / 选项路由键)', () => {
|
|
114
|
+
const probe = { flags: '--max-retries <n>', description: '复活探针' };
|
|
115
|
+
const otherCommand = COMMAND_DEFINITIONS.find(d => d.command === 'check')!;
|
|
116
|
+
const gateSlot = GATE_DEFINITIONS.find(g => g.id === 'acceptance')!;
|
|
117
|
+
|
|
118
|
+
const resurrected = [
|
|
119
|
+
...collectFlagSites([{ ...otherCommand, options: [...otherCommand.options, probe] }]),
|
|
120
|
+
...collectFlagSites([{ ...gateSlot.cli, options: [...gateSlot.cli.options, probe] }]),
|
|
121
|
+
...collectFlagSites([{
|
|
122
|
+
...otherCommand,
|
|
123
|
+
optionRoutes: [...(otherCommand.optionRoutes || []), { ...otherCommand.optionRoutes![0], flag: 'maxRetries' }],
|
|
124
|
+
}]),
|
|
125
|
+
];
|
|
126
|
+
|
|
127
|
+
expect(sitesHoldingDeletedFlag(resurrected).map(s => `${s.slot} ${s.token}`)).toEqual([
|
|
128
|
+
'check --max-retries',
|
|
129
|
+
'acceptance --max-retries',
|
|
130
|
+
'check maxRetries',
|
|
131
|
+
]);
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
it('CLI 装配链与 validator 默认配置都不再写重试字段', () => {
|
|
135
|
+
expect(cliSource).not.toMatch(/maxRetries|retryDelay/);
|
|
136
|
+
expect(validatorSource).not.toMatch(/maxRetries|retryDelay/);
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
it('PassesGateConfig / PassesGateOptions 的重试字段已从类型面消失(编译期钉)', () => {
|
|
140
|
+
// @ts-expect-error maxRetries 只写不读,随 A1 从 PassesGateConfig 删除
|
|
141
|
+
const removedMaxRetries: PassesGateConfig = { maxRetries: 2 };
|
|
142
|
+
// @ts-expect-error retryDelay 只写不读,随 A1 从 PassesGateConfig 删除
|
|
143
|
+
const removedRetryDelay: PassesGateConfig = { retryDelay: 1000 };
|
|
144
|
+
// @ts-expect-error CLI 侧同名字段随旗帜与装配一并删除
|
|
145
|
+
const removedOption: PassesGateOptions = { maxRetries: 2 };
|
|
146
|
+
expect([removedMaxRetries, removedRetryDelay, removedOption]).toHaveLength(3);
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
it('活字段仍可赋值(防止删多)', () => {
|
|
150
|
+
const live: PassesGateConfig = {
|
|
151
|
+
enabled: true,
|
|
152
|
+
testCommand: 'npm test',
|
|
153
|
+
requireEvidence: false,
|
|
154
|
+
allowPartialPass: true,
|
|
155
|
+
};
|
|
156
|
+
expect(Object.keys(live)).toHaveLength(4);
|
|
157
|
+
});
|
|
158
|
+
});
|
|
@@ -130,9 +130,13 @@ describe('passes-gate command', () => {
|
|
|
130
130
|
}));
|
|
131
131
|
|
|
132
132
|
await runPassesGate({ testCommand: 'pytest' }, io);
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
133
|
+
// 精确形状(A1):装配面只剩四个活字段,只写不读的重试字段已随旗帜一并删除
|
|
134
|
+
expect(MockPassesGate).toHaveBeenCalledWith({
|
|
135
|
+
enabled: true,
|
|
136
|
+
testCommand: 'pytest',
|
|
137
|
+
requireEvidence: false,
|
|
138
|
+
allowPartialPass: false,
|
|
139
|
+
});
|
|
136
140
|
});
|
|
137
141
|
});
|
|
138
142
|
|