@dommaker/harness 1.3.0 → 1.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +8 -0
- package/README.md +0 -2
- package/bin/harness.js +86 -32
- package/dist/cli/command-contract.d.ts +83 -0
- package/dist/cli/command-contract.d.ts.map +1 -0
- package/dist/cli/command-contract.js +66 -0
- package/dist/cli/command-contract.js.map +1 -0
- package/dist/cli/commands/acceptance.d.ts +3 -2
- package/dist/cli/commands/acceptance.d.ts.map +1 -1
- package/dist/cli/commands/acceptance.js +28 -24
- package/dist/cli/commands/acceptance.js.map +1 -1
- package/dist/cli/commands/analyze-sessions.d.ts +2 -1
- package/dist/cli/commands/analyze-sessions.d.ts.map +1 -1
- package/dist/cli/commands/analyze-sessions.js +25 -24
- package/dist/cli/commands/analyze-sessions.js.map +1 -1
- package/dist/cli/commands/check.d.ts +14 -2
- package/dist/cli/commands/check.d.ts.map +1 -1
- package/dist/cli/commands/check.js +76 -61
- package/dist/cli/commands/check.js.map +1 -1
- package/dist/cli/commands/command.d.ts +5 -1
- package/dist/cli/commands/command.d.ts.map +1 -1
- package/dist/cli/commands/command.js +26 -17
- package/dist/cli/commands/command.js.map +1 -1
- package/dist/cli/commands/constraints-report.d.ts +2 -1
- package/dist/cli/commands/constraints-report.d.ts.map +1 -1
- package/dist/cli/commands/constraints-report.js +37 -33
- package/dist/cli/commands/constraints-report.js.map +1 -1
- package/dist/cli/commands/constraints-retire.d.ts +6 -5
- package/dist/cli/commands/constraints-retire.d.ts.map +1 -1
- package/dist/cli/commands/constraints-retire.js +50 -52
- package/dist/cli/commands/constraints-retire.js.map +1 -1
- package/dist/cli/commands/constraints.d.ts +2 -1
- package/dist/cli/commands/constraints.d.ts.map +1 -1
- package/dist/cli/commands/constraints.js +10 -27
- package/dist/cli/commands/constraints.js.map +1 -1
- package/dist/cli/commands/contract.d.ts +3 -2
- package/dist/cli/commands/contract.d.ts.map +1 -1
- package/dist/cli/commands/contract.js +45 -42
- package/dist/cli/commands/contract.js.map +1 -1
- package/dist/cli/commands/definitions.d.ts +11 -11
- package/dist/cli/commands/definitions.d.ts.map +1 -1
- package/dist/cli/commands/definitions.js +29 -214
- package/dist/cli/commands/definitions.js.map +1 -1
- package/dist/cli/commands/failure.d.ts +5 -4
- package/dist/cli/commands/failure.d.ts.map +1 -1
- package/dist/cli/commands/failure.js +31 -25
- package/dist/cli/commands/failure.js.map +1 -1
- package/dist/cli/commands/init.d.ts +7 -5
- package/dist/cli/commands/init.d.ts.map +1 -1
- package/dist/cli/commands/init.js +147 -211
- package/dist/cli/commands/init.js.map +1 -1
- package/dist/cli/commands/knowledge.d.ts +21 -15
- package/dist/cli/commands/knowledge.d.ts.map +1 -1
- package/dist/cli/commands/knowledge.js +214 -199
- package/dist/cli/commands/knowledge.js.map +1 -1
- package/dist/cli/commands/passes-gate.d.ts +8 -2
- package/dist/cli/commands/passes-gate.d.ts.map +1 -1
- package/dist/cli/commands/passes-gate.js +44 -66
- package/dist/cli/commands/passes-gate.js.map +1 -1
- package/dist/cli/commands/performance.d.ts +2 -1
- package/dist/cli/commands/performance.d.ts.map +1 -1
- package/dist/cli/commands/performance.js +20 -18
- package/dist/cli/commands/performance.js.map +1 -1
- package/dist/cli/commands/posteval-plan.d.ts +5 -1
- package/dist/cli/commands/posteval-plan.d.ts.map +1 -1
- package/dist/cli/commands/posteval-plan.js +26 -15
- package/dist/cli/commands/posteval-plan.js.map +1 -1
- package/dist/cli/commands/release.d.ts +6 -1
- package/dist/cli/commands/release.d.ts.map +1 -1
- package/dist/cli/commands/release.js +69 -59
- package/dist/cli/commands/release.js.map +1 -1
- package/dist/cli/commands/report.d.ts +2 -1
- package/dist/cli/commands/report.d.ts.map +1 -1
- package/dist/cli/commands/report.js +9 -5
- package/dist/cli/commands/report.js.map +1 -1
- package/dist/cli/commands/review.d.ts +3 -2
- package/dist/cli/commands/review.d.ts.map +1 -1
- package/dist/cli/commands/review.js +33 -29
- package/dist/cli/commands/review.js.map +1 -1
- package/dist/cli/commands/sdd.d.ts +2 -1
- package/dist/cli/commands/sdd.d.ts.map +1 -1
- package/dist/cli/commands/sdd.js +7 -5
- package/dist/cli/commands/sdd.js.map +1 -1
- package/dist/cli/commands/security.d.ts +3 -2
- package/dist/cli/commands/security.d.ts.map +1 -1
- package/dist/cli/commands/security.js +29 -26
- package/dist/cli/commands/security.js.map +1 -1
- package/dist/cli/commands/spec-baseline-check.d.ts +2 -1
- package/dist/cli/commands/spec-baseline-check.d.ts.map +1 -1
- package/dist/cli/commands/spec-baseline-check.js +15 -11
- package/dist/cli/commands/spec-baseline-check.js.map +1 -1
- package/dist/cli/commands/spec.d.ts +7 -2
- package/dist/cli/commands/spec.d.ts.map +1 -1
- package/dist/cli/commands/spec.js +61 -51
- package/dist/cli/commands/spec.js.map +1 -1
- package/dist/cli/commands/status.d.ts +2 -1
- package/dist/cli/commands/status.d.ts.map +1 -1
- package/dist/cli/commands/status.js +57 -53
- package/dist/cli/commands/status.js.map +1 -1
- package/dist/cli/commands/sync-docs/agents-syncer.d.ts.map +1 -1
- package/dist/cli/commands/sync-docs/agents-syncer.js +5 -2
- package/dist/cli/commands/sync-docs/agents-syncer.js.map +1 -1
- package/dist/cli/commands/sync-docs/context-syncer.d.ts.map +1 -1
- package/dist/cli/commands/sync-docs/context-syncer.js +3 -2
- package/dist/cli/commands/sync-docs/context-syncer.js.map +1 -1
- package/dist/cli/commands/sync-docs/index.d.ts +2 -1
- package/dist/cli/commands/sync-docs/index.d.ts.map +1 -1
- package/dist/cli/commands/sync-docs/index.js +68 -88
- package/dist/cli/commands/sync-docs/index.js.map +1 -1
- package/dist/cli/commands/sync-docs/project-reader.d.ts +6 -1
- package/dist/cli/commands/sync-docs/project-reader.d.ts.map +1 -1
- package/dist/cli/commands/sync-docs/project-reader.js +14 -16
- package/dist/cli/commands/sync-docs/project-reader.js.map +1 -1
- package/dist/cli/commands/update-user-model.d.ts +2 -1
- package/dist/cli/commands/update-user-model.d.ts.map +1 -1
- package/dist/cli/commands/update-user-model.js +31 -45
- package/dist/cli/commands/update-user-model.js.map +1 -1
- package/dist/cli/commands/validate.d.ts +4 -3
- package/dist/cli/commands/validate.d.ts.map +1 -1
- package/dist/cli/commands/validate.js +28 -26
- package/dist/cli/commands/validate.js.map +1 -1
- package/dist/cli/session-mining/transcript.d.ts +7 -1
- package/dist/cli/session-mining/transcript.d.ts.map +1 -1
- package/dist/cli/session-mining/transcript.js +21 -14
- package/dist/cli/session-mining/transcript.js.map +1 -1
- package/dist/context/session-manager.d.ts.map +1 -1
- package/dist/context/session-manager.js +19 -32
- package/dist/context/session-manager.js.map +1 -1
- package/dist/core/constraints/agent-prompt-renderer.d.ts.map +1 -1
- package/dist/core/constraints/agent-prompt-renderer.js +1 -4
- package/dist/core/constraints/agent-prompt-renderer.js.map +1 -1
- package/dist/core/constraints/capabilities-parser.d.ts +24 -7
- package/dist/core/constraints/capabilities-parser.d.ts.map +1 -1
- package/dist/core/constraints/capabilities-parser.js +32 -28
- package/dist/core/constraints/capabilities-parser.js.map +1 -1
- package/dist/core/constraints/capabilities-reconcile.d.ts +67 -0
- package/dist/core/constraints/capabilities-reconcile.d.ts.map +1 -0
- package/dist/core/constraints/capabilities-reconcile.js +105 -0
- package/dist/core/constraints/capabilities-reconcile.js.map +1 -0
- package/dist/core/constraints/checker.d.ts +21 -43
- package/dist/core/constraints/checker.d.ts.map +1 -1
- package/dist/core/constraints/checker.js +64 -115
- package/dist/core/constraints/checker.js.map +1 -1
- package/dist/core/constraints/checkers/capability-sync.d.ts +4 -3
- package/dist/core/constraints/checkers/capability-sync.d.ts.map +1 -1
- package/dist/core/constraints/checkers/capability-sync.js +29 -69
- package/dist/core/constraints/checkers/capability-sync.js.map +1 -1
- package/dist/core/constraints/checkers/context-doc-sync.d.ts +4 -2
- package/dist/core/constraints/checkers/context-doc-sync.d.ts.map +1 -1
- package/dist/core/constraints/checkers/context-doc-sync.js +13 -22
- package/dist/core/constraints/checkers/context-doc-sync.js.map +1 -1
- package/dist/core/constraints/checkers/docs-freshness.d.ts.map +1 -1
- package/dist/core/constraints/checkers/docs-freshness.js +37 -63
- package/dist/core/constraints/checkers/docs-freshness.js.map +1 -1
- package/dist/core/constraints/checkers/governance-presence.d.ts +2 -2
- package/dist/core/constraints/checkers/governance-presence.d.ts.map +1 -1
- package/dist/core/constraints/checkers/governance-presence.js +7 -28
- package/dist/core/constraints/checkers/governance-presence.js.map +1 -1
- package/dist/core/constraints/checkers/no-test-simplification.d.ts.map +1 -1
- package/dist/core/constraints/checkers/no-test-simplification.js +4 -3
- package/dist/core/constraints/checkers/no-test-simplification.js.map +1 -1
- package/dist/core/constraints/checkers/types.d.ts +2 -2
- package/dist/core/constraints/context-builder.d.ts +15 -14
- package/dist/core/constraints/context-builder.d.ts.map +1 -1
- package/dist/core/constraints/context-builder.js +32 -96
- package/dist/core/constraints/context-builder.js.map +1 -1
- package/dist/core/constraints/doc-freshness/runner.d.ts.map +1 -1
- package/dist/core/constraints/doc-freshness/runner.js +2 -1
- package/dist/core/constraints/doc-freshness/runner.js.map +1 -1
- package/dist/core/constraints/git-evidence.d.ts +60 -0
- package/dist/core/constraints/git-evidence.d.ts.map +1 -0
- package/dist/core/constraints/git-evidence.js +88 -0
- package/dist/core/constraints/git-evidence.js.map +1 -0
- package/dist/core/constraints/injection-drift.d.ts +3 -20
- package/dist/core/constraints/injection-drift.d.ts.map +1 -1
- package/dist/core/constraints/injection-drift.js +10 -57
- package/dist/core/constraints/injection-drift.js.map +1 -1
- package/dist/core/constraints/injection-writer.d.ts +113 -0
- package/dist/core/constraints/injection-writer.d.ts.map +1 -0
- package/dist/core/constraints/injection-writer.js +228 -0
- package/dist/core/constraints/injection-writer.js.map +1 -0
- package/dist/core/constraints/usage-report.d.ts +22 -1
- package/dist/core/constraints/usage-report.d.ts.map +1 -1
- package/dist/core/constraints/usage-report.js +27 -20
- package/dist/core/constraints/usage-report.js.map +1 -1
- package/dist/core/index.d.ts +2 -2
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +4 -2
- package/dist/core/index.js.map +1 -1
- package/dist/core/project-config-loader.d.ts +32 -1
- package/dist/core/project-config-loader.d.ts.map +1 -1
- package/dist/core/project-config-loader.js +39 -9
- package/dist/core/project-config-loader.js.map +1 -1
- package/dist/core/validators/passes-gate.d.ts +15 -64
- package/dist/core/validators/passes-gate.d.ts.map +1 -1
- package/dist/core/validators/passes-gate.js +84 -222
- package/dist/core/validators/passes-gate.js.map +1 -1
- package/dist/core/validators/test-output.d.ts +58 -0
- package/dist/core/validators/test-output.d.ts.map +1 -0
- package/dist/core/validators/test-output.js +109 -0
- package/dist/core/validators/test-output.js.map +1 -0
- package/dist/failure/recorder.d.ts +6 -0
- package/dist/failure/recorder.d.ts.map +1 -1
- package/dist/failure/recorder.js +12 -8
- package/dist/failure/recorder.js.map +1 -1
- package/dist/gates/acceptance.d.ts +1 -48
- package/dist/gates/acceptance.d.ts.map +1 -1
- package/dist/gates/acceptance.js +6 -38
- package/dist/gates/acceptance.js.map +1 -1
- package/dist/gates/checker-gate.d.ts.map +1 -1
- package/dist/gates/checker-gate.js +6 -11
- package/dist/gates/checker-gate.js.map +1 -1
- package/dist/gates/command.d.ts.map +1 -1
- package/dist/gates/command.js +10 -22
- package/dist/gates/command.js.map +1 -1
- package/dist/gates/contract.d.ts.map +1 -1
- package/dist/gates/contract.js +22 -61
- package/dist/gates/contract.js.map +1 -1
- package/dist/gates/performance.d.ts.map +1 -1
- package/dist/gates/performance.js +13 -31
- package/dist/gates/performance.js.map +1 -1
- package/dist/gates/review.d.ts.map +1 -1
- package/dist/gates/review.js +21 -53
- package/dist/gates/review.js.map +1 -1
- package/dist/gates/security.d.ts.map +1 -1
- package/dist/gates/security.js +14 -32
- package/dist/gates/security.js.map +1 -1
- package/dist/gates/types.d.ts +28 -5
- package/dist/gates/types.d.ts.map +1 -1
- package/dist/gates/types.js +38 -1
- package/dist/gates/types.js.map +1 -1
- package/dist/hooks/bootstrap.d.ts +2 -0
- package/dist/hooks/bootstrap.d.ts.map +1 -1
- package/dist/hooks/bootstrap.js +5 -2
- package/dist/hooks/bootstrap.js.map +1 -1
- package/dist/index.d.ts +1 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/knowledge/audit.d.ts +7 -2
- package/dist/knowledge/audit.d.ts.map +1 -1
- package/dist/knowledge/audit.js +59 -79
- package/dist/knowledge/audit.js.map +1 -1
- package/dist/knowledge/flywheel-metrics.d.ts +39 -0
- package/dist/knowledge/flywheel-metrics.d.ts.map +1 -0
- package/dist/knowledge/flywheel-metrics.js +47 -0
- package/dist/knowledge/flywheel-metrics.js.map +1 -0
- package/dist/knowledge/import.d.ts.map +1 -1
- package/dist/knowledge/import.js +4 -14
- package/dist/knowledge/import.js.map +1 -1
- package/dist/knowledge/index-generator.d.ts.map +1 -1
- package/dist/knowledge/index-generator.js +17 -14
- package/dist/knowledge/index-generator.js.map +1 -1
- package/dist/knowledge/ingest.d.ts.map +1 -1
- package/dist/knowledge/ingest.js +9 -4
- package/dist/knowledge/ingest.js.map +1 -1
- package/dist/knowledge/migration.d.ts.map +1 -1
- package/dist/knowledge/migration.js +11 -8
- package/dist/knowledge/migration.js.map +1 -1
- package/dist/knowledge/reference-tracker.d.ts.map +1 -1
- package/dist/knowledge/reference-tracker.js +12 -9
- package/dist/knowledge/reference-tracker.js.map +1 -1
- package/dist/knowledge/store.d.ts +15 -0
- package/dist/knowledge/store.d.ts.map +1 -1
- package/dist/knowledge/store.js +59 -10
- package/dist/knowledge/store.js.map +1 -1
- package/dist/monitoring/context-tracker.d.ts.map +1 -1
- package/dist/monitoring/context-tracker.js +11 -20
- package/dist/monitoring/context-tracker.js.map +1 -1
- package/dist/monitoring/index.d.ts +1 -1
- package/dist/monitoring/index.d.ts.map +1 -1
- package/dist/monitoring/index.js +1 -2
- package/dist/monitoring/index.js.map +1 -1
- package/dist/monitoring/trace-analyzer.d.ts +15 -0
- package/dist/monitoring/trace-analyzer.d.ts.map +1 -1
- package/dist/monitoring/trace-analyzer.js +19 -2
- package/dist/monitoring/trace-analyzer.js.map +1 -1
- package/dist/monitoring/traces.d.ts +21 -2
- package/dist/monitoring/traces.d.ts.map +1 -1
- package/dist/monitoring/traces.js +38 -29
- package/dist/monitoring/traces.js.map +1 -1
- package/dist/release/index.d.ts +2 -2
- package/dist/release/index.d.ts.map +1 -1
- package/dist/release/index.js +1 -5
- package/dist/release/index.js.map +1 -1
- package/dist/sdd/index-generator.js +10 -11
- package/dist/sdd/index-generator.js.map +1 -1
- package/dist/test-setup/project-fixture.d.ts +48 -0
- package/dist/test-setup/project-fixture.d.ts.map +1 -0
- package/dist/test-setup/project-fixture.js +106 -0
- package/dist/test-setup/project-fixture.js.map +1 -0
- package/dist/types/constraint.d.ts +0 -18
- package/dist/types/constraint.d.ts.map +1 -1
- package/dist/types/constraint.js.map +1 -1
- package/dist/types/passes-gate.d.ts +10 -25
- package/dist/types/passes-gate.d.ts.map +1 -1
- package/dist/types/project-config.d.ts +1 -1
- package/dist/types/session.d.ts +6 -5
- package/dist/types/session.d.ts.map +1 -1
- package/dist/utils/exec.d.ts +10 -0
- package/dist/utils/exec.d.ts.map +1 -1
- package/dist/utils/exec.js +12 -0
- package/dist/utils/exec.js.map +1 -1
- package/dist/utils/file-walk.d.ts +9 -1
- package/dist/utils/file-walk.d.ts.map +1 -1
- package/dist/utils/file-walk.js +10 -1
- package/dist/utils/file-walk.js.map +1 -1
- package/dist/utils/frontmatter.d.ts +73 -0
- package/dist/utils/frontmatter.d.ts.map +1 -0
- package/dist/utils/frontmatter.js +141 -0
- package/dist/utils/frontmatter.js.map +1 -0
- package/dist/utils/jsonl.d.ts +92 -0
- package/dist/utils/jsonl.d.ts.map +1 -0
- package/dist/utils/jsonl.js +166 -0
- package/dist/utils/jsonl.js.map +1 -0
- package/dist/utils/package-version.d.ts +16 -0
- package/dist/utils/package-version.d.ts.map +1 -0
- package/dist/utils/package-version.js +63 -0
- package/dist/utils/package-version.js.map +1 -0
- package/package.json +1 -1
- package/src/CONTEXT.md +7 -2
- package/src/__tests__/acceptance-gate.test.ts +3 -1
- package/src/__tests__/checker-extra.test.ts +7 -1218
- package/src/__tests__/context-files-resolution.test.ts +116 -0
- package/src/__tests__/effective-constraints.test.ts +10 -13
- package/src/__tests__/exec.test.ts +35 -1
- package/src/__tests__/layering.test.ts +152 -0
- package/src/__tests__/passes-gate-extra.test.ts +0 -145
- package/src/__tests__/passes-gate.test.ts +142 -106
- package/src/__tests__/skip-semantics.test.ts +5 -9
- package/src/cli/__tests__/command-contract.test.ts +170 -0
- package/src/cli/command-contract.ts +108 -0
- package/src/cli/commands/CONTEXT.md +22 -7
- package/src/cli/commands/__tests__/acceptance.test.ts +40 -33
- package/src/cli/commands/__tests__/analyze-sessions.test.ts +35 -29
- package/src/cli/commands/__tests__/bin-exit-mapping.test.ts +101 -0
- package/src/cli/commands/__tests__/check-drift.test.ts +27 -34
- package/src/cli/commands/__tests__/check-skip-output.test.ts +21 -24
- package/src/cli/commands/__tests__/check.test.ts +378 -382
- package/src/cli/commands/__tests__/command.test.ts +85 -70
- package/src/cli/commands/__tests__/constraints-report.test.ts +100 -71
- package/src/cli/commands/__tests__/constraints-retire.test.ts +152 -95
- package/src/cli/commands/__tests__/contract.test.ts +27 -34
- package/src/cli/commands/__tests__/failure.test.ts +31 -34
- package/src/cli/commands/__tests__/init-injection.test.ts +58 -28
- package/src/cli/commands/__tests__/init.test.ts +77 -48
- package/src/cli/commands/__tests__/knowledge-flywheel-consistency.test.ts +108 -0
- package/src/cli/commands/__tests__/knowledge.test.ts +69 -43
- package/src/cli/commands/__tests__/passes-gate.test.ts +43 -45
- package/src/cli/commands/__tests__/performance.test.ts +22 -23
- package/src/cli/commands/__tests__/posteval-plan.test.ts +39 -38
- package/src/cli/commands/__tests__/project-path-anchoring.test.ts +157 -0
- package/src/cli/commands/__tests__/project-path-convention.test.ts +169 -0
- package/src/cli/commands/__tests__/registry.test.ts +69 -35
- package/src/cli/commands/__tests__/release.test.ts +209 -80
- package/src/cli/commands/__tests__/report-extra.test.ts +16 -16
- package/src/cli/commands/__tests__/report.test.ts +25 -25
- package/src/cli/commands/__tests__/review.test.ts +33 -31
- package/src/cli/commands/__tests__/security.test.ts +23 -27
- package/src/cli/commands/__tests__/spec-baseline-check.test.ts +20 -20
- package/src/cli/commands/__tests__/spec.test.ts +41 -29
- package/src/cli/commands/__tests__/status-extra.test.ts +18 -18
- package/src/cli/commands/__tests__/status-skipped-lines.test.ts +72 -0
- package/src/cli/commands/__tests__/status.test.ts +34 -34
- package/src/cli/commands/__tests__/sync-docs-agents.test.ts +77 -78
- package/src/cli/commands/__tests__/sync-docs.test.ts +72 -74
- package/src/cli/commands/__tests__/update-user-model.test.ts +62 -33
- package/src/cli/commands/__tests__/validate.test.ts +27 -29
- package/src/cli/commands/acceptance.ts +35 -24
- package/src/cli/commands/analyze-sessions.ts +25 -24
- package/src/cli/commands/check.ts +88 -65
- package/src/cli/commands/command.ts +30 -17
- package/src/cli/commands/constraints-report.ts +37 -34
- package/src/cli/commands/constraints-retire.ts +58 -55
- package/src/cli/commands/constraints.ts +10 -27
- package/src/cli/commands/contract.ts +51 -42
- package/src/cli/commands/definitions.ts +36 -222
- package/src/cli/commands/failure.ts +33 -26
- package/src/cli/commands/init.ts +166 -220
- package/src/cli/commands/knowledge.ts +225 -203
- package/src/cli/commands/passes-gate.ts +58 -68
- package/src/cli/commands/performance.ts +23 -18
- package/src/cli/commands/posteval-plan.ts +29 -15
- package/src/cli/commands/release.ts +70 -59
- package/src/cli/commands/report.ts +9 -5
- package/src/cli/commands/review.ts +39 -29
- package/src/cli/commands/sdd.ts +7 -5
- package/src/cli/commands/security.ts +35 -26
- package/src/cli/commands/spec-baseline-check.ts +16 -11
- package/src/cli/commands/spec.ts +66 -53
- package/src/cli/commands/status.ts +59 -53
- package/src/cli/commands/sync-docs/agents-syncer.ts +5 -2
- package/src/cli/commands/sync-docs/context-syncer.ts +3 -2
- package/src/cli/commands/sync-docs/index.ts +73 -100
- package/src/cli/commands/sync-docs/project-reader.ts +17 -18
- package/src/cli/commands/update-user-model.ts +33 -45
- package/src/cli/commands/validate.ts +31 -25
- package/src/cli/session-mining/__tests__/transcript.test.ts +118 -0
- package/src/cli/session-mining/transcript.ts +26 -8
- package/src/context/session-manager.ts +19 -33
- package/src/core/CONTEXT.md +9 -6
- package/src/core/constraints/__tests__/capabilities-reconcile.test.ts +200 -0
- package/src/core/constraints/__tests__/capability-counts.test.ts +94 -0
- package/src/core/constraints/__tests__/git-evidence.test.ts +208 -0
- package/src/core/constraints/__tests__/injection-drift.test.ts +3 -10
- package/src/core/constraints/__tests__/injection-writer.test.ts +231 -0
- package/src/core/constraints/__tests__/trace-injection.test.ts +71 -0
- package/src/core/constraints/__tests__/usage-report.test.ts +112 -0
- package/src/core/constraints/agent-prompt-renderer.ts +2 -6
- package/src/core/constraints/capabilities-parser.ts +53 -35
- package/src/core/constraints/capabilities-reconcile.ts +166 -0
- package/src/core/constraints/checker.ts +75 -130
- package/src/core/constraints/checkers/__tests__/capability-sync.test.ts +214 -0
- package/src/core/constraints/checkers/__tests__/context-doc-sync.test.ts +77 -0
- package/src/core/constraints/checkers/__tests__/docs-freshness.test.ts +117 -0
- package/src/{__tests__ → core/constraints/checkers/__tests__}/governance-presence.test.ts +83 -9
- package/src/core/constraints/checkers/__tests__/iron-flags.test.ts +50 -0
- package/src/core/constraints/checkers/__tests__/no-bypass-checkpoint.test.ts +76 -0
- package/src/{__tests__ → core/constraints/checkers/__tests__}/no-hardcoded-credentials.test.ts +4 -3
- package/src/core/constraints/checkers/__tests__/no-test-simplification.test.ts +58 -0
- package/src/core/constraints/checkers/__tests__/three-state-consistency.test.ts +145 -0
- package/src/core/constraints/checkers/capability-sync.ts +29 -88
- package/src/core/constraints/checkers/context-doc-sync.ts +15 -25
- package/src/core/constraints/checkers/docs-freshness.ts +40 -69
- package/src/core/constraints/checkers/governance-presence.ts +7 -25
- package/src/core/constraints/checkers/no-test-simplification.ts +4 -3
- package/src/core/constraints/checkers/types.ts +2 -2
- package/src/core/constraints/context-builder.ts +39 -91
- package/src/core/constraints/doc-freshness/runner.ts +2 -1
- package/src/core/constraints/git-evidence.ts +120 -0
- package/src/core/constraints/injection-drift.ts +13 -60
- package/src/core/constraints/injection-writer.ts +212 -0
- package/src/core/constraints/usage-report.ts +36 -17
- package/src/core/index.ts +4 -2
- package/src/core/project-config-loader.ts +49 -9
- package/src/core/validators/__tests__/passes-gate.test.ts +2 -56
- package/src/core/validators/__tests__/test-output.test.ts +372 -0
- package/src/core/validators/passes-gate.ts +86 -248
- package/src/core/validators/test-output.ts +128 -0
- package/src/failure/__tests__/recorder.test.ts +168 -0
- package/src/failure/recorder.ts +12 -10
- package/src/gates/CONTEXT.md +6 -3
- package/src/gates/__tests__/acceptance-types-single-source.test.ts +68 -0
- package/src/gates/__tests__/acceptance.test.ts +4 -86
- package/src/gates/__tests__/effective-gates.test.ts +3 -8
- package/src/gates/__tests__/test-verdict-consistency.test.ts +140 -0
- package/src/gates/acceptance.ts +19 -84
- package/src/gates/checker-gate.ts +8 -7
- package/src/gates/command.ts +10 -16
- package/src/gates/contract.ts +22 -61
- package/src/gates/performance.ts +10 -22
- package/src/gates/review.ts +21 -41
- package/src/gates/security.ts +10 -22
- package/src/gates/types.ts +70 -5
- package/src/hooks/CONTEXT.md +1 -1
- package/src/hooks/bootstrap.ts +5 -2
- package/src/index.ts +0 -4
- package/src/knowledge/CONTEXT.md +8 -3
- package/src/knowledge/__tests__/audit-labels.test.ts +44 -0
- package/src/knowledge/__tests__/flywheel-metrics.test.ts +135 -0
- package/src/knowledge/__tests__/import.test.ts +44 -0
- package/src/knowledge/__tests__/index-generator.test.ts +53 -0
- package/src/knowledge/__tests__/ingest.test.ts +85 -0
- package/src/knowledge/__tests__/migration.test.ts +47 -0
- package/src/knowledge/__tests__/reference-tracker.test.ts +16 -0
- package/src/knowledge/__tests__/store.test.ts +194 -0
- package/src/knowledge/audit.ts +67 -71
- package/src/knowledge/flywheel-metrics.ts +71 -0
- package/src/knowledge/import.ts +4 -18
- package/src/knowledge/index-generator.ts +19 -14
- package/src/knowledge/ingest.ts +9 -4
- package/src/knowledge/migration.ts +11 -8
- package/src/knowledge/reference-tracker.ts +12 -8
- package/src/knowledge/store.ts +64 -11
- package/src/monitoring/CONTEXT.md +8 -3
- package/src/monitoring/__tests__/skipped-lines-report.test.ts +178 -0
- package/src/monitoring/__tests__/traces.test.ts +57 -0
- package/src/monitoring/context-tracker.ts +11 -23
- package/src/monitoring/index.ts +1 -1
- package/src/monitoring/trace-analyzer.ts +21 -2
- package/src/monitoring/traces.ts +39 -36
- package/src/release/CONTEXT.md +1 -0
- package/src/release/__tests__/barrel.test.ts +60 -0
- package/src/release/index.ts +2 -13
- package/src/sdd/__tests__/index-generator.test.ts +71 -0
- package/src/sdd/index-generator.ts +9 -9
- package/src/test-setup/__tests__/project-fixture.test.ts +178 -0
- package/src/test-setup/project-fixture.ts +87 -0
- package/src/tools/CONTEXT.md +6 -0
- package/src/tools/__tests__/registry.test.ts +221 -0
- package/src/types/__tests__/types.test.ts +4 -5
- package/src/types/constraint.ts +0 -25
- package/src/types/passes-gate.ts +10 -30
- package/src/types/project-config.ts +1 -1
- package/src/types/session.ts +5 -5
- package/src/utils/__tests__/frontmatter.test.ts +206 -0
- package/src/utils/__tests__/jsonl-skip-disposition.test.ts +175 -0
- package/src/utils/__tests__/jsonl.test.ts +187 -0
- package/src/utils/__tests__/package-version.test.ts +97 -0
- package/src/utils/exec.ts +15 -0
- package/src/utils/file-walk.ts +11 -2
- package/src/utils/frontmatter.ts +121 -0
- package/src/utils/jsonl.ts +167 -0
- package/src/utils/package-version.ts +27 -0
- package/dist/cli/commands/doc-freshness-check.d.ts +0 -53
- package/dist/cli/commands/doc-freshness-check.d.ts.map +0 -1
- package/dist/cli/commands/doc-freshness-check.js +0 -352
- package/dist/cli/commands/doc-freshness-check.js.map +0 -1
- package/dist/types/index.d.ts +0 -14
- package/dist/types/index.d.ts.map +0 -1
- package/dist/types/index.js +0 -39
- package/dist/types/index.js.map +0 -1
- package/src/__tests__/long-running.test.ts +0 -17
- package/src/__tests__/passes-gate-extension.test.ts +0 -151
- package/src/cli/commands/__tests__/doc-freshness-check.test.ts +0 -168
- package/src/cli/commands/doc-freshness-check.ts +0 -386
- package/src/spec/CONTEXT.md +0 -11
- package/src/types/index.ts +0 -47
|
@@ -22,10 +22,12 @@ import * as path from 'path';
|
|
|
22
22
|
import * as os from 'os';
|
|
23
23
|
import {
|
|
24
24
|
readTranscriptSessions,
|
|
25
|
+
type TranscriptFilter,
|
|
25
26
|
extractCorrectionMatches,
|
|
26
27
|
cleanCorrectionConcept,
|
|
27
28
|
jaccardChinese,
|
|
28
29
|
} from '../session-mining';
|
|
30
|
+
import { log, processIO, type CommandIO, type CommandResult } from '../command-contract';
|
|
29
31
|
|
|
30
32
|
export interface UpdateUserModelOptions {
|
|
31
33
|
days?: number; // 只处理最近 N 天(自然日,含今天)的会话;缺省不过滤(向后兼容)
|
|
@@ -51,7 +53,7 @@ interface ModelState {
|
|
|
51
53
|
const STATE_FILE = path.join(os.homedir(), '.claude', 'user-model-state.json');
|
|
52
54
|
const PROFILE_FILE = path.join(os.homedir(), '.claude', 'projects', '-root-projects', 'memory', 'user_profile.md');
|
|
53
55
|
|
|
54
|
-
export async function updateUserModel(options: UpdateUserModelOptions): Promise<
|
|
56
|
+
export async function updateUserModel(options: UpdateUserModelOptions, io: CommandIO = processIO): Promise<CommandResult> {
|
|
55
57
|
const transcriptDir = process.env.CLAUDE_TRANSCRIPTS_DIR
|
|
56
58
|
|| path.join(os.homedir(), '.claude', 'projects', '-root--claude');
|
|
57
59
|
|
|
@@ -61,8 +63,8 @@ export async function updateUserModel(options: UpdateUserModelOptions): Promise<
|
|
|
61
63
|
// 2. Scan new data
|
|
62
64
|
const newSessions = findNewSessions(transcriptDir, state.sessionsProcessed, options.days);
|
|
63
65
|
if (newSessions.length === 0) {
|
|
64
|
-
|
|
65
|
-
return;
|
|
66
|
+
log(io, chalk.gray('No new sessions to process'));
|
|
67
|
+
return { kind: 'skip', reason: '没有新会话可处理' };
|
|
66
68
|
}
|
|
67
69
|
|
|
68
70
|
// 3. Extract signals from new data
|
|
@@ -94,12 +96,13 @@ export async function updateUserModel(options: UpdateUserModelOptions): Promise<
|
|
|
94
96
|
|
|
95
97
|
// 6. Output
|
|
96
98
|
if (options.json) {
|
|
97
|
-
|
|
98
|
-
return;
|
|
99
|
+
log(io, JSON.stringify({ newSessions: newSessions.length, changes }, null, 2));
|
|
100
|
+
return { kind: 'ok' };
|
|
99
101
|
}
|
|
100
102
|
|
|
101
|
-
|
|
102
|
-
printChanges(changes, signals);
|
|
103
|
+
log(io, chalk.blue(`📊 Processed ${newSessions.length} new sessions\n`));
|
|
104
|
+
printChanges(changes, signals, io);
|
|
105
|
+
return { kind: 'ok' };
|
|
103
106
|
}
|
|
104
107
|
|
|
105
108
|
// ── State I/O ──
|
|
@@ -139,17 +142,20 @@ interface SimpleSession {
|
|
|
139
142
|
}
|
|
140
143
|
|
|
141
144
|
function findNewSessions(dir: string, processed: string[], days?: number): SimpleSession[] {
|
|
142
|
-
|
|
143
|
-
|
|
145
|
+
// 过滤下推 seam(harness#112):excludeIds 走文件名、since 走 stat,未命中不 parse
|
|
146
|
+
const filter: TranscriptFilter = { excludeIds: processed };
|
|
144
147
|
|
|
145
148
|
// 「最近 N 天」:自然日窗口(含今天)。days<=0 视为不过滤,与缺省一致。
|
|
149
|
+
// date 是 mtime 的 UTC 日,date >= cutoff ⟺ mtimeMs >= cutoff 日 UTC 零点
|
|
146
150
|
if (days !== undefined && days > 0) {
|
|
147
151
|
const cutoff = new Date(Date.now() - (days - 1) * 86_400_000)
|
|
148
152
|
.toISOString()
|
|
149
153
|
.slice(0, 10);
|
|
150
|
-
|
|
154
|
+
filter.since = Date.parse(cutoff);
|
|
151
155
|
}
|
|
152
156
|
|
|
157
|
+
const sessions = readTranscriptSessions(dir, filter);
|
|
158
|
+
|
|
153
159
|
sessions.sort((a, b) => a.date.localeCompare(b.date));
|
|
154
160
|
|
|
155
161
|
return sessions.map(s => ({
|
|
@@ -329,6 +335,8 @@ function applySignals(state: ModelState, signals: SessionSignals[], mergedConcep
|
|
|
329
335
|
const now = new Date().toISOString().slice(0, 10);
|
|
330
336
|
|
|
331
337
|
// Update patterns from merged concept clusters
|
|
338
|
+
// occurrences 唯一来源:mergedConcepts 聚合值(含 correction phrase 的 ×3 加权,
|
|
339
|
+
// 见 buildMergedConcepts)。不再叠加 per-session 原始 count —— 那是 #113 裁决的双计 bug。
|
|
332
340
|
for (const [concept, agg] of Object.entries(mergedConcepts)) {
|
|
333
341
|
if (!state.patterns[concept]) {
|
|
334
342
|
state.patterns[concept] = {
|
|
@@ -344,26 +352,6 @@ function applySignals(state: ModelState, signals: SessionSignals[], mergedConcep
|
|
|
344
352
|
p.trend = p.occurrences >= 5 ? 'stable' : 'rising';
|
|
345
353
|
}
|
|
346
354
|
|
|
347
|
-
// Also track per-session concepts
|
|
348
|
-
for (const sig of signals) {
|
|
349
|
-
for (const [concept, count] of Object.entries(sig.concepts)) {
|
|
350
|
-
if (!state.patterns[concept]) {
|
|
351
|
-
state.patterns[concept] = {
|
|
352
|
-
firstSeen: now,
|
|
353
|
-
occurrences: 0,
|
|
354
|
-
sessions: [],
|
|
355
|
-
trend: 'new',
|
|
356
|
-
lastSeen: now,
|
|
357
|
-
};
|
|
358
|
-
}
|
|
359
|
-
const p = state.patterns[concept];
|
|
360
|
-
p.occurrences += count;
|
|
361
|
-
if (!p.sessions.includes(sig.sessionId)) p.sessions.push(sig.sessionId);
|
|
362
|
-
p.lastSeen = now;
|
|
363
|
-
p.trend = p.occurrences >= 5 ? 'stable' : 'rising';
|
|
364
|
-
}
|
|
365
|
-
}
|
|
366
|
-
|
|
367
355
|
// Update lens weights from correction signals
|
|
368
356
|
for (const sig of signals) {
|
|
369
357
|
if (sig.correctionPhrases.length > 0) {
|
|
@@ -430,9 +418,9 @@ function updateProfile(state: ModelState): void {
|
|
|
430
418
|
|
|
431
419
|
// ── Output ──
|
|
432
420
|
|
|
433
|
-
function printChanges(changes: Change[], signals: SessionSignals[]): void {
|
|
421
|
+
function printChanges(changes: Change[], signals: SessionSignals[], io: CommandIO): void {
|
|
434
422
|
if (changes.length === 0) {
|
|
435
|
-
|
|
423
|
+
log(io, chalk.green('No significant changes detected'));
|
|
436
424
|
return;
|
|
437
425
|
}
|
|
438
426
|
|
|
@@ -443,31 +431,31 @@ function printChanges(changes: Change[], signals: SessionSignals[]): void {
|
|
|
443
431
|
};
|
|
444
432
|
|
|
445
433
|
if (byType.new_pattern.length > 0) {
|
|
446
|
-
|
|
434
|
+
log(io, chalk.yellow(`🌱 New patterns: ${byType.new_pattern.length}`));
|
|
447
435
|
for (const c of byType.new_pattern.slice(0, 5)) {
|
|
448
|
-
|
|
436
|
+
log(io, chalk.gray(` ${c.key}: ${c.detail}`));
|
|
449
437
|
}
|
|
450
|
-
|
|
438
|
+
log(io);
|
|
451
439
|
}
|
|
452
440
|
|
|
453
441
|
if (byType.rising.length > 0) {
|
|
454
|
-
|
|
442
|
+
log(io, chalk.green(`📈 Re-emerging: ${byType.rising.length}`));
|
|
455
443
|
for (const c of byType.rising.slice(0, 5)) {
|
|
456
|
-
|
|
444
|
+
log(io, chalk.gray(` ${c.key}: ${c.detail}`));
|
|
457
445
|
}
|
|
458
|
-
|
|
446
|
+
log(io);
|
|
459
447
|
}
|
|
460
448
|
|
|
461
449
|
if (byType.lens_shift.length > 0) {
|
|
462
|
-
|
|
450
|
+
log(io, chalk.cyan(`🎯 Lens shifts:`));
|
|
463
451
|
for (const c of byType.lens_shift) {
|
|
464
|
-
|
|
452
|
+
log(io, chalk.gray(` ${c.key}: ${c.detail}`));
|
|
465
453
|
}
|
|
466
|
-
|
|
454
|
+
log(io);
|
|
467
455
|
}
|
|
468
456
|
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
457
|
+
log(io, chalk.bold(`Total signals processed:`));
|
|
458
|
+
log(io, ` Sessions: ${signals.length}`);
|
|
459
|
+
log(io, ` Correction phrases: ${signals.reduce((s, sig) => s + sig.correctionPhrases.length, 0)}`);
|
|
460
|
+
log(io, ` Concepts extracted: ${signals.reduce((s, sig) => s + Object.keys(sig.concepts).length, 0)}`);
|
|
473
461
|
}
|
|
@@ -10,6 +10,7 @@ import * as path from 'path';
|
|
|
10
10
|
import * as yaml from 'js-yaml';
|
|
11
11
|
import { CheckpointValidator } from '../../core/validators/checkpoint';
|
|
12
12
|
import type { Checkpoint, CheckpointContext } from '../../types/checkpoint';
|
|
13
|
+
import { log, processIO, type CommandIO, type CommandResult } from '../command-contract';
|
|
13
14
|
|
|
14
15
|
export interface ValidateOptions {
|
|
15
16
|
/** 检查点文件路径 */
|
|
@@ -28,13 +29,13 @@ const DEFAULT_CHECKPOINT_FILE = '.harness/checkpoints.yml';
|
|
|
28
29
|
/**
|
|
29
30
|
* 加载检查点配置
|
|
30
31
|
*/
|
|
31
|
-
async function loadCheckpoints(filePath: string): Promise<Checkpoint[]> {
|
|
32
|
+
async function loadCheckpoints(filePath: string, io: CommandIO): Promise<Checkpoint[]> {
|
|
32
33
|
try {
|
|
33
34
|
const content = await fs.readFile(filePath, 'utf-8');
|
|
34
35
|
const data = yaml.load(content) as { checkpoints?: Checkpoint[] };
|
|
35
36
|
return data.checkpoints || [];
|
|
36
37
|
} catch (error) {
|
|
37
|
-
|
|
38
|
+
log(io, chalk.yellow(`⚠️ 未找到检查点文件: ${filePath}`));
|
|
38
39
|
return [];
|
|
39
40
|
}
|
|
40
41
|
}
|
|
@@ -42,23 +43,26 @@ async function loadCheckpoints(filePath: string): Promise<Checkpoint[]> {
|
|
|
42
43
|
/**
|
|
43
44
|
* 执行检查点验证
|
|
44
45
|
*/
|
|
45
|
-
export async function validate(
|
|
46
|
-
|
|
46
|
+
export async function validate(
|
|
47
|
+
options: ValidateOptions,
|
|
48
|
+
io: CommandIO = processIO,
|
|
49
|
+
): Promise<CommandResult> {
|
|
50
|
+
log(io, chalk.blue('🔍 验证检查点...'));
|
|
47
51
|
|
|
48
52
|
const projectPath = options.projectPath || process.cwd();
|
|
49
53
|
const checkpointFile = options.file || path.join(projectPath, DEFAULT_CHECKPOINT_FILE);
|
|
50
54
|
|
|
51
55
|
// 加载检查点
|
|
52
|
-
const checkpoints = await loadCheckpoints(checkpointFile);
|
|
56
|
+
const checkpoints = await loadCheckpoints(checkpointFile, io);
|
|
53
57
|
|
|
54
58
|
if (checkpoints.length === 0) {
|
|
55
|
-
|
|
56
|
-
return;
|
|
59
|
+
log(io, chalk.gray('没有定义检查点,跳过验证'));
|
|
60
|
+
return { kind: 'skip', reason: `没有定义检查点: ${checkpointFile}` };
|
|
57
61
|
}
|
|
58
62
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
63
|
+
log(io, chalk.gray(`检查点文件: ${checkpointFile}`));
|
|
64
|
+
log(io, chalk.gray(`检查点数量: ${checkpoints.length}`));
|
|
65
|
+
log(io);
|
|
62
66
|
|
|
63
67
|
// 构建上下文
|
|
64
68
|
const context: CheckpointContext = {
|
|
@@ -69,20 +73,22 @@ export async function validate(options: ValidateOptions): Promise<void> {
|
|
|
69
73
|
// 执行验证
|
|
70
74
|
const validator = CheckpointValidator.getInstance();
|
|
71
75
|
const results = [];
|
|
76
|
+
const failedIds: string[] = [];
|
|
72
77
|
|
|
73
78
|
for (const checkpoint of checkpoints) {
|
|
74
79
|
const result = await validator.validate(checkpoint, context);
|
|
75
80
|
results.push(result);
|
|
76
81
|
|
|
77
82
|
if (result.passed) {
|
|
78
|
-
|
|
83
|
+
log(io, chalk.green(`✅ ${checkpoint.id}: 通过`));
|
|
79
84
|
} else {
|
|
80
|
-
|
|
85
|
+
log(io, chalk.red(`❌ ${checkpoint.id}: 失败`));
|
|
81
86
|
result.checks.forEach(check => {
|
|
82
87
|
if (!check.passed) {
|
|
83
|
-
|
|
88
|
+
log(io, chalk.red(` - ${check.checkId}: ${check.message || check.error}`));
|
|
84
89
|
}
|
|
85
90
|
});
|
|
91
|
+
failedIds.push(checkpoint.id);
|
|
86
92
|
}
|
|
87
93
|
}
|
|
88
94
|
|
|
@@ -90,16 +96,16 @@ export async function validate(options: ValidateOptions): Promise<void> {
|
|
|
90
96
|
const passed = results.filter(r => r.passed).length;
|
|
91
97
|
const failed = results.filter(r => !r.passed).length;
|
|
92
98
|
|
|
93
|
-
|
|
94
|
-
|
|
99
|
+
log(io);
|
|
100
|
+
log(io, chalk.gray(`通过: ${passed}/${results.length}`));
|
|
95
101
|
|
|
96
102
|
if (failed > 0) {
|
|
97
|
-
|
|
103
|
+
log(io, chalk.red(`\n🛑 ${failed} 个检查点未通过`));
|
|
98
104
|
// 工单 23:门控语义——检查点失败一律非零退出(此前仅 --strict 退出,钩子/CI 形同虚设)
|
|
99
|
-
|
|
100
|
-
} else {
|
|
101
|
-
console.log(chalk.green('\n✅ 所有检查点验证通过'));
|
|
105
|
+
return { kind: 'fail', reason: `${failed} 个检查点未通过: ${failedIds.join(', ')}` };
|
|
102
106
|
}
|
|
107
|
+
log(io, chalk.green('\n✅ 所有检查点验证通过'));
|
|
108
|
+
return { kind: 'ok' };
|
|
103
109
|
}
|
|
104
110
|
|
|
105
111
|
/**
|
|
@@ -138,14 +144,14 @@ export const DEFAULT_CHECKPOINTS: Checkpoint[] = [
|
|
|
138
144
|
/**
|
|
139
145
|
* 创建示例检查点文件
|
|
140
146
|
*/
|
|
141
|
-
export async function createExampleCheckpoint(projectPath: string): Promise<void> {
|
|
147
|
+
export async function createExampleCheckpoint(projectPath: string, io: CommandIO = processIO): Promise<void> {
|
|
142
148
|
const filePath = path.join(projectPath, DEFAULT_CHECKPOINT_FILE);
|
|
143
149
|
const dir = path.dirname(filePath);
|
|
144
150
|
|
|
145
151
|
// 如果已存在,不覆盖
|
|
146
152
|
try {
|
|
147
153
|
await fs.access(filePath);
|
|
148
|
-
|
|
154
|
+
log(io, chalk.gray(`checkpoints.yml 已存在,跳过`));
|
|
149
155
|
return;
|
|
150
156
|
} catch {
|
|
151
157
|
// 文件不存在,创建
|
|
@@ -156,7 +162,7 @@ export async function createExampleCheckpoint(projectPath: string): Promise<void
|
|
|
156
162
|
const content = yaml.dump({ checkpoints: DEFAULT_CHECKPOINTS }, { indent: 2 });
|
|
157
163
|
await fs.writeFile(filePath, content, 'utf-8');
|
|
158
164
|
|
|
159
|
-
|
|
165
|
+
log(io, chalk.green(`✅ 已创建示例检查点文件: ${filePath}`));
|
|
160
166
|
}
|
|
161
167
|
|
|
162
168
|
/**
|
|
@@ -180,14 +186,14 @@ const DEFAULT_RESOLUTIONS = {
|
|
|
180
186
|
/**
|
|
181
187
|
* 创建示例 Resolutions 文件(RKB dogfood)
|
|
182
188
|
*/
|
|
183
|
-
export async function createExampleResolutions(projectPath: string): Promise<void> {
|
|
189
|
+
export async function createExampleResolutions(projectPath: string, io: CommandIO = processIO): Promise<void> {
|
|
184
190
|
const harnessDir = path.join(projectPath, '.harness');
|
|
185
191
|
const filePath = path.join(harnessDir, 'resolutions.json');
|
|
186
192
|
|
|
187
193
|
// 如果已存在,不覆盖
|
|
188
194
|
try {
|
|
189
195
|
await fs.access(filePath);
|
|
190
|
-
|
|
196
|
+
log(io, chalk.gray(`resolutions.json 已存在,跳过`));
|
|
191
197
|
return;
|
|
192
198
|
} catch {
|
|
193
199
|
// 文件不存在,创建
|
|
@@ -198,5 +204,5 @@ export async function createExampleResolutions(projectPath: string): Promise<voi
|
|
|
198
204
|
const content = JSON.stringify(DEFAULT_RESOLUTIONS, null, 2);
|
|
199
205
|
await fs.writeFile(filePath, content, 'utf-8');
|
|
200
206
|
|
|
201
|
-
|
|
207
|
+
log(io, chalk.green(`✅ 已创建 Resolutions 文件: ${filePath}`));
|
|
202
208
|
}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* readTranscriptSessions 坏行/null 记录容错测试(harness#82)
|
|
3
|
+
*
|
|
4
|
+
* transcript 行可 parse 但值为 null(或提取异常)时,
|
|
5
|
+
* 与原逐行 catch 实现一致:该条跳过,不影响其余记录。
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import * as fs from 'fs';
|
|
9
|
+
import * as os from 'os';
|
|
10
|
+
import * as path from 'path';
|
|
11
|
+
import { readTranscriptSessions } from '../transcript';
|
|
12
|
+
|
|
13
|
+
describe('readTranscriptSessions 坏行容错(harness#82)', () => {
|
|
14
|
+
let dir: string;
|
|
15
|
+
|
|
16
|
+
beforeEach(() => {
|
|
17
|
+
dir = fs.mkdtempSync(path.join(os.tmpdir(), 'harness-transcript-'));
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
afterEach(() => {
|
|
21
|
+
fs.rmSync(dir, { recursive: true, force: true });
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
it('null 行与坏行只丢该行,合法 turn 照常提取', () => {
|
|
25
|
+
const lines = [
|
|
26
|
+
JSON.stringify({ message: { role: 'user', content: 'hello' } }),
|
|
27
|
+
'null', // parse 合法但值为 null,原实现经逐行 catch 跳过
|
|
28
|
+
'{"broken',
|
|
29
|
+
JSON.stringify({ message: { role: 'assistant', content: [{ type: 'text', text: 'hi' }] } }),
|
|
30
|
+
];
|
|
31
|
+
fs.writeFileSync(path.join(dir, 'session-a.jsonl'), lines.join('\n') + '\n', 'utf-8');
|
|
32
|
+
|
|
33
|
+
const sessions = readTranscriptSessions(dir);
|
|
34
|
+
expect(sessions).toHaveLength(1);
|
|
35
|
+
expect(sessions[0].turns.map(t => t.role)).toEqual(['user', 'assistant']);
|
|
36
|
+
expect(sessions[0].turns[1].content).toBe('hi');
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
it('目录不可读返回空数组', () => {
|
|
40
|
+
expect(readTranscriptSessions(path.join(dir, 'missing'))).toEqual([]);
|
|
41
|
+
});
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
describe('readTranscriptSessions 过滤(harness#112)', () => {
|
|
45
|
+
let dir: string;
|
|
46
|
+
|
|
47
|
+
beforeEach(() => {
|
|
48
|
+
dir = fs.mkdtempSync(path.join(os.tmpdir(), 'harness-transcript-filter-'));
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
afterEach(() => {
|
|
52
|
+
fs.rmSync(dir, { recursive: true, force: true });
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
function writeSession(name: string, text: string, mtime?: Date): void {
|
|
56
|
+
const p = path.join(dir, name);
|
|
57
|
+
fs.writeFileSync(
|
|
58
|
+
p,
|
|
59
|
+
JSON.stringify({ message: { role: 'user', content: text } }) + '\n',
|
|
60
|
+
'utf-8',
|
|
61
|
+
);
|
|
62
|
+
if (mtime) fs.utimesSync(p, mtime, mtime);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
it('excludeIds:命中的会话不进结果(文件名级过滤,不 parse)', () => {
|
|
66
|
+
writeSession('session-a.jsonl', '甲会话内容');
|
|
67
|
+
writeSession('session-b.jsonl', '乙会话内容');
|
|
68
|
+
|
|
69
|
+
const sessions = readTranscriptSessions(dir, { excludeIds: ['session-a'] });
|
|
70
|
+
expect(sessions.map(s => s.id)).toEqual(['session-b']);
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
it('excludeIds 按截断 40 字符的会话 ID 匹配', () => {
|
|
74
|
+
const longName = 'a'.repeat(50);
|
|
75
|
+
writeSession(`${longName}.jsonl`, '长名会话内容');
|
|
76
|
+
writeSession('session-b.jsonl', '乙会话内容');
|
|
77
|
+
|
|
78
|
+
const sessions = readTranscriptSessions(dir, { excludeIds: [longName.slice(0, 40)] });
|
|
79
|
+
expect(sessions.map(s => s.id)).toEqual(['session-b']);
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
it('since:mtimeMs 早于窗口的文件不进结果(stat 级过滤,不 parse)', () => {
|
|
83
|
+
writeSession('old.jsonl', '旧会话内容', new Date(Date.now() - 30 * 86_400_000));
|
|
84
|
+
writeSession('recent.jsonl', '新会话内容');
|
|
85
|
+
|
|
86
|
+
const since = Date.now() - 7 * 86_400_000;
|
|
87
|
+
const sessions = readTranscriptSessions(dir, { since });
|
|
88
|
+
expect(sessions.map(s => s.id)).toEqual(['recent']);
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
it('since 边界含等于:mtimeMs == since 仍计入', () => {
|
|
92
|
+
const t = new Date('2026-08-01T12:00:00.000Z');
|
|
93
|
+
writeSession('edge.jsonl', '边界会话内容', t);
|
|
94
|
+
|
|
95
|
+
const sessions = readTranscriptSessions(dir, { since: t.getTime() });
|
|
96
|
+
expect(sessions.map(s => s.id)).toEqual(['edge']);
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
it('since 与 excludeIds 可叠加', () => {
|
|
100
|
+
writeSession('old.jsonl', '旧会话内容', new Date(Date.now() - 30 * 86_400_000));
|
|
101
|
+
writeSession('excluded.jsonl', '被排除会话');
|
|
102
|
+
writeSession('kept.jsonl', '保留会话内容');
|
|
103
|
+
|
|
104
|
+
const sessions = readTranscriptSessions(dir, {
|
|
105
|
+
since: Date.now() - 7 * 86_400_000,
|
|
106
|
+
excludeIds: ['excluded'],
|
|
107
|
+
});
|
|
108
|
+
expect(sessions.map(s => s.id)).toEqual(['kept']);
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
it('无 filter:全量读取(向后兼容)', () => {
|
|
112
|
+
writeSession('a.jsonl', '甲会话内容', new Date(Date.now() - 30 * 86_400_000));
|
|
113
|
+
writeSession('b.jsonl', '乙会话内容');
|
|
114
|
+
|
|
115
|
+
const sessions = readTranscriptSessions(dir);
|
|
116
|
+
expect(sessions).toHaveLength(2);
|
|
117
|
+
});
|
|
118
|
+
});
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
|
|
8
8
|
import * as fs from 'fs';
|
|
9
9
|
import * as path from 'path';
|
|
10
|
+
import { readJsonl } from '../../utils/jsonl';
|
|
10
11
|
|
|
11
12
|
export interface MinedTurn {
|
|
12
13
|
role: string;
|
|
@@ -41,8 +42,18 @@ function extractText(content: unknown): string {
|
|
|
41
42
|
*
|
|
42
43
|
* 不可读/损坏的行静默跳过(与原实现一致)。
|
|
43
44
|
*/
|
|
44
|
-
export
|
|
45
|
+
export interface TranscriptFilter {
|
|
46
|
+
/** 只读 mtimeMs >= since 的文件(stat 级过滤,命中即不 parse);缺省不过滤 */
|
|
47
|
+
since?: number;
|
|
48
|
+
/** 按会话 ID(文件名去 .jsonl、截断 40 字符)排除(文件名级过滤,不 stat 不 parse);缺省不排除 */
|
|
49
|
+
excludeIds?: string[];
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export function readTranscriptSessions(dir: string, filter: TranscriptFilter = {}): MinedSession[] {
|
|
45
53
|
const sessions: MinedSession[] = [];
|
|
54
|
+
const exclude = filter.excludeIds && filter.excludeIds.length > 0
|
|
55
|
+
? new Set(filter.excludeIds)
|
|
56
|
+
: undefined;
|
|
46
57
|
|
|
47
58
|
let files: string[];
|
|
48
59
|
try {
|
|
@@ -53,6 +64,8 @@ export function readTranscriptSessions(dir: string): MinedSession[] {
|
|
|
53
64
|
|
|
54
65
|
for (const file of files) {
|
|
55
66
|
if (!file.endsWith('.jsonl')) continue;
|
|
67
|
+
const id = file.replace('.jsonl', '').slice(0, 40);
|
|
68
|
+
if (exclude?.has(id)) continue;
|
|
56
69
|
const filePath = path.join(dir, file);
|
|
57
70
|
|
|
58
71
|
let stat: fs.Stats;
|
|
@@ -61,21 +74,26 @@ export function readTranscriptSessions(dir: string): MinedSession[] {
|
|
|
61
74
|
} catch {
|
|
62
75
|
continue;
|
|
63
76
|
}
|
|
77
|
+
if (filter.since !== undefined && stat.mtimeMs < filter.since) continue;
|
|
64
78
|
|
|
65
79
|
const turns: MinedTurn[] = [];
|
|
66
80
|
const toolCalls: string[] = [];
|
|
67
81
|
|
|
68
|
-
let
|
|
82
|
+
let records: Record<string, any>[];
|
|
69
83
|
try {
|
|
70
|
-
|
|
84
|
+
// 损坏行静默跳过(坏行策略 skip,与原实现一致,harness#82 走 jsonl 正本);
|
|
85
|
+
// 外层 catch 兜文件不可读,沿用原「跳过该文件」语义
|
|
86
|
+
// 计数去向:豁免(harness#100)——读的是外部 Claude Code transcript(非 harness 写入面)。
|
|
87
|
+
// 影响方向如实:坏行使该会话少几条 turn,而 analyze-sessions 的候选按次数阈值筛
|
|
88
|
+
// (frequency>=4 / 跨会话>=2 / confidence=len/10)→ 只会少出候选,不会造出候选,且候选须人审;
|
|
89
|
+
// 告知需改 MinedSession 形状并波及 analyze-sessions/update-user-model 两个调用方,另票收口
|
|
90
|
+
records = readJsonl<Record<string, any>>(filePath, 'skip').records;
|
|
71
91
|
} catch {
|
|
72
92
|
continue;
|
|
73
93
|
}
|
|
74
94
|
|
|
75
|
-
for (const
|
|
76
|
-
if (!line.trim()) continue;
|
|
95
|
+
for (const entry of records) {
|
|
77
96
|
try {
|
|
78
|
-
const entry = JSON.parse(line);
|
|
79
97
|
const msg = entry.message;
|
|
80
98
|
if (msg?.role && (msg.content || entry.type === 'user')) {
|
|
81
99
|
turns.push({ role: msg.role, content: extractText(msg.content) });
|
|
@@ -88,13 +106,13 @@ export function readTranscriptSessions(dir: string): MinedSession[] {
|
|
|
88
106
|
}
|
|
89
107
|
}
|
|
90
108
|
} catch {
|
|
91
|
-
//
|
|
109
|
+
// 单条记录提取异常跳过(原逐行 catch 语义:parse 已由 module skip,此处兜提取)
|
|
92
110
|
}
|
|
93
111
|
}
|
|
94
112
|
|
|
95
113
|
if (turns.length > 0) {
|
|
96
114
|
sessions.push({
|
|
97
|
-
id
|
|
115
|
+
id,
|
|
98
116
|
date: stat.mtime.toISOString().slice(0, 10),
|
|
99
117
|
mtimeMs: stat.mtimeMs,
|
|
100
118
|
turns,
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
|
|
9
9
|
import * as fs from 'fs';
|
|
10
10
|
import * as path from 'path';
|
|
11
|
+
import { readJsonl, appendJsonl } from '../utils/jsonl';
|
|
11
12
|
import { ContextTracker } from '../monitoring/context-tracker';
|
|
12
13
|
import type {
|
|
13
14
|
SessionEvent,
|
|
@@ -65,20 +66,12 @@ export class SessionManager {
|
|
|
65
66
|
// 从磁盘恢复
|
|
66
67
|
const eventsPath = path.join(this.getSessionDir(id), 'events.jsonl');
|
|
67
68
|
try {
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
const events: SessionEvent[] = [];
|
|
75
|
-
for (const line of lines) {
|
|
76
|
-
try {
|
|
77
|
-
events.push(JSON.parse(line) as SessionEvent);
|
|
78
|
-
} catch {
|
|
79
|
-
// 跳过损坏行
|
|
80
|
-
}
|
|
81
|
-
}
|
|
69
|
+
// 坏行策略:skip(原逐行 catch 跳过语义不变,harness#82);
|
|
70
|
+
// 空文件判定保持原始非空行数口径(合法 + 坏行 = 0 才算空)
|
|
71
|
+
// 计数去向:并进空事件判定的原始行数口径(harness#100 记名豁免:会话恢复面只区分
|
|
72
|
+
// "有没有事件",单列坏行数不改变任何输出;会话事件写链在本地,损坏=半写入截断)
|
|
73
|
+
const { records: events, skippedLines } = readJsonl<SessionEvent>(eventsPath, 'skip');
|
|
74
|
+
if (events.length + skippedLines === 0) return undefined;
|
|
82
75
|
|
|
83
76
|
const stat = fs.statSync(eventsPath);
|
|
84
77
|
const handle: SessionHandle = {
|
|
@@ -178,22 +171,16 @@ export class SessionManager {
|
|
|
178
171
|
// 从 events.jsonl 恢复事件
|
|
179
172
|
const eventsPath = path.join(sessionsDir, sessionId, 'events.jsonl');
|
|
180
173
|
if (fs.existsSync(eventsPath)) {
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
//
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
return null;
|
|
192
|
-
}
|
|
193
|
-
})
|
|
194
|
-
.filter((e): e is SessionEvent => e !== null);
|
|
195
|
-
|
|
196
|
-
handle.events = events;
|
|
174
|
+
// 坏行策略:skip(原逐行 null-filter 语义不变,harness#82);
|
|
175
|
+
// 只恢复 checkpoint 之前的原始行(head 截断在 parse 之前);
|
|
176
|
+
// !== null 沿用原过滤口径
|
|
177
|
+
// 计数去向:豁免(harness#100)——恢复路径没有用户可见输出面(失败即整体抛
|
|
178
|
+
// `Checkpoint ${id} 不存在`),坏行只会让恢复出的事件少于 checkpoint 声明数;
|
|
179
|
+
// 告知需要改 loadCheckpoint 的抛错形状,属行为变更不在本票
|
|
180
|
+
const { records } = readJsonl<SessionEvent>(eventsPath, 'skip', {
|
|
181
|
+
head: checkpointData.eventCount,
|
|
182
|
+
});
|
|
183
|
+
handle.events = records.filter((e): e is SessionEvent => e !== null);
|
|
197
184
|
}
|
|
198
185
|
|
|
199
186
|
return handle;
|
|
@@ -237,9 +224,8 @@ export class SessionManager {
|
|
|
237
224
|
*/
|
|
238
225
|
private appendEvent(sessionId: string, event: SessionEvent): void {
|
|
239
226
|
try {
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
fs.appendFileSync(eventsPath, line, 'utf-8');
|
|
227
|
+
// 写链收口:ensureDir + append(harness#82)
|
|
228
|
+
appendJsonl(path.join(this.getSessionDir(sessionId), 'events.jsonl'), event);
|
|
243
229
|
} catch {
|
|
244
230
|
// 持久化失败,静默处理
|
|
245
231
|
}
|
package/src/core/CONTEXT.md
CHANGED
|
@@ -4,27 +4,30 @@
|
|
|
4
4
|
约束引擎核心:check/prompt 二元约束系统(ADR-0001)、生效集合并(effective-constraints)、检查点验证器(CSO/passes-gate)、会话管理、Spec 验证器、项目配置加载。
|
|
5
5
|
|
|
6
6
|
## 核心导出
|
|
7
|
-
- `constraints/` — 约束定义(IRON_LAWS/GUIDELINES/PROMPTS) + 检查引擎(ConstraintChecker,拦截统一由 checkBeforeExecution 承担,ADR-0004) + 缓存(CheckCache:TTL 缓存 + 计数采样,H6/G5 起公开导出) + 注入渲染(injection-renderer) + Agent prompt 渲染(agent-prompt-renderer:trigger 参数化分组渲染,role 路由留 studio,H6/G6)/漂移校验(injection-drift
|
|
7
|
+
- `constraints/` — 约束定义(IRON_LAWS/GUIDELINES/PROMPTS) + 检查引擎(ConstraintChecker,拦截统一由 checkBeforeExecution 承担,ADR-0004) + 缓存(CheckCache:TTL 缓存 + 计数采样,H6/G5 起公开导出) + 注入渲染(injection-renderer) + 落点写入器(injection-writer:「声明→对照→幂等替换」中 marker-range 替换的唯一 writer——replaceStandaloneRange/replaceEnclosedRange/cutMarkerBlock + 半标记守护;落点路由读写两侧同住此模块 resolveInjectionTarget(CLAUDE.md 有标记段优先、否则 AGENTS.md PRESERVE:governance,studio #307)/resolveGovernanceLanding(init 写侧,含旧版无标记 Governance Rules 块豁免),ADR-0011) + Agent prompt 渲染(agent-prompt-renderer:trigger 参数化分组渲染,role 路由留 studio,H6/G6)/漂移校验(injection-drift:纯检测只读,路由消费 injection-writer)/使用统计(usage-report:constraints report·retire 的只读数据层,读 trace 两个入口——`readProjectTracesReport()` 带 `skippedLines`、`readProjectTraces()` 兼容包装丢计数;报告模型 `ConstraintsUsageReport` 的降级位 = `traceFileExists` + `skippedLines`,harness#100)/清单对照(capabilities-reconcile:CAPABILITIES.md 与代码实况的覆盖/幽灵判定唯一实现,capability_sync·docs_freshness·sync-docs 共消费,ADR-0009);CheckEnv 生产侧唯一构造点 `buildCheckEnv(context, providers|'none')`(checkers/types.ts:providers = 证据接线,git 两项绑 GitEvidence 实例,'none' = 显式不接 → evidence flag checker 按契约 skip)
|
|
8
|
+
- `git-evidence.ts` — 全仓唯一 git 取证点(#87):`createGitEvidence(projectPath, run?)` 返回 `GitEvidence{stagedDiff, changedFileNames(staged), headDirs}`,seam 上两个真 adapter(缺省 `realGitCommandRunner` 走真 git / 注入 runner 供计数与替身)。命令级 memo 落在此实例(含失败结果),实例生命周期 = 一次 check run,故 context-builder 与 ConstraintChecker 传同一实例即共用证据;判定语义与迁移前一致(diff 取证失败 → 空串,`git ls-tree` 失败 → null = 所有目录视为新);`parseHeadDirs`/`splitFileNames` 是配套纯函数
|
|
9
|
+
- `constraints/context-builder.ts` — 只装配不取证:`buildConstraintContext(options.evidence?)` 与 `detectTrigger(options.evidence?)` 经 GitEvidence 取 git 事实(不传 = 自建真 adapter),本模块无 child_process import;其余证据标志(traces/文档标记)仍为本地探测
|
|
8
10
|
- `effective-constraints.ts` — `getEffectiveConstraints(projectRoot, {preset?})`:全仓唯一生效集来源(内置 → preset → config.yml 禁用(内置与 custom 同效)→ custom 追加(禁用/已退役的不追加)→ scenes 过滤);`getMergedConstraintsConfig(projectRoot, {preset?})`:同链路的完整 MergedConstraintsConfig 形状(含 disabled/custom/unknownIds),内置工单 23 优先级规则(--preset 仅在无项目自定义配置时生效),check 命令经此入口;`lintEffectiveConfig` 配置诊断
|
|
9
11
|
- `effective-set.ts` — `filterEnabledEntries(knownIds, entries, {onUnknownId})`:约束侧(collect)与门禁侧(throw)共用的 config 条目筛选器
|
|
10
|
-
- `validators/` — checkpoints、passes-gate、CSO
|
|
12
|
+
- `validators/` — checkpoints、passes-gate、CSO 验证器;`test-output.ts` —「测试产物解读」唯一实现:`extractFailures` 提取函数 + `judgeTestRun` 判定入口(退出码为主 + 行首锚定的文本失败信号交叉否决;文本救不回非零退出,`allowPartialPass` 只作用于文本否决那一维),passes-gate 与 `gates/acceptance` 的结论一律从它取、各自体内不写判定 `if`(解析收口 ADR-0012,判定依据 ADR-0014);**不读覆盖率**——harness 核心判定对覆盖率不取数不执法,判覆盖率的两处(CLI `passes-gate --coverage`、`gates/performance`)各自读 json-summary,`extractCoverage` 与 `TaskTestResult.coverage` 已随 ADR-0015 删除;`PassesGate.runTests(workDir)` 的执行与证据落盘根是**必传形参**,本层不再取 cwd(harness#95,约定正本见 `src/cli/commands/CONTEXT.md`);`detectTestCommand` 是测试命令探测唯一正本(模块级导出:test:ci → test 排 echo 占位 → test:e2e → test:coverage → Python 标记 pyproject.toml/pytest.ini → go.mod,探不到返回 undefined,兜底归调用方——CLI 映射 skip、PassesGate 内部 fail-closed,不再兜底 'npm test';CLI 本地版已删,架构评审 A2);PassesGate 扩展注册表(registerExtension/unregisterExtension/getExtensionNames/runAllTests/checkAllPasses + PassesGateExtension/ExtensionTestResult 两类型与包根导出)已整段删除——零 adapter 假想 seam 且扩展结果本就不参与 allowed 判定,需要扩展测试类型时按 ADR-0014 判例在 `judgeTestRun` 层加,不恢复旧 seam(harness#104,架构评审 B1);包内模块,不进 `src/index.ts` 导出面
|
|
11
13
|
- `session/` — 会话管理
|
|
12
14
|
- `spec/validator` — SpecValidator
|
|
13
|
-
- `project-config-loader` — 项目配置加载 + 约束合并(mergeConstraints 内含 preset 裁剪:presets/ 纯数据 + 未知名回落 standard,禁用到未知 id 经 effective-set 共享筛选器 collect
|
|
15
|
+
- `project-config-loader` — 项目配置加载 + 约束合并(mergeConstraints 内含 preset 裁剪:presets/ 纯数据 + 未知名回落 standard,禁用到未知 id 经 effective-set 共享筛选器 collect 模式);`getGovernanceConfig` 是全仓唯一允许手写钻取 `config.governance` 的点(工单 84),消费方一律经它或经 `resolveContextFiles`(三态:unconfigured / enabled-empty / enabled,dirs 元素类型在此收口)取数据,不得再自己 cast `Record<string, unknown>`;checker 对前两态一律 skip,自动探测回落只属于 init/扫描类工具流调用方
|
|
14
16
|
|
|
15
17
|
## 依赖关系
|
|
16
18
|
- 被所有模块依赖(基础层,无上层依赖)
|
|
17
19
|
- 依赖 `src/types/` 类型定义
|
|
18
20
|
- 依赖 `src/utils/` 工具函数
|
|
19
|
-
-
|
|
21
|
+
- 对 `cli/`、`gates/`、`monitoring/` **零值导入**(type-only 允许):方向由 eslint.config.mjs 的 `@typescript-eslint/no-restricted-imports`(error 级)锁死,守卫测试见 `src/__tests__/layering.test.ts`(harness#88)
|
|
20
22
|
|
|
21
23
|
## 约定
|
|
22
24
|
- 约束定义在 `constraints/definitions/{iron-laws,guidelines,prompts}.ts`,不在运行时代码中定义
|
|
23
25
|
- check 层必须带真实 checker(注册表闭环,引用未注册 checker 构建报错)
|
|
24
26
|
- Iron Law 违规必须 throw ConstraintViolationError
|
|
25
|
-
-
|
|
27
|
+
- 上行数据一律注入,不在 core 内 require 上层(harness#88):trace 记录器经 `ConstraintChecker` 构造参数注入(缺省 no-op,`getInstance()`/`constraintChecker` 即未接线的默认实例,只评估不写 trace),真实收集器由组合根接线(CLI check/report、`bootstrapHarness`);CAPABILITIES.md 能力清单计数经 `capabilities-parser` 的 `CapabilityDefinitionSource` 由 cli 侧注入定义表
|
|
28
|
+
- git 事实只能经 `constraints/git-evidence.ts` 的 adapter 取(#87):core/cli 内不得出现 `execSync('git …')`;一次 run 一份实例、沿调用链显式传递(CLI check → buildConstraintContext → checkConstraints),memo 既不做成模块级全局也不做成单例字段
|
|
26
29
|
|
|
27
30
|
## 注意事项
|
|
28
31
|
- 零 Token 成本:所有分析纯文件操作,无 LLM 调用
|
|
29
32
|
- 约束配置支持 .harness/config.yml 自定义合并(preset 真实生效)
|
|
30
|
-
- 存在性探测约束(capability_sync/docs_freshness/context_doc_sync
|
|
33
|
+
- 存在性探测约束(capability_sync/docs_freshness/context_doc_sync)在约定文件缺失,或 context_files 约定已立但无目标(enabled-empty)时 skip,不计 pass/fail;context_doc_sync 与 docs_freshness 对三态判定同构(工单 84)
|