@dommaker/harness 1.9.0 → 1.10.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 +6 -0
- package/README.md +9 -12
- package/dist/cli/commands/check.d.ts +3 -3
- package/dist/cli/commands/check.d.ts.map +1 -1
- package/dist/cli/commands/check.js +41 -78
- package/dist/cli/commands/check.js.map +1 -1
- package/dist/cli/commands/constraints-report.d.ts +2 -10
- package/dist/cli/commands/constraints-report.d.ts.map +1 -1
- package/dist/cli/commands/constraints-report.js +4 -57
- package/dist/cli/commands/constraints-report.js.map +1 -1
- package/dist/cli/commands/constraints-retire.d.ts +9 -23
- package/dist/cli/commands/constraints-retire.d.ts.map +1 -1
- package/dist/cli/commands/constraints-retire.js +39 -121
- package/dist/cli/commands/constraints-retire.js.map +1 -1
- package/dist/cli/commands/constraints.d.ts +3 -8
- package/dist/cli/commands/constraints.d.ts.map +1 -1
- package/dist/cli/commands/constraints.js +8 -23
- package/dist/cli/commands/constraints.js.map +1 -1
- package/dist/cli/commands/definitions.js +2 -2
- package/dist/cli/commands/init.d.ts +0 -32
- package/dist/cli/commands/init.d.ts.map +1 -1
- package/dist/cli/commands/init.js +7 -149
- package/dist/cli/commands/init.js.map +1 -1
- package/dist/cli/commands/report.d.ts.map +1 -1
- package/dist/cli/commands/report.js +14 -17
- package/dist/cli/commands/report.js.map +1 -1
- package/dist/cli/commands/scaffold-templates.d.ts +0 -2
- package/dist/cli/commands/scaffold-templates.d.ts.map +1 -1
- package/dist/cli/commands/scaffold-templates.js +2 -37
- package/dist/cli/commands/scaffold-templates.js.map +1 -1
- package/dist/cli/commands/scaffold.d.ts +0 -2
- package/dist/cli/commands/scaffold.d.ts.map +1 -1
- package/dist/cli/commands/scaffold.js +0 -10
- package/dist/cli/commands/scaffold.js.map +1 -1
- package/dist/cli/commands/status.js +10 -10
- package/dist/cli/commands/status.js.map +1 -1
- package/dist/cli/commands/sync-docs/agents-syncer.d.ts +0 -2
- package/dist/cli/commands/sync-docs/agents-syncer.d.ts.map +1 -1
- package/dist/cli/commands/sync-docs/agents-syncer.js +4 -23
- package/dist/cli/commands/sync-docs/agents-syncer.js.map +1 -1
- package/dist/core/constraints/capabilities-parser.d.ts.map +1 -1
- package/dist/core/constraints/capabilities-parser.js +16 -4
- package/dist/core/constraints/capabilities-parser.js.map +1 -1
- package/dist/core/constraints/checker.d.ts +15 -24
- package/dist/core/constraints/checker.d.ts.map +1 -1
- package/dist/core/constraints/checker.js +33 -72
- package/dist/core/constraints/checker.js.map +1 -1
- package/dist/core/constraints/checkers/docs-freshness.js +1 -1
- package/dist/core/constraints/checkers/docs-freshness.js.map +1 -1
- package/dist/core/constraints/checkers/governance-presence.d.ts +2 -1
- package/dist/core/constraints/checkers/governance-presence.d.ts.map +1 -1
- package/dist/core/constraints/checkers/governance-presence.js +4 -3
- package/dist/core/constraints/checkers/governance-presence.js.map +1 -1
- package/dist/core/constraints/checkers/index.d.ts +1 -1
- package/dist/core/constraints/checkers/index.d.ts.map +1 -1
- package/dist/core/constraints/checkers/index.js +4 -8
- package/dist/core/constraints/checkers/index.js.map +1 -1
- package/dist/core/constraints/checkers/iron-flags.d.ts +3 -4
- package/dist/core/constraints/checkers/iron-flags.d.ts.map +1 -1
- package/dist/core/constraints/checkers/iron-flags.js +4 -5
- package/dist/core/constraints/checkers/iron-flags.js.map +1 -1
- package/dist/core/constraints/checkers/no-test-simplification.js +1 -1
- package/dist/core/constraints/checkers/no-test-simplification.js.map +1 -1
- package/dist/core/constraints/checkers/types.d.ts +1 -1
- package/dist/core/constraints/checkers/types.js +1 -1
- package/dist/core/constraints/definitions/guidelines.d.ts +4 -4
- package/dist/core/constraints/definitions/guidelines.d.ts.map +1 -1
- package/dist/core/constraints/definitions/guidelines.js +9 -25
- package/dist/core/constraints/definitions/guidelines.js.map +1 -1
- package/dist/core/constraints/definitions/iron-laws.d.ts +4 -4
- package/dist/core/constraints/definitions/iron-laws.d.ts.map +1 -1
- package/dist/core/constraints/definitions/iron-laws.js +10 -81
- package/dist/core/constraints/definitions/iron-laws.js.map +1 -1
- package/dist/core/constraints/definitions.d.ts +7 -9
- package/dist/core/constraints/definitions.d.ts.map +1 -1
- package/dist/core/constraints/definitions.js +13 -16
- package/dist/core/constraints/definitions.js.map +1 -1
- package/dist/core/constraints/index.d.ts +2 -5
- package/dist/core/constraints/index.d.ts.map +1 -1
- package/dist/core/constraints/index.js +3 -13
- package/dist/core/constraints/index.js.map +1 -1
- package/dist/core/constraints/injection-writer.d.ts +10 -38
- package/dist/core/constraints/injection-writer.d.ts.map +1 -1
- package/dist/core/constraints/injection-writer.js +17 -54
- package/dist/core/constraints/injection-writer.js.map +1 -1
- package/dist/core/constraints/run-env.d.ts +1 -10
- package/dist/core/constraints/run-env.d.ts.map +1 -1
- package/dist/core/constraints/run-env.js +1 -22
- package/dist/core/constraints/run-env.js.map +1 -1
- package/dist/core/constraints/usage-report.d.ts +5 -7
- package/dist/core/constraints/usage-report.d.ts.map +1 -1
- package/dist/core/constraints/usage-report.js +5 -10
- package/dist/core/constraints/usage-report.js.map +1 -1
- package/dist/core/effective-constraints.d.ts +12 -22
- package/dist/core/effective-constraints.d.ts.map +1 -1
- package/dist/core/effective-constraints.js +13 -30
- package/dist/core/effective-constraints.js.map +1 -1
- package/dist/core/index.d.ts +2 -2
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +3 -9
- package/dist/core/index.js.map +1 -1
- package/dist/core/project-config-loader.d.ts +4 -42
- package/dist/core/project-config-loader.d.ts.map +1 -1
- package/dist/core/project-config-loader.js +16 -125
- package/dist/core/project-config-loader.js.map +1 -1
- package/dist/core/validators/passes-gate.d.ts +2 -2
- package/dist/core/validators/passes-gate.js +6 -6
- package/dist/core/validators/passes-gate.js.map +1 -1
- package/dist/index.d.ts +7 -10
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +9 -18
- package/dist/index.js.map +1 -1
- package/dist/monitoring/trace-analyzer.d.ts.map +1 -1
- package/dist/monitoring/trace-analyzer.js +11 -12
- package/dist/monitoring/trace-analyzer.js.map +1 -1
- package/dist/monitoring/traces.d.ts +4 -4
- package/dist/monitoring/traces.d.ts.map +1 -1
- package/dist/monitoring/traces.js +8 -8
- package/dist/monitoring/traces.js.map +1 -1
- package/dist/presets/standard.d.ts +8 -10
- package/dist/presets/standard.d.ts.map +1 -1
- package/dist/presets/standard.js +10 -16
- package/dist/presets/standard.js.map +1 -1
- package/dist/types/constraint.d.ts +24 -35
- package/dist/types/constraint.d.ts.map +1 -1
- package/dist/types/constraint.js +8 -7
- package/dist/types/constraint.js.map +1 -1
- package/dist/types/passes-gate.d.ts +5 -5
- package/dist/types/passes-gate.d.ts.map +1 -1
- package/dist/types/project-config.d.ts +8 -66
- package/dist/types/project-config.d.ts.map +1 -1
- package/dist/types/project-config.js +3 -2
- package/dist/types/project-config.js.map +1 -1
- package/dist/types/trace.d.ts +8 -10
- package/dist/types/trace.d.ts.map +1 -1
- package/package.json +2 -2
- package/src/CONTEXT.md +2 -2
- package/src/__tests__/checker-extra.test.ts +37 -61
- package/src/__tests__/checker.test.ts +10 -115
- package/src/__tests__/effective-constraints.test.ts +18 -83
- package/src/__tests__/iron-laws.test.ts +71 -90
- package/src/__tests__/passes-gate-check.test.ts +2 -2
- package/src/__tests__/project-config-loader-extra.test.ts +22 -123
- package/src/__tests__/project-config-loader.test.ts +5 -33
- package/src/__tests__/public-exports.test.ts +1 -7
- package/src/__tests__/public-type-surface.test.ts +2 -5
- package/src/__tests__/public-value-surface.test.ts +1 -7
- package/src/__tests__/skip-semantics.test.ts +21 -37
- package/src/__tests__/trace-analyzer-extra.test.ts +14 -14
- package/src/__tests__/trace-analyzer.test.ts +21 -21
- package/src/__tests__/trace-collector.test.ts +22 -22
- package/src/__tests__/traces.test.ts +27 -28
- package/src/cli/commands/CONTEXT.md +9 -9
- package/src/cli/commands/__tests__/check-read-count.test.ts +4 -15
- package/src/cli/commands/__tests__/check-skip-output.test.ts +14 -14
- package/src/cli/commands/__tests__/check.test.ts +14 -31
- package/src/cli/commands/__tests__/constraints-report.test.ts +12 -80
- package/src/cli/commands/__tests__/constraints-retire.test.ts +42 -231
- package/src/cli/commands/__tests__/init-governance-io.test.ts +12 -58
- package/src/cli/commands/__tests__/init-ondisk.test.ts +12 -20
- package/src/cli/commands/__tests__/init.test.ts +0 -11
- package/src/cli/commands/__tests__/project-path-anchoring.test.ts +2 -2
- package/src/cli/commands/__tests__/report-extra.test.ts +4 -4
- package/src/cli/commands/__tests__/report.test.ts +1 -1
- package/src/cli/commands/__tests__/scaffold.test.ts +4 -14
- package/src/cli/commands/__tests__/status-analysis-wiring.test.ts +3 -3
- package/src/cli/commands/__tests__/status-extra.test.ts +14 -14
- package/src/cli/commands/__tests__/status.test.ts +12 -12
- package/src/cli/commands/__tests__/sync-docs-agents.test.ts +1 -1
- package/src/cli/commands/check.ts +43 -82
- package/src/cli/commands/constraints-report.ts +4 -59
- package/src/cli/commands/constraints-retire.ts +49 -154
- package/src/cli/commands/constraints.ts +11 -26
- package/src/cli/commands/definitions.ts +2 -2
- package/src/cli/commands/init.ts +8 -179
- package/src/cli/commands/report.ts +19 -23
- package/src/cli/commands/scaffold-templates.ts +1 -37
- package/src/cli/commands/scaffold.ts +0 -11
- package/src/cli/commands/status.ts +10 -10
- package/src/cli/commands/sync-docs/agents-syncer.ts +4 -25
- package/src/core/CONTEXT.md +9 -9
- package/src/core/constraints/__tests__/capability-counts.test.ts +5 -5
- package/src/core/constraints/__tests__/collect-constraints.test.ts +13 -8
- package/src/core/constraints/__tests__/git-evidence.test.ts +4 -7
- package/src/core/constraints/__tests__/injection-writer.test.ts +8 -61
- package/src/core/constraints/__tests__/run-env.test.ts +5 -34
- package/src/core/constraints/__tests__/trace-injection.test.ts +1 -1
- package/src/core/constraints/capabilities-parser.ts +17 -5
- package/src/core/constraints/checker.ts +39 -88
- package/src/core/constraints/checkers/__tests__/check-outcome.test.ts +5 -8
- package/src/core/constraints/checkers/__tests__/governance-presence.test.ts +1 -53
- package/src/core/constraints/checkers/__tests__/iron-flags.test.ts +5 -25
- package/src/core/constraints/checkers/docs-freshness.ts +1 -1
- package/src/core/constraints/checkers/governance-presence.ts +4 -3
- package/src/core/constraints/checkers/index.ts +4 -10
- package/src/core/constraints/checkers/iron-flags.ts +3 -12
- package/src/core/constraints/checkers/no-test-simplification.ts +1 -1
- package/src/core/constraints/checkers/types.ts +1 -1
- package/src/core/constraints/definitions/guidelines.ts +8 -25
- package/src/core/constraints/definitions/iron-laws.ts +9 -82
- package/src/core/constraints/definitions.ts +14 -15
- package/src/core/constraints/index.ts +4 -19
- package/src/core/constraints/injection-writer.ts +16 -61
- package/src/core/constraints/run-env.ts +1 -33
- package/src/core/constraints/usage-report.ts +8 -15
- package/src/core/effective-constraints.ts +14 -45
- package/src/core/index.ts +3 -10
- package/src/core/project-config-loader.ts +20 -145
- package/src/core/validators/passes-gate.ts +6 -6
- package/src/failure/CONTEXT.md +1 -1
- package/src/hooks/__tests__/bootstrap.test.ts +3 -5
- package/src/index.ts +8 -18
- package/src/monitoring/__tests__/trace-file-anchoring.test.ts +1 -1
- package/src/monitoring/__tests__/traces.test.ts +22 -22
- package/src/monitoring/trace-analyzer.ts +12 -13
- package/src/monitoring/traces.ts +8 -8
- package/src/presets/__tests__/standard.test.ts +12 -16
- package/src/presets/standard.ts +14 -23
- package/src/types/__tests__/types.test.ts +3 -3
- package/src/types/constraint.ts +26 -40
- package/src/types/passes-gate.ts +5 -5
- package/src/types/project-config.ts +8 -77
- package/src/types/trace.ts +8 -11
- package/dist/core/constraints/agent-prompt-renderer.d.ts +0 -32
- package/dist/core/constraints/agent-prompt-renderer.d.ts.map +0 -1
- package/dist/core/constraints/agent-prompt-renderer.js +0 -55
- package/dist/core/constraints/agent-prompt-renderer.js.map +0 -1
- package/dist/core/constraints/checkers/no-bypass-checkpoint.d.ts +0 -6
- package/dist/core/constraints/checkers/no-bypass-checkpoint.d.ts.map +0 -1
- package/dist/core/constraints/checkers/no-bypass-checkpoint.js +0 -40
- package/dist/core/constraints/checkers/no-bypass-checkpoint.js.map +0 -1
- package/dist/core/constraints/definitions/prompts.d.ts +0 -12
- package/dist/core/constraints/definitions/prompts.d.ts.map +0 -1
- package/dist/core/constraints/definitions/prompts.js +0 -400
- package/dist/core/constraints/definitions/prompts.js.map +0 -1
- package/dist/core/constraints/injection-drift.d.ts +0 -61
- package/dist/core/constraints/injection-drift.d.ts.map +0 -1
- package/dist/core/constraints/injection-drift.js +0 -131
- package/dist/core/constraints/injection-drift.js.map +0 -1
- package/dist/core/constraints/injection-renderer.d.ts +0 -23
- package/dist/core/constraints/injection-renderer.d.ts.map +0 -1
- package/dist/core/constraints/injection-renderer.js +0 -44
- package/dist/core/constraints/injection-renderer.js.map +0 -1
- package/src/cli/commands/__tests__/check-drift.test.ts +0 -158
- package/src/cli/commands/__tests__/init-injection.test.ts +0 -466
- package/src/core/constraints/__tests__/agent-prompt-renderer.test.ts +0 -129
- package/src/core/constraints/__tests__/injection-drift.test.ts +0 -247
- package/src/core/constraints/agent-prompt-renderer.ts +0 -67
- package/src/core/constraints/checkers/__tests__/no-bypass-checkpoint.test.ts +0 -76
- package/src/core/constraints/checkers/no-bypass-checkpoint.ts +0 -40
- package/src/core/constraints/definitions/prompts.ts +0 -414
- package/src/core/constraints/injection-drift.ts +0 -142
- package/src/core/constraints/injection-renderer.ts +0 -44
|
@@ -1,30 +1,22 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* harness constraints retire —— 约束退役(ADR-0001 决策 2/5
|
|
2
|
+
* harness constraints retire —— 约束退役(ADR-0001 决策 2/5,ADR-0029 收窄)
|
|
3
3
|
*
|
|
4
4
|
* 建议层全自动(候选诊断复用 report 数据层),执行层保留一次人确认。
|
|
5
|
-
*
|
|
5
|
+
* 落盘形态(一处真相):
|
|
6
6
|
*
|
|
7
|
-
* -
|
|
7
|
+
* - config.yml `enabled: false` + `retired` 元数据:
|
|
8
8
|
*
|
|
9
9
|
* constraints:
|
|
10
10
|
* <id>:
|
|
11
11
|
* enabled: false
|
|
12
12
|
* retired: { at, reason, stats: { total, fail, failRate } }
|
|
13
13
|
*
|
|
14
|
-
*
|
|
15
|
-
* (不拆 config.yml 第二处):
|
|
14
|
+
* 每条同时写一条 KnowledgeStore 记录(consumptionMode: 'signal')。
|
|
16
15
|
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
* rule: ...
|
|
20
|
-
* retired: { at, reason, stats: { total, fail, failRate } }
|
|
21
|
-
*
|
|
22
|
-
* 每条同时写一条 KnowledgeStore 记录(consumptionMode: 'signal'),
|
|
23
|
-
* 并同步治理注入段(CLAUDE.md 或 AGENTS.md,存在 HARNESS_CONSTRAINTS 标记时;
|
|
24
|
-
* 落点路由与 init 一致,见 core/constraints/injection-drift resolveInjectionTarget)。
|
|
16
|
+
* ADR-0029:custom 纯文本约束与治理注入段同步已随文本注入层关停一并退役,
|
|
17
|
+
* retire 只处理内置 check 约束。
|
|
25
18
|
*
|
|
26
|
-
* retire
|
|
27
|
-
* custom 删 custom-constraints.yml 中 custom_constraints.<id>.retired 段。
|
|
19
|
+
* retire 不是删除——恢复方法:删 config.yml 中 constraints.<id> 段。
|
|
28
20
|
*
|
|
29
21
|
* 交互与执行分离:retireConstraint 为纯执行逻辑(同步、可测),
|
|
30
22
|
* runRetireInteractive 只做 readline 交互,IO 流可注入。
|
|
@@ -37,11 +29,7 @@ import { log, logError, processIO, type CommandIO, type CommandResult } from '..
|
|
|
37
29
|
import * as yaml from 'js-yaml';
|
|
38
30
|
import chalk from 'chalk';
|
|
39
31
|
import { getConstraint } from '../../core/constraints/definitions';
|
|
40
|
-
import {
|
|
41
|
-
import { replaceStandaloneRange, resolveInjectionTarget } from '../../core/constraints/injection-writer';
|
|
42
|
-
import { getEffectiveConstraints } from '../../core/effective-constraints';
|
|
43
|
-
import { isConstraintRetired, ProjectConfigLoader } from '../../core/project-config-loader';
|
|
44
|
-
import { getHarnessPackageVersion } from '../../utils/package-version';
|
|
32
|
+
import { ProjectConfigLoader } from '../../core/project-config-loader';
|
|
45
33
|
import { FileKnowledgeStore } from '../../knowledge/store';
|
|
46
34
|
import type { KnowledgeEntry } from '../../knowledge/types';
|
|
47
35
|
import type { Constraint } from '../../types/constraint';
|
|
@@ -65,15 +53,9 @@ export type RetireStatus = 'retired' | 'already_retired' | 'unknown_id';
|
|
|
65
53
|
export interface RetireResult {
|
|
66
54
|
id: string;
|
|
67
55
|
status: RetireStatus;
|
|
68
|
-
/** 是否
|
|
69
|
-
|
|
70
|
-
/** 退役落点:custom 约束落 custom-constraints.yml(studio#82 D6),内置落 config.yml */
|
|
71
|
-
landing: 'config.yml' | 'custom-constraints.yml';
|
|
56
|
+
/** 是否 severity='error'(交互模式据此追加确认) */
|
|
57
|
+
isError: boolean;
|
|
72
58
|
stats: { total: number; fail: number; failRate: number };
|
|
73
|
-
/** 治理注入段(CLAUDE.md / AGENTS.md)是否已同步 */
|
|
74
|
-
injectionSynced: boolean;
|
|
75
|
-
/** 实际同步的落点文件(injectionSynced 时存在) */
|
|
76
|
-
injectionFile?: string;
|
|
77
59
|
/** KnowledgeStore 条目 id(status='retired' 时存在) */
|
|
78
60
|
knowledgeEntryId?: string;
|
|
79
61
|
}
|
|
@@ -86,61 +68,34 @@ export interface ConstraintsRetireOptions {
|
|
|
86
68
|
}
|
|
87
69
|
|
|
88
70
|
interface RetireTargetInfo {
|
|
89
|
-
|
|
90
|
-
isIronLaw: boolean;
|
|
91
|
-
level: Constraint['level'];
|
|
71
|
+
severity: Constraint['severity'];
|
|
92
72
|
description?: string;
|
|
93
73
|
rule?: string;
|
|
94
74
|
message?: string;
|
|
95
|
-
promptInjection?: string;
|
|
96
75
|
}
|
|
97
76
|
|
|
98
77
|
/**
|
|
99
|
-
* 查找约束定义(内置 definitions
|
|
78
|
+
* 查找约束定义(内置 definitions)
|
|
100
79
|
*
|
|
101
80
|
* loader 由调用方给(一次退役一份观察面,见 retireConstraint):本函数只读它的装载结果,
|
|
102
81
|
* 不再自造 ProjectConfigLoader。
|
|
103
82
|
*/
|
|
104
|
-
function findRetireTarget(
|
|
105
|
-
loader: ProjectConfigLoader,
|
|
106
|
-
id: string
|
|
107
|
-
): RetireTargetInfo | undefined {
|
|
83
|
+
function findRetireTarget(id: string): RetireTargetInfo | undefined {
|
|
108
84
|
const builtIn = getConstraint(id);
|
|
109
|
-
if (builtIn)
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
message: builtIn.message,
|
|
117
|
-
promptInjection: builtIn.promptInjection,
|
|
118
|
-
};
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
const custom = loader.getCustomConstraints()[id];
|
|
122
|
-
if (custom) {
|
|
123
|
-
const level = custom.level || 'guideline';
|
|
124
|
-
return {
|
|
125
|
-
source: 'custom',
|
|
126
|
-
isIronLaw: false, // custom 约束统一 kind='prompt'(无 checker),不存在 check 层 iron
|
|
127
|
-
level,
|
|
128
|
-
description: custom.description,
|
|
129
|
-
rule: custom.rule,
|
|
130
|
-
message: custom.message,
|
|
131
|
-
promptInjection: custom.promptInjection,
|
|
132
|
-
};
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
return undefined;
|
|
85
|
+
if (!builtIn) return undefined;
|
|
86
|
+
return {
|
|
87
|
+
severity: builtIn.severity,
|
|
88
|
+
description: builtIn.description,
|
|
89
|
+
rule: builtIn.rule,
|
|
90
|
+
message: builtIn.message,
|
|
91
|
+
};
|
|
136
92
|
}
|
|
137
93
|
|
|
138
94
|
/**
|
|
139
95
|
* YAML 条目的读-改-写单点(harness#137)
|
|
140
96
|
*
|
|
141
|
-
* 内置与 custom 两处退役落点原本是两段同型的读-改-写,只差键路径与 patch 内容。
|
|
142
97
|
* js-yaml 不保留注释:原文件含注释行时重写会丢失,console 说明(`label` 是给用户看的
|
|
143
|
-
*
|
|
98
|
+
* 文件名)。落盘字节由 `__tests__/constraints-retire.test.ts`
|
|
144
99
|
* 的逐字节冻结用例钉住——合并属内部重构,对外产物不得漂移。
|
|
145
100
|
*/
|
|
146
101
|
function setYamlEntry(
|
|
@@ -191,7 +146,6 @@ function saveRetireKnowledge(
|
|
|
191
146
|
target.description ? `description: ${target.description}` : undefined,
|
|
192
147
|
target.rule ? `rule: ${target.rule}` : undefined,
|
|
193
148
|
target.message ? `message: ${target.message}` : undefined,
|
|
194
|
-
target.promptInjection ? `promptInjection: ${target.promptInjection}` : undefined,
|
|
195
149
|
'',
|
|
196
150
|
'## 退役原因',
|
|
197
151
|
'',
|
|
@@ -217,7 +171,7 @@ function saveRetireKnowledge(
|
|
|
217
171
|
lastReferenced: iso,
|
|
218
172
|
contributors: [],
|
|
219
173
|
projects: [],
|
|
220
|
-
tags: ['constraint-retired', `constraint:${id}`, `
|
|
174
|
+
tags: ['constraint-retired', `constraint:${id}`, `severity:${target.severity}`],
|
|
221
175
|
applicablePhases: [],
|
|
222
176
|
sourceReferences: [{ timestamp: iso }],
|
|
223
177
|
referencedBy: [],
|
|
@@ -231,26 +185,6 @@ function saveRetireKnowledge(
|
|
|
231
185
|
return entryId;
|
|
232
186
|
}
|
|
233
187
|
|
|
234
|
-
/**
|
|
235
|
-
* 同步治理注入段(CLAUDE.md 或 AGENTS.md,存在 HARNESS_CONSTRAINTS 标记时)
|
|
236
|
-
*
|
|
237
|
-
* 落点路由复用 resolveInjectionTarget(studio #307:新模型仓注入段在
|
|
238
|
-
* AGENTS.md PRESERVE:governance 内;旧模型仓 CLAUDE.md 优先)。
|
|
239
|
-
* 复用 renderConstraintsSection(P3 导出纯函数)按退役后生效集重渲染。
|
|
240
|
-
* 无标记段不动(不追加——retire 不承担 init 职责)。
|
|
241
|
-
*/
|
|
242
|
-
function syncGovernanceInjection(projectRoot: string): { synced: boolean; file?: string } {
|
|
243
|
-
const target = resolveInjectionTarget(projectRoot);
|
|
244
|
-
if (!target) return { synced: false };
|
|
245
|
-
|
|
246
|
-
const body = renderConstraintsSection(getEffectiveConstraints(projectRoot), getHarnessPackageVersion());
|
|
247
|
-
const write = replaceStandaloneRange(target.content, CONSTRAINTS_START_MARKER, CONSTRAINTS_END_MARKER, body);
|
|
248
|
-
if (write.kind === 'updated' && write.content !== target.content) {
|
|
249
|
-
fs.writeFileSync(path.join(projectRoot, target.file), write.content, 'utf-8');
|
|
250
|
-
}
|
|
251
|
-
return { synced: true, file: target.file };
|
|
252
|
-
}
|
|
253
|
-
|
|
254
188
|
/**
|
|
255
189
|
* 执行单条约束退役(纯执行逻辑,无交互)
|
|
256
190
|
*
|
|
@@ -265,27 +199,20 @@ export function retireConstraint(
|
|
|
265
199
|
const iso = now.toISOString();
|
|
266
200
|
const reason = options.reason ?? '';
|
|
267
201
|
|
|
268
|
-
// 一次退役一份观察面(ADR-0023 决策 2
|
|
269
|
-
// 解析共用这一份装载结果。此前同一次调用 new 了 2–3 枚加载器、各带一次 load()(harness#137)。
|
|
270
|
-
// 只覆盖写盘**之前**的读取:写盘后 syncGovernanceInjection 必须读到新状态,另起观察面。
|
|
202
|
+
// 一次退役一份观察面(ADR-0023 决策 2):定义查找与 already_retired 判定共用这一份装载结果。
|
|
271
203
|
const loader = new ProjectConfigLoader(projectRoot);
|
|
272
204
|
loader.load();
|
|
273
205
|
|
|
274
|
-
const target = findRetireTarget(
|
|
206
|
+
const target = findRetireTarget(id);
|
|
275
207
|
const emptyStats = { total: 0, fail: 0, failRate: 0 };
|
|
276
|
-
const landing: RetireResult['landing'] =
|
|
277
|
-
target?.source === 'custom' ? 'custom-constraints.yml' : 'config.yml';
|
|
278
208
|
if (!target) {
|
|
279
|
-
return { id, status: 'unknown_id',
|
|
209
|
+
return { id, status: 'unknown_id', isError: false, stats: emptyStats };
|
|
280
210
|
}
|
|
211
|
+
const isError = target.severity === 'error';
|
|
281
212
|
|
|
282
|
-
//
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
const disabledInConfig = loader.getConfig().constraints?.[id]?.enabled === false;
|
|
286
|
-
const customDef = target.source === 'custom' ? loader.getCustomConstraints()[id] : undefined;
|
|
287
|
-
if (isConstraintRetired(customDef, disabledInConfig)) {
|
|
288
|
-
return { id, status: 'already_retired', isIronLaw: target.isIronLaw, landing, stats: emptyStats, injectionSynced: false };
|
|
213
|
+
// 已退役保护:退役落点只有 config.yml constraints.<id>.enabled:false 一处
|
|
214
|
+
if (loader.getConfig().constraints?.[id]?.enabled === false) {
|
|
215
|
+
return { id, status: 'already_retired', isError, stats: emptyStats };
|
|
289
216
|
}
|
|
290
217
|
|
|
291
218
|
// 历史统计(来自 traces.log)
|
|
@@ -300,42 +227,24 @@ export function retireConstraint(
|
|
|
300
227
|
failRate: evaluated > 0 ? (usage!.fail / evaluated) : 0,
|
|
301
228
|
};
|
|
302
229
|
|
|
303
|
-
// 1. 落盘退役(
|
|
304
|
-
// 两处原文均保留)
|
|
230
|
+
// 1. 落盘退役(config.yml enabled:false + retired 段,原文保留)
|
|
305
231
|
const retiredMeta = { at: iso, reason, stats };
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
{ retired: retiredMeta }
|
|
314
|
-
);
|
|
315
|
-
} else {
|
|
316
|
-
setYamlEntry(
|
|
317
|
-
path.join(projectRoot, '.harness', 'config.yml'),
|
|
318
|
-
'config.yml',
|
|
319
|
-
'constraints',
|
|
320
|
-
id,
|
|
321
|
-
{ enabled: false, retired: retiredMeta }
|
|
322
|
-
);
|
|
323
|
-
}
|
|
232
|
+
setYamlEntry(
|
|
233
|
+
path.join(projectRoot, '.harness', 'config.yml'),
|
|
234
|
+
'config.yml',
|
|
235
|
+
'constraints',
|
|
236
|
+
id,
|
|
237
|
+
{ enabled: false, retired: retiredMeta }
|
|
238
|
+
);
|
|
324
239
|
|
|
325
240
|
// 2. KnowledgeStore
|
|
326
241
|
const knowledgeEntryId = saveRetireKnowledge(projectRoot, id, target, reason, stats, iso);
|
|
327
242
|
|
|
328
|
-
// 3. 治理注入段同步(CLAUDE.md / AGENTS.md,路由见 syncGovernanceInjection)
|
|
329
|
-
const injection = syncGovernanceInjection(projectRoot);
|
|
330
|
-
|
|
331
243
|
return {
|
|
332
244
|
id,
|
|
333
245
|
status: 'retired',
|
|
334
|
-
|
|
335
|
-
landing,
|
|
246
|
+
isError,
|
|
336
247
|
stats,
|
|
337
|
-
injectionSynced: injection.synced,
|
|
338
|
-
injectionFile: injection.file,
|
|
339
248
|
knowledgeEntryId,
|
|
340
249
|
};
|
|
341
250
|
}
|
|
@@ -346,7 +255,7 @@ export function retireConstraint(
|
|
|
346
255
|
export function printRetireResult(result: RetireResult, io: CommandIO = processIO): CommandResult {
|
|
347
256
|
switch (result.status) {
|
|
348
257
|
case 'unknown_id':
|
|
349
|
-
log(io, chalk.red(`❌ ${result.id}:
|
|
258
|
+
log(io, chalk.red(`❌ ${result.id}: 约束不存在(非内置约束),未做任何变更`));
|
|
350
259
|
return { kind: 'skip', reason: `${result.id}: 约束不存在,未做任何变更` };
|
|
351
260
|
case 'already_retired':
|
|
352
261
|
log(io, chalk.yellow(`⚠️ ${result.id}: 已处于退役状态(config.yml 中 enabled: false),跳过`));
|
|
@@ -355,14 +264,7 @@ export function printRetireResult(result: RetireResult, io: CommandIO = processI
|
|
|
355
264
|
log(io, chalk.green(`✅ ${result.id}: 已退役`));
|
|
356
265
|
log(io, ` 历史统计: total=${result.stats.total} fail=${result.stats.fail} fail率=${Math.round(result.stats.failRate * 100)}%`);
|
|
357
266
|
log(io, ` 知识沉淀: ${result.knowledgeEntryId}(.harness/knowledge)`);
|
|
358
|
-
|
|
359
|
-
log(io, ` 已同步 ${result.injectionFile ?? '治理文档'} 注入段`);
|
|
360
|
-
}
|
|
361
|
-
const recovery =
|
|
362
|
-
result.landing === 'custom-constraints.yml'
|
|
363
|
-
? `删除 custom-constraints.yml 中 custom_constraints.${result.id}.retired 段`
|
|
364
|
-
: `删除 config.yml 中 constraints.${result.id} 段`;
|
|
365
|
-
log(io, chalk.gray(` retire 不是删除——恢复方法:${recovery}`));
|
|
267
|
+
log(io, chalk.gray(` retire 不是删除——恢复方法:删除 config.yml 中 constraints.${result.id} 段`));
|
|
366
268
|
break;
|
|
367
269
|
}
|
|
368
270
|
}
|
|
@@ -439,25 +341,23 @@ export async function runRetireInteractive(
|
|
|
439
341
|
selectedIds = [...new Set(selectedIds)];
|
|
440
342
|
}
|
|
441
343
|
|
|
442
|
-
// 逐条收集 reason +
|
|
443
|
-
const
|
|
444
|
-
planLoader.load();
|
|
445
|
-
const plan: { id: string; reason: string; source: RetireTargetInfo['source'] }[] = [];
|
|
344
|
+
// 逐条收集 reason + error 级二次确认
|
|
345
|
+
const plan: { id: string; reason: string }[] = [];
|
|
446
346
|
for (const id of selectedIds) {
|
|
447
|
-
const target = findRetireTarget(
|
|
347
|
+
const target = findRetireTarget(id);
|
|
448
348
|
if (!target) {
|
|
449
349
|
console.log(chalk.red(`❌ ${id}: 约束不存在,跳过`));
|
|
450
350
|
continue;
|
|
451
351
|
}
|
|
452
|
-
if (target.
|
|
453
|
-
const confirm = await ask(chalk.yellow(`⚠️ ${id} 是一条
|
|
352
|
+
if (target.severity === 'error') {
|
|
353
|
+
const confirm = await ask(chalk.yellow(`⚠️ ${id} 是一条 error 级约束,确认退役?(y/N) `));
|
|
454
354
|
if (confirm.toLowerCase() !== 'y' && confirm.toLowerCase() !== 'yes') {
|
|
455
355
|
console.log(` 已跳过 ${id}`);
|
|
456
356
|
continue;
|
|
457
357
|
}
|
|
458
358
|
}
|
|
459
359
|
const reason = await ask(`退役原因(${id},可留空): `);
|
|
460
|
-
plan.push({ id, reason
|
|
360
|
+
plan.push({ id, reason });
|
|
461
361
|
}
|
|
462
362
|
|
|
463
363
|
if (plan.length === 0) {
|
|
@@ -469,14 +369,9 @@ export async function runRetireInteractive(
|
|
|
469
369
|
console.log();
|
|
470
370
|
console.log(chalk.bold('将执行以下变更:'));
|
|
471
371
|
for (const p of plan) {
|
|
472
|
-
|
|
473
|
-
console.log(` - custom-constraints.yml: custom_constraints.${p.id}.retired 元数据(原因: ${p.reason || '(空)'})`);
|
|
474
|
-
} else {
|
|
475
|
-
console.log(` - config.yml: constraints.${p.id}.enabled=false + retired 元数据(原因: ${p.reason || '(空)'})`);
|
|
476
|
-
}
|
|
372
|
+
console.log(` - config.yml: constraints.${p.id}.enabled=false + retired 元数据(原因: ${p.reason || '(空)'})`);
|
|
477
373
|
console.log(` - KnowledgeStore: 写入 constraint-retired-${p.id}`);
|
|
478
374
|
}
|
|
479
|
-
console.log(' - CLAUDE.md / AGENTS.md: 若含 HARNESS_CONSTRAINTS 标记段则同步重渲染');
|
|
480
375
|
const finalConfirm = await ask('确认执行?(y/N) ');
|
|
481
376
|
if (finalConfirm.toLowerCase() !== 'y' && finalConfirm.toLowerCase() !== 'yes') {
|
|
482
377
|
console.log('已取消');
|
|
@@ -527,8 +422,8 @@ export async function constraintsRetire(
|
|
|
527
422
|
}
|
|
528
423
|
|
|
529
424
|
const result = retireConstraint(projectRoot, id, { reason: options.reason });
|
|
530
|
-
if (result.status === 'retired' && result.
|
|
531
|
-
log(io, chalk.yellow(`⚠️ ${id} 是一条
|
|
425
|
+
if (result.status === 'retired' && result.isError) {
|
|
426
|
+
log(io, chalk.yellow(`⚠️ ${id} 是一条 error 级约束,已通过 --yes 直达退役(交互模式会要求二次确认)`));
|
|
532
427
|
}
|
|
533
428
|
return printRetireResult(result, io);
|
|
534
429
|
}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* harness constraints -- 约束集合元数据导出
|
|
3
3
|
*
|
|
4
4
|
* 纯数据导出,不调用 LLM,不访问文件系统(除 definitions.ts)。
|
|
5
|
-
* 供 Studio 等消费者获取约束的 hash
|
|
5
|
+
* 供 Studio 等消费者获取约束的 hash、计数等元数据。
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
import { createHash } from 'crypto';
|
|
@@ -13,41 +13,27 @@ import { log, processIO, type CommandIO, type CommandResult } from '../command-c
|
|
|
13
13
|
export interface ConstraintsMeta {
|
|
14
14
|
version: string;
|
|
15
15
|
hash: string;
|
|
16
|
-
counts: {
|
|
17
|
-
textSize: { total: number; perConstraint: number };
|
|
16
|
+
counts: { errors: number; warnings: number };
|
|
18
17
|
}
|
|
19
18
|
|
|
20
19
|
export function getConstraintsMeta(): ConstraintsMeta {
|
|
21
20
|
const constraints = getAllConstraints();
|
|
22
21
|
|
|
23
|
-
const
|
|
24
|
-
const
|
|
25
|
-
const prompts = constraints.filter(c => c.level === 'prompt');
|
|
22
|
+
const errors = constraints.filter(c => c.severity === 'error');
|
|
23
|
+
const warnings = constraints.filter(c => c.severity === 'warning');
|
|
26
24
|
|
|
27
|
-
//
|
|
28
|
-
const
|
|
29
|
-
.map(c => (c.
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
// 稳定 JSON 序列化后取 hash
|
|
33
|
-
const hashInput = JSON.stringify({
|
|
34
|
-
ironLaws: ironLaws.map(c => ({ id: c.id, promptInjection: c.promptInjection })),
|
|
35
|
-
guidelines: guidelines.map(c => ({ id: c.id, promptInjection: c.promptInjection })),
|
|
36
|
-
prompts: prompts.map(c => ({ id: c.id, promptInjection: c.promptInjection })),
|
|
37
|
-
});
|
|
25
|
+
// 稳定 JSON 序列化后取 hash(内容面 = id + severity + 规则文本)
|
|
26
|
+
const hashInput = JSON.stringify(
|
|
27
|
+
constraints.map(c => ({ id: c.id, severity: c.severity, rule: c.rule, message: c.message, description: c.description }))
|
|
28
|
+
);
|
|
38
29
|
const hash = createHash('sha256').update(hashInput).digest('hex');
|
|
39
30
|
|
|
40
31
|
return {
|
|
41
32
|
version: getHarnessPackageVersion(),
|
|
42
33
|
hash,
|
|
43
34
|
counts: {
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
prompts: prompts.length,
|
|
47
|
-
},
|
|
48
|
-
textSize: {
|
|
49
|
-
total: totalTextSize,
|
|
50
|
-
perConstraint: constraints.length > 0 ? Math.round(totalTextSize / constraints.length) : 0,
|
|
35
|
+
errors: errors.length,
|
|
36
|
+
warnings: warnings.length,
|
|
51
37
|
},
|
|
52
38
|
};
|
|
53
39
|
}
|
|
@@ -62,8 +48,7 @@ export async function constraints(options: { json?: boolean }, io: CommandIO = p
|
|
|
62
48
|
} else {
|
|
63
49
|
log(io, `version: ${meta.version}`);
|
|
64
50
|
log(io, `hash: ${meta.hash}`);
|
|
65
|
-
log(io, `
|
|
66
|
-
log(io, `textSize: ${meta.textSize.total} chars total, ~${meta.textSize.perConstraint} chars/constraint`);
|
|
51
|
+
log(io, `errors: ${meta.counts.errors}, warnings: ${meta.counts.warnings}`);
|
|
67
52
|
}
|
|
68
53
|
return { kind: 'ok' };
|
|
69
54
|
}
|
|
@@ -101,7 +101,7 @@ export interface CommandDefinition {
|
|
|
101
101
|
export const COMMAND_DEFINITIONS: CommandDefinition[] = [
|
|
102
102
|
{
|
|
103
103
|
command: 'check',
|
|
104
|
-
description: '
|
|
104
|
+
description: '检查约束是否满足',
|
|
105
105
|
options: [
|
|
106
106
|
// 不给缺省值:「没传 -p」与「传了 standard」必须可区分,否则生效集侧的覆盖规则恒触发、
|
|
107
107
|
// config.yml 的 preset 静默失效(漂移检测侧按 config.yml 算,两边就会稳定对不上)
|
|
@@ -109,7 +109,7 @@ export const COMMAND_DEFINITIONS: CommandDefinition[] = [
|
|
|
109
109
|
{ flags: '-s, --staged', description: '只检查暂存文件', defaultValue: false },
|
|
110
110
|
{ flags: '-t, --trigger <trigger>', description: '触发条件' },
|
|
111
111
|
{ flags: '--project-path <path>', description: '项目路径' },
|
|
112
|
-
{ flags: '--list', description: '
|
|
112
|
+
{ flags: '--list', description: '列出所有约束' },
|
|
113
113
|
],
|
|
114
114
|
action: { module: 'check', export: 'check' },
|
|
115
115
|
optionRoutes: [
|