@dommaker/harness 1.3.0 → 1.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +20 -0
- package/README.md +0 -2
- package/bin/harness.js +86 -32
- package/dist/cli/command-contract.d.ts +83 -0
- package/dist/cli/command-contract.d.ts.map +1 -0
- package/dist/cli/command-contract.js +66 -0
- package/dist/cli/command-contract.js.map +1 -0
- package/dist/cli/commands/acceptance.d.ts +3 -2
- package/dist/cli/commands/acceptance.d.ts.map +1 -1
- package/dist/cli/commands/acceptance.js +28 -24
- package/dist/cli/commands/acceptance.js.map +1 -1
- package/dist/cli/commands/analyze-sessions.d.ts +2 -1
- package/dist/cli/commands/analyze-sessions.d.ts.map +1 -1
- package/dist/cli/commands/analyze-sessions.js +25 -24
- package/dist/cli/commands/analyze-sessions.js.map +1 -1
- package/dist/cli/commands/check.d.ts +14 -2
- package/dist/cli/commands/check.d.ts.map +1 -1
- package/dist/cli/commands/check.js +104 -61
- package/dist/cli/commands/check.js.map +1 -1
- package/dist/cli/commands/command.d.ts +5 -1
- package/dist/cli/commands/command.d.ts.map +1 -1
- package/dist/cli/commands/command.js +26 -17
- package/dist/cli/commands/command.js.map +1 -1
- package/dist/cli/commands/constraints-report.d.ts +2 -1
- package/dist/cli/commands/constraints-report.d.ts.map +1 -1
- package/dist/cli/commands/constraints-report.js +37 -33
- package/dist/cli/commands/constraints-report.js.map +1 -1
- package/dist/cli/commands/constraints-retire.d.ts +6 -5
- package/dist/cli/commands/constraints-retire.d.ts.map +1 -1
- package/dist/cli/commands/constraints-retire.js +50 -52
- package/dist/cli/commands/constraints-retire.js.map +1 -1
- package/dist/cli/commands/constraints.d.ts +2 -1
- package/dist/cli/commands/constraints.d.ts.map +1 -1
- package/dist/cli/commands/constraints.js +10 -27
- package/dist/cli/commands/constraints.js.map +1 -1
- package/dist/cli/commands/contract.d.ts +3 -2
- package/dist/cli/commands/contract.d.ts.map +1 -1
- package/dist/cli/commands/contract.js +45 -42
- package/dist/cli/commands/contract.js.map +1 -1
- package/dist/cli/commands/definitions.d.ts +11 -11
- package/dist/cli/commands/definitions.d.ts.map +1 -1
- package/dist/cli/commands/definitions.js +27 -219
- package/dist/cli/commands/definitions.js.map +1 -1
- package/dist/cli/commands/failure.d.ts +5 -4
- package/dist/cli/commands/failure.d.ts.map +1 -1
- package/dist/cli/commands/failure.js +31 -25
- package/dist/cli/commands/failure.js.map +1 -1
- package/dist/cli/commands/init.d.ts +7 -5
- package/dist/cli/commands/init.d.ts.map +1 -1
- package/dist/cli/commands/init.js +147 -211
- package/dist/cli/commands/init.js.map +1 -1
- package/dist/cli/commands/knowledge.d.ts +17 -30
- package/dist/cli/commands/knowledge.d.ts.map +1 -1
- package/dist/cli/commands/knowledge.js +183 -273
- package/dist/cli/commands/knowledge.js.map +1 -1
- package/dist/cli/commands/passes-gate.d.ts +8 -2
- package/dist/cli/commands/passes-gate.d.ts.map +1 -1
- package/dist/cli/commands/passes-gate.js +44 -66
- package/dist/cli/commands/passes-gate.js.map +1 -1
- package/dist/cli/commands/performance.d.ts +2 -1
- package/dist/cli/commands/performance.d.ts.map +1 -1
- package/dist/cli/commands/performance.js +20 -18
- package/dist/cli/commands/performance.js.map +1 -1
- package/dist/cli/commands/posteval-plan.d.ts +5 -1
- package/dist/cli/commands/posteval-plan.d.ts.map +1 -1
- package/dist/cli/commands/posteval-plan.js +26 -15
- package/dist/cli/commands/posteval-plan.js.map +1 -1
- package/dist/cli/commands/release.d.ts +6 -1
- package/dist/cli/commands/release.d.ts.map +1 -1
- package/dist/cli/commands/release.js +69 -59
- package/dist/cli/commands/release.js.map +1 -1
- package/dist/cli/commands/report.d.ts +2 -1
- package/dist/cli/commands/report.d.ts.map +1 -1
- package/dist/cli/commands/report.js +9 -5
- package/dist/cli/commands/report.js.map +1 -1
- package/dist/cli/commands/review.d.ts +3 -2
- package/dist/cli/commands/review.d.ts.map +1 -1
- package/dist/cli/commands/review.js +33 -29
- package/dist/cli/commands/review.js.map +1 -1
- package/dist/cli/commands/sdd.d.ts +2 -1
- package/dist/cli/commands/sdd.d.ts.map +1 -1
- package/dist/cli/commands/sdd.js +7 -5
- package/dist/cli/commands/sdd.js.map +1 -1
- package/dist/cli/commands/security.d.ts +3 -2
- package/dist/cli/commands/security.d.ts.map +1 -1
- package/dist/cli/commands/security.js +29 -26
- package/dist/cli/commands/security.js.map +1 -1
- package/dist/cli/commands/spec-baseline-check.d.ts +2 -1
- package/dist/cli/commands/spec-baseline-check.d.ts.map +1 -1
- package/dist/cli/commands/spec-baseline-check.js +15 -11
- package/dist/cli/commands/spec-baseline-check.js.map +1 -1
- package/dist/cli/commands/spec.d.ts +7 -2
- package/dist/cli/commands/spec.d.ts.map +1 -1
- package/dist/cli/commands/spec.js +61 -51
- package/dist/cli/commands/spec.js.map +1 -1
- package/dist/cli/commands/status.d.ts +2 -1
- package/dist/cli/commands/status.d.ts.map +1 -1
- package/dist/cli/commands/status.js +57 -53
- package/dist/cli/commands/status.js.map +1 -1
- package/dist/cli/commands/sync-docs/agents-syncer.d.ts.map +1 -1
- package/dist/cli/commands/sync-docs/agents-syncer.js +5 -2
- package/dist/cli/commands/sync-docs/agents-syncer.js.map +1 -1
- package/dist/cli/commands/sync-docs/context-syncer.d.ts.map +1 -1
- package/dist/cli/commands/sync-docs/context-syncer.js +3 -2
- package/dist/cli/commands/sync-docs/context-syncer.js.map +1 -1
- package/dist/cli/commands/sync-docs/index.d.ts +2 -1
- package/dist/cli/commands/sync-docs/index.d.ts.map +1 -1
- package/dist/cli/commands/sync-docs/index.js +68 -88
- package/dist/cli/commands/sync-docs/index.js.map +1 -1
- package/dist/cli/commands/sync-docs/project-reader.d.ts +6 -1
- package/dist/cli/commands/sync-docs/project-reader.d.ts.map +1 -1
- package/dist/cli/commands/sync-docs/project-reader.js +14 -16
- package/dist/cli/commands/sync-docs/project-reader.js.map +1 -1
- package/dist/cli/commands/update-user-model.d.ts +9 -3
- package/dist/cli/commands/update-user-model.d.ts.map +1 -1
- package/dist/cli/commands/update-user-model.js +56 -61
- package/dist/cli/commands/update-user-model.js.map +1 -1
- package/dist/cli/commands/validate.d.ts +4 -3
- package/dist/cli/commands/validate.d.ts.map +1 -1
- package/dist/cli/commands/validate.js +28 -26
- package/dist/cli/commands/validate.js.map +1 -1
- package/dist/cli/session-mining/transcript.d.ts +7 -1
- package/dist/cli/session-mining/transcript.d.ts.map +1 -1
- package/dist/cli/session-mining/transcript.js +21 -14
- package/dist/cli/session-mining/transcript.js.map +1 -1
- package/dist/context/session-manager.d.ts.map +1 -1
- package/dist/context/session-manager.js +19 -32
- package/dist/context/session-manager.js.map +1 -1
- package/dist/core/constraints/agent-prompt-renderer.d.ts.map +1 -1
- package/dist/core/constraints/agent-prompt-renderer.js +1 -4
- package/dist/core/constraints/agent-prompt-renderer.js.map +1 -1
- package/dist/core/constraints/capabilities-parser.d.ts +24 -7
- package/dist/core/constraints/capabilities-parser.d.ts.map +1 -1
- package/dist/core/constraints/capabilities-parser.js +32 -28
- package/dist/core/constraints/capabilities-parser.js.map +1 -1
- package/dist/core/constraints/capabilities-reconcile.d.ts +67 -0
- package/dist/core/constraints/capabilities-reconcile.d.ts.map +1 -0
- package/dist/core/constraints/capabilities-reconcile.js +105 -0
- package/dist/core/constraints/capabilities-reconcile.js.map +1 -0
- package/dist/core/constraints/checker.d.ts +21 -43
- package/dist/core/constraints/checker.d.ts.map +1 -1
- package/dist/core/constraints/checker.js +68 -117
- package/dist/core/constraints/checker.js.map +1 -1
- package/dist/core/constraints/checkers/capability-sync.d.ts +20 -8
- package/dist/core/constraints/checkers/capability-sync.d.ts.map +1 -1
- package/dist/core/constraints/checkers/capability-sync.js +66 -77
- package/dist/core/constraints/checkers/capability-sync.js.map +1 -1
- package/dist/core/constraints/checkers/context-doc-sync.d.ts +4 -2
- package/dist/core/constraints/checkers/context-doc-sync.d.ts.map +1 -1
- package/dist/core/constraints/checkers/context-doc-sync.js +13 -22
- package/dist/core/constraints/checkers/context-doc-sync.js.map +1 -1
- package/dist/core/constraints/checkers/docs-freshness.d.ts.map +1 -1
- package/dist/core/constraints/checkers/docs-freshness.js +49 -66
- package/dist/core/constraints/checkers/docs-freshness.js.map +1 -1
- package/dist/core/constraints/checkers/governance-presence.d.ts +2 -2
- package/dist/core/constraints/checkers/governance-presence.d.ts.map +1 -1
- package/dist/core/constraints/checkers/governance-presence.js +7 -28
- package/dist/core/constraints/checkers/governance-presence.js.map +1 -1
- package/dist/core/constraints/checkers/index.d.ts +2 -2
- package/dist/core/constraints/checkers/index.d.ts.map +1 -1
- package/dist/core/constraints/checkers/index.js +2 -1
- package/dist/core/constraints/checkers/index.js.map +1 -1
- package/dist/core/constraints/checkers/no-test-simplification.d.ts.map +1 -1
- package/dist/core/constraints/checkers/no-test-simplification.js +4 -3
- package/dist/core/constraints/checkers/no-test-simplification.js.map +1 -1
- package/dist/core/constraints/checkers/types.d.ts +43 -4
- package/dist/core/constraints/checkers/types.d.ts.map +1 -1
- package/dist/core/constraints/checkers/types.js +33 -0
- package/dist/core/constraints/checkers/types.js.map +1 -1
- package/dist/core/constraints/context-builder.d.ts +15 -14
- package/dist/core/constraints/context-builder.d.ts.map +1 -1
- package/dist/core/constraints/context-builder.js +32 -96
- package/dist/core/constraints/context-builder.js.map +1 -1
- package/dist/core/constraints/doc-freshness/runner.d.ts.map +1 -1
- package/dist/core/constraints/doc-freshness/runner.js +2 -1
- package/dist/core/constraints/doc-freshness/runner.js.map +1 -1
- package/dist/core/constraints/git-evidence.d.ts +60 -0
- package/dist/core/constraints/git-evidence.d.ts.map +1 -0
- package/dist/core/constraints/git-evidence.js +88 -0
- package/dist/core/constraints/git-evidence.js.map +1 -0
- package/dist/core/constraints/injection-drift.d.ts +3 -20
- package/dist/core/constraints/injection-drift.d.ts.map +1 -1
- package/dist/core/constraints/injection-drift.js +10 -57
- package/dist/core/constraints/injection-drift.js.map +1 -1
- package/dist/core/constraints/injection-writer.d.ts +113 -0
- package/dist/core/constraints/injection-writer.d.ts.map +1 -0
- package/dist/core/constraints/injection-writer.js +228 -0
- package/dist/core/constraints/injection-writer.js.map +1 -0
- package/dist/core/constraints/usage-report.d.ts +22 -1
- package/dist/core/constraints/usage-report.d.ts.map +1 -1
- package/dist/core/constraints/usage-report.js +27 -20
- package/dist/core/constraints/usage-report.js.map +1 -1
- package/dist/core/index.d.ts +2 -2
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +4 -2
- package/dist/core/index.js.map +1 -1
- package/dist/core/project-config-loader.d.ts +32 -1
- package/dist/core/project-config-loader.d.ts.map +1 -1
- package/dist/core/project-config-loader.js +39 -9
- package/dist/core/project-config-loader.js.map +1 -1
- package/dist/core/validators/passes-gate.d.ts +15 -64
- package/dist/core/validators/passes-gate.d.ts.map +1 -1
- package/dist/core/validators/passes-gate.js +84 -222
- package/dist/core/validators/passes-gate.js.map +1 -1
- package/dist/core/validators/test-output.d.ts +58 -0
- package/dist/core/validators/test-output.d.ts.map +1 -0
- package/dist/core/validators/test-output.js +109 -0
- package/dist/core/validators/test-output.js.map +1 -0
- package/dist/failure/recorder.d.ts +6 -0
- package/dist/failure/recorder.d.ts.map +1 -1
- package/dist/failure/recorder.js +12 -8
- package/dist/failure/recorder.js.map +1 -1
- package/dist/gates/acceptance.d.ts +1 -48
- package/dist/gates/acceptance.d.ts.map +1 -1
- package/dist/gates/acceptance.js +6 -38
- package/dist/gates/acceptance.js.map +1 -1
- package/dist/gates/checker-gate.d.ts +2 -1
- package/dist/gates/checker-gate.d.ts.map +1 -1
- package/dist/gates/checker-gate.js +11 -13
- package/dist/gates/checker-gate.js.map +1 -1
- package/dist/gates/command.d.ts.map +1 -1
- package/dist/gates/command.js +10 -22
- package/dist/gates/command.js.map +1 -1
- package/dist/gates/contract.d.ts.map +1 -1
- package/dist/gates/contract.js +22 -61
- package/dist/gates/contract.js.map +1 -1
- package/dist/gates/performance.d.ts.map +1 -1
- package/dist/gates/performance.js +13 -31
- package/dist/gates/performance.js.map +1 -1
- package/dist/gates/review.d.ts.map +1 -1
- package/dist/gates/review.js +21 -53
- package/dist/gates/review.js.map +1 -1
- package/dist/gates/security.d.ts.map +1 -1
- package/dist/gates/security.js +14 -32
- package/dist/gates/security.js.map +1 -1
- package/dist/gates/types.d.ts +28 -5
- package/dist/gates/types.d.ts.map +1 -1
- package/dist/gates/types.js +38 -1
- package/dist/gates/types.js.map +1 -1
- package/dist/hooks/bootstrap.d.ts +2 -0
- package/dist/hooks/bootstrap.d.ts.map +1 -1
- package/dist/hooks/bootstrap.js +5 -2
- package/dist/hooks/bootstrap.js.map +1 -1
- package/dist/index.d.ts +1 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/knowledge/audit.d.ts +7 -2
- package/dist/knowledge/audit.d.ts.map +1 -1
- package/dist/knowledge/audit.js +59 -79
- package/dist/knowledge/audit.js.map +1 -1
- package/dist/knowledge/flywheel-metrics.d.ts +39 -0
- package/dist/knowledge/flywheel-metrics.d.ts.map +1 -0
- package/dist/knowledge/flywheel-metrics.js +47 -0
- package/dist/knowledge/flywheel-metrics.js.map +1 -0
- package/dist/knowledge/import.d.ts.map +1 -1
- package/dist/knowledge/import.js +4 -14
- package/dist/knowledge/import.js.map +1 -1
- package/dist/knowledge/index-generator.d.ts.map +1 -1
- package/dist/knowledge/index-generator.js +17 -14
- package/dist/knowledge/index-generator.js.map +1 -1
- package/dist/knowledge/ingest.d.ts.map +1 -1
- package/dist/knowledge/ingest.js +9 -4
- package/dist/knowledge/ingest.js.map +1 -1
- package/dist/knowledge/migration.d.ts.map +1 -1
- package/dist/knowledge/migration.js +11 -8
- package/dist/knowledge/migration.js.map +1 -1
- package/dist/knowledge/reference-tracker.d.ts.map +1 -1
- package/dist/knowledge/reference-tracker.js +12 -9
- package/dist/knowledge/reference-tracker.js.map +1 -1
- package/dist/knowledge/store.d.ts +15 -0
- package/dist/knowledge/store.d.ts.map +1 -1
- package/dist/knowledge/store.js +59 -10
- package/dist/knowledge/store.js.map +1 -1
- package/dist/monitoring/context-tracker.d.ts.map +1 -1
- package/dist/monitoring/context-tracker.js +11 -20
- package/dist/monitoring/context-tracker.js.map +1 -1
- package/dist/monitoring/index.d.ts +1 -1
- package/dist/monitoring/index.d.ts.map +1 -1
- package/dist/monitoring/index.js +1 -2
- package/dist/monitoring/index.js.map +1 -1
- package/dist/monitoring/trace-analyzer.d.ts +15 -0
- package/dist/monitoring/trace-analyzer.d.ts.map +1 -1
- package/dist/monitoring/trace-analyzer.js +19 -2
- package/dist/monitoring/trace-analyzer.js.map +1 -1
- package/dist/monitoring/traces.d.ts +21 -2
- package/dist/monitoring/traces.d.ts.map +1 -1
- package/dist/monitoring/traces.js +38 -29
- package/dist/monitoring/traces.js.map +1 -1
- package/dist/release/index.d.ts +2 -2
- package/dist/release/index.d.ts.map +1 -1
- package/dist/release/index.js +1 -5
- package/dist/release/index.js.map +1 -1
- package/dist/sdd/index-generator.js +10 -11
- package/dist/sdd/index-generator.js.map +1 -1
- package/dist/test-setup/project-fixture.d.ts +48 -0
- package/dist/test-setup/project-fixture.d.ts.map +1 -0
- package/dist/test-setup/project-fixture.js +106 -0
- package/dist/test-setup/project-fixture.js.map +1 -0
- package/dist/types/constraint.d.ts +8 -18
- package/dist/types/constraint.d.ts.map +1 -1
- package/dist/types/constraint.js +6 -1
- package/dist/types/constraint.js.map +1 -1
- package/dist/types/passes-gate.d.ts +10 -25
- package/dist/types/passes-gate.d.ts.map +1 -1
- package/dist/types/project-config.d.ts +1 -1
- package/dist/types/session.d.ts +6 -5
- package/dist/types/session.d.ts.map +1 -1
- package/dist/types/trace.d.ts +9 -0
- package/dist/types/trace.d.ts.map +1 -1
- package/dist/utils/exec.d.ts +10 -0
- package/dist/utils/exec.d.ts.map +1 -1
- package/dist/utils/exec.js +12 -0
- package/dist/utils/exec.js.map +1 -1
- package/dist/utils/file-walk.d.ts +9 -1
- package/dist/utils/file-walk.d.ts.map +1 -1
- package/dist/utils/file-walk.js +10 -1
- package/dist/utils/file-walk.js.map +1 -1
- package/dist/utils/frontmatter.d.ts +73 -0
- package/dist/utils/frontmatter.d.ts.map +1 -0
- package/dist/utils/frontmatter.js +141 -0
- package/dist/utils/frontmatter.js.map +1 -0
- package/dist/utils/jsonl.d.ts +92 -0
- package/dist/utils/jsonl.d.ts.map +1 -0
- package/dist/utils/jsonl.js +166 -0
- package/dist/utils/jsonl.js.map +1 -0
- package/dist/utils/package-version.d.ts +16 -0
- package/dist/utils/package-version.d.ts.map +1 -0
- package/dist/utils/package-version.js +63 -0
- package/dist/utils/package-version.js.map +1 -0
- package/package.json +1 -1
- package/src/CONTEXT.md +8 -2
- package/src/__tests__/acceptance-gate.test.ts +3 -1
- package/src/__tests__/checker-extra.test.ts +7 -1218
- package/src/__tests__/context-files-resolution.test.ts +116 -0
- package/src/__tests__/effective-constraints.test.ts +10 -13
- package/src/__tests__/exec.test.ts +35 -1
- package/src/__tests__/layering.test.ts +152 -0
- package/src/__tests__/passes-gate-extra.test.ts +0 -145
- package/src/__tests__/passes-gate.test.ts +130 -101
- package/src/__tests__/skip-semantics.test.ts +5 -9
- package/src/cli/__tests__/command-contract.test.ts +170 -0
- package/src/cli/command-contract.ts +108 -0
- package/src/cli/commands/CONTEXT.md +23 -8
- package/src/cli/commands/__tests__/acceptance.test.ts +40 -33
- package/src/cli/commands/__tests__/analyze-sessions.test.ts +35 -29
- package/src/cli/commands/__tests__/bin-exit-mapping.test.ts +107 -0
- package/src/cli/commands/__tests__/check-drift.test.ts +27 -34
- package/src/cli/commands/__tests__/check-skip-output.test.ts +21 -24
- package/src/cli/commands/__tests__/check.test.ts +448 -378
- package/src/cli/commands/__tests__/command.test.ts +85 -70
- package/src/cli/commands/__tests__/constraints-report.test.ts +100 -71
- package/src/cli/commands/__tests__/constraints-retire.test.ts +152 -95
- package/src/cli/commands/__tests__/contract.test.ts +27 -34
- package/src/cli/commands/__tests__/failure.test.ts +31 -34
- package/src/cli/commands/__tests__/init-injection.test.ts +58 -28
- package/src/cli/commands/__tests__/init.test.ts +77 -48
- package/src/cli/commands/__tests__/knowledge-flywheel-consistency.test.ts +108 -0
- package/src/cli/commands/__tests__/knowledge.test.ts +69 -43
- package/src/cli/commands/__tests__/passes-gate.test.ts +43 -45
- package/src/cli/commands/__tests__/performance.test.ts +22 -23
- package/src/cli/commands/__tests__/posteval-plan.test.ts +39 -38
- package/src/cli/commands/__tests__/project-path-anchoring.test.ts +157 -0
- package/src/cli/commands/__tests__/project-path-convention.test.ts +231 -0
- package/src/cli/commands/__tests__/registry.test.ts +75 -35
- package/src/cli/commands/__tests__/release.test.ts +209 -80
- package/src/cli/commands/__tests__/report-extra.test.ts +16 -16
- package/src/cli/commands/__tests__/report.test.ts +25 -25
- package/src/cli/commands/__tests__/review.test.ts +33 -31
- package/src/cli/commands/__tests__/security.test.ts +23 -27
- package/src/cli/commands/__tests__/spec-baseline-check.test.ts +20 -20
- package/src/cli/commands/__tests__/spec.test.ts +41 -29
- package/src/cli/commands/__tests__/status-extra.test.ts +18 -18
- package/src/cli/commands/__tests__/status-skipped-lines.test.ts +72 -0
- package/src/cli/commands/__tests__/status.test.ts +34 -34
- package/src/cli/commands/__tests__/sync-docs-agents.test.ts +77 -78
- package/src/cli/commands/__tests__/sync-docs.test.ts +72 -74
- package/src/cli/commands/__tests__/update-user-model.test.ts +97 -34
- package/src/cli/commands/__tests__/validate.test.ts +27 -29
- package/src/cli/commands/acceptance.ts +35 -24
- package/src/cli/commands/analyze-sessions.ts +25 -24
- package/src/cli/commands/check.ts +127 -66
- package/src/cli/commands/command.ts +30 -17
- package/src/cli/commands/constraints-report.ts +37 -34
- package/src/cli/commands/constraints-retire.ts +58 -55
- package/src/cli/commands/constraints.ts +10 -27
- package/src/cli/commands/contract.ts +51 -42
- package/src/cli/commands/definitions.ts +34 -227
- package/src/cli/commands/failure.ts +33 -26
- package/src/cli/commands/init.ts +166 -220
- package/src/cli/commands/knowledge.ts +192 -289
- package/src/cli/commands/passes-gate.ts +58 -68
- package/src/cli/commands/performance.ts +23 -18
- package/src/cli/commands/posteval-plan.ts +29 -15
- package/src/cli/commands/release.ts +70 -59
- package/src/cli/commands/report.ts +9 -5
- package/src/cli/commands/review.ts +39 -29
- package/src/cli/commands/sdd.ts +7 -5
- package/src/cli/commands/security.ts +35 -26
- package/src/cli/commands/spec-baseline-check.ts +16 -11
- package/src/cli/commands/spec.ts +66 -53
- package/src/cli/commands/status.ts +59 -53
- package/src/cli/commands/sync-docs/agents-syncer.ts +5 -2
- package/src/cli/commands/sync-docs/context-syncer.ts +3 -2
- package/src/cli/commands/sync-docs/index.ts +73 -100
- package/src/cli/commands/sync-docs/project-reader.ts +17 -18
- package/src/cli/commands/update-user-model.ts +64 -61
- package/src/cli/commands/validate.ts +31 -25
- package/src/cli/session-mining/__tests__/transcript.test.ts +118 -0
- package/src/cli/session-mining/transcript.ts +26 -8
- package/src/context/session-manager.ts +19 -33
- package/src/core/CONTEXT.md +10 -6
- package/src/core/constraints/__tests__/capabilities-reconcile.test.ts +200 -0
- package/src/core/constraints/__tests__/capability-counts.test.ts +94 -0
- package/src/core/constraints/__tests__/git-evidence.test.ts +208 -0
- package/src/core/constraints/__tests__/injection-drift.test.ts +3 -10
- package/src/core/constraints/__tests__/injection-writer.test.ts +231 -0
- package/src/core/constraints/__tests__/trace-injection.test.ts +71 -0
- package/src/core/constraints/__tests__/usage-report.test.ts +112 -0
- package/src/core/constraints/agent-prompt-renderer.ts +2 -6
- package/src/core/constraints/capabilities-parser.ts +53 -35
- package/src/core/constraints/capabilities-reconcile.ts +166 -0
- package/src/core/constraints/checker.ts +82 -133
- package/src/core/constraints/checkers/__tests__/capability-sync.test.ts +273 -0
- package/src/core/constraints/checkers/__tests__/check-outcome.test.ts +176 -0
- package/src/core/constraints/checkers/__tests__/context-doc-sync.test.ts +77 -0
- package/src/core/constraints/checkers/__tests__/docs-freshness.test.ts +126 -0
- package/src/{__tests__ → core/constraints/checkers/__tests__}/governance-presence.test.ts +83 -9
- package/src/core/constraints/checkers/__tests__/iron-flags.test.ts +50 -0
- package/src/core/constraints/checkers/__tests__/no-bypass-checkpoint.test.ts +76 -0
- package/src/{__tests__ → core/constraints/checkers/__tests__}/no-hardcoded-credentials.test.ts +4 -3
- package/src/core/constraints/checkers/__tests__/no-test-simplification.test.ts +58 -0
- package/src/core/constraints/checkers/__tests__/three-state-consistency.test.ts +153 -0
- package/src/core/constraints/checkers/capability-sync.ts +75 -96
- package/src/core/constraints/checkers/context-doc-sync.ts +15 -25
- package/src/core/constraints/checkers/docs-freshness.ts +54 -70
- package/src/core/constraints/checkers/governance-presence.ts +7 -25
- package/src/core/constraints/checkers/index.ts +9 -2
- package/src/core/constraints/checkers/no-test-simplification.ts +4 -3
- package/src/core/constraints/checkers/types.ts +60 -4
- package/src/core/constraints/context-builder.ts +39 -91
- package/src/core/constraints/doc-freshness/runner.ts +2 -1
- package/src/core/constraints/git-evidence.ts +120 -0
- package/src/core/constraints/injection-drift.ts +13 -60
- package/src/core/constraints/injection-writer.ts +212 -0
- package/src/core/constraints/usage-report.ts +36 -17
- package/src/core/index.ts +4 -2
- package/src/core/project-config-loader.ts +49 -9
- package/src/core/validators/__tests__/passes-gate.test.ts +2 -56
- package/src/core/validators/__tests__/test-output.test.ts +372 -0
- package/src/core/validators/passes-gate.ts +86 -248
- package/src/core/validators/test-output.ts +128 -0
- package/src/failure/__tests__/recorder.test.ts +168 -0
- package/src/failure/recorder.ts +12 -10
- package/src/gates/CONTEXT.md +7 -4
- package/src/gates/__tests__/acceptance-types-single-source.test.ts +68 -0
- package/src/gates/__tests__/acceptance.test.ts +4 -86
- package/src/gates/__tests__/checker-gate.test.ts +24 -0
- package/src/gates/__tests__/effective-gates.test.ts +3 -8
- package/src/gates/__tests__/test-verdict-consistency.test.ts +140 -0
- package/src/gates/acceptance.ts +19 -84
- package/src/gates/checker-gate.ts +12 -15
- package/src/gates/command.ts +10 -16
- package/src/gates/contract.ts +22 -61
- package/src/gates/performance.ts +10 -22
- package/src/gates/review.ts +21 -41
- package/src/gates/security.ts +10 -22
- package/src/gates/types.ts +70 -5
- package/src/hooks/CONTEXT.md +1 -1
- package/src/hooks/bootstrap.ts +5 -2
- package/src/index.ts +0 -4
- package/src/knowledge/CONTEXT.md +8 -3
- package/src/knowledge/__tests__/audit-labels.test.ts +44 -0
- package/src/knowledge/__tests__/flywheel-metrics.test.ts +135 -0
- package/src/knowledge/__tests__/import.test.ts +44 -0
- package/src/knowledge/__tests__/index-generator.test.ts +53 -0
- package/src/knowledge/__tests__/ingest.test.ts +85 -0
- package/src/knowledge/__tests__/migration.test.ts +47 -0
- package/src/knowledge/__tests__/reference-tracker.test.ts +16 -0
- package/src/knowledge/__tests__/store.test.ts +194 -0
- package/src/knowledge/audit.ts +67 -71
- package/src/knowledge/flywheel-metrics.ts +71 -0
- package/src/knowledge/import.ts +4 -18
- package/src/knowledge/index-generator.ts +19 -14
- package/src/knowledge/ingest.ts +9 -4
- package/src/knowledge/migration.ts +11 -8
- package/src/knowledge/reference-tracker.ts +12 -8
- package/src/knowledge/store.ts +64 -11
- package/src/monitoring/CONTEXT.md +8 -3
- package/src/monitoring/__tests__/skipped-lines-report.test.ts +178 -0
- package/src/monitoring/__tests__/traces.test.ts +57 -0
- package/src/monitoring/context-tracker.ts +11 -23
- package/src/monitoring/index.ts +1 -1
- package/src/monitoring/trace-analyzer.ts +21 -2
- package/src/monitoring/traces.ts +39 -36
- package/src/release/CONTEXT.md +1 -0
- package/src/release/__tests__/barrel.test.ts +60 -0
- package/src/release/index.ts +2 -13
- package/src/sdd/__tests__/index-generator.test.ts +71 -0
- package/src/sdd/index-generator.ts +9 -9
- package/src/test-setup/__tests__/project-fixture.test.ts +178 -0
- package/src/test-setup/project-fixture.ts +87 -0
- package/src/tools/CONTEXT.md +6 -0
- package/src/tools/__tests__/registry.test.ts +221 -0
- package/src/types/__tests__/types.test.ts +4 -5
- package/src/types/constraint.ts +16 -27
- package/src/types/passes-gate.ts +10 -30
- package/src/types/project-config.ts +1 -1
- package/src/types/session.ts +5 -5
- package/src/types/trace.ts +10 -0
- package/src/utils/__tests__/frontmatter.test.ts +206 -0
- package/src/utils/__tests__/jsonl-skip-disposition.test.ts +175 -0
- package/src/utils/__tests__/jsonl.test.ts +187 -0
- package/src/utils/__tests__/package-version.test.ts +97 -0
- package/src/utils/exec.ts +15 -0
- package/src/utils/file-walk.ts +11 -2
- package/src/utils/frontmatter.ts +121 -0
- package/src/utils/jsonl.ts +167 -0
- package/src/utils/package-version.ts +27 -0
- package/dist/cli/commands/doc-freshness-check.d.ts +0 -53
- package/dist/cli/commands/doc-freshness-check.d.ts.map +0 -1
- package/dist/cli/commands/doc-freshness-check.js +0 -352
- package/dist/cli/commands/doc-freshness-check.js.map +0 -1
- package/dist/types/index.d.ts +0 -14
- package/dist/types/index.d.ts.map +0 -1
- package/dist/types/index.js +0 -39
- package/dist/types/index.js.map +0 -1
- package/src/__tests__/long-running.test.ts +0 -17
- package/src/__tests__/passes-gate-extension.test.ts +0 -151
- package/src/cli/commands/__tests__/doc-freshness-check.test.ts +0 -168
- package/src/cli/commands/doc-freshness-check.ts +0 -386
- package/src/spec/CONTEXT.md +0 -11
- package/src/types/index.ts +0 -47
package/src/knowledge/audit.ts
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* 知识库质量审计引擎
|
|
3
3
|
*
|
|
4
4
|
* 纯代码检测,零 token 成本。
|
|
5
|
-
*
|
|
5
|
+
* 7 维度覆盖:结构完整性 / 内容质量 / 去重有效性 / 成熟度健康 / 新鲜度 / 飞轮验证 / 增量存活
|
|
6
6
|
*
|
|
7
7
|
* 两种模式:
|
|
8
8
|
* - validate(entry): 单条入库检查(ingest gate)
|
|
@@ -13,6 +13,7 @@ import * as fs from 'fs';
|
|
|
13
13
|
import * as path from 'path';
|
|
14
14
|
import { FileKnowledgeStore } from './store';
|
|
15
15
|
import type { KnowledgeStore } from './store';
|
|
16
|
+
import { evaluateFlywheel, genuineRefs } from './flywheel-metrics';
|
|
16
17
|
import type { KnowledgeEntry } from './types';
|
|
17
18
|
|
|
18
19
|
// ── Types ─────────────────────────────────────────────────
|
|
@@ -99,22 +100,22 @@ const EVENT_NOISE_PATTERNS = [
|
|
|
99
100
|
/^\[Session Feature\]\s/,
|
|
100
101
|
];
|
|
101
102
|
const REQUIRED_FRONTMATTER = ['id', 'type', 'title', 'maturity'];
|
|
102
|
-
const SYNTHETIC_REF_PATTERN = /^(search|test-agent|prompt-inject|monitor|analyst|auditor|triage|executor|session|trend|incident):\d{4}-\d{2}-\d{2}/;
|
|
103
|
-
|
|
104
|
-
/** Filter out synthetic references (automated search/ops records, not genuine consumption) */
|
|
105
|
-
function genuineRefs(refs: string[]): string[] {
|
|
106
|
-
return refs.filter(r => !SYNTHETIC_REF_PATTERN.test(r));
|
|
107
|
-
}
|
|
108
103
|
|
|
109
104
|
// ── Per-Entry Rules ───────────────────────────────────────
|
|
110
105
|
|
|
111
106
|
interface AuditRule {
|
|
112
107
|
name: AuditRuleName;
|
|
108
|
+
/** 中文展示文案正本(#109):定义即注册,CLI 经 AUDIT_RULE_LABELS 消费,无 label 即编译期失败 */
|
|
109
|
+
label: string;
|
|
113
110
|
severity: AuditIssue['severity'];
|
|
114
111
|
action: AuditAction;
|
|
112
|
+
/** 规则适用人口:active = 跳过 archived 条目;all = 全人口(含已归档) */
|
|
113
|
+
scope: AuditRuleScope;
|
|
115
114
|
detect: (entry: KnowledgeEntry, ctx: AuditContext) => string | null;
|
|
116
115
|
}
|
|
117
116
|
|
|
117
|
+
type AuditRuleScope = 'active' | 'all';
|
|
118
|
+
|
|
118
119
|
interface AuditContext {
|
|
119
120
|
shortContentThreshold: number;
|
|
120
121
|
staleDays: number;
|
|
@@ -126,8 +127,10 @@ const perEntryRules: AuditRule[] = [
|
|
|
126
127
|
// D1: 结构完整性
|
|
127
128
|
{
|
|
128
129
|
name: 'frontmatter-missing',
|
|
130
|
+
label: 'frontmatter 缺失',
|
|
129
131
|
severity: 'high',
|
|
130
132
|
action: 'reject',
|
|
133
|
+
scope: 'all',
|
|
131
134
|
detect: (entry) => {
|
|
132
135
|
const missing = REQUIRED_FRONTMATTER.filter(f => {
|
|
133
136
|
const val = (entry as any)[f];
|
|
@@ -143,10 +146,11 @@ const perEntryRules: AuditRule[] = [
|
|
|
143
146
|
// D2: 内容质量
|
|
144
147
|
{
|
|
145
148
|
name: 'test-data-pollution',
|
|
149
|
+
label: '测试数据污染',
|
|
146
150
|
severity: 'critical',
|
|
147
151
|
action: 'archive',
|
|
152
|
+
scope: 'active',
|
|
148
153
|
detect: (entry) => {
|
|
149
|
-
if (entry.maturity === 'archived') return null;
|
|
150
154
|
// Match test ID patterns
|
|
151
155
|
if (/^(test-|inj-test)/.test(entry.id)) {
|
|
152
156
|
return `测试 ID: "${entry.id}"`;
|
|
@@ -163,10 +167,11 @@ const perEntryRules: AuditRule[] = [
|
|
|
163
167
|
},
|
|
164
168
|
{
|
|
165
169
|
name: 'daily-audit-noise',
|
|
170
|
+
label: '每日审计噪音',
|
|
166
171
|
severity: 'high',
|
|
167
172
|
action: 'archive',
|
|
173
|
+
scope: 'active',
|
|
168
174
|
detect: (entry) => {
|
|
169
|
-
if (entry.maturity === 'archived') return null;
|
|
170
175
|
if (DAILY_AUDIT_PATTERN.test(entry.title)) {
|
|
171
176
|
return `每日审计摘要: "${entry.title}"`;
|
|
172
177
|
}
|
|
@@ -175,10 +180,11 @@ const perEntryRules: AuditRule[] = [
|
|
|
175
180
|
},
|
|
176
181
|
{
|
|
177
182
|
name: 'event-noise',
|
|
183
|
+
label: '运维事件噪音',
|
|
178
184
|
severity: 'critical',
|
|
179
185
|
action: 'archive',
|
|
186
|
+
scope: 'active',
|
|
180
187
|
detect: (entry) => {
|
|
181
|
-
if (entry.maturity === 'archived') return null;
|
|
182
188
|
for (const pattern of EVENT_NOISE_PATTERNS) {
|
|
183
189
|
if (pattern.test(entry.title)) {
|
|
184
190
|
return `运维事件标题: "${entry.title}"`;
|
|
@@ -189,8 +195,10 @@ const perEntryRules: AuditRule[] = [
|
|
|
189
195
|
},
|
|
190
196
|
{
|
|
191
197
|
name: 'zero-content-proven',
|
|
198
|
+
label: '零内容 proven',
|
|
192
199
|
severity: 'critical',
|
|
193
200
|
action: 'demote',
|
|
201
|
+
scope: 'all',
|
|
194
202
|
detect: (entry) => {
|
|
195
203
|
if (entry.maturity === 'proven' && entry.content.trim().length < ZERO_CONTENT_THRESHOLD) {
|
|
196
204
|
return `proven 条目内容仅 ${entry.content.trim().length} 字符`;
|
|
@@ -200,8 +208,10 @@ const perEntryRules: AuditRule[] = [
|
|
|
200
208
|
},
|
|
201
209
|
{
|
|
202
210
|
name: 'maturity-inflation',
|
|
211
|
+
label: '成熟度虚高',
|
|
203
212
|
severity: 'high',
|
|
204
213
|
action: 'demote',
|
|
214
|
+
scope: 'all',
|
|
205
215
|
detect: (entry) => {
|
|
206
216
|
if (entry.maturity === 'verified' && entry.content.trim().length < ZERO_CONTENT_THRESHOLD) {
|
|
207
217
|
return `verified 条目内容仅 ${entry.content.trim().length} 字符`;
|
|
@@ -211,10 +221,11 @@ const perEntryRules: AuditRule[] = [
|
|
|
211
221
|
},
|
|
212
222
|
{
|
|
213
223
|
name: 'short-content',
|
|
224
|
+
label: '短内容',
|
|
214
225
|
severity: 'medium',
|
|
215
226
|
action: 'flag',
|
|
227
|
+
scope: 'active',
|
|
216
228
|
detect: (entry, ctx) => {
|
|
217
|
-
if (entry.maturity === 'archived') return null;
|
|
218
229
|
const len = entry.content.trim().length;
|
|
219
230
|
if (len < ctx.shortContentThreshold && len >= ZERO_CONTENT_THRESHOLD) {
|
|
220
231
|
return `内容 ${len} 字符 (阈值 ${ctx.shortContentThreshold})`;
|
|
@@ -226,10 +237,11 @@ const perEntryRules: AuditRule[] = [
|
|
|
226
237
|
// D3: 去重有效性
|
|
227
238
|
{
|
|
228
239
|
name: 'title-duplicate',
|
|
240
|
+
label: '标题重复',
|
|
229
241
|
severity: 'medium',
|
|
230
242
|
action: 'flag',
|
|
243
|
+
scope: 'active',
|
|
231
244
|
detect: (entry, ctx) => {
|
|
232
|
-
if (entry.maturity === 'archived') return null;
|
|
233
245
|
if (!ctx.allEntries) return null;
|
|
234
246
|
if (!entry.title) return null;
|
|
235
247
|
const dupes = ctx.allEntries.filter(e =>
|
|
@@ -246,8 +258,10 @@ const perEntryRules: AuditRule[] = [
|
|
|
246
258
|
},
|
|
247
259
|
{
|
|
248
260
|
name: 'source-refs-bloat',
|
|
261
|
+
label: 'sourceReferences 膨胀',
|
|
249
262
|
severity: 'low',
|
|
250
263
|
action: 'trim',
|
|
264
|
+
scope: 'all',
|
|
251
265
|
detect: (entry) => {
|
|
252
266
|
if ((entry.sourceReferences?.length || 0) > MAX_SOURCE_REFS) {
|
|
253
267
|
return `sourceReferences ${entry.sourceReferences!.length} 条 (上限 ${MAX_SOURCE_REFS})`;
|
|
@@ -257,10 +271,11 @@ const perEntryRules: AuditRule[] = [
|
|
|
257
271
|
},
|
|
258
272
|
{
|
|
259
273
|
name: 'fragment-cluster',
|
|
274
|
+
label: '碎片集群',
|
|
260
275
|
severity: 'medium',
|
|
261
276
|
action: 'flag',
|
|
277
|
+
scope: 'active',
|
|
262
278
|
detect: (entry, ctx) => {
|
|
263
|
-
if (entry.maturity === 'archived') return null;
|
|
264
279
|
if (!ctx.allEntries || entry.content.trim().length >= 100) return null;
|
|
265
280
|
if (!entry.tags?.length) return null;
|
|
266
281
|
|
|
@@ -284,8 +299,10 @@ const perEntryRules: AuditRule[] = [
|
|
|
284
299
|
// D4: 成熟度健康
|
|
285
300
|
{
|
|
286
301
|
name: 'promotion-blocked',
|
|
302
|
+
label: 'promotion 受阻',
|
|
287
303
|
severity: 'medium',
|
|
288
304
|
action: 'flag',
|
|
305
|
+
scope: 'all',
|
|
289
306
|
detect: (entry, ctx) => {
|
|
290
307
|
if (entry.maturity !== 'draft') return null;
|
|
291
308
|
const created = new Date(entry.created);
|
|
@@ -298,8 +315,10 @@ const perEntryRules: AuditRule[] = [
|
|
|
298
315
|
},
|
|
299
316
|
{
|
|
300
317
|
name: 'orphan-draft',
|
|
318
|
+
label: '孤儿 draft',
|
|
301
319
|
severity: 'low',
|
|
302
320
|
action: 'flag',
|
|
321
|
+
scope: 'all',
|
|
303
322
|
detect: (entry) => {
|
|
304
323
|
if (entry.maturity !== 'draft') return null;
|
|
305
324
|
if (entry.contributors.length === 0 && entry.projects.length === 0 && genuineRefs(entry.referencedBy).length === 0) {
|
|
@@ -312,10 +331,11 @@ const perEntryRules: AuditRule[] = [
|
|
|
312
331
|
// D5: 新鲜度
|
|
313
332
|
{
|
|
314
333
|
name: 'stale-entry',
|
|
334
|
+
label: '过期条目',
|
|
315
335
|
severity: 'medium',
|
|
316
336
|
action: 'flag',
|
|
337
|
+
scope: 'active',
|
|
317
338
|
detect: (entry, ctx) => {
|
|
318
|
-
if (entry.maturity === 'archived') return null;
|
|
319
339
|
const lastRef = entry.lastReferenced || entry.created;
|
|
320
340
|
if (!lastRef) return null;
|
|
321
341
|
const daysSinceRef = (Date.now() - new Date(lastRef).getTime()) / (1000 * 60 * 60 * 24);
|
|
@@ -329,10 +349,11 @@ const perEntryRules: AuditRule[] = [
|
|
|
329
349
|
// D2b: 领域相关性 — 检测已废弃领域的残留条目
|
|
330
350
|
{
|
|
331
351
|
name: 'deprecated-domain',
|
|
352
|
+
label: '废弃领域残留',
|
|
332
353
|
severity: 'high',
|
|
333
354
|
action: 'archive',
|
|
355
|
+
scope: 'active',
|
|
334
356
|
detect: (entry) => {
|
|
335
|
-
if (entry.maturity === 'archived') return null;
|
|
336
357
|
const tags = (entry.tags ?? []).map(t => t.toLowerCase());
|
|
337
358
|
// Tag-level: "pipeline" tag is deprecated (Studio Pipeline superseded by Agent Network)
|
|
338
359
|
if (tags.includes('pipeline')) {
|
|
@@ -348,8 +369,19 @@ const perEntryRules: AuditRule[] = [
|
|
|
348
369
|
},
|
|
349
370
|
];
|
|
350
371
|
|
|
372
|
+
/** 规则 label 正本表(#109,ADR-0002 定义即注册):派生自 perEntryRules,与规则键集编译期闭环,CLI 展示层直接消费 */
|
|
373
|
+
export const AUDIT_RULE_LABELS: Record<AuditRuleName, string> = Object.fromEntries(
|
|
374
|
+
perEntryRules.map(r => [r.name, r.label])
|
|
375
|
+
) as Record<AuditRuleName, string>;
|
|
376
|
+
|
|
351
377
|
// ── Audit Engine ──────────────────────────────────────────
|
|
352
378
|
|
|
379
|
+
/** 按 scope 决定是否评估:active 规则对 archived 条目不判定(人口过滤唯一落点) */
|
|
380
|
+
function ruleDetail(rule: AuditRule, entry: KnowledgeEntry, ctx: AuditContext): string | null {
|
|
381
|
+
if (rule.scope === 'active' && entry.maturity === 'archived') return null;
|
|
382
|
+
return rule.detect(entry, ctx);
|
|
383
|
+
}
|
|
384
|
+
|
|
353
385
|
export class KnowledgeAudit {
|
|
354
386
|
private store: KnowledgeStore;
|
|
355
387
|
private shortContentThreshold: number;
|
|
@@ -372,21 +404,7 @@ export class KnowledgeAudit {
|
|
|
372
404
|
staleDays: this.staleDays,
|
|
373
405
|
promotionBlockDays: this.promotionBlockDays,
|
|
374
406
|
};
|
|
375
|
-
|
|
376
|
-
for (const rule of perEntryRules) {
|
|
377
|
-
const detail = rule.detect(entry, ctx);
|
|
378
|
-
if (detail) {
|
|
379
|
-
issues.push({
|
|
380
|
-
rule: rule.name,
|
|
381
|
-
entryId: entry.id,
|
|
382
|
-
title: entry.title,
|
|
383
|
-
severity: rule.severity,
|
|
384
|
-
action: rule.action,
|
|
385
|
-
detail,
|
|
386
|
-
});
|
|
387
|
-
}
|
|
388
|
-
}
|
|
389
|
-
return issues;
|
|
407
|
+
return this.scanEntries([entry], ctx);
|
|
390
408
|
}
|
|
391
409
|
|
|
392
410
|
/**
|
|
@@ -402,22 +420,7 @@ export class KnowledgeAudit {
|
|
|
402
420
|
};
|
|
403
421
|
|
|
404
422
|
// Per-entry issues
|
|
405
|
-
const allIssues
|
|
406
|
-
for (const entry of entries) {
|
|
407
|
-
for (const rule of perEntryRules) {
|
|
408
|
-
const detail = rule.detect(entry, ctx);
|
|
409
|
-
if (detail) {
|
|
410
|
-
allIssues.push({
|
|
411
|
-
rule: rule.name,
|
|
412
|
-
entryId: entry.id,
|
|
413
|
-
title: entry.title,
|
|
414
|
-
severity: rule.severity,
|
|
415
|
-
action: rule.action,
|
|
416
|
-
detail,
|
|
417
|
-
});
|
|
418
|
-
}
|
|
419
|
-
}
|
|
420
|
-
}
|
|
423
|
+
const allIssues = this.scanEntries(entries, ctx);
|
|
421
424
|
|
|
422
425
|
// Summary
|
|
423
426
|
const summary = {} as Record<AuditRuleName, number>;
|
|
@@ -438,7 +441,7 @@ export class KnowledgeAudit {
|
|
|
438
441
|
|
|
439
442
|
// Health score (after)
|
|
440
443
|
const entriesAfter = options?.autoFix ? this.store.list({ excludeArchived: false }) : entries;
|
|
441
|
-
const issuesAfter = options?.autoFix ? this.
|
|
444
|
+
const issuesAfter = options?.autoFix ? this.scanEntries(entriesAfter, ctx) : allIssues;
|
|
442
445
|
const healthAfter = this.calculateHealthScore(entriesAfter, issuesAfter);
|
|
443
446
|
|
|
444
447
|
return {
|
|
@@ -496,33 +499,23 @@ export class KnowledgeAudit {
|
|
|
496
499
|
const staleRatio = active.length > 0 ? d5Issues.length / active.length : 0;
|
|
497
500
|
const d5Score = active.length === 0 ? 100 : Math.max(0, 100 - (staleRatio * 100));
|
|
498
501
|
|
|
499
|
-
// D6: 飞轮验证
|
|
500
|
-
const withRefs = active.filter(e => genuineRefs(e.referencedBy).length > 0).length;
|
|
501
|
-
const refCoverage = active.length > 0 ? withRefs / active.length : 0;
|
|
502
|
-
const avgRefs = active.length > 0
|
|
503
|
-
? active.reduce((sum, e) => sum + genuineRefs(e.referencedBy).length, 0) / active.length
|
|
504
|
-
: 0;
|
|
505
|
-
|
|
506
|
-
// Consumption hit rate from aggregated stats file (written by MonitorAgent)
|
|
507
|
-
let consumptionHitRate = 0;
|
|
502
|
+
// D6: 飞轮验证 —— 指标计算唯一实现在 flywheel-metrics,此处只做 fs 读取与报告层映射
|
|
508
503
|
let dailyConsumptionEvents = 0;
|
|
509
504
|
try {
|
|
510
505
|
const statsPath = path.join(this.store.getBaseDir(), '.consumption-stats.json');
|
|
511
506
|
if (fs.existsSync(statsPath)) {
|
|
512
507
|
const stats = JSON.parse(fs.readFileSync(statsPath, 'utf-8'));
|
|
513
508
|
dailyConsumptionEvents = stats.dailyEvents || 0;
|
|
514
|
-
// hitRate: daily events / active entries, capped at 1
|
|
515
|
-
consumptionHitRate = active.length > 0
|
|
516
|
-
? Math.min(dailyConsumptionEvents / active.length, 1)
|
|
517
|
-
: 0;
|
|
518
509
|
}
|
|
519
510
|
} catch { /* best-effort */ }
|
|
520
511
|
|
|
512
|
+
const metrics = evaluateFlywheel({ entries: active, dailyConsumptionEvents });
|
|
513
|
+
|
|
521
514
|
// Score: refCoverage * 50 + avgRefs * 20 + consumptionHitRate * 30
|
|
522
515
|
const d6Score = Math.min(100, Math.round(
|
|
523
|
-
refCoverage * 50 +
|
|
524
|
-
Math.min(avgRefs / 5, 1) * 20 +
|
|
525
|
-
consumptionHitRate * 30
|
|
516
|
+
metrics.refCoverage * 50 +
|
|
517
|
+
Math.min(metrics.avgRefs / 5, 1) * 20 +
|
|
518
|
+
metrics.consumptionHitRate * 30
|
|
526
519
|
));
|
|
527
520
|
|
|
528
521
|
return {
|
|
@@ -576,12 +569,12 @@ export class KnowledgeAudit {
|
|
|
576
569
|
score: d6Score,
|
|
577
570
|
issues: 0,
|
|
578
571
|
details: {
|
|
579
|
-
activeEntries:
|
|
580
|
-
entriesWithRefs:
|
|
581
|
-
refCoverage: Math.round(refCoverage * 100),
|
|
582
|
-
avgRefCount: Math.round(avgRefs * 10) / 10,
|
|
583
|
-
dailyConsumptionEvents,
|
|
584
|
-
consumptionHitRate: Math.round(consumptionHitRate * 100),
|
|
572
|
+
activeEntries: metrics.activeEntries,
|
|
573
|
+
entriesWithRefs: metrics.entriesWithRefs,
|
|
574
|
+
refCoverage: Math.round(metrics.refCoverage * 100),
|
|
575
|
+
avgRefCount: Math.round(metrics.avgRefs * 10) / 10,
|
|
576
|
+
dailyConsumptionEvents: metrics.dailyConsumptionEvents,
|
|
577
|
+
consumptionHitRate: Math.round(metrics.consumptionHitRate * 100),
|
|
585
578
|
},
|
|
586
579
|
},
|
|
587
580
|
incremental: this.computeIncremental(),
|
|
@@ -608,11 +601,14 @@ export class KnowledgeAudit {
|
|
|
608
601
|
|
|
609
602
|
// ── Internal ────────────────────────────────────────────
|
|
610
603
|
|
|
611
|
-
|
|
604
|
+
/**
|
|
605
|
+
* 逐条目跑 perEntryRules(#111 收口):validate(单条目)、run(全量)与 autoFix 重扫共用
|
|
606
|
+
*/
|
|
607
|
+
private scanEntries(entries: KnowledgeEntry[], ctx: AuditContext): AuditIssue[] {
|
|
612
608
|
const issues: AuditIssue[] = [];
|
|
613
609
|
for (const entry of entries) {
|
|
614
610
|
for (const rule of perEntryRules) {
|
|
615
|
-
const detail = rule
|
|
611
|
+
const detail = ruleDetail(rule, entry, ctx);
|
|
616
612
|
if (detail) {
|
|
617
613
|
issues.push({
|
|
618
614
|
rule: rule.name,
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 知识飞轮指标(harness#81)
|
|
3
|
+
*
|
|
4
|
+
* 纯判定 module:吃 active 条目数组(+ 可选当日消费事件数),一次产出 canonical 飞轮指标。
|
|
5
|
+
* 零 IO——人口筛选(哪些条目算 active)与 `.consumption-stats.json` 读取都留在调用方。
|
|
6
|
+
*
|
|
7
|
+
* 此前同一组分子计算在 audit.ts D6、knowledge stats、knowledge health 三处独立实现,
|
|
8
|
+
* 后两处直接数 `referencedBy.length`,把 search / prompt-inject / test-agent 等自动化
|
|
9
|
+
* 触碰算成真实消费——同一知识库报出两套飞轮健康度(实测 refCoverage 26% vs 28%、
|
|
10
|
+
* avgRefs 0.4 vs 0.6)。飞轮指标是退役/降级判定的输入,口径必须唯一:
|
|
11
|
+
* **分子一律为过滤 synthetic 后的 genuine refs**(ADR-0013)。
|
|
12
|
+
*
|
|
13
|
+
* 单位约定:本 module 只出比例(0..1),百分比取整/一位小数等是展示层的事。
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
import type { KnowledgeEntry } from './types';
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* 自动化写入方形成的引用键:`<contributor>:<YYYY-MM-DD>`(contributor 见 recordReference)。
|
|
20
|
+
* 这些是检索/运维动作的按天记账,不代表条目被真实消费,不计入飞轮分子。
|
|
21
|
+
* `unknown:`(query() 注入路径)不在过滤面内——注入即消费,维持既有语义。
|
|
22
|
+
*/
|
|
23
|
+
const SYNTHETIC_REF_PATTERN = /^(search|test-agent|prompt-inject|monitor|analyst|auditor|triage|executor|session|trend|incident):\d{4}-\d{2}-\d{2}/;
|
|
24
|
+
|
|
25
|
+
/** 剔除 synthetic refs,返回真实消费引用(唯一口径) */
|
|
26
|
+
export function genuineRefs(refs: string[]): string[] {
|
|
27
|
+
return refs.filter(r => !SYNTHETIC_REF_PATTERN.test(r));
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export interface FlywheelEnv {
|
|
31
|
+
/** 参与统计的条目人口(调用方筛选,本 module 不再过滤 archived/deprecated) */
|
|
32
|
+
entries: KnowledgeEntry[];
|
|
33
|
+
/** 当日消费事件数(`.consumption-stats.json` 的 dailyEvents,MonitorAgent 汇总写入);未提供视为 0 */
|
|
34
|
+
dailyConsumptionEvents?: number;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export interface FlywheelMetrics {
|
|
38
|
+
/** 人口大小 */
|
|
39
|
+
activeEntries: number;
|
|
40
|
+
/** 分子:有 genuine 引用(含 1 条即算)的条目数 */
|
|
41
|
+
entriesWithRefs: number;
|
|
42
|
+
/** entriesWithRefs / activeEntries,0..1;空人口为 0 */
|
|
43
|
+
refCoverage: number;
|
|
44
|
+
/** genuine 引用总数 / activeEntries,未取整比例 */
|
|
45
|
+
avgRefs: number;
|
|
46
|
+
/** 透传输入,供报告层复用 */
|
|
47
|
+
dailyConsumptionEvents: number;
|
|
48
|
+
/** dailyConsumptionEvents / activeEntries,capped at 1;无消费事件为 0 */
|
|
49
|
+
consumptionHitRate: number;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export function evaluateFlywheel(env: FlywheelEnv): FlywheelMetrics {
|
|
53
|
+
const entries = env.entries;
|
|
54
|
+
const dailyConsumptionEvents = env.dailyConsumptionEvents ?? 0;
|
|
55
|
+
const activeEntries = entries.length;
|
|
56
|
+
|
|
57
|
+
const refCounts = entries.map(e => genuineRefs(e.referencedBy).length);
|
|
58
|
+
const entriesWithRefs = refCounts.filter(n => n > 0).length;
|
|
59
|
+
const totalRefs = refCounts.reduce((sum, n) => sum + n, 0);
|
|
60
|
+
|
|
61
|
+
return {
|
|
62
|
+
activeEntries,
|
|
63
|
+
entriesWithRefs,
|
|
64
|
+
refCoverage: activeEntries > 0 ? entriesWithRefs / activeEntries : 0,
|
|
65
|
+
avgRefs: activeEntries > 0 ? totalRefs / activeEntries : 0,
|
|
66
|
+
dailyConsumptionEvents,
|
|
67
|
+
consumptionHitRate: activeEntries > 0
|
|
68
|
+
? Math.min(dailyConsumptionEvents / activeEntries, 1)
|
|
69
|
+
: 0,
|
|
70
|
+
};
|
|
71
|
+
}
|
package/src/knowledge/import.ts
CHANGED
|
@@ -183,9 +183,7 @@ export class ColdStartImporter {
|
|
|
183
183
|
}
|
|
184
184
|
|
|
185
185
|
// 写入知识库
|
|
186
|
-
|
|
187
|
-
this.config.store.save(entry);
|
|
188
|
-
}
|
|
186
|
+
this.config.store.saveAll(entries);
|
|
189
187
|
|
|
190
188
|
return { source, entries, errors };
|
|
191
189
|
}
|
|
@@ -202,12 +200,6 @@ export class ColdStartImporter {
|
|
|
202
200
|
const { execSync } = require('child_process');
|
|
203
201
|
const cwd = this.config.projectRoot;
|
|
204
202
|
|
|
205
|
-
// 分析大型重构提交
|
|
206
|
-
execSync(
|
|
207
|
-
'git log --oneline --diff-filter=M --numstat --since="6 months ago" | head -100',
|
|
208
|
-
{ cwd, encoding: 'utf-8', timeout: 10000 },
|
|
209
|
-
);
|
|
210
|
-
|
|
211
203
|
// 查找 fix/hotfix 相关提交
|
|
212
204
|
const fixCommits = execSync(
|
|
213
205
|
'git log --oneline --grep="fix\\|hotfix\\|bug" --since="6 months ago" | head -20',
|
|
@@ -247,9 +239,7 @@ export class ColdStartImporter {
|
|
|
247
239
|
});
|
|
248
240
|
}
|
|
249
241
|
|
|
250
|
-
|
|
251
|
-
this.config.store.save(entry);
|
|
252
|
-
}
|
|
242
|
+
this.config.store.saveAll(entries);
|
|
253
243
|
|
|
254
244
|
return { source, entries, errors };
|
|
255
245
|
}
|
|
@@ -317,9 +307,7 @@ export class ColdStartImporter {
|
|
|
317
307
|
}
|
|
318
308
|
}
|
|
319
309
|
|
|
320
|
-
|
|
321
|
-
this.config.store.save(entry);
|
|
322
|
-
}
|
|
310
|
+
this.config.store.saveAll(entries);
|
|
323
311
|
|
|
324
312
|
return { source, entries, errors };
|
|
325
313
|
}
|
|
@@ -354,9 +342,7 @@ export class ColdStartImporter {
|
|
|
354
342
|
}
|
|
355
343
|
}
|
|
356
344
|
|
|
357
|
-
|
|
358
|
-
this.config.store.save(entry);
|
|
359
|
-
}
|
|
345
|
+
this.config.store.saveAll(entries);
|
|
360
346
|
|
|
361
347
|
return { source, entries, errors };
|
|
362
348
|
}
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
|
|
10
10
|
import * as fs from 'fs';
|
|
11
11
|
import * as path from 'path';
|
|
12
|
-
import
|
|
12
|
+
import { splitFrontmatter } from '../utils/frontmatter';
|
|
13
13
|
|
|
14
14
|
const EXCLUDED_DIRS = ['.archive', 'archived', '.snapshots', 'resolutions'];
|
|
15
15
|
const INDEX_FILENAME = '_index.md';
|
|
@@ -131,32 +131,37 @@ export class KnowledgeIndexGenerator {
|
|
|
131
131
|
// 跳过 ghost 文件(文件名为 .md)
|
|
132
132
|
if (path.basename(filename) === '.md') return null;
|
|
133
133
|
|
|
134
|
-
// 尝试解析 YAML frontmatter
|
|
135
|
-
const
|
|
136
|
-
if (
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
134
|
+
// 尝试解析 YAML frontmatter(语法与失败走法正本:utils/frontmatter)
|
|
135
|
+
const fm = splitFrontmatter(raw);
|
|
136
|
+
if (fm.state === 'malformed') {
|
|
137
|
+
// 统一口径(harness#89):损坏必须显式上报,恢复动作是 best-effort 索引原文
|
|
138
|
+
console.error(
|
|
139
|
+
`[harness] 知识索引 frontmatter ${fm.reason}(${fm.detail}),按无 frontmatter 处理 ${filename}`
|
|
140
|
+
);
|
|
141
|
+
}
|
|
142
|
+
if (fm.state === 'ok') {
|
|
143
|
+
const meta = fm.meta;
|
|
144
|
+
const headings = this.extractHeadings(fm.body);
|
|
140
145
|
|
|
141
146
|
// 检测 skill schema(name/description 而非 id/type)
|
|
142
|
-
const type = meta
|
|
147
|
+
const type = meta.type
|
|
143
148
|
? String(meta.type)
|
|
144
|
-
: meta
|
|
149
|
+
: meta.name
|
|
145
150
|
? 'skill'
|
|
146
151
|
: this.inferType(filename);
|
|
147
152
|
|
|
148
153
|
return {
|
|
149
154
|
filename,
|
|
150
|
-
id: String(meta
|
|
155
|
+
id: String(meta.id ?? meta.name ?? path.basename(filePath, '.md')),
|
|
151
156
|
type,
|
|
152
|
-
title: String(meta
|
|
153
|
-
maturity: String(meta
|
|
154
|
-
tags: Array.isArray(meta
|
|
157
|
+
title: String(meta.title ?? meta.description ?? ''),
|
|
158
|
+
maturity: String(meta.maturity ?? 'unknown'),
|
|
159
|
+
tags: Array.isArray(meta.tags) ? (meta.tags as unknown[]).map(String) : [],
|
|
155
160
|
headings,
|
|
156
161
|
};
|
|
157
162
|
}
|
|
158
163
|
|
|
159
|
-
//
|
|
164
|
+
// absent(含空 meta)或已上报的 malformed — best effort
|
|
160
165
|
const headings = this.extractHeadings(raw);
|
|
161
166
|
const h1Match = raw.match(/^#\s+(.+)$/m);
|
|
162
167
|
|
package/src/knowledge/ingest.ts
CHANGED
|
@@ -13,6 +13,7 @@ import type {
|
|
|
13
13
|
} from './types';
|
|
14
14
|
import type { KnowledgeStore } from './store';
|
|
15
15
|
import { KnowledgeAudit } from './audit';
|
|
16
|
+
import { splitFrontmatter } from '../utils/frontmatter';
|
|
16
17
|
|
|
17
18
|
const MAX_SOURCE_REFS = 20;
|
|
18
19
|
const MAX_EXTERNAL_CONTENT_LENGTH = 5000;
|
|
@@ -178,7 +179,10 @@ export class KnowledgeIngest {
|
|
|
178
179
|
|
|
179
180
|
private generateId(type: KnowledgeSubsystem): string {
|
|
180
181
|
const prefix = type.toUpperCase().slice(0, 3);
|
|
181
|
-
|
|
182
|
+
// 序号取自索引计数(harness#107):不再走 list() 逐条读条目文件;
|
|
183
|
+
// 与 list() 默认过滤口径一致,archived/deprecated 不计入序号
|
|
184
|
+
const existing = this.store.readIndex()
|
|
185
|
+
.filter(e => e.type === type && e.maturity !== 'archived' && e.maturity !== 'deprecated');
|
|
182
186
|
const seq = String(existing.length + 1).padStart(3, '0');
|
|
183
187
|
return `${prefix}-${seq}`;
|
|
184
188
|
}
|
|
@@ -242,9 +246,10 @@ export class KnowledgeIngest {
|
|
|
242
246
|
|
|
243
247
|
/** Extract first 50 chars of content body (after frontmatter), stripped of whitespace */
|
|
244
248
|
private getContentPrefix(content: string): string {
|
|
245
|
-
//
|
|
246
|
-
const
|
|
247
|
-
|
|
249
|
+
// 正本判定(harness#89):只有合法 frontmatter 块才剥头,正文里的 --- 分隔线不再被误吞
|
|
250
|
+
const fm = splitFrontmatter(content);
|
|
251
|
+
const body = fm.state === 'ok' ? fm.body : content;
|
|
252
|
+
return body.trim().slice(0, 50).replace(/\s+/g, '');
|
|
248
253
|
}
|
|
249
254
|
|
|
250
255
|
/** Calculate keyword overlap ratio between two normalized titles */
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
|
|
8
8
|
import * as fs from 'fs';
|
|
9
9
|
import * as path from 'path';
|
|
10
|
-
import
|
|
10
|
+
import { splitFrontmatter, joinFrontmatter } from '../utils/frontmatter';
|
|
11
11
|
|
|
12
12
|
interface MigrationResult {
|
|
13
13
|
total: number;
|
|
@@ -40,14 +40,19 @@ export function migrateKnowledgeEntries(baseDir: string): MigrationResult {
|
|
|
40
40
|
const filePath = path.join(baseDir, file);
|
|
41
41
|
try {
|
|
42
42
|
const raw = fs.readFileSync(filePath, 'utf-8');
|
|
43
|
-
const
|
|
44
|
-
if (
|
|
43
|
+
const fm = splitFrontmatter(raw);
|
|
44
|
+
if (fm.state === 'absent') {
|
|
45
45
|
result.errors.push(`${file}: no frontmatter found`);
|
|
46
46
|
continue;
|
|
47
47
|
}
|
|
48
|
+
if (fm.state === 'malformed') {
|
|
49
|
+
// 统一口径(harness#89):损坏的 frontmatter 落 errors,不静默丢
|
|
50
|
+
result.errors.push(`${file}: frontmatter ${fm.reason} (${fm.detail})`);
|
|
51
|
+
continue;
|
|
52
|
+
}
|
|
48
53
|
|
|
49
|
-
const meta =
|
|
50
|
-
const content =
|
|
54
|
+
const meta = fm.meta;
|
|
55
|
+
const content = fm.body;
|
|
51
56
|
|
|
52
57
|
// Check if migration needed
|
|
53
58
|
if (meta.consumptionMode && meta.origin) {
|
|
@@ -60,9 +65,7 @@ export function migrateKnowledgeEntries(baseDir: string): MigrationResult {
|
|
|
60
65
|
if (!meta.origin) meta.origin = 'agent';
|
|
61
66
|
|
|
62
67
|
// Write back
|
|
63
|
-
|
|
64
|
-
const newContent = `---\n${newFrontmatter}---\n\n${content}`;
|
|
65
|
-
fs.writeFileSync(filePath, newContent, 'utf-8');
|
|
68
|
+
fs.writeFileSync(filePath, joinFrontmatter(meta, content), 'utf-8');
|
|
66
69
|
result.migrated++;
|
|
67
70
|
} catch (err) {
|
|
68
71
|
result.errors.push(`${file}: ${err instanceof Error ? err.message : String(err)}`);
|
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
* Storage: append-only JSONL at .harness/knowledge/references.jsonl
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
import * as fs from 'fs';
|
|
9
8
|
import * as path from 'path';
|
|
9
|
+
import { appendJsonl, readJsonl } from '../utils/jsonl';
|
|
10
10
|
import type { ReferenceRecord } from './types';
|
|
11
11
|
import type { KnowledgeStore } from './store';
|
|
12
12
|
|
|
@@ -33,7 +33,8 @@ export class ReferenceTracker {
|
|
|
33
33
|
entryIds,
|
|
34
34
|
timestamp: new Date().toISOString(),
|
|
35
35
|
};
|
|
36
|
-
|
|
36
|
+
// 写链收口:ensureDir + append(harness#82;原实现不 ensureDir,依赖 store 建目录)
|
|
37
|
+
appendJsonl(this.filePath, record);
|
|
37
38
|
}
|
|
38
39
|
|
|
39
40
|
/**
|
|
@@ -85,13 +86,16 @@ export class ReferenceTracker {
|
|
|
85
86
|
// ── Internal ───────────────────────────────────────────────
|
|
86
87
|
|
|
87
88
|
private readAll(): ReferenceRecord[] {
|
|
88
|
-
if (!fs.existsSync(this.filePath)) return [];
|
|
89
89
|
try {
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
90
|
+
// 坏行策略:skip(harness#82:原「逐行 map 会抛 + 外层 catch 吞成整文件 []」
|
|
91
|
+
// ——坏一行丢全部记录——不可接受,改为单行损坏只丢该行);
|
|
92
|
+
// 外层 catch 仅兜 IO 读取错误,沿用原吞掉语义
|
|
93
|
+
// 计数去向:豁免(harness#100)——三个消费点 getReferencesForEntry /
|
|
94
|
+
// getReferencesForDecision / updateReferencedBy 只按合法记录取引用关系。
|
|
95
|
+
// 代价如实记录:checkOrphans(knowledge/lint.ts)以 refs.length>0 判孤儿,
|
|
96
|
+
// 坏行会让它给出假孤儿判定,不只是少报;透传需要给 LintIssue / `knowledge health`
|
|
97
|
+
// 报告加计数位,属 knowledge 域输出形状变更,另票收口
|
|
98
|
+
return readJsonl<ReferenceRecord>(this.filePath, 'skip').records;
|
|
95
99
|
} catch {
|
|
96
100
|
return [];
|
|
97
101
|
}
|