@dommaker/harness 1.3.0 → 1.5.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 +20 -0
- package/README.md +0 -2
- package/bin/harness.js +86 -32
- package/dist/cli/command-contract.d.ts +83 -0
- package/dist/cli/command-contract.d.ts.map +1 -0
- package/dist/cli/command-contract.js +66 -0
- package/dist/cli/command-contract.js.map +1 -0
- package/dist/cli/commands/acceptance.d.ts +3 -2
- package/dist/cli/commands/acceptance.d.ts.map +1 -1
- package/dist/cli/commands/acceptance.js +28 -24
- package/dist/cli/commands/acceptance.js.map +1 -1
- package/dist/cli/commands/analyze-sessions.d.ts +2 -1
- package/dist/cli/commands/analyze-sessions.d.ts.map +1 -1
- package/dist/cli/commands/analyze-sessions.js +25 -24
- package/dist/cli/commands/analyze-sessions.js.map +1 -1
- package/dist/cli/commands/check.d.ts +14 -2
- package/dist/cli/commands/check.d.ts.map +1 -1
- package/dist/cli/commands/check.js +104 -61
- package/dist/cli/commands/check.js.map +1 -1
- package/dist/cli/commands/command.d.ts +5 -1
- package/dist/cli/commands/command.d.ts.map +1 -1
- package/dist/cli/commands/command.js +26 -17
- package/dist/cli/commands/command.js.map +1 -1
- package/dist/cli/commands/constraints-report.d.ts +2 -1
- package/dist/cli/commands/constraints-report.d.ts.map +1 -1
- package/dist/cli/commands/constraints-report.js +37 -33
- package/dist/cli/commands/constraints-report.js.map +1 -1
- package/dist/cli/commands/constraints-retire.d.ts +6 -5
- package/dist/cli/commands/constraints-retire.d.ts.map +1 -1
- package/dist/cli/commands/constraints-retire.js +50 -52
- package/dist/cli/commands/constraints-retire.js.map +1 -1
- package/dist/cli/commands/constraints.d.ts +2 -1
- package/dist/cli/commands/constraints.d.ts.map +1 -1
- package/dist/cli/commands/constraints.js +10 -27
- package/dist/cli/commands/constraints.js.map +1 -1
- package/dist/cli/commands/contract.d.ts +3 -2
- package/dist/cli/commands/contract.d.ts.map +1 -1
- package/dist/cli/commands/contract.js +45 -42
- package/dist/cli/commands/contract.js.map +1 -1
- package/dist/cli/commands/definitions.d.ts +11 -11
- package/dist/cli/commands/definitions.d.ts.map +1 -1
- package/dist/cli/commands/definitions.js +27 -219
- package/dist/cli/commands/definitions.js.map +1 -1
- package/dist/cli/commands/failure.d.ts +5 -4
- package/dist/cli/commands/failure.d.ts.map +1 -1
- package/dist/cli/commands/failure.js +31 -25
- package/dist/cli/commands/failure.js.map +1 -1
- package/dist/cli/commands/init.d.ts +7 -5
- package/dist/cli/commands/init.d.ts.map +1 -1
- package/dist/cli/commands/init.js +147 -211
- package/dist/cli/commands/init.js.map +1 -1
- package/dist/cli/commands/knowledge.d.ts +17 -30
- package/dist/cli/commands/knowledge.d.ts.map +1 -1
- package/dist/cli/commands/knowledge.js +183 -273
- package/dist/cli/commands/knowledge.js.map +1 -1
- package/dist/cli/commands/passes-gate.d.ts +8 -2
- package/dist/cli/commands/passes-gate.d.ts.map +1 -1
- package/dist/cli/commands/passes-gate.js +44 -66
- package/dist/cli/commands/passes-gate.js.map +1 -1
- package/dist/cli/commands/performance.d.ts +2 -1
- package/dist/cli/commands/performance.d.ts.map +1 -1
- package/dist/cli/commands/performance.js +20 -18
- package/dist/cli/commands/performance.js.map +1 -1
- package/dist/cli/commands/posteval-plan.d.ts +5 -1
- package/dist/cli/commands/posteval-plan.d.ts.map +1 -1
- package/dist/cli/commands/posteval-plan.js +26 -15
- package/dist/cli/commands/posteval-plan.js.map +1 -1
- package/dist/cli/commands/release.d.ts +6 -1
- package/dist/cli/commands/release.d.ts.map +1 -1
- package/dist/cli/commands/release.js +69 -59
- package/dist/cli/commands/release.js.map +1 -1
- package/dist/cli/commands/report.d.ts +2 -1
- package/dist/cli/commands/report.d.ts.map +1 -1
- package/dist/cli/commands/report.js +9 -5
- package/dist/cli/commands/report.js.map +1 -1
- package/dist/cli/commands/review.d.ts +3 -2
- package/dist/cli/commands/review.d.ts.map +1 -1
- package/dist/cli/commands/review.js +33 -29
- package/dist/cli/commands/review.js.map +1 -1
- package/dist/cli/commands/sdd.d.ts +2 -1
- package/dist/cli/commands/sdd.d.ts.map +1 -1
- package/dist/cli/commands/sdd.js +7 -5
- package/dist/cli/commands/sdd.js.map +1 -1
- package/dist/cli/commands/security.d.ts +3 -2
- package/dist/cli/commands/security.d.ts.map +1 -1
- package/dist/cli/commands/security.js +29 -26
- package/dist/cli/commands/security.js.map +1 -1
- package/dist/cli/commands/spec-baseline-check.d.ts +2 -1
- package/dist/cli/commands/spec-baseline-check.d.ts.map +1 -1
- package/dist/cli/commands/spec-baseline-check.js +15 -11
- package/dist/cli/commands/spec-baseline-check.js.map +1 -1
- package/dist/cli/commands/spec.d.ts +7 -2
- package/dist/cli/commands/spec.d.ts.map +1 -1
- package/dist/cli/commands/spec.js +61 -51
- package/dist/cli/commands/spec.js.map +1 -1
- package/dist/cli/commands/status.d.ts +2 -1
- package/dist/cli/commands/status.d.ts.map +1 -1
- package/dist/cli/commands/status.js +57 -53
- package/dist/cli/commands/status.js.map +1 -1
- package/dist/cli/commands/sync-docs/agents-syncer.d.ts.map +1 -1
- package/dist/cli/commands/sync-docs/agents-syncer.js +5 -2
- package/dist/cli/commands/sync-docs/agents-syncer.js.map +1 -1
- package/dist/cli/commands/sync-docs/context-syncer.d.ts.map +1 -1
- package/dist/cli/commands/sync-docs/context-syncer.js +3 -2
- package/dist/cli/commands/sync-docs/context-syncer.js.map +1 -1
- package/dist/cli/commands/sync-docs/index.d.ts +2 -1
- package/dist/cli/commands/sync-docs/index.d.ts.map +1 -1
- package/dist/cli/commands/sync-docs/index.js +68 -88
- package/dist/cli/commands/sync-docs/index.js.map +1 -1
- package/dist/cli/commands/sync-docs/project-reader.d.ts +6 -1
- package/dist/cli/commands/sync-docs/project-reader.d.ts.map +1 -1
- package/dist/cli/commands/sync-docs/project-reader.js +14 -16
- package/dist/cli/commands/sync-docs/project-reader.js.map +1 -1
- package/dist/cli/commands/update-user-model.d.ts +9 -3
- package/dist/cli/commands/update-user-model.d.ts.map +1 -1
- package/dist/cli/commands/update-user-model.js +56 -61
- package/dist/cli/commands/update-user-model.js.map +1 -1
- package/dist/cli/commands/validate.d.ts +4 -3
- package/dist/cli/commands/validate.d.ts.map +1 -1
- package/dist/cli/commands/validate.js +28 -26
- package/dist/cli/commands/validate.js.map +1 -1
- package/dist/cli/session-mining/transcript.d.ts +7 -1
- package/dist/cli/session-mining/transcript.d.ts.map +1 -1
- package/dist/cli/session-mining/transcript.js +21 -14
- package/dist/cli/session-mining/transcript.js.map +1 -1
- package/dist/context/session-manager.d.ts.map +1 -1
- package/dist/context/session-manager.js +19 -32
- package/dist/context/session-manager.js.map +1 -1
- package/dist/core/constraints/agent-prompt-renderer.d.ts.map +1 -1
- package/dist/core/constraints/agent-prompt-renderer.js +1 -4
- package/dist/core/constraints/agent-prompt-renderer.js.map +1 -1
- package/dist/core/constraints/capabilities-parser.d.ts +24 -7
- package/dist/core/constraints/capabilities-parser.d.ts.map +1 -1
- package/dist/core/constraints/capabilities-parser.js +32 -28
- package/dist/core/constraints/capabilities-parser.js.map +1 -1
- package/dist/core/constraints/capabilities-reconcile.d.ts +67 -0
- package/dist/core/constraints/capabilities-reconcile.d.ts.map +1 -0
- package/dist/core/constraints/capabilities-reconcile.js +105 -0
- package/dist/core/constraints/capabilities-reconcile.js.map +1 -0
- package/dist/core/constraints/checker.d.ts +21 -43
- package/dist/core/constraints/checker.d.ts.map +1 -1
- package/dist/core/constraints/checker.js +68 -117
- package/dist/core/constraints/checker.js.map +1 -1
- package/dist/core/constraints/checkers/capability-sync.d.ts +20 -8
- package/dist/core/constraints/checkers/capability-sync.d.ts.map +1 -1
- package/dist/core/constraints/checkers/capability-sync.js +66 -77
- package/dist/core/constraints/checkers/capability-sync.js.map +1 -1
- package/dist/core/constraints/checkers/context-doc-sync.d.ts +4 -2
- package/dist/core/constraints/checkers/context-doc-sync.d.ts.map +1 -1
- package/dist/core/constraints/checkers/context-doc-sync.js +13 -22
- package/dist/core/constraints/checkers/context-doc-sync.js.map +1 -1
- package/dist/core/constraints/checkers/docs-freshness.d.ts.map +1 -1
- package/dist/core/constraints/checkers/docs-freshness.js +49 -66
- package/dist/core/constraints/checkers/docs-freshness.js.map +1 -1
- package/dist/core/constraints/checkers/governance-presence.d.ts +2 -2
- package/dist/core/constraints/checkers/governance-presence.d.ts.map +1 -1
- package/dist/core/constraints/checkers/governance-presence.js +7 -28
- package/dist/core/constraints/checkers/governance-presence.js.map +1 -1
- package/dist/core/constraints/checkers/index.d.ts +2 -2
- package/dist/core/constraints/checkers/index.d.ts.map +1 -1
- package/dist/core/constraints/checkers/index.js +2 -1
- package/dist/core/constraints/checkers/index.js.map +1 -1
- package/dist/core/constraints/checkers/no-test-simplification.d.ts.map +1 -1
- package/dist/core/constraints/checkers/no-test-simplification.js +4 -3
- package/dist/core/constraints/checkers/no-test-simplification.js.map +1 -1
- package/dist/core/constraints/checkers/types.d.ts +43 -4
- package/dist/core/constraints/checkers/types.d.ts.map +1 -1
- package/dist/core/constraints/checkers/types.js +33 -0
- package/dist/core/constraints/checkers/types.js.map +1 -1
- package/dist/core/constraints/context-builder.d.ts +15 -14
- package/dist/core/constraints/context-builder.d.ts.map +1 -1
- package/dist/core/constraints/context-builder.js +32 -96
- package/dist/core/constraints/context-builder.js.map +1 -1
- package/dist/core/constraints/doc-freshness/runner.d.ts.map +1 -1
- package/dist/core/constraints/doc-freshness/runner.js +2 -1
- package/dist/core/constraints/doc-freshness/runner.js.map +1 -1
- package/dist/core/constraints/git-evidence.d.ts +60 -0
- package/dist/core/constraints/git-evidence.d.ts.map +1 -0
- package/dist/core/constraints/git-evidence.js +88 -0
- package/dist/core/constraints/git-evidence.js.map +1 -0
- package/dist/core/constraints/injection-drift.d.ts +3 -20
- package/dist/core/constraints/injection-drift.d.ts.map +1 -1
- package/dist/core/constraints/injection-drift.js +10 -57
- package/dist/core/constraints/injection-drift.js.map +1 -1
- package/dist/core/constraints/injection-writer.d.ts +113 -0
- package/dist/core/constraints/injection-writer.d.ts.map +1 -0
- package/dist/core/constraints/injection-writer.js +228 -0
- package/dist/core/constraints/injection-writer.js.map +1 -0
- package/dist/core/constraints/usage-report.d.ts +22 -1
- package/dist/core/constraints/usage-report.d.ts.map +1 -1
- package/dist/core/constraints/usage-report.js +27 -20
- package/dist/core/constraints/usage-report.js.map +1 -1
- package/dist/core/index.d.ts +2 -2
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +4 -2
- package/dist/core/index.js.map +1 -1
- package/dist/core/project-config-loader.d.ts +32 -1
- package/dist/core/project-config-loader.d.ts.map +1 -1
- package/dist/core/project-config-loader.js +39 -9
- package/dist/core/project-config-loader.js.map +1 -1
- package/dist/core/validators/passes-gate.d.ts +15 -64
- package/dist/core/validators/passes-gate.d.ts.map +1 -1
- package/dist/core/validators/passes-gate.js +84 -222
- package/dist/core/validators/passes-gate.js.map +1 -1
- package/dist/core/validators/test-output.d.ts +58 -0
- package/dist/core/validators/test-output.d.ts.map +1 -0
- package/dist/core/validators/test-output.js +109 -0
- package/dist/core/validators/test-output.js.map +1 -0
- package/dist/failure/recorder.d.ts +6 -0
- package/dist/failure/recorder.d.ts.map +1 -1
- package/dist/failure/recorder.js +12 -8
- package/dist/failure/recorder.js.map +1 -1
- package/dist/gates/acceptance.d.ts +1 -48
- package/dist/gates/acceptance.d.ts.map +1 -1
- package/dist/gates/acceptance.js +6 -38
- package/dist/gates/acceptance.js.map +1 -1
- package/dist/gates/checker-gate.d.ts +2 -1
- package/dist/gates/checker-gate.d.ts.map +1 -1
- package/dist/gates/checker-gate.js +11 -13
- package/dist/gates/checker-gate.js.map +1 -1
- package/dist/gates/command.d.ts.map +1 -1
- package/dist/gates/command.js +10 -22
- package/dist/gates/command.js.map +1 -1
- package/dist/gates/contract.d.ts.map +1 -1
- package/dist/gates/contract.js +22 -61
- package/dist/gates/contract.js.map +1 -1
- package/dist/gates/performance.d.ts.map +1 -1
- package/dist/gates/performance.js +13 -31
- package/dist/gates/performance.js.map +1 -1
- package/dist/gates/review.d.ts.map +1 -1
- package/dist/gates/review.js +21 -53
- package/dist/gates/review.js.map +1 -1
- package/dist/gates/security.d.ts.map +1 -1
- package/dist/gates/security.js +14 -32
- package/dist/gates/security.js.map +1 -1
- package/dist/gates/types.d.ts +28 -5
- package/dist/gates/types.d.ts.map +1 -1
- package/dist/gates/types.js +38 -1
- package/dist/gates/types.js.map +1 -1
- package/dist/hooks/bootstrap.d.ts +2 -0
- package/dist/hooks/bootstrap.d.ts.map +1 -1
- package/dist/hooks/bootstrap.js +5 -2
- package/dist/hooks/bootstrap.js.map +1 -1
- package/dist/index.d.ts +1 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/knowledge/audit.d.ts +7 -2
- package/dist/knowledge/audit.d.ts.map +1 -1
- package/dist/knowledge/audit.js +59 -79
- package/dist/knowledge/audit.js.map +1 -1
- package/dist/knowledge/flywheel-metrics.d.ts +39 -0
- package/dist/knowledge/flywheel-metrics.d.ts.map +1 -0
- package/dist/knowledge/flywheel-metrics.js +47 -0
- package/dist/knowledge/flywheel-metrics.js.map +1 -0
- package/dist/knowledge/import.d.ts.map +1 -1
- package/dist/knowledge/import.js +4 -14
- package/dist/knowledge/import.js.map +1 -1
- package/dist/knowledge/index-generator.d.ts.map +1 -1
- package/dist/knowledge/index-generator.js +17 -14
- package/dist/knowledge/index-generator.js.map +1 -1
- package/dist/knowledge/ingest.d.ts.map +1 -1
- package/dist/knowledge/ingest.js +9 -4
- package/dist/knowledge/ingest.js.map +1 -1
- package/dist/knowledge/migration.d.ts.map +1 -1
- package/dist/knowledge/migration.js +11 -8
- package/dist/knowledge/migration.js.map +1 -1
- package/dist/knowledge/reference-tracker.d.ts.map +1 -1
- package/dist/knowledge/reference-tracker.js +12 -9
- package/dist/knowledge/reference-tracker.js.map +1 -1
- package/dist/knowledge/store.d.ts +15 -0
- package/dist/knowledge/store.d.ts.map +1 -1
- package/dist/knowledge/store.js +59 -10
- package/dist/knowledge/store.js.map +1 -1
- package/dist/monitoring/context-tracker.d.ts.map +1 -1
- package/dist/monitoring/context-tracker.js +11 -20
- package/dist/monitoring/context-tracker.js.map +1 -1
- package/dist/monitoring/index.d.ts +1 -1
- package/dist/monitoring/index.d.ts.map +1 -1
- package/dist/monitoring/index.js +1 -2
- package/dist/monitoring/index.js.map +1 -1
- package/dist/monitoring/trace-analyzer.d.ts +15 -0
- package/dist/monitoring/trace-analyzer.d.ts.map +1 -1
- package/dist/monitoring/trace-analyzer.js +19 -2
- package/dist/monitoring/trace-analyzer.js.map +1 -1
- package/dist/monitoring/traces.d.ts +21 -2
- package/dist/monitoring/traces.d.ts.map +1 -1
- package/dist/monitoring/traces.js +38 -29
- package/dist/monitoring/traces.js.map +1 -1
- package/dist/release/index.d.ts +2 -2
- package/dist/release/index.d.ts.map +1 -1
- package/dist/release/index.js +1 -5
- package/dist/release/index.js.map +1 -1
- package/dist/sdd/index-generator.js +10 -11
- package/dist/sdd/index-generator.js.map +1 -1
- package/dist/test-setup/project-fixture.d.ts +48 -0
- package/dist/test-setup/project-fixture.d.ts.map +1 -0
- package/dist/test-setup/project-fixture.js +106 -0
- package/dist/test-setup/project-fixture.js.map +1 -0
- package/dist/types/constraint.d.ts +8 -18
- package/dist/types/constraint.d.ts.map +1 -1
- package/dist/types/constraint.js +6 -1
- package/dist/types/constraint.js.map +1 -1
- package/dist/types/passes-gate.d.ts +10 -25
- package/dist/types/passes-gate.d.ts.map +1 -1
- package/dist/types/project-config.d.ts +1 -1
- package/dist/types/session.d.ts +6 -5
- package/dist/types/session.d.ts.map +1 -1
- package/dist/types/trace.d.ts +9 -0
- package/dist/types/trace.d.ts.map +1 -1
- package/dist/utils/exec.d.ts +10 -0
- package/dist/utils/exec.d.ts.map +1 -1
- package/dist/utils/exec.js +12 -0
- package/dist/utils/exec.js.map +1 -1
- package/dist/utils/file-walk.d.ts +9 -1
- package/dist/utils/file-walk.d.ts.map +1 -1
- package/dist/utils/file-walk.js +10 -1
- package/dist/utils/file-walk.js.map +1 -1
- package/dist/utils/frontmatter.d.ts +73 -0
- package/dist/utils/frontmatter.d.ts.map +1 -0
- package/dist/utils/frontmatter.js +141 -0
- package/dist/utils/frontmatter.js.map +1 -0
- package/dist/utils/jsonl.d.ts +92 -0
- package/dist/utils/jsonl.d.ts.map +1 -0
- package/dist/utils/jsonl.js +166 -0
- package/dist/utils/jsonl.js.map +1 -0
- package/dist/utils/package-version.d.ts +16 -0
- package/dist/utils/package-version.d.ts.map +1 -0
- package/dist/utils/package-version.js +63 -0
- package/dist/utils/package-version.js.map +1 -0
- package/package.json +1 -1
- package/src/CONTEXT.md +8 -2
- package/src/__tests__/acceptance-gate.test.ts +3 -1
- package/src/__tests__/checker-extra.test.ts +7 -1218
- package/src/__tests__/context-files-resolution.test.ts +116 -0
- package/src/__tests__/effective-constraints.test.ts +10 -13
- package/src/__tests__/exec.test.ts +35 -1
- package/src/__tests__/layering.test.ts +152 -0
- package/src/__tests__/passes-gate-extra.test.ts +0 -145
- package/src/__tests__/passes-gate.test.ts +130 -101
- package/src/__tests__/skip-semantics.test.ts +5 -9
- package/src/cli/__tests__/command-contract.test.ts +170 -0
- package/src/cli/command-contract.ts +108 -0
- package/src/cli/commands/CONTEXT.md +23 -8
- package/src/cli/commands/__tests__/acceptance.test.ts +40 -33
- package/src/cli/commands/__tests__/analyze-sessions.test.ts +35 -29
- package/src/cli/commands/__tests__/bin-exit-mapping.test.ts +107 -0
- package/src/cli/commands/__tests__/check-drift.test.ts +27 -34
- package/src/cli/commands/__tests__/check-skip-output.test.ts +21 -24
- package/src/cli/commands/__tests__/check.test.ts +448 -378
- package/src/cli/commands/__tests__/command.test.ts +85 -70
- package/src/cli/commands/__tests__/constraints-report.test.ts +100 -71
- package/src/cli/commands/__tests__/constraints-retire.test.ts +152 -95
- package/src/cli/commands/__tests__/contract.test.ts +27 -34
- package/src/cli/commands/__tests__/failure.test.ts +31 -34
- package/src/cli/commands/__tests__/init-injection.test.ts +58 -28
- package/src/cli/commands/__tests__/init.test.ts +77 -48
- package/src/cli/commands/__tests__/knowledge-flywheel-consistency.test.ts +108 -0
- package/src/cli/commands/__tests__/knowledge.test.ts +69 -43
- package/src/cli/commands/__tests__/passes-gate.test.ts +43 -45
- package/src/cli/commands/__tests__/performance.test.ts +22 -23
- package/src/cli/commands/__tests__/posteval-plan.test.ts +39 -38
- package/src/cli/commands/__tests__/project-path-anchoring.test.ts +157 -0
- package/src/cli/commands/__tests__/project-path-convention.test.ts +231 -0
- package/src/cli/commands/__tests__/registry.test.ts +75 -35
- package/src/cli/commands/__tests__/release.test.ts +209 -80
- package/src/cli/commands/__tests__/report-extra.test.ts +16 -16
- package/src/cli/commands/__tests__/report.test.ts +25 -25
- package/src/cli/commands/__tests__/review.test.ts +33 -31
- package/src/cli/commands/__tests__/security.test.ts +23 -27
- package/src/cli/commands/__tests__/spec-baseline-check.test.ts +20 -20
- package/src/cli/commands/__tests__/spec.test.ts +41 -29
- package/src/cli/commands/__tests__/status-extra.test.ts +18 -18
- package/src/cli/commands/__tests__/status-skipped-lines.test.ts +72 -0
- package/src/cli/commands/__tests__/status.test.ts +34 -34
- package/src/cli/commands/__tests__/sync-docs-agents.test.ts +77 -78
- package/src/cli/commands/__tests__/sync-docs.test.ts +72 -74
- package/src/cli/commands/__tests__/update-user-model.test.ts +97 -34
- package/src/cli/commands/__tests__/validate.test.ts +27 -29
- package/src/cli/commands/acceptance.ts +35 -24
- package/src/cli/commands/analyze-sessions.ts +25 -24
- package/src/cli/commands/check.ts +127 -66
- package/src/cli/commands/command.ts +30 -17
- package/src/cli/commands/constraints-report.ts +37 -34
- package/src/cli/commands/constraints-retire.ts +58 -55
- package/src/cli/commands/constraints.ts +10 -27
- package/src/cli/commands/contract.ts +51 -42
- package/src/cli/commands/definitions.ts +34 -227
- package/src/cli/commands/failure.ts +33 -26
- package/src/cli/commands/init.ts +166 -220
- package/src/cli/commands/knowledge.ts +192 -289
- package/src/cli/commands/passes-gate.ts +58 -68
- package/src/cli/commands/performance.ts +23 -18
- package/src/cli/commands/posteval-plan.ts +29 -15
- package/src/cli/commands/release.ts +70 -59
- package/src/cli/commands/report.ts +9 -5
- package/src/cli/commands/review.ts +39 -29
- package/src/cli/commands/sdd.ts +7 -5
- package/src/cli/commands/security.ts +35 -26
- package/src/cli/commands/spec-baseline-check.ts +16 -11
- package/src/cli/commands/spec.ts +66 -53
- package/src/cli/commands/status.ts +59 -53
- package/src/cli/commands/sync-docs/agents-syncer.ts +5 -2
- package/src/cli/commands/sync-docs/context-syncer.ts +3 -2
- package/src/cli/commands/sync-docs/index.ts +73 -100
- package/src/cli/commands/sync-docs/project-reader.ts +17 -18
- package/src/cli/commands/update-user-model.ts +64 -61
- package/src/cli/commands/validate.ts +31 -25
- package/src/cli/session-mining/__tests__/transcript.test.ts +118 -0
- package/src/cli/session-mining/transcript.ts +26 -8
- package/src/context/session-manager.ts +19 -33
- package/src/core/CONTEXT.md +10 -6
- package/src/core/constraints/__tests__/capabilities-reconcile.test.ts +200 -0
- package/src/core/constraints/__tests__/capability-counts.test.ts +94 -0
- package/src/core/constraints/__tests__/git-evidence.test.ts +208 -0
- package/src/core/constraints/__tests__/injection-drift.test.ts +3 -10
- package/src/core/constraints/__tests__/injection-writer.test.ts +231 -0
- package/src/core/constraints/__tests__/trace-injection.test.ts +71 -0
- package/src/core/constraints/__tests__/usage-report.test.ts +112 -0
- package/src/core/constraints/agent-prompt-renderer.ts +2 -6
- package/src/core/constraints/capabilities-parser.ts +53 -35
- package/src/core/constraints/capabilities-reconcile.ts +166 -0
- package/src/core/constraints/checker.ts +82 -133
- package/src/core/constraints/checkers/__tests__/capability-sync.test.ts +273 -0
- package/src/core/constraints/checkers/__tests__/check-outcome.test.ts +176 -0
- package/src/core/constraints/checkers/__tests__/context-doc-sync.test.ts +77 -0
- package/src/core/constraints/checkers/__tests__/docs-freshness.test.ts +126 -0
- package/src/{__tests__ → core/constraints/checkers/__tests__}/governance-presence.test.ts +83 -9
- package/src/core/constraints/checkers/__tests__/iron-flags.test.ts +50 -0
- package/src/core/constraints/checkers/__tests__/no-bypass-checkpoint.test.ts +76 -0
- package/src/{__tests__ → core/constraints/checkers/__tests__}/no-hardcoded-credentials.test.ts +4 -3
- package/src/core/constraints/checkers/__tests__/no-test-simplification.test.ts +58 -0
- package/src/core/constraints/checkers/__tests__/three-state-consistency.test.ts +153 -0
- package/src/core/constraints/checkers/capability-sync.ts +75 -96
- package/src/core/constraints/checkers/context-doc-sync.ts +15 -25
- package/src/core/constraints/checkers/docs-freshness.ts +54 -70
- package/src/core/constraints/checkers/governance-presence.ts +7 -25
- package/src/core/constraints/checkers/index.ts +9 -2
- package/src/core/constraints/checkers/no-test-simplification.ts +4 -3
- package/src/core/constraints/checkers/types.ts +60 -4
- package/src/core/constraints/context-builder.ts +39 -91
- package/src/core/constraints/doc-freshness/runner.ts +2 -1
- package/src/core/constraints/git-evidence.ts +120 -0
- package/src/core/constraints/injection-drift.ts +13 -60
- package/src/core/constraints/injection-writer.ts +212 -0
- package/src/core/constraints/usage-report.ts +36 -17
- package/src/core/index.ts +4 -2
- package/src/core/project-config-loader.ts +49 -9
- package/src/core/validators/__tests__/passes-gate.test.ts +2 -56
- package/src/core/validators/__tests__/test-output.test.ts +372 -0
- package/src/core/validators/passes-gate.ts +86 -248
- package/src/core/validators/test-output.ts +128 -0
- package/src/failure/__tests__/recorder.test.ts +168 -0
- package/src/failure/recorder.ts +12 -10
- package/src/gates/CONTEXT.md +7 -4
- package/src/gates/__tests__/acceptance-types-single-source.test.ts +68 -0
- package/src/gates/__tests__/acceptance.test.ts +4 -86
- package/src/gates/__tests__/checker-gate.test.ts +24 -0
- package/src/gates/__tests__/effective-gates.test.ts +3 -8
- package/src/gates/__tests__/test-verdict-consistency.test.ts +140 -0
- package/src/gates/acceptance.ts +19 -84
- package/src/gates/checker-gate.ts +12 -15
- package/src/gates/command.ts +10 -16
- package/src/gates/contract.ts +22 -61
- package/src/gates/performance.ts +10 -22
- package/src/gates/review.ts +21 -41
- package/src/gates/security.ts +10 -22
- package/src/gates/types.ts +70 -5
- package/src/hooks/CONTEXT.md +1 -1
- package/src/hooks/bootstrap.ts +5 -2
- package/src/index.ts +0 -4
- package/src/knowledge/CONTEXT.md +8 -3
- package/src/knowledge/__tests__/audit-labels.test.ts +44 -0
- package/src/knowledge/__tests__/flywheel-metrics.test.ts +135 -0
- package/src/knowledge/__tests__/import.test.ts +44 -0
- package/src/knowledge/__tests__/index-generator.test.ts +53 -0
- package/src/knowledge/__tests__/ingest.test.ts +85 -0
- package/src/knowledge/__tests__/migration.test.ts +47 -0
- package/src/knowledge/__tests__/reference-tracker.test.ts +16 -0
- package/src/knowledge/__tests__/store.test.ts +194 -0
- package/src/knowledge/audit.ts +67 -71
- package/src/knowledge/flywheel-metrics.ts +71 -0
- package/src/knowledge/import.ts +4 -18
- package/src/knowledge/index-generator.ts +19 -14
- package/src/knowledge/ingest.ts +9 -4
- package/src/knowledge/migration.ts +11 -8
- package/src/knowledge/reference-tracker.ts +12 -8
- package/src/knowledge/store.ts +64 -11
- package/src/monitoring/CONTEXT.md +8 -3
- package/src/monitoring/__tests__/skipped-lines-report.test.ts +178 -0
- package/src/monitoring/__tests__/traces.test.ts +57 -0
- package/src/monitoring/context-tracker.ts +11 -23
- package/src/monitoring/index.ts +1 -1
- package/src/monitoring/trace-analyzer.ts +21 -2
- package/src/monitoring/traces.ts +39 -36
- package/src/release/CONTEXT.md +1 -0
- package/src/release/__tests__/barrel.test.ts +60 -0
- package/src/release/index.ts +2 -13
- package/src/sdd/__tests__/index-generator.test.ts +71 -0
- package/src/sdd/index-generator.ts +9 -9
- package/src/test-setup/__tests__/project-fixture.test.ts +178 -0
- package/src/test-setup/project-fixture.ts +87 -0
- package/src/tools/CONTEXT.md +6 -0
- package/src/tools/__tests__/registry.test.ts +221 -0
- package/src/types/__tests__/types.test.ts +4 -5
- package/src/types/constraint.ts +16 -27
- package/src/types/passes-gate.ts +10 -30
- package/src/types/project-config.ts +1 -1
- package/src/types/session.ts +5 -5
- package/src/types/trace.ts +10 -0
- package/src/utils/__tests__/frontmatter.test.ts +206 -0
- package/src/utils/__tests__/jsonl-skip-disposition.test.ts +175 -0
- package/src/utils/__tests__/jsonl.test.ts +187 -0
- package/src/utils/__tests__/package-version.test.ts +97 -0
- package/src/utils/exec.ts +15 -0
- package/src/utils/file-walk.ts +11 -2
- package/src/utils/frontmatter.ts +121 -0
- package/src/utils/jsonl.ts +167 -0
- package/src/utils/package-version.ts +27 -0
- package/dist/cli/commands/doc-freshness-check.d.ts +0 -53
- package/dist/cli/commands/doc-freshness-check.d.ts.map +0 -1
- package/dist/cli/commands/doc-freshness-check.js +0 -352
- package/dist/cli/commands/doc-freshness-check.js.map +0 -1
- package/dist/types/index.d.ts +0 -14
- package/dist/types/index.d.ts.map +0 -1
- package/dist/types/index.js +0 -39
- package/dist/types/index.js.map +0 -1
- package/src/__tests__/long-running.test.ts +0 -17
- package/src/__tests__/passes-gate-extension.test.ts +0 -151
- package/src/cli/commands/__tests__/doc-freshness-check.test.ts +0 -168
- package/src/cli/commands/doc-freshness-check.ts +0 -386
- package/src/spec/CONTEXT.md +0 -11
- package/src/types/index.ts +0 -47
|
@@ -1,16 +1,28 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* capability_sync:CAPABILITIES.md 与代码同步检查(工单 21)
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
* 1. Git diff 增量 —
|
|
6
|
-
* 2.
|
|
4
|
+
* 两步验证,归因不同(harness#119):
|
|
5
|
+
* 1. Git diff 增量 — 本次变更的非测试文件是否在文档中有记录 → **判违规**(有因果)
|
|
6
|
+
* 2. 全量扫描(T-058)— 源码根下所有源文件是否都在 CAPABILITIES.md 中 → **只出提示**
|
|
7
7
|
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
8
|
+
* Step 2 不判违规的理由:它是仓库级完备性不变量,与正在被评估的那次变更无因果——
|
|
9
|
+
* 一处历史漏登会让此后每次 module_* 评估恒红(studio 实测 22/22 fail,且因 fail
|
|
10
|
+
* 零证据而无人能定位)。本处保留缺口输出是为了让人看得见、能自己修,而不是为了拦。
|
|
11
|
+
*
|
|
12
|
+
* 已知缺口(ADR-0016「影响」①):降级后仓库级漏登**没有自动拦截点**。`sync-docs --check`
|
|
13
|
+
* 单独跑会点名并 exit 1,但 CI/ship 都按「先 sync-docs 写入、后 --check」的顺序跑
|
|
14
|
+
* (2026-08-08 CI 4 连红固化的顺序),而 file 模式的写入正给缺登记自动补行
|
|
15
|
+
* (`capabilities-syncer` 的 `mode !== 'module'` 分支)、那份写入又不回提——于是流水线里
|
|
16
|
+
* 永远查不到漏登。补这个牙齿归流水线侧(sync 后 git diff 非空即失败),不在本约束里做。
|
|
17
|
+
*
|
|
18
|
+
* 例外:「有表格但零条目」= 文档被清空,判违规(历史门,此前靠 Step 2 兜,现显式化)。
|
|
19
|
+
*
|
|
20
|
+
* 覆盖/漏登判定不在本文件实现,统一走 capabilities-reconcile(ADR-0009):
|
|
21
|
+
* 目录条目(以 / 结尾)前缀匹配,文件条目精确匹配或路径边界后缀匹配;
|
|
22
|
+
* module 模式下目录条目参与覆盖,未覆盖文件按源码根下第一级子目录聚合。
|
|
11
23
|
*
|
|
12
24
|
* 清单格式(计数行,mode=listing 或嗅探命中)无文件表可核对,直接放行;
|
|
13
|
-
*
|
|
25
|
+
* 无表格的散文文档保持历史放行;检查异常时 fail-open 但输出 console.warn 保留可观测性。
|
|
14
26
|
*
|
|
15
27
|
* ADR-0001 存在性探测:项目根无 CAPABILITIES.md(未采用该约定)时返回 'skip',
|
|
16
28
|
* 不计 pass/fail,避免在未采用约定的项目上全量误报。
|
|
@@ -18,32 +30,11 @@
|
|
|
18
30
|
|
|
19
31
|
import { existsSync, readFileSync } from 'fs';
|
|
20
32
|
import { join } from 'path';
|
|
21
|
-
import {
|
|
22
|
-
aggregateToSourceSubdir,
|
|
23
|
-
isCapabilityListingFormat,
|
|
24
|
-
parseCapabilitiesEntries,
|
|
25
|
-
} from '../capabilities-parser';
|
|
33
|
+
import { isCapabilityListingFormat } from '../capabilities-parser';
|
|
26
34
|
import { getCapabilitiesMode } from '../../project-config-loader';
|
|
27
35
|
import { detectSourceRoots } from '../../../utils/detect-source-roots';
|
|
28
|
-
import
|
|
29
|
-
|
|
30
|
-
/** markdown 表格分隔行(|------|------|):区分「无表格的散文文档」与「有表格但零条目」 */
|
|
31
|
-
const TABLE_SEPARATOR_REGEX = /^\s*\|[\s:|-]+\|\s*$/m;
|
|
32
|
-
|
|
33
|
-
/**
|
|
34
|
-
* 变更文件是否被条目覆盖
|
|
35
|
-
*
|
|
36
|
-
* 目录条目(以 / 结尾)前缀匹配;文件条目精确匹配或路径边界后缀匹配
|
|
37
|
-
* (兼容 basename 条目,但拒绝 xfoo.ts 命中 foo.ts、docs/src/foo.tsx 命中 src/foo.ts
|
|
38
|
-
* 这类 endsWith/includes 模糊匹配造成的碰撞)
|
|
39
|
-
*/
|
|
40
|
-
function isCoveredBy(entries: string[], changed: string): boolean {
|
|
41
|
-
return entries.some((listed) =>
|
|
42
|
-
listed.endsWith('/')
|
|
43
|
-
? changed.startsWith(listed)
|
|
44
|
-
: changed === listed || changed.endsWith('/' + listed)
|
|
45
|
-
);
|
|
46
|
-
}
|
|
36
|
+
import { reconcileCapabilities, significantCodeChanges } from '../capabilities-reconcile';
|
|
37
|
+
import { formatEvidence, type ConstraintCheck } from './types';
|
|
47
38
|
|
|
48
39
|
export const capabilitySync: ConstraintCheck = {
|
|
49
40
|
id: 'capability_sync',
|
|
@@ -55,15 +46,6 @@ export const capabilitySync: ConstraintCheck = {
|
|
|
55
46
|
}
|
|
56
47
|
try {
|
|
57
48
|
const capabilitiesPath = join(projectPath, 'CAPABILITIES.md');
|
|
58
|
-
if (!existsSync(capabilitiesPath)) {
|
|
59
|
-
// 检查是否有代码变更,无变更则跳过
|
|
60
|
-
const diff = await env.stagedDiffNames();
|
|
61
|
-
const changedCodeFiles = diff.split('\n').filter(
|
|
62
|
-
(f: string) => f.endsWith('.ts') || f.endsWith('.tsx') || f.endsWith('.js')
|
|
63
|
-
);
|
|
64
|
-
return changedCodeFiles.length === 0;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
49
|
const content = readFileSync(capabilitiesPath, 'utf-8');
|
|
68
50
|
const capabilitiesMode = getCapabilitiesMode(projectPath);
|
|
69
51
|
|
|
@@ -72,71 +54,68 @@ export const capabilitySync: ConstraintCheck = {
|
|
|
72
54
|
return true;
|
|
73
55
|
}
|
|
74
56
|
|
|
75
|
-
const
|
|
76
|
-
|
|
77
|
-
const
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
const hasTable = TABLE_SEPARATOR_REGEX.test(content);
|
|
57
|
+
const sourceRoots = detectSourceRoots(projectPath);
|
|
58
|
+
const population: string[] = [];
|
|
59
|
+
for (const root of sourceRoots) {
|
|
60
|
+
if (existsSync(join(projectPath, root))) {
|
|
61
|
+
population.push(...env.srcScan(root));
|
|
62
|
+
}
|
|
63
|
+
}
|
|
83
64
|
|
|
84
|
-
|
|
85
|
-
const
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
);
|
|
65
|
+
const diffNames = (await env.stagedDiffNames()).split('\n').filter(Boolean);
|
|
66
|
+
const verdict = reconcileCapabilities({
|
|
67
|
+
content,
|
|
68
|
+
populationFiles: population,
|
|
69
|
+
changedFiles: significantCodeChanges(diffNames),
|
|
70
|
+
sourceRoots,
|
|
71
|
+
});
|
|
92
72
|
|
|
93
|
-
//
|
|
94
|
-
if (
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
) {
|
|
99
|
-
return
|
|
73
|
+
// 无表格的散文文档:历史放行语义
|
|
74
|
+
if (!verdict.hasTable) return true;
|
|
75
|
+
|
|
76
|
+
// 文档退化门:有表格却什么都没登记(限定「源码根下确有文件」——空仓 + 空表没有可登记
|
|
77
|
+
// 对象,历史行为是放行,本票不顺手扩大 fail 面)
|
|
78
|
+
if (verdict.coverageEntries.length === 0 && population.length > 0) {
|
|
79
|
+
return {
|
|
80
|
+
pass: false,
|
|
81
|
+
evidence: ['CAPABILITIES.md 有表格但零条目登记,运行 harness sync-docs 或直接补登记'],
|
|
82
|
+
};
|
|
100
83
|
}
|
|
101
84
|
|
|
102
|
-
// ── Step
|
|
103
|
-
if (
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
const srcDir = join(projectPath, root);
|
|
125
|
-
if (existsSync(srcDir)) {
|
|
126
|
-
for (const file of env.srcScan(root)) {
|
|
127
|
-
if (!isCoveredBy(listedFiles, file)) {
|
|
128
|
-
return false;
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
}
|
|
85
|
+
// ── Step 1: Git diff 增量检查(与本次变更有因果,每个变更文件都必须被覆盖)──
|
|
86
|
+
if (verdict.uncoveredChanges.length > 0) {
|
|
87
|
+
return {
|
|
88
|
+
pass: false,
|
|
89
|
+
evidence: formatEvidence(
|
|
90
|
+
`本次变更有 ${verdict.uncoveredChanges.length} 个文件未登记进 CAPABILITIES.md`,
|
|
91
|
+
verdict.uncoveredChanges
|
|
92
|
+
),
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// ── Step 2: 全量源码根扫描(T-058)——仓库级漂移,只提示不判违规,见文件头 ──
|
|
97
|
+
const gaps = capabilitiesMode === 'module' ? verdict.uncoveredDirs : verdict.uncoveredFiles;
|
|
98
|
+
if (gaps.length > 0) {
|
|
99
|
+
const kind = capabilitiesMode === 'module' ? '未登记模块目录' : '未登记源文件';
|
|
100
|
+
return {
|
|
101
|
+
pass: true,
|
|
102
|
+
evidence: formatEvidence(
|
|
103
|
+
`CAPABILITIES.md ${kind} ${gaps.length} 项(仓库级漂移,与本次变更无关;修复: harness sync-docs)`,
|
|
104
|
+
gaps
|
|
105
|
+
),
|
|
106
|
+
};
|
|
133
107
|
}
|
|
134
108
|
|
|
135
109
|
return true;
|
|
136
110
|
} catch (err) {
|
|
137
|
-
// fail-open
|
|
111
|
+
// fail-open 语义保留,但异常放行也要落地可见:warn 只进本地 stderr,
|
|
112
|
+
// 进不了 trace——静默吞错会让解析 bug 变成「永远通过」(harness#119 同族问题)
|
|
113
|
+
const reason = err instanceof Error ? err.message : String(err);
|
|
138
114
|
console.warn('[capability_sync] 检查执行异常,默认放行:', err);
|
|
139
|
-
return
|
|
115
|
+
return {
|
|
116
|
+
pass: true,
|
|
117
|
+
evidence: [`检查异常,按 fail-open 放行: ${reason}(本次结果不代表文档已同步)`],
|
|
118
|
+
};
|
|
140
119
|
}
|
|
141
120
|
},
|
|
142
121
|
};
|
|
@@ -1,43 +1,33 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* context_doc_sync:关键目录必须有 CONTEXT.md(工单 21)
|
|
3
3
|
*
|
|
4
|
-
* ADR-0001
|
|
5
|
-
*
|
|
4
|
+
* ADR-0001 存在性探测 + context_files 三态统一口径(工单 84):
|
|
5
|
+
* 未配置 / enabled 但无目标(required_dirs 缺失或空)→ 一律 'skip',
|
|
6
|
+
* 不计 pass/fail,与 docs_freshness 同构;判定只走 resolveContextFiles
|
|
7
|
+
* 访问器,不做 governance 手写钻取。
|
|
6
8
|
*/
|
|
7
9
|
|
|
8
10
|
import { existsSync } from 'fs';
|
|
9
11
|
import { join } from 'path';
|
|
10
|
-
import {
|
|
12
|
+
import { resolveContextFiles } from '../../project-config-loader';
|
|
11
13
|
import type { ConstraintCheck } from './types';
|
|
12
14
|
|
|
13
15
|
export const contextDocSync: ConstraintCheck = {
|
|
14
16
|
id: 'context_doc_sync',
|
|
15
17
|
async evaluate(env) {
|
|
16
18
|
const projectPath = env.projectPath;
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
if (!contextFiles?.enabled || !Array.isArray(contextFiles.required_dirs)) {
|
|
23
|
-
return 'skip'; // 未配置 context_files 约定,跳过评估
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
const requiredDirs = contextFiles.required_dirs as string[];
|
|
27
|
-
if (requiredDirs.length === 0) {
|
|
28
|
-
return 'skip'; // 无目标目录,约定未生效
|
|
29
|
-
}
|
|
19
|
+
const resolution = resolveContextFiles(projectPath);
|
|
20
|
+
if (resolution.state !== 'enabled') {
|
|
21
|
+
return 'skip'; // 未配置或约定已立但无目标,跳过评估
|
|
22
|
+
}
|
|
30
23
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
}
|
|
24
|
+
for (const dir of resolution.dirs) {
|
|
25
|
+
const contextPath = join(projectPath, dir, 'CONTEXT.md');
|
|
26
|
+
if (!existsSync(contextPath)) {
|
|
27
|
+
return false;
|
|
36
28
|
}
|
|
37
|
-
|
|
38
|
-
return true;
|
|
39
|
-
} catch {
|
|
40
|
-
return 'skip'; // 配置不存在或解析失败 = 无法判定约定,跳过
|
|
41
29
|
}
|
|
30
|
+
|
|
31
|
+
return true;
|
|
42
32
|
},
|
|
43
33
|
};
|
|
@@ -9,11 +9,13 @@
|
|
|
9
9
|
|
|
10
10
|
import { existsSync, readFileSync } from 'fs';
|
|
11
11
|
import { join } from 'path';
|
|
12
|
-
import {
|
|
12
|
+
import { getGovernanceConfig, resolveContextFiles } from '../../project-config-loader';
|
|
13
13
|
import { FreshnessRunner, type FreshnessCheckResult } from '../doc-freshness/runner';
|
|
14
14
|
import { detectSourceRoots } from '../../../utils/detect-source-roots';
|
|
15
|
-
import
|
|
16
|
-
import type {
|
|
15
|
+
import { reconcileCapabilities } from '../capabilities-reconcile';
|
|
16
|
+
import type { DocFreshnessCheck } from '../../../types/project-config';
|
|
17
|
+
import type { ConstraintCheck, CheckEnv } from './types';
|
|
18
|
+
import { formatEvidence } from './types';
|
|
17
19
|
|
|
18
20
|
/**
|
|
19
21
|
* 内置默认文档新鲜度检查配置
|
|
@@ -30,45 +32,31 @@ function getBuiltInDocFreshnessConfig(): DocFreshnessCheck[] {
|
|
|
30
32
|
}
|
|
31
33
|
|
|
32
34
|
/**
|
|
33
|
-
* CAPABILITIES.md
|
|
34
|
-
*
|
|
35
|
-
*
|
|
35
|
+
* CAPABILITIES.md 文件表新鲜度:登记的条目(文件与目录)必须仍存在(ADR-0009 口径从严)。
|
|
36
|
+
* 判定逻辑统一走 capabilities-reconcile;多根查找支持不同项目的源码根
|
|
37
|
+
* (harness=src/, studio=apps/api/src/ 等)。无表格(能力清单格式)时自然零幽灵。
|
|
36
38
|
*/
|
|
37
|
-
function
|
|
39
|
+
function findDeadCapabilityEntries(projectPath: string, env: CheckEnv): string[] {
|
|
38
40
|
try {
|
|
39
41
|
const capabilitiesPath = join(projectPath, 'CAPABILITIES.md');
|
|
40
|
-
if (!existsSync(capabilitiesPath)) return
|
|
42
|
+
if (!existsSync(capabilitiesPath)) return [];
|
|
41
43
|
const content = readFileSync(capabilitiesPath, 'utf-8');
|
|
42
44
|
|
|
43
|
-
const listedFiles: string[] = [];
|
|
44
|
-
const tableRowRegex = /^\|[^|]+\|\s*([^|]+?\.(?:ts|tsx|js|jsx))\s*\|/gm;
|
|
45
|
-
let match;
|
|
46
|
-
while ((match = tableRowRegex.exec(content)) !== null) {
|
|
47
|
-
listedFiles.push(match[1].trim());
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
if (listedFiles.length === 0) return true;
|
|
51
|
-
|
|
52
45
|
const sourceRoots = detectSourceRoots(projectPath);
|
|
53
|
-
const
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
if (existsSync(join(projectPath, root, file))) return true;
|
|
57
|
-
}
|
|
58
|
-
return false;
|
|
59
|
-
};
|
|
60
|
-
|
|
61
|
-
const missing = listedFiles.filter(f => !fileExists(f));
|
|
62
|
-
if (missing.length > 0) {
|
|
63
|
-
// 报出具体文件名:此前只返回 false,CLI 只能打印通用提示,
|
|
64
|
-
// 幽灵条目 basename 碰撞时 sync-docs 也不剔除,用户无从定位(2026-08-08 studio CI 4 连红)
|
|
65
|
-
console.error(`[docs_freshness] CAPABILITIES.md 列出的文件不存在: ${missing.join(', ')}`);
|
|
66
|
-
return false;
|
|
46
|
+
const population: string[] = [];
|
|
47
|
+
for (const root of sourceRoots) {
|
|
48
|
+
if (existsSync(join(projectPath, root))) population.push(...env.srcScan(root));
|
|
67
49
|
}
|
|
68
50
|
|
|
69
|
-
|
|
51
|
+
const verdict = reconcileCapabilities({
|
|
52
|
+
content,
|
|
53
|
+
populationFiles: population,
|
|
54
|
+
sourceRoots,
|
|
55
|
+
fileExists: (rel) => existsSync(join(projectPath, rel)),
|
|
56
|
+
});
|
|
57
|
+
return verdict.deadEntries;
|
|
70
58
|
} catch {
|
|
71
|
-
return
|
|
59
|
+
return [];
|
|
72
60
|
}
|
|
73
61
|
}
|
|
74
62
|
|
|
@@ -77,7 +65,7 @@ function checkCapabilitiesFreshness(projectPath: string): boolean {
|
|
|
77
65
|
*
|
|
78
66
|
* 判定信号(任一命中即视为采用了文档新鲜度约定):
|
|
79
67
|
* - 配置了 governance.doc_freshness.checks
|
|
80
|
-
* - 配置了 governance.context_files
|
|
68
|
+
* - 配置了 governance.context_files 且约定有效(enabled + 非空 required_dirs)
|
|
81
69
|
* - 项目根存在 CAPABILITIES.md
|
|
82
70
|
* - 项目根存在 CHANGELOG.md / CHANGELOG
|
|
83
71
|
*
|
|
@@ -89,26 +77,12 @@ function hasFreshnessTargets(projectPath: string): boolean {
|
|
|
89
77
|
return true;
|
|
90
78
|
}
|
|
91
79
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
const freshnessConfig = governance?.doc_freshness as DocFreshnessConfig | undefined;
|
|
97
|
-
if (freshnessConfig?.checks && freshnessConfig.checks.length > 0) return true;
|
|
98
|
-
|
|
99
|
-
const contextFiles = governance?.context_files as Record<string, unknown> | undefined;
|
|
100
|
-
if (
|
|
101
|
-
contextFiles?.enabled &&
|
|
102
|
-
Array.isArray(contextFiles.required_dirs) &&
|
|
103
|
-
(contextFiles.required_dirs as string[]).length > 0
|
|
104
|
-
) {
|
|
105
|
-
return true;
|
|
106
|
-
}
|
|
107
|
-
} catch {
|
|
108
|
-
// 配置不可读视为无配置
|
|
80
|
+
const governance = getGovernanceConfig(projectPath);
|
|
81
|
+
if (governance?.doc_freshness?.checks && governance.doc_freshness.checks.length > 0) {
|
|
82
|
+
return true;
|
|
109
83
|
}
|
|
110
84
|
|
|
111
|
-
return
|
|
85
|
+
return resolveContextFiles(projectPath).state === 'enabled';
|
|
112
86
|
}
|
|
113
87
|
|
|
114
88
|
export const docsFreshness: ConstraintCheck = {
|
|
@@ -119,26 +93,27 @@ export const docsFreshness: ConstraintCheck = {
|
|
|
119
93
|
// ADR-0001 存在性探测:项目无任何 freshness 配置/目标 → skip(不计 pass/fail)
|
|
120
94
|
if (!hasFreshnessTargets(projectPath)) return 'skip';
|
|
121
95
|
|
|
122
|
-
// Step 1: 文件表格式 —
|
|
123
|
-
|
|
96
|
+
// Step 1: 文件表格式 — 登记的条目(文件+目录)是否仍存在(ADR-0009)
|
|
97
|
+
const deadEntries = findDeadCapabilityEntries(projectPath, env);
|
|
98
|
+
if (deadEntries.length > 0) {
|
|
99
|
+
// 证据通道点名条目(harness#119):此前是 console.error 侧信道(2026-08-08 studio
|
|
100
|
+
// CI 4 连红时的临时办法),CLI 结构化输出与 trace 两头都拿不到,
|
|
101
|
+
// 铁律拦截时用户只看到一句通用提示,basename 碰撞下无从定位
|
|
102
|
+
return {
|
|
103
|
+
pass: false,
|
|
104
|
+
evidence: formatEvidence('CAPABILITIES.md 登记的条目不存在', deadEntries),
|
|
105
|
+
};
|
|
106
|
+
}
|
|
124
107
|
|
|
125
108
|
// Step 2: 能力清单格式 + CLAUDE.md + CHANGELOG — 通过 FreshnessRunner
|
|
126
109
|
try {
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
const contextFiles = governance?.context_files as Record<string, unknown> | undefined;
|
|
136
|
-
if (contextFiles?.enabled && Array.isArray(contextFiles.required_dirs)) {
|
|
137
|
-
requiredDirs = contextFiles.required_dirs as string[];
|
|
138
|
-
}
|
|
139
|
-
} catch {
|
|
140
|
-
// 配置解析失败,使用默认
|
|
141
|
-
}
|
|
110
|
+
const freshnessConfig = getGovernanceConfig(projectPath)?.doc_freshness;
|
|
111
|
+
|
|
112
|
+
// context_files 三态统一口径(工单 84):约定已立但无目标(enabled 但
|
|
113
|
+
// required_dirs 缺失/空)→ skip,与 context_doc_sync 同构;不再静默放行
|
|
114
|
+
const contextFiles = resolveContextFiles(projectPath);
|
|
115
|
+
if (contextFiles.state === 'enabled-empty') return 'skip';
|
|
116
|
+
const requiredDirs = contextFiles.state === 'enabled' ? contextFiles.dirs : undefined;
|
|
142
117
|
|
|
143
118
|
const runner = new FreshnessRunner();
|
|
144
119
|
let results: FreshnessCheckResult[];
|
|
@@ -149,7 +124,16 @@ export const docsFreshness: ConstraintCheck = {
|
|
|
149
124
|
results = runner.runAll({ checks: getBuiltInDocFreshnessConfig() }, projectPath, { requiredDirs });
|
|
150
125
|
}
|
|
151
126
|
|
|
152
|
-
|
|
127
|
+
const failed = results.filter(r => !r.pass);
|
|
128
|
+
if (failed.length > 0) {
|
|
129
|
+
return {
|
|
130
|
+
pass: false,
|
|
131
|
+
evidence: formatEvidence(
|
|
132
|
+
'文档新鲜度检查未通过',
|
|
133
|
+
failed.map(r => `${r.label}: ${r.message ?? '未通过'}`)
|
|
134
|
+
),
|
|
135
|
+
};
|
|
136
|
+
}
|
|
153
137
|
} catch {
|
|
154
138
|
// FreshnessRunner 失败不影响整体
|
|
155
139
|
}
|
|
@@ -10,42 +10,24 @@
|
|
|
10
10
|
* 不强制迁移;两处都没有才报违规。
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
|
-
import { readFileSync } from 'fs';
|
|
14
13
|
import { join } from 'path';
|
|
15
14
|
import { loadRawProjectConfig } from '../../project-config-loader';
|
|
15
|
+
import { hasGovernanceContract, hasPreserveBlock, readIfExists } from '../injection-writer';
|
|
16
16
|
import type { ConstraintCheck } from './types';
|
|
17
17
|
|
|
18
18
|
/** 治理契约 PRESERVE 段名(ADR 落点模型约定) */
|
|
19
19
|
export const GOVERNANCE_PRESERVE_NAME = 'governance';
|
|
20
20
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
/** AGENTS.md 是否存在非空 PRESERVE:governance 块(标记须独占一行,与 preserve-block.ts 同语义) */
|
|
21
|
+
/** AGENTS.md 是否存在非空 PRESERVE:governance 块(切片判定收口 injection-writer.hasPreserveBlock,#83) */
|
|
24
22
|
export function hasGovernancePreserveBlock(agentsMdPath: string): boolean {
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
content = readFileSync(agentsMdPath, 'utf-8');
|
|
28
|
-
} catch {
|
|
29
|
-
return false;
|
|
30
|
-
}
|
|
31
|
-
const beginMatch = GOVERNANCE_BEGIN_RE.exec(content);
|
|
32
|
-
if (!beginMatch) return false;
|
|
33
|
-
const rest = content.slice(beginMatch.index + beginMatch[0].length);
|
|
34
|
-
const endIdx = rest.indexOf(`<!-- /PRESERVE:${GOVERNANCE_PRESERVE_NAME} -->`);
|
|
35
|
-
if (endIdx === -1) return false;
|
|
36
|
-
// 块体(首尾标记之间)去空白后非空才算「在场」
|
|
37
|
-
return rest.slice(0, endIdx).trim().length > 0;
|
|
23
|
+
const content = readIfExists(agentsMdPath);
|
|
24
|
+
return content !== null && hasPreserveBlock(content, GOVERNANCE_PRESERVE_NAME);
|
|
38
25
|
}
|
|
39
26
|
|
|
40
|
-
/** CLAUDE.md
|
|
27
|
+
/** CLAUDE.md 是否有治理契约在场(判定收口 injection-writer.hasGovernanceContract,#83;旧模型仓豁免) */
|
|
41
28
|
export function hasClaudeGovernance(claudeMdPath: string): boolean {
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
content = readFileSync(claudeMdPath, 'utf-8');
|
|
45
|
-
} catch {
|
|
46
|
-
return false;
|
|
47
|
-
}
|
|
48
|
-
return /^##\s+Governance Rules/m.test(content) || content.includes('HARNESS_CONSTRAINTS_START');
|
|
29
|
+
const content = readIfExists(claudeMdPath);
|
|
30
|
+
return content !== null && hasGovernanceContract(content);
|
|
49
31
|
}
|
|
50
32
|
|
|
51
33
|
export const governancePresence: ConstraintCheck = {
|
|
@@ -80,5 +80,12 @@ export function registeredCheckCount(): number {
|
|
|
80
80
|
return registry.size;
|
|
81
81
|
}
|
|
82
82
|
|
|
83
|
-
export { buildCheckEnv } from './types';
|
|
84
|
-
export type {
|
|
83
|
+
export { buildCheckEnv, normalizeCheckOutcome } from './types';
|
|
84
|
+
export type {
|
|
85
|
+
ConstraintCheck,
|
|
86
|
+
CheckEnv,
|
|
87
|
+
CheckOutcome,
|
|
88
|
+
CheckDetail,
|
|
89
|
+
NormalizedOutcome,
|
|
90
|
+
EvidenceProviders,
|
|
91
|
+
} from './types';
|
|
@@ -4,10 +4,11 @@
|
|
|
4
4
|
|
|
5
5
|
import type { ConstraintCheck } from './types';
|
|
6
6
|
|
|
7
|
+
// m 标志必需:真实 diff 首行恒为 `diff --git`,缺 m 则 ^ 永不命中删除行(铁律静默失效)
|
|
7
8
|
const DELETED_TEST_PATTERNS = [
|
|
8
|
-
/^-\s*(test|it|describe)\s*\(
|
|
9
|
-
/^-\s*expect\s*\(
|
|
10
|
-
/^-\s*\/\/\s*test
|
|
9
|
+
/^-\s*(test|it|describe)\s*\(/m, // 删除 test/it/describe
|
|
10
|
+
/^-\s*expect\s*\(/m, // 删除 expect
|
|
11
|
+
/^-\s*\/\/\s*test/m, // 删除注释的 test
|
|
11
12
|
];
|
|
12
13
|
|
|
13
14
|
export const noTestSimplification: ConstraintCheck = {
|
|
@@ -29,8 +29,8 @@ export interface CheckEnv {
|
|
|
29
29
|
/**
|
|
30
30
|
* 证据提供者组:git diff / 源码扫描的 memoized I/O
|
|
31
31
|
*
|
|
32
|
-
* 由调用方绑定后传入 buildCheckEnv
|
|
33
|
-
* run
|
|
32
|
+
* 由调用方绑定后传入 buildCheckEnv(#87:git 两项绑 GitEvidence adapter 实例,
|
|
33
|
+
* 一次 run 一份,命令级 memo 在 adapter 层);工厂本身不做 memoization。
|
|
34
34
|
*/
|
|
35
35
|
export interface EvidenceProviders {
|
|
36
36
|
/** staged 全量 diff */
|
|
@@ -73,8 +73,64 @@ export function buildCheckEnv(
|
|
|
73
73
|
* - true = 满足(pass)
|
|
74
74
|
* - false = 违反(fail)
|
|
75
75
|
* - 'skip' = 未评估(项目未采用对应约定,或证据 flag 未接线),不计 pass/fail
|
|
76
|
+
* - CheckDetail = 判定 + 证据行(harness#119)
|
|
76
77
|
*/
|
|
77
|
-
export type CheckOutcome = boolean | 'skip';
|
|
78
|
+
export type CheckOutcome = boolean | 'skip' | CheckDetail;
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* 带证据的检查结果(harness#119)
|
|
82
|
+
*
|
|
83
|
+
* 动机:只回布尔时,fail 的具体原因(哪个文件没登记)在 CLI 与 trace 两头都落脚不了,
|
|
84
|
+
* 一条恒红的约束无法被诊断。证据行由 checker 自行措辞(自描述、可直接给人看),
|
|
85
|
+
* 编排层只负责透传与打印,不参与解释内容。
|
|
86
|
+
*
|
|
87
|
+
* `pass: true` + 非空 evidence = 「满足但有提示」:不进 pass/fail 统计口径,
|
|
88
|
+
* 仅作为可观测输出(如仓库级文档漂移——与本次变更无因果,不该判违规)。
|
|
89
|
+
*/
|
|
90
|
+
export interface CheckDetail {
|
|
91
|
+
/** false = 违反;true = 满足 */
|
|
92
|
+
pass: boolean;
|
|
93
|
+
/** 证据行(每条自描述,如「变更文件未登记: src/foo.ts」) */
|
|
94
|
+
evidence?: string[];
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/** 归一后的检查结果:编排层 / gate 唯一消费形状 */
|
|
98
|
+
export interface NormalizedOutcome {
|
|
99
|
+
satisfied: boolean;
|
|
100
|
+
skipped: boolean;
|
|
101
|
+
evidence: string[];
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/** 证据条数上限:trace 是 JSONL,缺口上百项时不能整仓落盘 */
|
|
105
|
+
export const MAX_EVIDENCE_ITEMS = 10;
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* 组装证据行:一行说明 + 逐条依据(超限截断)
|
|
109
|
+
*
|
|
110
|
+
* 每行自描述且不带缩进——缩进由消费端(CLI / gate 理由 / 铁律异常文案)决定,trace 原样存。
|
|
111
|
+
* 修复入口不写在这里:那是各约束自己的事,写进各自的 summary 行(docs_freshness 的
|
|
112
|
+
* 幽灵条目与 sync-docs 无关,共用一个指针会误导)。
|
|
113
|
+
*/
|
|
114
|
+
export function formatEvidence(summary: string, items: string[]): string[] {
|
|
115
|
+
const shown = items.slice(0, MAX_EVIDENCE_ITEMS);
|
|
116
|
+
const hidden = items.length - shown.length;
|
|
117
|
+
return [...(summary ? [summary] : []), ...shown, ...(hidden > 0 ? [`…另 ${hidden} 项`] : [])];
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* 归一 CheckOutcome(boolean | 'skip' | CheckDetail)为统一形状
|
|
122
|
+
*
|
|
123
|
+
* skip 恒不携带证据:未评估的约束不得留下证据行(否则统计侧会把「没查」读成「查出问题」)。
|
|
124
|
+
*/
|
|
125
|
+
export function normalizeCheckOutcome(outcome: CheckOutcome): NormalizedOutcome {
|
|
126
|
+
if (outcome === 'skip') return { satisfied: true, skipped: true, evidence: [] };
|
|
127
|
+
if (typeof outcome === 'boolean') return { satisfied: outcome, skipped: false, evidence: [] };
|
|
128
|
+
return {
|
|
129
|
+
satisfied: outcome.pass,
|
|
130
|
+
skipped: false,
|
|
131
|
+
evidence: outcome.evidence ?? [],
|
|
132
|
+
};
|
|
133
|
+
}
|
|
78
134
|
|
|
79
135
|
/**
|
|
80
136
|
* 单条约束检查实现
|
|
@@ -82,7 +138,7 @@ export type CheckOutcome = boolean | 'skip';
|
|
|
82
138
|
export interface ConstraintCheck {
|
|
83
139
|
/** 约束 ID(与 definitions 一致) */
|
|
84
140
|
id: string;
|
|
85
|
-
/** 检查主体:true = 满足;false = 违反;'skip' =
|
|
141
|
+
/** 检查主体:true = 满足;false = 违反;'skip' = 未评估;CheckDetail = 判定 + 证据行 */
|
|
86
142
|
evaluate(env: CheckEnv): Promise<CheckOutcome> | CheckOutcome;
|
|
87
143
|
}
|
|
88
144
|
|