@dommaker/harness 1.8.1 → 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 +16 -0
- package/README.md +10 -13
- 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/cli/commands/sync-docs/capabilities-syncer.d.ts +22 -0
- package/dist/cli/commands/sync-docs/capabilities-syncer.d.ts.map +1 -1
- package/dist/cli/commands/sync-docs/capabilities-syncer.js +113 -8
- package/dist/cli/commands/sync-docs/capabilities-syncer.js.map +1 -1
- package/dist/cli/commands/sync-docs/index.d.ts.map +1 -1
- package/dist/cli/commands/sync-docs/index.js +36 -4
- package/dist/cli/commands/sync-docs/index.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/hooks/bootstrap.d.ts +9 -12
- package/dist/hooks/bootstrap.d.ts.map +1 -1
- package/dist/hooks/bootstrap.js +9 -31
- package/dist/hooks/bootstrap.js.map +1 -1
- package/dist/hooks/index.d.ts +5 -7
- package/dist/hooks/index.d.ts.map +1 -1
- package/dist/hooks/index.js +4 -10
- package/dist/hooks/index.js.map +1 -1
- package/dist/index.d.ts +9 -12
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +10 -23
- 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 +3 -3
- 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 +31 -11
- package/src/__tests__/public-type-surface.test.ts +2 -13
- 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 +12 -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__/registry.test.ts +39 -3
- 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/__tests__/sync-docs-table-layout.test.ts +259 -0
- 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/cli/commands/sync-docs/capabilities-syncer.ts +139 -9
- package/src/cli/commands/sync-docs/index.ts +41 -4
- 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/CONTEXT.md +12 -22
- package/src/hooks/__tests__/bootstrap.test.ts +24 -75
- package/src/hooks/bootstrap.ts +9 -48
- package/src/hooks/index.ts +5 -20
- package/src/index.ts +9 -31
- 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/dist/hooks/config.d.ts +0 -30
- package/dist/hooks/config.d.ts.map +0 -1
- package/dist/hooks/config.js +0 -34
- package/dist/hooks/config.js.map +0 -1
- package/dist/hooks/pipeline.d.ts +0 -54
- package/dist/hooks/pipeline.d.ts.map +0 -1
- package/dist/hooks/pipeline.js +0 -173
- package/dist/hooks/pipeline.js.map +0 -1
- package/dist/hooks/registry.d.ts +0 -70
- package/dist/hooks/registry.d.ts.map +0 -1
- package/dist/hooks/registry.js +0 -141
- package/dist/hooks/registry.js.map +0 -1
- package/dist/hooks/types.d.ts +0 -113
- package/dist/hooks/types.d.ts.map +0 -1
- package/dist/hooks/types.js +0 -9
- package/dist/hooks/types.js.map +0 -1
- package/src/__tests__/hooks-pipeline.test.ts +0 -201
- 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
- package/src/hooks/__tests__/config.test.ts +0 -19
- package/src/hooks/__tests__/pipeline.test.ts +0 -195
- package/src/hooks/__tests__/registry.test.ts +0 -115
- package/src/hooks/config.ts +0 -33
- package/src/hooks/pipeline.ts +0 -202
- package/src/hooks/registry.ts +0 -166
- package/src/hooks/types.ts +0 -120
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
12
|
import * as fs from 'fs';
|
|
13
|
-
import {
|
|
13
|
+
import { CONSTRAINTS } from './definitions';
|
|
14
14
|
import { FreshnessRunner } from './doc-freshness/runner';
|
|
15
15
|
import type { DocFreshnessCheck } from '../../types/project-config';
|
|
16
16
|
|
|
@@ -79,10 +79,14 @@ export function readCapabilitiesEntries(capabilitiesPath: string, options: Capab
|
|
|
79
79
|
* checker 与 sync-docs 都应按此跳过条目级比对。
|
|
80
80
|
*/
|
|
81
81
|
export function isCapabilityListingFormat(content: string): boolean {
|
|
82
|
-
// 能力清单格式特征:包含 "CLI Commands (N)"
|
|
82
|
+
// 能力清单格式特征:包含 "CLI Commands (N)" 与约束计数行
|
|
83
|
+
// (ADR-0029 前为 "Iron Laws (N)" / "Guidelines (N)",现行为 "errors (N)" / "warnings (N)",
|
|
84
|
+
// 新旧行都认——旧文档不因此失去格式身份)
|
|
83
85
|
return /CLI Commands\s*\(\d+\)/.test(content) ||
|
|
84
86
|
/Iron Laws?\s*\(\d+\)/.test(content) ||
|
|
85
|
-
/Guidelines?\s*\(\d+\)/.test(content)
|
|
87
|
+
/Guidelines?\s*\(\d+\)/.test(content) ||
|
|
88
|
+
/errors?\s*\(\d+\)/.test(content) ||
|
|
89
|
+
/warnings?\s*\(\d+\)/.test(content);
|
|
86
90
|
}
|
|
87
91
|
|
|
88
92
|
/**
|
|
@@ -143,8 +147,16 @@ function capabilityCountRules(source: CapabilityDefinitionSource): CapabilityCou
|
|
|
143
147
|
actual: source.commands.length + source.gates.filter(g => g.cli).length,
|
|
144
148
|
},
|
|
145
149
|
{ label: 'Quality Gates', pattern: 'Quality Gates?\\s*\\((\\d+)\\)', actual: source.gates.length },
|
|
146
|
-
{
|
|
147
|
-
|
|
150
|
+
{
|
|
151
|
+
label: 'errors',
|
|
152
|
+
pattern: 'errors?\\s*\\((\\d+)\\)',
|
|
153
|
+
actual: Object.values(CONSTRAINTS).filter(c => c.severity === 'error').length,
|
|
154
|
+
},
|
|
155
|
+
{
|
|
156
|
+
label: 'warnings',
|
|
157
|
+
pattern: 'warnings?\\s*\\((\\d+)\\)',
|
|
158
|
+
actual: Object.values(CONSTRAINTS).filter(c => c.severity === 'warning').length,
|
|
159
|
+
},
|
|
148
160
|
];
|
|
149
161
|
}
|
|
150
162
|
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* 约束检查引擎
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
* -
|
|
6
|
-
* -
|
|
7
|
-
*
|
|
4
|
+
* severity 显式模型(ADR-0029):
|
|
5
|
+
* - severity='error':检查失败立即抛出异常(block 模式)
|
|
6
|
+
* - severity='warning':检查失败记录警告
|
|
7
|
+
* 全部约束 kind='check',必须带真实 checker(注册表闭环)。
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
10
|
import {
|
|
@@ -12,11 +12,10 @@ import {
|
|
|
12
12
|
ConstraintContext,
|
|
13
13
|
ConstraintResult,
|
|
14
14
|
ConstraintCheckResult,
|
|
15
|
-
ConstraintLevel,
|
|
16
15
|
ConstraintViolationError,
|
|
17
16
|
} from '../../types/constraint';
|
|
18
17
|
import type { ExecutionTrace } from '../../types/trace';
|
|
19
|
-
import {
|
|
18
|
+
import { CONSTRAINTS } from './definitions';
|
|
20
19
|
import type { MergedConstraintsConfig } from '../../types/project-config';
|
|
21
20
|
import { matchesTrigger } from './triggers';
|
|
22
21
|
import { join, relative } from 'path';
|
|
@@ -74,21 +73,8 @@ export class ConstraintChecker {
|
|
|
74
73
|
*
|
|
75
74
|
* @param customConfig 可选,per-request 自定义配置;不传则返回内置约束集
|
|
76
75
|
*/
|
|
77
|
-
getConstraints(customConfig?: MergedConstraintsConfig | null): {
|
|
78
|
-
|
|
79
|
-
guidelines: Record<string, Constraint>;
|
|
80
|
-
prompts: Record<string, Constraint>;
|
|
81
|
-
} {
|
|
82
|
-
const config = customConfig;
|
|
83
|
-
const source = config
|
|
84
|
-
? { ironLaws: config.ironLaws, guidelines: config.guidelines, prompts: config.prompts ?? PROMPTS }
|
|
85
|
-
: { ironLaws: IRON_LAWS, guidelines: GUIDELINES, prompts: PROMPTS };
|
|
86
|
-
|
|
87
|
-
return {
|
|
88
|
-
ironLaws: source.ironLaws,
|
|
89
|
-
guidelines: source.guidelines,
|
|
90
|
-
prompts: source.prompts,
|
|
91
|
-
};
|
|
76
|
+
getConstraints(customConfig?: MergedConstraintsConfig | null): Record<string, Constraint> {
|
|
77
|
+
return customConfig ? customConfig.constraints : CONSTRAINTS;
|
|
92
78
|
}
|
|
93
79
|
|
|
94
80
|
/**
|
|
@@ -103,17 +89,6 @@ export class ConstraintChecker {
|
|
|
103
89
|
evidence?: GitEvidence,
|
|
104
90
|
runEnv?: RunEnv
|
|
105
91
|
): Promise<ConstraintResult> {
|
|
106
|
-
// prompt 类约束不参与 checker 执行(ADR-0001:仅参与注入)
|
|
107
|
-
if (constraint.kind === 'prompt') {
|
|
108
|
-
return {
|
|
109
|
-
id: constraint.id,
|
|
110
|
-
level: constraint.level,
|
|
111
|
-
satisfied: true,
|
|
112
|
-
constraint,
|
|
113
|
-
checkedAt: new Date(),
|
|
114
|
-
};
|
|
115
|
-
}
|
|
116
|
-
|
|
117
92
|
// 检查前置条件('skip' = 约定未采用/证据未接线:satisfied 置 true 但不计 pass/fail)
|
|
118
93
|
const outcome = normalizeCheckOutcome(
|
|
119
94
|
await this.checkPrecondition(constraint, context, evidence, runEnv)
|
|
@@ -122,7 +97,7 @@ export class ConstraintChecker {
|
|
|
122
97
|
if (outcome.skipped) {
|
|
123
98
|
return {
|
|
124
99
|
id: constraint.id,
|
|
125
|
-
|
|
100
|
+
severity: constraint.severity,
|
|
126
101
|
satisfied: true,
|
|
127
102
|
skipped: true,
|
|
128
103
|
constraint,
|
|
@@ -135,7 +110,7 @@ export class ConstraintChecker {
|
|
|
135
110
|
|
|
136
111
|
return {
|
|
137
112
|
id: constraint.id,
|
|
138
|
-
|
|
113
|
+
severity: constraint.severity,
|
|
139
114
|
satisfied,
|
|
140
115
|
constraint,
|
|
141
116
|
message: satisfied ? undefined : constraint.message,
|
|
@@ -145,22 +120,6 @@ export class ConstraintChecker {
|
|
|
145
120
|
};
|
|
146
121
|
}
|
|
147
122
|
|
|
148
|
-
/**
|
|
149
|
-
* 根据约束层级获取严重性
|
|
150
|
-
*/
|
|
151
|
-
private getSeverity(level: ConstraintLevel): 'error' | 'warning' | 'info' {
|
|
152
|
-
switch (level) {
|
|
153
|
-
case 'iron_law':
|
|
154
|
-
return 'error';
|
|
155
|
-
case 'guideline':
|
|
156
|
-
return 'warning';
|
|
157
|
-
case 'prompt':
|
|
158
|
-
return 'info';
|
|
159
|
-
default:
|
|
160
|
-
return 'warning';
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
|
|
164
123
|
/**
|
|
165
124
|
* 记录约束检查的 trace
|
|
166
125
|
*/
|
|
@@ -171,11 +130,10 @@ export class ConstraintChecker {
|
|
|
171
130
|
): void {
|
|
172
131
|
this.traceRecorder.record({
|
|
173
132
|
constraintId: constraint.id,
|
|
174
|
-
|
|
133
|
+
severity: constraint.severity,
|
|
175
134
|
timestamp: Date.now(),
|
|
176
135
|
result: checkResult.skipped ? 'skip' : checkResult.satisfied ? 'pass' : 'fail',
|
|
177
136
|
operation: context.operation,
|
|
178
|
-
severity: this.getSeverity(constraint.level),
|
|
179
137
|
projectPath: context.projectPath,
|
|
180
138
|
sessionId: context.sessionId,
|
|
181
139
|
evidence: checkResult.evidence,
|
|
@@ -186,7 +144,7 @@ export class ConstraintChecker {
|
|
|
186
144
|
* 检查约束前置条件(工单 21:分发至 checkers/ 注册表)
|
|
187
145
|
*
|
|
188
146
|
* 注册表闭环(ADR-0001):kind='check' 未注册 checker 直接抛错,
|
|
189
|
-
* 不再有"未注册默认通过"
|
|
147
|
+
* 不再有"未注册默认通过"路径。
|
|
190
148
|
*
|
|
191
149
|
* git 证据(stagedDiff/stagedDiffNames)单一来源 = GitEvidence adapter(#87):
|
|
192
150
|
* 一次 run 内调用方传同一实例即至多取证一次,run 外调用独占一份。
|
|
@@ -202,7 +160,7 @@ export class ConstraintChecker {
|
|
|
202
160
|
if (!impl) {
|
|
203
161
|
throw new Error(
|
|
204
162
|
`[harness] 约束 "${constraint.id}" (kind='check') 未注册 checker,拒绝静默通过。` +
|
|
205
|
-
`请在 checkers/
|
|
163
|
+
`请在 checkers/ 注册实现(纯文本提示层已随 ADR-0029 关停,文本规则写入项目治理文档)。`
|
|
206
164
|
);
|
|
207
165
|
}
|
|
208
166
|
|
|
@@ -232,31 +190,27 @@ export class ConstraintChecker {
|
|
|
232
190
|
context: ConstraintContext,
|
|
233
191
|
customConfig?: MergedConstraintsConfig | null
|
|
234
192
|
): {
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
prompts: Constraint[];
|
|
193
|
+
errors: Constraint[];
|
|
194
|
+
warnings: Constraint[];
|
|
238
195
|
} {
|
|
239
196
|
const operations = [context.operation, ...(context.extraTriggers ?? [])];
|
|
240
197
|
const constraints = this.getConstraints(customConfig);
|
|
241
198
|
|
|
242
|
-
const
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
);
|
|
246
|
-
};
|
|
199
|
+
const applicable = Object.values(constraints).filter(constraint =>
|
|
200
|
+
matchesTrigger(constraint, operations)
|
|
201
|
+
);
|
|
247
202
|
|
|
248
203
|
return {
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
prompts: filterByTrigger(constraints.prompts),
|
|
204
|
+
errors: applicable.filter(c => c.severity === 'error'),
|
|
205
|
+
warnings: applicable.filter(c => c.severity === 'warning'),
|
|
252
206
|
};
|
|
253
207
|
}
|
|
254
208
|
|
|
255
209
|
/**
|
|
256
210
|
* 执行约束检查
|
|
257
211
|
*
|
|
258
|
-
* -
|
|
259
|
-
* -
|
|
212
|
+
* - severity='error':检查失败立即抛出异常
|
|
213
|
+
* - severity='warning':检查失败记录警告
|
|
260
214
|
*
|
|
261
215
|
* @param context 约束上下文
|
|
262
216
|
* @param customConfig 可选,per-request 自定义配置(避免多请求间的单例状态污染)
|
|
@@ -279,7 +233,7 @@ export class ConstraintChecker {
|
|
|
279
233
|
* 收集模式执行约束检查(harness report 的不抛出口,架构评审候选1)
|
|
280
234
|
*
|
|
281
235
|
* 与 checkConstraints 共享同一检查体,唯一差别是不 throw:
|
|
282
|
-
*
|
|
236
|
+
* error 级违规照进 result.errors、passed=false,后续 error 与 warning 级照常执行,
|
|
283
237
|
* trace 逐条照记。报告类消费者拿全量视图;阻断语义只属于 checkConstraints
|
|
284
238
|
* (throw 契约是 #119 判定证据的外溢面,逐字不动)。
|
|
285
239
|
*/
|
|
@@ -294,7 +248,7 @@ export class ConstraintChecker {
|
|
|
294
248
|
|
|
295
249
|
/**
|
|
296
250
|
* checkConstraints / collectConstraints 的共享检查体;
|
|
297
|
-
* mode='block'
|
|
251
|
+
* mode='block' 首个 error 级违规即抛,mode='collect' 全量跑完不抛
|
|
298
252
|
*/
|
|
299
253
|
private async runAllConstraints(
|
|
300
254
|
context: ConstraintContext,
|
|
@@ -311,8 +265,8 @@ export class ConstraintChecker {
|
|
|
311
265
|
const env = runEnv ?? createRunEnv(projectPath);
|
|
312
266
|
|
|
313
267
|
const result: ConstraintCheckResult = {
|
|
314
|
-
|
|
315
|
-
|
|
268
|
+
errors: [],
|
|
269
|
+
warnings: [],
|
|
316
270
|
passed: true,
|
|
317
271
|
warningCount: 0,
|
|
318
272
|
};
|
|
@@ -321,12 +275,12 @@ export class ConstraintChecker {
|
|
|
321
275
|
// context.operation 为主触发条件,extraTriggers 为次级推断(ADR-0001),任一命中即匹配
|
|
322
276
|
const operations = [context.operation, ...(context.extraTriggers ?? [])];
|
|
323
277
|
|
|
324
|
-
// 1.
|
|
325
|
-
for (const constraint of Object.values(constraints.
|
|
278
|
+
// 1. error 级: block 模式首个违规即抛;collect 模式全量收集
|
|
279
|
+
for (const constraint of Object.values(constraints).filter(c => c.severity === 'error')) {
|
|
326
280
|
if (!matchesTrigger(constraint, operations)) continue;
|
|
327
281
|
|
|
328
282
|
const checkResult = await this.check(constraint, context, run, env);
|
|
329
|
-
result.
|
|
283
|
+
result.errors.push(checkResult);
|
|
330
284
|
this.recordTrace(constraint, checkResult, context);
|
|
331
285
|
|
|
332
286
|
if (!checkResult.satisfied) {
|
|
@@ -337,12 +291,12 @@ export class ConstraintChecker {
|
|
|
337
291
|
}
|
|
338
292
|
}
|
|
339
293
|
|
|
340
|
-
// 2.
|
|
341
|
-
for (const constraint of Object.values(constraints.
|
|
294
|
+
// 2. warning 级: 记录警告
|
|
295
|
+
for (const constraint of Object.values(constraints).filter(c => c.severity === 'warning')) {
|
|
342
296
|
if (!matchesTrigger(constraint, operations)) continue;
|
|
343
297
|
|
|
344
298
|
const checkResult = await this.check(constraint, context, run, env);
|
|
345
|
-
result.
|
|
299
|
+
result.warnings.push(checkResult);
|
|
346
300
|
this.recordTrace(constraint, checkResult, context);
|
|
347
301
|
|
|
348
302
|
if (!checkResult.satisfied) {
|
|
@@ -354,12 +308,12 @@ export class ConstraintChecker {
|
|
|
354
308
|
}
|
|
355
309
|
|
|
356
310
|
/**
|
|
357
|
-
* 执行前检查(仅检查
|
|
311
|
+
* 执行前检查(仅检查 severity='error' 的约束)
|
|
358
312
|
*
|
|
359
313
|
* @param context 约束上下文
|
|
360
314
|
* @param customConfig 可选,per-request 自定义配置(避免多请求间的单例状态污染)
|
|
361
315
|
* @param evidence 可选,本次检查共用的 git 证据 adapter(#87,同 checkConstraints)
|
|
362
|
-
* @throws ConstraintViolationError
|
|
316
|
+
* @throws ConstraintViolationError 如果有 error 级违规
|
|
363
317
|
*/
|
|
364
318
|
async beforeExecution(
|
|
365
319
|
context: ConstraintContext,
|
|
@@ -373,7 +327,7 @@ export class ConstraintChecker {
|
|
|
373
327
|
const constraints = this.getConstraints(customConfig);
|
|
374
328
|
const operations = [context.operation, ...(context.extraTriggers ?? [])];
|
|
375
329
|
|
|
376
|
-
for (const constraint of Object.values(constraints.
|
|
330
|
+
for (const constraint of Object.values(constraints).filter(c => c.severity === 'error')) {
|
|
377
331
|
if (!matchesTrigger(constraint, operations)) continue;
|
|
378
332
|
|
|
379
333
|
const result = await this.check(constraint, context, run, env);
|
|
@@ -401,15 +355,12 @@ export async function checkConstraint(
|
|
|
401
355
|
const checker = ConstraintChecker.getInstance();
|
|
402
356
|
const constraints = checker.getConstraints(customConfig);
|
|
403
357
|
|
|
404
|
-
const constraint =
|
|
405
|
-
constraints.ironLaws[constraintId] ||
|
|
406
|
-
constraints.guidelines[constraintId] ||
|
|
407
|
-
constraints.prompts[constraintId];
|
|
358
|
+
const constraint = constraints[constraintId];
|
|
408
359
|
|
|
409
360
|
if (!constraint) {
|
|
410
361
|
return {
|
|
411
362
|
id: constraintId,
|
|
412
|
-
|
|
363
|
+
severity: 'warning',
|
|
413
364
|
satisfied: false,
|
|
414
365
|
message: `未知的约束: ${constraintId}`,
|
|
415
366
|
checkedAt: new Date(),
|
|
@@ -430,7 +381,7 @@ export interface CheckConstraintsOptions {
|
|
|
430
381
|
}
|
|
431
382
|
|
|
432
383
|
/**
|
|
433
|
-
*
|
|
384
|
+
* 快捷函数:执行约束检查
|
|
434
385
|
*
|
|
435
386
|
* @param context 约束上下文
|
|
436
387
|
* @param options.onTrace 每条约束检查后的回调(用于记录 trace 到外部存储)
|
|
@@ -442,8 +393,8 @@ export async function checkConstraints(
|
|
|
442
393
|
): Promise<ConstraintCheckResult> {
|
|
443
394
|
const result = await ConstraintChecker.getInstance().checkConstraints(context, options?.customConfig ?? null);
|
|
444
395
|
if (options?.onTrace) {
|
|
445
|
-
for (const r of result.
|
|
446
|
-
for (const r of result.
|
|
396
|
+
for (const r of result.errors) options.onTrace(r);
|
|
397
|
+
for (const r of result.warnings) options.onTrace(r);
|
|
447
398
|
}
|
|
448
399
|
return result;
|
|
449
400
|
}
|
|
@@ -23,7 +23,7 @@ import type { MergedConstraintsConfig } from '../../../../types/project-config';
|
|
|
23
23
|
const CAPABILITY_SYNC: Constraint = {
|
|
24
24
|
id: 'capability_sync',
|
|
25
25
|
kind: 'check',
|
|
26
|
-
|
|
26
|
+
severity: 'warning',
|
|
27
27
|
rule: 'CODE CHANGES MUST UPDATE CAPABILITIES.MD',
|
|
28
28
|
message: '核心模块变更必须同步功能清单',
|
|
29
29
|
trigger: ['module_modification'],
|
|
@@ -62,11 +62,8 @@ describe('normalizeCheckOutcome — 三态 + 证据归一', () => {
|
|
|
62
62
|
/** 只含 capability_sync 的生效集:一次 run 一条 trace,不牵动其他约束 */
|
|
63
63
|
function onlyCapabilitySync(): MergedConstraintsConfig {
|
|
64
64
|
return {
|
|
65
|
-
|
|
66
|
-
guidelines: { capability_sync: CAPABILITY_SYNC },
|
|
67
|
-
prompts: {},
|
|
65
|
+
constraints: { capability_sync: CAPABILITY_SYNC },
|
|
68
66
|
disabled: [],
|
|
69
|
-
custom: [],
|
|
70
67
|
};
|
|
71
68
|
}
|
|
72
69
|
|
|
@@ -81,7 +78,7 @@ async function runGuideline(dir: string): Promise<{
|
|
|
81
78
|
{ operation: 'module_modification', projectPath: dir },
|
|
82
79
|
onlyCapabilitySync()
|
|
83
80
|
);
|
|
84
|
-
const result = run.
|
|
81
|
+
const result = run.warnings.find(r => r.id === 'capability_sync')!;
|
|
85
82
|
const trace = traces.find(t => t.constraintId === 'capability_sync')!;
|
|
86
83
|
return { result, trace };
|
|
87
84
|
}
|
|
@@ -151,7 +148,7 @@ describe('证据随铁律异常外溢(CLI catch 分支只打印 error.message
|
|
|
151
148
|
it('ConstraintViolationError 文案带出证据行', () => {
|
|
152
149
|
const error = new ConstraintViolationError({
|
|
153
150
|
id: 'docs_freshness',
|
|
154
|
-
|
|
151
|
+
severity: 'error',
|
|
155
152
|
satisfied: false,
|
|
156
153
|
message: '文档新鲜度检查未通过',
|
|
157
154
|
evidence: ['CAPABILITIES.md 登记的条目不存在:', 'src/gone.ts'],
|
|
@@ -165,7 +162,7 @@ describe('证据随铁律异常外溢(CLI catch 分支只打印 error.message
|
|
|
165
162
|
it('无证据时文案保持原样(旧消费方断言不受影响)', () => {
|
|
166
163
|
const error = new ConstraintViolationError({
|
|
167
164
|
id: 'no_test_simplification',
|
|
168
|
-
|
|
165
|
+
severity: 'error',
|
|
169
166
|
satisfied: false,
|
|
170
167
|
message: '禁止简化测试绕过困难',
|
|
171
168
|
checkedAt: new Date(),
|
|
@@ -16,7 +16,6 @@ import {
|
|
|
16
16
|
hasGovernancePreserveBlock,
|
|
17
17
|
hasClaudeGovernance,
|
|
18
18
|
} from '../governance-presence';
|
|
19
|
-
import { detectInjectionDrift } from '../../injection-drift';
|
|
20
19
|
import { createProjectFixture, writeProjectConfig } from '../../../../test-setup/project-fixture';
|
|
21
20
|
import { normalizeCheckOutcome, type CheckEnv } from '../types';
|
|
22
21
|
import { createRunEnv } from '../../run-env';
|
|
@@ -99,7 +98,7 @@ describe('governance_presence checker', () => {
|
|
|
99
98
|
const outcome = await outcomeOf(tempDir);
|
|
100
99
|
expect(outcome.satisfied).toBe(false);
|
|
101
100
|
expect(outcome.evidence.join('\n')).toContain('治理契约');
|
|
102
|
-
expect(outcome.evidence.join('\n')).toContain('
|
|
101
|
+
expect(outcome.evidence.join('\n')).toContain('PRESERVE:governance');
|
|
103
102
|
// ADR-0016:证据只有一个出口。侧信道留着会让 CLI 结构化输出与 trace 两头口径不一致
|
|
104
103
|
expect(errorSpy).not.toHaveBeenCalled();
|
|
105
104
|
});
|
|
@@ -159,54 +158,3 @@ describe('hasGovernancePreserveBlock / hasClaudeGovernance 判定函数', () =>
|
|
|
159
158
|
expect(hasGovernancePreserveBlock(p)).toBe(false);
|
|
160
159
|
});
|
|
161
160
|
});
|
|
162
|
-
|
|
163
|
-
describe('governance_presence × detectInjectionDrift 同 fixture 一致性(#83)', () => {
|
|
164
|
-
let tempDir: string;
|
|
165
|
-
|
|
166
|
-
const writeConfig = () => writeProjectConfig(tempDir, 'preset: standard\n');
|
|
167
|
-
|
|
168
|
-
beforeEach(() => {
|
|
169
|
-
tempDir = createProjectFixture({
|
|
170
|
-
name: 'temp-test-gov-consistency',
|
|
171
|
-
parentDir: process.cwd(),
|
|
172
|
-
});
|
|
173
|
-
});
|
|
174
|
-
|
|
175
|
-
afterEach(() => {
|
|
176
|
-
fs.rmSync(tempDir, { recursive: true, force: true });
|
|
177
|
-
});
|
|
178
|
-
|
|
179
|
-
it('双空格标题:presence 认在场(pass),drift 严格计数 0 不报重复——两层不再互相矛盾', async () => {
|
|
180
|
-
writeConfig();
|
|
181
|
-
fs.writeFileSync(path.join(tempDir, 'CLAUDE.md'), '# CLAUDE.md\n\n## Governance Rules\n\n条款\n');
|
|
182
|
-
|
|
183
|
-
expect(await governancePresence.evaluate(makeEnv(tempDir))).toBe(true);
|
|
184
|
-
const drift = detectInjectionDrift(tempDir);
|
|
185
|
-
expect(drift.notInjected).toBe(true);
|
|
186
|
-
expect(drift.duplicateHeading).toBe(false);
|
|
187
|
-
expect(drift.hasDrift).toBe(false);
|
|
188
|
-
});
|
|
189
|
-
|
|
190
|
-
it('精确拼写单标题:presence pass,drift 不报重复', async () => {
|
|
191
|
-
writeConfig();
|
|
192
|
-
fs.writeFileSync(path.join(tempDir, 'CLAUDE.md'), '# CLAUDE.md\n\n## Governance Rules\n\n条款\n');
|
|
193
|
-
|
|
194
|
-
expect(await governancePresence.evaluate(makeEnv(tempDir))).toBe(true);
|
|
195
|
-
const drift = detectInjectionDrift(tempDir);
|
|
196
|
-
expect(drift.notInjected).toBe(true);
|
|
197
|
-
expect(drift.duplicateHeading).toBe(false);
|
|
198
|
-
});
|
|
199
|
-
|
|
200
|
-
it('精确拼写双标题:presence 认在场,drift 报重复章节(计数是 drift 的独立职责)', async () => {
|
|
201
|
-
writeConfig();
|
|
202
|
-
fs.writeFileSync(
|
|
203
|
-
path.join(tempDir, 'CLAUDE.md'),
|
|
204
|
-
'# CLAUDE.md\n\n## Governance Rules\n\n甲\n\n## Governance Rules\n\n乙\n'
|
|
205
|
-
);
|
|
206
|
-
|
|
207
|
-
expect(await governancePresence.evaluate(makeEnv(tempDir))).toBe(true);
|
|
208
|
-
const drift = detectInjectionDrift(tempDir);
|
|
209
|
-
expect(drift.notInjected).toBe(true);
|
|
210
|
-
expect(drift.duplicateHeading).toBe(true);
|
|
211
|
-
});
|
|
212
|
-
});
|
|
@@ -1,17 +1,16 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* 铁律层 flag 检查旁测(架构评审候选4,ADR-0009 同模式)
|
|
3
3
|
*
|
|
4
|
-
*
|
|
4
|
+
* 唯一存活的 flag 铁律为 contextEvidenceFlag 构造,真实 bug 面 = 读错上下文字段
|
|
5
5
|
* 与三态语义(undefined→skip / false→fail / true→pass)。直接喂不同字段组合
|
|
6
6
|
* 钉死映射,不再经 engine facade(旧测在 skip-semantics/checker.test 间接打)。
|
|
7
|
+
*
|
|
8
|
+
* harness#174 删除 incremental_progress / no_implementation_without_requirement,
|
|
9
|
+
* 对应用例一并移除。
|
|
7
10
|
*/
|
|
8
11
|
|
|
9
12
|
import { describe, it, expect } from '@jest/globals';
|
|
10
|
-
import {
|
|
11
|
-
noCompletionWithoutVerification,
|
|
12
|
-
incrementalProgress,
|
|
13
|
-
noImplementationWithoutRequirement,
|
|
14
|
-
} from '../iron-flags';
|
|
13
|
+
import { noCompletionWithoutVerification } from '../iron-flags';
|
|
15
14
|
import { buildCheckEnv } from '../types';
|
|
16
15
|
import type { ConstraintContext } from '../../../../types/constraint';
|
|
17
16
|
|
|
@@ -28,23 +27,4 @@ describe('iron flags — 三态与字段映射', () => {
|
|
|
28
27
|
// 相邻字段不串台:hasTest 不能顶替
|
|
29
28
|
expect(await evaluate(noCompletionWithoutVerification, { hasTest: true })).toBe('skip');
|
|
30
29
|
});
|
|
31
|
-
|
|
32
|
-
it('incremental_progress → 读 hasSingleTask', async () => {
|
|
33
|
-
expect(await evaluate(incrementalProgress, {})).toBe('skip');
|
|
34
|
-
expect(await evaluate(incrementalProgress, { hasSingleTask: false })).toBe(false);
|
|
35
|
-
expect(await evaluate(incrementalProgress, { hasSingleTask: true })).toBe(true);
|
|
36
|
-
});
|
|
37
|
-
|
|
38
|
-
it('no_implementation_without_requirement → 读 hasRequirement', async () => {
|
|
39
|
-
expect(await evaluate(noImplementationWithoutRequirement, {})).toBe('skip');
|
|
40
|
-
expect(await evaluate(noImplementationWithoutRequirement, { hasRequirement: false })).toBe(false);
|
|
41
|
-
expect(await evaluate(noImplementationWithoutRequirement, { hasRequirement: true })).toBe(true);
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
it('三 flag 各自独立判定(组合上下文互不影响)', async () => {
|
|
45
|
-
const ctx: Partial<ConstraintContext> = { hasVerificationEvidence: true, hasSingleTask: false };
|
|
46
|
-
expect(await evaluate(noCompletionWithoutVerification, ctx)).toBe(true);
|
|
47
|
-
expect(await evaluate(incrementalProgress, ctx)).toBe(false);
|
|
48
|
-
expect(await evaluate(noImplementationWithoutRequirement, ctx)).toBe('skip');
|
|
49
|
-
});
|
|
50
30
|
});
|
|
@@ -90,7 +90,7 @@ export const docsFreshness: ConstraintCheck = {
|
|
|
90
90
|
if (deadEntries.length > 0) {
|
|
91
91
|
// 证据通道点名条目(harness#119):此前是 console.error 侧信道(2026-08-08 studio
|
|
92
92
|
// CI 4 连红时的临时办法),CLI 结构化输出与 trace 两头都拿不到,
|
|
93
|
-
//
|
|
93
|
+
// error 级拦截时用户只看到一句通用提示,basename 碰撞下无从定位
|
|
94
94
|
return {
|
|
95
95
|
pass: false,
|
|
96
96
|
evidence: formatEvidence('CAPABILITIES.md 登记的条目不存在', deadEntries),
|
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
* governance_presence:治理契约在场守护(studio #302,ADR 2026-08-21 落点模型)
|
|
3
3
|
*
|
|
4
4
|
* 治理契约正本 = AGENTS.md 手写 `PRESERVE:governance` 段(旧模型仓 = CLAUDE.md
|
|
5
|
-
* Governance Rules / HARNESS_CONSTRAINTS
|
|
5
|
+
* Governance Rules 块 / 历史 HARNESS_CONSTRAINTS 注入段,ADR-0029 后注入段不再
|
|
6
|
+
* 生成,残留段仅作历史兼容判据)。PRESERVE 只保「存在」不保「在场」:
|
|
6
7
|
* 段被删除/掏空后 sync-docs 重新生成会静默丢失,此处补「在场」校验。
|
|
7
8
|
*
|
|
8
9
|
* ADR-0001 存在性探测:项目未采用 harness 治理(无 .harness/config.yml)→ skip。
|
|
@@ -48,12 +49,12 @@ export const governancePresence: ConstraintCheck = {
|
|
|
48
49
|
if (hasClaudeGovernance(join(projectPath, 'CLAUDE.md'))) return true;
|
|
49
50
|
|
|
50
51
|
// 证据随判定一并返回(ADR-0016 补迁):此前这里是 console.error 侧信道——
|
|
51
|
-
// 只进本地 stderr,进不了 CLI 结论块与 trace
|
|
52
|
+
// 只进本地 stderr,进不了 CLI 结论块与 trace,error 级拦截时用户看不到该恢复哪个正本
|
|
52
53
|
return {
|
|
53
54
|
pass: false,
|
|
54
55
|
evidence: [
|
|
55
56
|
'治理契约缺失:AGENTS.md 无非空 PRESERVE:governance 段,CLAUDE.md 也无 Governance Rules 块(正本静默丢失)',
|
|
56
|
-
'修复:
|
|
57
|
+
'修复: 恢复其一——AGENTS.md 补回手写 PRESERVE:governance 段,或 CLAUDE.md 补回 Governance Rules 块',
|
|
57
58
|
],
|
|
58
59
|
};
|
|
59
60
|
},
|
|
@@ -13,10 +13,7 @@ import { getAllConstraints } from '../definitions';
|
|
|
13
13
|
|
|
14
14
|
import {
|
|
15
15
|
noCompletionWithoutVerification,
|
|
16
|
-
incrementalProgress,
|
|
17
|
-
noImplementationWithoutRequirement,
|
|
18
16
|
} from './iron-flags';
|
|
19
|
-
import { noBypassCheckpoint } from './no-bypass-checkpoint';
|
|
20
17
|
import { noTestSimplification } from './no-test-simplification';
|
|
21
18
|
import { capabilitySync } from './capability-sync';
|
|
22
19
|
import { contextDocSync } from './context-doc-sync';
|
|
@@ -25,15 +22,12 @@ import { noHardcodedCredentials } from './no-hardcoded-credentials';
|
|
|
25
22
|
import { governancePresence } from './governance-presence';
|
|
26
23
|
|
|
27
24
|
const CHECKS: ConstraintCheck[] = [
|
|
28
|
-
//
|
|
25
|
+
// severity='error'
|
|
29
26
|
noCompletionWithoutVerification,
|
|
30
|
-
incrementalProgress,
|
|
31
|
-
noImplementationWithoutRequirement,
|
|
32
27
|
noTestSimplification,
|
|
33
28
|
docsFreshness,
|
|
34
|
-
//
|
|
29
|
+
// severity='warning'
|
|
35
30
|
noHardcodedCredentials,
|
|
36
|
-
noBypassCheckpoint,
|
|
37
31
|
capabilitySync,
|
|
38
32
|
contextDocSync,
|
|
39
33
|
governancePresence,
|
|
@@ -51,7 +45,7 @@ for (const c of checkConstraints) {
|
|
|
51
45
|
if (!registry.has(c.id)) {
|
|
52
46
|
throw new Error(
|
|
53
47
|
`[harness] 约束注册表闭环校验失败:kind='check' 的约束 "${c.id}" 未注册 checker。` +
|
|
54
|
-
`请在 checkers/
|
|
48
|
+
`请在 checkers/ 中实现并注册(纯文本提示层已随 ADR-0029 关停)。`
|
|
55
49
|
);
|
|
56
50
|
}
|
|
57
51
|
}
|
|
@@ -67,7 +61,7 @@ for (const id of registry.keys()) {
|
|
|
67
61
|
|
|
68
62
|
/**
|
|
69
63
|
* 按约束 ID 查找检查实现;未注册返回 undefined
|
|
70
|
-
* (编排层对 kind='check'
|
|
64
|
+
* (编排层对 kind='check' 未注册的情况抛错)
|
|
71
65
|
*/
|
|
72
66
|
export function getConstraintCheck(id: string): ConstraintCheck | undefined {
|
|
73
67
|
return registry.get(id);
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* error 级轻量检查(工单 21):纯上下文证据标志判定,无 I/O
|
|
3
3
|
*
|
|
4
|
-
*
|
|
4
|
+
* harness#174 后仅存活的 flag:hasVerificationEvidence
|
|
5
|
+
*(incremental_progress / no_implementation_without_requirement 已随定义一并删除)
|
|
5
6
|
*
|
|
6
7
|
* 三态语义(ADR-0001 防爆措施):
|
|
7
8
|
* - undefined = flag 未接线 → skip(不评估,CLI pre-commit 等路径不误报违规)
|
|
@@ -14,13 +15,3 @@ export const noCompletionWithoutVerification = contextEvidenceFlag(
|
|
|
14
15
|
'no_completion_without_verification',
|
|
15
16
|
ctx => ctx.hasVerificationEvidence
|
|
16
17
|
);
|
|
17
|
-
|
|
18
|
-
export const incrementalProgress = contextEvidenceFlag(
|
|
19
|
-
'incremental_progress',
|
|
20
|
-
ctx => ctx.hasSingleTask
|
|
21
|
-
);
|
|
22
|
-
|
|
23
|
-
export const noImplementationWithoutRequirement = contextEvidenceFlag(
|
|
24
|
-
'no_implementation_without_requirement',
|
|
25
|
-
ctx => ctx.hasRequirement
|
|
26
|
-
);
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
import type { ConstraintCheck } from './types';
|
|
6
6
|
|
|
7
|
-
// m 标志必需:真实 diff 首行恒为 `diff --git`,缺 m 则 ^
|
|
7
|
+
// m 标志必需:真实 diff 首行恒为 `diff --git`,缺 m 则 ^ 永不命中删除行(checker 静默失效)
|
|
8
8
|
const DELETED_TEST_PATTERNS = [
|
|
9
9
|
/^-\s*(test|it|describe)\s*\(/m, // 删除 test/it/describe
|
|
10
10
|
/^-\s*expect\s*\(/m, // 删除 expect
|
|
@@ -113,7 +113,7 @@ export const MAX_EVIDENCE_ITEMS = 10;
|
|
|
113
113
|
/**
|
|
114
114
|
* 组装证据行:一行说明 + 逐条依据(超限截断)
|
|
115
115
|
*
|
|
116
|
-
* 每行自描述且不带缩进——缩进由消费端(CLI / gate 理由 /
|
|
116
|
+
* 每行自描述且不带缩进——缩进由消费端(CLI / gate 理由 / error 级异常文案)决定,trace 原样存。
|
|
117
117
|
* 修复入口不写在这里:那是各约束自己的事,写进各自的 summary 行(docs_freshness 的
|
|
118
118
|
* 幽灵条目与 sync-docs 无关,共用一个指针会误导)。
|
|
119
119
|
*/
|