@dommaker/harness 0.16.8 → 0.17.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 +41 -0
- package/README.md +33 -32
- package/bin/harness.js +34 -20
- package/dist/cli/commands/check.d.ts +3 -2
- package/dist/cli/commands/check.d.ts.map +1 -1
- package/dist/cli/commands/check.js +69 -36
- package/dist/cli/commands/check.js.map +1 -1
- package/dist/cli/commands/constraints-report.d.ts +42 -0
- package/dist/cli/commands/constraints-report.d.ts.map +1 -0
- package/dist/cli/commands/constraints-report.js +233 -0
- package/dist/cli/commands/constraints-report.js.map +1 -0
- package/dist/cli/commands/constraints-retire.d.ts +71 -0
- package/dist/cli/commands/constraints-retire.d.ts.map +1 -0
- package/dist/cli/commands/constraints-retire.js +384 -0
- package/dist/cli/commands/constraints-retire.js.map +1 -0
- package/dist/cli/commands/constraints.d.ts +1 -1
- package/dist/cli/commands/constraints.d.ts.map +1 -1
- package/dist/cli/commands/constraints.js +4 -4
- package/dist/cli/commands/constraints.js.map +1 -1
- package/dist/cli/commands/index.d.ts +2 -1
- package/dist/cli/commands/index.d.ts.map +1 -1
- package/dist/cli/commands/index.js +10 -4
- package/dist/cli/commands/index.js.map +1 -1
- package/dist/cli/commands/init.d.ts +20 -0
- package/dist/cli/commands/init.d.ts.map +1 -1
- package/dist/cli/commands/init.js +81 -59
- package/dist/cli/commands/init.js.map +1 -1
- package/dist/cli/commands/report.js +4 -4
- 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 +3 -4
- package/dist/cli/commands/status.js.map +1 -1
- package/dist/cli/commands/sync-docs/capabilities-syncer.d.ts +19 -2
- package/dist/cli/commands/sync-docs/capabilities-syncer.d.ts.map +1 -1
- package/dist/cli/commands/sync-docs/capabilities-syncer.js +79 -19
- package/dist/cli/commands/sync-docs/capabilities-syncer.js.map +1 -1
- package/dist/cli/commands/sync-docs/index.d.ts +2 -0
- package/dist/cli/commands/sync-docs/index.d.ts.map +1 -1
- package/dist/cli/commands/sync-docs/index.js +83 -20
- package/dist/cli/commands/sync-docs/index.js.map +1 -1
- package/dist/cli/commands/validate.d.ts.map +1 -1
- package/dist/cli/commands/validate.js +1 -5
- package/dist/cli/commands/validate.js.map +1 -1
- package/dist/core/constraints/capabilities-parser.d.ts +14 -0
- package/dist/core/constraints/capabilities-parser.d.ts.map +1 -1
- package/dist/core/constraints/capabilities-parser.js +30 -0
- package/dist/core/constraints/capabilities-parser.js.map +1 -1
- package/dist/core/constraints/checker.d.ts +13 -5
- package/dist/core/constraints/checker.d.ts.map +1 -1
- package/dist/core/constraints/checker.js +62 -25
- package/dist/core/constraints/checker.js.map +1 -1
- package/dist/core/constraints/checkers/capability-sync.d.ts +10 -0
- package/dist/core/constraints/checkers/capability-sync.d.ts.map +1 -1
- package/dist/core/constraints/checkers/capability-sync.js +73 -11
- package/dist/core/constraints/checkers/capability-sync.js.map +1 -1
- package/dist/core/constraints/checkers/context-doc-sync.d.ts +3 -0
- package/dist/core/constraints/checkers/context-doc-sync.d.ts.map +1 -1
- package/dist/core/constraints/checkers/context-doc-sync.js +8 -2
- package/dist/core/constraints/checkers/context-doc-sync.js.map +1 -1
- package/dist/core/constraints/checkers/docs-freshness.d.ts +1 -0
- package/dist/core/constraints/checkers/docs-freshness.d.ts.map +1 -1
- package/dist/core/constraints/checkers/docs-freshness.js +39 -0
- package/dist/core/constraints/checkers/docs-freshness.js.map +1 -1
- package/dist/core/constraints/checkers/index.d.ts +8 -4
- package/dist/core/constraints/checkers/index.d.ts.map +1 -1
- package/dist/core/constraints/checkers/index.js +29 -46
- package/dist/core/constraints/checkers/index.js.map +1 -1
- package/dist/core/constraints/checkers/iron-flags.d.ts +6 -7
- package/dist/core/constraints/checkers/iron-flags.d.ts.map +1 -1
- package/dist/core/constraints/checkers/iron-flags.js +10 -17
- package/dist/core/constraints/checkers/iron-flags.js.map +1 -1
- package/dist/core/constraints/checkers/no-hardcoded-credentials.d.ts +13 -0
- package/dist/core/constraints/checkers/no-hardcoded-credentials.d.ts.map +1 -0
- package/dist/core/constraints/checkers/no-hardcoded-credentials.js +91 -0
- package/dist/core/constraints/checkers/no-hardcoded-credentials.js.map +1 -0
- package/dist/core/constraints/checkers/types.d.ts +15 -4
- package/dist/core/constraints/checkers/types.d.ts.map +1 -1
- package/dist/core/constraints/checkers/types.js +16 -4
- package/dist/core/constraints/checkers/types.js.map +1 -1
- package/dist/core/constraints/context-builder.d.ts +6 -3
- package/dist/core/constraints/context-builder.d.ts.map +1 -1
- package/dist/core/constraints/context-builder.js +29 -20
- package/dist/core/constraints/context-builder.js.map +1 -1
- package/dist/core/constraints/definitions/guidelines.d.ts +6 -2
- package/dist/core/constraints/definitions/guidelines.d.ts.map +1 -1
- package/dist/core/constraints/definitions/guidelines.js +33 -574
- package/dist/core/constraints/definitions/guidelines.js.map +1 -1
- package/dist/core/constraints/definitions/iron-laws.d.ts +6 -2
- package/dist/core/constraints/definitions/iron-laws.d.ts.map +1 -1
- package/dist/core/constraints/definitions/iron-laws.js +48 -231
- package/dist/core/constraints/definitions/iron-laws.js.map +1 -1
- package/dist/core/constraints/definitions/prompts.d.ts +12 -0
- package/dist/core/constraints/definitions/prompts.d.ts.map +1 -0
- package/dist/core/constraints/definitions/prompts.js +405 -0
- package/dist/core/constraints/definitions/prompts.js.map +1 -0
- package/dist/core/constraints/definitions.d.ts +15 -9
- package/dist/core/constraints/definitions.d.ts.map +1 -1
- package/dist/core/constraints/definitions.js +18 -12
- package/dist/core/constraints/definitions.js.map +1 -1
- package/dist/core/constraints/index.d.ts +3 -2
- package/dist/core/constraints/index.d.ts.map +1 -1
- package/dist/core/constraints/index.js +8 -2
- package/dist/core/constraints/index.js.map +1 -1
- package/dist/core/constraints/injection-drift.d.ts +48 -0
- package/dist/core/constraints/injection-drift.d.ts.map +1 -0
- package/dist/core/constraints/injection-drift.js +140 -0
- package/dist/core/constraints/injection-drift.js.map +1 -0
- package/dist/core/constraints/injection-renderer.d.ts +23 -0
- package/dist/core/constraints/injection-renderer.d.ts.map +1 -0
- package/dist/core/constraints/injection-renderer.js +44 -0
- package/dist/core/constraints/injection-renderer.js.map +1 -0
- package/dist/core/constraints/interceptor.d.ts.map +1 -1
- package/dist/core/constraints/interceptor.js +3 -2
- package/dist/core/constraints/interceptor.js.map +1 -1
- package/dist/core/constraints/usage-report.d.ts +95 -0
- package/dist/core/constraints/usage-report.d.ts.map +1 -0
- package/dist/core/constraints/usage-report.js +206 -0
- package/dist/core/constraints/usage-report.js.map +1 -0
- package/dist/core/effective-constraints.d.ts +47 -0
- package/dist/core/effective-constraints.d.ts.map +1 -0
- package/dist/core/effective-constraints.js +60 -0
- package/dist/core/effective-constraints.js.map +1 -0
- package/dist/core/index.d.ts +1 -0
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +2 -0
- package/dist/core/index.js.map +1 -1
- package/dist/core/project-config-loader.d.ts +28 -3
- package/dist/core/project-config-loader.d.ts.map +1 -1
- package/dist/core/project-config-loader.js +74 -8
- package/dist/core/project-config-loader.js.map +1 -1
- package/dist/dashboard/data.d.ts +1 -9
- package/dist/dashboard/data.d.ts.map +1 -1
- package/dist/dashboard/data.js +7 -15
- package/dist/dashboard/data.js.map +1 -1
- package/dist/dashboard/types.d.ts +13 -1
- package/dist/dashboard/types.d.ts.map +1 -1
- package/dist/index.d.ts +0 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -13
- package/dist/index.js.map +1 -1
- package/dist/monitoring/index.d.ts +0 -2
- package/dist/monitoring/index.d.ts.map +1 -1
- package/dist/monitoring/index.js +0 -2
- package/dist/monitoring/index.js.map +1 -1
- package/dist/monitoring/knowledge-evolver.d.ts +1 -1
- package/dist/monitoring/knowledge-evolver.js +1 -1
- package/dist/monitoring/trace-analyzer.d.ts +1 -1
- package/dist/monitoring/trace-analyzer.d.ts.map +1 -1
- package/dist/monitoring/trace-analyzer.js +16 -10
- package/dist/monitoring/trace-analyzer.js.map +1 -1
- package/dist/monitoring/traces.d.ts +2 -1
- package/dist/monitoring/traces.d.ts.map +1 -1
- package/dist/monitoring/traces.js +5 -3
- package/dist/monitoring/traces.js.map +1 -1
- package/dist/presets/standard.d.ts +3 -1
- package/dist/presets/standard.d.ts.map +1 -1
- package/dist/presets/standard.js +18 -8
- package/dist/presets/standard.js.map +1 -1
- package/dist/types/constraint.d.ts +51 -11
- package/dist/types/constraint.d.ts.map +1 -1
- package/dist/types/constraint.js +8 -4
- package/dist/types/constraint.js.map +1 -1
- package/dist/types/index.d.ts +1 -1
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/index.js.map +1 -1
- package/dist/types/monitoring-types.d.ts +2 -63
- package/dist/types/monitoring-types.d.ts.map +1 -1
- package/dist/types/monitoring-types.js +2 -2
- package/dist/types/project-config.d.ts +32 -1
- package/dist/types/project-config.d.ts.map +1 -1
- package/dist/types/trace.d.ts +16 -7
- package/dist/types/trace.d.ts.map +1 -1
- package/dist/types/trace.js +8 -0
- package/dist/types/trace.js.map +1 -1
- package/package.json +1 -1
- package/src/CONTEXT.md +2 -2
- package/src/__tests__/checker-extra.test.ts +356 -331
- package/src/__tests__/checker.test.ts +87 -724
- package/src/__tests__/constraint-doctor.test.ts +5 -5
- package/src/__tests__/doctor-extra.test.ts +164 -0
- package/src/__tests__/effective-constraints.test.ts +147 -0
- package/src/__tests__/extend-exceptions.test.ts +3 -3
- package/src/__tests__/iron-laws.test.ts +115 -91
- package/src/__tests__/no-hardcoded-credentials.test.ts +90 -0
- package/src/__tests__/presets.test.ts +7 -7
- package/src/__tests__/project-config-loader-extra.test.ts +4 -4
- package/src/__tests__/project-config-loader.test.ts +40 -1
- package/src/__tests__/skip-semantics.test.ts +322 -0
- package/src/cli/commands/CONTEXT.md +5 -3
- package/src/cli/commands/__tests__/check-drift.test.ts +127 -0
- package/src/cli/commands/__tests__/check-skip-output.test.ts +128 -0
- package/src/cli/commands/__tests__/check.test.ts +14 -25
- package/src/cli/commands/__tests__/constraints-report.test.ts +327 -0
- package/src/cli/commands/__tests__/constraints-retire.test.ts +283 -0
- package/src/cli/commands/__tests__/init-injection.test.ts +234 -0
- package/src/cli/commands/__tests__/status-extra.test.ts +11 -11
- package/src/cli/commands/__tests__/status.test.ts +1 -1
- package/src/cli/commands/__tests__/sync-docs.test.ts +163 -0
- package/src/cli/commands/check.ts +72 -38
- package/src/cli/commands/constraints-report.ts +234 -0
- package/src/cli/commands/constraints-retire.ts +443 -0
- package/src/cli/commands/constraints.ts +5 -5
- package/src/cli/commands/index.ts +2 -1
- package/src/cli/commands/init.ts +94 -66
- package/src/cli/commands/report.ts +6 -6
- package/src/cli/commands/status.ts +3 -4
- package/src/cli/commands/sync-docs/capabilities-syncer.ts +90 -15
- package/src/cli/commands/sync-docs/index.ts +87 -24
- package/src/cli/commands/validate.ts +1 -5
- package/src/core/CONTEXT.md +7 -4
- package/src/core/constraints/__tests__/injection-drift.test.ts +164 -0
- package/src/core/constraints/__tests__/interceptor.test.ts +4 -0
- package/src/core/constraints/capabilities-parser.ts +28 -0
- package/src/core/constraints/checker.ts +73 -28
- package/src/core/constraints/checkers/capability-sync.ts +89 -18
- package/src/core/constraints/checkers/context-doc-sync.ts +9 -2
- package/src/core/constraints/checkers/docs-freshness.ts +43 -0
- package/src/core/constraints/checkers/index.ts +38 -71
- package/src/core/constraints/checkers/iron-flags.ts +13 -49
- package/src/core/constraints/checkers/no-hardcoded-credentials.ts +93 -0
- package/src/core/constraints/checkers/types.ts +27 -5
- package/src/core/constraints/context-builder.ts +28 -19
- package/src/core/constraints/definitions/guidelines.ts +33 -599
- package/src/core/constraints/definitions/iron-laws.ts +48 -239
- package/src/core/constraints/definitions/prompts.ts +419 -0
- package/src/core/constraints/definitions.ts +18 -11
- package/src/core/constraints/index.ts +10 -1
- package/src/core/constraints/injection-drift.ts +139 -0
- package/src/core/constraints/injection-renderer.ts +44 -0
- package/src/core/constraints/interceptor.ts +3 -2
- package/src/core/constraints/usage-report.ts +254 -0
- package/src/core/effective-constraints.ts +85 -0
- package/src/core/index.ts +4 -1
- package/src/core/project-config-loader.ts +82 -9
- package/src/dashboard/__tests__/data.test.ts +5 -12
- package/src/dashboard/data.ts +9 -19
- package/src/dashboard/types.ts +18 -1
- package/src/index.ts +0 -12
- package/src/knowledge/CONTEXT.md +2 -2
- package/src/monitoring/CONTEXT.md +3 -4
- package/src/monitoring/index.ts +0 -2
- package/src/monitoring/knowledge-evolver.ts +1 -1
- package/src/monitoring/trace-analyzer.ts +15 -10
- package/src/monitoring/traces.ts +10 -6
- package/src/presets/__tests__/standard.test.ts +11 -9
- package/src/presets/standard.ts +24 -15
- package/src/types/constraint.ts +59 -14
- package/src/types/index.ts +1 -3
- package/src/types/monitoring-types.ts +2 -84
- package/src/types/project-config.ts +37 -1
- package/src/types/trace.ts +18 -7
- package/src/verification/CONTEXT.md +1 -1
- package/dist/cli/commands/flow.d.ts +0 -22
- package/dist/cli/commands/flow.d.ts.map +0 -1
- package/dist/cli/commands/flow.js +0 -275
- package/dist/cli/commands/flow.js.map +0 -1
- package/dist/constraints/lifecycle-runner.d.ts +0 -52
- package/dist/constraints/lifecycle-runner.d.ts.map +0 -1
- package/dist/constraints/lifecycle-runner.js +0 -151
- package/dist/constraints/lifecycle-runner.js.map +0 -1
- package/dist/constraints/registry.d.ts +0 -27
- package/dist/constraints/registry.d.ts.map +0 -1
- package/dist/constraints/registry.js +0 -128
- package/dist/constraints/registry.js.map +0 -1
- package/dist/constraints/types.d.ts +0 -53
- package/dist/constraints/types.d.ts.map +0 -1
- package/dist/constraints/types.js +0 -8
- package/dist/constraints/types.js.map +0 -1
- package/dist/core/constraints/checkers/always-pass.d.ts +0 -17
- package/dist/core/constraints/checkers/always-pass.d.ts.map +0 -1
- package/dist/core/constraints/checkers/always-pass.js +0 -23
- package/dist/core/constraints/checkers/always-pass.js.map +0 -1
- package/dist/core/constraints/checkers/guideline-flags.d.ts +0 -9
- package/dist/core/constraints/checkers/guideline-flags.d.ts.map +0 -1
- package/dist/core/constraints/checkers/guideline-flags.js +0 -13
- package/dist/core/constraints/checkers/guideline-flags.js.map +0 -1
- package/dist/core/constraints/checkers/no-any-type.d.ts +0 -6
- package/dist/core/constraints/checkers/no-any-type.d.ts.map +0 -1
- package/dist/core/constraints/checkers/no-any-type.js +0 -42
- package/dist/core/constraints/checkers/no-any-type.js.map +0 -1
- package/dist/core/constraints/checkers/no-excuse-patterns.d.ts +0 -6
- package/dist/core/constraints/checkers/no-excuse-patterns.d.ts.map +0 -1
- package/dist/core/constraints/checkers/no-excuse-patterns.js +0 -25
- package/dist/core/constraints/checkers/no-excuse-patterns.js.map +0 -1
- package/dist/core/constraints/checkers/no-fuzzy-completion-claim.d.ts +0 -6
- package/dist/core/constraints/checkers/no-fuzzy-completion-claim.d.ts.map +0 -1
- package/dist/core/constraints/checkers/no-fuzzy-completion-claim.js +0 -34
- package/dist/core/constraints/checkers/no-fuzzy-completion-claim.js.map +0 -1
- package/dist/core/constraints/checkers/no-performative-agreement.d.ts +0 -8
- package/dist/core/constraints/checkers/no-performative-agreement.d.ts.map +0 -1
- package/dist/core/constraints/checkers/no-performative-agreement.js +0 -23
- package/dist/core/constraints/checkers/no-performative-agreement.js.map +0 -1
- package/dist/core/constraints/checkers/no-simplification-without-approval.d.ts +0 -6
- package/dist/core/constraints/checkers/no-simplification-without-approval.d.ts.map +0 -1
- package/dist/core/constraints/checkers/no-simplification-without-approval.js +0 -30
- package/dist/core/constraints/checkers/no-simplification-without-approval.js.map +0 -1
- package/dist/core/constraints/checkers/test-coverage.d.ts +0 -6
- package/dist/core/constraints/checkers/test-coverage.d.ts.map +0 -1
- package/dist/core/constraints/checkers/test-coverage.js +0 -33
- package/dist/core/constraints/checkers/test-coverage.js.map +0 -1
- package/dist/core/constraints/checkers/yagni.d.ts +0 -8
- package/dist/core/constraints/checkers/yagni.d.ts.map +0 -1
- package/dist/core/constraints/checkers/yagni.js +0 -96
- package/dist/core/constraints/checkers/yagni.js.map +0 -1
- package/dist/core/constraints/definitions/tips.d.ts +0 -7
- package/dist/core/constraints/definitions/tips.d.ts.map +0 -1
- package/dist/core/constraints/definitions/tips.js +0 -62
- package/dist/core/constraints/definitions/tips.js.map +0 -1
- package/dist/evolution/auto-evolve.d.ts +0 -35
- package/dist/evolution/auto-evolve.d.ts.map +0 -1
- package/dist/evolution/auto-evolve.js +0 -64
- package/dist/evolution/auto-evolve.js.map +0 -1
- package/dist/evolution/index.d.ts +0 -2
- package/dist/evolution/index.d.ts.map +0 -1
- package/dist/evolution/index.js +0 -18
- package/dist/evolution/index.js.map +0 -1
- package/dist/monitoring/constraint-evolver.d.ts +0 -120
- package/dist/monitoring/constraint-evolver.d.ts.map +0 -1
- package/dist/monitoring/constraint-evolver.js +0 -410
- package/dist/monitoring/constraint-evolver.js.map +0 -1
- package/src/__tests__/constraint-evolver.test.ts +0 -405
- package/src/__tests__/doctor-evolver.test.ts +0 -381
- package/src/cli/commands/__tests__/flow.test.ts +0 -343
- package/src/cli/commands/flow.ts +0 -277
- package/src/constraints/__tests__/lifecycle-runner.test.ts +0 -246
- package/src/constraints/__tests__/registry.test.ts +0 -196
- package/src/constraints/lifecycle-runner.ts +0 -184
- package/src/constraints/registry.ts +0 -134
- package/src/constraints/types.ts +0 -59
- package/src/core/constraints/checkers/always-pass.ts +0 -22
- package/src/core/constraints/checkers/guideline-flags.ts +0 -30
- package/src/core/constraints/checkers/no-any-type.ts +0 -42
- package/src/core/constraints/checkers/no-excuse-patterns.ts +0 -24
- package/src/core/constraints/checkers/no-fuzzy-completion-claim.ts +0 -33
- package/src/core/constraints/checkers/no-performative-agreement.ts +0 -22
- package/src/core/constraints/checkers/no-simplification-without-approval.ts +0 -29
- package/src/core/constraints/checkers/test-coverage.ts +0 -35
- package/src/core/constraints/checkers/yagni.ts +0 -65
- package/src/core/constraints/definitions/tips.ts +0 -63
- package/src/evolution/CONTEXT.md +0 -22
- package/src/evolution/__tests__/auto-evolve.test.ts +0 -319
- package/src/evolution/auto-evolve.ts +0 -98
- package/src/evolution/index.ts +0 -1
- package/src/monitoring/constraint-evolver.ts +0 -501
|
@@ -1,16 +1,17 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* checker.ts 补充测试
|
|
3
3
|
*
|
|
4
|
-
* 目标:覆盖
|
|
5
|
-
*
|
|
4
|
+
* 目标:覆盖 checkCapabilitySync 完整流程、beforeExecution、findApplicableConstraints
|
|
5
|
+
* (ADR-0001:已退役 checker 的用例随约束数据模型 v2 移除)
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
import { describe, it, expect, beforeAll, afterAll } from '@jest/globals';
|
|
8
|
+
import { describe, it, expect, beforeAll, afterAll, jest } from '@jest/globals';
|
|
9
9
|
import {
|
|
10
10
|
ConstraintChecker,
|
|
11
11
|
checkConstraints,
|
|
12
12
|
checkBeforeExecution,
|
|
13
13
|
} from '../core/constraints/checker';
|
|
14
|
+
import { getConstraintCheck, type CheckEnv } from '../core/constraints/checkers';
|
|
14
15
|
import type { ConstraintContext } from '../types/constraint';
|
|
15
16
|
import * as fs from 'fs';
|
|
16
17
|
import * as path from 'path';
|
|
@@ -42,8 +43,11 @@ describe('ConstraintChecker - 补充覆盖', () => {
|
|
|
42
43
|
}
|
|
43
44
|
});
|
|
44
45
|
|
|
45
|
-
describe('
|
|
46
|
-
it('
|
|
46
|
+
describe('checkCapabilitySync', () => {
|
|
47
|
+
it('无代码变更应该通过', async () => {
|
|
48
|
+
// 清理 staged changes
|
|
49
|
+
execSync('git reset HEAD', { cwd: tempDir, stdio: 'pipe' });
|
|
50
|
+
|
|
47
51
|
const context: ConstraintContext = {
|
|
48
52
|
operation: 'commit',
|
|
49
53
|
projectPath: tempDir,
|
|
@@ -51,9 +55,10 @@ describe('ConstraintChecker - 补充覆盖', () => {
|
|
|
51
55
|
|
|
52
56
|
const result = await checker.check(
|
|
53
57
|
{
|
|
54
|
-
id: '
|
|
58
|
+
id: 'capability_sync',
|
|
59
|
+
kind: 'check',
|
|
55
60
|
level: 'guideline',
|
|
56
|
-
rule: '
|
|
61
|
+
rule: 'CAPABILITY SYNC',
|
|
57
62
|
message: 'test',
|
|
58
63
|
trigger: 'commit',
|
|
59
64
|
enforcement: 'test',
|
|
@@ -64,23 +69,15 @@ describe('ConstraintChecker - 补充覆盖', () => {
|
|
|
64
69
|
expect(result.satisfied).toBe(true);
|
|
65
70
|
});
|
|
66
71
|
|
|
67
|
-
it('
|
|
68
|
-
// 创建
|
|
69
|
-
const
|
|
70
|
-
fs.
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
total: {
|
|
77
|
-
lines: { pct: 80 },
|
|
78
|
-
statements: { pct: 80 },
|
|
79
|
-
branches: { pct: 75 },
|
|
80
|
-
functions: { pct: 85 },
|
|
81
|
-
},
|
|
82
|
-
})
|
|
83
|
-
);
|
|
72
|
+
it('有代码变更且有 CAPABILITIES.md 应该通过', async () => {
|
|
73
|
+
// 创建 CAPABILITIES.md(如果不存在)
|
|
74
|
+
const capFile = path.join(tempDir, 'CAPABILITIES.md');
|
|
75
|
+
fs.writeFileSync(capFile, '# Capabilities\n\n- Feature: test');
|
|
76
|
+
|
|
77
|
+
// 创建代码文件并 stage
|
|
78
|
+
const codeFile = path.join(tempDir, 'feature.ts');
|
|
79
|
+
fs.writeFileSync(codeFile, 'export function feature() {}');
|
|
80
|
+
execSync('git add .', { cwd: tempDir });
|
|
84
81
|
|
|
85
82
|
const context: ConstraintContext = {
|
|
86
83
|
operation: 'commit',
|
|
@@ -89,9 +86,10 @@ describe('ConstraintChecker - 补充覆盖', () => {
|
|
|
89
86
|
|
|
90
87
|
const result = await checker.check(
|
|
91
88
|
{
|
|
92
|
-
id: '
|
|
89
|
+
id: 'capability_sync',
|
|
90
|
+
kind: 'check',
|
|
93
91
|
level: 'guideline',
|
|
94
|
-
rule: '
|
|
92
|
+
rule: 'CAPABILITY SYNC',
|
|
95
93
|
message: 'test',
|
|
96
94
|
trigger: 'commit',
|
|
97
95
|
enforcement: 'test',
|
|
@@ -101,23 +99,19 @@ describe('ConstraintChecker - 补充覆盖', () => {
|
|
|
101
99
|
|
|
102
100
|
expect(result.satisfied).toBe(true);
|
|
103
101
|
|
|
104
|
-
//
|
|
105
|
-
|
|
102
|
+
// Cleanup
|
|
103
|
+
execSync('git reset HEAD', { cwd: tempDir, stdio: 'pipe' });
|
|
106
104
|
});
|
|
107
105
|
|
|
108
|
-
it('
|
|
109
|
-
|
|
110
|
-
|
|
106
|
+
it('有代码变更且 CAPABILITIES.md 有表格但缺少新模块应该失败', async () => {
|
|
107
|
+
// 创建 CAPABILITIES.md,含表格但不包含新文件
|
|
108
|
+
const capFile = path.join(tempDir, 'CAPABILITIES.md');
|
|
109
|
+
fs.writeFileSync(capFile, '# Capabilities\n\n| 模块 | 文件 | 功能 |\n|------|------|------|\n| 旧模块 | old/module.ts | 旧功能 |');
|
|
111
110
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
total: {
|
|
117
|
-
lines: { pct: 30 },
|
|
118
|
-
},
|
|
119
|
-
})
|
|
120
|
-
);
|
|
111
|
+
// 创建新的代码文件并 stage
|
|
112
|
+
const codeFile = path.join(tempDir, 'new-module.ts');
|
|
113
|
+
fs.writeFileSync(codeFile, 'export function newModule() {}');
|
|
114
|
+
execSync('git add .', { cwd: tempDir, stdio: 'pipe' });
|
|
121
115
|
|
|
122
116
|
const context: ConstraintContext = {
|
|
123
117
|
operation: 'commit',
|
|
@@ -126,9 +120,10 @@ describe('ConstraintChecker - 补充覆盖', () => {
|
|
|
126
120
|
|
|
127
121
|
const result = await checker.check(
|
|
128
122
|
{
|
|
129
|
-
id: '
|
|
123
|
+
id: 'capability_sync',
|
|
124
|
+
kind: 'check',
|
|
130
125
|
level: 'guideline',
|
|
131
|
-
rule: '
|
|
126
|
+
rule: 'CAPABILITY SYNC',
|
|
132
127
|
message: 'test',
|
|
133
128
|
trigger: 'commit',
|
|
134
129
|
enforcement: 'test',
|
|
@@ -136,17 +131,24 @@ describe('ConstraintChecker - 补充覆盖', () => {
|
|
|
136
131
|
context
|
|
137
132
|
);
|
|
138
133
|
|
|
134
|
+
// CAPABILITIES.md 有表格但新文件未被覆盖,应该失败
|
|
139
135
|
expect(result.satisfied).toBe(false);
|
|
140
136
|
|
|
141
|
-
|
|
137
|
+
// Cleanup
|
|
138
|
+
execSync('git reset HEAD', { cwd: tempDir, stdio: 'pipe' });
|
|
142
139
|
});
|
|
143
140
|
|
|
144
|
-
it('
|
|
145
|
-
|
|
146
|
-
|
|
141
|
+
it('有代码变更但无 CAPABILITIES.md 应该跳过(ADR-0001 存在性探测)', async () => {
|
|
142
|
+
// 确保 CAPABILITIES.md 不存在
|
|
143
|
+
const capFile = path.join(tempDir, 'CAPABILITIES.md');
|
|
144
|
+
if (fs.existsSync(capFile)) {
|
|
145
|
+
fs.rmSync(capFile, { force: true });
|
|
146
|
+
}
|
|
147
147
|
|
|
148
|
-
|
|
149
|
-
|
|
148
|
+
// 创建新的代码文件并 stage
|
|
149
|
+
const newCodeFile = path.join(tempDir, 'newfeature.ts');
|
|
150
|
+
fs.writeFileSync(newCodeFile, 'export function newfeature() {}');
|
|
151
|
+
execSync('git add ' + newCodeFile, { cwd: tempDir });
|
|
150
152
|
|
|
151
153
|
const context: ConstraintContext = {
|
|
152
154
|
operation: 'commit',
|
|
@@ -155,9 +157,10 @@ describe('ConstraintChecker - 补充覆盖', () => {
|
|
|
155
157
|
|
|
156
158
|
const result = await checker.check(
|
|
157
159
|
{
|
|
158
|
-
id: '
|
|
160
|
+
id: 'capability_sync',
|
|
161
|
+
kind: 'check',
|
|
159
162
|
level: 'guideline',
|
|
160
|
-
rule: '
|
|
163
|
+
rule: 'CAPABILITY SYNC',
|
|
161
164
|
message: 'test',
|
|
162
165
|
trigger: 'commit',
|
|
163
166
|
enforcement: 'test',
|
|
@@ -165,216 +168,318 @@ describe('ConstraintChecker - 补充覆盖', () => {
|
|
|
165
168
|
context
|
|
166
169
|
);
|
|
167
170
|
|
|
168
|
-
//
|
|
171
|
+
// 未采用 CAPABILITIES.md 约定 → skip(不计 pass/fail,不阻断)
|
|
172
|
+
expect(result.skipped).toBe(true);
|
|
169
173
|
expect(result.satisfied).toBe(true);
|
|
170
174
|
|
|
171
|
-
|
|
175
|
+
// Cleanup
|
|
176
|
+
execSync('git reset HEAD', { cwd: tempDir, stdio: 'pipe' });
|
|
172
177
|
});
|
|
173
178
|
});
|
|
174
179
|
|
|
175
|
-
describe('
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
const
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
};
|
|
180
|
+
describe('checkCapabilitySync module 模式(governance.capabilities.mode)', () => {
|
|
181
|
+
/** 建一个带 .harness/config.yml + CAPABILITIES.md + 源文件的临时项目 */
|
|
182
|
+
const setupCapProject = (
|
|
183
|
+
name: string,
|
|
184
|
+
mode: 'file' | 'module' | undefined,
|
|
185
|
+
capContent: string,
|
|
186
|
+
files: string[]
|
|
187
|
+
): string => {
|
|
188
|
+
const dir = path.join(tempDir, name);
|
|
189
|
+
fs.mkdirSync(path.join(dir, '.harness'), { recursive: true });
|
|
190
|
+
const yaml = require('js-yaml');
|
|
191
|
+
const config = mode ? { governance: { capabilities: { mode } } } : {};
|
|
192
|
+
fs.writeFileSync(path.join(dir, '.harness', 'config.yml'), yaml.dump(config));
|
|
193
|
+
fs.writeFileSync(path.join(dir, 'CAPABILITIES.md'), capContent);
|
|
194
|
+
for (const f of files) {
|
|
195
|
+
const fp = path.join(dir, f);
|
|
196
|
+
fs.mkdirSync(path.dirname(fp), { recursive: true });
|
|
197
|
+
fs.writeFileSync(fp, 'export const x = 1;');
|
|
198
|
+
}
|
|
199
|
+
return dir;
|
|
200
|
+
};
|
|
187
201
|
|
|
188
|
-
|
|
202
|
+
const runCapCheck = (projectPath: string) =>
|
|
203
|
+
checker.check(
|
|
189
204
|
{
|
|
190
|
-
id: '
|
|
205
|
+
id: 'capability_sync',
|
|
206
|
+
kind: 'check',
|
|
191
207
|
level: 'guideline',
|
|
192
|
-
rule: '
|
|
208
|
+
rule: 'CAPABILITY SYNC',
|
|
193
209
|
message: 'test',
|
|
194
210
|
trigger: 'commit',
|
|
195
211
|
enforcement: 'test',
|
|
196
212
|
},
|
|
197
|
-
|
|
213
|
+
{ operation: 'commit', projectPath }
|
|
214
|
+
);
|
|
215
|
+
|
|
216
|
+
beforeAll(() => {
|
|
217
|
+
// 清理 staged 状态,隔离 step 1(git diff 增量)对本组用例的干扰
|
|
218
|
+
try {
|
|
219
|
+
execSync('git reset HEAD', { cwd: tempDir, stdio: 'pipe' });
|
|
220
|
+
} catch {
|
|
221
|
+
// ignore
|
|
222
|
+
}
|
|
223
|
+
});
|
|
224
|
+
|
|
225
|
+
it('module 模式:目录条目覆盖源文件应该通过', async () => {
|
|
226
|
+
const dir = setupCapProject(
|
|
227
|
+
'capmod-covered',
|
|
228
|
+
'module',
|
|
229
|
+
'# Capabilities\n\n| 模块 | 文件 | 说明 |\n|------|------|------|\n| 核心 | src/core/ | 核心模块 |',
|
|
230
|
+
['src/core/foo.ts', 'src/core/bar.ts']
|
|
198
231
|
);
|
|
199
232
|
|
|
233
|
+
const result = await runCapCheck(dir);
|
|
200
234
|
expect(result.satisfied).toBe(true);
|
|
235
|
+
|
|
236
|
+
fs.rmSync(dir, { recursive: true, force: true });
|
|
201
237
|
});
|
|
202
238
|
|
|
203
|
-
it('
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
fs.writeFileSync(simplifyFile, '// removed test for simplicity\nexport const y = 2;');
|
|
211
|
-
execSync('git add .', { cwd: tempDir });
|
|
239
|
+
it('module 模式:文件条目精确匹配也算覆盖', async () => {
|
|
240
|
+
const dir = setupCapProject(
|
|
241
|
+
'capmod-file-entry',
|
|
242
|
+
'module',
|
|
243
|
+
'# Capabilities\n\n| 模块 | 文件 | 说明 |\n|------|------|------|\n| foo | src/core/foo.ts | foo |',
|
|
244
|
+
['src/core/foo.ts']
|
|
245
|
+
);
|
|
212
246
|
|
|
213
|
-
const
|
|
214
|
-
|
|
215
|
-
projectPath: tempDir,
|
|
216
|
-
};
|
|
247
|
+
const result = await runCapCheck(dir);
|
|
248
|
+
expect(result.satisfied).toBe(true);
|
|
217
249
|
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
context
|
|
250
|
+
fs.rmSync(dir, { recursive: true, force: true });
|
|
251
|
+
});
|
|
252
|
+
|
|
253
|
+
it('module 模式:新目录未登记应该失败', async () => {
|
|
254
|
+
const dir = setupCapProject(
|
|
255
|
+
'capmod-uncovered',
|
|
256
|
+
'module',
|
|
257
|
+
'# Capabilities\n\n| 模块 | 文件 | 说明 |\n|------|------|------|\n| 核心 | src/core/ | 核心模块 |',
|
|
258
|
+
['src/core/foo.ts', 'src/newdir/bar.ts']
|
|
228
259
|
);
|
|
229
260
|
|
|
261
|
+
const result = await runCapCheck(dir);
|
|
230
262
|
expect(result.satisfied).toBe(false);
|
|
231
|
-
|
|
232
|
-
// cleanup - unstage and remove
|
|
233
|
-
execSync('git reset HEAD -- ' + simplifyFile, { cwd: tempDir, stdio: 'pipe' });
|
|
234
|
-
fs.rmSync(simplifyFile, { force: true });
|
|
235
|
-
});
|
|
236
|
-
});
|
|
237
263
|
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
// 清理 staged changes
|
|
241
|
-
execSync('git reset HEAD', { cwd: tempDir, stdio: 'pipe' });
|
|
242
|
-
|
|
243
|
-
const context: ConstraintContext = {
|
|
244
|
-
operation: 'commit',
|
|
245
|
-
projectPath: tempDir,
|
|
246
|
-
};
|
|
264
|
+
fs.rmSync(dir, { recursive: true, force: true });
|
|
265
|
+
});
|
|
247
266
|
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
enforcement: 'test',
|
|
256
|
-
},
|
|
257
|
-
context
|
|
267
|
+
it('file 模式原行为不变:目录条目不参与覆盖判定', async () => {
|
|
268
|
+
// file 模式下 step2 要求逐文件精确匹配,src/core/ 目录条目不能 rescue bar.ts
|
|
269
|
+
const dir = setupCapProject(
|
|
270
|
+
'capfile-dir-no-rescue',
|
|
271
|
+
'file',
|
|
272
|
+
'# Capabilities\n\n| 模块 | 文件 | 说明 |\n|------|------|------|\n| foo | src/core/foo.ts | foo |\n| 目录 | src/core/ | 目录条目 |',
|
|
273
|
+
['src/core/foo.ts', 'src/core/bar.ts']
|
|
258
274
|
);
|
|
259
275
|
|
|
260
|
-
|
|
276
|
+
const result = await runCapCheck(dir);
|
|
277
|
+
expect(result.satisfied).toBe(false);
|
|
278
|
+
|
|
279
|
+
fs.rmSync(dir, { recursive: true, force: true });
|
|
261
280
|
});
|
|
262
281
|
|
|
263
|
-
it('
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
fs.writeFileSync(codeFile, 'export function feature() {}');
|
|
271
|
-
execSync('git add .', { cwd: tempDir });
|
|
282
|
+
it('step2 全量扫描(file 模式):全部源文件已登记应该通过', async () => {
|
|
283
|
+
const dir = setupCapProject(
|
|
284
|
+
'capfile-step2-ok',
|
|
285
|
+
undefined,
|
|
286
|
+
'# Capabilities\n\n| 模块 | 文件 | 说明 |\n|------|------|------|\n| foo | src/foo.ts | foo |',
|
|
287
|
+
['src/foo.ts']
|
|
288
|
+
);
|
|
272
289
|
|
|
273
|
-
const
|
|
274
|
-
|
|
275
|
-
projectPath: tempDir,
|
|
276
|
-
};
|
|
290
|
+
const result = await runCapCheck(dir);
|
|
291
|
+
expect(result.satisfied).toBe(true);
|
|
277
292
|
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
context
|
|
293
|
+
fs.rmSync(dir, { recursive: true, force: true });
|
|
294
|
+
});
|
|
295
|
+
|
|
296
|
+
it('step2 全量扫描(file 模式):有未登记源文件应该失败', async () => {
|
|
297
|
+
const dir = setupCapProject(
|
|
298
|
+
'capfile-step2-missing',
|
|
299
|
+
undefined,
|
|
300
|
+
'# Capabilities\n\n| 模块 | 文件 | 说明 |\n|------|------|------|\n| foo | src/foo.ts | foo |',
|
|
301
|
+
['src/foo.ts', 'src/unlisted.ts']
|
|
288
302
|
);
|
|
289
303
|
|
|
290
|
-
|
|
304
|
+
const result = await runCapCheck(dir);
|
|
305
|
+
expect(result.satisfied).toBe(false);
|
|
291
306
|
|
|
292
|
-
|
|
293
|
-
execSync('git reset HEAD', { cwd: tempDir, stdio: 'pipe' });
|
|
307
|
+
fs.rmSync(dir, { recursive: true, force: true });
|
|
294
308
|
});
|
|
309
|
+
});
|
|
295
310
|
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
311
|
+
describe('checkCapabilitySync 遗留问题回归(2026-08-08 评估稿第四节)', () => {
|
|
312
|
+
const capCheck = getConstraintCheck('capability_sync')!;
|
|
313
|
+
|
|
314
|
+
const setupDir = (name: string, capContent: string, files: string[] = []): string => {
|
|
315
|
+
const dir = path.join(tempDir, name);
|
|
316
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
317
|
+
fs.writeFileSync(path.join(dir, 'CAPABILITIES.md'), capContent);
|
|
318
|
+
for (const f of files) {
|
|
319
|
+
const fp = path.join(dir, f);
|
|
320
|
+
fs.mkdirSync(path.dirname(fp), { recursive: true });
|
|
321
|
+
fs.writeFileSync(fp, 'export const x = 1;');
|
|
322
|
+
}
|
|
323
|
+
return dir;
|
|
324
|
+
};
|
|
325
|
+
|
|
326
|
+
/** 直接构造 CheckEnv:stub stagedDiffNames / srcScan,不走真实 git */
|
|
327
|
+
const makeEnv = (
|
|
328
|
+
projectPath: string,
|
|
329
|
+
staged: string[],
|
|
330
|
+
scan: Record<string, string[]> = {}
|
|
331
|
+
): CheckEnv => ({
|
|
332
|
+
context: { operation: 'commit', projectPath },
|
|
333
|
+
projectPath,
|
|
334
|
+
stagedDiff: async () => '',
|
|
335
|
+
stagedDiffNames: async () => staged.join('\n'),
|
|
336
|
+
srcScan: (root: string) => scan[root] ?? [],
|
|
337
|
+
});
|
|
300
338
|
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
fs.writeFileSync(codeFile, 'export function newModule() {}');
|
|
304
|
-
execSync('git add .', { cwd: tempDir, stdio: 'pipe' });
|
|
339
|
+
const tableWith = (row: string): string =>
|
|
340
|
+
'# Capabilities\n\n| 模块 | 文件 | 说明 |\n|------|------|------|\n' + row + '\n';
|
|
305
341
|
|
|
306
|
-
|
|
307
|
-
operation: 'commit',
|
|
308
|
-
projectPath: tempDir,
|
|
309
|
-
};
|
|
342
|
+
const EMPTY_TABLE = '# Capabilities\n\n| 模块 | 文件 | 说明 |\n|------|------|------|\n';
|
|
310
343
|
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
);
|
|
344
|
+
it('问题1:step1 应要求每个变更文件都被覆盖(every 而非 some)', async () => {
|
|
345
|
+
// 文档登记 src/foo.ts;同时 staged 已登记的 src/foo.ts 与未登记的 scripts/bar.ts
|
|
346
|
+
// some() 下只要有 foo.ts 命中即整体通过,bar.ts 漏网
|
|
347
|
+
const dir = setupDir('legacy-step1-some', tableWith('| foo | src/foo.ts | foo |'));
|
|
348
|
+
try {
|
|
349
|
+
expect(await capCheck.evaluate(makeEnv(dir, ['src/foo.ts', 'scripts/bar.ts']))).toBe(false);
|
|
350
|
+
} finally {
|
|
351
|
+
fs.rmSync(dir, { recursive: true, force: true });
|
|
352
|
+
}
|
|
353
|
+
});
|
|
322
354
|
|
|
323
|
-
|
|
324
|
-
|
|
355
|
+
it('问题3a:step1 不得因 endsWith 造成后缀碰撞(xfoo.ts 不应被 foo.ts 覆盖)', async () => {
|
|
356
|
+
const dir = setupDir('legacy-step1-endswith', tableWith('| foo | foo.ts | foo |'));
|
|
357
|
+
try {
|
|
358
|
+
expect(await capCheck.evaluate(makeEnv(dir, ['web/xfoo.ts']))).toBe(false);
|
|
359
|
+
} finally {
|
|
360
|
+
fs.rmSync(dir, { recursive: true, force: true });
|
|
361
|
+
}
|
|
362
|
+
});
|
|
325
363
|
|
|
326
|
-
|
|
327
|
-
|
|
364
|
+
it('问题3b:step1 不得因 includes 造成子串误配(docs/src/foo.tsx 不应被 src/foo.ts 覆盖)', async () => {
|
|
365
|
+
const dir = setupDir('legacy-step1-includes', tableWith('| foo | src/foo.ts | foo |'));
|
|
366
|
+
try {
|
|
367
|
+
expect(await capCheck.evaluate(makeEnv(dir, ['docs/src/foo.tsx']))).toBe(false);
|
|
368
|
+
} finally {
|
|
369
|
+
fs.rmSync(dir, { recursive: true, force: true });
|
|
370
|
+
}
|
|
328
371
|
});
|
|
329
372
|
|
|
330
|
-
it('
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
373
|
+
it('兼容:basename 条目仍可按路径边界后缀匹配(src/foo.ts 被 foo.ts 覆盖)', async () => {
|
|
374
|
+
const dir = setupDir('legacy-step1-suffix-ok', tableWith('| foo | foo.ts | foo |'));
|
|
375
|
+
try {
|
|
376
|
+
expect(await capCheck.evaluate(makeEnv(dir, ['src/foo.ts']))).toBe(true);
|
|
377
|
+
} finally {
|
|
378
|
+
fs.rmSync(dir, { recursive: true, force: true });
|
|
335
379
|
}
|
|
336
|
-
|
|
337
|
-
// 创建新的代码文件并 stage
|
|
338
|
-
const newCodeFile = path.join(tempDir, 'newfeature.ts');
|
|
339
|
-
fs.writeFileSync(newCodeFile, 'export function newfeature() {}');
|
|
340
|
-
execSync('git add ' + newCodeFile, { cwd: tempDir });
|
|
380
|
+
});
|
|
341
381
|
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
382
|
+
it('问题2:空表格 + 有 staged 变更时不得直接放行', async () => {
|
|
383
|
+
const dir = setupDir('legacy-empty-table-diff', EMPTY_TABLE);
|
|
384
|
+
try {
|
|
385
|
+
expect(await capCheck.evaluate(makeEnv(dir, ['src/foo.ts']))).toBe(false);
|
|
386
|
+
} finally {
|
|
387
|
+
fs.rmSync(dir, { recursive: true, force: true });
|
|
388
|
+
}
|
|
389
|
+
});
|
|
346
390
|
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
391
|
+
it('问题2:空表格 + 源码根有文件时 step2 不得直接放行', async () => {
|
|
392
|
+
const dir = setupDir('legacy-empty-table-scan', EMPTY_TABLE, ['src/foo.ts']);
|
|
393
|
+
try {
|
|
394
|
+
expect(await capCheck.evaluate(makeEnv(dir, [], { src: ['src/foo.ts'] }))).toBe(false);
|
|
395
|
+
} finally {
|
|
396
|
+
fs.rmSync(dir, { recursive: true, force: true });
|
|
397
|
+
}
|
|
398
|
+
});
|
|
399
|
+
|
|
400
|
+
it('问题2 兼容:清单格式(计数行)无文件表,仍直接放行', async () => {
|
|
401
|
+
const dir = setupDir(
|
|
402
|
+
'legacy-listing-format',
|
|
403
|
+
'# Harness Capabilities\n\n## CLI Commands (25)\ncheck, validate\n'
|
|
357
404
|
);
|
|
405
|
+
try {
|
|
406
|
+
expect(await capCheck.evaluate(makeEnv(dir, ['src/foo.ts']))).toBe(true);
|
|
407
|
+
} finally {
|
|
408
|
+
fs.rmSync(dir, { recursive: true, force: true });
|
|
409
|
+
}
|
|
410
|
+
});
|
|
358
411
|
|
|
359
|
-
|
|
360
|
-
|
|
412
|
+
it('问题4:检查异常默认放行时应输出 warn 而非静默吞错', async () => {
|
|
413
|
+
const dir = setupDir('legacy-failopen', tableWith('| foo | src/foo.ts | foo |'));
|
|
414
|
+
const warnSpy = jest.spyOn(console, 'warn').mockImplementation(() => {});
|
|
415
|
+
try {
|
|
416
|
+
const env: CheckEnv = {
|
|
417
|
+
...makeEnv(dir, []),
|
|
418
|
+
stagedDiffNames: async () => {
|
|
419
|
+
throw new Error('git boom');
|
|
420
|
+
},
|
|
421
|
+
};
|
|
422
|
+
// fail-open 语义保留:异常时仍放行
|
|
423
|
+
expect(await capCheck.evaluate(env)).toBe(true);
|
|
424
|
+
expect(warnSpy).toHaveBeenCalled();
|
|
425
|
+
} finally {
|
|
426
|
+
warnSpy.mockRestore();
|
|
427
|
+
fs.rmSync(dir, { recursive: true, force: true });
|
|
428
|
+
}
|
|
429
|
+
});
|
|
361
430
|
|
|
362
|
-
|
|
363
|
-
|
|
431
|
+
it('step2(file 模式)与 step1 语义一致:basename 条目可按路径边界后缀覆盖', async () => {
|
|
432
|
+
// 文档第二列写 basename foo.ts;step1 认可它(边界后缀),
|
|
433
|
+
// step2 裸精确匹配却永远不命中 srcScan 返回的 src/foo.ts → 永远红
|
|
434
|
+
const dir = setupDir('legacy-step2-basename', tableWith('| foo | foo.ts | foo |'), [
|
|
435
|
+
'src/foo.ts',
|
|
436
|
+
]);
|
|
437
|
+
try {
|
|
438
|
+
expect(await capCheck.evaluate(makeEnv(dir, [], { src: ['src/foo.ts'] }))).toBe(true);
|
|
439
|
+
} finally {
|
|
440
|
+
fs.rmSync(dir, { recursive: true, force: true });
|
|
441
|
+
}
|
|
442
|
+
});
|
|
443
|
+
|
|
444
|
+
it('step2(file 模式):不同路径的同后缀文件不得被误覆盖(lib/foo.ts 不覆盖 src/foo.ts)', async () => {
|
|
445
|
+
const dir = setupDir('legacy-step2-boundary', tableWith('| foo | lib/foo.ts | foo |'), [
|
|
446
|
+
'src/foo.ts',
|
|
447
|
+
]);
|
|
448
|
+
try {
|
|
449
|
+
expect(await capCheck.evaluate(makeEnv(dir, [], { src: ['src/foo.ts'] }))).toBe(false);
|
|
450
|
+
} finally {
|
|
451
|
+
fs.rmSync(dir, { recursive: true, force: true });
|
|
452
|
+
}
|
|
453
|
+
});
|
|
454
|
+
|
|
455
|
+
it('step2(module 模式)文件条目同样按路径边界后缀覆盖', async () => {
|
|
456
|
+
const dir = setupDir('legacy-step2-module-suffix', tableWith('| foo | foo.ts | foo |'), [
|
|
457
|
+
'src/foo.ts',
|
|
458
|
+
]);
|
|
459
|
+
fs.mkdirSync(path.join(dir, '.harness'), { recursive: true });
|
|
460
|
+
fs.writeFileSync(
|
|
461
|
+
path.join(dir, '.harness', 'config.yml'),
|
|
462
|
+
'governance:\n capabilities:\n mode: module\n'
|
|
463
|
+
);
|
|
464
|
+
try {
|
|
465
|
+
expect(await capCheck.evaluate(makeEnv(dir, [], { src: ['src/foo.ts'] }))).toBe(true);
|
|
466
|
+
} finally {
|
|
467
|
+
fs.rmSync(dir, { recursive: true, force: true });
|
|
468
|
+
}
|
|
364
469
|
});
|
|
365
470
|
});
|
|
366
471
|
|
|
367
472
|
describe('findApplicableConstraints', () => {
|
|
368
473
|
it('应该过滤出匹配 trigger 的约束', () => {
|
|
369
474
|
const context: ConstraintContext = {
|
|
370
|
-
operation: '
|
|
475
|
+
operation: 'code_implementation',
|
|
371
476
|
};
|
|
372
477
|
|
|
373
478
|
const result = checker.findApplicableConstraints(context);
|
|
374
479
|
|
|
375
480
|
expect(result.ironLaws.length).toBeGreaterThan(0);
|
|
376
481
|
expect(
|
|
377
|
-
result.ironLaws.some((c: any) => c.id === '
|
|
482
|
+
result.ironLaws.some((c: any) => c.id === 'no_completion_without_verification')
|
|
378
483
|
).toBe(true);
|
|
379
484
|
});
|
|
380
485
|
|
|
@@ -474,6 +579,7 @@ describe('ConstraintChecker - 补充覆盖', () => {
|
|
|
474
579
|
const result = await checker.check(
|
|
475
580
|
{
|
|
476
581
|
id: 'test_severity_iron',
|
|
582
|
+
kind: 'prompt',
|
|
477
583
|
level: 'iron_law',
|
|
478
584
|
rule: 'TEST',
|
|
479
585
|
message: 'test',
|
|
@@ -494,6 +600,7 @@ describe('ConstraintChecker - 补充覆盖', () => {
|
|
|
494
600
|
const result = await checker.check(
|
|
495
601
|
{
|
|
496
602
|
id: 'test_severity_guideline',
|
|
603
|
+
kind: 'prompt',
|
|
497
604
|
level: 'guideline',
|
|
498
605
|
rule: 'TEST',
|
|
499
606
|
message: 'test',
|
|
@@ -514,6 +621,7 @@ describe('ConstraintChecker - 补充覆盖', () => {
|
|
|
514
621
|
const result = await checker.check(
|
|
515
622
|
{
|
|
516
623
|
id: 'test_severity_tip',
|
|
624
|
+
kind: 'prompt',
|
|
517
625
|
level: 'tip',
|
|
518
626
|
rule: 'TEST',
|
|
519
627
|
message: 'test',
|
|
@@ -536,9 +644,10 @@ describe('ConstraintChecker - 补充覆盖', () => {
|
|
|
536
644
|
|
|
537
645
|
const result = await checker.check(
|
|
538
646
|
{
|
|
539
|
-
id: '
|
|
647
|
+
id: 'incremental_progress',
|
|
648
|
+
kind: 'check',
|
|
540
649
|
level: 'guideline',
|
|
541
|
-
rule: '
|
|
650
|
+
rule: 'ONE TASK PER SESSION',
|
|
542
651
|
message: 'test',
|
|
543
652
|
trigger: 'code_implementation',
|
|
544
653
|
enforcement: 'test',
|
|
@@ -560,9 +669,10 @@ describe('ConstraintChecker - 补充覆盖', () => {
|
|
|
560
669
|
|
|
561
670
|
const result = await checker.check(
|
|
562
671
|
{
|
|
563
|
-
id: '
|
|
672
|
+
id: 'incremental_progress',
|
|
673
|
+
kind: 'check',
|
|
564
674
|
level: 'guideline',
|
|
565
|
-
rule: '
|
|
675
|
+
rule: 'ONE TASK PER SESSION',
|
|
566
676
|
message: 'test',
|
|
567
677
|
trigger: 'code_implementation',
|
|
568
678
|
enforcement: 'test',
|
|
@@ -571,20 +681,23 @@ describe('ConstraintChecker - 补充覆盖', () => {
|
|
|
571
681
|
context
|
|
572
682
|
);
|
|
573
683
|
|
|
574
|
-
|
|
684
|
+
// hasSingleTask 未接线(undefined)→ skip(ADR-0001:flag 未接线不评估,不误报违规)
|
|
685
|
+
expect(result.skipped).toBe(true);
|
|
686
|
+
expect(result.satisfied).toBe(true);
|
|
575
687
|
});
|
|
576
688
|
|
|
577
689
|
it('iron_law 不应该检查例外条件', async () => {
|
|
578
690
|
const context: ConstraintContext = {
|
|
579
691
|
operation: 'code_implementation',
|
|
580
|
-
|
|
692
|
+
isSimpleTypo: true,
|
|
581
693
|
};
|
|
582
694
|
|
|
583
695
|
const result = await checker.check(
|
|
584
696
|
{
|
|
585
|
-
id: '
|
|
697
|
+
id: 'incremental_progress',
|
|
698
|
+
kind: 'check',
|
|
586
699
|
level: 'iron_law',
|
|
587
|
-
rule: '
|
|
700
|
+
rule: 'ONE TASK PER SESSION',
|
|
588
701
|
message: 'test',
|
|
589
702
|
trigger: 'code_implementation',
|
|
590
703
|
enforcement: 'test',
|
|
@@ -593,20 +706,23 @@ describe('ConstraintChecker - 补充覆盖', () => {
|
|
|
593
706
|
context
|
|
594
707
|
);
|
|
595
708
|
|
|
596
|
-
|
|
709
|
+
// iron_law 不适用例外;hasSingleTask 未接线(undefined)→ skip(ADR-0001)
|
|
710
|
+
expect(result.skipped).toBe(true);
|
|
711
|
+
expect(result.satisfied).toBe(true);
|
|
597
712
|
});
|
|
598
713
|
|
|
599
714
|
it('无 exceptions 字段应该正常检查', async () => {
|
|
600
715
|
const context: ConstraintContext = {
|
|
601
716
|
operation: 'code_implementation',
|
|
602
|
-
|
|
717
|
+
hasVerificationEvidence: true,
|
|
603
718
|
};
|
|
604
719
|
|
|
605
720
|
const result = await checker.check(
|
|
606
721
|
{
|
|
607
|
-
id: '
|
|
608
|
-
|
|
609
|
-
|
|
722
|
+
id: 'no_completion_without_verification',
|
|
723
|
+
kind: 'check',
|
|
724
|
+
level: 'iron_law',
|
|
725
|
+
rule: 'NO COMPLETION WITHOUT VERIFICATION',
|
|
610
726
|
message: 'test',
|
|
611
727
|
trigger: 'code_implementation',
|
|
612
728
|
enforcement: 'test',
|
|
@@ -633,6 +749,7 @@ describe('ConstraintChecker - 补充覆盖', () => {
|
|
|
633
749
|
const result = await checker.check(
|
|
634
750
|
{
|
|
635
751
|
id: 'no_bypass_checkpoint',
|
|
752
|
+
kind: 'check',
|
|
636
753
|
level: 'iron_law',
|
|
637
754
|
rule: 'NO BYPASS',
|
|
638
755
|
message: 'test',
|
|
@@ -662,6 +779,7 @@ describe('ConstraintChecker - 补充覆盖', () => {
|
|
|
662
779
|
const result = await checker.check(
|
|
663
780
|
{
|
|
664
781
|
id: 'no_bypass_checkpoint',
|
|
782
|
+
kind: 'check',
|
|
665
783
|
level: 'iron_law',
|
|
666
784
|
rule: 'NO BYPASS',
|
|
667
785
|
message: 'test',
|
|
@@ -678,120 +796,6 @@ describe('ConstraintChecker - 补充覆盖', () => {
|
|
|
678
796
|
});
|
|
679
797
|
});
|
|
680
798
|
|
|
681
|
-
describe('checkNoAnyType 文件检查', () => {
|
|
682
|
-
it('.ts 文件包含 : any 应该失败', async () => {
|
|
683
|
-
const anyFile = path.join(tempDir, 'any-test.ts');
|
|
684
|
-
fs.writeFileSync(anyFile, 'const x: any = {};');
|
|
685
|
-
|
|
686
|
-
const context: ConstraintContext = {
|
|
687
|
-
operation: 'code_implementation',
|
|
688
|
-
projectPath: tempDir,
|
|
689
|
-
changedFiles: [anyFile],
|
|
690
|
-
};
|
|
691
|
-
|
|
692
|
-
const result = await checker.check(
|
|
693
|
-
{
|
|
694
|
-
id: 'no_any_type',
|
|
695
|
-
level: 'guideline',
|
|
696
|
-
rule: 'NO ANY',
|
|
697
|
-
message: 'test',
|
|
698
|
-
trigger: 'code_implementation',
|
|
699
|
-
enforcement: 'test',
|
|
700
|
-
},
|
|
701
|
-
context
|
|
702
|
-
);
|
|
703
|
-
|
|
704
|
-
expect(result.satisfied).toBe(false);
|
|
705
|
-
|
|
706
|
-
fs.unlinkSync(anyFile);
|
|
707
|
-
});
|
|
708
|
-
|
|
709
|
-
it('.ts 文件注释中的 : any 应该被忽略', async () => {
|
|
710
|
-
const commentFile = path.join(tempDir, 'comment-any.ts');
|
|
711
|
-
fs.writeFileSync(commentFile, '// const x: any = {};\nconst y: string = "ok";');
|
|
712
|
-
|
|
713
|
-
const context: ConstraintContext = {
|
|
714
|
-
operation: 'code_implementation',
|
|
715
|
-
projectPath: tempDir,
|
|
716
|
-
changedFiles: [commentFile],
|
|
717
|
-
};
|
|
718
|
-
|
|
719
|
-
const result = await checker.check(
|
|
720
|
-
{
|
|
721
|
-
id: 'no_any_type',
|
|
722
|
-
level: 'guideline',
|
|
723
|
-
rule: 'NO ANY',
|
|
724
|
-
message: 'test',
|
|
725
|
-
trigger: 'code_implementation',
|
|
726
|
-
enforcement: 'test',
|
|
727
|
-
},
|
|
728
|
-
context
|
|
729
|
-
);
|
|
730
|
-
|
|
731
|
-
expect(result.satisfied).toBe(true);
|
|
732
|
-
|
|
733
|
-
fs.unlinkSync(commentFile);
|
|
734
|
-
});
|
|
735
|
-
|
|
736
|
-
it('非 .ts 文件应该跳过检查', async () => {
|
|
737
|
-
const jsFile = path.join(tempDir, 'any-test.js');
|
|
738
|
-
fs.writeFileSync(jsFile, 'const x = {};');
|
|
739
|
-
|
|
740
|
-
const context: ConstraintContext = {
|
|
741
|
-
operation: 'code_implementation',
|
|
742
|
-
projectPath: tempDir,
|
|
743
|
-
changedFiles: [jsFile],
|
|
744
|
-
};
|
|
745
|
-
|
|
746
|
-
const result = await checker.check(
|
|
747
|
-
{
|
|
748
|
-
id: 'no_any_type',
|
|
749
|
-
level: 'guideline',
|
|
750
|
-
rule: 'NO ANY',
|
|
751
|
-
message: 'test',
|
|
752
|
-
trigger: 'code_implementation',
|
|
753
|
-
enforcement: 'test',
|
|
754
|
-
},
|
|
755
|
-
context
|
|
756
|
-
);
|
|
757
|
-
|
|
758
|
-
expect(result.satisfied).toBe(true);
|
|
759
|
-
|
|
760
|
-
fs.unlinkSync(jsFile);
|
|
761
|
-
});
|
|
762
|
-
});
|
|
763
|
-
|
|
764
|
-
describe('checkTestCoverage coverage-final.json', () => {
|
|
765
|
-
it('只有 coverage-final.json 应该通过', async () => {
|
|
766
|
-
const coverageDir = path.join(tempDir, 'coverage');
|
|
767
|
-
fs.mkdirSync(coverageDir, { recursive: true });
|
|
768
|
-
|
|
769
|
-
const finalPath = path.join(coverageDir, 'coverage-final.json');
|
|
770
|
-
fs.writeFileSync(finalPath, JSON.stringify({}));
|
|
771
|
-
|
|
772
|
-
const context: ConstraintContext = {
|
|
773
|
-
operation: 'commit',
|
|
774
|
-
projectPath: tempDir,
|
|
775
|
-
};
|
|
776
|
-
|
|
777
|
-
const result = await checker.check(
|
|
778
|
-
{
|
|
779
|
-
id: 'test_coverage_required',
|
|
780
|
-
level: 'guideline',
|
|
781
|
-
rule: 'COVERAGE',
|
|
782
|
-
message: 'test',
|
|
783
|
-
trigger: 'commit',
|
|
784
|
-
enforcement: 'test',
|
|
785
|
-
},
|
|
786
|
-
context
|
|
787
|
-
);
|
|
788
|
-
|
|
789
|
-
expect(result.satisfied).toBe(true);
|
|
790
|
-
|
|
791
|
-
fs.rmSync(coverageDir, { recursive: true, force: true });
|
|
792
|
-
});
|
|
793
|
-
});
|
|
794
|
-
|
|
795
799
|
describe('checkConstraint 快捷函数', () => {
|
|
796
800
|
it('未知约束应该返回不满足', async () => {
|
|
797
801
|
const { checkConstraint } = await import('../core/constraints/checker');
|
|
@@ -810,11 +814,11 @@ describe('ConstraintChecker - 补充覆盖', () => {
|
|
|
810
814
|
|
|
811
815
|
const context: ConstraintContext = {
|
|
812
816
|
operation: 'code_implementation',
|
|
813
|
-
|
|
817
|
+
hasVerificationEvidence: true,
|
|
814
818
|
};
|
|
815
819
|
|
|
816
|
-
const result = await checkConstraint('
|
|
817
|
-
expect(result.id).toBe('
|
|
820
|
+
const result = await checkConstraint('no_completion_without_verification', context);
|
|
821
|
+
expect(result.id).toBe('no_completion_without_verification');
|
|
818
822
|
expect(result.satisfied).toBe(true);
|
|
819
823
|
});
|
|
820
824
|
});
|
|
@@ -845,6 +849,7 @@ describe('ConstraintChecker - 补充覆盖', () => {
|
|
|
845
849
|
const result = await checker.check(
|
|
846
850
|
{
|
|
847
851
|
id: 'no_test_simplification',
|
|
852
|
+
kind: 'check',
|
|
848
853
|
level: 'iron_law',
|
|
849
854
|
rule: 'NO SIMPLIFY',
|
|
850
855
|
message: 'test',
|
|
@@ -874,6 +879,7 @@ describe('ConstraintChecker - 补充覆盖', () => {
|
|
|
874
879
|
const result = await checker.check(
|
|
875
880
|
{
|
|
876
881
|
id: 'context_doc_sync',
|
|
882
|
+
kind: 'check',
|
|
877
883
|
level: 'guideline',
|
|
878
884
|
rule: 'CONTEXT DOC SYNC',
|
|
879
885
|
message: 'test',
|
|
@@ -918,6 +924,7 @@ describe('ConstraintChecker - 补充覆盖', () => {
|
|
|
918
924
|
const result = await checker.check(
|
|
919
925
|
{
|
|
920
926
|
id: 'context_doc_sync',
|
|
927
|
+
kind: 'check',
|
|
921
928
|
level: 'guideline',
|
|
922
929
|
rule: 'CONTEXT DOC SYNC',
|
|
923
930
|
message: 'test',
|
|
@@ -959,6 +966,7 @@ describe('ConstraintChecker - 补充覆盖', () => {
|
|
|
959
966
|
const result = await checker.check(
|
|
960
967
|
{
|
|
961
968
|
id: 'context_doc_sync',
|
|
969
|
+
kind: 'check',
|
|
962
970
|
level: 'guideline',
|
|
963
971
|
rule: 'CONTEXT DOC SYNC',
|
|
964
972
|
message: 'test',
|
|
@@ -997,6 +1005,7 @@ describe('ConstraintChecker - 补充覆盖', () => {
|
|
|
997
1005
|
const result = await checker.check(
|
|
998
1006
|
{
|
|
999
1007
|
id: 'context_doc_sync',
|
|
1008
|
+
kind: 'check',
|
|
1000
1009
|
level: 'guideline',
|
|
1001
1010
|
rule: 'CONTEXT DOC SYNC',
|
|
1002
1011
|
message: 'test',
|
|
@@ -1025,6 +1034,7 @@ describe('ConstraintChecker - 补充覆盖', () => {
|
|
|
1025
1034
|
const result = await checker.check(
|
|
1026
1035
|
{
|
|
1027
1036
|
id: 'docs_freshness',
|
|
1037
|
+
kind: 'check',
|
|
1028
1038
|
level: 'guideline',
|
|
1029
1039
|
rule: 'DOCS FRESHNESS',
|
|
1030
1040
|
message: 'test',
|
|
@@ -1052,6 +1062,7 @@ describe('ConstraintChecker - 补充覆盖', () => {
|
|
|
1052
1062
|
const result = await checker.check(
|
|
1053
1063
|
{
|
|
1054
1064
|
id: 'docs_freshness',
|
|
1065
|
+
kind: 'check',
|
|
1055
1066
|
level: 'guideline',
|
|
1056
1067
|
rule: 'DOCS FRESHNESS',
|
|
1057
1068
|
message: 'test',
|
|
@@ -1088,6 +1099,7 @@ describe('ConstraintChecker - 补充覆盖', () => {
|
|
|
1088
1099
|
const result = await checker.check(
|
|
1089
1100
|
{
|
|
1090
1101
|
id: 'docs_freshness',
|
|
1102
|
+
kind: 'check',
|
|
1091
1103
|
level: 'guideline',
|
|
1092
1104
|
rule: 'DOCS FRESHNESS',
|
|
1093
1105
|
message: 'test',
|
|
@@ -1125,6 +1137,7 @@ describe('ConstraintChecker - 补充覆盖', () => {
|
|
|
1125
1137
|
const result = await checker.check(
|
|
1126
1138
|
{
|
|
1127
1139
|
id: 'docs_freshness',
|
|
1140
|
+
kind: 'check',
|
|
1128
1141
|
level: 'guideline',
|
|
1129
1142
|
rule: 'DOCS FRESHNESS',
|
|
1130
1143
|
message: 'test',
|
|
@@ -1161,6 +1174,7 @@ describe('ConstraintChecker - 补充覆盖', () => {
|
|
|
1161
1174
|
const result = await checker.check(
|
|
1162
1175
|
{
|
|
1163
1176
|
id: 'docs_freshness',
|
|
1177
|
+
kind: 'check',
|
|
1164
1178
|
level: 'guideline',
|
|
1165
1179
|
rule: 'DOCS FRESHNESS',
|
|
1166
1180
|
message: 'test',
|
|
@@ -1194,6 +1208,7 @@ describe('ConstraintChecker - 补充覆盖', () => {
|
|
|
1194
1208
|
const result = await checker.check(
|
|
1195
1209
|
{
|
|
1196
1210
|
id: 'docs_freshness',
|
|
1211
|
+
kind: 'check',
|
|
1197
1212
|
level: 'guideline',
|
|
1198
1213
|
rule: 'DOCS FRESHNESS',
|
|
1199
1214
|
message: 'test',
|
|
@@ -1226,6 +1241,7 @@ describe('ConstraintChecker - 补充覆盖', () => {
|
|
|
1226
1241
|
const result = await checker.check(
|
|
1227
1242
|
{
|
|
1228
1243
|
id: 'docs_freshness',
|
|
1244
|
+
kind: 'check',
|
|
1229
1245
|
level: 'guideline',
|
|
1230
1246
|
rule: 'DOCS FRESHNESS',
|
|
1231
1247
|
message: 'test',
|
|
@@ -1261,6 +1277,7 @@ describe('ConstraintChecker - 补充覆盖', () => {
|
|
|
1261
1277
|
const result = await checker.check(
|
|
1262
1278
|
{
|
|
1263
1279
|
id: 'docs_freshness',
|
|
1280
|
+
kind: 'check',
|
|
1264
1281
|
level: 'guideline',
|
|
1265
1282
|
rule: 'DOCS FRESHNESS',
|
|
1266
1283
|
message: 'test',
|
|
@@ -1293,6 +1310,7 @@ describe('ConstraintChecker - 补充覆盖', () => {
|
|
|
1293
1310
|
const result = await checker.check(
|
|
1294
1311
|
{
|
|
1295
1312
|
id: 'docs_freshness',
|
|
1313
|
+
kind: 'check',
|
|
1296
1314
|
level: 'guideline',
|
|
1297
1315
|
rule: 'DOCS FRESHNESS',
|
|
1298
1316
|
message: 'test',
|
|
@@ -1325,6 +1343,7 @@ describe('ConstraintChecker - 补充覆盖', () => {
|
|
|
1325
1343
|
const result = await checker.check(
|
|
1326
1344
|
{
|
|
1327
1345
|
id: 'docs_freshness',
|
|
1346
|
+
kind: 'check',
|
|
1328
1347
|
level: 'guideline',
|
|
1329
1348
|
rule: 'DOCS FRESHNESS',
|
|
1330
1349
|
message: 'test',
|
|
@@ -1351,6 +1370,7 @@ describe('ConstraintChecker - 补充覆盖', () => {
|
|
|
1351
1370
|
const result = await checker.check(
|
|
1352
1371
|
{
|
|
1353
1372
|
id: 'docs_freshness',
|
|
1373
|
+
kind: 'check',
|
|
1354
1374
|
level: 'guideline',
|
|
1355
1375
|
rule: 'DOCS FRESHNESS',
|
|
1356
1376
|
message: 'test',
|
|
@@ -1419,6 +1439,7 @@ describe('ConstraintChecker - 补充覆盖', () => {
|
|
|
1419
1439
|
ironLaws: {
|
|
1420
1440
|
test_only: {
|
|
1421
1441
|
id: 'test_only',
|
|
1442
|
+
kind: 'prompt' as const,
|
|
1422
1443
|
level: 'iron_law' as const,
|
|
1423
1444
|
rule: 'TEST',
|
|
1424
1445
|
message: 'test',
|
|
@@ -1452,6 +1473,7 @@ describe('ConstraintChecker - 补充覆盖', () => {
|
|
|
1452
1473
|
ironLaws: {
|
|
1453
1474
|
rule_a: {
|
|
1454
1475
|
id: 'rule_a',
|
|
1476
|
+
kind: 'prompt' as const,
|
|
1455
1477
|
level: 'iron_law' as const,
|
|
1456
1478
|
rule: 'A',
|
|
1457
1479
|
message: 'project A',
|
|
@@ -1469,6 +1491,7 @@ describe('ConstraintChecker - 补充覆盖', () => {
|
|
|
1469
1491
|
ironLaws: {
|
|
1470
1492
|
rule_b: {
|
|
1471
1493
|
id: 'rule_b',
|
|
1494
|
+
kind: 'prompt' as const,
|
|
1472
1495
|
level: 'iron_law' as const,
|
|
1473
1496
|
rule: 'B',
|
|
1474
1497
|
message: 'project B',
|
|
@@ -1518,7 +1541,7 @@ describe('ConstraintChecker - 补充覆盖', () => {
|
|
|
1518
1541
|
const defaultKeys = Object.keys(defaultConstraints.ironLaws);
|
|
1519
1542
|
|
|
1520
1543
|
const customConfig = {
|
|
1521
|
-
ironLaws: { compat_test: { id: 'compat_test', level: 'iron_law' as const, rule: 'C', message: 'compat', trigger: 'file_modification', enforcement: 'test' } },
|
|
1544
|
+
ironLaws: { compat_test: { id: 'compat_test', kind: 'prompt' as const, level: 'iron_law' as const, rule: 'C', message: 'compat', trigger: 'file_modification', enforcement: 'test' } },
|
|
1522
1545
|
guidelines: {},
|
|
1523
1546
|
tips: {},
|
|
1524
1547
|
disabled: [] as string[],
|
|
@@ -1542,6 +1565,7 @@ describe('ConstraintChecker - 补充覆盖', () => {
|
|
|
1542
1565
|
ironLaws: {
|
|
1543
1566
|
custom_rule: {
|
|
1544
1567
|
id: 'custom_rule',
|
|
1568
|
+
kind: 'prompt' as const,
|
|
1545
1569
|
level: 'iron_law' as const,
|
|
1546
1570
|
rule: 'CUSTOM',
|
|
1547
1571
|
message: 'custom',
|
|
@@ -1580,6 +1604,7 @@ describe('ConstraintChecker - 补充覆盖', () => {
|
|
|
1580
1604
|
const result = await checker.check(
|
|
1581
1605
|
{
|
|
1582
1606
|
id: 'docs_freshness',
|
|
1607
|
+
kind: 'check',
|
|
1583
1608
|
level: 'guideline',
|
|
1584
1609
|
rule: 'DOCS FRESHNESS',
|
|
1585
1610
|
message: 'test',
|