@dommaker/harness 0.16.9 → 0.17.1
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 +39 -0
- package/README.md +33 -32
- package/bin/harness.js +33 -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 +5 -1
- package/dist/cli/commands/sync-docs/capabilities-syncer.d.ts.map +1 -1
- package/dist/cli/commands/sync-docs/capabilities-syncer.js +2 -10
- package/dist/cli/commands/sync-docs/capabilities-syncer.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 +7 -0
- package/dist/core/constraints/capabilities-parser.d.ts.map +1 -1
- package/dist/core/constraints/capabilities-parser.js +13 -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 +9 -2
- package/dist/core/constraints/checkers/capability-sync.d.ts.map +1 -1
- package/dist/core/constraints/checkers/capability-sync.js +55 -22
- 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 +29 -572
- 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 +17 -2
- package/dist/core/project-config-loader.d.ts.map +1 -1
- package/dist/core/project-config-loader.js +55 -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 +26 -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 +228 -333
- 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 +41 -4
- 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/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 +5 -7
- 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 +13 -0
- package/src/core/constraints/checker.ts +73 -28
- package/src/core/constraints/checkers/capability-sync.ts +72 -29
- 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 +29 -597
- 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 +59 -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 +30 -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,8 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* checker.ts 测试
|
|
3
|
+
*
|
|
4
|
+
* ADR-0001:只覆盖存活 check 约束的 checker 行为;
|
|
5
|
+
* prompt 类约束的短路语义见 'Prompt constraints' 一节;
|
|
6
|
+
* 已退役/被吸收约束的用例随之移除。
|
|
3
7
|
*/
|
|
4
8
|
|
|
5
|
-
import { ConstraintChecker,
|
|
9
|
+
import { ConstraintChecker, checkConstraint } from '../core/constraints/checker';
|
|
10
|
+
import { PROMPTS } from '../core/constraints/definitions';
|
|
6
11
|
import type { ConstraintContext } from '../types/constraint';
|
|
7
12
|
import { writeFileSync, mkdirSync, rmSync } from 'fs';
|
|
8
13
|
import { join } from 'path';
|
|
@@ -37,7 +42,7 @@ describe('ConstraintChecker', () => {
|
|
|
37
42
|
};
|
|
38
43
|
|
|
39
44
|
const result = await checker.check(
|
|
40
|
-
{ id: 'no_bypass_checkpoint', level: '
|
|
45
|
+
{ id: 'no_bypass_checkpoint', kind: 'check', level: 'guideline', rule: 'NO BYPASS', message: 'test', trigger: 'code_implementation', enforcement: 'test' },
|
|
41
46
|
context
|
|
42
47
|
);
|
|
43
48
|
|
|
@@ -54,38 +59,13 @@ describe('ConstraintChecker', () => {
|
|
|
54
59
|
};
|
|
55
60
|
|
|
56
61
|
const result = await checker.check(
|
|
57
|
-
{ id: 'no_bypass_checkpoint', level: '
|
|
62
|
+
{ id: 'no_bypass_checkpoint', kind: 'check', level: 'guideline', rule: 'NO BYPASS', message: 'test', trigger: 'code_implementation', enforcement: 'test' },
|
|
58
63
|
context
|
|
59
64
|
);
|
|
60
65
|
|
|
61
66
|
expect(result.satisfied).toBe(true);
|
|
62
67
|
});
|
|
63
68
|
|
|
64
|
-
it('should check no_self_approval with test evidence', async () => {
|
|
65
|
-
const contextWithTest: ConstraintContext = {
|
|
66
|
-
operation: 'code_implementation',
|
|
67
|
-
hasTest: true,
|
|
68
|
-
};
|
|
69
|
-
|
|
70
|
-
const contextWithoutTest: ConstraintContext = {
|
|
71
|
-
operation: 'code_implementation',
|
|
72
|
-
hasTest: false,
|
|
73
|
-
};
|
|
74
|
-
|
|
75
|
-
const resultWithTest = await checker.check(
|
|
76
|
-
{ id: 'no_self_approval', level: 'iron_law', rule: 'NO SELF APPROVAL', message: 'test', trigger: 'code_implementation', enforcement: 'test' },
|
|
77
|
-
contextWithTest
|
|
78
|
-
);
|
|
79
|
-
|
|
80
|
-
const resultWithoutTest = await checker.check(
|
|
81
|
-
{ id: 'no_self_approval', level: 'iron_law', rule: 'NO SELF APPROVAL', message: 'test', trigger: 'code_implementation', enforcement: 'test' },
|
|
82
|
-
contextWithoutTest
|
|
83
|
-
);
|
|
84
|
-
|
|
85
|
-
expect(resultWithTest.satisfied).toBe(true);
|
|
86
|
-
expect(resultWithoutTest.satisfied).toBe(false);
|
|
87
|
-
});
|
|
88
|
-
|
|
89
69
|
it('should check no_completion_without_verification', async () => {
|
|
90
70
|
const contextWithEvidence: ConstraintContext = {
|
|
91
71
|
operation: 'code_implementation',
|
|
@@ -98,158 +78,19 @@ describe('ConstraintChecker', () => {
|
|
|
98
78
|
};
|
|
99
79
|
|
|
100
80
|
const resultWithEvidence = await checker.check(
|
|
101
|
-
{ id: 'no_completion_without_verification', level: 'iron_law', rule: 'NO COMPLETION', message: 'test', trigger: 'code_implementation', enforcement: 'test' },
|
|
81
|
+
{ id: 'no_completion_without_verification', kind: 'check', level: 'iron_law', rule: 'NO COMPLETION', message: 'test', trigger: 'code_implementation', enforcement: 'test' },
|
|
102
82
|
contextWithEvidence
|
|
103
83
|
);
|
|
104
84
|
|
|
105
85
|
const resultWithoutEvidence = await checker.check(
|
|
106
|
-
{ id: 'no_completion_without_verification', level: 'iron_law', rule: 'NO COMPLETION', message: 'test', trigger: 'code_implementation', enforcement: 'test' },
|
|
86
|
+
{ id: 'no_completion_without_verification', kind: 'check', level: 'iron_law', rule: 'NO COMPLETION', message: 'test', trigger: 'code_implementation', enforcement: 'test' },
|
|
107
87
|
contextWithoutEvidence
|
|
108
88
|
);
|
|
109
89
|
|
|
110
90
|
expect(resultWithEvidence.satisfied).toBe(true);
|
|
111
91
|
expect(resultWithoutEvidence.satisfied).toBe(false);
|
|
112
92
|
});
|
|
113
|
-
});
|
|
114
|
-
|
|
115
|
-
describe('Guidelines', () => {
|
|
116
|
-
it('should check no_any_type with any in file', async () => {
|
|
117
|
-
const anyFile = join(tempDir, 'any-test.ts');
|
|
118
|
-
writeFileSync(anyFile, 'const x: any = "test";');
|
|
119
|
-
|
|
120
|
-
const context: ConstraintContext = {
|
|
121
|
-
operation: 'code_implementation',
|
|
122
|
-
changedFiles: [anyFile],
|
|
123
|
-
};
|
|
124
|
-
|
|
125
|
-
const result = await checker.check(
|
|
126
|
-
{ id: 'no_any_type', level: 'guideline', rule: 'NO ANY', message: 'test', trigger: 'code_implementation', enforcement: 'test' },
|
|
127
|
-
context
|
|
128
|
-
);
|
|
129
|
-
|
|
130
|
-
expect(result.satisfied).toBe(false);
|
|
131
|
-
});
|
|
132
|
-
|
|
133
|
-
it('should pass no_any_type without any type', async () => {
|
|
134
|
-
const safeFile = join(tempDir, 'safe-test.ts');
|
|
135
|
-
writeFileSync(safeFile, 'const x: string = "test";');
|
|
136
|
-
|
|
137
|
-
const context: ConstraintContext = {
|
|
138
|
-
operation: 'code_implementation',
|
|
139
|
-
changedFiles: [safeFile],
|
|
140
|
-
};
|
|
141
|
-
|
|
142
|
-
const result = await checker.check(
|
|
143
|
-
{ id: 'no_any_type', level: 'guideline', rule: 'NO ANY', message: 'test', trigger: 'code_implementation', enforcement: 'test' },
|
|
144
|
-
context
|
|
145
|
-
);
|
|
146
|
-
|
|
147
|
-
expect(result.satisfied).toBe(true);
|
|
148
|
-
});
|
|
149
|
-
|
|
150
|
-
it('should check capability_sync without CAPABILITIES.md', async () => {
|
|
151
|
-
// 注意:tempDir 在 harness 仓库内,如果有缓存的变更,会检查到代码变更
|
|
152
|
-
// 所以需要创建一个无代码变更的场景或创建 CAPABILITIES.md
|
|
153
|
-
const context: ConstraintContext = {
|
|
154
|
-
operation: 'commit',
|
|
155
|
-
projectPath: tempDir,
|
|
156
|
-
};
|
|
157
|
-
|
|
158
|
-
// 创建 CAPABILITIES.md 文件确保测试通过
|
|
159
|
-
const fs = require('fs');
|
|
160
|
-
const path = require('path');
|
|
161
|
-
const capabilitiesPath = path.join(tempDir, 'CAPABILITIES.md');
|
|
162
|
-
fs.writeFileSync(capabilitiesPath, '# Capabilities\n');
|
|
163
|
-
|
|
164
|
-
const result = await checker.check(
|
|
165
|
-
{ id: 'capability_sync', level: 'guideline', rule: 'CAPABILITY SYNC', message: 'test', trigger: 'commit', enforcement: 'test' },
|
|
166
|
-
context
|
|
167
|
-
);
|
|
168
|
-
|
|
169
|
-
// 有 CAPABILITIES.md 文件,应该通过
|
|
170
|
-
expect(result.satisfied).toBe(true);
|
|
171
|
-
|
|
172
|
-
// 清理
|
|
173
|
-
fs.unlinkSync(capabilitiesPath);
|
|
174
|
-
});
|
|
175
|
-
|
|
176
|
-
it('should check no_fix_without_root_cause', async () => {
|
|
177
|
-
const contextWithInvestigation: ConstraintContext = {
|
|
178
|
-
operation: 'code_implementation',
|
|
179
|
-
hasRootCauseInvestigation: true,
|
|
180
|
-
};
|
|
181
|
-
|
|
182
|
-
const contextWithoutInvestigation: ConstraintContext = {
|
|
183
|
-
operation: 'code_implementation',
|
|
184
|
-
hasRootCauseInvestigation: false,
|
|
185
|
-
};
|
|
186
|
-
|
|
187
|
-
const resultWith = await checker.check(
|
|
188
|
-
{ id: 'no_fix_without_root_cause', level: 'guideline', rule: 'NO FIX', message: 'test', trigger: 'code_implementation', enforcement: 'test' },
|
|
189
|
-
contextWithInvestigation
|
|
190
|
-
);
|
|
191
|
-
|
|
192
|
-
const resultWithout = await checker.check(
|
|
193
|
-
{ id: 'no_fix_without_root_cause', level: 'guideline', rule: 'NO FIX', message: 'test', trigger: 'code_implementation', enforcement: 'test' },
|
|
194
|
-
contextWithoutInvestigation
|
|
195
|
-
);
|
|
196
|
-
|
|
197
|
-
expect(resultWith.satisfied).toBe(true);
|
|
198
|
-
expect(resultWithout.satisfied).toBe(false);
|
|
199
|
-
});
|
|
200
|
-
|
|
201
|
-
it('should check no_code_without_test', async () => {
|
|
202
|
-
const contextWithFailingTest: ConstraintContext = {
|
|
203
|
-
operation: 'code_implementation',
|
|
204
|
-
hasFailingTest: true,
|
|
205
|
-
};
|
|
206
|
-
|
|
207
|
-
const contextWithoutTest: ConstraintContext = {
|
|
208
|
-
operation: 'code_implementation',
|
|
209
|
-
hasFailingTest: false,
|
|
210
|
-
};
|
|
211
|
-
|
|
212
|
-
const resultWith = await checker.check(
|
|
213
|
-
{ id: 'no_code_without_test', level: 'guideline', rule: 'NO CODE', message: 'test', trigger: 'code_implementation', enforcement: 'test' },
|
|
214
|
-
contextWithFailingTest
|
|
215
|
-
);
|
|
216
|
-
|
|
217
|
-
const resultWithout = await checker.check(
|
|
218
|
-
{ id: 'no_code_without_test', level: 'guideline', rule: 'NO CODE', message: 'test', trigger: 'code_implementation', enforcement: 'test' },
|
|
219
|
-
contextWithoutTest
|
|
220
|
-
);
|
|
221
|
-
|
|
222
|
-
expect(resultWith.satisfied).toBe(true);
|
|
223
|
-
expect(resultWithout.satisfied).toBe(false);
|
|
224
|
-
});
|
|
225
|
-
|
|
226
|
-
it('should check reuse-first guidelines', async () => {
|
|
227
|
-
const contextWithReuseCheck: ConstraintContext = {
|
|
228
|
-
operation: 'code_implementation',
|
|
229
|
-
hasReuseCheck: true,
|
|
230
|
-
};
|
|
231
|
-
|
|
232
|
-
const contextWithoutReuseCheck: ConstraintContext = {
|
|
233
|
-
operation: 'code_implementation',
|
|
234
|
-
hasReuseCheck: false,
|
|
235
|
-
};
|
|
236
|
-
|
|
237
|
-
const resultWith = await checker.check(
|
|
238
|
-
{ id: 'no_creation_without_reuse_check', level: 'guideline', rule: 'REUSE FIRST', message: 'test', trigger: 'code_implementation', enforcement: 'test' },
|
|
239
|
-
contextWithReuseCheck
|
|
240
|
-
);
|
|
241
|
-
|
|
242
|
-
const resultWithout = await checker.check(
|
|
243
|
-
{ id: 'no_creation_without_reuse_check', level: 'guideline', rule: 'REUSE FIRST', message: 'test', trigger: 'code_implementation', enforcement: 'test' },
|
|
244
|
-
contextWithoutReuseCheck
|
|
245
|
-
);
|
|
246
|
-
|
|
247
|
-
expect(resultWith.satisfied).toBe(true);
|
|
248
|
-
expect(resultWithout.satisfied).toBe(false);
|
|
249
|
-
});
|
|
250
|
-
});
|
|
251
93
|
|
|
252
|
-
describe('New Iron Laws', () => {
|
|
253
94
|
it('should check incremental_progress', async () => {
|
|
254
95
|
const contextWithSingleTask: ConstraintContext = {
|
|
255
96
|
operation: 'code_implementation',
|
|
@@ -262,12 +103,12 @@ describe('ConstraintChecker', () => {
|
|
|
262
103
|
};
|
|
263
104
|
|
|
264
105
|
const resultWith = await checker.check(
|
|
265
|
-
{ id: 'incremental_progress', level: 'iron_law', rule: 'ONE TASK', message: 'test', trigger: 'code_implementation', enforcement: 'test' },
|
|
106
|
+
{ id: 'incremental_progress', kind: 'check', level: 'iron_law', rule: 'ONE TASK', message: 'test', trigger: 'code_implementation', enforcement: 'test' },
|
|
266
107
|
contextWithSingleTask
|
|
267
108
|
);
|
|
268
109
|
|
|
269
110
|
const resultWithout = await checker.check(
|
|
270
|
-
{ id: 'incremental_progress', level: 'iron_law', rule: 'ONE TASK', message: 'test', trigger: 'code_implementation', enforcement: 'test' },
|
|
111
|
+
{ id: 'incremental_progress', kind: 'check', level: 'iron_law', rule: 'ONE TASK', message: 'test', trigger: 'code_implementation', enforcement: 'test' },
|
|
271
112
|
contextWithMultipleTasks
|
|
272
113
|
);
|
|
273
114
|
|
|
@@ -275,67 +116,71 @@ describe('ConstraintChecker', () => {
|
|
|
275
116
|
expect(resultWithout.satisfied).toBe(false);
|
|
276
117
|
});
|
|
277
118
|
|
|
278
|
-
it('should check
|
|
279
|
-
const
|
|
280
|
-
operation: '
|
|
281
|
-
|
|
119
|
+
it('should check no_implementation_without_requirement', async () => {
|
|
120
|
+
const contextWithRequirement: ConstraintContext = {
|
|
121
|
+
operation: 'code_implementation',
|
|
122
|
+
hasRequirement: true,
|
|
282
123
|
};
|
|
283
124
|
|
|
284
|
-
const
|
|
285
|
-
operation: '
|
|
286
|
-
|
|
125
|
+
const contextWithoutRequirement: ConstraintContext = {
|
|
126
|
+
operation: 'code_implementation',
|
|
127
|
+
hasRequirement: false,
|
|
287
128
|
};
|
|
288
129
|
|
|
289
|
-
const
|
|
290
|
-
{ id: '
|
|
291
|
-
|
|
130
|
+
const resultWith = await checker.check(
|
|
131
|
+
{ id: 'no_implementation_without_requirement', kind: 'check', level: 'iron_law', rule: 'REQ EXISTS', message: 'test', trigger: 'code_implementation', enforcement: 'test' },
|
|
132
|
+
contextWithRequirement
|
|
292
133
|
);
|
|
293
134
|
|
|
294
|
-
const
|
|
295
|
-
{ id: '
|
|
296
|
-
|
|
135
|
+
const resultWithout = await checker.check(
|
|
136
|
+
{ id: 'no_implementation_without_requirement', kind: 'check', level: 'iron_law', rule: 'REQ EXISTS', message: 'test', trigger: 'code_implementation', enforcement: 'test' },
|
|
137
|
+
contextWithoutRequirement
|
|
297
138
|
);
|
|
298
139
|
|
|
299
|
-
expect(
|
|
300
|
-
expect(
|
|
140
|
+
expect(resultWith.satisfied).toBe(true);
|
|
141
|
+
expect(resultWithout.satisfied).toBe(false);
|
|
301
142
|
});
|
|
302
143
|
});
|
|
303
144
|
|
|
304
|
-
describe('
|
|
305
|
-
it('should
|
|
145
|
+
describe('Guidelines', () => {
|
|
146
|
+
it('should check capability_sync without CAPABILITIES.md', async () => {
|
|
147
|
+
// 注意:tempDir 在 harness 仓库内,如果有缓存的变更,会检查到代码变更
|
|
148
|
+
// 所以需要创建一个无代码变更的场景或创建 CAPABILITIES.md
|
|
306
149
|
const context: ConstraintContext = {
|
|
307
|
-
operation: '
|
|
308
|
-
|
|
309
|
-
isSimpleTypo: true,
|
|
150
|
+
operation: 'commit',
|
|
151
|
+
projectPath: tempDir,
|
|
310
152
|
};
|
|
311
153
|
|
|
154
|
+
// 创建 CAPABILITIES.md 文件确保测试通过
|
|
155
|
+
const fs = require('fs');
|
|
156
|
+
const path = require('path');
|
|
157
|
+
const capabilitiesPath = path.join(tempDir, 'CAPABILITIES.md');
|
|
158
|
+
fs.writeFileSync(capabilitiesPath, '# Capabilities\n');
|
|
159
|
+
|
|
312
160
|
const result = await checker.check(
|
|
313
|
-
{
|
|
314
|
-
id: 'no_fix_without_root_cause',
|
|
315
|
-
level: 'guideline',
|
|
316
|
-
rule: 'NO FIX',
|
|
317
|
-
message: 'test',
|
|
318
|
-
trigger: 'code_implementation',
|
|
319
|
-
enforcement: 'test',
|
|
320
|
-
exceptions: ['simple_typo'],
|
|
321
|
-
},
|
|
161
|
+
{ id: 'capability_sync', kind: 'check', level: 'guideline', rule: 'CAPABILITY SYNC', message: 'test', trigger: 'commit', enforcement: 'test' },
|
|
322
162
|
context
|
|
323
163
|
);
|
|
324
164
|
|
|
165
|
+
// 有 CAPABILITIES.md 文件,应该通过
|
|
325
166
|
expect(result.satisfied).toBe(true);
|
|
326
|
-
|
|
167
|
+
|
|
168
|
+
// 清理
|
|
169
|
+
fs.unlinkSync(capabilitiesPath);
|
|
327
170
|
});
|
|
171
|
+
});
|
|
328
172
|
|
|
173
|
+
describe('Exception handling', () => {
|
|
329
174
|
it('should apply exception for scalability_required', async () => {
|
|
330
175
|
const context: ConstraintContext = {
|
|
331
176
|
operation: 'code_implementation',
|
|
332
|
-
hasReuseCheck: false,
|
|
333
177
|
scalabilityRequired: true,
|
|
334
178
|
};
|
|
335
179
|
|
|
336
180
|
const result = await checker.check(
|
|
337
181
|
{
|
|
338
182
|
id: 'simplest_solution_first',
|
|
183
|
+
kind: 'check',
|
|
339
184
|
level: 'guideline',
|
|
340
185
|
rule: 'SIMPLEST FIRST',
|
|
341
186
|
message: 'test',
|
|
@@ -352,13 +197,13 @@ describe('ConstraintChecker', () => {
|
|
|
352
197
|
it('should apply exception for security_required', async () => {
|
|
353
198
|
const context: ConstraintContext = {
|
|
354
199
|
operation: 'code_implementation',
|
|
355
|
-
hasReuseCheck: false,
|
|
356
200
|
securityRequired: true,
|
|
357
201
|
};
|
|
358
202
|
|
|
359
203
|
const result = await checker.check(
|
|
360
204
|
{
|
|
361
205
|
id: 'simplest_solution_first',
|
|
206
|
+
kind: 'check',
|
|
362
207
|
level: 'guideline',
|
|
363
208
|
rule: 'SIMPLEST FIRST',
|
|
364
209
|
message: 'test',
|
|
@@ -375,13 +220,13 @@ describe('ConstraintChecker', () => {
|
|
|
375
220
|
it('should apply exception for performance_required', async () => {
|
|
376
221
|
const context: ConstraintContext = {
|
|
377
222
|
operation: 'code_implementation',
|
|
378
|
-
hasReuseCheck: false,
|
|
379
223
|
performanceRequired: true,
|
|
380
224
|
};
|
|
381
225
|
|
|
382
226
|
const result = await checker.check(
|
|
383
227
|
{
|
|
384
228
|
id: 'simplest_solution_first',
|
|
229
|
+
kind: 'check',
|
|
385
230
|
level: 'guideline',
|
|
386
231
|
rule: 'SIMPLEST FIRST',
|
|
387
232
|
message: 'test',
|
|
@@ -398,13 +243,13 @@ describe('ConstraintChecker', () => {
|
|
|
398
243
|
it('should apply exception for reliability_required', async () => {
|
|
399
244
|
const context: ConstraintContext = {
|
|
400
245
|
operation: 'code_implementation',
|
|
401
|
-
hasReuseCheck: false,
|
|
402
246
|
reliabilityRequired: true,
|
|
403
247
|
};
|
|
404
248
|
|
|
405
249
|
const result = await checker.check(
|
|
406
250
|
{
|
|
407
251
|
id: 'simplest_solution_first',
|
|
252
|
+
kind: 'check',
|
|
408
253
|
level: 'guideline',
|
|
409
254
|
rule: 'SIMPLEST FIRST',
|
|
410
255
|
message: 'test',
|
|
@@ -421,13 +266,13 @@ describe('ConstraintChecker', () => {
|
|
|
421
266
|
it('should apply exception for config_value_error', async () => {
|
|
422
267
|
const context: ConstraintContext = {
|
|
423
268
|
operation: 'code_implementation',
|
|
424
|
-
hasRootCauseInvestigation: false,
|
|
425
269
|
isConfigValueError: true,
|
|
426
270
|
};
|
|
427
271
|
|
|
428
272
|
const result = await checker.check(
|
|
429
273
|
{
|
|
430
274
|
id: 'no_fix_without_root_cause',
|
|
275
|
+
kind: 'check',
|
|
431
276
|
level: 'guideline',
|
|
432
277
|
rule: 'NO FIX',
|
|
433
278
|
message: 'test',
|
|
@@ -444,13 +289,13 @@ describe('ConstraintChecker', () => {
|
|
|
444
289
|
it('should apply exception for missing_config', async () => {
|
|
445
290
|
const context: ConstraintContext = {
|
|
446
291
|
operation: 'code_implementation',
|
|
447
|
-
hasRootCauseInvestigation: false,
|
|
448
292
|
isMissingConfig: true,
|
|
449
293
|
};
|
|
450
294
|
|
|
451
295
|
const result = await checker.check(
|
|
452
296
|
{
|
|
453
297
|
id: 'no_fix_without_root_cause',
|
|
298
|
+
kind: 'check',
|
|
454
299
|
level: 'guideline',
|
|
455
300
|
rule: 'NO FIX',
|
|
456
301
|
message: 'test',
|
|
@@ -467,13 +312,13 @@ describe('ConstraintChecker', () => {
|
|
|
467
312
|
it('should apply exception for config_file', async () => {
|
|
468
313
|
const context: ConstraintContext = {
|
|
469
314
|
operation: 'code_implementation',
|
|
470
|
-
hasFailingTest: false,
|
|
471
315
|
isConfigFile: true,
|
|
472
316
|
};
|
|
473
317
|
|
|
474
318
|
const result = await checker.check(
|
|
475
319
|
{
|
|
476
320
|
id: 'no_code_without_test',
|
|
321
|
+
kind: 'check',
|
|
477
322
|
level: 'guideline',
|
|
478
323
|
rule: 'NO CODE',
|
|
479
324
|
message: 'test',
|
|
@@ -490,13 +335,13 @@ describe('ConstraintChecker', () => {
|
|
|
490
335
|
it('should apply exception for type_definition', async () => {
|
|
491
336
|
const context: ConstraintContext = {
|
|
492
337
|
operation: 'code_implementation',
|
|
493
|
-
hasFailingTest: false,
|
|
494
338
|
isTypeDefinition: true,
|
|
495
339
|
};
|
|
496
340
|
|
|
497
341
|
const result = await checker.check(
|
|
498
342
|
{
|
|
499
343
|
id: 'no_code_without_test',
|
|
344
|
+
kind: 'check',
|
|
500
345
|
level: 'guideline',
|
|
501
346
|
rule: 'NO CODE',
|
|
502
347
|
message: 'test',
|
|
@@ -513,13 +358,13 @@ describe('ConstraintChecker', () => {
|
|
|
513
358
|
it('should apply exception for simple_accessor', async () => {
|
|
514
359
|
const context: ConstraintContext = {
|
|
515
360
|
operation: 'code_implementation',
|
|
516
|
-
hasFailingTest: false,
|
|
517
361
|
isSimpleAccessor: true,
|
|
518
362
|
};
|
|
519
363
|
|
|
520
364
|
const result = await checker.check(
|
|
521
365
|
{
|
|
522
366
|
id: 'no_code_without_test',
|
|
367
|
+
kind: 'check',
|
|
523
368
|
level: 'guideline',
|
|
524
369
|
rule: 'NO CODE',
|
|
525
370
|
message: 'test',
|
|
@@ -536,13 +381,13 @@ describe('ConstraintChecker', () => {
|
|
|
536
381
|
it('should apply exception for pure_display_component', async () => {
|
|
537
382
|
const context: ConstraintContext = {
|
|
538
383
|
operation: 'code_implementation',
|
|
539
|
-
hasFailingTest: false,
|
|
540
384
|
isPureDisplayComponent: true,
|
|
541
385
|
};
|
|
542
386
|
|
|
543
387
|
const result = await checker.check(
|
|
544
388
|
{
|
|
545
389
|
id: 'no_code_without_test',
|
|
390
|
+
kind: 'check',
|
|
546
391
|
level: 'guideline',
|
|
547
392
|
rule: 'NO CODE',
|
|
548
393
|
message: 'test',
|
|
@@ -556,75 +401,6 @@ describe('ConstraintChecker', () => {
|
|
|
556
401
|
expect(result.satisfied).toBe(true);
|
|
557
402
|
});
|
|
558
403
|
|
|
559
|
-
it('should apply exception for json_parse_result', async () => {
|
|
560
|
-
const context: ConstraintContext = {
|
|
561
|
-
operation: 'code_implementation',
|
|
562
|
-
changedFiles: [],
|
|
563
|
-
isJsonParseResult: true,
|
|
564
|
-
};
|
|
565
|
-
|
|
566
|
-
const result = await checker.check(
|
|
567
|
-
{
|
|
568
|
-
id: 'no_any_type',
|
|
569
|
-
level: 'guideline',
|
|
570
|
-
rule: 'NO ANY',
|
|
571
|
-
message: 'test',
|
|
572
|
-
trigger: 'code_implementation',
|
|
573
|
-
enforcement: 'test',
|
|
574
|
-
exceptions: ['json_parse_result'],
|
|
575
|
-
},
|
|
576
|
-
context
|
|
577
|
-
);
|
|
578
|
-
|
|
579
|
-
expect(result.satisfied).toBe(true);
|
|
580
|
-
});
|
|
581
|
-
|
|
582
|
-
it('should apply exception for third_party_no_types', async () => {
|
|
583
|
-
const context: ConstraintContext = {
|
|
584
|
-
operation: 'code_implementation',
|
|
585
|
-
changedFiles: [],
|
|
586
|
-
isThirdPartyNoTypes: true,
|
|
587
|
-
};
|
|
588
|
-
|
|
589
|
-
const result = await checker.check(
|
|
590
|
-
{
|
|
591
|
-
id: 'no_any_type',
|
|
592
|
-
level: 'guideline',
|
|
593
|
-
rule: 'NO ANY',
|
|
594
|
-
message: 'test',
|
|
595
|
-
trigger: 'code_implementation',
|
|
596
|
-
enforcement: 'test',
|
|
597
|
-
exceptions: ['third_party_no_types'],
|
|
598
|
-
},
|
|
599
|
-
context
|
|
600
|
-
);
|
|
601
|
-
|
|
602
|
-
expect(result.satisfied).toBe(true);
|
|
603
|
-
});
|
|
604
|
-
|
|
605
|
-
it('should apply exception for legacy_migration', async () => {
|
|
606
|
-
const context: ConstraintContext = {
|
|
607
|
-
operation: 'code_implementation',
|
|
608
|
-
changedFiles: [],
|
|
609
|
-
isLegacyMigration: true,
|
|
610
|
-
};
|
|
611
|
-
|
|
612
|
-
const result = await checker.check(
|
|
613
|
-
{
|
|
614
|
-
id: 'no_any_type',
|
|
615
|
-
level: 'guideline',
|
|
616
|
-
rule: 'NO ANY',
|
|
617
|
-
message: 'test',
|
|
618
|
-
trigger: 'code_implementation',
|
|
619
|
-
enforcement: 'test',
|
|
620
|
-
exceptions: ['legacy_migration'],
|
|
621
|
-
},
|
|
622
|
-
context
|
|
623
|
-
);
|
|
624
|
-
|
|
625
|
-
expect(result.satisfied).toBe(true);
|
|
626
|
-
});
|
|
627
|
-
|
|
628
404
|
it('should apply exception for internal_refactor', async () => {
|
|
629
405
|
const context: ConstraintContext = {
|
|
630
406
|
operation: 'commit',
|
|
@@ -635,6 +411,7 @@ describe('ConstraintChecker', () => {
|
|
|
635
411
|
const result = await checker.check(
|
|
636
412
|
{
|
|
637
413
|
id: 'capability_sync',
|
|
414
|
+
kind: 'check',
|
|
638
415
|
level: 'guideline',
|
|
639
416
|
rule: 'CAPABILITY SYNC',
|
|
640
417
|
message: 'test',
|
|
@@ -658,6 +435,7 @@ describe('ConstraintChecker', () => {
|
|
|
658
435
|
const result = await checker.check(
|
|
659
436
|
{
|
|
660
437
|
id: 'capability_sync',
|
|
438
|
+
kind: 'check',
|
|
661
439
|
level: 'guideline',
|
|
662
440
|
rule: 'CAPABILITY SYNC',
|
|
663
441
|
message: 'test',
|
|
@@ -681,6 +459,7 @@ describe('ConstraintChecker', () => {
|
|
|
681
459
|
const result = await checker.check(
|
|
682
460
|
{
|
|
683
461
|
id: 'capability_sync',
|
|
462
|
+
kind: 'check',
|
|
684
463
|
level: 'guideline',
|
|
685
464
|
rule: 'CAPABILITY SYNC',
|
|
686
465
|
message: 'test',
|
|
@@ -704,6 +483,7 @@ describe('ConstraintChecker', () => {
|
|
|
704
483
|
const result = await checker.check(
|
|
705
484
|
{
|
|
706
485
|
id: 'no_simplification_without_approval',
|
|
486
|
+
kind: 'check',
|
|
707
487
|
level: 'guideline',
|
|
708
488
|
rule: 'NO SIMPLIFICATION',
|
|
709
489
|
message: 'test',
|
|
@@ -727,6 +507,7 @@ describe('ConstraintChecker', () => {
|
|
|
727
507
|
const result = await checker.check(
|
|
728
508
|
{
|
|
729
509
|
id: 'no_simplification_without_approval',
|
|
510
|
+
kind: 'check',
|
|
730
511
|
level: 'guideline',
|
|
731
512
|
rule: 'NO SIMPLIFICATION',
|
|
732
513
|
message: 'test',
|
|
@@ -750,6 +531,7 @@ describe('ConstraintChecker', () => {
|
|
|
750
531
|
const result = await checker.check(
|
|
751
532
|
{
|
|
752
533
|
id: 'no_simplification_without_approval',
|
|
534
|
+
kind: 'check',
|
|
753
535
|
level: 'guideline',
|
|
754
536
|
rule: 'NO SIMPLIFICATION',
|
|
755
537
|
message: 'test',
|
|
@@ -764,472 +546,53 @@ describe('ConstraintChecker', () => {
|
|
|
764
546
|
});
|
|
765
547
|
});
|
|
766
548
|
|
|
767
|
-
describe('
|
|
768
|
-
it('
|
|
769
|
-
const context: ConstraintContext = {
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
const result = await checkConstraint('no_self_approval', context);
|
|
775
|
-
expect(result.satisfied).toBe(true);
|
|
549
|
+
describe('Prompt constraints(ADR-0001:不执行 checker,check() 短路 satisfied)', () => {
|
|
550
|
+
it('所有内置 prompt 约束 check() 均短路通过', async () => {
|
|
551
|
+
const context: ConstraintContext = { operation: 'code_implementation' };
|
|
552
|
+
for (const prompt of Object.values(PROMPTS)) {
|
|
553
|
+
const result = await checker.check(prompt, context);
|
|
554
|
+
expect(result.satisfied).toBe(true);
|
|
555
|
+
}
|
|
776
556
|
});
|
|
777
557
|
|
|
778
|
-
it('
|
|
779
|
-
const context: ConstraintContext = {
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
expect(result.satisfied).toBe(false);
|
|
785
|
-
expect(result.message).toContain('未知的约束');
|
|
558
|
+
it('prompt 短路不产生 requiredAction/message', async () => {
|
|
559
|
+
const context: ConstraintContext = { operation: 'code_implementation' };
|
|
560
|
+
const result = await checker.check(PROMPTS['no_fix_without_root_cause'], context);
|
|
561
|
+
expect(result.satisfied).toBe(true);
|
|
562
|
+
expect(result.message).toBeUndefined();
|
|
563
|
+
expect(result.requiredAction).toBeUndefined();
|
|
786
564
|
});
|
|
787
565
|
});
|
|
788
566
|
|
|
789
|
-
describe('
|
|
790
|
-
it('
|
|
791
|
-
const context: ConstraintContext = {
|
|
792
|
-
operation: 'code_implementation',
|
|
793
|
-
completionClaimText: '应该没问题,大概完成了',
|
|
794
|
-
};
|
|
795
|
-
|
|
796
|
-
const result = await checker.check(
|
|
797
|
-
{ id: 'no_fuzzy_completion_claim', level: 'iron_law', rule: 'NO FUZZY', message: 'test', trigger: 'code_implementation', enforcement: 'test' },
|
|
798
|
-
context
|
|
799
|
-
);
|
|
800
|
-
|
|
801
|
-
expect(result.satisfied).toBe(false);
|
|
802
|
-
});
|
|
803
|
-
|
|
804
|
-
it('no_fuzzy_completion_claim should pass clean text', async () => {
|
|
567
|
+
describe('Helper functions', () => {
|
|
568
|
+
it('should check single constraint via checkConstraint', async () => {
|
|
805
569
|
const context: ConstraintContext = {
|
|
806
570
|
operation: 'code_implementation',
|
|
807
|
-
|
|
571
|
+
hasVerificationEvidence: true,
|
|
808
572
|
};
|
|
809
573
|
|
|
810
|
-
const result = await
|
|
811
|
-
{ id: 'no_fuzzy_completion_claim', level: 'iron_law', rule: 'NO FUZZY', message: 'test', trigger: 'code_implementation', enforcement: 'test' },
|
|
812
|
-
context
|
|
813
|
-
);
|
|
814
|
-
|
|
574
|
+
const result = await checkConstraint('no_completion_without_verification', context);
|
|
815
575
|
expect(result.satisfied).toBe(true);
|
|
816
576
|
});
|
|
817
577
|
|
|
818
|
-
it('
|
|
578
|
+
it('prompt 约束经 checkConstraint 短路通过', async () => {
|
|
819
579
|
const context: ConstraintContext = {
|
|
820
580
|
operation: 'code_implementation',
|
|
821
|
-
completionClaimText: '',
|
|
822
581
|
};
|
|
823
582
|
|
|
824
|
-
const result = await
|
|
825
|
-
|
|
826
|
-
context
|
|
827
|
-
);
|
|
828
|
-
|
|
583
|
+
const result = await checkConstraint('no_fuzzy_completion_claim', context);
|
|
584
|
+
expect(result.id).toBe('no_fuzzy_completion_claim');
|
|
829
585
|
expect(result.satisfied).toBe(true);
|
|
830
586
|
});
|
|
831
587
|
|
|
832
|
-
it('
|
|
588
|
+
it('should return false for unknown constraint', async () => {
|
|
833
589
|
const context: ConstraintContext = {
|
|
834
|
-
operation: '
|
|
835
|
-
taskDescription: '好的,我来做',
|
|
590
|
+
operation: 'code_implementation',
|
|
836
591
|
};
|
|
837
592
|
|
|
838
|
-
const result = await
|
|
839
|
-
{ id: 'no_performative_agreement', level: 'iron_law', rule: 'NO PERFORMATIVE', message: 'test', trigger: 'design_request', enforcement: 'test' },
|
|
840
|
-
context
|
|
841
|
-
);
|
|
842
|
-
|
|
593
|
+
const result = await checkConstraint('unknown_constraint', context);
|
|
843
594
|
expect(result.satisfied).toBe(false);
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
it('no_performative_agreement should pass with analysis', async () => {
|
|
847
|
-
const context: ConstraintContext = {
|
|
848
|
-
operation: 'design_request',
|
|
849
|
-
taskDescription: 'This is a detailed analysis of the problem with multiple considerations and proposed solutions.',
|
|
850
|
-
};
|
|
851
|
-
|
|
852
|
-
const result = await checker.check(
|
|
853
|
-
{ id: 'no_performative_agreement', level: 'iron_law', rule: 'NO PERFORMATIVE', message: 'test', trigger: 'design_request', enforcement: 'test' },
|
|
854
|
-
context
|
|
855
|
-
);
|
|
856
|
-
|
|
857
|
-
expect(result.satisfied).toBe(true);
|
|
858
|
-
});
|
|
859
|
-
|
|
860
|
-
it('no_claim_without_evidence should pass with verification evidence', async () => {
|
|
861
|
-
const context: ConstraintContext = {
|
|
862
|
-
operation: 'code_implementation',
|
|
863
|
-
hasVerificationEvidence: true,
|
|
864
|
-
};
|
|
865
|
-
|
|
866
|
-
const result = await checker.check(
|
|
867
|
-
{ id: 'no_claim_without_evidence', level: 'guideline', rule: 'NO CLAIM', message: 'test', trigger: 'code_implementation', enforcement: 'test' },
|
|
868
|
-
context
|
|
869
|
-
);
|
|
870
|
-
|
|
871
|
-
expect(result.satisfied).toBe(true);
|
|
872
|
-
});
|
|
873
|
-
|
|
874
|
-
it('no_claim_without_evidence should pass with taskDescription containing test', async () => {
|
|
875
|
-
const context: ConstraintContext = {
|
|
876
|
-
operation: 'code_implementation',
|
|
877
|
-
hasVerificationEvidence: false,
|
|
878
|
-
taskDescription: 'Need to run the test suite to verify',
|
|
879
|
-
};
|
|
880
|
-
|
|
881
|
-
const result = await checker.check(
|
|
882
|
-
{ id: 'no_claim_without_evidence', level: 'guideline', rule: 'NO CLAIM', message: 'test', trigger: 'code_implementation', enforcement: 'test' },
|
|
883
|
-
context
|
|
884
|
-
);
|
|
885
|
-
|
|
886
|
-
expect(result.satisfied).toBe(true);
|
|
887
|
-
});
|
|
888
|
-
|
|
889
|
-
it('no_claim_without_evidence should fail without evidence', async () => {
|
|
890
|
-
const context: ConstraintContext = {
|
|
891
|
-
operation: 'code_implementation',
|
|
892
|
-
hasVerificationEvidence: false,
|
|
893
|
-
hasTest: false,
|
|
894
|
-
taskDescription: 'Did some work',
|
|
895
|
-
};
|
|
896
|
-
|
|
897
|
-
const result = await checker.check(
|
|
898
|
-
{ id: 'no_claim_without_evidence', level: 'guideline', rule: 'NO CLAIM', message: 'test', trigger: 'code_implementation', enforcement: 'test' },
|
|
899
|
-
context
|
|
900
|
-
);
|
|
901
|
-
|
|
902
|
-
expect(result.satisfied).toBe(false);
|
|
903
|
-
});
|
|
904
|
-
|
|
905
|
-
it('no_delete_without_context should pass with requirement review', async () => {
|
|
906
|
-
const context: ConstraintContext = {
|
|
907
|
-
operation: 'file_deletion',
|
|
908
|
-
hasRequirementReview: true,
|
|
909
|
-
};
|
|
910
|
-
|
|
911
|
-
const result = await checker.check(
|
|
912
|
-
{ id: 'no_delete_without_context', level: 'guideline', rule: 'NO DELETE', message: 'test', trigger: 'file_deletion', enforcement: 'test' },
|
|
913
|
-
context
|
|
914
|
-
);
|
|
915
|
-
|
|
916
|
-
expect(result.satisfied).toBe(true);
|
|
917
|
-
});
|
|
918
|
-
|
|
919
|
-
it('no_delete_without_context should pass with existing design', async () => {
|
|
920
|
-
const context: ConstraintContext = {
|
|
921
|
-
operation: 'file_deletion',
|
|
922
|
-
hasRequirementReview: false,
|
|
923
|
-
hasRequirement: false,
|
|
924
|
-
isExistingDesign: true,
|
|
925
|
-
};
|
|
926
|
-
|
|
927
|
-
const result = await checker.check(
|
|
928
|
-
{ id: 'no_delete_without_context', level: 'guideline', rule: 'NO DELETE', message: 'test', trigger: 'file_deletion', enforcement: 'test' },
|
|
929
|
-
context
|
|
930
|
-
);
|
|
931
|
-
|
|
932
|
-
expect(result.satisfied).toBe(true);
|
|
933
|
-
});
|
|
934
|
-
|
|
935
|
-
it('no_delete_without_context should fail without any context', async () => {
|
|
936
|
-
const context: ConstraintContext = {
|
|
937
|
-
operation: 'file_deletion',
|
|
938
|
-
hasRequirementReview: false,
|
|
939
|
-
hasRequirement: false,
|
|
940
|
-
isExistingDesign: false,
|
|
941
|
-
};
|
|
942
|
-
|
|
943
|
-
const result = await checker.check(
|
|
944
|
-
{ id: 'no_delete_without_context', level: 'guideline', rule: 'NO DELETE', message: 'test', trigger: 'file_deletion', enforcement: 'test' },
|
|
945
|
-
context
|
|
946
|
-
);
|
|
947
|
-
|
|
948
|
-
expect(result.satisfied).toBe(false);
|
|
949
|
-
});
|
|
950
|
-
});
|
|
951
|
-
|
|
952
|
-
describe('Behavior guidelines (always true)', () => {
|
|
953
|
-
it('surgical_changes_only should return true', async () => {
|
|
954
|
-
const context: ConstraintContext = { operation: 'code_implementation' };
|
|
955
|
-
const result = await checker.check(
|
|
956
|
-
{ id: 'surgical_changes_only', level: 'guideline', rule: 'SURGICAL', message: 'test', trigger: 'code_implementation', enforcement: 'test' },
|
|
957
|
-
context
|
|
958
|
-
);
|
|
959
|
-
expect(result.satisfied).toBe(true);
|
|
960
|
-
});
|
|
961
|
-
|
|
962
|
-
it('no_model_for_deterministic should return true', async () => {
|
|
963
|
-
const context: ConstraintContext = { operation: 'code_implementation' };
|
|
964
|
-
const result = await checker.check(
|
|
965
|
-
{ id: 'no_model_for_deterministic', level: 'guideline', rule: 'NO MODEL', message: 'test', trigger: 'code_implementation', enforcement: 'test' },
|
|
966
|
-
context
|
|
967
|
-
);
|
|
968
|
-
expect(result.satisfied).toBe(true);
|
|
969
|
-
});
|
|
970
|
-
|
|
971
|
-
it('no_conflict_blending should return true', async () => {
|
|
972
|
-
const context: ConstraintContext = { operation: 'code_implementation' };
|
|
973
|
-
const result = await checker.check(
|
|
974
|
-
{ id: 'no_conflict_blending', level: 'guideline', rule: 'NO BLEND', message: 'test', trigger: 'code_implementation', enforcement: 'test' },
|
|
975
|
-
context
|
|
976
|
-
);
|
|
977
|
-
expect(result.satisfied).toBe(true);
|
|
978
|
-
});
|
|
979
|
-
|
|
980
|
-
it('read_before_write should return true', async () => {
|
|
981
|
-
const context: ConstraintContext = { operation: 'code_implementation' };
|
|
982
|
-
const result = await checker.check(
|
|
983
|
-
{ id: 'read_before_write', level: 'guideline', rule: 'READ FIRST', message: 'test', trigger: 'code_implementation', enforcement: 'test' },
|
|
984
|
-
context
|
|
985
|
-
);
|
|
986
|
-
expect(result.satisfied).toBe(true);
|
|
987
|
-
});
|
|
988
|
-
|
|
989
|
-
it('first_principles_first should return true', async () => {
|
|
990
|
-
const context: ConstraintContext = { operation: 'code_implementation' };
|
|
991
|
-
const result = await checker.check(
|
|
992
|
-
{ id: 'first_principles_first', level: 'guideline', rule: 'PRINCIPLES', message: 'test', trigger: 'code_implementation', enforcement: 'test' },
|
|
993
|
-
context
|
|
994
|
-
);
|
|
995
|
-
expect(result.satisfied).toBe(true);
|
|
996
|
-
});
|
|
997
|
-
|
|
998
|
-
it('fix_the_problem_not_the_gate should return true', async () => {
|
|
999
|
-
const context: ConstraintContext = { operation: 'code_implementation' };
|
|
1000
|
-
const result = await checker.check(
|
|
1001
|
-
{ id: 'fix_the_problem_not_the_gate', level: 'guideline', rule: 'FIX PROBLEM', message: 'test', trigger: 'code_implementation', enforcement: 'test' },
|
|
1002
|
-
context
|
|
1003
|
-
);
|
|
1004
|
-
expect(result.satisfied).toBe(true);
|
|
1005
|
-
});
|
|
1006
|
-
|
|
1007
|
-
it('diagnosis_to_fix_gate should return true', async () => {
|
|
1008
|
-
const context: ConstraintContext = { operation: 'code_implementation' };
|
|
1009
|
-
const result = await checker.check(
|
|
1010
|
-
{ id: 'diagnosis_to_fix_gate', level: 'guideline', rule: 'DIAGNOSIS', message: 'test', trigger: 'code_implementation', enforcement: 'test' },
|
|
1011
|
-
context
|
|
1012
|
-
);
|
|
1013
|
-
expect(result.satisfied).toBe(true);
|
|
1014
|
-
});
|
|
1015
|
-
|
|
1016
|
-
it('follow_conventions should return true', async () => {
|
|
1017
|
-
const context: ConstraintContext = { operation: 'code_implementation' };
|
|
1018
|
-
const result = await checker.check(
|
|
1019
|
-
{ id: 'follow_conventions', level: 'guideline', rule: 'CONVENTIONS', message: 'test', trigger: 'code_implementation', enforcement: 'test' },
|
|
1020
|
-
context
|
|
1021
|
-
);
|
|
1022
|
-
expect(result.satisfied).toBe(true);
|
|
1023
|
-
});
|
|
1024
|
-
});
|
|
1025
|
-
|
|
1026
|
-
describe('Default guideline constraints', () => {
|
|
1027
|
-
it('no_hardcoded_credentials should pass by default', async () => {
|
|
1028
|
-
const context: ConstraintContext = { operation: 'code_implementation' };
|
|
1029
|
-
const result = await checker.check(
|
|
1030
|
-
{ id: 'no_hardcoded_credentials', level: 'guideline', rule: 'NO CREDENTIALS', message: 'test', trigger: 'code_implementation', enforcement: 'test' },
|
|
1031
|
-
context
|
|
1032
|
-
);
|
|
1033
|
-
expect(result.satisfied).toBe(true);
|
|
1034
|
-
});
|
|
1035
|
-
|
|
1036
|
-
it('design_decision_requires_discussion should pass by default', async () => {
|
|
1037
|
-
const context: ConstraintContext = { operation: 'code_implementation' };
|
|
1038
|
-
const result = await checker.check(
|
|
1039
|
-
{ id: 'design_decision_requires_discussion', level: 'guideline', rule: 'DISCUSS', message: 'test', trigger: 'code_implementation', enforcement: 'test' },
|
|
1040
|
-
context
|
|
1041
|
-
);
|
|
1042
|
-
expect(result.satisfied).toBe(true);
|
|
1043
|
-
});
|
|
1044
|
-
});
|
|
1045
|
-
|
|
1046
|
-
describe('Additional Iron Laws (pure context)', () => {
|
|
1047
|
-
it('no_implementation_without_requirement_review should pass with review', async () => {
|
|
1048
|
-
const context: ConstraintContext = { operation: 'code_implementation', hasRequirementReview: true };
|
|
1049
|
-
const result = await checker.check(
|
|
1050
|
-
{ id: 'no_implementation_without_requirement_review', level: 'iron_law', rule: 'REVIEW REQ', message: 'test', trigger: 'code_implementation', enforcement: 'test' },
|
|
1051
|
-
context
|
|
1052
|
-
);
|
|
1053
|
-
expect(result.satisfied).toBe(true);
|
|
1054
|
-
});
|
|
1055
|
-
|
|
1056
|
-
it('no_implementation_without_requirement_review should fail without review', async () => {
|
|
1057
|
-
const context: ConstraintContext = { operation: 'code_implementation', hasRequirementReview: false };
|
|
1058
|
-
const result = await checker.check(
|
|
1059
|
-
{ id: 'no_implementation_without_requirement_review', level: 'iron_law', rule: 'REVIEW REQ', message: 'test', trigger: 'code_implementation', enforcement: 'test' },
|
|
1060
|
-
context
|
|
1061
|
-
);
|
|
1062
|
-
expect(result.satisfied).toBe(false);
|
|
1063
|
-
});
|
|
1064
|
-
|
|
1065
|
-
it('no_implementation_without_requirement should pass with requirement', async () => {
|
|
1066
|
-
const context: ConstraintContext = { operation: 'code_implementation', hasRequirement: true };
|
|
1067
|
-
const result = await checker.check(
|
|
1068
|
-
{ id: 'no_implementation_without_requirement', level: 'iron_law', rule: 'REQ EXISTS', message: 'test', trigger: 'code_implementation', enforcement: 'test' },
|
|
1069
|
-
context
|
|
1070
|
-
);
|
|
1071
|
-
expect(result.satisfied).toBe(true);
|
|
1072
|
-
});
|
|
1073
|
-
|
|
1074
|
-
it('no_implementation_without_requirement should fail without requirement', async () => {
|
|
1075
|
-
const context: ConstraintContext = { operation: 'code_implementation', hasRequirement: false };
|
|
1076
|
-
const result = await checker.check(
|
|
1077
|
-
{ id: 'no_implementation_without_requirement', level: 'iron_law', rule: 'REQ EXISTS', message: 'test', trigger: 'code_implementation', enforcement: 'test' },
|
|
1078
|
-
context
|
|
1079
|
-
);
|
|
1080
|
-
expect(result.satisfied).toBe(false);
|
|
1081
|
-
});
|
|
1082
|
-
|
|
1083
|
-
it('prefer_worktree should pass with worktree', async () => {
|
|
1084
|
-
const context: ConstraintContext = { operation: 'code_implementation', hasWorktree: true };
|
|
1085
|
-
const result = await checker.check(
|
|
1086
|
-
{ id: 'prefer_worktree', level: 'guideline', rule: 'WORKTREE', message: 'test', trigger: 'code_implementation', enforcement: 'test' },
|
|
1087
|
-
context
|
|
1088
|
-
);
|
|
1089
|
-
expect(result.satisfied).toBe(true);
|
|
1090
|
-
});
|
|
1091
|
-
|
|
1092
|
-
it('prefer_worktree should fail without worktree', async () => {
|
|
1093
|
-
const context: ConstraintContext = { operation: 'code_implementation', hasWorktree: false };
|
|
1094
|
-
const result = await checker.check(
|
|
1095
|
-
{ id: 'prefer_worktree', level: 'guideline', rule: 'WORKTREE', message: 'test', trigger: 'code_implementation', enforcement: 'test' },
|
|
1096
|
-
context
|
|
1097
|
-
);
|
|
1098
|
-
expect(result.satisfied).toBe(false);
|
|
1099
|
-
});
|
|
1100
|
-
|
|
1101
|
-
it('two_stage_review_required should pass with two-stage review', async () => {
|
|
1102
|
-
const context: ConstraintContext = { operation: 'code_implementation', hasTwoStageReview: true };
|
|
1103
|
-
const result = await checker.check(
|
|
1104
|
-
{ id: 'two_stage_review_required', level: 'iron_law', rule: 'TWO STAGE', message: 'test', trigger: 'code_implementation', enforcement: 'test' },
|
|
1105
|
-
context
|
|
1106
|
-
);
|
|
1107
|
-
expect(result.satisfied).toBe(true);
|
|
1108
|
-
});
|
|
1109
|
-
|
|
1110
|
-
it('two_stage_review_required should fail without two-stage review', async () => {
|
|
1111
|
-
const context: ConstraintContext = { operation: 'code_implementation', hasTwoStageReview: false };
|
|
1112
|
-
const result = await checker.check(
|
|
1113
|
-
{ id: 'two_stage_review_required', level: 'iron_law', rule: 'TWO STAGE', message: 'test', trigger: 'code_implementation', enforcement: 'test' },
|
|
1114
|
-
context
|
|
1115
|
-
);
|
|
1116
|
-
expect(result.satisfied).toBe(false);
|
|
1117
|
-
});
|
|
1118
|
-
});
|
|
1119
|
-
|
|
1120
|
-
describe('Additional guidelines (pure context)', () => {
|
|
1121
|
-
it('no_skill_without_test should pass with test', async () => {
|
|
1122
|
-
const context: ConstraintContext = { operation: 'module_creation', hasTest: true };
|
|
1123
|
-
const result = await checker.check(
|
|
1124
|
-
{ id: 'no_skill_without_test', level: 'guideline', rule: 'SKILL TEST', message: 'test', trigger: 'module_creation', enforcement: 'test' },
|
|
1125
|
-
context
|
|
1126
|
-
);
|
|
1127
|
-
expect(result.satisfied).toBe(true);
|
|
1128
|
-
});
|
|
1129
|
-
|
|
1130
|
-
it('no_skill_without_test should fail without test', async () => {
|
|
1131
|
-
const context: ConstraintContext = { operation: 'module_creation', hasTest: false };
|
|
1132
|
-
const result = await checker.check(
|
|
1133
|
-
{ id: 'no_skill_without_test', level: 'guideline', rule: 'SKILL TEST', message: 'test', trigger: 'module_creation', enforcement: 'test' },
|
|
1134
|
-
context
|
|
1135
|
-
);
|
|
1136
|
-
expect(result.satisfied).toBe(false);
|
|
1137
|
-
});
|
|
1138
|
-
|
|
1139
|
-
it('simplest_solution_first should pass with reuse check', async () => {
|
|
1140
|
-
// matches trigger code_implementation
|
|
1141
|
-
const context: ConstraintContext = { operation: 'code_implementation', hasReuseCheck: true };
|
|
1142
|
-
const result = await checker.check(
|
|
1143
|
-
{ id: 'simplest_solution_first', level: 'guideline', rule: 'SIMPLEST', message: 'test', trigger: 'code_implementation', enforcement: 'test' },
|
|
1144
|
-
context
|
|
1145
|
-
);
|
|
1146
|
-
expect(result.satisfied).toBe(true);
|
|
1147
|
-
});
|
|
1148
|
-
|
|
1149
|
-
it('simplest_solution_first should fail without reuse check', async () => {
|
|
1150
|
-
const context: ConstraintContext = { operation: 'code_implementation', hasReuseCheck: false };
|
|
1151
|
-
const result = await checker.check(
|
|
1152
|
-
{ id: 'simplest_solution_first', level: 'guideline', rule: 'SIMPLEST', message: 'test', trigger: 'code_implementation', enforcement: 'test' },
|
|
1153
|
-
context
|
|
1154
|
-
);
|
|
1155
|
-
expect(result.satisfied).toBe(false);
|
|
1156
|
-
});
|
|
1157
|
-
});
|
|
1158
|
-
|
|
1159
|
-
describe('Tip constraints', () => {
|
|
1160
|
-
it('readme_required should always pass', async () => {
|
|
1161
|
-
const context: ConstraintContext = { operation: 'module_creation' };
|
|
1162
|
-
const result = await checker.check(
|
|
1163
|
-
{ id: 'readme_required', level: 'tip', rule: 'README', message: 'test', trigger: 'module_creation', enforcement: 'test' },
|
|
1164
|
-
context
|
|
1165
|
-
);
|
|
1166
|
-
expect(result.satisfied).toBe(true);
|
|
1167
|
-
});
|
|
1168
|
-
|
|
1169
|
-
it('doc_required_for_public_api should always pass', async () => {
|
|
1170
|
-
const context: ConstraintContext = { operation: 'export_change' };
|
|
1171
|
-
const result = await checker.check(
|
|
1172
|
-
{ id: 'doc_required_for_public_api', level: 'tip', rule: 'DOC', message: 'test', trigger: 'export_change', enforcement: 'test' },
|
|
1173
|
-
context
|
|
1174
|
-
);
|
|
1175
|
-
expect(result.satisfied).toBe(true);
|
|
1176
|
-
});
|
|
1177
|
-
});
|
|
1178
|
-
|
|
1179
|
-
describe('no_excuse_patterns', () => {
|
|
1180
|
-
it('should detect excuse patterns in completion claim', async () => {
|
|
1181
|
-
const context: ConstraintContext = {
|
|
1182
|
-
operation: 'code_implementation',
|
|
1183
|
-
completionClaimText: '稍后修复这个bug',
|
|
1184
|
-
};
|
|
1185
|
-
|
|
1186
|
-
const result = await checker.check(
|
|
1187
|
-
{ id: 'no_excuse_patterns', level: 'guideline', rule: 'NO EXCUSE', message: 'test', trigger: 'code_implementation', enforcement: 'test' },
|
|
1188
|
-
context
|
|
1189
|
-
);
|
|
1190
|
-
|
|
1191
|
-
expect(result.satisfied).toBe(false);
|
|
1192
|
-
});
|
|
1193
|
-
|
|
1194
|
-
it('should detect excuse patterns in task description', async () => {
|
|
1195
|
-
const context: ConstraintContext = {
|
|
1196
|
-
operation: 'code_implementation',
|
|
1197
|
-
taskDescription: '这是个临时方案,先这样',
|
|
1198
|
-
};
|
|
1199
|
-
|
|
1200
|
-
const result = await checker.check(
|
|
1201
|
-
{ id: 'no_excuse_patterns', level: 'guideline', rule: 'NO EXCUSE', message: 'test', trigger: 'code_implementation', enforcement: 'test' },
|
|
1202
|
-
context
|
|
1203
|
-
);
|
|
1204
|
-
|
|
1205
|
-
expect(result.satisfied).toBe(false);
|
|
1206
|
-
});
|
|
1207
|
-
|
|
1208
|
-
it('should pass with clean text', async () => {
|
|
1209
|
-
const context: ConstraintContext = {
|
|
1210
|
-
operation: 'code_implementation',
|
|
1211
|
-
completionClaimText: 'Fixed by refactoring the validation logic in checker.ts',
|
|
1212
|
-
};
|
|
1213
|
-
|
|
1214
|
-
const result = await checker.check(
|
|
1215
|
-
{ id: 'no_excuse_patterns', level: 'guideline', rule: 'NO EXCUSE', message: 'test', trigger: 'code_implementation', enforcement: 'test' },
|
|
1216
|
-
context
|
|
1217
|
-
);
|
|
1218
|
-
|
|
1219
|
-
expect(result.satisfied).toBe(true);
|
|
1220
|
-
});
|
|
1221
|
-
|
|
1222
|
-
it('should pass with empty text', async () => {
|
|
1223
|
-
const context: ConstraintContext = {
|
|
1224
|
-
operation: 'code_implementation',
|
|
1225
|
-
};
|
|
1226
|
-
|
|
1227
|
-
const result = await checker.check(
|
|
1228
|
-
{ id: 'no_excuse_patterns', level: 'guideline', rule: 'NO EXCUSE', message: 'test', trigger: 'code_implementation', enforcement: 'test' },
|
|
1229
|
-
context
|
|
1230
|
-
);
|
|
1231
|
-
|
|
1232
|
-
expect(result.satisfied).toBe(true);
|
|
595
|
+
expect(result.message).toContain('未知的约束');
|
|
1233
596
|
});
|
|
1234
597
|
});
|
|
1235
|
-
});
|
|
598
|
+
});
|