@dommaker/harness 1.7.0 → 1.8.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +44 -0
- package/bin/harness.js +17 -1
- package/dist/agents/index.d.ts +6 -2
- package/dist/agents/index.d.ts.map +1 -1
- package/dist/agents/index.js +6 -16
- package/dist/agents/index.js.map +1 -1
- package/dist/cli/commands/__tests__/gate-decision.d.ts +18 -0
- package/dist/cli/commands/__tests__/gate-decision.d.ts.map +1 -0
- package/dist/cli/commands/__tests__/gate-decision.js +26 -0
- package/dist/cli/commands/__tests__/gate-decision.js.map +1 -0
- package/dist/cli/commands/acceptance.d.ts.map +1 -1
- package/dist/cli/commands/acceptance.js +17 -28
- package/dist/cli/commands/acceptance.js.map +1 -1
- package/dist/cli/commands/check.d.ts +19 -3
- package/dist/cli/commands/check.d.ts.map +1 -1
- package/dist/cli/commands/check.js +36 -22
- package/dist/cli/commands/check.js.map +1 -1
- package/dist/cli/commands/command.d.ts +0 -1
- package/dist/cli/commands/command.d.ts.map +1 -1
- package/dist/cli/commands/command.js +8 -6
- package/dist/cli/commands/command.js.map +1 -1
- package/dist/cli/commands/constraints-retire.d.ts.map +1 -1
- package/dist/cli/commands/constraints-retire.js +36 -57
- package/dist/cli/commands/constraints-retire.js.map +1 -1
- package/dist/cli/commands/contract.d.ts.map +1 -1
- package/dist/cli/commands/contract.js +36 -42
- package/dist/cli/commands/contract.js.map +1 -1
- package/dist/cli/commands/definitions.d.ts +2 -0
- package/dist/cli/commands/definitions.d.ts.map +1 -1
- package/dist/cli/commands/definitions.js +11 -6
- package/dist/cli/commands/definitions.js.map +1 -1
- package/dist/cli/commands/failure.d.ts.map +1 -1
- package/dist/cli/commands/failure.js +16 -2
- package/dist/cli/commands/failure.js.map +1 -1
- package/dist/cli/commands/init.d.ts +14 -8
- package/dist/cli/commands/init.d.ts.map +1 -1
- package/dist/cli/commands/init.js +172 -364
- package/dist/cli/commands/init.js.map +1 -1
- package/dist/cli/commands/knowledge-view.d.ts +90 -0
- package/dist/cli/commands/knowledge-view.d.ts.map +1 -0
- package/dist/cli/commands/knowledge-view.js +198 -0
- package/dist/cli/commands/knowledge-view.js.map +1 -0
- package/dist/cli/commands/knowledge.d.ts +137 -52
- package/dist/cli/commands/knowledge.d.ts.map +1 -1
- package/dist/cli/commands/knowledge.js +534 -400
- package/dist/cli/commands/knowledge.js.map +1 -1
- package/dist/cli/commands/passes-gate.d.ts +4 -1
- package/dist/cli/commands/passes-gate.d.ts.map +1 -1
- package/dist/cli/commands/passes-gate.js +11 -2
- package/dist/cli/commands/passes-gate.js.map +1 -1
- package/dist/cli/commands/performance.d.ts.map +1 -1
- package/dist/cli/commands/performance.js +19 -31
- package/dist/cli/commands/performance.js.map +1 -1
- package/dist/cli/commands/report.d.ts.map +1 -1
- package/dist/cli/commands/report.js +2 -1
- package/dist/cli/commands/report.js.map +1 -1
- package/dist/cli/commands/review.d.ts.map +1 -1
- package/dist/cli/commands/review.js +13 -25
- package/dist/cli/commands/review.js.map +1 -1
- package/dist/cli/commands/scaffold-templates.d.ts +73 -0
- package/dist/cli/commands/scaffold-templates.d.ts.map +1 -0
- package/dist/cli/commands/scaffold-templates.js +424 -0
- package/dist/cli/commands/scaffold-templates.js.map +1 -0
- package/dist/cli/commands/scaffold.d.ts +105 -0
- package/dist/cli/commands/scaffold.d.ts.map +1 -0
- package/dist/cli/commands/scaffold.js +263 -0
- package/dist/cli/commands/scaffold.js.map +1 -0
- package/dist/cli/commands/security.d.ts.map +1 -1
- package/dist/cli/commands/security.js +22 -24
- package/dist/cli/commands/security.js.map +1 -1
- package/dist/cli/commands/spec-baseline-check.d.ts +43 -0
- package/dist/cli/commands/spec-baseline-check.d.ts.map +1 -1
- package/dist/cli/commands/spec-baseline-check.js +109 -34
- package/dist/cli/commands/spec-baseline-check.js.map +1 -1
- package/dist/cli/commands/status.d.ts +8 -0
- package/dist/cli/commands/status.d.ts.map +1 -1
- package/dist/cli/commands/status.js +5 -7
- package/dist/cli/commands/status.js.map +1 -1
- package/dist/cli/commands/sync-docs/context-syncer.d.ts +21 -2
- package/dist/cli/commands/sync-docs/context-syncer.d.ts.map +1 -1
- package/dist/cli/commands/sync-docs/context-syncer.js +112 -28
- package/dist/cli/commands/sync-docs/context-syncer.js.map +1 -1
- package/dist/cli/commands/sync-docs/index.d.ts +1 -1
- package/dist/cli/commands/sync-docs/index.d.ts.map +1 -1
- package/dist/cli/commands/sync-docs/index.js +86 -27
- package/dist/cli/commands/sync-docs/index.js.map +1 -1
- package/dist/cli/commands/sync-docs/project-reader.d.ts +24 -1
- package/dist/cli/commands/sync-docs/project-reader.d.ts.map +1 -1
- package/dist/cli/commands/sync-docs/project-reader.js +33 -7
- package/dist/cli/commands/sync-docs/project-reader.js.map +1 -1
- package/dist/cli/commands/validate.d.ts +0 -16
- package/dist/cli/commands/validate.d.ts.map +1 -1
- package/dist/cli/commands/validate.js +2 -97
- package/dist/cli/commands/validate.js.map +1 -1
- package/dist/cli/gate-command.d.ts +37 -0
- package/dist/cli/gate-command.d.ts.map +1 -0
- package/dist/cli/gate-command.js +64 -0
- package/dist/cli/gate-command.js.map +1 -0
- package/dist/cli/state-io.d.ts +34 -0
- package/dist/cli/state-io.d.ts.map +1 -0
- package/dist/cli/state-io.js +71 -0
- package/dist/cli/state-io.js.map +1 -0
- package/dist/completion-checkers/index.d.ts +1 -1
- package/dist/completion-checkers/index.d.ts.map +1 -1
- package/dist/completion-checkers/index.js +0 -15
- package/dist/completion-checkers/index.js.map +1 -1
- package/dist/context/knowledge-injector.d.ts +4 -2
- package/dist/context/knowledge-injector.d.ts.map +1 -1
- package/dist/context/knowledge-injector.js +13 -6
- package/dist/context/knowledge-injector.js.map +1 -1
- package/dist/core/constraints/agent-prompt-renderer.js +2 -2
- package/dist/core/constraints/agent-prompt-renderer.js.map +1 -1
- package/dist/core/constraints/capabilities-reconcile.d.ts +20 -0
- package/dist/core/constraints/capabilities-reconcile.d.ts.map +1 -1
- package/dist/core/constraints/capabilities-reconcile.js +26 -4
- package/dist/core/constraints/capabilities-reconcile.js.map +1 -1
- package/dist/core/constraints/check-cache.d.ts +1 -1
- package/dist/core/constraints/check-cache.js +1 -1
- package/dist/core/constraints/checker.d.ts +8 -3
- package/dist/core/constraints/checker.d.ts.map +1 -1
- package/dist/core/constraints/checker.js +30 -19
- package/dist/core/constraints/checker.js.map +1 -1
- package/dist/core/constraints/checkers/capability-sync.d.ts +3 -1
- package/dist/core/constraints/checkers/capability-sync.d.ts.map +1 -1
- package/dist/core/constraints/checkers/capability-sync.js +17 -24
- package/dist/core/constraints/checkers/capability-sync.js.map +1 -1
- package/dist/core/constraints/checkers/context-doc-sync.d.ts +1 -1
- package/dist/core/constraints/checkers/context-doc-sync.d.ts.map +1 -1
- package/dist/core/constraints/checkers/context-doc-sync.js +9 -6
- 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 +24 -30
- package/dist/core/constraints/checkers/docs-freshness.js.map +1 -1
- package/dist/core/constraints/checkers/governance-presence.d.ts.map +1 -1
- package/dist/core/constraints/checkers/governance-presence.js +10 -4
- package/dist/core/constraints/checkers/governance-presence.js.map +1 -1
- package/dist/core/constraints/checkers/types.d.ts +10 -6
- package/dist/core/constraints/checkers/types.d.ts.map +1 -1
- package/dist/core/constraints/checkers/types.js +7 -3
- package/dist/core/constraints/checkers/types.js.map +1 -1
- package/dist/core/constraints/context-builder.d.ts +11 -10
- package/dist/core/constraints/context-builder.d.ts.map +1 -1
- package/dist/core/constraints/context-builder.js +31 -27
- package/dist/core/constraints/context-builder.js.map +1 -1
- package/dist/core/constraints/context-reconcile.d.ts +75 -0
- package/dist/core/constraints/context-reconcile.d.ts.map +1 -0
- package/dist/core/constraints/context-reconcile.js +161 -0
- package/dist/core/constraints/context-reconcile.js.map +1 -0
- package/dist/core/constraints/doc-freshness/runner.d.ts +7 -0
- package/dist/core/constraints/doc-freshness/runner.d.ts.map +1 -1
- package/dist/core/constraints/doc-freshness/runner.js +8 -3
- package/dist/core/constraints/doc-freshness/runner.js.map +1 -1
- package/dist/core/constraints/git-evidence.js +1 -1
- package/dist/core/constraints/git-evidence.js.map +1 -1
- package/dist/core/constraints/injection-drift.d.ts +7 -2
- package/dist/core/constraints/injection-drift.d.ts.map +1 -1
- package/dist/core/constraints/injection-drift.js +13 -7
- package/dist/core/constraints/injection-drift.js.map +1 -1
- package/dist/core/constraints/run-env.d.ts +92 -0
- package/dist/core/constraints/run-env.d.ts.map +1 -0
- package/dist/core/constraints/run-env.js +175 -0
- package/dist/core/constraints/run-env.js.map +1 -0
- package/dist/core/constraints/triggers.d.ts +22 -0
- package/dist/core/constraints/triggers.d.ts.map +1 -0
- package/dist/core/constraints/triggers.js +31 -0
- package/dist/core/constraints/triggers.js.map +1 -0
- package/dist/core/effective-constraints.d.ts +13 -4
- package/dist/core/effective-constraints.d.ts.map +1 -1
- package/dist/core/effective-constraints.js +16 -6
- package/dist/core/effective-constraints.js.map +1 -1
- package/dist/core/effective-set.d.ts +8 -15
- package/dist/core/effective-set.d.ts.map +1 -1
- package/dist/core/effective-set.js +7 -12
- package/dist/core/effective-set.js.map +1 -1
- package/dist/core/index.d.ts +1 -0
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js.map +1 -1
- package/dist/core/project-config-loader.d.ts +39 -17
- package/dist/core/project-config-loader.d.ts.map +1 -1
- package/dist/core/project-config-loader.js +51 -122
- package/dist/core/project-config-loader.js.map +1 -1
- package/dist/core/validators/check-handlers/http.d.ts +2 -2
- package/dist/core/validators/check-handlers/http.d.ts.map +1 -1
- package/dist/core/validators/check-handlers/http.js +12 -7
- package/dist/core/validators/check-handlers/http.js.map +1 -1
- package/dist/failure/classifier.d.ts +1 -1
- package/dist/failure/classifier.d.ts.map +1 -1
- package/dist/failure/classifier.js +8 -8
- package/dist/failure/classifier.js.map +1 -1
- package/dist/failure/index.d.ts +2 -1
- package/dist/failure/index.d.ts.map +1 -1
- package/dist/failure/index.js +9 -17
- package/dist/failure/index.js.map +1 -1
- package/dist/failure/recorder.d.ts +1 -1
- package/dist/failure/recorder.d.ts.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 +3 -2
- package/dist/gates/checker-gate.js.map +1 -1
- package/dist/gates/command.d.ts +10 -4
- package/dist/gates/command.d.ts.map +1 -1
- package/dist/gates/command.js +36 -62
- package/dist/gates/command.js.map +1 -1
- package/dist/gates/contract.d.ts.map +1 -1
- package/dist/gates/contract.js +0 -4
- package/dist/gates/contract.js.map +1 -1
- package/dist/gates/definitions.d.ts +2 -1
- package/dist/gates/definitions.d.ts.map +1 -1
- package/dist/gates/definitions.js +6 -5
- package/dist/gates/definitions.js.map +1 -1
- package/dist/gates/index.d.ts +0 -4
- package/dist/gates/index.d.ts.map +1 -1
- package/dist/gates/index.js +1 -6
- package/dist/gates/index.js.map +1 -1
- package/dist/gates/performance.d.ts.map +1 -1
- package/dist/gates/performance.js +0 -4
- package/dist/gates/performance.js.map +1 -1
- package/dist/gates/runner.d.ts +1 -1
- package/dist/gates/runner.js +1 -1
- package/dist/gates/security.d.ts +1 -1
- package/dist/gates/security.d.ts.map +1 -1
- package/dist/gates/security.js +5 -6
- package/dist/gates/security.js.map +1 -1
- package/dist/gates/types.d.ts +14 -17
- package/dist/gates/types.d.ts.map +1 -1
- package/dist/gates/types.js.map +1 -1
- package/dist/hooks/bootstrap.d.ts +6 -4
- package/dist/hooks/bootstrap.d.ts.map +1 -1
- package/dist/hooks/bootstrap.js +25 -13
- package/dist/hooks/bootstrap.js.map +1 -1
- package/dist/hooks/config.d.ts +6 -2
- package/dist/hooks/config.d.ts.map +1 -1
- package/dist/hooks/config.js +5 -1
- package/dist/hooks/config.js.map +1 -1
- package/dist/hooks/index.d.ts +1 -1
- package/dist/hooks/index.d.ts.map +1 -1
- package/dist/hooks/index.js +0 -15
- package/dist/hooks/index.js.map +1 -1
- package/dist/hooks/pipeline.d.ts +19 -1
- package/dist/hooks/pipeline.d.ts.map +1 -1
- package/dist/hooks/pipeline.js +42 -4
- package/dist/hooks/pipeline.js.map +1 -1
- package/dist/hooks/registry.d.ts +11 -8
- package/dist/hooks/registry.d.ts.map +1 -1
- package/dist/hooks/registry.js +22 -7
- package/dist/hooks/registry.js.map +1 -1
- package/dist/hooks/types.d.ts +25 -7
- package/dist/hooks/types.d.ts.map +1 -1
- package/dist/index.d.ts +3 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -4
- package/dist/index.js.map +1 -1
- package/dist/knowledge/audit-scoring.d.ts +87 -0
- package/dist/knowledge/audit-scoring.d.ts.map +1 -0
- package/dist/knowledge/audit-scoring.js +470 -0
- package/dist/knowledge/audit-scoring.js.map +1 -0
- package/dist/knowledge/audit.d.ts +11 -59
- package/dist/knowledge/audit.d.ts.map +1 -1
- package/dist/knowledge/audit.js +47 -522
- package/dist/knowledge/audit.js.map +1 -1
- package/dist/knowledge/import.d.ts.map +1 -1
- package/dist/knowledge/import.js +2 -0
- package/dist/knowledge/import.js.map +1 -1
- package/dist/knowledge/index-generator.d.ts.map +1 -1
- package/dist/knowledge/index-generator.js +4 -5
- package/dist/knowledge/index-generator.js.map +1 -1
- package/dist/knowledge/index.d.ts +3 -2
- package/dist/knowledge/index.d.ts.map +1 -1
- package/dist/knowledge/index.js +3 -16
- package/dist/knowledge/index.js.map +1 -1
- package/dist/knowledge/ingest.js +1 -1
- package/dist/knowledge/ingest.js.map +1 -1
- package/dist/knowledge/lifecycle.d.ts.map +1 -1
- package/dist/knowledge/lifecycle.js +4 -2
- package/dist/knowledge/lifecycle.js.map +1 -1
- package/dist/knowledge/migration.d.ts +3 -0
- package/dist/knowledge/migration.d.ts.map +1 -1
- package/dist/knowledge/migration.js +8 -2
- package/dist/knowledge/migration.js.map +1 -1
- package/dist/knowledge/query.d.ts +6 -0
- package/dist/knowledge/query.d.ts.map +1 -1
- package/dist/knowledge/query.js +8 -2
- package/dist/knowledge/query.js.map +1 -1
- package/dist/knowledge/reference-tracker.d.ts.map +1 -1
- package/dist/knowledge/reference-tracker.js +4 -6
- package/dist/knowledge/reference-tracker.js.map +1 -1
- package/dist/knowledge/store.d.ts +22 -16
- package/dist/knowledge/store.d.ts.map +1 -1
- package/dist/knowledge/store.js +53 -12
- package/dist/knowledge/store.js.map +1 -1
- package/dist/knowledge/tree-walker.d.ts +19 -0
- package/dist/knowledge/tree-walker.d.ts.map +1 -0
- package/dist/knowledge/tree-walker.js +30 -0
- package/dist/knowledge/tree-walker.js.map +1 -0
- package/dist/knowledge/types.d.ts +16 -0
- package/dist/knowledge/types.d.ts.map +1 -1
- package/dist/monitoring/traces.d.ts +5 -3
- package/dist/monitoring/traces.d.ts.map +1 -1
- package/dist/monitoring/traces.js +19 -5
- package/dist/monitoring/traces.js.map +1 -1
- package/dist/test-setup/jsonl-fake-fs.d.ts +30 -0
- package/dist/test-setup/jsonl-fake-fs.d.ts.map +1 -0
- package/dist/test-setup/jsonl-fake-fs.js +49 -0
- package/dist/test-setup/jsonl-fake-fs.js.map +1 -0
- package/dist/tools/index.d.ts +4 -1
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +7 -15
- package/dist/tools/index.js.map +1 -1
- package/dist/types/checkpoint.d.ts +5 -0
- package/dist/types/checkpoint.d.ts.map +1 -1
- package/dist/types/project-config.d.ts +18 -0
- package/dist/types/project-config.d.ts.map +1 -1
- package/dist/types/trace.d.ts +13 -4
- package/dist/types/trace.d.ts.map +1 -1
- package/dist/types/trace.js +4 -3
- package/dist/types/trace.js.map +1 -1
- package/dist/utils/exec.d.ts +4 -27
- package/dist/utils/exec.d.ts.map +1 -1
- package/dist/utils/exec.js +4 -94
- package/dist/utils/exec.js.map +1 -1
- package/dist/utils/jsonl.d.ts +17 -7
- package/dist/utils/jsonl.d.ts.map +1 -1
- package/dist/utils/jsonl.js +144 -17
- package/dist/utils/jsonl.js.map +1 -1
- package/dist/utils/numeric-flag.d.ts +44 -0
- package/dist/utils/numeric-flag.d.ts.map +1 -0
- package/dist/utils/numeric-flag.js +62 -0
- package/dist/utils/numeric-flag.js.map +1 -0
- package/package.json +1 -1
- package/src/CONTEXT.md +5 -2
- package/src/__tests__/acceptance-gate.test.ts +7 -4
- package/src/__tests__/checker-extra.test.ts +3 -2
- package/src/__tests__/checker.test.ts +4 -3
- package/src/__tests__/checkpoint.test.ts +26 -9
- package/src/__tests__/context-files-resolution.test.ts +29 -15
- package/src/__tests__/contract-gate.test.ts +19 -40
- package/src/__tests__/error-classifier.test.ts +1 -1
- package/src/__tests__/exec.test.ts +45 -107
- package/src/__tests__/failure-recorder.test.ts +7 -5
- package/src/__tests__/hooks-pipeline.test.ts +34 -47
- package/src/__tests__/layering.test.ts +217 -25
- package/src/__tests__/passes-gate.test.ts +9 -4
- package/src/__tests__/performance-gate.test.ts +3 -15
- package/src/__tests__/project-config-loader-extra.test.ts +31 -57
- package/src/__tests__/project-config-loader.test.ts +6 -3
- package/src/__tests__/public-exports.test.ts +0 -1
- package/src/__tests__/public-type-surface.test.ts +5 -4
- package/src/__tests__/public-value-surface.test.ts +182 -0
- package/src/__tests__/review-gate.test.ts +4 -6
- package/src/__tests__/security-gate.test.ts +5 -20
- package/src/__tests__/skip-semantics.test.ts +5 -3
- package/src/__tests__/spec-validator.test.ts +3 -2
- package/src/__tests__/sub-barrels-explicit.test.ts +87 -0
- package/src/__tests__/test-fixture-hygiene.test.ts +53 -0
- package/src/__tests__/trace-analyzer-extra.test.ts +5 -3
- package/src/__tests__/trace-analyzer.test.ts +5 -3
- package/src/__tests__/trace-collector.test.ts +5 -3
- package/src/agents/index.ts +13 -2
- package/src/cli/__tests__/gate-command.test.ts +162 -0
- package/src/cli/__tests__/state-io.test.ts +50 -0
- package/src/cli/commands/CONTEXT.md +30 -5
- package/src/cli/commands/__tests__/acceptance.test.ts +24 -25
- package/src/cli/commands/__tests__/bin-exit-mapping.test.ts +15 -0
- package/src/cli/commands/__tests__/check-drift.test.ts +42 -1
- package/src/cli/commands/__tests__/check-read-count.test.ts +170 -0
- package/src/cli/commands/__tests__/check-skip-output.test.ts +4 -1
- package/src/cli/commands/__tests__/check.test.ts +63 -44
- package/src/cli/commands/__tests__/command-gate-dead-options.test.ts +60 -0
- package/src/cli/commands/__tests__/command.test.ts +33 -17
- package/src/cli/commands/__tests__/constraints-retire.test.ts +52 -0
- package/src/cli/commands/__tests__/context-syncer.test.ts +141 -0
- package/src/cli/commands/__tests__/contract.test.ts +20 -20
- package/src/cli/commands/__tests__/failure.test.ts +5 -4
- package/src/cli/commands/__tests__/gate-decision.ts +30 -0
- package/src/cli/commands/__tests__/init-dead-options.test.ts +50 -0
- package/src/cli/commands/__tests__/init-governance-io.test.ts +139 -0
- package/src/cli/commands/__tests__/init-injection.test.ts +3 -3
- package/src/cli/commands/__tests__/init-ondisk.test.ts +867 -0
- package/src/cli/commands/__tests__/init.test.ts +82 -6
- package/src/cli/commands/__tests__/knowledge-audit-threshold.test.ts +146 -0
- package/src/cli/commands/__tests__/knowledge-flywheel-consistency.test.ts +1 -1
- package/src/cli/commands/__tests__/knowledge-tone-mapping.test.ts +244 -0
- package/src/cli/commands/__tests__/knowledge-view.test.ts +839 -0
- package/src/cli/commands/__tests__/knowledge.test.ts +33 -15
- package/src/cli/commands/__tests__/numeric-flag-assembly.test.ts +368 -0
- package/src/cli/commands/__tests__/performance.test.ts +19 -21
- package/src/cli/commands/__tests__/posteval-plan.test.ts +5 -3
- package/src/cli/commands/__tests__/pre-push-hook.test.ts +181 -0
- package/src/cli/commands/__tests__/project-path-anchoring.test.ts +95 -2
- package/src/cli/commands/__tests__/project-path-convention.test.ts +103 -25
- package/src/cli/commands/__tests__/registry.test.ts +2 -0
- package/src/cli/commands/__tests__/report.test.ts +23 -1
- package/src/cli/commands/__tests__/review.test.ts +10 -17
- package/src/cli/commands/__tests__/scaffold.test.ts +505 -0
- package/src/cli/commands/__tests__/security-default-scan.test.ts +75 -0
- package/src/cli/commands/__tests__/security.test.ts +21 -24
- package/src/cli/commands/__tests__/spec-baseline-check.test.ts +3 -2
- package/src/cli/commands/__tests__/spec-baseline-index-cap.test.ts +131 -0
- package/src/cli/commands/__tests__/spec-baseline-read-count.test.ts +325 -0
- package/src/cli/commands/__tests__/status-extra.test.ts +25 -8
- package/src/cli/commands/__tests__/status.test.ts +46 -18
- package/src/cli/commands/__tests__/sync-docs-agents.test.ts +19 -4
- package/src/cli/commands/__tests__/sync-docs-context-drift.test.ts +232 -0
- package/src/cli/commands/__tests__/sync-docs-module-order.test.ts +111 -0
- package/src/cli/commands/__tests__/sync-docs-read-count.test.ts +192 -0
- package/src/cli/commands/__tests__/sync-docs.test.ts +3 -2
- package/src/cli/commands/__tests__/validate.test.ts +1 -48
- package/src/cli/commands/acceptance.ts +24 -29
- package/src/cli/commands/check.ts +60 -35
- package/src/cli/commands/command.ts +9 -8
- package/src/cli/commands/constraints-retire.ts +57 -70
- package/src/cli/commands/contract.ts +44 -47
- package/src/cli/commands/definitions.ts +12 -6
- package/src/cli/commands/failure.ts +16 -3
- package/src/cli/commands/init.ts +242 -389
- package/src/cli/commands/knowledge-view.ts +224 -0
- package/src/cli/commands/knowledge.ts +643 -448
- package/src/cli/commands/passes-gate.ts +12 -3
- package/src/cli/commands/performance.ts +31 -38
- package/src/cli/commands/report.ts +3 -2
- package/src/cli/commands/review.ts +22 -28
- package/src/cli/commands/scaffold-templates.ts +406 -0
- package/src/cli/commands/scaffold.ts +302 -0
- package/src/cli/commands/security.ts +27 -23
- package/src/cli/commands/spec-baseline-check.ts +158 -33
- package/src/cli/commands/status.ts +12 -7
- package/src/cli/commands/sync-docs/__tests__/context-export-surface.test.ts +102 -0
- package/src/cli/commands/sync-docs/__tests__/module-descriptions.test.ts +196 -0
- package/src/cli/commands/sync-docs/context-syncer.ts +137 -31
- package/src/cli/commands/sync-docs/index.ts +103 -28
- package/src/cli/commands/sync-docs/project-reader.ts +51 -7
- package/src/cli/commands/validate.ts +1 -104
- package/src/cli/gate-command.ts +87 -0
- package/src/cli/state-io.ts +53 -0
- package/src/completion-checkers/index.ts +10 -1
- package/src/context/CONTEXT.md +2 -1
- package/src/context/__tests__/knowledge-injector.test.ts +27 -0
- package/src/context/__tests__/session-manager.test.ts +19 -12
- package/src/context/knowledge-injector.ts +14 -7
- package/src/core/CONTEXT.md +10 -7
- package/src/core/__tests__/effective-set.test.ts +36 -60
- package/src/core/constraints/__tests__/context-reconcile.test.ts +246 -0
- package/src/core/constraints/__tests__/run-env.test.ts +377 -0
- package/src/core/constraints/__tests__/triggers.test.ts +70 -0
- package/src/core/constraints/agent-prompt-renderer.ts +1 -1
- package/src/core/constraints/capabilities-reconcile.ts +28 -4
- package/src/core/constraints/check-cache.ts +1 -1
- package/src/core/constraints/checker.ts +30 -14
- package/src/core/constraints/checkers/__tests__/context-doc-sync.test.ts +8 -3
- package/src/core/constraints/checkers/__tests__/governance-presence.test.ts +16 -7
- package/src/core/constraints/checkers/__tests__/no-hardcoded-credentials.test.ts +2 -1
- package/src/core/constraints/checkers/capability-sync.ts +27 -28
- package/src/core/constraints/checkers/context-doc-sync.ts +9 -7
- package/src/core/constraints/checkers/docs-freshness.ts +28 -33
- package/src/core/constraints/checkers/governance-presence.ts +10 -6
- package/src/core/constraints/checkers/types.ts +14 -8
- package/src/core/constraints/context-builder.ts +35 -26
- package/src/core/constraints/context-reconcile.ts +200 -0
- package/src/core/constraints/doc-freshness/__tests__/runner.test.ts +25 -0
- package/src/core/constraints/doc-freshness/runner.ts +18 -4
- package/src/core/constraints/git-evidence.ts +1 -1
- package/src/core/constraints/injection-drift.ts +19 -8
- package/src/core/constraints/run-env.ts +207 -0
- package/src/core/constraints/triggers.ts +33 -0
- package/src/core/effective-constraints.ts +17 -6
- package/src/core/effective-set.ts +8 -24
- package/src/core/index.ts +2 -0
- package/src/core/project-config-loader.ts +54 -102
- package/src/core/validators/__tests__/http-retry-sleep.test.ts +231 -0
- package/src/core/validators/check-handlers/http.ts +18 -7
- package/src/failure/CONTEXT.md +2 -1
- package/src/failure/classifier.ts +2 -2
- package/src/failure/index.ts +14 -2
- package/src/failure/recorder.ts +1 -1
- package/src/gates/CONTEXT.md +13 -7
- package/src/gates/__tests__/checker-gate.test.ts +1 -1
- package/src/gates/__tests__/command-single-predicate.test.ts +135 -0
- package/src/gates/__tests__/command.test.ts +8 -15
- package/src/gates/__tests__/contract.test.ts +5 -5
- package/src/gates/__tests__/gate-interface.test.ts +0 -17
- package/src/gates/__tests__/performance.test.ts +0 -13
- package/src/gates/__tests__/review.test.ts +0 -1
- package/src/gates/__tests__/runner.test.ts +1 -1
- package/src/gates/__tests__/security-default-scan.test.ts +97 -0
- package/src/gates/__tests__/security.test.ts +0 -13
- package/src/gates/checker-gate.ts +3 -2
- package/src/gates/command.ts +51 -74
- package/src/gates/contract.ts +0 -5
- package/src/gates/definitions.ts +6 -5
- package/src/gates/index.ts +0 -5
- package/src/gates/performance.ts +1 -6
- package/src/gates/runner.ts +1 -1
- package/src/gates/security.ts +9 -11
- package/src/gates/types.ts +20 -23
- package/src/hooks/CONTEXT.md +10 -9
- package/src/hooks/__tests__/bootstrap.test.ts +29 -6
- package/src/hooks/__tests__/pipeline.test.ts +133 -17
- package/src/hooks/__tests__/registry.test.ts +51 -3
- package/src/hooks/bootstrap.ts +35 -15
- package/src/hooks/config.ts +6 -2
- package/src/hooks/index.ts +10 -1
- package/src/hooks/pipeline.ts +51 -6
- package/src/hooks/registry.ts +31 -12
- package/src/hooks/types.ts +26 -7
- package/src/index.ts +1 -2
- package/src/knowledge/CONTEXT.md +14 -7
- package/src/knowledge/__tests__/audit-labels.test.ts +8 -5
- package/src/knowledge/__tests__/audit-scoring.test.ts +230 -0
- package/src/knowledge/__tests__/audit-write-count.test.ts +131 -0
- package/src/knowledge/__tests__/audit.test.ts +291 -208
- package/src/knowledge/__tests__/doctor.test.ts +3 -2
- package/src/knowledge/__tests__/ingest.test.ts +3 -2
- package/src/knowledge/__tests__/lifecycle.test.ts +57 -2
- package/src/knowledge/__tests__/migration.test.ts +35 -6
- package/src/knowledge/__tests__/query.test.ts +3 -2
- package/src/knowledge/__tests__/reference-tracker.test.ts +23 -2
- package/src/knowledge/__tests__/store.test.ts +149 -4
- package/src/knowledge/__tests__/tree-walker.test.ts +132 -0
- package/src/knowledge/audit-scoring.ts +589 -0
- package/src/knowledge/audit.ts +55 -599
- package/src/knowledge/import.ts +2 -0
- package/src/knowledge/index-generator.ts +4 -6
- package/src/knowledge/index.ts +27 -2
- package/src/knowledge/ingest.ts +1 -1
- package/src/knowledge/lifecycle.ts +5 -2
- package/src/knowledge/migration.ts +8 -2
- package/src/knowledge/query.ts +8 -1
- package/src/knowledge/reference-tracker.ts +5 -7
- package/src/knowledge/store.ts +75 -16
- package/src/knowledge/tree-walker.ts +29 -0
- package/src/knowledge/types.ts +19 -0
- package/src/monitoring/CONTEXT.md +5 -2
- package/src/monitoring/__tests__/context-tracker.test.ts +16 -8
- package/src/monitoring/__tests__/trace-file-anchoring.test.ts +80 -0
- package/src/monitoring/traces.ts +19 -5
- package/src/release/CONTEXT.md +1 -1
- package/src/release/__tests__/integrity.test.ts +21 -12
- package/src/test-setup/__tests__/jsonl-fake-fs.test.ts +98 -0
- package/src/test-setup/jsonl-fake-fs.ts +59 -0
- package/src/tools/index.ts +5 -1
- package/src/types/checkpoint.ts +6 -0
- package/src/types/project-config.ts +21 -0
- package/src/types/trace.ts +14 -4
- package/src/utils/__tests__/file-walk.test.ts +3 -2
- package/src/utils/__tests__/jsonl-bounded-read.test.ts +106 -0
- package/src/utils/__tests__/jsonl-skip-disposition.test.ts +10 -6
- package/src/utils/__tests__/jsonl.test.ts +61 -14
- package/src/utils/__tests__/numeric-flag.test.ts +80 -0
- package/src/utils/__tests__/package-version.test.ts +2 -2
- package/src/utils/exec.ts +4 -64
- package/src/utils/jsonl.ts +159 -20
- package/src/utils/numeric-flag.ts +64 -0
- package/dist/failure/types.d.ts +0 -9
- package/dist/failure/types.d.ts.map +0 -1
- package/dist/failure/types.js +0 -25
- package/dist/failure/types.js.map +0 -1
- package/dist/gates/effective-gates.d.ts +0 -30
- package/dist/gates/effective-gates.d.ts.map +0 -1
- package/dist/gates/effective-gates.js +0 -81
- package/dist/gates/effective-gates.js.map +0 -1
- package/src/failure/types.ts +0 -9
- package/src/gates/__tests__/effective-gates.test.ts +0 -77
- package/src/gates/effective-gates.ts +0 -99
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,50 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
|
|
6
6
|
|
|
7
7
|
## [Unreleased]
|
|
8
8
|
|
|
9
|
+
## [1.8.1] - 2026-09-17
|
|
10
|
+
|
|
11
|
+
### Changes
|
|
12
|
+
- feat(hooks): `HookPipeline` 新增 `runOne(name, context)`——按名执行单个 hook 的公共入口(#167,#159 的 studio 侧随动遗留;票下 grilling 裁决 Q1–Q6)——原缺口:管线执行粒度是**时机**(`run(phase)` 一次跑该时机全部 enabled hook),consumer 按名直调单个函数的场景(studio 唯一生产调用点)无入口可委托,`enabled` / env 开关在直调路径上不配不生效。落地:方法挂在已导出类 `HookPipeline` 上,采样与错误隔离复用 `executeOne` 单路径(判定与错误策略的实现体只有一份),enabled / errorStrategy 值来源仍是注册环节填充的 `EffectiveHook`(唯一声明点 HookConfig,#159)。语义三面(裁决 Q2/Q3/Q5):`enabled:false` → 实现体零调用、返回 `skipped:true / passed:true` 记录(`HookExecutionRecord` 加性新字段,镜像 `sampled` 先例:未执行 = 记录上一面旗);`errorStrategy:'block'` 且失败(实现体抛或返回 `passed:false`)→ 抛裸 `Error`,message 形如 `[harness] hook "<name>" blocked: <原文>`(不新设 `HookBlockedError`,裁决明确不做);`'warn'` 且失败 → resolve、返回 `passed:false` 带 `error` 的记录;未知 hook 名 → 抛错(与 `assertHookRegistryClosed` 闭环口径一致,拒绝静默缺失)。**对外行为变化 1 处**(定级**非 breaking / minor**,ADR-0022 加性判据):已导出类加一个方法、已冻结类型加一个可选字段,无符号增删——`public-exports` / `public-type-surface` / `public-value-surface` 三套闸清单零变更(裁决预期核实成立)。测试:`src/hooks/__tests__/pipeline.test.ts` 新增「runOne 按名执行」describe 7 项——反证三形各一条(enabled:false 零调用 + skipped 记录;block 实现体抛 / 返回 passed:false 两形均抛且 message 含 hook 名与原文;warn 失败 resolve 且记录 passed:false 带 error)、未知名抛错、sampleRate 采样语义与 `run` 路径一致(未抽中零调用 + sampled 记录、抽中执行)。**先红后绿**:实现前 TS2339「runOne 不存在」令套件红。文档:`src/hooks/CONTEXT.md` 核心导出行补 `runOne` 与 `skipped` 语义。studio 侧随动(删本地判定读取点、委托 `runOne`)另开下游票,本仓发版后执行(照 #159 拆分模式)。
|
|
13
|
+
- feat(cli): 新立可注入状态文件接缝 `StateIO`,收编 `.harness/.state.json` 全部读写并修复智能提示去重失效(#148,#140 C 票;决策 ADR-0026)——原状两个写者裸调同步 `fs`、无注入缝,且 `status` 不读就整文件重写,把 `check` 写入的 `shownHints` 抹掉,「记录已足够,运行 harness status 查看统计」提示的「首次达到阈值」去重机制因此实面失效(每两次 `check` 夹一次 `status` 就再响一次)。落地:新增 `src/cli/state-io.ts`(cli 层,不进包根导出面,零公共面变化)——`HarnessState` 具名类型(`shownHints?` / `lastStatusRun?`;凭想象留下的 `lastDiagnoseRun` 按 ADR-0022 口径删除,旧落盘文件残留该键无害不迁移)、`StateIO` 接口(`read()` 文件缺失/空返 `{}` / 损坏照现状抛 / `write()`)、缺省真实 fs 实现 `fileStateIO(projectPath)`(状态文件路径知识单点化);`check` / `status` 两命令加**可选** `stateIO` 注入参数(照 `CommandIO` 模式,不扩 `CommandIO`、不动 `RunEnv` 只读契约),写语义统一为**读-改-写**。**对外行为变化 2 处**(均定级**非 breaking / patch**,ADR-0022 判据同 #138「恢复的是声明语义、修掉的是缺陷状态」先例):① 智能提示去重从此真生效——`shownHints` 跨 `status` 存活,提示出现频次由「夹一次 status 再响一次」恢复为设计口径「首次达到阈值一次」;② `.state.json` 损坏时 `harness status` 由「不读直接整文件覆盖重写」变为 `JSON.parse` 抛错(读-改-写决策 2 与「损坏抛即抛不兜底」决策 4 的合并后果,ADR-0026 已裁;`check` 侧原本就是这语义,未变);命令语法、输出文案、退出码、`.state.json` 路径与键名零变化。测试:状态相关用例全部改经注入内存假件、不再碰真文件系统(`check.test.ts` 智能提示组、`status.test.ts` 全部调用点);`status.test.ts` 新增「读-改-写:shownHints 不被抹掉」用例(**反证已做**:退回整文件重写该例转红并还原);计数闸 `check-read-count.test.ts` 夹具补 `.harness/.state.json`、冻结表新增「一次 check 运行内状态文件恰读一次」行(**反证已做**:`fileStateIO.read` 改双读 → 冻结表与「至多读一次」两例同红并还原)。文档:`src/CONTEXT.md` StateIO 条目由「代码未落」改为落地口径。
|
|
14
|
+
|
|
15
|
+
## [1.8.0] - 2026-09-16
|
|
16
|
+
|
|
17
|
+
### BREAKING
|
|
18
|
+
发版前只看这一节即可拿到本车全部 breaking 判定(#162 复审遗留项 5 设立;细节与迁移路径见 `### Changes` 对应条目):
|
|
19
|
+
- **#134 ①**:包根公开类 `KnowledgeAudit` 构造签名由 `new KnowledgeAudit({ baseDir, … })` 变为 `new KnowledgeAudit(store, { 阈值 })`(`AuditOptions` 去掉 `baseDir` 与 `autoFix`)。
|
|
20
|
+
- **#134 ④**(#162 复审遗留项 1 补记定级):包根公开接口 `KnowledgeStore` 由 13 成员增至 15 成员,新增**必选**方法 `applyAll(updates: StoreUpdate[]): void` 与 `getConsumptionStats(): ConsumptionStats | undefined`——库侧自定义 store 实现者编译期 breaking(`public-type-surface` 是名单闸,看不见成员级增量)。
|
|
21
|
+
- **#135**:包根公开类型 `CommandGateConfig` 收缩两字段(`strict` / `customBlacklist` 删除,现只剩 `ignoreCategories`)、`harness command` 删除 `--strict` 选项;多重命中输入上 `harness command --level` 报告的等级可能由低变高(与同一条目的裁决一致)。
|
|
22
|
+
- **#159**(晚于本批复审批次,同车 breaking,一并汇总以免漏级):包根公开类型 `HookDefinition` 收缩 `enabled` / `errorStrategy` 两字段、`HookErrorStrategy` 取值收窄为 `'block' | 'warn'`、`HookRegistry.register` / `registerAll` 签名变化(配置表成为必填配对)、`bootstrapHarness` / `bootstrapHarnessSync` 加第三参 `hookConfigs`。
|
|
23
|
+
发布级别随本车 ship 时统一裁决,判据同 ADR-0022 / ADR-0024「breaking 内容按 minor 号发布」先例。
|
|
24
|
+
|
|
25
|
+
### Changes
|
|
26
|
+
- fix(knowledge): 三处声明与执法背离对齐正本——absent 静默跳过、外部 marking 接线、rule 降级边界取 <=(#161,commit `c9e42cf`;本条为 #164 复审遗留项 1 的补记——该 commit 落地时 Unreleased 无条目,同批 #154/#156/#157/#159/#163 均带,本票独缺)——① `migrateKnowledgeEntries`:frontmatter 缺失('absent')的 .md 不再写入 `result.errors`(`no frontmatter found` 假阳性),按 #89 裁决 2 的非条目语义改计 `skipped`,`MigrationResult` 形状不变;② `KnowledgeInjector`:`origin === 'external'` 条目的注入与格式化输出带 `EXTERNAL_SOURCE_MARKER` 前缀——三层防御第二层 retrieval marking 此前只有声明未接线,本票接通,标记唯一正本收在 `knowledge/query.ts` 并与 `formatForPrompt` 共用,注入 metadata 增 `origin` 字段;③ lifecycle rule 降级条件由 `<` 改 `<=`——成功率恰 0.5(失败率 >= 50%)的 rule 条目由不降级变为降级,与方法注释/CONTEXT.md 的既有声明一致。**对外行为变化 3 处**(定级**非 breaking / patch**,ADR-0022 判据同 #138「恢复的是声明语义、修掉的是缺陷状态」先例):三处均把可观察行为对齐到已声明口径——公开符号零删除、签名零变化,`EXTERNAL_SOURCE_MARKER` 为加性导出;受影响的只有依赖旧误报(errors 里的 absent 条目)与旧边界(恰 50% 不降级)的用法。测试:migration / knowledge-injector / lifecycle 三套件各补边界反证用例(absent 计 skipped 不进 errors、external 条目带标记、恰 50% 触发降级),随 commit `c9e42cf` 同车落地。
|
|
27
|
+
- chore(cleanup+perf): 复审遗留项合并票的代码面两项(#162,ticket-loop #134–#147 统一复审)——① `utils/exec.ts` 删 `runCommand()`:#137 头注记它「有生产消费者」实为两处**注释**引用,非测试代码调用点为 0 且不在包公共面(`src/index.ts` 与五个 exports 入口均无),按 ADR-0022 同判据删除(`execAsync` 保留,判据与头注全文见 `src/__tests__/exec.test.ts`);② `spec-baseline-check` 共享索引加驻留上限 `SOURCE_INDEX_MAX_ENTRIES = 5000` / `SOURCE_INDEX_MAX_BYTES = 64MB`,超任一上限即放弃驻留、回落逐文件流式读——峰值内存由 O(全仓源码) 回到 O(单文件),正常规模仓保留 #146「一次遍历」收益(本仓 146 个源文件的规模测不出大仓峰值,故走上限+回落而非折叠重构)。**对外行为变化 0 处**(非 breaking):判定、证据文案、stdout、退出码、包公共面零变化;`runCommand` 外部不可达故零迁移成本。测试:`exec.test.ts` 收缩记录改写(`runCommand` 列入已删名单,`@ts-expect-error` + 运行时键双钉);新增 `spec-baseline-index-cap.test.ts` 4 项驻留上界闸(上限内驻留重放每文件至多读一遍、超条目/字节上限回落流式且判定不变——反证已做:摘掉回落分支 2 例转红并还原)。文档:`src/cli/commands/CONTEXT.md` 记名回落路径。
|
|
28
|
+
- refactor(hooks)!: `HookConfig` 成为 `enabled` / `errorStrategy` 唯一声明点——`HookDefinition` 删除同名字段,注册环节由配置表填充有效值(#159,harness#142 核对出的「同一语义两处声明」根治票,triage 裁路线 1 配置表唯一化)——原缺陷:配置表两字段为必填却零读取点,执行链只读 `HookDefinition` 同名字段,`assertHookRegistryClosed` 只按 `name` 配对,consumer 写 `{ enabled: false, errorStrategy: 'block' }` 而注册定义是 `{ errorStrategy: 'warn' }` 时 hook 照样执行、按 warn 继续,闭环断言全绿。落地:`HookDefinition` 类型上不再有 `enabled` / `errorStrategy`(编译期 `@ts-expect-error` 双钉冻结新形状);`HookRegistry.register(hook, config)` 注册即配对(名称不一致 / `registerAll` 有实现缺配置声明均抛错),填充出 `EffectiveHook`(新公开类型 = 定义 + 有效 enabled / errorStrategy),`getEnabled` / `get` / `listAll` 返回它,管线 block/warn 分派与启用过滤的判定语义不变、只换值来源;`bootstrapHarness` / `bootstrapHarnessSync` 加第三参 `hookConfigs`,给定义不给配置表即抛错。有效策略集合收敛为 `'block' | 'warn'`——`HookErrorStrategy` 收窄、原 `'ignore'` 与「未声明 strategy 静默跳过」形态退出有效面(仓内核实零生产消费者,唯一引用是一份测试,已随新形状重写);`toErrorStrategy` 语义不变、返回类型随收窄。studio 侧随动(`callHook` 自建判定层拆除、委托 harness 管线)另开下游票,须在本仓发版后执行。**对外行为变化**(**breaking**,发布级别随本车 ship 时裁决,判据同 ADR-0022 / ADR-0024「breaking 内容按 minor 号发布」先例):包根公开类型 `HookDefinition` 收缩两必填语义词字段、`HookErrorStrategy` 取值收窄、`HookRegistry.register`/`registerAll` 签名变化(配置表成为必填配对)、`bootstrapHarness*` 加参;迁移路径 = 把定义上的 `enabled` / `errorStrategy` 挪进 `HookConfig` 声明表并随注册传入。测试:`src/hooks/__tests__/registry.test.ts` 新增「注册即配对」4 项(配置填充有效值、名称不一致抛错、缺声明抛错、编译期钉)、`pipeline.test.ts` 改写为配置驱动并新增「配置 enabled:false 不进管线」反证、`bootstrap.test.ts` 补「给定义不给表即抛错」×2、`src/__tests__/hooks-pipeline.test.ts` 全量改用新 API(原 'ignore' 用例随有效面收缩删除)、`public-type-surface.test.ts` 类型清单 +`EffectiveHook`。**先红后绿**:新测试对旧实现全红(TS2554 签名不匹配 + 行为断言失败)。文档:`src/hooks/CONTEXT.md` 已知偏差条删除、「配置归一/唯一真相」表述改为与实现一致。
|
|
29
|
+
- fix(cli): `init --print-snippets --ci gitlab -g <level>` 打印面补齐治理任务——`printSnippets` 收 `governanceLevel`、gitlab 形改打 `renderGitLabCiJobs(governanceLevel)`(#157,#143 落地后统一复审 F3,#153 同源判据的 gitlab 形态)——此前打印链路打的是无 level 的 `GITLAB_CI_SNIPPET`(只有 `harness-check` 一个任务),而同一条命令真落盘的 `.gitlab-ci.yml` 在 `-g` 档含 `harness-governance` + `harness-docs-freshness` 共三个任务;照打印输出手工合并的 GitLab 用户静默少拿两道门禁。修复后与落盘 / 冲突分支共用同一个正本函数,不新建第二份 GitLab 正文。**对外行为变化 1 处**(定级**非 breaking / patch**,ADR-0022 判据同 #156):`--print-snippets --ci gitlab -g <level>` 的打印内容多两个任务——照旧抄的用户只会多拿到任务、无需改命令,命令语法、旗帜集合、退出码、落盘正文、公共导出面零变化;不传 `-g` 的 gitlab 打印面与 GitHub 形打印面逐字不变。`-g <非法值>` 走 #156 已落地的入口值域校验(`usage-error`、零打印零落盘),本票不加新分支。测试:`__tests__/init-ondisk.test.ts` 新增「init --print-snippets 的 GitLab CI 片段视图」describe 4 项——`-g standard` 同源闸(打印正文逐字等于 `GITLAB_GOVERNED` 字节级基线的任务段 + 与真落盘 `.gitlab-ci.yml` 按 YAML 解析比对 harness-* 任务集合,给落盘正本删一个任务集合即不等、闸必红)、script 集合闸(check / validate / passes-gate 一道不缺)、不传 `-g` 单任务回归、`-g` 非法值 usage-error 且零 CI 片段。**先红后绿**:实现前同源闸红(打印缺治理与 docs 新鲜度两个任务)。
|
|
30
|
+
- fix(cli): `init` 的 `--ci` × `-g` 组合边界统一——`--ci none` 真做到零 CI 文件,`-g` 值域校验提到命令入口(#156,#143 落地后统一复审 F1/F2,维护者裁决 2026-09-16)——**F1(major)**:`--ci none` 此前只挡住 harness-check 站点,治理 CI 面由 `-g` 独立触发且 `setupGovernanceWorkflow` 的平台豁免只认 `gitlab` 不认 `none`,于是 `init --ci none -g standard` 落 `.github/workflows/harness-governance.yml` 而 `config.yml` 同写 `ci.platform: none`——配置声称不接任何 CI 平台、磁盘上却有一份 GitHub Actions 文件(GitLab 用户选 `none` 拿到 GitHub 文件感受最直接)。裁决走「`none` = 不创建任何 CI 文件」:豁免口径由 `platform === 'gitlab'` 扩为 `platform !== 'github'`,治理 CI 面随 `none` 不建;治理文档面(CHANGELOG、约束段、CONTEXT.md)由 `-g` 独立决定、`none` 下照常生成(票面 out of scope 保留现状)。本条推翻 #143 CHANGELOG 记名的「有意保留」现状。**F2(minor)**:`-g <非法值>` 此前装配前无值域校验,gitlab 侧原样透传 `renderGitLabCiJobs` 落 `harness-check` + `harness-governance` + `harness-docs-freshness` 三个任务、github 侧 `GOVERNANCE_PRESETS` 查表 miss 静默不建治理站——同一非法输入两平台两种后果。裁决走入口校验(与 #152 脏输入 fail-loud 同判据):`-g` 合法值域 = `GOVERNANCE_PRESETS` 键集合(入口校验与装配共用同一份表),非法值在 CI 平台解析之后、任何落盘之前判 `usage-error` 退 1,github / gitlab / none 三平台同判。**对外行为变化 2 处**(定级**非 breaking / patch**):① `--ci none -g <level>`(含 `--no-github-actions` 别名)由「落 GH 治理 workflow」变为「零 CI 文件」——判据同 #138 缺省路径修复先例:恢复的是 `--ci none` 的声明语义、修掉的是配置与磁盘自相矛盾的缺陷状态,合法命令语法、旗帜集合、退出码、公共导出面零变化,受影响的只有依赖该缺陷组合产物的用法(迁移路径 = 要治理 workflow 就选 `--ci github`);② `-g <非法值>` 由「gitlab 落三任务 / github 静默不建」变为「三平台一致 usage-error 退 1、零落盘」——判据同 `[1.6.0]` 删 `--max-retries` 与 #152/#163 的「静默失效 → 报错」先例;合法 `-g` 值(minimal/standard/strict)在各平台下行为逐字不变。测试:`__tests__/init-ondisk.test.ts` 新增「init --ci × -g 组合边界」describe 5 项——`--ci none -g standard` 两投影(落盘文件集合 + config.yml 内容,版本归一化)逐字冻结、`-g` 非法值三平台后果一致(钉「一致」本身:跨平台 `toEqual` 对撞结果与落盘集合,非各自冻基线)、合法值 ×3 回归;既有「治理 CI 站点」用例原钉 #143 旧边界(`--no-github-actions -g` 自建 GH 治理 workflow),按裁决整体翻面板为新语义,其覆盖的 governanceWorkflowFile「自建 + 第二趟已存在」场景挪到「github 下既有用户 workflow 不覆盖治理命令」形(本站点唯一真落盘路径)保留。**先红后绿**:实现前两新用例红(none 组合多落 `.github/workflows/harness-governance.yml`、三平台 bogus 落盘集合互不相同);反证两处各改坏一次并还原——豁免写回 `platform === 'gitlab'` → 2 项红,入口校验删除 → 一致性用例红。文档:`--ci` 帮助文本与 `src/cli/commands/CONTEXT.md` 边界改写为「`none` = 不接线任何服务端 CI,治理 CI 面随之不建;治理文档面由 `-g` 独立决定」。`public-value-surface` / `public-exports` / `public-type-surface` 三闸清单零改动(`git diff` 为空,公共面未动)
|
|
31
|
+
- fix(cli): 数值旗帜脏输入全面 fail-loud——#152「数值旗帜装配口径」推广到剩余 7 面旗帜,统一解析器收口(#154,#152 resolution 第 3/4 点留账)——#152 只收了 `knowledge audit --threshold` 一处,其余数值旗帜的脏输入后果分两类留在账上:**静默降级**(`constraints report` 三阈值 NaN 过 `!== undefined` 进阈值槽 → 比较恒 false → 候选静默减少、退出码 0;`knowledge --limit` NaN 被 `|| 20` 兜成缺省量;`failure --limit` NaN falsy → 静默不截断;门禁 `--bundle-threshold` NaN falsy → 落 gate 缺省)与 **fail-closed 但文案自证异常**(`passes-gate --coverage-threshold` 打出「覆盖率不足 (x% < NaN%)」、`review --min-reviewers` 恒不通过)。落地:唯一解析器 `src/utils/numeric-flag.ts`(`parseNumericFlag` 判别 + `requireNumericFlag` 抛出 + `NumericFlagError`,trim 后全数字/一段小数才收,`parseInt`/`parseFloat` 的前缀截断 `'30abc'→30`、`'1e2'→1` 同脏值拒),CONTEXT.md 口径条目指名为正本、不建第二套(#152 的 `assembleShortContentThreshold` 改为委派同一规则,函数面与报错文案保留)。两消费形:定义表 `mapActionArgs` 站点(constraints report 三阈值、performance 两阈值、review `--min-reviewers`)走 `requireNumericFlag` 抛出、`bin/harness.js` 在 `runDefinition` 捕获映射 `usage-error`(定义表是纯数据模块返回不了 CommandResult,装配失败通道只此一条,bin 不新增单命令知识);命令模块站点(`knowledge search --limit`、`failure list --limit`、`passes-gate --coverage-threshold`)走 `parseNumericFlag` 就地 `logError` + `usage-error`,全部先于 store/recorder 构造与任何执行(脏值零落盘)。**fail-closed 两处不保留、一并收敛 fail-loud**(票面授权的裁定):脏输入属用法错误、自证异常的文案即缺陷。顺带修一处同源暴露的 io 漏传:`knowledgeSearchCommand` 调 `knowledgeSearch` 未透传注入 `io`(生产路径经缺省 `processIO` 无差,测试注入面静默漏字)。**对外行为变化**(定级**非 breaking / patch**,判据同 `[1.6.0]` 删 `--max-retries` 与 #152/#163 的「静默失效 → 报错」先例):合法取值路径逐字不变(未传 vs 显式缺省值输出逐字相等、显式 `0` 不被当未传兜掉——`knowledge --limit 0` 由兜回 20 改为真按 0 判定、其余站点 0 语义本就成立),命令语法、旗帜集合、`--json` 字段集合、公共导出面零变化;变化的只有脏输入面——四组静默降级站点由「退 0 + 结果少几条」变为报错退 1,两处 fail-closed 站点由自证异常文案变为可定位报错(review 1→1,passes-gate coverage 脏值 0→1)。边界不动:门禁/引擎构造器侧的 falsy/`??` 约定是库面向语义(显式 `0` 在 performance 门禁内仍 = 不检查该项),与 #163 同例不重复兜;`status --hours` 是死旗帜另族另票。测试:新增 `src/utils/__tests__/numeric-flag.test.ts` 26 项(解析规则矩阵)+ `src/cli/commands/__tests__/numeric-flag-assembly.test.ts` 30 项(定义表逐旗帜装配、命令入口 fail-loud、端到端真实 spawn `bin/harness.js`:脏输入 → 退 1 + stderr 点名旗帜 + stdout 零字节 + 零副作用落盘,未传 vs 显式缺省逐字对拍,显式 `0` 语义逐站钉住),**先红后绿**(红基线:模块缺失套件不可运行 + 脏输入退 0);`knowledge-view.test.ts` 闸 1 豁免表 2→3 行(search --limit 入参闸门,理由随表注);`public-value-surface`/`public-exports`/`public-type-surface` 三闸零清单改动。验收:`npx jest --runInBand` 全量 186 套件 2638 passed、`tsc --noEmit` 与 `eslint src` 零错、`node bin/harness.js check` 通过
|
|
32
|
+
- feat(knowledge): `KnowledgeAudit` 构造器对三个数值槽的脏输入 fail-loud——显式传入 NaN / ±Infinity / 负数时构造期抛 `TypeError`(#163,#155 留账、#152 同构「转不出来就响」;维护者已裁走法 1 构造器 fail-loud,收窄类型与引擎兜底回缺省两走法在 #155 明确否决、本票不复活)——三槽(`shortContentThreshold`/`staleDays`/`promotionBlockDays`)经 `resolveThresholds` 的 `??` 兜缺省,而 `??` 只兜 `null`/`undefined`、NaN 照单全收:NaN 进 ctx 后三处比较恒 false,`short-content`/`stale-entry`/`promotion-blocked` 三条规则同时静默关闭,构造方拿到零报错的正常审计结果。落地:守卫加在 `resolveThresholds` 上游的构造期(新增模块内辅助 `assertValidThresholds`,两处不重复兜),任一槽**显式传入**的值非有限或为负即同步抛 `TypeError`、message 含槽名与实参;未传/显式 `undefined` 走缺省逐字不变,显式 `0` 合法且按 0 生效(不被兜回缺省,口径同 #152 CLI 面「显式 0 不被当未传」),正有限值(含非整数)行为不变;`AuditOptions` 类型形状不动(仍 `number` 可选,走法 2 已否决)。CLI `knowledge audit --threshold` 行为零变化——上游装配点已挡脏输入,守卫不会被 CLI 路径触发。**对外行为变化 1 处**(定级**非 breaking**,判据同 `[1.6.0]` 删 `--max-retries` 与 #152 的「静默失效 → 报错」先例,落地复核成立:仓内 ingest 不传 options、CLI 已被 #152 挡住、studio 不传数值槽——零已知消费者受影响):库面直调 `new KnowledgeAudit(store, {…})` 传脏值由「静默关掉三条判定」变为构造期报错;合法取值的行为字节不变。测试:`src/knowledge/__tests__/audit.test.ts` 新增「构造器数值槽守卫(harness#163)」describe 17 项——三槽 × NaN/Infinity/-Infinity/-1 各抛 `TypeError` 且 message 含槽名与实参(**先红后绿**:实现前 12 条全红「did not throw」)、不传与显式 `undefined` 同果走缺省、显式 `0` 时 short-content 不触发且 `staleDays: 0` 下昨天引用的条目即判 stale(两槽各证「0 不被兜成缺省」)、正有限非整数(30.5)边界随入参移动。CLI 面闸 `knowledge-audit-threshold.test.ts` 与 `bin-exit-mapping.test.ts` 零改动全绿。文档:`src/cli/commands/CONTEXT.md` 数值旗帜装配口径段末「库面向的守卫另票」更新为本票结论、`src/knowledge/CONTEXT.md` 构造入参口径同步。验收:`npx jest` 相关 22 套件 554 项全绿、`tsc --noEmit` 与 `eslint src` 零错
|
|
33
|
+
- perf(sync-docs): 按需读取——capability-listing 模式对源码树**零内容读**,描述提取改并发而清单顺序逐字不变(#147,#140 B 票;ADR-0023 未收口三处之二)——`sync-docs` 入口此前无条件对所有源码目录全树扫描:逐文件 `await readFile` **只为取首行注释作描述**,而这份描述在 capability-listing 格式(本仓即是)下根本不进任何输出——该格式的判定面是计数,条目级比对与表格写回都住 file-table 分支,`currentModules` 在 listing 分支是自扫自用的死数据;串行 await 又在大仓上线性放大。改造形状 = **先判定「本次要什么」再决定「读什么」**:① `index.ts` 把 CAPABILITIES.md 的格式判定移到扫描之前(只搬读取路径,判定/漂移检测/写回内容一字未动),listing 分支自此整棵源码树一份 `.ts` 内容都不读;② 要描述的 file-table 分支照旧取描述,但 `project-reader.ts:scanSourceModules` 拆成两步——先按目录遍历序定清单(`name`/`file`),再经新增的 `extractFileDescriptions()` **并发**取数并**按原索引回填**,上限固定 16(按票下裁决不做成配置面)。**输出顺序逐字保持现状**是票面裁决:该顺序对外经 `--check` 的行级比对与人看 diff 可见,改字典序要付一次全仓漂移的代价(已裁不值),故「按并发完成顺序 append」按行为漂移对待而非优化。**对外行为变化 0 处**:判定、人读与 `--json` 两面、stdout 与退出码逐字节不变,`ModuleInfo` 与包公共面零改动(`extractFileDescriptions` 是本模块公共面,不进 `src/index.ts`)。实测数字对照(同一插桩、同一棵树)——本仓 listing 模式 `.ts` 内容读 **290 → 144**、命中文件 **161 → 144**,被消掉的 **146** 份正是扫描分支的全部读取(= 源码树内 `.ts` 排 barrel/`.d.ts`/`__tests__` 的文件数,与生成的模块表 146 行同源),余下 144 份是 CONTEXT 导出面采集(#142,票面范围外、一字未动);同树改判为 file-table 后两版构建读取数同为 **290**(本票不削减该分支的读取量,只把它并行)、在途并发 **1 → 16**、`--check` 三轮 **430/453/420ms → 408/398/407ms**(收益上限是 libuv 线程池缺省 4,票面承诺是「不再串行放大」而非倍增)。等值验收用真构建两版对撞:改动前(HEAD)与改动后两版 `dist` 跑同一棵树 `sync-docs --check`,**stdout 与退出码逐字节一致**;写回面同法——删掉 CAPABILITIES.md 让两版各自生成 146 行模块表,两份产物**逐字节一致**(行序与每条描述都对得上)。**测试**(新增 3 套件 / +12 项,全量 184 套件 2560 passed,改前同树同命令 181 套件 2548):`__tests__/sync-docs-read-count.test.ts` 形状照 `check-read-count.test.ts`(`fs.readFile` 与 `fs.readFileSync` 记件、原地清空防假绿)——listing 模式 `.ts` 内容读 = 0(**改前实测红:4 份**)、file-table 反证每份源文件恰读一次且描述确实进对外 JSON、CAPABILITIES.md 缺席走同一分支、listing 整张读取表冻结(表上 `CAPABILITIES.md=5` 是**本票范围外的既有重复读**:入口一次异步读 + 计数核对按每条计数规则各读一次,如实登记、不为它改动);`sync-docs/__tests__/module-descriptions.test.ts` 用替身把「起始序」与「完成序」刻意错开(起始靠后的读更快落地),钉住并发真发生、在途 ≤16、清单顺序 = 读取发起顺序、每条描述与自己那份文件配对(串位即红)、读失败回退文件名的兜底语义不变;`__tests__/sync-docs-module-order.test.ts` 冻结对外可见面(写出的表格行序 = 目录遍历序 = 扫描清单顺序,且两次运行逐字复现;**不写字面顺序**——`readdir` 返回序由文件系统决定,本仓 tmpfs 上是字典序、ext4 上是哈希序,写死等于把断言建立在机器上,故以遍历序为口径正本)。**反证已做**(四态各自实测):拆掉 listing 的扫描闸 → 计数闸 2 项转红、file-table 两项照绿(闸不空转);改按完成顺序 append → 配对/顺序 3 项转红;去掉并发上限 → 上限那条转红;退回串行 → 并发与顺序 2 项转红(与改前状态同形);四态全部还原后 12 项复绿。验收:`npx jest` 184 套件全绿(2560 passed / 6 skipped)、`npx jest --coverage --no-cache` 两态对撞四档全升(全局 lines **96.18% → 96.24%**、stmts 95.35% → 95.4%、branches 84.23% → 84.32%、functions 82.06% → 82.12%;`project-reader.ts` stmts/lines **79/81**、branches 10/17、functions 14/14,`sync-docs/index.ts` stmts 198/210)、`tsc --noEmit` 与 `eslint src` 零错、`npm run build` 绿、`node bin/harness.js check` 通过、`sync-docs --check` 零漂移。文档:`src/cli/commands/CONTEXT.md`「约定」新增「先判定本次要什么再决定读什么,且清单顺序是对外面」条。范围外按票面未碰:输出顺序改字典序、`agents-syncer.ts`(自有 sort)、`spec-baseline-check`(#146 已落)与 `check.ts getSmartHint`(#148)的读取收口、并发上限配置化
|
|
34
|
+
- perf(spec-baseline-check): 一次运行只扫一遍全仓——消除「前置条件数 × 关键词数 × 源文件数」的逐条重扫(#146,#140 A 票;ADR-0023 未收口三处之一)——工单 19 只把 `checkCodePattern` 的**文件遍历**收敛成一次 `walkFiles`,读取仍留在逐关键词的循环里:每个关键词把全部源文件 `readFileSync` 一遍(一条前置 K 个关键词就重读 K 遍),`checkDependency` 又逐条前置重新读取并 `JSON.parse` 一次 `package.json`。三条验证路径(文件存在性 / 依赖 / 代码模式)自此一律从**命令级共享索引** `createBaselineIndex(projectPath)` 取数:全仓 `.ts`/`.js` 内容扫描一遍建成 `路径 → 内容` 表(读失败的文件不入表 = 原逐文件 try/catch 跳过同义)、`package.json` 读解析一次且**失败态同样入库**(不逐条重试)、同一落点的存在性探测只 stat 一次;逐条前置与每个关键词只在索引上重放,匹配语义(`content.includes(kw)` 逐文件计数)逐字等价。索引**懒建**(没有前置要某类数据时该类读取一次都不发生,故纯存在性/纯依赖型 spec 不触发全仓扫描)且**运行结束即弃**——按 #140 triage 裁决 5 **不扩 `RunEnv` 公共面**(本命令是独立命令、不是 `harness check` 的子步骤,「同一口径取一次」命令内 memo 自足),四个验证器函数的 `index` 形参全为模块私有面。**对外行为变化 0 处**:判定、证据文案、stdout(人读表与 `--json` 两面)与退出码逐字节不变,`RunEnv`/`CheckEnv`/包根导出清单零改动。实测数字对照(同一插桩跑同一夹具:7 条前置含 2 条依赖 + 3 条代码模式各 2 关键词,6 份源文件)——内容读总数 **39 → 8**、`package.json` 解析 **2 → 1**、每个源文件 **6 → 1** 遍、全仓目录列举 **9 → 3** 次、存在性探测 **3 → 2** 次;关键词扩到 15 个(7 条前置)时改前每文件 15 遍、改后仍是 1 遍(计数闸第三条:两次不同条数的运行剔掉 spec 自身后读取表逐条相同)。**测试**(新增 1 套件 / +5 项,全量 181 套件 2548 passed):`__tests__/spec-baseline-read-count.test.ts` 形状照 `check-read-count.test.ts`(真执行、只在 `readFileSync` / 只读 `openSync` / `existsSync` / `readdirSync` 上记一笔)——整张读取表与目录扫描表逐条冻结(表上无 `dist/`、`node_modules/`、`.harness/` 条目即跳过口径未变的证据)、「除冻结条目外任何项目文件至多读一次」、N×K 缩放不变式、懒建(纯依赖 spec → 零目录列举)、`package.json` 读取失败态入库(两条依赖前置只尝试读一次且各报一次「无法读取 package.json」),每条断言带正对照(三条验证路径确实都真评估,防闸空跑)。**反证已做**:三枚 memo(源码索引 / package.json / 存在性)逐枚拆开后——拆源码索引 3 项转红、拆 package.json 4 项转红、拆存在性 1 项转红(冻结表用例),三枚全在时 5 项全绿,还原后复绿;改前状态另以 `git show HEAD` 的源文件跑同一枚计数闸量得(上表 39/2/6/9/3 即该轮输出)。等值验收用真 CLI 两版构建对撞:改动前构建(HEAD)与改动后构建分别跑同一夹具的普通模式与 `--json` 模式,**stdout 与退出码逐字节一致**(含 `✗` 行与黄色证据行,退出码同为 1)。验收:`npx jest` 全量 181 套件全绿(2548 passed / 6 skipped,改前同树同命令 2543 passed)、`npx jest --coverage --coverageReporters=json-summary` 两态对撞:全局 lines **95.37% → 96.18%**、stmts 94.58% → 95.35%、branches 83.39% → 84.23%、functions 81.81% → 82.06%,`spec-baseline-check.ts` 自身 lines **91/159 → 168/176**、branches 43/82 → 74/86、stmts 95/165 → 173/182(余下未覆盖的 9 条语句全是本票未动的既有分支:三处「无法从描述中提取 X」与两处「部分存在/依赖缺失」证据行、`implMatch` 追加关键词一支、`formatTable` 的空表早退与两条 `未满足` 排版行。**两态数字一律 `--no-cache` 量得**——jest 的 transform 缓存会跨源文件切换端出旧的插桩表,带缓存复测时同一棵树上读到过 159/165 与 176/182 两组互相矛盾的本文件分母,据此写下的任何对照数字都不可信)、`tsc --noEmit` 与 `eslint src` 零错、`npm run build` 绿、`node bin/harness.js check` 通过。范围外按票面未碰:判定逻辑与关键词/包名提取正则、证据文案(零改动)、`sync-docs` 与 `check.ts getSmartHint` 的读取收口(#147 / #148)、`traces.log` 相关读取。文档:`src/cli/commands/CONTEXT.md`「约定」新增「一次命令运行内同一份数据至多取一次」条
|
|
35
|
+
- test(hygiene): 33 个测试套件固定 `temp-test-*` 夹具迁移 `mkdtemp` 每轮唯一目录(#145;本条为 #162 复审遗留项 4 的补记——Unreleased 原 18 条里 #145 出现 0 次,而同为纯测试面的 #131 有条目,同车口径不一致)——对外影响为零的纯测试内部改动,但 33 个套件的夹具形状变了,后续读到红基线的人需要这条线索。口径记名:**测试内部改动同样入 CHANGELOG**(与 #131 同例),以免下次再争。
|
|
36
|
+
- feat(init): 新增第 9 个脚手架站点 `.git/hooks/pre-push`——推送前的本地全量防线(#144,#132 grilling 曝光的已知缺口)——pre-commit 可被 `git commit --no-verify` 绕过,而绕过后的内容此前**无任何本地拦截**直接离机(全仓无 pre-push hook)。落地形状走 #132 的 scaffold 三态模型:`scaffold.ts` 新增 `prePushHookFile` 工厂(目标路径 + 三态文案 + `mode 0o755`),正文住 `scaffold-templates.ts`(`PRE_PUSH_SNIPPET` / `renderPrePushHook`,与 pre-commit 同一形状:落盘正文 = shebang 头 + 打印片段,#103 判据),`init` 的 `setupGitHooks` 退化为「一条 plan 装两道 hook」,跳过策略仍在命令层(`--no-git-hooks` 一并覆盖本站点,**不新增任何跳过旗帜**)。三道决定按 grilling 定论钉死并写进 hook 正文:**① 不做增量**——不解析 pre-push 从 stdin 收到的 `<local_ref> <local_oid> <remote_ref> <remote_oid>` 清单,无论推什么(含删远端分支这种 stdin 空清单)整仓过一遍,钩子内两条命令一律 `< /dev/null` 不让子进程吃掉 ref 清单(`npx` 缺包时的交互确认一旦读到 ref 行会把 push 顶成一条看不出所以然的失败);**② 不内建逃生机制**——无环境变量开关、无超时、无「慢则降级」,唯一口子是 git 原生 `git push --no-verify`;**③ 定位不变**——本地 hook 是自检与提醒,门禁真正的落点仍是服务端 CI(`--ci` 维度,见 #143),pre-push 不替代它。**对外行为变化 3 处**(定级 **minor**,加性站点 + 两处文案):① 带 `.git` 的项目跑 `init` 现在多落一个可执行的 `.git/hooks/pre-push`,此后每次 `git push` 前先跑全量 `harness check`(不带 `--staged`)+ `harness validate`,任一失败非零退出挡住推送——**含新工程**:`init` 生成的缺省 `checkpoints.yml` 两条检查点跑 `npm run build` / `npm test`,脚本缺失的新项目真机实测 `git push` 会被 `❌ Validate failed` 挡下,这与同一份 `init` 生成的 `harness-check.yml` / `.gitlab-ci.yml` 里 `validate` 步骤的服务端语义完全一致(本地只是早一步撞到),出路是补脚本、改检查点或 `--no-verify`;② `init` 收尾「下一步」第 3 行由「正常开发,每次 git commit 会自动检查约束」改为写明两道分工(commit 查暂存的、push 查整仓的,**重复是设计使然**);③ `init --print-snippets` 新增 `Git pre-push hook:` 段(引导语同叙事),既有 pre-commit / CI 段逐字不变。pre-commit 既有内容按票面范围外**一字未改**,仓库自身的 `bin/install-precommit-hook.sh`(`npm run hooks:install`)仍是单道。**测试**(+1 套件 / +14 项,全量 179 套件 2541 passed):`scaffold.test.ts` 站点表 8→9(目标路径逐字冻结、`0o755` chmod、落盘态/在场态文案逐字、同源闸与「改落盘正文不改片段」反证探针扩到两道 hook 各一条),另加两枚静态闸钉住决定不被悄悄改回——「恰好 check + validate 两道」(`check` 不得带 `--staged`、出现第三条即红)与「不解析 stdin ref、无环境变量开关、无超时」;`init.test.ts` +3(可执行位、落盘正文形状、已存在时不覆盖且打印同源片段);`init-ondisk.test.ts` 整屏基线加一行、`.git/hooks/pre-push` 落盘**字节级冻结**(同 `GITLAB_PLAIN` 手法:改模板必须同步改基线,这个「同步」动作正是拦住门禁被削弱的地方)、第二趟第三态与「打印即磁盘正文」扩到 9 站点、第三趟用户接管表含本站点且一字节不动;新增 `pre-push-hook.test.ts` 走**真 git 真 push**(临时仓库 + 本地 bare 远端 + PATH 上的记账替身 `npx`,装上的是 `renderPrePushHook()` 正本而非手抄):两道全过→push 成功且调用序列恰为 `check`→`validate`、`check` 失败→非零退出且输出点名 `❌ Iron law check failed` 且远端一格未收、`validate` 失败→同样挡住(不是只看 check)、`--no-verify`→push 照过且钩子整个人没被调用、删远端分支(stdin 无 ref 清单)→仍整仓跑一遍。真机另跑一遍全链(`node bin/harness.js init` → 装上 hook → 真 `git push` 被挡 / `--no-verify` 放行 / 冲突分支与 `--print-snippets` 打印即落盘正文)。**同源反证已实测做正**:只往 `renderPrePushHook()` 追加一行 `passes-gate` 而不动打印片段 → 5 项转红(含 #103 同源闸与字节冻结基线),还原后全绿。**票面范围外未碰**(另开票):GitLab CI 接线缺口、服务端门禁改动、增量/按 refs 范围检查。验收:`npm test` 179 套件全绿、`tsc --noEmit` 与 `eslint src` 零错、`node bin/harness.js check` 通过(铁律 3/3、指导原则 3/3)、`sync-docs --check` 本票文档已同步。文档:`src/cli/commands/CONTEXT.md` 站点口径 8→9(「pre-push 为已知缺口,另开票」改为已落地)并新增「本地防线两道」条
|
|
37
|
+
- feat(docs): CONTEXT.md 新鲜度判定由 **mtime 比较**换为「核心导出」节与目录导出面的**内容对撞**,并进 governance CI(#142,架构评审 2026-09-14 批次;判定形状对位 ADR-0009,决策记 ADR-0025)——旧判定是「目录内最新 `.ts` 的 mtime 比 `CONTEXT.md` 新即报过时」,三种失真全部实测过:改一行注释算漂移;**什么都不改、只碰时间戳也算**(`git checkout`/`stash`/cherry-pick 都会刷新源文件 mtime——票面证据:`src/cli/commands/CONTEXT.md` 当天被 6 张票逐个更新、`git status` 干净、内容与实现相符却被报);接口真变了反而漏报(文档晚写一次就整目录洗白)。本会话同一命令在同一棵树上两次跑出**不同集合**(票面 4 处 vs 实测 6 处且与票面不重合),而 CI runner 是全新 clone、mtime 由 clone 顺序决定(同目录 `CONTEXT.md` 排序恒先于小写 `.ts`)→ 恒假阳性。另一半病灶是无人报警:`harness-governance.yml` 只 `sync-docs`(写入自愈)后对 `CAPABILITIES.md` 的 diff 报错,CONTEXT.md 无论漂多远 CI 不红——票面那 4 处就是这么攒出来的,而 agent 读代码前先读 CONTEXT.md,读到不实陈述直接下游误判。**新增纯判定** `src/core/constraints/context-reconcile.ts`(包内模块,不进 `src/index.ts` 导出面):`reconcileContext({contextMdContent, exportSurface, barrelExports?})` → `{declaredSymbols, ghosts, unlistedBarrelExports, hasCoreExportsSection}`,与 `capabilities-reconcile` 同一套覆盖/幽灵语义、同一个「判定不吃 fs、清单由调用方组装」的形状,不另造第二套对照逻辑;两个口径正本同为纯函数——`parseDeclaredExportSymbols`(只认 bullet **行首**反引号标识符,`/` 连接视为多声明,形参列表与 `(type)`注解剥掉,剥完非合法标识符的整条跳过 = `types.ts`/`audit-scoring`/`constraints/` 这类模块名条目)与 `parseExportStatements`(声明形 / `export { a, b as c }` 交导出名与本名 / 逐项与块级 `type` / `export default` / `export *` 的待解析 spec)。**fs 采集在 cli 侧**(`sync-docs/context-syncer.ts` 新增 `collectContextExportSurface(dirPath, projectPath)`:`findTsSourceFiles` 排 `__tests__/`、`.d.ts`,`export *` 与具名再导出沿仓内相对 spec 解析,越出 projectPath/命中 node_modules/跳过目录不并入,按正本声明剔除类型-only 并**核对具名再导出的本名是否真在正本里**——反证撞出这条:虚再导出会洗白幽灵,改名恰恰是最该抓的情形;环上核不到就从宽不判)。**口径不对称**(票面验收 4 要的可操作口径):幽灵方向值与类型一视同仁(文档写 `HookConfig`(type)就必须真有其物,且「某内部文件仍导出它」不足以救——导出面是全目录并集,改名要改到声明处),覆盖方向只要求 barrel 的**值**符号逐个可见(按字面要求全部再导出符号登记需往 12 份文档补约 500 个类型名,`core` 单个 barrel 就 63 项,而类型面早有 `public-type-surface`/`public-value-surface` 两道闸冻结清单),无 `index.ts` 的目录跳过覆盖方向(内部 seam 登记与否是文档裁量,`release/CONTEXT.md` 是先例);「出现在该节」按标识符边界匹配、inline 提及即算登记,但**其它 `## ` 节的正文不救**未登记。**级别内建、不加独立开关**(票下 Brief 裁决 3):内容漂移 → `--check` 判 fail 且 `reason` 直接点名文件与符号;mtime → 只打提示、不影响退出码,`process.env.CI` 置位时连提示都不给;写入模式**不改写 CONTEXT.md**(散文不可机械生成)、退出码面不变;`--json` 新增 `contentDrift: [{dir,file,ghosts,unlisted}]` 与 `summary.contextContentDrift`,`contextStale` 保留但自此只装 mtime 提示(CI 下恒空)。**进 CI**:`harness-governance.yml` 在 CAPABILITIES diff 门之后加 `Gate on stale CONTEXT.md`(`node bin/harness.js sync-docs --check`),按 #120 方案 A 先例清完存量**直接变红**、不给 warning + 限期档(给了就等于没接——第一批误报会把它磨成「预期失败」);不套「写入 + diff 门」那套(那是可机械自愈的表格格式专属,CONTEXT 是散文)。**存量清理按闸的全部报出执行**(票面写 4 处,接 CI 前必须清干净):7 个目录 32 项(31 未登记 + 1 幽灵)——core 12 / failure 7 / gates 5 / knowledge 3 / monitoring 3 / context 1 是公开值符号真漏登记,逐条核过消费者与签名后补进各自文档(例:`getTraceCollector`/`configureTraceCollector`/`createAnalyzer` 此前只在「约定」里被提到,不进「核心导出」就永远不可见);`cli/commands` 那 1 项是 bullet 行首反引号写的是 CLI 子命令名 `command`(非导出符号),按「行首 = 声明」约定加散文前缀,句子一字未删。**逐条核对**(闸只判符号面,散文靠人读;hooks/knowledge/monitoring/release/cli/commands 五份全文对撞实现)另出**五处不实陈述已改文档**(hooks 的类型正本在 `src/hooks/types.ts` 而 `src/types/` 无 hook 类型、两条已失效的消费边(core / CLI 初始化)、`HookRegistry` 方法枚举漏 3 个;monitoring 读入口漏 `getStats()`、`ContextTracker` 的 `context/session-manager` 消费边未列;knowledge 的「依赖 `src/types/`」不实、`audit-scoring`「不进导出面」对类型面为假;release 的同步闸门归属写错)**+ 五处「文档正确、代码待改」不改文档、另开缺陷票**(#159 hooks `HookConfig.enabled`/`errorStrategy` 零读取点、#160 release 清单同步闸门只做正向 `toContain`、#161 knowledge 三条:`absent` 报进 errors 与 `utils/frontmatter.ts` 正本裁决相反 / 外部内容三层防御第二层 `formatForPrompt` 生产零接线 / `rule` 降级边界差一);十处判定与证据逐条登记在 #142 票面,各文档原句就地标「现状偏差」并指回缺陷票。**对外行为变化 2 处同向**(定级 **minor**,标 `!`):① CONTEXT 内容漂移自 `--check` 起判非零退出并点名文件与符号(此前永不报警);② 「源码比文档新」不再判失败(此前会),CI 环境下不再产出该提示——判定面是从时间戳换成内容,不是单纯放松或单纯收紧。**消费方影响单列**(release note 必提):升级后 `sync-docs --check` 对所有消费方变严,studio 侧 49 个 CONTEXT.md 将获得这套新判定(其修复不在本票);已核实的缓冲是 init 生成的消费者工作流里该步骤带 `continue-on-error: true`(GitHub)/ `allow_failure: true`(GitLab),故消费方 CI 不会因本变更直接红。**测试**:新增 3 文件 36 项(19 + 5 + 12)——`core/constraints/__tests__/context-reconcile.test.ts` 19 项(判定与两口径,夹具取仓内真实写法,零 fs)、`sync-docs/__tests__/context-export-surface.test.ts` 5 项(采集、类型分型、`export *` 展开、跨目录正本核对、虚再导出不计入)、`__tests__/sync-docs-context-drift.test.ts` 12 项(fail 点名、mtime 降级与 CI 抑制、`--json` 形状、写入模式不改写);既有 `sync-docs-agents.test.ts` 一处断言随措辞改字(`可能过时` → `源码比文档新`),其判失败位点从 mtime 换成缺失判定。**票面验收 2 的反证两种都跑**:① 只改声明侧类名(`ContextTracker` → `ContextSink`)不动 barrel 与文档 → `CI=true sync-docs --check` rc=1 并指名 `src/monitoring/CONTEXT.md` 与符号;② 只往 `src/release/index.ts` 加一行公开值再导出 → rc=1 并指名 `src/release/CONTEXT.md` 与 `HARNESS_PACKAGE_NAME`;两者还原后 rc=0 且输出「所有文档都是最新的」。验收:`npm test` 178 套件 / 2527 passed / 6 skipped 全绿、`npx jest --coverage` 全局 **94.58% stmts**(#141 的 94.56% 不降;branches 83.36%、functions 81.79%、lines 95.37%;`context-reconcile.ts` stmts/lines/functions 100%、branches 94.11%)、`tsc --noEmit` 与 `eslint src` 零错、`npm run build` 绿、`node bin/harness.js check` 通过(铁律 3/3、指导原则 3/3)、`sync-docs --check` 在 CI 与非 CI 两态下均干净。文档:新增 ADR-0025(含**绕闸限度**登记:删整节或删 bullet 可消漂、无该节的文档两方向都不判、导出面是正则解析源文本故模板字符串里行首 `export ` 会造成假阴);`src/core/CONTEXT.md` 加新模块条目与 barrel 公开面条目、`src/cli/commands/CONTEXT.md` 记采集侧归属本层与降级语义,hooks/knowledge/monitoring/release/core/failure/gates/context 八份随核随改。范围外按票面未碰:`--agents` 半张闸(实测 AGENTS.md 零漂移)、`capabilities-reconcile` 既有判定、非 barrel 内部导出的登记要求、studio 侧修复。
|
|
38
|
+
- chore(cleanup): `effective-set` 的 `'throw'` 模式删除——共享筛选器的第二个模式失去生产调用方(#141,架构评审 2026-09-14 候选 1 步骤 3 的直接产物;判据 ADR-0022)——`filterEnabledEntries(knownIds, entries, {onUnknownId})` 是「config.yml 引用了哪些 id、哪些被 `enabled:false` 裁剪」的唯一实现(ADR-0001 收口),两个模式按语义分而非按调用方分:`'collect'` 归约束侧 `mergeConstraints`、`'throw'` 归门禁侧 `getEffectiveGates`。后者连同 config.yml 的 `gates:` 声明式面已随候选 1 收缩删除(commit `209511e`,理由记在 ADR-0002 文末「后续变更」),于是 `'throw'` 分支与 `unknownIdError` 选项**只剩自己的单元测试在供养**——一处「为两个消费方共用而抽出的共享件」退化成单消费方 + 一个无人使用的分支,正是 ADR-0022 定义的那类漏收面,只是这次由候选 1 的删除动作**新造**出来。**删**:`FilterEnabledEntriesOptions` 整个接口(唯一必填成员是 `onUnknownId`,单成员联合是空转开关)、`unknownIdError` 选项、函数体内的 throw 分支;签名退化为 `(knownIds, entries)` 的单一语义,`unknownIds` 保留(`mergeConstraints` 在用它做诊断)。**对外行为变化 0 处、零公共面变化**:`effective-set` 是包内模块,不在五个 `exports` 入口的名字清单里,三道公共面闸(`public-exports`·`public-type-surface`·`public-value-surface`)清单零改动且全绿。门禁侧将来若恢复声明式配置面,重建成本 = 一个 `if` + 一条错误消息,整段实现与测试在 git 历史里。**测试**:throw 那一组 3 条用例删除,collect 侧 4 条断言逐字保留(调用点随签名去掉第三参数);按 ADR-0022 决策 2 的先例(AC-007 改写为钉新形状)补三枚「新形状钉」——`filterEnabledEntries.length === 2` 运行期钉 + 两枚 `@ts-expect-error` 编译期钉(第三参数不再是合法入参、`FilterEnabledEntriesOptions` 不再是可导入类型),**先红后绿**:实现前实测 `TS2554 Expected 3 arguments, but got 2` 四处 + `TS2578 Unused '@ts-expect-error' directive` 两处令套件红。**票面验收 4 的反证两种都跑**:① 往函数里加一条真·无主分支(`process.env` 门控、签名不变)→ 7 项全绿,说明清掉的是无主分支而非把断言挪了地方;② 把删掉的选项按可选形参复原 → 两枚编译期钉各顶一次 TS2578、套件红,说明形状冻结有牙(挡得住「悄悄改回来」,ADR-0003 本意)。**同型面登记(票面第 4 条:只登记不顺手改)**:`src/utils/jsonl.ts` 的 `JsonlBadLinePolicy = 'skip' | 'throw'` 与本票病灶同形——11 个生产调用点一律传 `'skip'`、`'throw'` 只被自己的单元测试供养,但它**不属漏收**:工单 #82 裁决 1 明文保留该选项(「既不让静默丢数据成为框架缺省,也不强制统一策略」),且 `jsonl-skip-disposition.test.ts` 有一条活闸钉住「`'throw'` 调用点目前为零、出现即逐个裁决」;本票病灶两者皆无(无裁决记录、无 tripwire),故一删一留。另登记 `src/knowledge/lifecycle.ts` 的 `recordReference(…, source?: 'human' | 'auto')`——本仓唯一生产调用点只传 1 个实参,但 `KnowledgeLifecycle` 经包根导出、studio 侧消费未核实,删不删须先双仓查。验收:`npm test` 175 套件 / 2491 passed / 6 skipped 全绿、`npm test -- --coverage` 全局 **94.56% stmts 与 #139 基线逐位相同不降**(`effective-set.ts` 四项 100%)、`tsc --noEmit` 与 `eslint src` 零错、`npm run build` 绿、`node bin/harness.js check` 通过(铁律 3/3、指导原则 3/3)。文档:`src/core/effective-set.ts` 头部与 `src/core/CONTEXT.md` 的「门禁侧曾用、按语义保留」历史叙述压成一行去向指引
|
|
39
|
+
- fix(monitoring): `trace` 落点锚 `--project-path`——从别处跑 `check --project-path B` 时 trace 由写进调用方 cwd 改为写进 B(#139,架构评审 2026-09-14「附带发现」第 1 条;违反 #95「收到的根要传到自己每个 IO/执行点」)——`DEFAULT_TRACE_FILE` 是相对路径而采集器全程按 cwd 解析(建目录/追加/读/stat),生产构造点又是 cwd 锚定的模块级单例 `getTraceCollector()`(`configureTraceCollector` 生产调用点为零),于是约束评估真跑了 B、trace 落进 A,且按 projectPath 直读 jsonl 正本的消费方(`status`、`constraints report`)读不到刚写的记录——#95 点名的假绿族,且表现为**静默写错位置**而非报错。守护面两头漏:闸 2 冻结的是「src 减 cli」的 cwd 站点而这里是相对路径**默认值**,闸 3 的正则只认名字以 `Path` 结尾的键 + 字符串字面量,`traceFile: DEFAULT_TRACE_FILE` 因「键名不带 Path、值是常量引用」不撞闸。**修法按票下 Agent Brief 裁决取 A(构造收根)**:`TraceCollectorConfig` 新增可选 `projectPath`,给了则缺省/相对的 `traceFile` 一律 `path.resolve(projectPath, …)`、没给保持 cwd 解析(跨仓消费者 studio 两处直调靠「API 进程 cwd 恰好是项目」成立,近期零破坏,远期在自己组合根传根迁移);`DEFAULT_TRACE_FILE` 常量名不变、语义在 JSDoc 里明确为**项目相对片段**(不是可直接打开的路径);四个组合根(CLI `check`、CLI `report`、`bootstrapHarness` 与 `bootstrapHarnessSync`)改为每调用一次锚根构造 `TraceCollector`,形状照仓内先例 `cli/commands/failure.ts` 的 `getRecorder(projectPath)`,harness 内部对单例的消费归零。`getTraceCollector()`/`configureTraceCollector()` 按裁决**保留为公共面**(JSDoc 写明 cwd 锚定的兼容语义),摘除留待 studio 迁移后的收缩票。**对外行为变化 1 处**(定级 **minor**,公共面为加性可选字段):带 `--project-path` 从别的目录跑 `check`/`report` 时,trace 由落调用方 cwd 改为落目标项目 `.harness/logs/traces.log`;**不带 `--project-path` 的项目内使用逐字不变**(入口本就 `options.projectPath || process.cwd()`,锚定后解析出的仍是同一绝对路径,studio 缺省走这条)。存量杂散 trace 于 2026-09-15 判为垃圾数据并本机清理,无迁移。测试:新增 `src/monitoring/__tests__/trace-file-anchoring.test.ts`(真 fs 不 mock IO,两态各钉:收根→锚项目、不收根→锚 cwd,另覆显式绝对/相对 `traceFile` 与「读侧同锚」)+ `project-path-anchoring.test.ts` 站点 3(**红基线实测**:cwd=A 跑 `check --project-path B`,B 侧新增记录数 0、A 侧长出 `A/.harness/logs/traces.log`;并钉读-写闭环——`status --project-path B` 的 `记录数` 等于 B 正本行数且列出 check 落的约束);闸 3 两臂扩形(键名后缀 `Path` → `Path|File|Log` + 新增 `\w+(Path|File|Log)\s*[:=]\s*[A-Z][A-Z0-9_]+` 常量引用臂,只扫使用点不冻结常量定义)并带**反证用例**(未锚的 `traceFile: DEFAULT_TRACE_FILE`、`errorLog: 'logs/…'`、`summaryPath = './…'` 三形各顶闸一次;锚定形、绝对值、小写值、`maxFileSize` 不误报——实测全下游层命中恰好 3 处 = 既有 validator 豁免 + 本票病灶 + `trace-analyzer` 的 `summaryFile`,零假阳性);新增闸 4(`src/cli`、`src/hooks` 生产代码对 `getTraceCollector()` 零消费)。`trace-analyzer` 的 `summaryFile` 同型病灶与 `DEFAULT_FAILURE_LOG_FILE` 一并登记豁免不修(harness 侧无生产写点,与 studio 侧三件套迁移同票,#139 Out of scope)。随迁:`check.test.ts` 不再重定向全局收集器(改断言项目正本、切掉夹具种子行)、`check-read-count.test.ts` 删除已失效的重定向(写入不经读取计数器,冻结读取表逐行不变)、`check-drift` / `check-skip-output` 的 traces 模块替身由 `getTraceCollector` 换为 `TraceCollector` 构造形。验收:`npx jest` 全量套件全绿、`tsc --noEmit` 与 `eslint src` 零错、`node bin/harness.js check` 通过。文档:`src/monitoring/CONTEXT.md` 新增落点锚根约定条(含四处可检面)、`src/cli/commands/CONTEXT.md` 的 #88 注入形状与 #95 三道闸→四道闸、`src/hooks/CONTEXT.md` 组合根形状、`src/gates/CONTEXT.md` 的 #95 适用域描述
|
|
40
|
+
- fix(security): `harness security` 缺省扫描命令断链修复——`?? ''` 把「未提供」兜成空串,令三级兜底恒停在第二级、自动探测不可达(#138)——`src/gates/security.ts` 构造器 `scanCommand: config.scanCommand ?? ''` 把「未给命令」表示成空串,而 `scan()` 的三级优先级用 `??`(空串非 nullish),于是链恒在第二级返回 `''`、第三级 `detectScanCommand()` 全仓无可达路径;`runScan('')` 拿空串去 `exec` 直接抛 `The argument 'file' cannot be empty. Received ''` → 门禁自身报错退出而非判定,`harness security` 不带 `--scan-command` 必失败。根因是类型层不诚实:`SecurityGateConfig.scanCommand` 本就是可选,但 `this.config`/`getConfig()` 声明为 `Required<SecurityGateConfig>`,逼构造器兜空串。**修法**(票面方案 A,非 `||` 短路——不把空串当有意义的缺省位):构造器 `config.scanCommand || undefined` 把空串归一为 `undefined`,判定链保持 `??`(「未提供 = undefined」的唯一表示),`this.config`/`getConfig()` 类型随之由 `Required<SecurityGateConfig>` 改回 `SecurityGateConfig`(该类型仅 `scanCommand` 可选、其余三字段本已必填,故「scanCommand 可选、其余必填」正是类型本身,无需 `Required<>` 也无需新造别名);`detectScanCommand()` 恢复可达、内容不改(仍常量返回 `npm audit --json`)。**对外行为变化**(缺省路径,定级 **fix/patch 非 breaking**):不给 `--scan-command` 的 `harness security` / `harness security audit` 由「恒报错退 1」变为「按探测命令真跑一次扫描并按结果判定、退出码由扫描结果决定」;显式 `--scan-command <cmd>` 与 `context.securityScanCommand` 两条路径逐字不变;`--scan-command ""` 视为未提供 → 落到探测。定级核实:本仓 `.github/workflows/` 仅 `harness-check.yml` 调 `harness check --preset`,无任一处缺省 `harness security`;`harness security` 只出现在 README 示例与 `dist` 产物注释(非调用点);`getGate()`/`listRegisteredGates()`/`runGates` 生产零调用点,security 门禁只经其 CLI 命令进入,`harness check` 不受影响——与票下 Agent Brief「harness 与 studio 两仓 CI、studio-config 部署脚本均核实无缺省 security 调用点」一致,故无流水线依赖「security 必红」语义。测试:新增 `src/gates/__tests__/security-default-scan.test.ts`(门禁级)与 `src/cli/commands/__tests__/security-default-scan.test.ts`(命令级),**先红后绿、与修复同 commit**。替身不落 `child_process`(`security.test.ts` 顶层整体 mock 后 `exec('')` 照样回调桩数据、永不抛错——正是缺省路径一直亮绿灯的机制),改在 exec 唯一出口 `src/utils/exec` 的 `execAsync` 上打缝:记录门禁「实际下发去执行的命令字符串」并断言缺省时恰为 `detectScanCommand()` 的返回值 `npm audit --json`(断链时是 `''` → 红),缝替身对空串复现真实 exec 抛错以保持红/绿分界诚实;覆盖缺省 scan/evaluate、context 优先级、config 优先级、`--scan-command ''` 归一、`getConfig().scanCommand` 为 `undefined`、CLI `security`/`security audit`/显式命令四形。既有 `security.test.ts` 两条(context 命令 / config 命令)逐字保留。公共类型面:`SecurityGateConfig` 名字清单零改动(`public-type-surface` 闸绿),仅 `getConfig()` 返回类型 `scanCommand` 由 `string` 收窄为可选——本仓零消费者的纯类型面。验收:`npx jest` 全量 173 套件全绿(新增 12 项,含 `layering.test.ts` 逐目录分层闸——CLI 级用例落 cli 层避免 gates→cli 越界)、`tsc --noEmit` 与 `eslint src` 零错。文档:`src/gates/CONTEXT.md` 注意事项补 `SecurityGate` 三级优先级与实际生效语义一条(防后续读码者再以为探测是死代码)。范围外按票面另开票:按包管理器探测(读 lock 选 pnpm/yarn audit,`detectScanCommand` 维持常量)、`auditDetails` 的吞错(扫描失败仍 exit 0)、severity 阈值语义与漏洞 JSON 解析格式
|
|
41
|
+
- chore(cleanup): 零消费者与转发链第三轮·机械清账(#137,架构评审 2026-09-14 候选 8 + ADR-0022 判据)——判据照旧是删除测试:删掉后复杂度消失/集中,还是只是搬家。**删**三处零生产消费者:① `utils/exec.ts` 的 `isCommandAvailable()`/`delay()`(同文件 `runCommand()` 按票面保留);② `ProjectConfigLoader.isConstraintEnabled()`/`getConstraintSource()`——ADR-0022 型漏收,二者是 `mergeConstraints` → `getEffectiveConstraints`(ADR-0001 唯一生效集来源)的平行复印;③ `failure/types.ts` 兼容再导出 shim(工单 14 已把类型正本归位 `types/failure.ts`,转发链 `failure/types` → `types/failure` → `failure/index` → 包根的三跳里两跳是星号),删除后 classifier/recorder 与三个测试文件直连正本。**归位**:`normalizeTriggers()`/`matchesTrigger()` 从 `utils/exec.ts` 迁到新增 `core/constraints/triggers.ts`——harness#105 定的 trigger 匹配语义单点,此前住在 utils 层等于给 utils 挂一枚只有约束域会调的假接缝,`constraints/checker.ts` 与 `agent-prompt-renderer.ts` 的拉用点随之转为同目录 import。**子 barrel 星号收口**:票面点名的 8 处目录级 `export *` 全部改显式清单(`agents/index.ts` 2 处、`completion-checkers`、`failure/index.ts`、`hooks`、`knowledge`、`tools`),第 8 处即 `failure/types.ts` 那枚 shim——按票面「与 shim 一起裁决,避免一处删一处留」取删而非改写,故**零豁免条目**;同批新增 `src/__tests__/sub-barrels-explicit.test.ts` 把这条例子落成闸(src 下每个 barrel 扫 `export *`/`export type *`,豁免须逐文件登记理由,且登记了却已无星号也算死账红),ADR-0003 的禁令从此不只钉五个 `exports` 入口。**分层闸参数化**:`src/__tests__/layering.test.ts` 原先只守 `src/core/**` ↛ `cli`/`gates`/`monitoring` 一条边,types/utils 的回边与领域层互 import(如 `context/session-manager.ts` → `monitoring`)全部放行;改为「每个顶层单元(目录 + src 根文件)声明允许的下行集合、逐目录冻结」——20 个单元各一条 `DOWNSTREAM` 条目(新增登记闸双向对撞:未登记的新目录即红、登记了却已不存在的单元也红),测试文件另走 `TEST_ONLY_EDGES` 单列放行(夹具、core 测试回读包根 barrel、failure 测试覆盖 CLI 命令),免得把「failure 可值导入 cli」宣布进生产面;同层债逐条带注(`context` → knowledge/monitoring、`hooks` → monitoring 组合根),集合只多不减、还清即删条目。`scanViolations(relPath, code)` 改成纯函数(代码不从磁盘取),于是**反证进测试**:11 条合成越界边各红一次并指名到单元/文件/目标/源串,11 条合法边与噪声(type-only、同目录、node 内置、字符串字面量、注释里的示例 import)不误报——不再需要往 src 里塞临时文件;文件级真反证另做:`src/types/__night_probe__.ts` 注入 `import { constraintsReport } from '../cli/commands/constraints-report'` → 「types 零越界值 import」单项转红并打出该边,删探针后还原。**retire 内部重构**(`cli/commands/constraints-retire.ts`):两段约 27 行、只差键路径的 YAML 读-改-写合成一个 `setYamlEntry(filePath, label, section, id, patch)`;同一次 `retireConstraint` 里 `new ProjectConfigLoader().load()` 由 2–3 枚收成**一份观察面**(ADR-0023 决策 2 的形状,定义查找 / already_retired 判定 / custom 文件名解析共用;写盘后 `syncGovernanceInjection` 必须读新状态,故仍另起一枚);`:311` 手拼的退役判定改为复用 `project-config-loader` 新增导出的 `isConstraintRetired(customDef, disabled)`——它本就是 `mergeConstraints` 那条「禁用或条目带 `retired` 即不追加」规则的复印,现两处共消费。**验收 6 的落盘逐字一致由测试钉**:新增两枚逐字节冻结用例(内置落 config.yml、custom 落 custom-constraints.yml,含带注释原文件被重写的形态),钉的是 YAML 文本而非 `yaml.load` 后的对象——键序、两空格缩进、`lineWidth: 120`、`at:` 的单引号形状全在断言范围内;两枚用例在**重构前**先跑绿(照现状取基线),重构后逐字仍绿。装载次数由新用例钉住(custom 路径 `load()` 实测 3 次 → 1 次,红基线 3)。**公共面定级**(ADR-0022 追记第 5 条口径,双证据 = 五个 `exports` 入口源文件 + 已发布 npm 产物 `@dommaker/harness@1.7.0` 的 `.d.ts`):`isCommandAvailable`/`delay`/`normalizeTriggers`/`matchesTrigger` **非 breaking**——五个入口文件与五入口 `.d.ts` 全部零命中,它们只在随包出厂的 `dist/utils/exec.d.ts` 这份**文件**里,而 1.7.0 的 `exports` 恰只有 `.`/`./core`/`./presets`/`./context`/`./gates` 五个入口,深路径不可解析;`failure/types.ts` 同判(`dist/failure/types.d.ts` 出厂但不可经入口可达);`isConstraintEnabled`/`getConstraintSource` 是**类型面 breaking on `./core`**——`ProjectConfigLoader` 经 `dist/core/index.d.ts:13` 再导出,两方法签名在 published `dist/core/project-config-loader.d.ts:107,111`,删方法即改公开类面(值面冻结闸看不见类成员,故按人工双证据定级,见上),迁移路径 = 删引用(票面双仓核实零消费者);barrel 显式化与 `isConstraintRetired` 新增 **零公共面变化**——三道公共面闸(`public-exports`/`public-type-surface`/`public-value-surface`)清单零改动且全绿,即「五入口名字清单逐字未变」的机器证据。发布级别:含 breaking 一项,按 2026-09-09 人类裁决走 **minor**。**记名复核**:票面称 `runCommand` 已有生产消费者(`check-cache.ts`、`git-evidence.ts`),本仓复核那两处命中是**文档注释**(`check-cache.ts:17` 示例、`git-evidence.ts:46` 缓冲上限说明)而非 import——`runCommand` 当下生产消费者为 0,但票面明文「不得删」,故保留并在此记名,删不删由下一轮按同判据裁。**范围外不动**:`package.json` 子路径入口(`./core`/`./presets`/`./context`/`./gates`)删除按票面属 #131 阻塞项(值面冻结闸现已由 #131 落地,但删除另须裁决,不在本票);票面「明确不再提」清单(presets/、tools/、sdd ⊕ cli、monitoring collector↔analyzer、completion-checkers/、hooks/ 与 agents/、flywheel-metrics、capabilities-reconcile、KnowledgeLinter/HealthScorer)一律未碰。测试:新增 3 个文件(`core/constraints/__tests__/triggers.test.ts` 13 项随迁用例、`__tests__/sub-barrels-explicit.test.ts` 5 项、layering 参数化 52 项含反证)+ retire 3 项 + loader 4 项;删除面双向钉(`@ts-expect-error` 编译期钉 + 运行时键/原型断言),删多与复活都红。验收:`npx jest --runInBand --coverage` 172 套件 / 2471 passed / 6 skipped、覆盖率 **94.47% stmts**(#136 的 94.46% 不降;`core/constraints/triggers.ts` 四项 100%、`utils/exec.ts` 收缩后仍 100%)、`npm test` 并行 4 worker 同绿、`tsc --noEmit` 与 `eslint src` 零错、`npm run build` 绿且产物内零 `export *`、`node bin/harness.js check` 通过(铁律 3/3、指导原则 3/3)。文档:`src/CONTEXT.md` 把「禁 export *」的管辖面改写为「src 下全部目录 barrel + 豁免逐文件记名」;`src/core/CONTEXT.md` 补 `constraints/triggers.ts` 归位与 `isConstraintRetired` 判定单点两条、并把分层守卫描述改成参数化口径;`src/failure/CONTEXT.md` 的 `types.ts` 条目随 shim 消失改为「barrel 直连类型正本」。已知残留:`sync-docs --check` 的「CONTEXT.md 可能过时(源码比文档新)」位点由 4 处(hooks/knowledge/monitoring/release,#136 记名的既有漂移)增至 8 处——新增 4 处是本票动过 barrel/命令文件的 agents、completion-checkers、tools、cli/commands,逐条核对是 mtime 信号而非内容漂移(这些文档记的是模块级导出与职责,星号改显式清单不改它们所述的对外面),未为凑新鲜度改写正文
|
|
42
|
+
- perf(tests): `http_*` 检查族的重试退避加「等待」注入缝——串行套件不再为重试真等 24 秒(#136,架构评审 2026-09-14 候选 7)——`src/core/validators/check-handlers/http.ts` 的 `fetchWithRetry()` 把退避等待内联成 `await new Promise(r => setTimeout(r, 2000 * (i + 1)))`(状态码分支与 catch 分支各一处),`2000` 与 `retries = 3` 都是硬事实、无注入口。后果是最慢的测试路径与生产正确性无关:两个「mock fetch 直接 reject」的用例各真烧 2+4+6s,本会话基线实测 `src/__tests__/checkpoint.test.ts` 单套件 `--runInBand` **27.19 秒**,其中 **24.01 秒**(12002ms + 12012ms)就是这两处真等待(票面「约 45% 串行占比」复核成立;其余 44 条用例体合计约 77ms)。落地按 triage 裁决取方案 A 并修正其注入车辆(原措辞「sleep 提为 handler 可注入形参」与验证器固定的 `(check, context)` 分发不合——形参加不进去):`CheckpointContext` 加可选 `sleep?: (ms: number) => Promise<void>`(同类型既有的调用方注入位 `customHandlers` 已是这形状),`checkHttpStatus` / `checkHttpBody` 由「收 context 而从不读」改为把 `context.sleep` 透传给 `fetchWithRetry()` 的新形参,形参缺省 = 模块私有的真定时器实现,退避公式 `2000 × (n+1)`、`retries = 3`、调用点全部逐字不动。**不做** `retries` 与退避基数的可配置化(票面方案 A 的后半句按 2026-09-15 裁决移出——验收正是对着这两个固定缺省写的,投机可配置违反仓 simplicity first);**不取** jest fake timers(方案 B,裁决:要为待决 promise 重排测试并手动推进计时器,且与处理器用的原生 `AbortSignal.timeout` 相冲)。**对外行为变化 0 处**,定级非 breaking:发布类型 `CheckpointContext` 追加一个**可选**字段,未注入时缺省路径逐字不变,命令语法 / 旗帜集合 / 退出码 / 五入口公共面名字清单零改动(`public-exports`·`public-type-surface`·`public-value-surface` 三闸零改动),下游按 `CheckpointContext` 构造对象的代码不受影响。测试:新增 `src/core/validators/__tests__/http-retry-sleep.test.ts` 10 项——注入替身侧 8 项把重试语义钉成「尝试次数 = retries + 1(fetch 恰被调 4 次)」与「退避序列 = 2000/4000/6000」(`http_status`:持续抛错 / 5xx 后恢复 / 429 后恢复 / 5xx 用尽后返回最后响应判不匹配 / 404 非可重试只试一次 / 首次即成功零退避;`http_body`:持续抛错与不重试两形),另两项分别为**分发接线闸**(经 `CheckpointValidator.validate()` 传入,证明 context 真抵达 handler,而非只在直接调用的形状里成立)与**缺省路径闸**(不注入 sleep,用同步触发的 `setTimeout` 替身记到 `[2000, 4000, 6000]`——生产缺省仍是真定时器且序列不变,而这一项自身零真等待);既有两条重试用例改为注入记录型零等待 sleep,断言只增不减(`passed` + `message` 两条原样保留,新增尝试次数与退避序列两条),随真等待消失移除其 `20_000` 毫秒超时兜底。**三道反向验闸各改坏一次并还原现场**:`checkHttpStatus` 改回不读 `context.sleep` → 注入侧 4 项 + 接线项红(且各退化到 5 秒超时,正是本票要消掉的形态);缺省 `realSleep` 改 no-op → 仅缺省路径项红;`retries = 3` 改 2 → 尝试次数与三项序列的断言共 7 项红(含既有套件那 2 项)。**前后对照**:`checkpoint.test.ts` 套件墙钟 **27.19s → 1.87s**(`--runInBand`,热缓存;本机 4 核并发负载均值 7.7 时另测得 2.9–4.2s,故同时给负载无关的口径——46 条**用例体合计 24.09s → 82ms**,两条重试用例 12002+12012ms → 3+2ms);全量 `npx jest --runInBand --coverage` 170 套件 / 2420 passed / 6 skipped、覆盖率 **94.46% stmts**(#134 记的 94.29% 不降)、`npm test` 并行 4 worker 同绿(21.4s,票面提到的并行 SIGTERM 现象本会话未复现)、`tsc --noEmit` 与 `eslint src` 零错、`node bin/harness.js check` 通过(铁律 3/3、指导原则 3/3)、`sync-docs --check` 仍只剩 hooks/knowledge/monitoring/release 四处既有漂移。文档:`src/core/CONTEXT.md` 的 `validators/` 条目补记「`check-handlers/` 各族统一 `(check, context)`,context 即注入车辆,等待类副作用经 `CheckpointContext.sleep` 注入、不再内联」。范围外按票面裁决不动:`src/cli/commands/posteval-plan.ts` 里另一份同名 `fetchWithRetry`(自带 `retries` 形参、无等待注入口,但不是本票的 interface);约 30 个测试文件共用的固定 `temp-test-*` 工作目录模式(含 `src/knowledge/__tests__/store.test.ts`)——triage 判为独立关注点、与观测到的 SIGTERM 大概率无关,是否另票属 maintainer 决定,本票未碰
|
|
43
|
+
- refactor(gates): `CommandGate` 三条同构匹配循环收成一个谓词 + 两个零消费者配置位删除(#135,架构评审 2026-09-14 候选 6)——`CommandGate` 的一份规则表服务三个入口(`check()` 经 `checkBlacklist()`、`isAllowed()`、`getRiskLevel()`),三条循环逐行同构(类别忽略 → 模式测试 → 按级别分派),改一条匹配语义要动三处;同批核出三处「声明与执法背离」:① `CommandGateConfig.strict` 的类型注释承诺「warn 也阻止」、CLI `--strict` 把它写进构造参数,而三条判定循环从不读取它(全仓唯一读取点在构造器)——带不带旗帜判定完全一致;② `CommandGateConfig.customBlacklist` 除构造器与类型声明外两仓零生产注入者(`addRule()` 才是已存在的运行时扩展点),是给下游的假扩展点;③ CLI 默认分支用带配置创建的实例、`--level` 分支却调模块级单例出口,传进去的配置到不了判定。三份同构循环还顺带藏着第四个后果:`getRiskLevel()` 取规则表里**首条**命中的级别,若首条级别较低而命中集合里另有阻断级,它报出的等级与同一条目在 `check()` / `isAllowed()` 上的裁决相反(`--level` 因此可判 high 之外而默认分支判阻断,退出码 0)。落地按 triage 两项裁决(判据 ADR-0018 / ADR-0022):**匹配单点化**——新增私有谓词 `matchCommand(command) → 命中规则集合`(遍历规则表、类别忽略、模式测试只在此处)与折裁点 `judge(command)`(级别 → 三桶 + `allowed` + `riskLevel` 只在此处解释),三个入口退化为该裁决的三个投影,等级改取命中集合最高档(不变式「存在阻断级命中 ⟺ `check` 不通过 ⟺ `isAllowed` false ⟺ 等级 high」);**两个配置位删**——`strict` 不接进判定(接进等于为一个零消费者开关新增「warn 级命中从此阻断」的执法语义),连 CLI `--strict` 旗帜一并 removal,`customBlacklist` 连同构造器合并段删除。**对外行为变化**(breaking,发布级别随本车 ship 时裁决,判据同 ADR-0018/0022 的 minor 先例;studio 侧对删除面零引用):`CommandGateConfig` 收缩两字段(现只剩 `ignoreCategories`)、`harness command` 删 `--strict` 选项、多重命中输入上 `harness command --level` 报告的等级可能由低变高(但与同一条目的裁决一致)。第三项裁决同时把 hook 侧现状定成正本:`src/pretool-use-hook.ts` **保持裸构造**、不引入项目配置装载(「hook 只用出厂规则、fail-open」写进 `src/gates/CONTEXT.md`,配置装载只属于 CLI 侧),CLI 的 `--level` 与默认分支改共用它创建的那台实例。测试:新增 `src/gates/__tests__/command-single-predicate.test.ts`(**源形状闸**:`pattern.test(` / `ignoreCategories.includes(` / 遍历规则表的循环体各恰好一处、级别 `switch` 归零——红基线实测 3/3/3;**三投影一致性闸**:单条命中、不变式对撞、**次序无关的正对照**(warn 排在 block 前 → 旧语义报 medium、新语义 high)、忽略类别对三投影同样生效,输入一律用 `addRule()` 挂的合成规则,不涉规则表内容)+ `src/cli/commands/__tests__/command-gate-dead-options.test.ts`(定义表旗帜面逐字冻结不含 `--strict`、`@ts-expect-error` 编译期钉三个已删字段、配置读取面运行期形状钉、CLI 源面禁再引单例出口;手法照 `passes-gate-dead-options.test.ts`);既有 `customBlacklist` 用例改走 `addRule()`;CLI `--level` 替身补 `getRiskLevel` 并新增「等级取自本命令创建的那台实例、全程只创建一次」;`project-path-convention.test.ts` 的 cwd 豁免理由随旗帜面收缩改字。三道闸先红后绿。记名不动:三个模块级便捷出口(`getCommandGate` / `isCommandAllowed` / `getCommandRiskLevel`)自此在本仓生产路径零消费者,但它们是包根与 `./gates` 的冻结公开面,删除属另一张公共面收缩票(ADR-0022 口径)。对外措辞纪律(PIT-021):本票的 commit message / CONTEXT / ADR 只写泛化表述,不复述规则表内容、不写具体规则的匹配样例与生效范围结论。验收:`npx jest --runInBand --coverage` 169 套件 / 2410 passed / 6 skipped、`tsc --noEmit` 与 `eslint src` 零错、`node bin/harness.js check` 通过、真 CLI 冒烟(`command --list` / 默认裁决 / `--level` 两档 / `--json` / 已删旗帜报错)。文档:新增 `docs/adr/0024-command-gate-single-predicate-and-config-trim.md`(两项删除裁决与判据、hook 决定、记名残留)+ `src/gates/CONTEXT.md` 两条约定(匹配语义单一落点、hook 只用出厂规则)
|
|
44
|
+
- refactor(knowledge): `KnowledgeAudit` 改收 store + 补「按 id 部分更新」的批量出口 + 知识树排除口径单点化(#134,架构评审 2026-09-14 候选 5)——`lint` / `doctor` / `query` / `lifecycle` / `ingest` 五个兄弟模块全部「构造收 store」,唯独 `KnowledgeAudit` 收 `baseDir` 并自建 `FileKnowledgeStore`,后果是 D1–D7 纯打分判定**必须先有真目录**:`audit.test.ts` 里 `makeTmpDir()` 出现 **47 次**,全部只因构造签名(该构造顺带 `mkdir`)。同车的三处放大与一处口径分叉:① 修复/衰减循环逐条 `store.update()`,而 `update()` = get→save、`save()` 每次全量重写 `index.json` → 一次 `audit --fix` 的代价 = 问题条数 × 一次全量索引重写;② 打分核心内嵌两处 IO(直读 baseDir 下 `.consumption-stats.json`、经 `getSurvivalRate()` 读快照),纯判定与取数搅在一起;③ 知识树 4 套 walker 各写各的排除清单,`harness knowledge index` 落在 baseDir 的生成物 `_index.md`(无 frontmatter)被 `harness knowledge migrate` 判成 `no frontmatter found` 计入 errors——同一份树两个命令两套人口,且 `knowledge audit` 的人读路径收尾就重建 `_index.md`,故这条在真实使用里必然发生(实跑复核:1 条目 + `_index.md` → `total: 2 / errors: ["_index.md: no frontmatter found"]`,同一目录 `store.list()` 只报 1 条)。落地按 triage 三项裁决:**拆纯模块**——新增 `audit-scoring.ts`(规则表 + `scanEntries` / `summarizeIssues` / `computeDimensions` / `calculateHealthScore`,零 fs,环境数据经 `AuditEnv` 喂入),`audit.ts` 693 → 135 行退化为 store 装配层;**两处 IO 归 store 供给**(不走 RunEnv——那是 check 侧对项目/git 的观察面,owner 不对)新增 `store.getConsumptionStats()`(照 `getSurvivalRate()` 形状;缺文件/坏 JSON = `undefined`,即「无数据」而非「零消费」);**新增 `applyAll(updates)`**——与 `saveAll` 是两个函数、不改 `saveAll` 签名(它有 cold-start import 4 处生产消费),语义 = `update(id, partial)` 的批量形(逐条 get→合并→只更内存索引→结束单次 `writeIndex`;未知 id 逐条跳过、空批零读写),`audit --fix`、`lifecycle.runDecayCycle()`、`reference-tracker.updateReferencedBy()` 三个循环改走它(顺带把 `save` / `saveAll` / `applyAll` 三处各抄一遍的「条目文件正文落盘」写法收成 `store.writeEntryFile()`,落盘字节逐字不变);**排除口径统一到「排除」**——新增 `tree-walker.ts`(`isEntryFile` / `isInfraDir` / `INDEX_MD_FILE` / `SNAPSHOTS_DIR`),store 顶层扫描、migration 顶层扫描、index-generator 递归扫描三处共消费同一份;`import.ts` 的 docs 扫描按「吃的是**项目文档树**、本口径在它那里没有对应物」原地记名而不改(统一的是排除口径,不是遍历深度——store/migration 顶层、index-generator 递归,这是现状不是分歧)。**对外行为变化 4 处**:① **breaking**——包根公开类 `KnowledgeAudit` 构造签名由 `new KnowledgeAudit({ baseDir, … })` 变为 `new KnowledgeAudit(store, { 阈值 })`,`AuditOptions` 随之去掉 `baseDir` 与**从未被读取过**的 `autoFix` 字段(类型名保留,`public-type-surface` 五入口清单零改动),迁移路径 = 先 `new FileKnowledgeStore({ baseDir })` 再把它传进来;② `knowledge migrate` 不再把 `_index.md` 计入 `errors`,`total` 也不再把它算进人口(假阳性修正,`migrate --json` 两个计数随之变小);③ 库调用方可见的写放大收敛:一次 `audit --fix` / 一轮 `runDecayCycle()` / 一次 `updateReferencedBy()` 的 `index.json` 重写次数由「修复条数」降为 **1**(条目 `.md` 的写次数逐条不变);④ **breaking**——包根公开接口 `KnowledgeStore` 由 13 成员增至 15 成员:新增**必选**方法 `applyAll(updates: StoreUpdate[]): void` 与 `getConsumptionStats(): ConsumptionStats | undefined`,库侧自定义 store 实现者编译期即破(`public-type-surface` 是名单闸、只比名字清单不比成员,看不见这一类;本条由 #162 统一复审补记定级,成员本身保留),迁移路径 = 自定义实现补上这两个方法。定级:随本车 ship 时裁决,判据同 `[1.7.0]`(本包唯一消费者为 studio,且 studio 侧按 `KnowledgeAudit({baseDir})` 直调——`.scratch/harness-deep-clean/research-studio-usage.md:157` 记着这形,故 ① 需 studio 同步跟进,属 ship-chain 阶段 2 的采纳动作)。测试:`audit.test.ts` 的 `makeTmpDir()` **47 → 5**(其余走内存 store 双 `MemoryKnowledgeStore`——它实现同一 `KnowledgeStore` 接口,接口再长即编译期报错;46 项既有断言逐条保留、用例 46 → 53,新增含「`validate()` 全程不碰存储」的 Proxy 钉、D7 有/无快照两形、reject 类问题不产生修复动作);新增 `audit-scoring.test.ts` 19 项(**源形状闸**:打分核心零 `fs` import、零 `fs.*` 调用、零 store 构造;另收 `resolveThresholds` 缺省、`scanEntries` 的人口语义、`summarizeIssues` 键集与 label 表闭环、D6/D7 环境数据入参、四档 severity 权重与 fragment-cluster——后两者此前无任何测试);新增 `tree-walker.test.ts` 6 项(谓词 + **三处对撞同一份条目人口**:同一棵带 `_index.md` / `.snapshots` / `.archive` / `resolutions` 的树,store / migration / index-generator 报出同一集合);新增 `audit-write-count.test.ts` 2 项(真执行 + `jest.mock('fs')` 记底层写、手法照 `check-read-count.test.ts`:4 条修复 → `index.json` 恰 **1** 次重写、4 个条目文件各 1 次,正对照断言 `autoFixed === 4` 防闸空跑);`store.test.ts` 加 `applyAll` 8 项 + `getConsumptionStats` 4 项(含「与逐条 `update()` 的落盘结果逐字节相同,只是少重写索引」对撞);`lifecycle.test.ts` / `reference-tracker.test.ts` 各加一次 stringify 计数项(3 条 → 1 次;**红基线实测 3**,并因此暴露 `mockRestore()` 会清空 `mock.calls`、断言必须落在 try 内)。`knowledge.test.ts` 的 audit describe 因视图层现在会真构造 store(构造即 `mkdir`)而补 ctor 替身(免测试把 `/custom/path` 写到真盘),其对 `KnowledgeAudit` 的接线断言改钉 `toHaveBeenCalledWith(store, { shortContentThreshold: 30 })`。三道闸先红后绿。验收:`npx jest --runInBand --coverage` 167 套件 / **2396 passed** / 6 skipped、覆盖率 **94.29% stmts**(较 #153 的 94.22% 不降;`audit-scoring.ts` 97.88%、`audit.ts` 97.67%(行 100%)、`tree-walker.ts` 100%)、`tsc --noEmit` 与 `eslint src` 零错、`node bin/harness.js check` 通过(铁律 3/3)、真 CLI 冒烟(`knowledge audit --fix` 3 条修复正常落盘并重建索引;同目录 `knowledge migrate --json` 由 `total 4 / errors 1` 变 `total 3 / errors []`;`knowledge stats` 人口不受 `_index.md` 在场影响)。范围外按票面裁决不动:`store.list()` 每条一次 `findFile()` 线性扫索引的 O(N²)(待实际规模重新量一次再判是否单开票)、`saveAll` 本体、#106 的 mtime+size 索引缓存、lint/doctor/query 自身构造。同型残留记名于 `src/knowledge/CONTEXT.md` 另票评估:`lint.ts` 三处 autoFix 的逐条 `update()`、`recordReference()`(逐事件调用且返回更新后条目并触发回调,批量化会改它的契约)、`ingest.mergeEntries()`。文档:`src/knowledge/CONTEXT.md` 新增三条约定(树排除口径唯一正本、循环内禁止逐条 `store.update()`、审计判定脱离 fs 可测)+ 两个新包内模块条目 + 残留记名;`src/cli/commands/CONTEXT.md` 的 #133「后到者适配」条款改为已适配并记名落点
|
|
45
|
+
- fix(cli): `knowledge audit --threshold` 的声明与运行时收口 + 脏输入 fail-loud(#152,#133 搬运时记名的那笔账)——`KnowledgeAuditOptions.threshold` 声明 `number`,而 commander 的 `--threshold <n>`(含缺省 `'50'`)给到的恒是字符串,两处形状相反靠 `parseInt(options.threshold as any, 10)` 躲过编译期(`as any` 把「这旗帜实际是什么形状」从编译器手里拿走,`git log -S` 指向 `4c3577e`)。后果是脏输入 `--threshold abc` → `parseInt` 出 NaN → 引擎侧 `?? 缺省值` 只兜 `null`/`undefined`、NaN 照单全收 → `len < NaN` 恒 false → **短内容判定静默不触发而退出码仍是 0**(端到端实测复现:同一 2 条目知识库,缺省报 `short-content: 1`、`--threshold abc` 报 `0`;`30abc`/`1e2`/`0.7` 亦静默误读)。落地按「声明与运行时一致」判据取窄化在命令模块装配点那一形(knowledge 族是纯投影条目、编组归命令模块,与 `knowledgeSearchCommand` 的 `--limit` 同形;不给 `CommandSubcommand` 补 `mapActionArgs`——那是为通用引擎加单命令知识):声明改 `threshold?: string`,`assembleShortContentThreshold` 只认「trim 后全数字」→ 非负整数,未传落引擎缺省、显式 `'0'` 不被当未传,转不出来 `logError` + `usage-error`(bin 映射退出码 1,审计与索引重建均不发生);引擎侧 `audit.ts` 的 `??` 不重复兜(上游已挡)。**对外行为变化 1 处**:脏阈值由「静默少一道判定 + 报告里可能打出『阈值 NaN』」变为报错退 1;命令语法、旗帜集合、`--json` 字段集合、合法取值的输出字节全部不变(非 breaking,判据同 `[1.6.0]` 删 `--max-retries` 那条「静默无效 → 报错」)。测试:新增 `__tests__/knowledge-audit-threshold.test.ts` 17 项(真 KnowledgeAudit,证阈值落进判定而非参数传到——脏值 10 形 fail-loud 且 stdout 零字节、不写盘;未传与显式 `'50'` 逐字同果;`'30'`/`'40'`/`'29'` 边界随入参移动;显式 `'0'` 不被兜掉;`knowledge.ts` 零 `as any`)+ `__tests__/bin-exit-mapping.test.ts` 端到端补一条「脏阈值 → 1」;三道闸先红后绿(红基线:脏输入退 0、字符串实参在 `threshold: number` 下 TS2322 编译不过)。既有面:`knowledge-view.test.ts` 闸 1 的 `kind:` 逐行冻结豁免表随 #152 增第二行(理由随表注,同 search 缺参那条——入参闸门而非投影出口),其余 65 项含 json 字段清单与人读逐行冻结零改动;`public-value-surface`/`public-exports` 三闸零清单改动。同型自查(票面第 3 点,登记不改):`knowledge.ts` 的 `as any` 归零,本目录其余 7 处(acceptance/contract/performance/security/status)不在数值旗帜装配链上;其余 `<n>`/`<rate>` 旗帜的声明与运行时形状全部一致(`status --hours`、`constraints report` 三阈值、`passes-gate --coverage-threshold`、门禁 `--bundle-threshold`/`--min-reviewers`、`knowledge`/`failure --limit` 均在装配点显式转一次,`failure --limit` 且声明双形),但脏输入的下游后果分两类——fail-closed(coverage 阈值 NaN → 恒判不足;`min-reviewers` NaN → 恒不通过)与静默降级(`--noise-*` NaN 进阈值槽 → 候选静默减少;`--limit` NaN falsy → 落缺省 20/不截断;`--bundle-threshold` NaN falsy → 阈值不生效),另 `status --hours` 转出的数值全仓零消费者(死旗帜,与 `init-dead-options` 同族)。统一收法(装配点抽 fail-loud 的数值旗帜解析器)另票。验收:`npx jest --runInBand` 163 套件 / 2299 passed / 6 skipped、`tsc --noEmit` 与 `eslint src` 零错、`node bin/harness.js check` 通过(铁律 3/3、指导原则 3/3)、`knowledge.ts` 行覆盖 94.55%(本票新增行全覆盖,未覆盖行 165-170/194-195/518/600-605/611-612/652 均为既有分支)、真 CLI 冒烟(`--threshold abc` 退 1 且无报告 / `--threshold 30` 让 30 字符条目退出判定 / 缺省仍 `阈值 50` / `--threshold 0` 一条不报)。文档:`src/cli/commands/CONTEXT.md` 新增「数值旗帜装配口径」条目
|
|
46
|
+
- fix(cli): `init --print-snippets` 的 GitHub Actions 片段由落盘正本裁剪派生(#153,#132 resolution 记名的那处「未动」)——`--print-snippets` 打印的 `GITHUB_ACTIONS_SNIPPET` 是 `HARNESS_CHECK_WORKFLOW` 之外的第二份手抄 YAML:实测 230 字符对 608 字符、steps 只到 `harness check`,比同版本 `harness init` 落盘的 workflow **少 `validate` 与 `passes-gate` 两道门禁**,两份文本之间且无同源闸(连空行与 `- name:` 都各写各的,`HARNESS_CHECK_WORKFLOW.includes(GITHUB_ACTIONS_SNIPPET)` = false)。用户照指引把 job 粘进现有 workflow,得到弱一半的 CI 且无任何提示——这是 #103 判据的第三种形态:不是「打印的文字与落盘的不同」而是「打印的功能上更弱」;同一命令里两种「给你看要写什么」的形状(CI 冲突分支打全文、旗帜打弱片段)也自相矛盾。落地:`scaffold-templates.ts` 删掉手抄常量,改为 `HARNESS_CHECK_WORKFLOW.slice(indexOf(' harness-check:'))`——单一正本 = 落盘的 workflow,片段是它 `jobs:` 段之后的一切(494 字符),形状与 #143 的 GitLab 侧「打印的任务正文是落盘全文的尾巴」对仗;`init.ts` 引导语 `添加到 .github/workflows/*.yml 的 jobs 中` 改为 `添加到 .github/workflows/*.yml 的 jobs 下(以下正文取自 harness-check.yml 的 job 段)`。**不取**「保留弱片段 + 加一行免责标注」那条形(免责行不解决「照抄就少两道 gate」);若认为片段视图**应当**只装 `check` 一步,那是功能取舍,须回炉重裁、本票未擅自做。**对外行为变化 1 处**(定级判据同 `[1.6.0]` 删 `--max-retries` 与 ADR-0022,发布级别随本车 ship 时裁决):`--print-snippets` 的 GH 片段正文变长(补 `validate` / `passes-gate` 两个 step、step 带 `- name:`、前导空行由 2 行并为 1 行以对齐 GitLab 段)加引导语改字;命令语法、旗帜集合(`--print-snippets` 保留不删旗)、退出码、**落盘字节**全部不变,迁移路径 = 无需改命令,照旧抄即拿到与 `harness init` 同强度的 CI。测试:三道闸先红后绿——`__tests__/init-ondisk.test.ts` 新增「init --print-snippets 的 GitHub Actions 片段视图」3 项(**同源闸**:打印的 job 正文逐字等于 `harness-check.yml` 字节级冻结基线 `jobs:` 段之后,且是 init 真正落盘那份文件的子串、两处出口的 `run:` 集合相等;**steps 集合闸**:按 YAML 解析枚举 job 的 `run:` 命令而非子串碰运气,须含 `check`/`validate`/`passes-gate`;**引导语逐字冻结**)+ `__tests__/scaffold.test.ts` 的 `#103 判据` describe 加一条「片段视图是落盘正本裁出来的一段」包含闸。反向验闸各红一次并还原现场(sha1 对拍一致):删正本 `passes-gate` 一步 → 同源闸与 steps 集合闸各红(引导语项按预期仍绿,它是另一根轴);把打印改回独立手抄 → 包含闸与同源闸同红,即本票开工时的红基线。**同族自查(票体第 4 点)**:`PRE_COMMIT_SNIPPET` 无独立第二份正文——落盘 hook = `#!/bin/sh` + 说明行 + 该常量(`renderPreCommitHook`),冲突分支与片段视图打的都是这同一常量,`init.test.ts`「pre-commit 片段与落盘 hook 同源」与 `scaffold.test.ts`「pre-commit 站点落盘正文 = 打印片段 + shebang 头」「merge 站点全部同源」三条闸在位,本票对它零改动;两处极性相反但各自单份(pre-commit 以片段为原子组合出全文,GH 以全文为正本裁出片段),「单一正本」判据在两站点同时成立。既有冻结面的改动清单:`init-ondisk.test.ts` 的整屏冻结基线与 `init-dead-options.test.ts` 的旗帜面冻结**零行改动**(前者冻结的是不带 `--print-snippets` 的落盘路径,后者冻结旗帜定义表),断言形状未放松。验收:`npx jest --runInBand` 160 套件 / 2270 passed / 6 skipped、`tsc --noEmit` 与 `eslint src` 零错、`node bin/harness.js check` 通过(铁律 3/3、指导原则 3/3)、覆盖率 94.22% stmts 与 #143 持平且 `scaffold-templates.ts`/`scaffold.ts` 行覆盖 100%(`init.ts` 余下未覆盖行 443-444/449-450/687-688 是本票未触碰的既有分支)、真 CLI 冒烟(`init --print-snippets` 的 GH 段与 `init` 落盘的 `.github/workflows/harness-check.yml` 逐字同源)、`sync-docs --check` 只剩 hooks/knowledge/monitoring/release 四处既有目录漂移。文档:`src/cli/commands/CONTEXT.md` 的 scaffold 条目补记「片段视图由正本裁剪派生」,并新增「同族不同面」子条与 #150(CONTEXT.md 模板双正本,同一判据的另一面:那是两个命令各抄一份,本票是同一命令的两个出口各抄一份)互指,两票不并
|
|
47
|
+
- fix(cli): `createContextMd` 改消费 scaffold 正本,消除 CONTEXT.md 模板双份漂移(#150,#132 resolution「顺带发现,未做」①)——#132 按票体口径收了 8 站点(init 6 + validate 2),落地后全仓又查出**第 9 处同形写手**:`src/cli/commands/sync-docs/context-syncer.ts` 的 `createContextMd` 自带一份 CONTEXT.md 模板正文,与 `scaffold-templates.ts` 的 `renderContextDoc`(`:280`)已漂移——节标题(职责 / 核心导出 / 依赖关系 / 注意事项)两边相同、占位正文不同(副本独有「请阅读源代码…」「AI 编码助手…」两行,且占位一处是散文式提问、一处是 HTML 注释形)。同一份骨架由两个命令各抄一份,是 #103/#153「打印的即落盘的」判据的同族另一面(#153 是同一命令两个出口各抄一份,本票是两个命令各抄一份),在 #132 的 8 站点口径外、该票按「一张票就是一张票」未顺手做。落地:副本独有两条引导并入正本、四节占位统一取 HTML 注释形(散文式提问消失);`createContextMd` 改经 `contextDocFile()` + `runPlan()` 消费正本(带 `io` 形参与注入 `ScaffoldFileSystem`),删除自带模板正文与 `fs.mkdir`/`fs.writeFile`;`sync-docs/index.ts` 调用点删重复绿字——该句与 `contextDocFile.created` 文案逐字同文,收进 `runPlan` 是去重、输出字节不变。**语义不变**:仍只为 `contextMissing` 的目录落盘、走 `created` 分支,`exists`/`manual` 在该判定下不被触发(已在 doc 注明:若被触发说明两命令的在场判定口径不一致,写进票面不静默兜)。**对外行为变化 1 处**:`harness init` 与 `harness sync-docs` 两条路径落盘的 `CONTEXT.md` 骨架正文变了(首行去句号 + 占位由散文式改 HTML 注释形 + 并入两行引导)。定级:非 breaking——变的是**新建文件的注释文本**,命令语法、旗帜集合、退出码、公共导出面零变化,且已持有 `CONTEXT.md` 的项目不受影响(sync-docs 只为缺失目录落盘、在场不覆盖),迁移路径 = 无需迁移。测试:新增 `__tests__/context-syncer.test.ts`(内存 fs 替身,零真实文件系统)——单一正本闸(`grep -rn "此文件描述" src bin` 现仅 `scaffold-templates.ts:284` 一处)、`createContextMd` 落盘字节 == `contextDocFile().content` 对撞、正本文案逐字钉 + 散文式提问 `not.toContain`、seed 后返回 `exists` 且用户正文一字节不动;`sync-docs.test.ts` 既有「应该创建缺失的 CONTEXT.md」仍过;`public-value-surface`/`public-exports`/`public-type-surface` 三闸零清单改动(`renderContextDoc`/`createContextMd` 均不在五入口公开值面上)。验收:`npx jest --runInBand` 161 套件 / 2274 passed / 6 skipped、`tsc --noEmit` 与 `eslint src` 零错、`node bin/harness.js check` 通过(铁律 3/3、指导原则 3/3)。文档:`src/cli/commands/CONTEXT.md` 的「8 站点的落点」子条追加第 9 处归位说明、「同族不同面」子条把本票由待办改记已落地并注可检面;票体验收 #7 点名的 `src/cli/commands/sync-docs/CONTEXT.md` 实测**不存在**(全仓 src 下 CONTEXT.md 恰 13 个,与 AGENTS.md 计数一致),新建会破 13 计数约定属越界,故补记全部落在父级文件并在票面记名。已知残留另票:上述「对撞断言」是单边自撞(init 侧从不被执行),给正本加一行仍全绿,即「改正本无测试报警」——统一复审 F5,见 #158
|
|
48
|
+
- feat(cli): init 的 CI 接线加平台维度——`--ci <github|gitlab|none>` 与 `.gitlab-ci.yml` 落盘(#143,#132 曝光的已知缺口)——harness 的约束要成立必须抢到「合并前」这个服务端执行时机:本地 hook 跑在推送者控制的机器上(`--no-verify` 可绕过、`.git/hooks` 不进仓库)只能算自检,而 init 的 CI 面此前只懂 GitHub Actions(harness-check workflow / `-g` 档治理 workflow / `--print-snippets` 三处全是 GH 形状),自建 GitLab 用户零 scaffold 支持。落地(决议 ①–⑥,正本见 `src/cli/commands/CONTEXT.md`):`types/project-config.ts` 新增 `CiPlatform`(`github`/`gitlab`)与 `CiConfig` + `ProjectConfig.ci`;`scaffold-templates.ts` 新增 `GITLAB_CI_SNIPPET`(harness-check 任务正文,`--print-snippets` 与冲突分支共用)、`renderGitLabCiJobs`、`renderGitLabCiFile`(= 文件头 + harness 拥有的任务),`renderGovernanceWorkflow(level, platform)` 按平台出 GH workflow 或 GitLab 任务(治理档的 `sync-docs --check` 非阻断在 GitLab 侧对应单列 `harness-docs-freshness` 任务 + `allow_failure: true`,因每个任务都是全新容器);`scaffold.ts` 的 CI 站点工厂收口成 `harnessCheckCiFile(projectPath, platform, existingCiWorkflows, governanceLevel?)`——github 形(含冲突清单与文案)逐字节不动,gitlab 形目标 `.gitlab-ci.yml`、冲突面即 target 自身、三态 `created`/`manual`,打印的任务正文是落盘全文的尾巴(#103 判据);`init.ts` 新增解析链 flag > config.yml `ci.platform` > `github`(`resolveCiPlatform` / `readConfiguredCiPlatform`,脏配置按未配置)并把平台选择贯通三个面,`setupGitHubActions`→`setupCiWiring`、治理站 `setupGovernanceWorkflow` 加平台入参。**按决议不建 CiPlatform 注册表/通用抽象**(第三平台出现再提),**不做 remote URL 自动检测**。**三处对外行为变化**(是否记 breaking 由本车 ship 时裁决,判据同 `[1.6.0]`/`[1.7.0]`):① `--no-github-actions` 降为 `--ci none` 的别名,改用即黄字 deprecation 警告,且它现在把 `ci.platform: none` 写进 config.yml(此前无痕),迁移路径 = 换成 `--ci none`;② `--ci` 非法值、以及 `--ci <非 none>` 与 `--no-github-actions` 同时给出,判 `usage-error` 退出 1 且完全不落盘(此前无从属关系);③ 非默认平台才写 `ci.platform` 键——`github` 不写键而 init 每次重写 config.yml,故「不写」即清除,旧配置零迁移、`validate` 不因此报错。有意保留的现状:`none` 只摘掉 harness-check 站点(`-g` 档照建 GH 治理 workflow、`--print-snippets` 照出 GH 片段,即今天 `--no-github-actions` 的行为),切回 `github` 时不删既有的 `.gitlab-ci.yml`(scaffold 只有落盘/告知两种动作)。测试:`__tests__/scaffold.test.ts` 新增「CI 站点的平台维度」7 项(目标路径 / 三态文案逐字冻结 / 冲突面按平台分岔 / 与 GH 对仗的命令与 `rules:` 面 / 治理并入 / 落盘正文是合法 YAML)并把同源闸扩到两平台四形(另 2 项);`__tests__/init-ondisk.test.ts` 新增「init --ci 平台维度」8 项(`.gitlab-ci.yml` 逐字节两档 + 第二趟 manual 且用户正文一字节不动 + 持久化回读让裸 init 与 `--print-snippets` 都按 gitlab 出面 + `none`/别名/冲突/非法值 + 脏 `ci` 段回落);`__tests__/init-dead-options.test.ts` 的旗帜面冻结随 `--ci <platform>` 更新。反向验闸七处各红一次并还原现场:删 `allow_failure: true`(红 3 项)、冲突分支片段改为整份正文(红同源闸)、解析链去掉 config 回落(红持久化回读)、持久化写成恒 `github`(红 3 项)、冲突判定条件反转(红冲突项)、去掉非法值校验(红非法值项)、`ci` 段读取不兜 YAML 解析失败(红脏配置回落项)。验收:`npx jest --runInBand` 160 套件 / 2266 passed / 6 skipped、`tsc --noEmit` 与 `eslint src` 零错、`node bin/harness.js check` 通过、覆盖率 94.22% stmts 且 `scaffold-templates.ts`/`scaffold.ts` 行覆盖 100%(`init.ts` 余下未覆盖行 444-445/450-451/688-689 是本票未触碰的既有分支)、真 CLI 冒烟(`--ci gitlab -g standard` 落盘全文、重跑 manual、`--ci bitbucket` 与 `--ci gitlab --no-github-actions` 退 1、`--print-snippets` 按 config 出 GitLab 片段、`--ci github` 清掉 `ci` 段并回到 GH 形状、全新目录裸 init 输出逐字节不变)。文档:`src/cli/commands/CONTEXT.md` 的 CI 平台维度条目由「grilling 落定待实施」改为已落地并记名两处形状差。已知缺口按决议另开票,本票不做:pre-push hook #144、CI 缓存(两家一起加)、remote URL 自动检测、删除 `--no-github-actions`(属下个大版本)
|
|
49
|
+
- refactor(cli): knowledge 11 子操作的两份手抄投影收成一次分派(#133,架构评审候选4)——`knowledge.ts` 的每个子操作原先同时干「取数 + json 投影 + 人读排版 + 退出码」四件事,同一个数据两处落地、字段名靠人对齐(17 处 `options.json` 分支、8 处 `new KnowledgeStore`、95 处 `log(io, …)`),给 `--json` 加字段没有报警。落地:新增 `knowledge-view.ts` 收口 json/人读唯一分派与退出码(`emitKnowledgeView`)、取数期进度行(`announce`,`--json` 下静默)、角色→样式单表(`TONE_STYLES`,命令侧零 `chalk`)、维度/规则 label 与成熟度/分数/严重度三张映射、路径兜底与 store 构造单点(`resolveKnowledgeBaseDir`/`openKnowledgeStore`);命令模块只产 `{ data, human() }`(11 个 `knowledgeXxxView` 具名导出即投影本体,`data` 是 `--json` 正文唯一正本)。术语 **display model**:`human()` 返回 `{ sections: [{ title, rows: [{ cells }] }] }`,一格三选一——`label`(纯文案)/ `field`(点分路径声明投影自 json 面哪个字段,数组下标与 `.length` 合法)/ `derived`(json 面没有的派生量,须在豁免表登记理由);空行改为显式一行,不再靠 `\n` 前后缀藏排版。**json 面按决策现状冻结**:11 个顶层形状逐字不动(`knowledge --json` 双仓核实零程序化消费者,studio 走 library 直调;统一包壳是纯 churn,删 `--json` 死面按 ADR-0022 口径另票评估)。三处有意偏离,均不改字段集合:① `snapshot`/`index` 的 `--json` 由单行紧凑改为两空格缩进(分派单点化的直接结果,与其余 9 个同形);② `sync-rag` 两个空态此前把人类文案直接打到 `--json` 的 stdout(吐出的不是 JSON),现由 display model 承担、json 面恒为 `{directory, files}`——正是「两投影各写一遍会漂」的实证;③ `stats` 人读面 `verified` 的颜色随 `toneForMaturity` 单表变青色(此前 list 青 / stats 黄两处手抄不一致,文字逐字不变)。测试:新增 `__tests__/knowledge-view.test.ts` 66 项四道闸——源形状闸(`knowledge.ts` 零 chalk/store 构造/JSON.stringify,`if (options.json)` 只余 audit 索引重建一行豁免并逐行冻结;view 模块 store 构造与 JSON.stringify 各恰好一处、`chalk.` 只准出现在样式表里)、11/11 json 字段清单冻结(含 `entries[0]`/`summary`/`dimensions` 等嵌套层)、两投影一致性(display model 声明的 `field` 必须在真实 `--json` 输出里解析得到 + `derived` 双向对撞登记表防化石)、满态与**空态**人读输出逐行冻结(两份基线均取自改造前实现实测捕获,非凭记忆)。反向验闸各红一次并还原现场:把 `derived` 谎报成 `field`(红在一致性闸两条)、向 `knowledge.ts` 注入第二处 `JSON.stringify`(红在源形状闸)、人读文案改一个字(红在人读冻结)、json 面多一个键(红在字段清单)。`knowledge.test.ts` 的 `MOCK_REPORT` 标注成 `AuditReport`——7 维度/14 规则键改由编译期穷尽性管住,原先手写 6 键再 splice `incremental` 的缺键补偿写不出来(#109 的编译期闭环不再被 mock 绕开),既有 20 条用例逐条保留、断言不降。`registry.test.ts` 的懒加载探针登记项按新增行扩一条(`knowledge-view.js` 随命令模块一并懒加载,per-command 懒加载不变式仍成立)。行覆盖与 `npm test` 全绿;非 breaking:命令语法、退出码、字段集合、公共导出面零变化。文档:`src/cli/commands/CONTEXT.md` 收口模型条目由「grilling 落定待实施」改为已落地并记名三处偏离。与 #134(KnowledgeAudit 收 store)唯一交点是 `knowledgeAudit` 命令函数,后到者适配
|
|
50
|
+
- refactor(cli): init/validate 的脚手架三态判定收口成 scaffold 模块(#132,架构评审候选3)——`init.ts` 922 行里混着「目标在不在场→写或告知」的同一判定 6 处、`validate.ts` 另抄 2 处,且 `init.ts` 反向 import `validate.ts` 取那两个站点函数,改一条落盘语义要动三处、两处的在场文案已经各写各的。落地:新增 `src/cli/commands/scaffold.ts`(三态 `created`(不在场→落盘)/ `exists`(在场→告知跳过,**不细分内容是否等于模板**——内容比较是独立特性)/ `manual`(在场→打印片段请用户手工合并)+ 8 个 `ManagedFile` 站点工厂 + `runPlan`,fs 走 `ScaffoldFileSystem` 注入端口,缺省 node 实现)与 `scaffold-templates.ts`(模板正文,按决议留代码内、不落 `templates/`——该目录无运行时消费者且 `release/integrity.ts` 的 dist 清单不覆盖);`init.ts` 只留「前置告知 + plan 列表 + 循环」,`validate.ts` 退化到验证本体。行数:`init.ts` 922→619(-303)、`validate.ts` 208→105。边收口边删掉两条反向依赖:`init → validate` 的 import 删除,新增 `init → scaffold` 与 `validate → scaffold-templates`(检查点路径约定单一正本)。**决议边界**:scaffold 不持覆盖/跳过策略——`--no-git-hooks` / `--no-github-actions` 由命令层翻成 plan 里有无该站点,scaffold 只见 plan;标记化幂等写族(`CLAUDE.md`/`AGENTS.md` 治理段读-改-写)不纳入本模块。**两处对外行为变化**:① 死选项 `-t/--type` 删除(自始只有定义表一条与 `InitOptions.type` 一个字段、全仓零读取方),`harness init -t x` 由静默接受变为 commander `unknown option` exit 1,迁移路径 = 去掉该参数;② GH Actions 站点的冲突分支由打印 job 片段改为打印完整 workflow 全文——打印的即落盘的(#103 判据),`--print-snippets` 的 job 片段视图未动。是否记 breaking 由本车 ship 时裁决,判据同 `[1.6.0]` 删 `--max-retries` 那条。测试:新增 `__tests__/scaffold.test.ts`(内存 fs 替身零真实文件系统测全三态 + 建目录/`chmod`/上色路由 + 8 站点 × 落盘态/在场态文案逐字冻结 + 同源闸)、`__tests__/init-ondisk.test.ts`(不 mock 任何 IO,改造前从当前 HEAD 实抓 `harness init` 整屏输出冻结为第一遍断言,第二遍在临时目录跑在场态——7 站点按 init 落盘顺序断言,第 8 站点(治理 CI)在无 `--no-github-actions` 冲突的场景另例断言)、`__tests__/init-dead-options.test.ts`(逐字冻结 init 旗帜面不含 `--type` + 编译期钉 `InitOptions.type` 不存在,防换命令位复活);`init.test.ts` 新增两例钉跳过旗帜归属边界;`validate.test.ts` 原 4 例由 scaffold 的 8 站点×三态覆盖等价承接。反证已做实:把落盘 hook 正文改掉而不动打印片段 → `merge 站点全部同源` 与 `pre-commit 站点落盘正文 = 打印片段 + shebang 头` 两条转红(改后还原)。验收:`npx jest --runInBand` 159 套件 / 2183 passed / 6 skipped、`tsc --noEmit` 与 `eslint src` 零错、`node bin/harness.js check` 通过、覆盖率 92.03% stmts 且 `scaffold.ts`/`scaffold-templates.ts` 行覆盖 100%。文档:`src/cli/commands/CONTEXT.md` 的 scaffold 三态模型条目由「grilling 落定待实施」改为已落地。已知缺口按决议另开票,本票不做:GitLab CI 接线 #143、pre-push hook #144、第 9 处模板副本 `sync-docs/context-syncer.ts:createContextMd`(与 `scaffold-templates.ts` 的 `renderContextDoc` 正文已漂移)#150、治理段三 writer 调用丢 io #149
|
|
51
|
+
- test(exports): 子路径入口值面全量冻结闸(#131,ADR-0022 追记第 5 条收口)——新增 `src/__tests__/public-value-surface.test.ts`,补齐 `public-type-surface.test.ts` 的另一半:类型面已按 `package.json` 的 `exports` 逐入口冻结,值面却只有包根被 `public-exports.test.ts` 钉住(`Object.keys` 只看得到 `.`),「这个函数不在公开面上、删它非 breaking」在子路径入口仍无闸可跑。四个子路径(`./core`/`./presets`/`./context`/`./gates`)的运行时导出键集合逐入口冻结、入口清单同样从 `exports` 派生(新增子路径未登记即红);包根不重复钉(同一入口两份清单必然漂移,那条判定逐字保留),「两边都不漏」由登记闸 + 委派闸钉住。清单不手抄:`src` 侧 ts-jest 运行时键与 tsc 产物逐入口对撞,106/29/4/4/24 全部逐字一致。**落闸前实测校正了本票票面的前提**:删 `./gates` 的 `create*Gate` 其实会红(`src/index.ts` 经该 barrel 再导出),只是红名报 `.` 分不清入口;真正零覆盖的是包根未转发的 `./core` 七个(`ConstraintChecker`/`ProjectConfigLoader`/`constraintChecker`/`getCapabilitiesMode`/`getGovernanceConfig`/`loadRawProjectConfig`/`resolveContextFiles`)与 `./presets` 全部四个(实测删 `STRICT_PRESET` 时既有三道公共面闸全绿),新增方向四个子路径都漏。反向验闸四例各红一次且指名到入口与符号:删 `./gates` 的 `createReviewGate`、向 `./gates` 注入 `createScratchGate`、删 `./presets` 的 `STRICT_PRESET`、`package.json` 新增 `./monitoring` 子路径;另测类型面改动(注 `export type { DynamicTask }` 令 `public-exports.test.ts` TS2578「failed to run」)不连带抹掉本闸;每次注入后按 sha1 还原现场。文档:ADR-0022 追记第 5 条改判已收口、`src/gates/CONTEXT.md` 记账。非 breaking:纯测试 + 文档,零生产代码改动、零公共面变化。验收:`npx jest --runInBand` 全绿、`tsc --noEmit` 与 `eslint src` 零错
|
|
52
|
+
|
|
9
53
|
## [1.7.0] - 2026-09-09
|
|
10
54
|
|
|
11
55
|
### Changes
|
package/bin/harness.js
CHANGED
|
@@ -164,7 +164,23 @@ async function runDefinition(command, def, positionals, options) {
|
|
|
164
164
|
command.help();
|
|
165
165
|
return;
|
|
166
166
|
}
|
|
167
|
-
|
|
167
|
+
// mapActionArgs 装配失败的唯一失败通道(harness#154):数值旗帜脏输入由
|
|
168
|
+
// requireNumericFlag 抛 NumericFlagError,此处就地映射 usage-error——
|
|
169
|
+
// 定义表是纯数据模块返回不了 CommandResult,退出码映射只在 bin 这一处。
|
|
170
|
+
let actionArgs;
|
|
171
|
+
try {
|
|
172
|
+
actionArgs = def.mapActionArgs ? def.mapActionArgs(positionals, options) : [options];
|
|
173
|
+
} catch (err) {
|
|
174
|
+
// 懒 require:仅装配抛错时加载(纯函数模块,不破坏 --help/--version 零实现加载)
|
|
175
|
+
const { NumericFlagError } = require('../dist/utils/numeric-flag');
|
|
176
|
+
if (err instanceof NumericFlagError) {
|
|
177
|
+
console.error(err.message);
|
|
178
|
+
applyResult({ kind: 'usage-error', reason: err.message });
|
|
179
|
+
return;
|
|
180
|
+
}
|
|
181
|
+
throw err;
|
|
182
|
+
}
|
|
183
|
+
applyResult(await callImpl(def.action, actionArgs));
|
|
168
184
|
}
|
|
169
185
|
|
|
170
186
|
/**
|
package/dist/agents/index.d.ts
CHANGED
|
@@ -1,3 +1,7 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Agents 模块导出(ADR-0003:显式清单,禁 export *,harness#137)
|
|
3
|
+
*/
|
|
4
|
+
export type { AgentStatus, AgentConfig, AgentState, AgentEvent, FallbackStrategy, } from './types';
|
|
5
|
+
export { AgentLifecycle } from './lifecycle';
|
|
6
|
+
export type { EventHandler } from './lifecycle';
|
|
3
7
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/agents/index.ts"],"names":[],"mappings":"AAAA,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/agents/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,YAAY,EACV,WAAW,EACX,WAAW,EACX,UAAU,EACV,UAAU,EACV,gBAAgB,GACjB,MAAM,SAAS,CAAC;AACjB,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7C,YAAY,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC"}
|
package/dist/agents/index.js
CHANGED
|
@@ -1,19 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
-
}
|
|
8
|
-
Object.defineProperty(o, k2, desc);
|
|
9
|
-
}) : (function(o, m, k, k2) {
|
|
10
|
-
if (k2 === undefined) k2 = k;
|
|
11
|
-
o[k2] = m[k];
|
|
12
|
-
}));
|
|
13
|
-
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
-
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
-
};
|
|
2
|
+
/**
|
|
3
|
+
* Agents 模块导出(ADR-0003:显式清单,禁 export *,harness#137)
|
|
4
|
+
*/
|
|
16
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
-
|
|
18
|
-
|
|
6
|
+
exports.AgentLifecycle = void 0;
|
|
7
|
+
var lifecycle_1 = require("./lifecycle");
|
|
8
|
+
Object.defineProperty(exports, "AgentLifecycle", { enumerable: true, get: function () { return lifecycle_1.AgentLifecycle; } });
|
|
19
9
|
//# sourceMappingURL=index.js.map
|
package/dist/agents/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/agents/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/agents/index.ts"],"names":[],"mappings":";AAAA;;GAEG;;;AASH,yCAA6C;AAApC,2GAAA,cAAc,OAAA"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 门禁命令测试的决策替身
|
|
3
|
+
*
|
|
4
|
+
* 命令的唯一入口是 `evaluate()`,所以替身是「产一枚决策的假门禁」——
|
|
5
|
+
* 映射与报告构造器用真实现(decisionFromResult / gateResult),
|
|
6
|
+
* 六个命令的测试因此不需要 git、gh 或真扫描。
|
|
7
|
+
*/
|
|
8
|
+
import type { GateDecision } from '../../../gates/types';
|
|
9
|
+
export declare function decide(gateId: string, passed: boolean, message: string, details?: Record<string, any>): GateDecision;
|
|
10
|
+
/** 恒产同一枚决策的假门禁(evaluate 记录调用参数,供断言上下文) */
|
|
11
|
+
export declare function fakeGate(decision: GateDecision): {
|
|
12
|
+
evaluate: jest.Mock;
|
|
13
|
+
};
|
|
14
|
+
/** evaluate 直接抛出的假门禁:命令出错分支测的是门禁之外的失败(git / fs) */
|
|
15
|
+
export declare function throwingGate(error: unknown): {
|
|
16
|
+
evaluate: jest.Mock;
|
|
17
|
+
};
|
|
18
|
+
//# sourceMappingURL=gate-decision.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gate-decision.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/__tests__/gate-decision.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAEzD,wBAAgB,MAAM,CACpB,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,OAAO,EACf,OAAO,EAAE,MAAM,EACf,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAC5B,YAAY,CAEd;AAED,0CAA0C;AAC1C,wBAAgB,QAAQ,CAAC,QAAQ,EAAE,YAAY,GAAG;IAAE,QAAQ,EAAE,IAAI,CAAC,IAAI,CAAA;CAAE,CAExE;AAED,mDAAmD;AACnD,wBAAgB,YAAY,CAAC,KAAK,EAAE,OAAO,GAAG;IAAE,QAAQ,EAAE,IAAI,CAAC,IAAI,CAAA;CAAE,CAEpE"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* 门禁命令测试的决策替身
|
|
4
|
+
*
|
|
5
|
+
* 命令的唯一入口是 `evaluate()`,所以替身是「产一枚决策的假门禁」——
|
|
6
|
+
* 映射与报告构造器用真实现(decisionFromResult / gateResult),
|
|
7
|
+
* 六个命令的测试因此不需要 git、gh 或真扫描。
|
|
8
|
+
*/
|
|
9
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
+
exports.decide = decide;
|
|
11
|
+
exports.fakeGate = fakeGate;
|
|
12
|
+
exports.throwingGate = throwingGate;
|
|
13
|
+
const decision_1 = require("../../../gates/decision");
|
|
14
|
+
const types_1 = require("../../../gates/types");
|
|
15
|
+
function decide(gateId, passed, message, details) {
|
|
16
|
+
return (0, decision_1.decisionFromResult)((0, types_1.gateResult)(gateId, passed, message, Date.now(), details));
|
|
17
|
+
}
|
|
18
|
+
/** 恒产同一枚决策的假门禁(evaluate 记录调用参数,供断言上下文) */
|
|
19
|
+
function fakeGate(decision) {
|
|
20
|
+
return { evaluate: jest.fn().mockResolvedValue(decision) };
|
|
21
|
+
}
|
|
22
|
+
/** evaluate 直接抛出的假门禁:命令出错分支测的是门禁之外的失败(git / fs) */
|
|
23
|
+
function throwingGate(error) {
|
|
24
|
+
return { evaluate: jest.fn().mockRejectedValue(error) };
|
|
25
|
+
}
|
|
26
|
+
//# sourceMappingURL=gate-decision.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gate-decision.js","sourceRoot":"","sources":["../../../../src/cli/commands/__tests__/gate-decision.ts"],"names":[],"mappings":";AAAA;;;;;;GAMG;;AAMH,wBAOC;AAGD,4BAEC;AAGD,oCAEC;AArBD,sDAA6D;AAC7D,gDAAkD;AAGlD,SAAgB,MAAM,CACpB,MAAc,EACd,MAAe,EACf,OAAe,EACf,OAA6B;IAE7B,OAAO,IAAA,6BAAkB,EAAC,IAAA,kBAAU,EAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,CAAC,GAAG,EAAE,EAAE,OAAO,CAAC,CAAC,CAAC;AACtF,CAAC;AAED,0CAA0C;AAC1C,SAAgB,QAAQ,CAAC,QAAsB;IAC7C,OAAO,EAAE,QAAQ,EAAE,IAAI,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC,QAAQ,CAAC,EAAE,CAAC;AAC7D,CAAC;AAED,mDAAmD;AACnD,SAAgB,YAAY,CAAC,KAAc;IACzC,OAAO,EAAE,QAAQ,EAAE,IAAI,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC,KAAK,CAAC,EAAE,CAAC;AAC1D,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"acceptance.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/acceptance.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAMH,OAAO,EAAkB,KAAK,SAAS,EAAE,KAAK,aAAa,EAAE,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"acceptance.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/acceptance.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAMH,OAAO,EAAkB,KAAK,SAAS,EAAE,KAAK,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAIzF,MAAM,WAAW,iBAAiB;IAChC,YAAY;IACZ,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,mBAAmB;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW;IACX,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,eAAe;IACf,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,kBAAkB;IAClB,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED;;GAEG;AACH,wBAAsB,UAAU,CAC9B,OAAO,EAAE,iBAAiB,EAC1B,EAAE,GAAE,SAAqB,GACxB,OAAO,CAAC,aAAa,CAAC,CAwCxB;AAED;;GAEG;AACH,wBAAsB,sBAAsB,CAC1C,OAAO,EAAE,iBAAiB,EAC1B,EAAE,GAAE,SAAqB,GACxB,OAAO,CAAC,aAAa,CAAC,CAmCxB"}
|
|
@@ -48,6 +48,7 @@ const fs = __importStar(require("fs/promises"));
|
|
|
48
48
|
const path = __importStar(require("path"));
|
|
49
49
|
const acceptance_1 = require("../../gates/acceptance");
|
|
50
50
|
const command_contract_1 = require("../command-contract");
|
|
51
|
+
const gate_command_1 = require("../gate-command");
|
|
51
52
|
/**
|
|
52
53
|
* 执行验收门控
|
|
53
54
|
*/
|
|
@@ -61,38 +62,26 @@ async function acceptance(options, io = command_contract_1.processIO) {
|
|
|
61
62
|
e2eTestCommand: options.runE2e ? 'npx playwright test' : undefined,
|
|
62
63
|
});
|
|
63
64
|
try {
|
|
64
|
-
|
|
65
|
-
const context = {
|
|
65
|
+
const decision = await gate.evaluate({
|
|
66
66
|
projectPath,
|
|
67
67
|
taskId: options.taskId,
|
|
68
|
-
};
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
(
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
if (result.details?.uncheckedCriteria) {
|
|
83
|
-
result.details.uncheckedCriteria.forEach((criteria) => {
|
|
84
|
-
(0, command_contract_1.log)(io, chalk_1.default.red(` - ${criteria}`));
|
|
85
|
-
});
|
|
86
|
-
}
|
|
87
|
-
return { kind: 'fail', reason: `acceptance gate denied: ${result.message}` };
|
|
88
|
-
}
|
|
89
|
-
return { kind: 'ok' };
|
|
68
|
+
});
|
|
69
|
+
return (0, gate_command_1.reportGateDecision)(io, {
|
|
70
|
+
gateId: 'acceptance',
|
|
71
|
+
label: '验收标准',
|
|
72
|
+
onPass: (r) => r.details
|
|
73
|
+
? [
|
|
74
|
+
chalk_1.default.gray(` 通过项: ${r.details.checkedCriteria ?? 0}`),
|
|
75
|
+
chalk_1.default.gray(` 总项数: ${r.details.totalCriteria ?? 0}`),
|
|
76
|
+
]
|
|
77
|
+
: [],
|
|
78
|
+
onFail: (r) => r.details?.uncheckedCriteria
|
|
79
|
+
? r.details.uncheckedCriteria.map((criteria) => chalk_1.default.red(` - ${criteria}`))
|
|
80
|
+
: [],
|
|
81
|
+
}, decision);
|
|
90
82
|
}
|
|
91
83
|
catch (error) {
|
|
92
|
-
(0,
|
|
93
|
-
(0, command_contract_1.log)(io, chalk_1.default.red('❌ 验收标准检查出错'));
|
|
94
|
-
(0, command_contract_1.log)(io, chalk_1.default.red(` ${error.message}`));
|
|
95
|
-
return { kind: 'fail', reason: `acceptance gate error: ${error.message}` };
|
|
84
|
+
return (0, gate_command_1.reportGateError)(io, 'acceptance', '验收标准', error);
|
|
96
85
|
}
|
|
97
86
|
}
|
|
98
87
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"acceptance.js","sourceRoot":"","sources":["../../../src/cli/commands/acceptance.ts"],"names":[],"mappings":";AAAA;;;;GAIG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"acceptance.js","sourceRoot":"","sources":["../../../src/cli/commands/acceptance.ts"],"names":[],"mappings":";AAAA;;;;GAIG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA0BH,gCA2CC;AAKD,wDAsCC;AA9GD,kDAA0B;AAC1B,gDAAkC;AAClC,2CAA6B;AAC7B,uDAA4D;AAC5D,0DAAyF;AACzF,kDAAsE;AAgBtE;;GAEG;AACI,KAAK,UAAU,UAAU,CAC9B,OAA0B,EAC1B,KAAgB,4BAAS;IAEzB,IAAA,sBAAG,EAAC,EAAE,EAAE,eAAK,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC,CAAC;IAEtC,MAAM,WAAW,GAAG,OAAO,CAAC,WAAW,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC;IAEzD,WAAW;IACX,MAAM,IAAI,GAAG,IAAI,+BAAkB,CAAC;QAClC,SAAS,EAAE,OAAO,CAAC,SAAS;QAC5B,aAAa,EAAE,OAAO,CAAC,QAAQ;QAC/B,cAAc,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,qBAAqB,CAAC,CAAC,CAAC,SAAS;KACnE,CAAC,CAAC;IAEH,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC;YACnC,WAAW;YACX,MAAM,EAAE,OAAO,CAAC,MAAM;SACvB,CAAC,CAAC;QAEH,OAAO,IAAA,iCAAkB,EACvB,EAAE,EACF;YACE,MAAM,EAAE,YAAY;YACpB,KAAK,EAAE,MAAM;YACb,MAAM,EAAE,CAAC,CAAC,EAAE,EAAE,CACZ,CAAC,CAAC,OAAO;gBACP,CAAC,CAAC;oBACE,eAAK,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,OAAO,CAAC,eAAe,IAAI,CAAC,EAAE,CAAC;oBACvD,eAAK,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,OAAO,CAAC,aAAa,IAAI,CAAC,EAAE,CAAC;iBACtD;gBACH,CAAC,CAAC,EAAE;YACR,MAAM,EAAE,CAAC,CAAC,EAAE,EAAE,CACZ,CAAC,CAAC,OAAO,EAAE,iBAAiB;gBAC1B,CAAC,CAAE,CAAC,CAAC,OAAO,CAAC,iBAA8B,CAAC,GAAG,CAAC,CAAC,QAAgB,EAAE,EAAE,CAAC,eAAK,CAAC,GAAG,CAAC,QAAQ,QAAQ,EAAE,CAAC,CAAC;gBACpG,CAAC,CAAC,EAAE;SACT,EACD,QAAQ,CACT,CAAC;IACJ,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,IAAA,8BAAe,EAAC,EAAE,EAAE,YAAY,EAAE,MAAM,EAAE,KAAK,CAAC,CAAC;IAC1D,CAAC;AACH,CAAC;AAED;;GAEG;AACI,KAAK,UAAU,sBAAsB,CAC1C,OAA0B,EAC1B,KAAgB,4BAAS;IAEzB,IAAA,sBAAG,EAAC,EAAE,EAAE,eAAK,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC,CAAC;IAExC,MAAM,WAAW,GAAG,OAAO,CAAC,WAAW,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC;IACzD,MAAM,SAAS,GAAG,OAAO,CAAC,SAAS,IAAI,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,WAAW,CAAC,CAAC;IAE3E,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;QACtD,MAAM,IAAI,GAAG,wDAAa,SAAS,GAAC,CAAC;QACrC,MAAM,KAAK,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,CAAQ,CAAC;QAExC,IAAI,CAAC,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;YACxC,IAAA,sBAAG,EAAC,EAAE,EAAE,eAAK,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC,CAAC;YACrC,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,YAAY,SAAS,EAAE,EAAE,CAAC;QAC3D,CAAC;QAED,KAAK,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;YACnD,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,KAAK,IAAI,EAAE,CAAC;gBAC9C,IAAA,sBAAG,EAAC,EAAE,EAAE,eAAK,CAAC,IAAI,CAAC,GAAG,MAAM,GAAG,CAAC,CAAC,CAAC;gBAClC,MAAM,OAAO,GAAG,IAAW,CAAC;gBAC5B,IAAI,OAAO,CAAC,kBAAkB,EAAE,CAAC;oBAC/B,OAAO,CAAC,kBAAkB,CAAC,OAAO,CAAC,CAAC,QAAgB,EAAE,CAAS,EAAE,EAAE;wBACjE,IAAA,sBAAG,EAAC,EAAE,EAAE,eAAK,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,QAAQ,EAAE,CAAC,CAAC,CAAC;oBACjD,CAAC,CAAC,CAAC;gBACL,CAAC;qBAAM,CAAC;oBACN,IAAA,sBAAG,EAAC,EAAE,EAAE,eAAK,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC;gBACnC,CAAC;gBACD,IAAA,sBAAG,EAAC,EAAE,CAAC,CAAC;YACV,CAAC;QACH,CAAC;QACD,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;IACxB,CAAC;IAAC,OAAO,KAAU,EAAE,CAAC;QACpB,IAAA,sBAAG,EAAC,EAAE,EAAE,eAAK,CAAC,GAAG,CAAC,sBAAsB,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;QAC1D,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,oBAAoB,KAAK,CAAC,OAAO,EAAE,EAAE,CAAC;IACvE,CAAC;AACH,CAAC"}
|
|
@@ -5,14 +5,16 @@
|
|
|
5
5
|
* 工单 23:触发条件与证据检测迁至 core/constraints/context-builder
|
|
6
6
|
* ADR-0001:约束集统一走 getMergedConstraintsConfig 生效集链路(preset/config 禁用/custom/scenes)
|
|
7
7
|
* harness#88:本命令是 trace 记录器的组合根——core 不上行依赖 monitoring,
|
|
8
|
-
*
|
|
8
|
+
* 真实收集器在此经构造参数接线;#139:收集器锚根构造,trace 落点跟 --project-path 走
|
|
9
9
|
*/
|
|
10
10
|
import { type GitEvidence } from '../../core/constraints/git-evidence';
|
|
11
|
+
import { type RunEnv } from '../../core/constraints/run-env';
|
|
11
12
|
import type { ConstraintTrigger } from '../../types/constraint';
|
|
12
13
|
import { type CommandIO, type CommandResult } from '../command-contract';
|
|
14
|
+
import { type StateIO } from '../state-io';
|
|
13
15
|
export interface CheckOptions {
|
|
14
|
-
/**
|
|
15
|
-
preset
|
|
16
|
+
/** 预设名称;**不传 = 按项目 `.harness/config.yml` 的 preset**(CLI 不给缺省值,见 commands/definitions.ts) */
|
|
17
|
+
preset?: string;
|
|
16
18
|
/** 是否只检查暂存文件 */
|
|
17
19
|
staged: boolean;
|
|
18
20
|
/** 触发条件 */
|
|
@@ -26,6 +28,20 @@ export interface CheckOptions {
|
|
|
26
28
|
* 测试据此断言"同一 run 内每条 git 命令至多执行一次"。
|
|
27
29
|
*/
|
|
28
30
|
evidence?: GitEvidence;
|
|
31
|
+
/**
|
|
32
|
+
* 运行级观察面(非 CLI flag;ADR-0023)
|
|
33
|
+
*
|
|
34
|
+
* 缺省 = 本 run 独占一份。注入则与调用方共用同一份上行数据读取,
|
|
35
|
+
* 测试据此断言「同一次运行内同一项目文件至多读一次」。
|
|
36
|
+
*/
|
|
37
|
+
runEnv?: RunEnv;
|
|
38
|
+
/**
|
|
39
|
+
* 状态文件接缝(非 CLI flag;ADR-0026)
|
|
40
|
+
*
|
|
41
|
+
* 缺省 = 真实 fs 实现(fileStateIO)。注入则 `.harness/.state.json` 的读写
|
|
42
|
+
* 走替身,测试据此不碰真文件系统。
|
|
43
|
+
*/
|
|
44
|
+
stateIO?: StateIO;
|
|
29
45
|
}
|
|
30
46
|
/**
|
|
31
47
|
* 执行约束检查
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"check.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/check.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;
|
|
1
|
+
{"version":3,"file":"check.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/check.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAQH,OAAO,EAAqB,KAAK,WAAW,EAAE,MAAM,qCAAqC,CAAC;AAC1F,OAAO,EAAgB,KAAK,MAAM,EAAE,MAAM,gCAAgC,CAAC;AAM3E,OAAO,KAAK,EAAoB,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAClF,OAAO,EAAkB,KAAK,SAAS,EAAE,KAAK,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACzF,OAAO,EAAe,KAAK,OAAO,EAAE,MAAM,aAAa,CAAC;AA4BxD,MAAM,WAAW,YAAY;IAC3B,4FAA4F;IAC5F,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,gBAAgB;IAChB,MAAM,EAAE,OAAO,CAAC;IAChB,WAAW;IACX,OAAO,CAAC,EAAE,iBAAiB,CAAC;IAC5B,WAAW;IACX,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;;;OAKG;IACH,QAAQ,CAAC,EAAE,WAAW,CAAC;IACvB;;;;;OAKG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;;;OAKG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED;;GAEG;AACH,wBAAsB,KAAK,CACzB,OAAO,EAAE,YAAY,EACrB,EAAE,GAAE,SAAqB,GACxB,OAAO,CAAC,aAAa,CAAC,CAyJxB;AA6CD;;GAEG;AACH,yDAAyD;AACzD,wBAAgB,QAAQ,CAAC,QAAQ,GAAE,OAAO,CAAC,YAAY,CAAM,EAAE,EAAE,GAAE,SAAqB,GAAG,aAAa,CA8BvG"}
|