@dommaker/harness 1.3.0 → 1.4.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 +8 -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 +76 -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 +29 -214
- 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 +21 -15
- package/dist/cli/commands/knowledge.d.ts.map +1 -1
- package/dist/cli/commands/knowledge.js +214 -199
- 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 +2 -1
- package/dist/cli/commands/update-user-model.d.ts.map +1 -1
- package/dist/cli/commands/update-user-model.js +31 -45
- 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 +64 -115
- package/dist/core/constraints/checker.js.map +1 -1
- package/dist/core/constraints/checkers/capability-sync.d.ts +4 -3
- package/dist/core/constraints/checkers/capability-sync.d.ts.map +1 -1
- package/dist/core/constraints/checkers/capability-sync.js +29 -69
- 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 +37 -63
- 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/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 +2 -2
- 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.map +1 -1
- package/dist/gates/checker-gate.js +6 -11
- 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 +0 -18
- package/dist/types/constraint.d.ts.map +1 -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/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 +7 -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 +142 -106
- 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 +22 -7
- 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 +101 -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 +378 -382
- 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 +169 -0
- package/src/cli/commands/__tests__/registry.test.ts +69 -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 +62 -33
- 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 +88 -65
- 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 +36 -222
- package/src/cli/commands/failure.ts +33 -26
- package/src/cli/commands/init.ts +166 -220
- package/src/cli/commands/knowledge.ts +225 -203
- 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 +33 -45
- 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 +9 -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 +75 -130
- package/src/core/constraints/checkers/__tests__/capability-sync.test.ts +214 -0
- package/src/core/constraints/checkers/__tests__/context-doc-sync.test.ts +77 -0
- package/src/core/constraints/checkers/__tests__/docs-freshness.test.ts +117 -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 +145 -0
- package/src/core/constraints/checkers/capability-sync.ts +29 -88
- package/src/core/constraints/checkers/context-doc-sync.ts +15 -25
- package/src/core/constraints/checkers/docs-freshness.ts +40 -69
- package/src/core/constraints/checkers/governance-presence.ts +7 -25
- package/src/core/constraints/checkers/no-test-simplification.ts +4 -3
- package/src/core/constraints/checkers/types.ts +2 -2
- 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 +6 -3
- 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__/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 +8 -7
- 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 +0 -25
- 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/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
|
@@ -3,7 +3,8 @@
|
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
5
|
import { describe, it, expect, beforeAll, afterAll } from '@jest/globals';
|
|
6
|
-
import { PassesGate, createPassesGate } from '../core/validators/passes-gate';
|
|
6
|
+
import { PassesGate, createPassesGate, detectTestCommand } from '../core/validators/passes-gate';
|
|
7
|
+
import type { TaskTestResult } from '../types/passes-gate';
|
|
7
8
|
import { mkdirSync, rmSync, writeFileSync } from 'fs';
|
|
8
9
|
import { join } from 'path';
|
|
9
10
|
|
|
@@ -60,13 +61,13 @@ describe('PassesGate', () => {
|
|
|
60
61
|
});
|
|
61
62
|
|
|
62
63
|
describe('runTests', () => {
|
|
63
|
-
//
|
|
64
|
-
it
|
|
65
|
-
const result = await gate.runTests();
|
|
66
|
-
|
|
67
|
-
expect(result).
|
|
68
|
-
expect(result.
|
|
69
|
-
expect(result.duration).
|
|
64
|
+
// 执行根由调用方传入(#95):tempDir 的 package.json 测试命令是 echo,不再跑真实套件
|
|
65
|
+
it('应该返回测试结果', async () => {
|
|
66
|
+
const result = await gate.runTests(tempDir);
|
|
67
|
+
|
|
68
|
+
expect(result.passed).toBe(true);
|
|
69
|
+
expect(result.passedTests).toBe(1);
|
|
70
|
+
expect(result.duration).toBeGreaterThanOrEqual(0);
|
|
70
71
|
});
|
|
71
72
|
});
|
|
72
73
|
|
|
@@ -79,6 +80,93 @@ describe('PassesGate', () => {
|
|
|
79
80
|
});
|
|
80
81
|
});
|
|
81
82
|
|
|
83
|
+
// 探测正本行为钉住(架构评审 A2:CLI/core 双版收口后的统一语义,
|
|
84
|
+
// 此前 e2e 优先级、echo 排除、兜底均无测试钉住)
|
|
85
|
+
describe('detectTestCommand 正本(统一探测顺序)', () => {
|
|
86
|
+
const detectDir = join(process.cwd(), 'temp-test-detect-command');
|
|
87
|
+
|
|
88
|
+
const writePkg = (dir: string, scripts: Record<string, string>) => {
|
|
89
|
+
mkdirSync(dir, { recursive: true });
|
|
90
|
+
writeFileSync(join(dir, 'package.json'), JSON.stringify({ name: 'detect-case', scripts }));
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
afterAll(() => {
|
|
94
|
+
try {
|
|
95
|
+
rmSync(detectDir, { recursive: true, force: true });
|
|
96
|
+
} catch {
|
|
97
|
+
// ignore
|
|
98
|
+
}
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
it('test:ci 与 test 同存时优先 test:ci', async () => {
|
|
102
|
+
const dir = join(detectDir, 'ci-over-test');
|
|
103
|
+
writePkg(dir, { test: 'jest', 'test:ci': 'jest --ci' });
|
|
104
|
+
|
|
105
|
+
expect(await detectTestCommand(dir)).toBe('npm run test:ci');
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
it('echo 占位脚本不算 test,同存 e2e 时落到 e2e', async () => {
|
|
109
|
+
const dir = join(detectDir, 'echo-placeholder');
|
|
110
|
+
writePkg(dir, { test: 'echo "Error: no test specified"', 'test:e2e': 'playwright test' });
|
|
111
|
+
|
|
112
|
+
expect(await detectTestCommand(dir)).toBe('npm run test:e2e');
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
it('仅有 echo 占位且无其他标记时返回 undefined', async () => {
|
|
116
|
+
const dir = join(detectDir, 'echo-only');
|
|
117
|
+
writePkg(dir, { test: 'echo "Error: no test specified"' });
|
|
118
|
+
|
|
119
|
+
expect(await detectTestCommand(dir)).toBeUndefined();
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
it('无 test/test:ci 时 test:e2e 命中,无 e2e 时 test:coverage 命中', async () => {
|
|
123
|
+
const e2eDir = join(detectDir, 'e2e-only');
|
|
124
|
+
writePkg(e2eDir, { 'test:e2e': 'vitest e2e', 'test:coverage': 'vitest --coverage' });
|
|
125
|
+
expect(await detectTestCommand(e2eDir)).toBe('npm run test:e2e');
|
|
126
|
+
|
|
127
|
+
const covDir = join(detectDir, 'coverage-only');
|
|
128
|
+
writePkg(covDir, { 'test:coverage': 'vitest --coverage' });
|
|
129
|
+
expect(await detectTestCommand(covDir)).toBe('npm run test:coverage');
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
it('Python 标记 pyproject.toml 或 pytest.ini 任一命中', async () => {
|
|
133
|
+
const pyprojectDir = join(detectDir, 'py-pyproject');
|
|
134
|
+
mkdirSync(pyprojectDir, { recursive: true });
|
|
135
|
+
writeFileSync(join(pyprojectDir, 'pyproject.toml'), '[project]\nname = "x"\n');
|
|
136
|
+
expect(await detectTestCommand(pyprojectDir)).toBe('pytest');
|
|
137
|
+
|
|
138
|
+
const pytestIniDir = join(detectDir, 'py-pytest-ini');
|
|
139
|
+
mkdirSync(pytestIniDir, { recursive: true });
|
|
140
|
+
writeFileSync(join(pytestIniDir, 'pytest.ini'), '[pytest]\n');
|
|
141
|
+
expect(await detectTestCommand(pytestIniDir)).toBe('pytest');
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
it('go.mod 命中 go test,无任何标记返回 undefined', async () => {
|
|
145
|
+
const goDir = join(detectDir, 'go-mod');
|
|
146
|
+
mkdirSync(goDir, { recursive: true });
|
|
147
|
+
writeFileSync(join(goDir, 'go.mod'), 'module example.com/x\n');
|
|
148
|
+
expect(await detectTestCommand(goDir)).toBe('go test ./...');
|
|
149
|
+
|
|
150
|
+
const emptyDir = join(detectDir, 'empty');
|
|
151
|
+
mkdirSync(emptyDir, { recursive: true });
|
|
152
|
+
expect(await detectTestCommand(emptyDir)).toBeUndefined();
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
it('探测失败时 runTests 与 setPasses 双路径 fail-closed', async () => {
|
|
156
|
+
const emptyDir = join(detectDir, 'fail-closed');
|
|
157
|
+
mkdirSync(emptyDir, { recursive: true });
|
|
158
|
+
|
|
159
|
+
const runResult = await gate.runTests(emptyDir);
|
|
160
|
+
expect(runResult.passed).toBe(false);
|
|
161
|
+
expect(runResult.message).toBe('未检测到测试命令');
|
|
162
|
+
|
|
163
|
+
const setResult = await gate.setPasses('task-nocmd', true, emptyDir);
|
|
164
|
+
expect(setResult.allowed).toBe(false);
|
|
165
|
+
expect(setResult.testResult?.passed).toBe(false);
|
|
166
|
+
expect(setResult.testResult?.output).toBe('未检测到测试命令');
|
|
167
|
+
});
|
|
168
|
+
});
|
|
169
|
+
|
|
82
170
|
describe('checkTestFileChanges', () => {
|
|
83
171
|
it('应该检测测试文件变更', async () => {
|
|
84
172
|
// 无 git 变更时返回空数组
|
|
@@ -88,104 +176,6 @@ describe('PassesGate', () => {
|
|
|
88
176
|
});
|
|
89
177
|
});
|
|
90
178
|
|
|
91
|
-
describe('扩展点支持', () => {
|
|
92
|
-
it('应该能注册扩展', () => {
|
|
93
|
-
gate.registerExtension('custom', {
|
|
94
|
-
name: 'custom',
|
|
95
|
-
run: async () => ({
|
|
96
|
-
passed: true,
|
|
97
|
-
command: 'custom-test',
|
|
98
|
-
timestamp: new Date(),
|
|
99
|
-
}),
|
|
100
|
-
});
|
|
101
|
-
|
|
102
|
-
const names = gate.getExtensionNames();
|
|
103
|
-
expect(names).toContain('custom');
|
|
104
|
-
});
|
|
105
|
-
|
|
106
|
-
it('应该能注销扩展', () => {
|
|
107
|
-
gate.registerExtension('temp', {
|
|
108
|
-
name: 'temp',
|
|
109
|
-
run: async () => ({
|
|
110
|
-
passed: true,
|
|
111
|
-
command: 'temp-test',
|
|
112
|
-
timestamp: new Date(),
|
|
113
|
-
}),
|
|
114
|
-
});
|
|
115
|
-
|
|
116
|
-
const removed = gate.unregisterExtension('temp');
|
|
117
|
-
expect(removed).toBe(true);
|
|
118
|
-
|
|
119
|
-
const names = gate.getExtensionNames();
|
|
120
|
-
expect(names).not.toContain('temp');
|
|
121
|
-
});
|
|
122
|
-
|
|
123
|
-
it('runAllTests 应该运行所有测试包括扩展', async () => {
|
|
124
|
-
gate.registerExtension('puppeteer', {
|
|
125
|
-
name: 'puppeteer',
|
|
126
|
-
run: async () => ({
|
|
127
|
-
passed: true,
|
|
128
|
-
command: 'puppeteer-test',
|
|
129
|
-
timestamp: new Date(),
|
|
130
|
-
}),
|
|
131
|
-
});
|
|
132
|
-
|
|
133
|
-
const results = await gate.runAllTests(tempDir);
|
|
134
|
-
|
|
135
|
-
expect(results.length).toBeGreaterThan(1); // 单元测试 + puppeteer
|
|
136
|
-
expect(results.some(r => r.type === 'puppeteer')).toBe(true);
|
|
137
|
-
});
|
|
138
|
-
|
|
139
|
-
it('checkAllPasses 应该返回综合结果', async () => {
|
|
140
|
-
gate.registerExtension('passing-ext', {
|
|
141
|
-
name: 'passing-ext',
|
|
142
|
-
run: async () => ({
|
|
143
|
-
passed: true,
|
|
144
|
-
command: 'passing-test',
|
|
145
|
-
timestamp: new Date(),
|
|
146
|
-
}),
|
|
147
|
-
});
|
|
148
|
-
|
|
149
|
-
const result = await gate.checkAllPasses(tempDir);
|
|
150
|
-
|
|
151
|
-
expect(result.passed).toBeDefined();
|
|
152
|
-
expect(result.results).toBeDefined();
|
|
153
|
-
expect(Array.isArray(result.failedTypes)).toBe(true);
|
|
154
|
-
});
|
|
155
|
-
|
|
156
|
-
it('checkAllPasses 应该返回失败类型', async () => {
|
|
157
|
-
const failingGate = createPassesGate({ enabled: true });
|
|
158
|
-
failingGate.registerExtension('failing-ext', {
|
|
159
|
-
name: 'failing-ext',
|
|
160
|
-
run: async () => ({
|
|
161
|
-
passed: false,
|
|
162
|
-
command: 'failing-test',
|
|
163
|
-
timestamp: new Date(),
|
|
164
|
-
}),
|
|
165
|
-
});
|
|
166
|
-
|
|
167
|
-
const result = await failingGate.checkAllPasses(tempDir);
|
|
168
|
-
|
|
169
|
-
expect(result.failedTypes).toContain('failing-ext');
|
|
170
|
-
});
|
|
171
|
-
|
|
172
|
-
it('扩展抛错应返回失败结果', async () => {
|
|
173
|
-
const errorGate = createPassesGate({ enabled: true });
|
|
174
|
-
errorGate.registerExtension('error-ext', {
|
|
175
|
-
name: 'error-ext',
|
|
176
|
-
run: async () => {
|
|
177
|
-
throw new Error('Extension error');
|
|
178
|
-
},
|
|
179
|
-
});
|
|
180
|
-
|
|
181
|
-
const results = await errorGate.runAllTests(tempDir);
|
|
182
|
-
|
|
183
|
-
const errorResult = results.find(r => r.type === 'error-ext');
|
|
184
|
-
expect(errorResult?.passed).toBe(false);
|
|
185
|
-
expect(errorResult?.error).toContain('Extension error');
|
|
186
|
-
});
|
|
187
|
-
});
|
|
188
|
-
|
|
189
179
|
describe('getTestResult', () => {
|
|
190
180
|
it('应该返回已存储的测试结果', async () => {
|
|
191
181
|
const result = await gate.setPasses('stored-task', true, tempDir);
|
|
@@ -228,4 +218,50 @@ describe('PassesGate', () => {
|
|
|
228
218
|
rmSync(retryDir, { recursive: true, force: true });
|
|
229
219
|
});
|
|
230
220
|
});
|
|
221
|
+
|
|
222
|
+
/**
|
|
223
|
+
* #94 裁决 B:harness 核心判定不管覆盖率 —— 从 stdout 抠覆盖率的 regex 路
|
|
224
|
+
* (extractCoverage → TaskTestResult.coverage)整体删除,结果面不再有 coverage 字段。
|
|
225
|
+
*/
|
|
226
|
+
describe('覆盖率取数路删除(harness#94)', () => {
|
|
227
|
+
const covDir = join(process.cwd(), 'temp-test-no-coverage-field');
|
|
228
|
+
|
|
229
|
+
beforeAll(() => {
|
|
230
|
+
mkdirSync(covDir, { recursive: true });
|
|
231
|
+
|
|
232
|
+
// 输出里放一份 jest 覆盖率表:删除前 extractCoverage 会从中抠出 80.5 填进结果字段
|
|
233
|
+
writeFileSync(join(covDir, 'package.json'), JSON.stringify({
|
|
234
|
+
name: 'coverage-project',
|
|
235
|
+
scripts: { test: 'echo "All files | 80.50 | 70.21 | 83.33 | 79.59 |"' },
|
|
236
|
+
}));
|
|
237
|
+
});
|
|
238
|
+
|
|
239
|
+
afterAll(() => {
|
|
240
|
+
try {
|
|
241
|
+
rmSync(covDir, { recursive: true, force: true });
|
|
242
|
+
} catch {
|
|
243
|
+
// ignore
|
|
244
|
+
}
|
|
245
|
+
});
|
|
246
|
+
|
|
247
|
+
it('setPasses 结果不带 coverage 字段', async () => {
|
|
248
|
+
const covGate = createPassesGate({ enabled: true, requireEvidence: false });
|
|
249
|
+
|
|
250
|
+
const result = await covGate.setPasses('cov-task', true, covDir);
|
|
251
|
+
|
|
252
|
+
expect(result.testResult?.passed).toBe(true);
|
|
253
|
+
expect(result.testResult).not.toHaveProperty('coverage');
|
|
254
|
+
});
|
|
255
|
+
|
|
256
|
+
it('TaskTestResult 公开类型面不再接受 coverage 字段', () => {
|
|
257
|
+
const testResult: TaskTestResult = {
|
|
258
|
+
passed: true,
|
|
259
|
+
command: 'npm test',
|
|
260
|
+
// @ts-expect-error coverage 随 harness#94 删除,类型面不接受该字段
|
|
261
|
+
coverage: 85,
|
|
262
|
+
};
|
|
263
|
+
|
|
264
|
+
expect(testResult.passed).toBe(true);
|
|
265
|
+
});
|
|
266
|
+
});
|
|
231
267
|
});
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
* - trace 记录 result: 'skip';TraceAnalyzer 的 pass/fail 率分母不计 skip
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
|
-
import { describe, it, expect, beforeAll, afterAll
|
|
12
|
+
import { describe, it, expect, beforeAll, afterAll } from '@jest/globals';
|
|
13
13
|
import { ConstraintChecker } from '../core/constraints/checker';
|
|
14
14
|
import { detectTrigger, buildConstraintContext } from '../core/constraints/context-builder';
|
|
15
15
|
import { IRON_LAWS } from '../core/constraints/definitions';
|
|
@@ -20,7 +20,8 @@ import * as fs from 'fs';
|
|
|
20
20
|
import * as path from 'path';
|
|
21
21
|
import { execSync } from 'child_process';
|
|
22
22
|
|
|
23
|
-
|
|
23
|
+
/** 套件共用 checker:显式 no-op 记录器(trace 断言的用例自带记录器实例) */
|
|
24
|
+
const checker = new ConstraintChecker({ record: () => undefined });
|
|
24
25
|
|
|
25
26
|
function makeConstraint(
|
|
26
27
|
id: string,
|
|
@@ -51,11 +52,6 @@ describe('skip 三态语义(ADR-0001)', () => {
|
|
|
51
52
|
}
|
|
52
53
|
});
|
|
53
54
|
|
|
54
|
-
afterEach(() => {
|
|
55
|
-
// 复位 trace recorder,避免泄漏到其他用例
|
|
56
|
-
checker.setTraceRecorder({ record: () => undefined });
|
|
57
|
-
});
|
|
58
|
-
|
|
59
55
|
describe('capability_sync 存在性探测', () => {
|
|
60
56
|
it('无 CAPABILITIES.md(未采用约定)→ skip,不计 fail', async () => {
|
|
61
57
|
const dir = path.join(tempDir, 'cap-skip');
|
|
@@ -289,9 +285,9 @@ describe('skip 三态语义(ADR-0001)', () => {
|
|
|
289
285
|
describe('trace 的 skip 形态', () => {
|
|
290
286
|
it('recordTrace:skip 记录为 result: skip', async () => {
|
|
291
287
|
const records: ExecutionTrace[] = [];
|
|
292
|
-
|
|
288
|
+
const recording = new ConstraintChecker({ record: (t) => records.push(t) });
|
|
293
289
|
|
|
294
|
-
await
|
|
290
|
+
await recording.checkConstraints({
|
|
295
291
|
operation: 'code_implementation',
|
|
296
292
|
projectPath: path.join(tempDir, 'empty'),
|
|
297
293
|
});
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 命令契约测试(架构评审候选7)
|
|
3
|
+
*
|
|
4
|
+
* Seam:src/cli/command-contract.ts —— 命令实现的返回形状 + 输出注入面。
|
|
5
|
+
* 关键不变量:注入缺省 io(process 流)时,log/logError 的输出字节与
|
|
6
|
+
* console.log/console.error 逐字一致(CLI 语法冻结护栏:输出文案不得漂移)。
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { Writable } from 'stream';
|
|
10
|
+
import {
|
|
11
|
+
captureIO,
|
|
12
|
+
lastJsonOutput,
|
|
13
|
+
log,
|
|
14
|
+
logError,
|
|
15
|
+
processIO,
|
|
16
|
+
type CommandIO,
|
|
17
|
+
type CommandResult,
|
|
18
|
+
} from '../command-contract';
|
|
19
|
+
|
|
20
|
+
/** 同步收集写入 chunk 的最小可写流(console.Console 与 CommandIO 共用同一 sink) */
|
|
21
|
+
class Sink extends Writable {
|
|
22
|
+
private chunks: string[] = [];
|
|
23
|
+
_write(chunk: any, _enc: string, cb: () => void): void {
|
|
24
|
+
this.chunks.push(String(chunk));
|
|
25
|
+
cb();
|
|
26
|
+
}
|
|
27
|
+
reset(): void {
|
|
28
|
+
this.chunks = [];
|
|
29
|
+
}
|
|
30
|
+
get text(): string {
|
|
31
|
+
return this.chunks.join('');
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* 同一参数分别经 Node 的 console(标准实现)与 log/logError(命令侧写入面)
|
|
37
|
+
* 写入同一 sink,返回两者渲染文本。
|
|
38
|
+
*/
|
|
39
|
+
function renderBoth(method: 'log' | 'error', args: unknown[]): { viaConsole: string; viaContract: string } {
|
|
40
|
+
const out = new Sink();
|
|
41
|
+
const err = new Sink();
|
|
42
|
+
const io: CommandIO = { stdout: out, stderr: err };
|
|
43
|
+
|
|
44
|
+
const nodeConsole = new console.Console(out, err);
|
|
45
|
+
(nodeConsole[method] as (...a: unknown[]) => void)(...args);
|
|
46
|
+
const viaConsole = method === 'log' ? out.text : err.text;
|
|
47
|
+
|
|
48
|
+
out.reset();
|
|
49
|
+
err.reset();
|
|
50
|
+
if (method === 'log') log(io, ...args);
|
|
51
|
+
else logError(io, ...args);
|
|
52
|
+
const viaContract = method === 'log' ? out.text : err.text;
|
|
53
|
+
|
|
54
|
+
return { viaConsole, viaContract };
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
describe('log/logError 与 console 输出等价', () => {
|
|
58
|
+
const cases: unknown[][] = [
|
|
59
|
+
[],
|
|
60
|
+
['plain'],
|
|
61
|
+
['%s and %d and %j', 'x', 3, { a: 1 }],
|
|
62
|
+
[{ nested: { deep: [1, 2, 3] } }],
|
|
63
|
+
[null, undefined, 0, false],
|
|
64
|
+
['多字节 ✓ emoji 🎉'],
|
|
65
|
+
[''],
|
|
66
|
+
];
|
|
67
|
+
|
|
68
|
+
it.each(cases.map((c, i) => [i, c] as [number, unknown[]]))(
|
|
69
|
+
'case %i:log(io) 与 console.log 逐字节一致',
|
|
70
|
+
(_i, args) => {
|
|
71
|
+
const { viaConsole, viaContract } = renderBoth('log', args as unknown[]);
|
|
72
|
+
expect(viaContract).toBe(viaConsole);
|
|
73
|
+
},
|
|
74
|
+
);
|
|
75
|
+
|
|
76
|
+
it.each(cases.map((c, i) => [i, c] as [number, unknown[]]))(
|
|
77
|
+
'case %i:logError(io) 与 console.error 逐字节一致',
|
|
78
|
+
(_i, args) => {
|
|
79
|
+
const { viaConsole, viaContract } = renderBoth('error', args as unknown[]);
|
|
80
|
+
expect(viaContract).toBe(viaConsole);
|
|
81
|
+
},
|
|
82
|
+
);
|
|
83
|
+
|
|
84
|
+
it('缺省 io 指向 process 标准流', () => {
|
|
85
|
+
expect(processIO.stdout).toBe(process.stdout);
|
|
86
|
+
expect(processIO.stderr).toBe(process.stderr);
|
|
87
|
+
});
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
describe('captureIO(测试注入面)', () => {
|
|
91
|
+
it('stdout/stderr 分别累积,按行可取', () => {
|
|
92
|
+
const io = captureIO();
|
|
93
|
+
log(io, 'one');
|
|
94
|
+
log(io, 'two %s', 'x');
|
|
95
|
+
logError(io, 'boom');
|
|
96
|
+
expect(io.outLines()).toEqual(['one', 'two x']);
|
|
97
|
+
expect(io.errLines()).toEqual(['boom']);
|
|
98
|
+
expect(io.outText()).toBe('one\ntwo x\n');
|
|
99
|
+
expect(io.errText()).toBe('boom\n');
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
it('无参 log 产生空行(console.log() 语义)', () => {
|
|
103
|
+
const io = captureIO();
|
|
104
|
+
log(io);
|
|
105
|
+
expect(io.outText()).toBe('\n');
|
|
106
|
+
expect(io.outLines()).toEqual(['']);
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
it('outRecords/errRecords 保留每次写入原文(多行 JSON 等同一次打印的整体)', () => {
|
|
110
|
+
const io = captureIO();
|
|
111
|
+
log(io, JSON.stringify({ a: 1 }, null, 2));
|
|
112
|
+
logError(io, 'e1');
|
|
113
|
+
logError(io, 'e2');
|
|
114
|
+
|
|
115
|
+
expect(io.outRecords()).toHaveLength(1);
|
|
116
|
+
expect(JSON.parse(io.outRecords()[0])).toEqual({ a: 1 });
|
|
117
|
+
expect(io.errRecords()).toEqual(['e1\n', 'e2\n']);
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
it('同一命令内 stdout 与 stderr 互不串台', () => {
|
|
121
|
+
const io = captureIO();
|
|
122
|
+
log(io, 'a');
|
|
123
|
+
logError(io, 'b');
|
|
124
|
+
log(io, 'c');
|
|
125
|
+
expect(io.outLines()).toEqual(['a', 'c']);
|
|
126
|
+
expect(io.errLines()).toEqual(['b']);
|
|
127
|
+
});
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
describe('lastJsonOutput(--json 命令输出解析正本,harness#108)', () => {
|
|
131
|
+
it('解析 captureIO 累计的 stdout 为 JSON(缺省 Record 形状)', () => {
|
|
132
|
+
const io = captureIO();
|
|
133
|
+
log(io, JSON.stringify({ sessions: 3, corrections: 3 }));
|
|
134
|
+
expect(lastJsonOutput(io)).toEqual({ sessions: 3, corrections: 3 });
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
it('多行 pretty JSON 整体解析(一次 log 写入)', () => {
|
|
138
|
+
const io = captureIO();
|
|
139
|
+
log(io, JSON.stringify({ a: 1, nested: { b: [2] } }, null, 2));
|
|
140
|
+
expect(lastJsonOutput(io)).toEqual({ a: 1, nested: { b: [2] } });
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
it('泛型参数解锁消费方已知形状(任意字段穿透)', () => {
|
|
144
|
+
const io = captureIO();
|
|
145
|
+
log(io, JSON.stringify({ flywheel: { refCoverage: 0.5 } }));
|
|
146
|
+
expect(lastJsonOutput<any>(io).flywheel.refCoverage).toBe(0.5);
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
it('stdout 非 JSON 时抛错(解析失败不静默吞掉)', () => {
|
|
150
|
+
const io = captureIO();
|
|
151
|
+
log(io, 'not json');
|
|
152
|
+
expect(() => lastJsonOutput(io)).toThrow();
|
|
153
|
+
});
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
describe('CommandResult 判别联合', () => {
|
|
157
|
+
it('四种 kind 均可构造,fail/usage-error 必带 reason(类型层护栏)', () => {
|
|
158
|
+
const results: CommandResult[] = [
|
|
159
|
+
{ kind: 'ok' },
|
|
160
|
+
{ kind: 'skip', reason: '约定未采纳' },
|
|
161
|
+
{ kind: 'skip' },
|
|
162
|
+
{ kind: 'fail', reason: 'gate:branch 非 master' },
|
|
163
|
+
{ kind: 'usage-error', reason: '缺少 planPath' },
|
|
164
|
+
];
|
|
165
|
+
const kinds = results.map(r => r.kind);
|
|
166
|
+
expect(kinds).toEqual(['ok', 'skip', 'skip', 'fail', 'usage-error']);
|
|
167
|
+
expect(results.filter(r => r.kind !== 'ok').map(r => ('reason' in r ? r.reason : undefined)))
|
|
168
|
+
.toEqual(['约定未采纳', undefined, 'gate:branch 非 master', '缺少 planPath']);
|
|
169
|
+
});
|
|
170
|
+
});
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CLI 命令契约(架构评审候选7)
|
|
3
|
+
*
|
|
4
|
+
* 命令实现的 interface 由两部分组成,都在本模块定义:
|
|
5
|
+
* - **返回值 `CommandResult`**:判定结果(哪个 kind、为什么)。退出码不再由命令
|
|
6
|
+
* 自己 `process.exit`,而是由 bin 依 kind 唯一映射(`process.exit` 因此只出现在
|
|
7
|
+
* bin/harness.js 一处)。
|
|
8
|
+
* - **写入面 `CommandIO`**:流式输出去向。命令一律经注入的 io 打印,缺省 process
|
|
9
|
+
* 标准流——长命令(如 release)边跑边输出,不憋到结束由 bin 统一打印。
|
|
10
|
+
*
|
|
11
|
+
* 对外行为护栏:`processIO` 下 log/logError 的输出字节与 console.log/console.error
|
|
12
|
+
* 逐字一致(见 __tests__/command-contract.test.ts),CLI 语法与文案冻结。
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
import { format } from 'util';
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* 命令判定类别。
|
|
19
|
+
* 对外退出码只有 0/1(历史面),语义放进 kind,码值映射收敛在 bin。
|
|
20
|
+
*/
|
|
21
|
+
export type CommandKind = 'ok' | 'skip' | 'fail' | 'usage-error';
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* 命令实现返回值(判别联合)。
|
|
25
|
+
* `fail` / `usage-error` 必附 `reason`,且 reason 要能唯一定位失败点
|
|
26
|
+
* (多闸门命令须含闸门标识);`skip` 可选附原因。
|
|
27
|
+
*/
|
|
28
|
+
export type CommandResult =
|
|
29
|
+
| { kind: 'ok' }
|
|
30
|
+
| { kind: 'skip'; reason?: string }
|
|
31
|
+
| { kind: 'fail'; reason: string }
|
|
32
|
+
| { kind: 'usage-error'; reason: string };
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* 命令输出流注入面(最小可写接口,`process.stdout` / `process.stderr` 结构化满足)
|
|
36
|
+
*/
|
|
37
|
+
export interface CommandIO {
|
|
38
|
+
stdout: { write(chunk: string): boolean };
|
|
39
|
+
stderr: { write(chunk: string): boolean };
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/** 缺省 io:process 标准流(bin 不注入时的现状行为) */
|
|
43
|
+
export const processIO: CommandIO = {
|
|
44
|
+
stdout: process.stdout,
|
|
45
|
+
stderr: process.stderr,
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* 与 console.log 同语义(util.format + 换行)写入 io.stdout
|
|
50
|
+
*/
|
|
51
|
+
export function log(io: CommandIO, ...args: unknown[]): void {
|
|
52
|
+
io.stdout.write(format(...args) + '\n');
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* 与 console.error 同语义(util.format + 换行)写入 io.stderr
|
|
57
|
+
*/
|
|
58
|
+
export function logError(io: CommandIO, ...args: unknown[]): void {
|
|
59
|
+
io.stderr.write(format(...args) + '\n');
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* 捕获型 io:测试注入面,替代 `spyOn(process, 'exit')` 时代的彩色字符串断言。
|
|
64
|
+
*/
|
|
65
|
+
export interface CapturingIO extends CommandIO {
|
|
66
|
+
/** 已写入 stdout 的全部文本 */
|
|
67
|
+
outText(): string;
|
|
68
|
+
/** 已写入 stderr 的全部文本 */
|
|
69
|
+
errText(): string;
|
|
70
|
+
/** stdout 按行切分(末尾换行不产生空尾行) */
|
|
71
|
+
outLines(): string[];
|
|
72
|
+
/** stderr 按行切分(末尾换行不产生空尾行) */
|
|
73
|
+
errLines(): string[];
|
|
74
|
+
/** stdout 每次写入的原始文本(一次 log 调用 = 一条记录,等价旧的 console.log 调用参数视图) */
|
|
75
|
+
outRecords(): string[];
|
|
76
|
+
/** stderr 每次写入的原始文本 */
|
|
77
|
+
errRecords(): string[];
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export function captureIO(): CapturingIO {
|
|
81
|
+
let out = '';
|
|
82
|
+
let err = '';
|
|
83
|
+
const outChunks: string[] = [];
|
|
84
|
+
const errChunks: string[] = [];
|
|
85
|
+
const split = (text: string): string[] =>
|
|
86
|
+
text.endsWith('\n') ? text.slice(0, -1).split('\n') : (text === '' ? [] : text.split('\n'));
|
|
87
|
+
return {
|
|
88
|
+
stdout: { write: (chunk: string) => { out += chunk; outChunks.push(chunk); return true; } },
|
|
89
|
+
stderr: { write: (chunk: string) => { err += chunk; errChunks.push(chunk); return true; } },
|
|
90
|
+
outText: () => out,
|
|
91
|
+
errText: () => err,
|
|
92
|
+
outLines: () => split(out),
|
|
93
|
+
errLines: () => split(err),
|
|
94
|
+
outRecords: () => [...outChunks],
|
|
95
|
+
errRecords: () => [...errChunks],
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* 解析 --json 命令的捕获输出(测试断言面,harness#108)
|
|
101
|
+
*
|
|
102
|
+
* 与 captureIO 同住一处:它是 captureIO 的消费端正本,此前散在各命令测试里
|
|
103
|
+
* 逐字复制(JSON.parse(outText()))。缺省返回 Record 形状;消费方已知字段
|
|
104
|
+
* 形状时传泛型(如 lastJsonOutput<any>(io) 做任意字段穿透)。
|
|
105
|
+
*/
|
|
106
|
+
export function lastJsonOutput<T = Record<string, unknown>>(capture: CapturingIO): T {
|
|
107
|
+
return JSON.parse(capture.outText());
|
|
108
|
+
}
|
|
@@ -1,18 +1,19 @@
|
|
|
1
1
|
# cli/commands/
|
|
2
2
|
|
|
3
3
|
## 职责
|
|
4
|
-
CLI 子命令实现:
|
|
4
|
+
CLI 子命令实现:23 个顶层命令 + constraints 治理子命令 report/retire,覆盖约束检查/门禁验证/文档同步/知识管理/失败诊断/发布/会话分析等。
|
|
5
5
|
|
|
6
6
|
H5(#44)起:
|
|
7
7
|
- **命令定义即注册**:`definitions.ts` 的 `COMMAND_DEFINITIONS` 是命令形状(名称/别名/位置参数/选项/子命令/实现引用)的单一来源;bin/harness.js 遍历本表注册表驱动生成,不再手写 commander 命令块,不再有 index.ts barrel 两处同步(R6)
|
|
8
8
|
- **per-command 懒加载**(O2):定义表存实现引用 `{ module, export }`,bin 只在 action 执行时 require 对应命令模块,任一命令执行不再加载全部命令实现
|
|
9
9
|
|
|
10
10
|
## 核心导出
|
|
11
|
-
- `COMMAND_DEFINITIONS`(definitions.ts)—
|
|
12
|
-
-
|
|
11
|
+
- `COMMAND_DEFINITIONS`(definitions.ts)— 全部非门禁命令定义(纯数据模块、零闭包,禁止 import 命令实现;ADR-0010)
|
|
12
|
+
- 命令契约(`src/cli/command-contract.ts`,上层目录)— `CommandResult` / `CommandKind` / `CommandIO` / `processIO` / `captureIO` / `lastJsonOutput` / `log` / `logError`
|
|
13
|
+
- 各命令文件:check / validate / passes-gate / init / report / status / spec / sync-docs / knowledge / sdd / failure / posteval-plan / release / analyze-sessions / update-user-model / constraints / spec-baseline-check
|
|
13
14
|
- 6 门禁命令实现在 `acceptance` / `command` / `contract` / `performance` / `review` / `security`(其 CLI 元数据在 `src/gates/definitions.ts`,形状同为 `CommandDefinition`,ADR-0007)
|
|
14
15
|
|
|
15
|
-
`constraints` 下挂治理子命令:`constraints report`(使用统计 + 退役候选诊断 + 配置健康 + 注入漂移,`--export` 脱敏)、`constraints retire`(交互选择 + 人确认退役;带 id 直达需显式 `--yes`(#24 人确认闸门),无 `--yes` 报错 + 非零退出码且不落盘;内置落 config.yml retired 元数据,custom 落 custom-constraints.yml 条目 retired
|
|
16
|
+
`constraints` 下挂治理子命令:`constraints report`(使用统计 + 退役候选诊断 + 配置健康 + 注入漂移,`--export` 脱敏)、`constraints retire`(交互选择 + 人确认退役;带 id 直达需显式 `--yes`(#24 人确认闸门),无 `--yes` 报错 + 非零退出码且不落盘;内置落 config.yml retired 元数据,custom 落 custom-constraints.yml 条目 retired 段(studio#82 D6 一处真相)+ KnowledgeStore 沉淀 + 治理注入段同步)。
|
|
16
17
|
|
|
17
18
|
## 依赖关系
|
|
18
19
|
- 依赖 `src/core/constraints/` 约束引擎
|
|
@@ -25,13 +26,27 @@ H5(#44)起:
|
|
|
25
26
|
## 约定
|
|
26
27
|
- 每个命令一个实现文件,命名与命令名一致(sync-docs 为模块族目录)
|
|
27
28
|
- **新增命令 = 命令实现文件 + definitions.ts 一条定义(含 CLI 元数据与实现引用)+ 测试**,不再改 bin/harness.js
|
|
28
|
-
- **definitions.ts
|
|
29
|
+
- **definitions.ts 是纯数据模块(ADR-0010 后零闭包)**:禁止 import 任何命令实现/运行时依赖(保 --help/--version 懒加载);子命令别名是数据(条目 `aliases: string[]`,不复印整块),实参编组(缺参闸门/强转/兜底)归各命令模块的具名导出(如 `knowledgeSearchCommand`/`coverageCheck`);实现引用可解析性由 `__tests__/registry.test.ts` 构建/测试期断言
|
|
29
30
|
- 命令选项类型命名规范:XxxOptions
|
|
31
|
+
- **本层是上行数据的注入方(harness#88)**:core 对 cli/gates/monitoring 零值导入,故 `check`/`report` 自己 `new ConstraintChecker(getTraceCollector())`(组合根接线 trace 记录器;用 `constraintChecker`/`getInstance()` 拿到的默认实例不写 trace),`sync-docs` 把 `COMMAND_DEFINITIONS` + `GATE_DEFINITIONS` 组装成 `CapabilityDefinitionSource` 注入 `capabilities-parser` 供能力清单计数
|
|
32
|
+
- **projectPath 只在入口兜底一次,并传到每个 IO/执行点(harness#95)**:`-p/--project-path` 的 cwd 兜底唯一落点是命令模块入口(`const projectPath = options.projectPath || process.cwd()`);往下每层只能收参数,**禁止再取一次 `process.cwd()`、也禁止用相对路径默认值**——两者都让 `-p` 半失效:执行/读写位置悄悄回到调用方 cwd,而 acceptance 的「无 tasks.yml 即跳过」本身就是 `passed:true`,于是失效表现为假绿。落地形状:执行/IO 根用**必传形参**表达(`PassesGate.runTests(workDir)`),门禁内的相对子路径锚到 projectPath:`ContractGate` 一直是 `path.join(context.projectPath, contractPath)`,`SpecAcceptanceGate` 的 tasksPath 随 #95 对齐成 `path.resolve(projectPath, 相对值)`(绝对值原样,缺省 `<projectPath>/tasks.yml`)
|
|
33
|
+
- 机器可检:`__tests__/project-path-convention.test.ts` 三道闸——CLI 层 cwd 必须是 `xxx || process.cwd()` 兜底形状、下游层(core/gates/context/monitoring/hooks)cwd 站点集合冻结、`xxxPath: '相对值'` 默认值冻结;豁免逐条带理由,站点消失却不删条目同样失败
|
|
34
|
+
- 行为可检:`__tests__/project-path-anchoring.test.ts` 前提统一 **cwd ≠ projectPath**、不 mock 任何 IO,断言测试真在 B 执行、证据落 `B/.harness/evidence/`、acceptance 读 `B/tasks.yml`。「根已传入却又取 cwd」这类静态看不出的漂移由它守,冻结表守的是不再新增站点
|
|
35
|
+
- **读到部分结果必须告知(harness#100)**:命令面以 `skip` 策略读 JSONL(traces.log / failures.log)时,坏行计数要到用户可见输出,**不允许默默丢弃**。共同约束:无损坏零噪声(计数为 0 不出行)、不改任何既有计数口径(`status` 的 `记录数` 仍是原始非空行数,逐字节不变)、计数一律取自 `src/utils/jsonl` 读链返回的 `skippedLines`(经报告入口透传或在读点就地取用),**禁止**用「原始行数 − 统计条数」反推(窗过滤掉的合法行与坏行分不开)。三处落点各自对得上一行代码:
|
|
36
|
+
- `status`:告知**走 stderr**(`logError(io, …)`),因为 stdout 是报告体、其字节已被 `记录数` 那一行定死,挤进去等于改输出
|
|
37
|
+
- `constraints report`:提示属于**报告体内的降级位**,与既有的 `traceFileExists` 说明同在 stdout;结构化面另两份——`--json` 的 `skippedLines` 字段、`--export` markdown 的警示行(只报条数,不报路径与坏行内容)
|
|
38
|
+
- `constraints retire`:两条路径都**走 stderr**——交互模式在候选列表前一行(沿用本函数既有的 console 例外,`console.error`),`--yes` 直达分支在落盘前 `logError(io, …)`(`retireConstraint` 本身按契约「纯执行无交互」不打印)
|
|
39
|
+
- 原则正本与逐点去向见 `src/monitoring/CONTEXT.md`「约定」段;机器可检面是 `src/utils/__tests__/jsonl-skip-disposition.test.ts`(冻结全仓 skip 读点集合 + 要求每个读点记名声明 `计数去向:`)
|
|
30
40
|
|
|
31
41
|
## 注意事项
|
|
32
42
|
- 新增命令需同步更新 CLAUDE.md / CAPABILITIES.md / src/CONTEXT.md
|
|
33
43
|
- init 治理约束段写入落点(studio #302,ADR 2026-08-21 落点模型):新仓 → AGENTS.md `PRESERVE:governance` 段(sync-docs 重新生成时保留);旧模型仓(CLAUDE.md 已有 HARNESS_CONSTRAINTS 标记或 `## Governance Rules` 块)→ 续写 CLAUDE.md,幂等重跑不制造双份正本。治理段「在场守护」由 core 侧 governance_presence checker 承担(段缺失/为空时 check 报警)
|
|
34
44
|
- PRESERVE:governance 段内写入纪律:机器管理的只有 HARNESS_CONSTRAINTS 标记区间——有标记只换标记区间,无标记(纯手写段)在段尾追加注入段;段内其余手写内容(治理契约引言/流程/纪律等)必须原样保留(曾整段替换清空手写内容的回归,init-injection.test 有防回归用例)
|
|
35
|
-
-
|
|
45
|
+
- 注入段落点路由与 marker-range 替换收口在 `core/constraints/injection-writer`(ADR-0011):读侧 `resolveInjectionTarget`(漂移检测/retire 同步共用「CLAUDE.md 有标记优先,否则 AGENTS.md」)+ 写侧 `resolveGovernanceLanding`(init 落点选择);init 三个治理段 writer 与 retire 注入同步均为「渲染 body + 调 writer」,半标记(单边/乱序)一律拒写告警;未注入 = 两处均无完整标记段
|
|
36
46
|
- knowledge 命令包含 13 个子操作(list/search/import/decay/stats/upsert/sync-status/sync-rag/audit/snapshot/migrate/index/health)
|
|
37
|
-
-
|
|
47
|
+
- `stats` / `health` 的飞轮数字不在 CLI 内计算:分子口径唯一实现是 `knowledge/flywheel-metrics.ts`(`evaluateFlywheel`,ADR-0013),本层只做百分比取整/一位小数与字段名映射;`.consumption-stats.json` 的读取留在各命令(module 零 IO)
|
|
48
|
+
- 特殊路由(选项条件、子命令兜底、裸跑语义)表达在定义表的 optionRoutes / subcommands / subcommandStrict / bareRunsAction 字段,bin 是纯通用引擎、不含单命令知识
|
|
49
|
+
- **命令 interface = `CommandResult` + 注入 io(架构评审候选7)**:命令实现一律声明 `Promise<CommandResult>`(判别联合 `ok|skip|fail|usage-error`,`fail`/`usage-error` 必附可定位的 `reason`,多闸门命令 reason 含 `gate <id>`),末位可选形参 `io: CommandIO = processIO`;类型与写入面在 `src/cli/command-contract.ts`
|
|
50
|
+
- **本目录零 `process.exit` / `process.exitCode`**:kind → 退出码的唯一映射在 `bin/harness.js`(`ok`/`skip` → 0,`fail`/`usage-error` → 1,未知 kind fail-closed)。历史上两处条件式(`command --level` 按严重级、门禁按 passed)已由命令侧译成 kind;`sync-docs --check` 的漂移改由实现返回 `fail`(定义表的 `afterRun` 逃生门随之废除)
|
|
51
|
+
- **输出不得直接用 console**:流式打印走 `log(io, …)` / `logError(io, …)`(`util.format` + 换行,与 console 逐字节等价,见 `src/cli/__tests__/command-contract.test.ts`);测试断言输出用 `captureIO()`,不再 `spyOn(process, 'exit')`;`--json` 输出断言用 `lastJsonOutput(io)`(JSON.parse 正本,harness#108)。例外:`constraints retire` 交互正文仍走 console(其 `RetireIO` 只注入 readline 流),退役结果打印已接注入流
|
|
52
|
+
- **#95 同型扫荡结论**:两门禁站点已修(`passes-gate` 执行/证据落 projectPath、`acceptance` 去掉 `tasksPath: './tasks.yml'` 相对默认值)。逐点判定后的豁免三处,理由与站点原文一起冻结在 `__tests__/project-path-convention.test.ts` 的豁免表:`release` 的 `pkgPath`(定义表本无 `-p`,pkgPath 就是该命令唯一的根且已逐个传给每条 `run(cmd, pkgPath)`,不构成半失效;给发布流水线新增 `-p` 属新能力)、`constraints` 的 `join(process.cwd(), 'package.json')`(报的是 harness 自身包版本,主锚 `__dirname`,cwd 仅兜底)、`core/spec/validator.ts` 的 `schemaPath: './specs/schemas'`(**确是同型病灶**:`validateAll(projectPath)` 用 projectPath 找 spec 文件、却用 cwd 找 schema;但 `validateFile`/`loadSchema` 签名里没有根,补齐要穿透整个 spec 域,留待 spec 单票收口)
|