onto-mcp 0.3.2 → 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.onto/processes/reconstruct/actionable-ontology-seed-recomposition-design.md +447 -0
- package/.onto/processes/reconstruct/foundry-style-ontology-seed-contract.md +934 -0
- package/.onto/processes/reconstruct/reconstruct-boundary-contract.md +303 -725
- package/.onto/processes/reconstruct/reconstruct-contract-registry.yaml +1645 -0
- package/.onto/processes/reconstruct/reconstruct-execution-ux-contract.md +26 -22
- package/.onto/processes/reconstruct/source-profile-contract.md +49 -23
- package/.onto/processes/reconstruct/source-profiles/code.md +6 -3
- package/.onto/processes/reconstruct/source-profiles/database.md +5 -2
- package/.onto/processes/reconstruct/source-profiles/document.md +5 -2
- package/.onto/processes/reconstruct/source-profiles/spreadsheet.md +5 -4
- package/.onto/processes/review/review-execution-ux-contract.md +40 -0
- package/.onto/processes/shared/pipeline-execution-ledger-contract.md +26 -10
- package/.onto/processes/shared/target-material-kind-contract.md +29 -16
- package/AGENTS.md +6 -4
- package/README.md +149 -76
- package/dist/cli.js +8 -8
- package/dist/core-api/reconstruct-api.js +117 -31
- package/dist/core-api/review-api.js +47 -0
- package/dist/core-runtime/cli/codex-review-unit-executor.js +39 -2
- package/dist/core-runtime/cli/complete-review-session.js +2 -2
- package/dist/core-runtime/cli/mock-review-unit-executor.js +1 -1
- package/dist/core-runtime/cli/review-invoke.js +9 -9
- package/dist/core-runtime/cli/run-review-prompt-execution.js +39 -5
- package/dist/core-runtime/cli/spawn-watcher.js +266 -47
- package/dist/core-runtime/cli/start-review-session.js +3 -3
- package/dist/core-runtime/llm/llm-caller.js +11 -0
- package/dist/core-runtime/llm/llm-tool-loop.js +2 -0
- package/dist/core-runtime/observability/runtime-stream-observation.js +118 -0
- package/dist/core-runtime/onboard/cli-host.js +174 -0
- package/dist/core-runtime/onboard/host-target.js +22 -0
- package/dist/core-runtime/onboard/json-config-host.js +122 -0
- package/dist/core-runtime/onboard/path-scan.js +26 -0
- package/dist/core-runtime/onboard/prompt.js +51 -0
- package/dist/core-runtime/onboard/register.js +214 -0
- package/dist/core-runtime/onboard/types.js +27 -0
- package/dist/core-runtime/reconstruct/actionable-seed-validation.js +1777 -0
- package/dist/core-runtime/reconstruct/artifact-types.js +10 -4
- package/dist/core-runtime/reconstruct/contract-registry.js +623 -0
- package/dist/core-runtime/reconstruct/domain-id.js +10 -0
- package/dist/core-runtime/reconstruct/governing-snapshot.js +716 -0
- package/dist/core-runtime/reconstruct/material-profile-validation.js +191 -0
- package/dist/core-runtime/reconstruct/materialize-preparation.js +49 -11
- package/dist/core-runtime/reconstruct/pipeline-execution-ledger.js +269 -79
- package/dist/core-runtime/reconstruct/post-seed-validation.js +1194 -51
- package/dist/core-runtime/reconstruct/record.js +104 -20
- package/dist/core-runtime/reconstruct/run.js +2107 -413
- package/dist/core-runtime/reconstruct/seed-claim-projections.js +268 -0
- package/dist/core-runtime/reconstruct/source-profiles.js +93 -4
- package/dist/core-runtime/reconstruct/terminal-validation.js +807 -0
- package/dist/core-runtime/review/review-invocation-runner.js +4 -4
- package/dist/mcp/server.js +110 -38
- package/dist/mcp/tool-schemas.js +20 -6
- package/package.json +8 -17
- package/scripts/onto-review-watch.sh +486 -0
- package/scripts/onto-runtime-watch.sh +122 -0
- package/scripts/postinstall-hint.js +22 -0
- package/.onto/processes/reconstruct/top-level-concept-discovery-contract.md +0 -387
- package/dist/core-runtime/cli/bootstrap-review-binding.js +0 -186
- package/dist/core-runtime/cli/codex-nested-dispatch.test.js +0 -390
- package/dist/core-runtime/cli/codex-nested-teamlead-executor.test.js +0 -335
- package/dist/core-runtime/cli/coordinator-helpers.js +0 -583
- package/dist/core-runtime/cli/coordinator-state-machine-deliberation.test.js +0 -167
- package/dist/core-runtime/cli/coordinator-state-machine.js +0 -794
- package/dist/core-runtime/cli/e2e-codex-multi-agent-fixes.test.js +0 -615
- package/dist/core-runtime/cli/e2e-start-review-session.test.js +0 -312
- package/dist/core-runtime/cli/health.js +0 -44
- package/dist/core-runtime/cli/inline-http-review-unit-executor.test.js +0 -567
- package/dist/core-runtime/cli/materialize-review-execution-preparation.js +0 -104
- package/dist/core-runtime/cli/migrate-session-roots.js +0 -118
- package/dist/core-runtime/cli/repo-layout-migration-replace.smoke.test.js +0 -106
- package/dist/core-runtime/cli/review-invoke-auto-resolution.test.js +0 -268
- package/dist/core-runtime/cli/review-invoke-coordinator-topology.test.js +0 -136
- package/dist/core-runtime/cli/review-invoke-resolver-caching.test.js +0 -201
- package/dist/core-runtime/cli/review-invoke-topology-dispatch.test.js +0 -192
- package/dist/core-runtime/cli/session-root-guard.js +0 -168
- package/dist/core-runtime/cli/spawn-watcher.test.js +0 -457
- package/dist/core-runtime/cli/strip-wrapping-code-fence.test.js +0 -79
- package/dist/core-runtime/cli/teamcreate-lens-deliberation-executor.js +0 -412
- package/dist/core-runtime/cli/teamcreate-lens-deliberation-executor.test.js +0 -351
- package/dist/core-runtime/cli/topology-executor-mapping.js +0 -139
- package/dist/core-runtime/cli/topology-executor-mapping.test.js +0 -173
- package/dist/core-runtime/cli/write-review-interpretation.js +0 -81
- package/dist/core-runtime/config/onto-config-cli.js +0 -278
- package/dist/core-runtime/config/onto-config-key-path.js +0 -288
- package/dist/core-runtime/config/onto-config-key-path.test.js +0 -195
- package/dist/core-runtime/config/onto-config-preview.js +0 -108
- package/dist/core-runtime/config/onto-config-preview.test.js +0 -132
- package/dist/core-runtime/discovery/config-chain.js +0 -118
- package/dist/core-runtime/discovery/config-chain.test.js +0 -103
- package/dist/core-runtime/discovery/config-profile.js +0 -199
- package/dist/core-runtime/discovery/config-profile.test.js +0 -233
- package/dist/core-runtime/discovery/host-detection.test.js +0 -186
- package/dist/core-runtime/discovery/installation-paths.test.js +0 -65
- package/dist/core-runtime/discovery/lens-registry.test.js +0 -81
- package/dist/core-runtime/discovery/path-normalization.test.js +0 -22
- package/dist/core-runtime/discovery/plugin-path.js +0 -72
- package/dist/core-runtime/discovery/plugin-path.test.js +0 -95
- package/dist/core-runtime/evolve/adapters/code-product/compile/compile-defense.js +0 -344
- package/dist/core-runtime/evolve/adapters/code-product/compile/compile-defense.test.js +0 -915
- package/dist/core-runtime/evolve/adapters/code-product/compile/compile.js +0 -564
- package/dist/core-runtime/evolve/adapters/code-product/compile/compile.test.js +0 -708
- package/dist/core-runtime/evolve/adapters/code-product/parsers/brief-parser.js +0 -165
- package/dist/core-runtime/evolve/adapters/code-product/parsers/brief-parser.test.js +0 -227
- package/dist/core-runtime/evolve/adapters/code-product/validators/validate.js +0 -59
- package/dist/core-runtime/evolve/adapters/code-product/validators/validate.test.js +0 -205
- package/dist/core-runtime/evolve/adapters/methodology/adapter.js +0 -16
- package/dist/core-runtime/evolve/adapters/methodology/adapter.test.js +0 -9
- package/dist/core-runtime/evolve/adapters/methodology/perspectives/authority-consistency.js +0 -298
- package/dist/core-runtime/evolve/adapters/methodology/perspectives/authority-consistency.test.js +0 -70
- package/dist/core-runtime/evolve/adapters/methodology/scope-types/process.js +0 -46
- package/dist/core-runtime/evolve/adapters/methodology/scope-types/process.test.js +0 -73
- package/dist/core-runtime/evolve/adapters/registry.js +0 -47
- package/dist/core-runtime/evolve/adapters/registry.test.js +0 -67
- package/dist/core-runtime/evolve/cli.js +0 -256
- package/dist/core-runtime/evolve/commands/align.js +0 -194
- package/dist/core-runtime/evolve/commands/align.test.js +0 -82
- package/dist/core-runtime/evolve/commands/apply.js +0 -161
- package/dist/core-runtime/evolve/commands/apply.test.js +0 -138
- package/dist/core-runtime/evolve/commands/close.js +0 -39
- package/dist/core-runtime/evolve/commands/close.test.js +0 -99
- package/dist/core-runtime/evolve/commands/defer.js +0 -40
- package/dist/core-runtime/evolve/commands/defer.test.js +0 -134
- package/dist/core-runtime/evolve/commands/draft.js +0 -323
- package/dist/core-runtime/evolve/commands/draft.test.js +0 -178
- package/dist/core-runtime/evolve/commands/e2e-evolve-full-cycle.test.js +0 -208
- package/dist/core-runtime/evolve/commands/error-messages.js +0 -125
- package/dist/core-runtime/evolve/commands/error-messages.test.js +0 -167
- package/dist/core-runtime/evolve/commands/propose-align.js +0 -222
- package/dist/core-runtime/evolve/commands/propose-align.test.js +0 -136
- package/dist/core-runtime/evolve/commands/reconstruct.js +0 -330
- package/dist/core-runtime/evolve/commands/reconstruct.test.js +0 -278
- package/dist/core-runtime/evolve/commands/shared.js +0 -22
- package/dist/core-runtime/evolve/commands/stale-check.js +0 -103
- package/dist/core-runtime/evolve/commands/stale-check.test.js +0 -84
- package/dist/core-runtime/evolve/commands/start.js +0 -887
- package/dist/core-runtime/evolve/commands/start.test.js +0 -396
- package/dist/core-runtime/evolve/config/project-config.js +0 -99
- package/dist/core-runtime/evolve/config/project-config.test.js +0 -170
- package/dist/core-runtime/evolve/renderers/align-packet.js +0 -280
- package/dist/core-runtime/evolve/renderers/align-packet.test.js +0 -332
- package/dist/core-runtime/evolve/renderers/draft-packet.js +0 -303
- package/dist/core-runtime/evolve/renderers/draft-packet.test.js +0 -377
- package/dist/core-runtime/evolve/renderers/format.js +0 -5
- package/dist/core-runtime/evolve/renderers/scope-md.js +0 -237
- package/dist/core-runtime/evolve/renderers/scope-md.test.js +0 -306
- package/dist/core-runtime/govern/cli.js +0 -369
- package/dist/core-runtime/govern/cli.test.js +0 -314
- package/dist/core-runtime/govern/drift-engine.js +0 -103
- package/dist/core-runtime/govern/drift-engine.test.js +0 -319
- package/dist/core-runtime/govern/promote-principle.js +0 -206
- package/dist/core-runtime/govern/promote-principle.test.js +0 -368
- package/dist/core-runtime/govern/queue.js +0 -81
- package/dist/core-runtime/govern/types.js +0 -16
- package/dist/core-runtime/install/cli.js +0 -530
- package/dist/core-runtime/install/detect.js +0 -128
- package/dist/core-runtime/install/detect.test.js +0 -155
- package/dist/core-runtime/install/gitignore-update.js +0 -74
- package/dist/core-runtime/install/gitignore-update.test.js +0 -64
- package/dist/core-runtime/install/install-integration.test.js +0 -373
- package/dist/core-runtime/install/prompts.js +0 -389
- package/dist/core-runtime/install/prompts.test.js +0 -293
- package/dist/core-runtime/install/types.js +0 -26
- package/dist/core-runtime/install/validation.js +0 -295
- package/dist/core-runtime/install/validation.test.js +0 -313
- package/dist/core-runtime/install/writer.js +0 -254
- package/dist/core-runtime/install/writer.test.js +0 -218
- package/dist/core-runtime/learning/extractor.js +0 -461
- package/dist/core-runtime/learning/feedback.js +0 -179
- package/dist/core-runtime/learning/health-report.js +0 -165
- package/dist/core-runtime/learning/health-report.test.js +0 -169
- package/dist/core-runtime/learning/loader.js +0 -388
- package/dist/core-runtime/learning/loader.test.js +0 -102
- package/dist/core-runtime/learning/promote/apply-state.js +0 -240
- package/dist/core-runtime/learning/promote/audit-obligation.js +0 -195
- package/dist/core-runtime/learning/promote/collector.js +0 -432
- package/dist/core-runtime/learning/promote/degraded-state.js +0 -125
- package/dist/core-runtime/learning/promote/domain-doc-proposer.js +0 -166
- package/dist/core-runtime/learning/promote/e2e-promote.test.js +0 -6385
- package/dist/core-runtime/learning/promote/health-snapshot.js +0 -150
- package/dist/core-runtime/learning/promote/insight-reclassifier.js +0 -544
- package/dist/core-runtime/learning/promote/judgment-auditor.js +0 -517
- package/dist/core-runtime/learning/promote/panel-reviewer.js +0 -1158
- package/dist/core-runtime/learning/promote/promote-executor.js +0 -1675
- package/dist/core-runtime/learning/promote/promoter.js +0 -307
- package/dist/core-runtime/learning/promote/retirement.js +0 -122
- package/dist/core-runtime/learning/promote/types.js +0 -23
- package/dist/core-runtime/learning/prompt-sections.js +0 -51
- package/dist/core-runtime/learning/shared/artifact-registry-init.js +0 -45
- package/dist/core-runtime/learning/shared/artifact-registry.js +0 -254
- package/dist/core-runtime/learning/shared/audit-obligation-kernel.js +0 -73
- package/dist/core-runtime/learning/shared/audit-state.js +0 -99
- package/dist/core-runtime/learning/shared/duplicate-check.js +0 -28
- package/dist/core-runtime/learning/shared/llm-caller.js +0 -831
- package/dist/core-runtime/learning/shared/llm-caller.test.js +0 -601
- package/dist/core-runtime/learning/shared/llm-tool-loop.js +0 -393
- package/dist/core-runtime/learning/shared/mode.js +0 -25
- package/dist/core-runtime/learning/shared/paths.js +0 -84
- package/dist/core-runtime/learning/shared/paths.test.js +0 -79
- package/dist/core-runtime/learning/shared/patterns.js +0 -37
- package/dist/core-runtime/learning/shared/recoverability.js +0 -355
- package/dist/core-runtime/learning/shared/recovery-context.js +0 -374
- package/dist/core-runtime/learning/shared/scope.js +0 -1
- package/dist/core-runtime/learning/shared/semantic-classifier.js +0 -94
- package/dist/core-runtime/learning/shared/specs/apply-execution-state-spec.js +0 -42
- package/dist/core-runtime/learning/shared/specs/audit-state-spec.js +0 -37
- package/dist/core-runtime/learning/shared/specs/backup-metadata-spec.js +0 -39
- package/dist/core-runtime/learning/shared/specs/emergency-log-spec.js +0 -41
- package/dist/core-runtime/learning/shared/specs/layout-version-spec.js +0 -38
- package/dist/core-runtime/learning/shared/specs/promote-decisions-spec.js +0 -43
- package/dist/core-runtime/learning/shared/specs/promote-report-spec.js +0 -113
- package/dist/core-runtime/learning/shared/specs/prune-log-spec.js +0 -36
- package/dist/core-runtime/learning/shared/specs/recovery-resolution-spec.js +0 -48
- package/dist/core-runtime/learning/shared/specs/restore-manifest-spec.js +0 -43
- package/dist/core-runtime/learning/shared/specs/spec-helpers.js +0 -64
- package/dist/core-runtime/learning/usage-tracker.js +0 -190
- package/dist/core-runtime/learning/usage-tracker.test.js +0 -176
- package/dist/core-runtime/onboard/detect-review-axes.js +0 -122
- package/dist/core-runtime/onboard/detect-review-axes.test.js +0 -127
- package/dist/core-runtime/onboard/write-review-block.js +0 -188
- package/dist/core-runtime/onboard/write-review-block.test.js +0 -240
- package/dist/core-runtime/readers/brownfield-builder.js +0 -150
- package/dist/core-runtime/readers/brownfield-builder.test.js +0 -136
- package/dist/core-runtime/readers/code-chunk-collector.js +0 -53
- package/dist/core-runtime/readers/code-chunk-collector.test.js +0 -136
- package/dist/core-runtime/readers/file-utils.js +0 -240
- package/dist/core-runtime/readers/file-utils.test.js +0 -146
- package/dist/core-runtime/readers/lexicon-citation-check.js +0 -93
- package/dist/core-runtime/readers/lexicon-citation-check.test.js +0 -77
- package/dist/core-runtime/readers/mcp-figma.js +0 -30
- package/dist/core-runtime/readers/mcp-figma.test.js +0 -82
- package/dist/core-runtime/readers/mcp-generic.js +0 -31
- package/dist/core-runtime/readers/mcp-generic.test.js +0 -76
- package/dist/core-runtime/readers/ontology-index.js +0 -148
- package/dist/core-runtime/readers/ontology-index.test.js +0 -245
- package/dist/core-runtime/readers/ontology-query.js +0 -168
- package/dist/core-runtime/readers/ontology-query.test.js +0 -311
- package/dist/core-runtime/readers/ontology-resolve.js +0 -48
- package/dist/core-runtime/readers/ontology-resolve.test.js +0 -48
- package/dist/core-runtime/readers/patterns/index.js +0 -7
- package/dist/core-runtime/readers/review-log.js +0 -213
- package/dist/core-runtime/readers/review-log.test.js +0 -313
- package/dist/core-runtime/readers/scan-local.js +0 -102
- package/dist/core-runtime/readers/scan-local.test.js +0 -102
- package/dist/core-runtime/readers/scan-tarball.js +0 -121
- package/dist/core-runtime/readers/scan-tarball.test.js +0 -283
- package/dist/core-runtime/readers/scan-vault.js +0 -34
- package/dist/core-runtime/readers/scan-vault.test.js +0 -81
- package/dist/core-runtime/readers/types.js +0 -42
- package/dist/core-runtime/readers/types.test.js +0 -94
- package/dist/core-runtime/readers/viewpoint-collectors.js +0 -229
- package/dist/core-runtime/reconstruct/seed-candidate-validation.js +0 -385
- package/dist/core-runtime/review/citation-audit.test.js +0 -165
- package/dist/core-runtime/review/execution-plan-resolver.js +0 -247
- package/dist/core-runtime/review/execution-plan-resolver.test.js +0 -243
- package/dist/core-runtime/review/execution-topology-resolver-axis-first.test.js +0 -246
- package/dist/core-runtime/review/execution-topology-resolver.js +0 -401
- package/dist/core-runtime/review/execution-topology-resolver.test.js +0 -315
- package/dist/core-runtime/review/inline-context-embedder.test.js +0 -154
- package/dist/core-runtime/review/legacy-mode-policy.js +0 -88
- package/dist/core-runtime/review/materializers-effort-persist.test.js +0 -79
- package/dist/core-runtime/review/ontology-path-classifier.js +0 -179
- package/dist/core-runtime/review/ontology-path-classifier.test.js +0 -216
- package/dist/core-runtime/review/packet-boundary-policy.test.js +0 -107
- package/dist/core-runtime/review/participating-lens-paths.test.js +0 -73
- package/dist/core-runtime/review/review-config-legacy-translate.js +0 -244
- package/dist/core-runtime/review/review-config-legacy-translate.test.js +0 -161
- package/dist/core-runtime/review/review-config-validator.js +0 -289
- package/dist/core-runtime/review/review-config-validator.test.js +0 -236
- package/dist/core-runtime/review/shape-pipeline-audit.test.js +0 -311
- package/dist/core-runtime/review/shape-to-topology-id.js +0 -117
- package/dist/core-runtime/review/shape-to-topology-id.test.js +0 -132
- package/dist/core-runtime/review/topology-shape-derivation.js +0 -155
- package/dist/core-runtime/review/topology-shape-derivation.test.js +0 -195
- package/dist/core-runtime/scope-runtime/constants.js +0 -12
- package/dist/core-runtime/scope-runtime/constraint-pool.js +0 -166
- package/dist/core-runtime/scope-runtime/constraint-pool.test.js +0 -674
- package/dist/core-runtime/scope-runtime/domain-validation-log.js +0 -135
- package/dist/core-runtime/scope-runtime/domain-validation-log.test.js +0 -156
- package/dist/core-runtime/scope-runtime/eval-persistence.js +0 -65
- package/dist/core-runtime/scope-runtime/eval-persistence.test.js +0 -84
- package/dist/core-runtime/scope-runtime/event-pipeline.js +0 -64
- package/dist/core-runtime/scope-runtime/event-pipeline.test.js +0 -450
- package/dist/core-runtime/scope-runtime/event-store.js +0 -39
- package/dist/core-runtime/scope-runtime/event-store.test.js +0 -95
- package/dist/core-runtime/scope-runtime/gate-guard.js +0 -348
- package/dist/core-runtime/scope-runtime/gate-guard.test.js +0 -1047
- package/dist/core-runtime/scope-runtime/hash.js +0 -4
- package/dist/core-runtime/scope-runtime/hash.test.js +0 -33
- package/dist/core-runtime/scope-runtime/id.js +0 -4
- package/dist/core-runtime/scope-runtime/id.test.js +0 -17
- package/dist/core-runtime/scope-runtime/reducer.js +0 -297
- package/dist/core-runtime/scope-runtime/reducer.test.js +0 -759
- package/dist/core-runtime/scope-runtime/scope-manager.js +0 -161
- package/dist/core-runtime/scope-runtime/state-machine.js +0 -309
- package/dist/core-runtime/scope-runtime/state-machine.test.js +0 -704
- package/dist/core-runtime/scope-runtime/types.js +0 -116
- package/dist/core-runtime/scope-runtime/types.test.js +0 -69
- package/dist/core-runtime/translate/render-for-user.js +0 -169
- package/dist/core-runtime/translate/render-for-user.test.js +0 -122
- package/dist/providers/capability-contract.js +0 -1
|
@@ -1,432 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Phase 3 Promote — Collector (Step 7).
|
|
3
|
-
*
|
|
4
|
-
* Design authority:
|
|
5
|
-
* - learn-phase3-design-v9.md (delta + DD-23)
|
|
6
|
-
* - learn-phase3-design-v6.md DD-18 §SST (candidate_items canonical definition)
|
|
7
|
-
* - learn-phase3-design-v5.md §5.1 (collector.ts skeleton)
|
|
8
|
-
* - learn-phase3-design-v5.md DD-10 (BaselineHash + freshness gate)
|
|
9
|
-
* - .onto/processes/learn/promote.md Step 1~2
|
|
10
|
-
* - learning-rules.md (file format)
|
|
11
|
-
*
|
|
12
|
-
* Responsibility:
|
|
13
|
-
* - Discover learning files (project + global) per CollectorMode.
|
|
14
|
-
* - Parse §1.3 lines into ParsedLearningItem (Phase 3 shape from promote/types.ts).
|
|
15
|
-
* - Capture BaselineHash (DD-10) for freshness re-check at Phase B.
|
|
16
|
-
* - Build candidate_items per DD-18 §SST table (mode-dispatched filter).
|
|
17
|
-
* - Return CollectionResult with project_items / global_items / candidate_items
|
|
18
|
-
* as separate canonical seats. Consumers MUST read candidate_items rather
|
|
19
|
-
* than re-deriving from project_items/global_items.
|
|
20
|
-
*
|
|
21
|
-
* Layering:
|
|
22
|
-
* - Phase A only (strict source-read-only). No mutation, no LLM calls.
|
|
23
|
-
* - Reuses TAG_PATTERN/SOURCE_PATTERN/CONTENT_CAPTURE from shared/patterns.ts.
|
|
24
|
-
* - File path resolution mirrors shared/paths.ts: bare-id .md files under
|
|
25
|
-
* `<root>/.onto/learnings/`. Phase 0 dual-read tolerates `onto_` legacy
|
|
26
|
-
* filenames during the migration window.
|
|
27
|
-
*
|
|
28
|
-
* Failure model:
|
|
29
|
-
* - Per-line parse failures append to parse_errors and the line is skipped.
|
|
30
|
-
* Collection itself does not throw; the caller decides whether parse_errors
|
|
31
|
-
* gates Phase A. v5 §5.1 explicitly returns parse failures rather than
|
|
32
|
-
* aborting the whole collection.
|
|
33
|
-
*/
|
|
34
|
-
import fs from "node:fs";
|
|
35
|
-
import path from "node:path";
|
|
36
|
-
import os from "node:os";
|
|
37
|
-
import crypto from "node:crypto";
|
|
38
|
-
import { ITEM_LINE_RE, SOURCE_PATTERN, } from "../shared/patterns.js";
|
|
39
|
-
// ---------------------------------------------------------------------------
|
|
40
|
-
// Path discovery
|
|
41
|
-
// ---------------------------------------------------------------------------
|
|
42
|
-
const LEARNINGS_SUBDIR = path.join(".onto", "learnings");
|
|
43
|
-
function getProjectLearningsDir(projectRoot) {
|
|
44
|
-
return path.join(projectRoot, LEARNINGS_SUBDIR);
|
|
45
|
-
}
|
|
46
|
-
function getGlobalLearningsDir() {
|
|
47
|
-
return path.join(os.homedir(), LEARNINGS_SUBDIR);
|
|
48
|
-
}
|
|
49
|
-
/**
|
|
50
|
-
* agent_id is the file basename without `.md`. Phase 0 dual-read accepts the
|
|
51
|
-
* legacy `onto_` prefix; canonical agent_id strips it so promote outputs join
|
|
52
|
-
* cleanly with the rest of the runtime.
|
|
53
|
-
*/
|
|
54
|
-
function deriveAgentId(filename) {
|
|
55
|
-
const base = filename.endsWith(".md") ? filename.slice(0, -3) : filename;
|
|
56
|
-
return base.startsWith("onto_") ? base.slice(5) : base;
|
|
57
|
-
}
|
|
58
|
-
function listLearningFiles(dir, scope) {
|
|
59
|
-
if (!fs.existsSync(dir))
|
|
60
|
-
return [];
|
|
61
|
-
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
62
|
-
const files = [];
|
|
63
|
-
for (const entry of entries) {
|
|
64
|
-
if (!entry.isFile())
|
|
65
|
-
continue;
|
|
66
|
-
if (!entry.name.endsWith(".md"))
|
|
67
|
-
continue;
|
|
68
|
-
files.push({
|
|
69
|
-
absolute_path: path.join(dir, entry.name),
|
|
70
|
-
agent_id: deriveAgentId(entry.name),
|
|
71
|
-
scope,
|
|
72
|
-
});
|
|
73
|
-
}
|
|
74
|
-
// Sort for deterministic baseline hash ordering.
|
|
75
|
-
files.sort((a, b) => a.absolute_path.localeCompare(b.absolute_path));
|
|
76
|
-
return files;
|
|
77
|
-
}
|
|
78
|
-
// ---------------------------------------------------------------------------
|
|
79
|
-
// Line parsing
|
|
80
|
-
// ---------------------------------------------------------------------------
|
|
81
|
-
const LEARNING_ID_COMMENT_RE = /<!--\s*learning_id:\s*(\w+)(?:\s+taxonomy_version:\s*[\w.-]+)?\s*-->/;
|
|
82
|
-
const EVENT_MARKER_COMMENT_RE = /<!--\s*(applied-then-found-invalid|observed-obsolete):\s*([^>]*?)\s*-->/g;
|
|
83
|
-
const RETENTION_CONFIRMED_RE = /<!--\s*retention-confirmed:\s*(\d{4}-\d{2}-\d{2})\s*-->/;
|
|
84
|
-
/**
|
|
85
|
-
* Extract applicability tags and role from the bracket-tag prefix of a line.
|
|
86
|
-
*
|
|
87
|
-
* §1.3 grammar:
|
|
88
|
-
* - [type] [methodology|domain/X]+ [role]? content (source: ...) [impact:...]
|
|
89
|
-
*
|
|
90
|
-
* The role bracket is optional. When [insight] appears it is preserved as-is
|
|
91
|
-
* because Phase 3 reclassify-insights (DD-9) needs to find it; Phase 1 loader's
|
|
92
|
-
* "insight → null" rewrite is intentionally NOT applied here.
|
|
93
|
-
*/
|
|
94
|
-
function extractApplicabilityAndRole(line) {
|
|
95
|
-
const applicability_tags = [];
|
|
96
|
-
let role = null;
|
|
97
|
-
const bracketRe = /\[([^\]]+)\]/g;
|
|
98
|
-
let match;
|
|
99
|
-
// Skip the first bracket which is the [type] discriminator.
|
|
100
|
-
let firstSeen = false;
|
|
101
|
-
while ((match = bracketRe.exec(line)) !== null) {
|
|
102
|
-
const value = match[1];
|
|
103
|
-
if (!firstSeen) {
|
|
104
|
-
firstSeen = true;
|
|
105
|
-
continue; // [fact] | [judgment]
|
|
106
|
-
}
|
|
107
|
-
if (value === "methodology" || value.startsWith("domain/")) {
|
|
108
|
-
applicability_tags.push(value);
|
|
109
|
-
continue;
|
|
110
|
-
}
|
|
111
|
-
if (value === "guardrail" ||
|
|
112
|
-
value === "foundation" ||
|
|
113
|
-
value === "convention" ||
|
|
114
|
-
value === "insight") {
|
|
115
|
-
role = value;
|
|
116
|
-
continue;
|
|
117
|
-
}
|
|
118
|
-
if (value.startsWith("impact:")) {
|
|
119
|
-
// impact handled by IMPACT_RE; bracket scan ignores it.
|
|
120
|
-
break;
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
return { applicability_tags, role };
|
|
124
|
-
}
|
|
125
|
-
/**
|
|
126
|
-
* Lenient §1.3 line parser.
|
|
127
|
-
*
|
|
128
|
-
* Phase 3 collector intentionally accepts BOTH strict Phase 2 output and
|
|
129
|
-
* pre-Phase 2 legacy lines: the whole point of promote is to review legacy
|
|
130
|
-
* items and elevate or retire them. Strict TAG_PATTERN would drop too much.
|
|
131
|
-
*
|
|
132
|
-
* Required: line begins with `- [fact]` / `- [judgment]` and at least one
|
|
133
|
-
* applicability tag.
|
|
134
|
-
*
|
|
135
|
-
* Best-effort: source metadata may be missing or use the pre-Phase 2 2-field
|
|
136
|
-
* shape `(source: <description>, <date>)`. Impact defaults to "normal" when
|
|
137
|
-
* absent. Trailing annotations (e.g., `(-> promoted to global, ...)`) are
|
|
138
|
-
* tolerated.
|
|
139
|
-
*
|
|
140
|
-
* parse_errors only fires when the line truly cannot be classified — i.e.,
|
|
141
|
-
* the type discriminator is missing or there is no usable applicability tag.
|
|
142
|
-
*/
|
|
143
|
-
function parseLearningLine(rawLine, agentId, scope, sourcePath, lineNumber) {
|
|
144
|
-
const typeMatch = rawLine.match(ITEM_LINE_RE);
|
|
145
|
-
if (!typeMatch) {
|
|
146
|
-
return { error: "line does not start with [fact] or [judgment] marker" };
|
|
147
|
-
}
|
|
148
|
-
const type = typeMatch[1];
|
|
149
|
-
const { applicability_tags, role } = extractApplicabilityAndRole(rawLine);
|
|
150
|
-
if (applicability_tags.length === 0) {
|
|
151
|
-
return { error: "no applicability tags ([methodology] or [domain/X])" };
|
|
152
|
-
}
|
|
153
|
-
const impactMatch = rawLine.match(/\[impact:(high|normal)\]/);
|
|
154
|
-
const impact = (impactMatch?.[1] ?? "normal");
|
|
155
|
-
// Source metadata: try strict 3-field shape first, fall back to 2-field
|
|
156
|
-
// legacy shape, fall back to null when absent entirely.
|
|
157
|
-
let source_project = null;
|
|
158
|
-
let source_domain = null;
|
|
159
|
-
let source_date = null;
|
|
160
|
-
const source3 = rawLine.match(SOURCE_PATTERN);
|
|
161
|
-
if (source3) {
|
|
162
|
-
source_project = source3[1].trim();
|
|
163
|
-
source_domain = source3[2].trim();
|
|
164
|
-
source_date = source3[3].trim();
|
|
165
|
-
}
|
|
166
|
-
else {
|
|
167
|
-
const source2 = rawLine.match(/\(source:\s*([^,]+),\s*(\d{4}-\d{2}-\d{2})\)/);
|
|
168
|
-
if (source2) {
|
|
169
|
-
source_project = source2[1].trim();
|
|
170
|
-
source_date = source2[2].trim();
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
// Content: strip the leading `- [type] [tags...] [role]?` prefix and the
|
|
174
|
-
// trailing `(source: ...)` / `[impact:...]` / `(-> ...)` annotations. The
|
|
175
|
-
// remainder is the human-readable body.
|
|
176
|
-
const content = extractContentBody(rawLine);
|
|
177
|
-
if (!content) {
|
|
178
|
-
return { error: "empty content body" };
|
|
179
|
-
}
|
|
180
|
-
return {
|
|
181
|
-
item: {
|
|
182
|
-
agent_id: agentId,
|
|
183
|
-
scope,
|
|
184
|
-
source_path: sourcePath,
|
|
185
|
-
raw_line: rawLine,
|
|
186
|
-
line_number: lineNumber,
|
|
187
|
-
type,
|
|
188
|
-
applicability_tags,
|
|
189
|
-
role,
|
|
190
|
-
content,
|
|
191
|
-
source_project,
|
|
192
|
-
source_domain,
|
|
193
|
-
source_date,
|
|
194
|
-
impact,
|
|
195
|
-
},
|
|
196
|
-
};
|
|
197
|
-
}
|
|
198
|
-
/**
|
|
199
|
-
* Strip the §1.3 wrapper and return just the content body.
|
|
200
|
-
*
|
|
201
|
-
* Strategy:
|
|
202
|
-
* 1. Drop the leading `- [type] [tag] [role]?` bracket prefix.
|
|
203
|
-
* 2. Drop everything from the first `(source: ...)` onward (which also
|
|
204
|
-
* removes trailing `(-> ...)` and `[impact:...]` annotations attached
|
|
205
|
-
* after the source clause).
|
|
206
|
-
* 3. Trim whitespace.
|
|
207
|
-
*
|
|
208
|
-
* If no source clause exists, also strip a trailing `[impact:...]` and any
|
|
209
|
-
* trailing `(-> ...)` notes so legacy lines without source still produce a
|
|
210
|
-
* clean body.
|
|
211
|
-
*/
|
|
212
|
-
function extractContentBody(rawLine) {
|
|
213
|
-
// Remove leading list marker.
|
|
214
|
-
let body = rawLine.replace(/^[-*+]\s+/, "");
|
|
215
|
-
// Remove leading bracket prefix: walk through consecutive `[...]` blocks.
|
|
216
|
-
while (true) {
|
|
217
|
-
const m = body.match(/^\[[^\]]+\]\s*/);
|
|
218
|
-
if (!m)
|
|
219
|
-
break;
|
|
220
|
-
body = body.slice(m[0].length);
|
|
221
|
-
}
|
|
222
|
-
// Cut at the first source clause if present.
|
|
223
|
-
const sourceIdx = body.indexOf("(source:");
|
|
224
|
-
if (sourceIdx >= 0) {
|
|
225
|
-
body = body.slice(0, sourceIdx);
|
|
226
|
-
}
|
|
227
|
-
else {
|
|
228
|
-
// No source clause: still strip trailing impact and `(-> ...)` notes.
|
|
229
|
-
body = body.replace(/\s*\[impact:(high|normal)\]\s*$/, "");
|
|
230
|
-
body = body.replace(/\s*\(->[^)]*\)\s*$/, "");
|
|
231
|
-
}
|
|
232
|
-
return body.trim();
|
|
233
|
-
}
|
|
234
|
-
function parseLearningFile(file) {
|
|
235
|
-
const buffer = fs.readFileSync(file.absolute_path);
|
|
236
|
-
const content = buffer.toString("utf8");
|
|
237
|
-
const lines = content.split("\n");
|
|
238
|
-
const items = [];
|
|
239
|
-
const errors = [];
|
|
240
|
-
for (let i = 0; i < lines.length; i++) {
|
|
241
|
-
const raw = lines[i];
|
|
242
|
-
const trimmed = raw.trim();
|
|
243
|
-
if (!trimmed)
|
|
244
|
-
continue;
|
|
245
|
-
if (trimmed.startsWith("#"))
|
|
246
|
-
continue; // markdown heading
|
|
247
|
-
if (trimmed.startsWith("<!--"))
|
|
248
|
-
continue; // top-of-file format marker
|
|
249
|
-
if (!/^[-*+]\s+\[/.test(trimmed))
|
|
250
|
-
continue;
|
|
251
|
-
const parsed = parseLearningLine(trimmed, file.agent_id, file.scope, file.absolute_path, i + 1);
|
|
252
|
-
if ("error" in parsed) {
|
|
253
|
-
errors.push({
|
|
254
|
-
source_path: file.absolute_path,
|
|
255
|
-
line_number: i + 1,
|
|
256
|
-
raw_line: trimmed,
|
|
257
|
-
error: parsed.error,
|
|
258
|
-
});
|
|
259
|
-
continue;
|
|
260
|
-
}
|
|
261
|
-
// Look ahead for trailing comment annotations attached to this learning.
|
|
262
|
-
let learning_id = null;
|
|
263
|
-
let retention_confirmed_at = null;
|
|
264
|
-
const event_markers = [];
|
|
265
|
-
let lookahead = i + 1;
|
|
266
|
-
while (lookahead < lines.length) {
|
|
267
|
-
const nextRaw = lines[lookahead].trim();
|
|
268
|
-
if (!nextRaw)
|
|
269
|
-
break;
|
|
270
|
-
if (!nextRaw.startsWith("<!--"))
|
|
271
|
-
break;
|
|
272
|
-
const idMatch = nextRaw.match(LEARNING_ID_COMMENT_RE);
|
|
273
|
-
if (idMatch) {
|
|
274
|
-
learning_id = idMatch[1];
|
|
275
|
-
lookahead++;
|
|
276
|
-
continue;
|
|
277
|
-
}
|
|
278
|
-
const retentionMatch = nextRaw.match(RETENTION_CONFIRMED_RE);
|
|
279
|
-
if (retentionMatch) {
|
|
280
|
-
retention_confirmed_at = retentionMatch[1];
|
|
281
|
-
lookahead++;
|
|
282
|
-
continue;
|
|
283
|
-
}
|
|
284
|
-
const markerRe = new RegExp(EVENT_MARKER_COMMENT_RE.source, "g");
|
|
285
|
-
let mm;
|
|
286
|
-
let isMarker = false;
|
|
287
|
-
while ((mm = markerRe.exec(nextRaw)) !== null) {
|
|
288
|
-
// Store the FULL marker comment text so retirement.ts can parse the
|
|
289
|
-
// date for retention-confirmed cutoff handling (DD-6 + promote.md §4a).
|
|
290
|
-
event_markers.push(mm[0]);
|
|
291
|
-
isMarker = true;
|
|
292
|
-
}
|
|
293
|
-
if (isMarker) {
|
|
294
|
-
lookahead++;
|
|
295
|
-
continue;
|
|
296
|
-
}
|
|
297
|
-
// Unrecognized comment — stop scanning so we don't swallow neighbours.
|
|
298
|
-
break;
|
|
299
|
-
}
|
|
300
|
-
items.push({
|
|
301
|
-
...parsed.item,
|
|
302
|
-
learning_id,
|
|
303
|
-
event_markers,
|
|
304
|
-
retention_confirmed_at,
|
|
305
|
-
});
|
|
306
|
-
}
|
|
307
|
-
const baseline = {
|
|
308
|
-
path: file.absolute_path,
|
|
309
|
-
scope: file.scope,
|
|
310
|
-
agent_id: file.agent_id,
|
|
311
|
-
size_bytes: buffer.byteLength,
|
|
312
|
-
content_sha256: crypto.createHash("sha256").update(buffer).digest("hex"),
|
|
313
|
-
line_count: lines.length,
|
|
314
|
-
};
|
|
315
|
-
return { items, errors, baseline };
|
|
316
|
-
}
|
|
317
|
-
// ---------------------------------------------------------------------------
|
|
318
|
-
// DD-18 §SST candidate selection (canonical definition — single seat)
|
|
319
|
-
// ---------------------------------------------------------------------------
|
|
320
|
-
/**
|
|
321
|
-
* DD-18 §SST canonical definition. This is the only place candidate_items is
|
|
322
|
-
* computed; consumers must read CollectionResult.candidate_items rather than
|
|
323
|
-
* recomputing it.
|
|
324
|
-
*
|
|
325
|
-
* | Mode | candidate_items |
|
|
326
|
-
* |----------------------|-------------------------------------------------------|
|
|
327
|
-
* | promote | project_items.filter(item => item.role !== "insight") |
|
|
328
|
-
* | reclassify-insights | global_items.filter(item => item.role === "insight") |
|
|
329
|
-
*/
|
|
330
|
-
function buildCandidateItems(mode, project_items, global_items) {
|
|
331
|
-
switch (mode) {
|
|
332
|
-
case "promote":
|
|
333
|
-
return project_items.filter((item) => item.role !== "insight");
|
|
334
|
-
case "reclassify-insights":
|
|
335
|
-
return global_items.filter((item) => item.role === "insight");
|
|
336
|
-
default: {
|
|
337
|
-
const _exhaustive = mode;
|
|
338
|
-
throw new Error(`Unknown CollectorMode: ${String(_exhaustive)}`);
|
|
339
|
-
}
|
|
340
|
-
}
|
|
341
|
-
}
|
|
342
|
-
export function collect(config) {
|
|
343
|
-
const collected_at = new Date().toISOString();
|
|
344
|
-
const projectFiles = listLearningFiles(getProjectLearningsDir(config.projectRoot), "project");
|
|
345
|
-
const globalFiles = listLearningFiles(getGlobalLearningsDir(), "global");
|
|
346
|
-
const project_items = [];
|
|
347
|
-
const global_items = [];
|
|
348
|
-
const parse_errors = [];
|
|
349
|
-
const baseline_files = [];
|
|
350
|
-
for (const file of projectFiles) {
|
|
351
|
-
const result = parseLearningFile(file);
|
|
352
|
-
project_items.push(...result.items);
|
|
353
|
-
parse_errors.push(...result.errors);
|
|
354
|
-
baseline_files.push(result.baseline);
|
|
355
|
-
}
|
|
356
|
-
for (const file of globalFiles) {
|
|
357
|
-
const result = parseLearningFile(file);
|
|
358
|
-
global_items.push(...result.items);
|
|
359
|
-
parse_errors.push(...result.errors);
|
|
360
|
-
baseline_files.push(result.baseline);
|
|
361
|
-
}
|
|
362
|
-
const candidate_items = buildCandidateItems(config.mode, project_items, global_items);
|
|
363
|
-
const baseline_hash = {
|
|
364
|
-
schema_version: "1",
|
|
365
|
-
source_scope: config.mode,
|
|
366
|
-
captured_at: collected_at,
|
|
367
|
-
files: baseline_files,
|
|
368
|
-
};
|
|
369
|
-
return {
|
|
370
|
-
schema_version: "1",
|
|
371
|
-
mode: config.mode,
|
|
372
|
-
collected_at,
|
|
373
|
-
project_items,
|
|
374
|
-
global_items,
|
|
375
|
-
candidate_items,
|
|
376
|
-
baseline_hash,
|
|
377
|
-
parse_errors,
|
|
378
|
-
};
|
|
379
|
-
}
|
|
380
|
-
/**
|
|
381
|
-
* Re-hash the files captured in a BaselineHash and report any mismatches.
|
|
382
|
-
*
|
|
383
|
-
* Phase B calls this before mutation to confirm the source files have not
|
|
384
|
-
* shifted between Phase A's collect() snapshot and the apply window.
|
|
385
|
-
*
|
|
386
|
-
* Returns an empty array when the baseline still holds. The caller decides
|
|
387
|
-
* whether to halt (default) or proceed with --force-stale.
|
|
388
|
-
*/
|
|
389
|
-
export function verifyBaselineHash(baseline) {
|
|
390
|
-
const mismatches = [];
|
|
391
|
-
for (const file of baseline.files) {
|
|
392
|
-
if (!fs.existsSync(file.path)) {
|
|
393
|
-
mismatches.push({
|
|
394
|
-
path: file.path,
|
|
395
|
-
reason: "file_missing",
|
|
396
|
-
expected: file.content_sha256,
|
|
397
|
-
actual: "<missing>",
|
|
398
|
-
});
|
|
399
|
-
continue;
|
|
400
|
-
}
|
|
401
|
-
const buffer = fs.readFileSync(file.path);
|
|
402
|
-
if (buffer.byteLength !== file.size_bytes) {
|
|
403
|
-
mismatches.push({
|
|
404
|
-
path: file.path,
|
|
405
|
-
reason: "size_changed",
|
|
406
|
-
expected: String(file.size_bytes),
|
|
407
|
-
actual: String(buffer.byteLength),
|
|
408
|
-
});
|
|
409
|
-
continue;
|
|
410
|
-
}
|
|
411
|
-
const sha = crypto.createHash("sha256").update(buffer).digest("hex");
|
|
412
|
-
if (sha !== file.content_sha256) {
|
|
413
|
-
mismatches.push({
|
|
414
|
-
path: file.path,
|
|
415
|
-
reason: "content_sha256_changed",
|
|
416
|
-
expected: file.content_sha256,
|
|
417
|
-
actual: sha,
|
|
418
|
-
});
|
|
419
|
-
continue;
|
|
420
|
-
}
|
|
421
|
-
const lineCount = buffer.toString("utf8").split("\n").length;
|
|
422
|
-
if (lineCount !== file.line_count) {
|
|
423
|
-
mismatches.push({
|
|
424
|
-
path: file.path,
|
|
425
|
-
reason: "line_count_changed",
|
|
426
|
-
expected: String(file.line_count),
|
|
427
|
-
actual: String(lineCount),
|
|
428
|
-
});
|
|
429
|
-
}
|
|
430
|
-
}
|
|
431
|
-
return mismatches;
|
|
432
|
-
}
|
|
@@ -1,125 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Phase 3 Promote — Degraded state aggregator (Step 9b).
|
|
3
|
-
*
|
|
4
|
-
* Design authority:
|
|
5
|
-
* - learn-phase3-design-v4.md DD-11 (degraded state taxonomy)
|
|
6
|
-
* - learn-phase3-design-v4.md DD-12 (panel_minimum_unmet hard gate)
|
|
7
|
-
*
|
|
8
|
-
* Responsibility:
|
|
9
|
-
* - Aggregate DegradedStateEntry records emitted by panel-reviewer,
|
|
10
|
-
* judgment-auditor, and the orchestrator into operator-friendly views.
|
|
11
|
-
* - Map DegradedStateKind → severity tier so the report can highlight
|
|
12
|
-
* hard-gate items (panel_minimum_unmet) above informational ones
|
|
13
|
-
* (criterion_6_waived).
|
|
14
|
-
* - Determine which candidates are blocked from the ordinary apply path —
|
|
15
|
-
* these surface in the user-approval section as "needs explicit decision".
|
|
16
|
-
*
|
|
17
|
-
* Scope:
|
|
18
|
-
* - This module owns no I/O and emits no degraded states itself. The
|
|
19
|
-
* types stay in promote/types.ts so emitter modules can construct entries
|
|
20
|
-
* without depending on this aggregator. Aggregation is a one-way
|
|
21
|
-
* downstream operation from emitters into PromoteReport assembly.
|
|
22
|
-
*
|
|
23
|
-
* Severity tiers (axis = "what does the operator do?"):
|
|
24
|
-
* - blocking: candidate cannot follow the ordinary apply path; explicit
|
|
25
|
-
* review or waiver is required.
|
|
26
|
-
* - degraded: review still possible but with reduced confidence; the
|
|
27
|
-
* report should annotate the affected candidates but not block them.
|
|
28
|
-
* - informational: surfaced for transparency; no action required.
|
|
29
|
-
*/
|
|
30
|
-
const SEVERITY_BY_KIND = {
|
|
31
|
-
panel_minimum_unmet: "blocking",
|
|
32
|
-
panel_contract_invalid: "degraded",
|
|
33
|
-
member_unreachable: "degraded",
|
|
34
|
-
criterion_6_blocked: "degraded",
|
|
35
|
-
criterion_6_waived: "informational",
|
|
36
|
-
stale_baseline: "blocking",
|
|
37
|
-
};
|
|
38
|
-
export function severityOf(kind) {
|
|
39
|
-
return SEVERITY_BY_KIND[kind];
|
|
40
|
-
}
|
|
41
|
-
/**
|
|
42
|
-
* Group entries by kind, preserving insertion order within each group so the
|
|
43
|
-
* timeline of when each degraded state surfaced is recoverable.
|
|
44
|
-
*/
|
|
45
|
-
export function groupByKind(entries) {
|
|
46
|
-
const buckets = new Map();
|
|
47
|
-
for (const e of entries) {
|
|
48
|
-
const arr = buckets.get(e.kind) ?? [];
|
|
49
|
-
arr.push(e);
|
|
50
|
-
buckets.set(e.kind, arr);
|
|
51
|
-
}
|
|
52
|
-
return Array.from(buckets.entries()).map(([kind, list]) => ({
|
|
53
|
-
kind,
|
|
54
|
-
severity: severityOf(kind),
|
|
55
|
-
count: list.length,
|
|
56
|
-
entries: list,
|
|
57
|
-
}));
|
|
58
|
-
}
|
|
59
|
-
/**
|
|
60
|
-
* Collect candidate ids that are blocked from the ordinary apply path.
|
|
61
|
-
*
|
|
62
|
-
* DD-12 hard gate: any candidate touched by a `panel_minimum_unmet` entry is
|
|
63
|
-
* blocked. `stale_baseline` is also blocking but is session-wide rather than
|
|
64
|
-
* per-candidate, so it does not contribute candidate ids here — the
|
|
65
|
-
* orchestrator surfaces it as a top-level abort.
|
|
66
|
-
*/
|
|
67
|
-
export function collectBlockedCandidates(entries) {
|
|
68
|
-
const blocked = new Set();
|
|
69
|
-
for (const e of entries) {
|
|
70
|
-
if (e.kind !== "panel_minimum_unmet")
|
|
71
|
-
continue;
|
|
72
|
-
for (const id of e.affected_candidates ?? []) {
|
|
73
|
-
blocked.add(id);
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
return [...blocked].sort();
|
|
77
|
-
}
|
|
78
|
-
/**
|
|
79
|
-
* Roll up the full degraded-state picture into a summary block ready for
|
|
80
|
-
* inclusion in PromoteReport assembly.
|
|
81
|
-
*/
|
|
82
|
-
export function summarizeDegradedStates(entries) {
|
|
83
|
-
const by_kind = groupByKind(entries);
|
|
84
|
-
let blocking_count = 0;
|
|
85
|
-
let degraded_count = 0;
|
|
86
|
-
let informational_count = 0;
|
|
87
|
-
for (const g of by_kind) {
|
|
88
|
-
if (g.severity === "blocking")
|
|
89
|
-
blocking_count += g.count;
|
|
90
|
-
else if (g.severity === "degraded")
|
|
91
|
-
degraded_count += g.count;
|
|
92
|
-
else
|
|
93
|
-
informational_count += g.count;
|
|
94
|
-
}
|
|
95
|
-
return {
|
|
96
|
-
total: entries.length,
|
|
97
|
-
blocking_count,
|
|
98
|
-
degraded_count,
|
|
99
|
-
informational_count,
|
|
100
|
-
by_kind,
|
|
101
|
-
blocked_candidate_ids: collectBlockedCandidates(entries),
|
|
102
|
-
};
|
|
103
|
-
}
|
|
104
|
-
// ---------------------------------------------------------------------------
|
|
105
|
-
// Stable-baseline helper (called by promoter / promote-executor)
|
|
106
|
-
// ---------------------------------------------------------------------------
|
|
107
|
-
/**
|
|
108
|
-
* Construct a `stale_baseline` entry from verifyBaselineHash() mismatches.
|
|
109
|
-
*
|
|
110
|
-
* The orchestrator calls verifyBaselineHash() on Phase B entry and converts
|
|
111
|
-
* any mismatches into a single degraded state entry — the entry is itself a
|
|
112
|
-
* blocking gate that aborts the apply path unless --force-stale is set.
|
|
113
|
-
*/
|
|
114
|
-
export function buildStaleBaselineEntry(mismatches) {
|
|
115
|
-
const detail = mismatches.length === 0
|
|
116
|
-
? "no mismatches (defensive entry)"
|
|
117
|
-
: mismatches
|
|
118
|
-
.map((m) => `${m.path}: ${m.reason}`)
|
|
119
|
-
.join("; ");
|
|
120
|
-
return {
|
|
121
|
-
kind: "stale_baseline",
|
|
122
|
-
detail,
|
|
123
|
-
occurred_at: new Date().toISOString(),
|
|
124
|
-
};
|
|
125
|
-
}
|