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,81 +0,0 @@
|
|
|
1
|
-
import fs from "node:fs";
|
|
2
|
-
import path from "node:path";
|
|
3
|
-
import { fileURLToPath } from "node:url";
|
|
4
|
-
import { describe, it, expect } from "vitest";
|
|
5
|
-
import { canonicalizeLensId, loadCoreLensRegistry } from "./lens-registry.js";
|
|
6
|
-
function resolveRegistryPath() {
|
|
7
|
-
const here = path.dirname(fileURLToPath(import.meta.url));
|
|
8
|
-
let cur = here;
|
|
9
|
-
const root = path.parse(cur).root;
|
|
10
|
-
while (cur !== root) {
|
|
11
|
-
const candidate = path.join(cur, ".onto", "authority", "core-lens-registry.yaml");
|
|
12
|
-
if (fs.existsSync(candidate))
|
|
13
|
-
return candidate;
|
|
14
|
-
cur = path.dirname(cur);
|
|
15
|
-
}
|
|
16
|
-
throw new Error(".onto/authority/core-lens-registry.yaml not found");
|
|
17
|
-
}
|
|
18
|
-
describe("canonicalizeLensId — Phase 0 dual-read (W-A-01)", () => {
|
|
19
|
-
it("strips onto_ prefix from legacy IDs", () => {
|
|
20
|
-
expect(canonicalizeLensId("onto_logic")).toBe("logic");
|
|
21
|
-
expect(canonicalizeLensId("onto_axiology")).toBe("axiology");
|
|
22
|
-
expect(canonicalizeLensId("onto_synthesize")).toBe("synthesize");
|
|
23
|
-
});
|
|
24
|
-
it("is idempotent — bare IDs pass through unchanged", () => {
|
|
25
|
-
expect(canonicalizeLensId("logic")).toBe("logic");
|
|
26
|
-
expect(canonicalizeLensId("axiology")).toBe("axiology");
|
|
27
|
-
expect(canonicalizeLensId("synthesize")).toBe("synthesize");
|
|
28
|
-
});
|
|
29
|
-
it("handles all 10 rename targets", () => {
|
|
30
|
-
const targets = [
|
|
31
|
-
"logic", "structure", "dependency", "semantics", "pragmatics",
|
|
32
|
-
"evolution", "coverage", "conciseness", "axiology", "synthesize",
|
|
33
|
-
];
|
|
34
|
-
for (const bare of targets) {
|
|
35
|
-
expect(canonicalizeLensId(`onto_${bare}`)).toBe(bare);
|
|
36
|
-
expect(canonicalizeLensId(bare)).toBe(bare);
|
|
37
|
-
}
|
|
38
|
-
});
|
|
39
|
-
it("does not strip prefix when not exact onto_ match", () => {
|
|
40
|
-
expect(canonicalizeLensId("ontology")).toBe("ontology");
|
|
41
|
-
expect(canonicalizeLensId("onto-logic")).toBe("onto-logic");
|
|
42
|
-
expect(canonicalizeLensId("custom_logic")).toBe("custom_logic");
|
|
43
|
-
});
|
|
44
|
-
});
|
|
45
|
-
describe("loadCoreLensRegistry — core-axis composition contract (v0.2.1)", () => {
|
|
46
|
-
// These assertions lock the v0.2.1 cost-constrained Pareto-optimal
|
|
47
|
-
// composition into a test so that any future registry edit that changes
|
|
48
|
-
// the core-axis set must also update this test (intentional checkpoint).
|
|
49
|
-
// SSOT: .onto/authority/core-lens-registry.yaml; empirical basis:
|
|
50
|
-
// development-records/benchmark/20260419-lens-contribution-analysis.md.
|
|
51
|
-
const registry = loadCoreLensRegistry();
|
|
52
|
-
it("core_axis_lens_ids contains exactly the v0.2.1 6-lens set", () => {
|
|
53
|
-
expect(registry.core_axis_lens_ids).toHaveLength(6);
|
|
54
|
-
expect([...registry.core_axis_lens_ids].sort()).toEqual([
|
|
55
|
-
"axiology",
|
|
56
|
-
"coverage",
|
|
57
|
-
"evolution",
|
|
58
|
-
"logic",
|
|
59
|
-
"semantics",
|
|
60
|
-
"structure",
|
|
61
|
-
]);
|
|
62
|
-
});
|
|
63
|
-
it("full_review_lens_ids remains 9-lens", () => {
|
|
64
|
-
expect(registry.full_review_lens_ids).toHaveLength(9);
|
|
65
|
-
});
|
|
66
|
-
it("always_include_lens_ids is [axiology]", () => {
|
|
67
|
-
expect(registry.always_include_lens_ids).toEqual(["axiology"]);
|
|
68
|
-
});
|
|
69
|
-
it("every always_include lens is present in core_axis composition", () => {
|
|
70
|
-
for (const id of registry.always_include_lens_ids) {
|
|
71
|
-
expect(registry.core_axis_lens_ids).toContain(id);
|
|
72
|
-
}
|
|
73
|
-
});
|
|
74
|
-
// F-E1 (2nd review): loader currently does not consume `schema_version`.
|
|
75
|
-
// Assert the raw field exists at the registry seat — forces any future
|
|
76
|
-
// recomposition to bump the field together with contents.
|
|
77
|
-
it("registry file declares schema_version: 2 (raw-text guard)", () => {
|
|
78
|
-
const text = fs.readFileSync(resolveRegistryPath(), "utf8");
|
|
79
|
-
expect(text).toMatch(/^schema_version:\s*2\b/m);
|
|
80
|
-
});
|
|
81
|
-
});
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it } from "vitest";
|
|
2
|
-
import { startsWithDirPrefix } from "./path-normalization.js";
|
|
3
|
-
describe("startsWithDirPrefix — segment-bound check", () => {
|
|
4
|
-
it("matches exact segment boundary with trailing slash", () => {
|
|
5
|
-
expect(startsWithDirPrefix(".onto/principles/foo.md", ".onto/principles/")).toBe(true);
|
|
6
|
-
expect(startsWithDirPrefix(".onto/principles/sub/bar.md", ".onto/principles")).toBe(true);
|
|
7
|
-
});
|
|
8
|
-
it("rejects mid-segment prefix collision", () => {
|
|
9
|
-
expect(startsWithDirPrefix(".onto/principlesABC/foo.md", ".onto/principles")).toBe(false);
|
|
10
|
-
expect(startsWithDirPrefix(".onto/principles_backup/foo.md", ".onto/principles")).toBe(false);
|
|
11
|
-
expect(startsWithDirPrefix(".onto/authorityX/foo.md", ".onto/authority")).toBe(false);
|
|
12
|
-
});
|
|
13
|
-
it("rejects the directory itself (must be a path under the directory)", () => {
|
|
14
|
-
expect(startsWithDirPrefix(".onto/principles", ".onto/principles")).toBe(false);
|
|
15
|
-
expect(startsWithDirPrefix(".onto/principles/", ".onto/principles")).toBe(false);
|
|
16
|
-
});
|
|
17
|
-
it("treats trailing slash in `dir` argument uniformly", () => {
|
|
18
|
-
const p = ".onto/principles/foo.md";
|
|
19
|
-
expect(startsWithDirPrefix(p, ".onto/principles")).toBe(true);
|
|
20
|
-
expect(startsWithDirPrefix(p, ".onto/principles/")).toBe(true);
|
|
21
|
-
});
|
|
22
|
-
});
|
|
@@ -1,72 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Plugin install path resolver.
|
|
3
|
-
*
|
|
4
|
-
* onto's canonical authority files (process.md, .onto/processes/, learning-rules.md,
|
|
5
|
-
* .onto/roles/, etc.) are read at runtime from the install location. The path
|
|
6
|
-
* resolution must support multiple install scenarios:
|
|
7
|
-
*
|
|
8
|
-
* 1. Claude Code plugin install: `~/.claude/plugins/onto/`
|
|
9
|
-
* 2. Standalone clone + symlink: arbitrary path
|
|
10
|
-
* 3. Repo development: the repo itself is the plugin
|
|
11
|
-
*
|
|
12
|
-
* # Resolution priority (highest first)
|
|
13
|
-
*
|
|
14
|
-
* 1. ONTO_PLUGIN_DIR env var (explicit override)
|
|
15
|
-
* 2. ~/.claude/plugins/onto/ (Claude Code install default)
|
|
16
|
-
* 3. (None) → returns null; caller decides its explicit default
|
|
17
|
-
*
|
|
18
|
-
* # Why no automatic repo-relative default
|
|
19
|
-
*
|
|
20
|
-
* Repo-relative paths are correct only during local dev. In production
|
|
21
|
-
* (npm-installed CLI, Claude Code plugin), the plugin lives elsewhere.
|
|
22
|
-
* Returning null when no install is detected lets the caller emit a clear
|
|
23
|
-
* "set ONTO_PLUGIN_DIR or install via /plugin install" error rather than
|
|
24
|
-
* silently using the wrong source tree.
|
|
25
|
-
*/
|
|
26
|
-
import fsSync from "node:fs";
|
|
27
|
-
import os from "node:os";
|
|
28
|
-
import path from "node:path";
|
|
29
|
-
export const ENV_ONTO_PLUGIN_DIR = "ONTO_PLUGIN_DIR";
|
|
30
|
-
/** The default Claude Code plugin install location. */
|
|
31
|
-
export const CLAUDE_CODE_PLUGIN_DEFAULT_PATH = path.join(os.homedir(), ".claude", "plugins", "onto");
|
|
32
|
-
/**
|
|
33
|
-
* Resolve the onto plugin install directory.
|
|
34
|
-
*
|
|
35
|
-
* Returns null when no install is found. Callers in the plugin's own runtime
|
|
36
|
-
* (where __dirname can locate the source) may use repo-relative paths as a
|
|
37
|
-
* default; documentation reads should error out when this returns null.
|
|
38
|
-
*/
|
|
39
|
-
export function resolvePluginPath() {
|
|
40
|
-
const envOverride = process.env[ENV_ONTO_PLUGIN_DIR];
|
|
41
|
-
if (typeof envOverride === "string" && envOverride.length > 0) {
|
|
42
|
-
const expanded = expandHome(envOverride);
|
|
43
|
-
return { pluginDir: expanded, source: "env_override" };
|
|
44
|
-
}
|
|
45
|
-
if (fsSync.existsSync(CLAUDE_CODE_PLUGIN_DEFAULT_PATH)) {
|
|
46
|
-
return {
|
|
47
|
-
pluginDir: CLAUDE_CODE_PLUGIN_DEFAULT_PATH,
|
|
48
|
-
source: "claude_code_install_default",
|
|
49
|
-
};
|
|
50
|
-
}
|
|
51
|
-
return null;
|
|
52
|
-
}
|
|
53
|
-
/**
|
|
54
|
-
* Resolve a plugin-relative path. Returns null when the plugin install is
|
|
55
|
-
* not found.
|
|
56
|
-
*
|
|
57
|
-
* Example: `resolvePluginRelativePath(".onto/processes/reconstruct.md")` returns
|
|
58
|
-
* `/home/user/.claude/plugins/onto/.onto/processes/reconstruct.md` (or whatever
|
|
59
|
-
* `ONTO_PLUGIN_DIR` resolves to).
|
|
60
|
-
*/
|
|
61
|
-
export function resolvePluginRelativePath(relativePath) {
|
|
62
|
-
const resolution = resolvePluginPath();
|
|
63
|
-
if (!resolution)
|
|
64
|
-
return null;
|
|
65
|
-
return path.join(resolution.pluginDir, relativePath);
|
|
66
|
-
}
|
|
67
|
-
function expandHome(p) {
|
|
68
|
-
if (p.startsWith("~/") || p === "~") {
|
|
69
|
-
return path.join(os.homedir(), p.slice(p === "~" ? 1 : 2));
|
|
70
|
-
}
|
|
71
|
-
return p;
|
|
72
|
-
}
|
|
@@ -1,95 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect, beforeEach, afterEach } from "vitest";
|
|
2
|
-
import { mkdirSync, mkdtempSync, rmSync } from "node:fs";
|
|
3
|
-
import { tmpdir } from "node:os";
|
|
4
|
-
import path from "node:path";
|
|
5
|
-
import { resolvePluginPath, resolvePluginRelativePath, ENV_ONTO_PLUGIN_DIR, } from "./plugin-path.js";
|
|
6
|
-
let savedEnvOverride;
|
|
7
|
-
let savedHomeOverride;
|
|
8
|
-
let scratchDir;
|
|
9
|
-
beforeEach(() => {
|
|
10
|
-
savedEnvOverride = process.env[ENV_ONTO_PLUGIN_DIR];
|
|
11
|
-
delete process.env[ENV_ONTO_PLUGIN_DIR];
|
|
12
|
-
// Redirect HOME to a scratch dir so the real ~/.claude/plugins/onto/ doesn't
|
|
13
|
-
// accidentally satisfy the default-detection branch.
|
|
14
|
-
savedHomeOverride = process.env.HOME;
|
|
15
|
-
scratchDir = mkdtempSync(path.join(tmpdir(), "plugin-path-test-"));
|
|
16
|
-
process.env.HOME = scratchDir;
|
|
17
|
-
});
|
|
18
|
-
afterEach(() => {
|
|
19
|
-
if (savedEnvOverride === undefined) {
|
|
20
|
-
delete process.env[ENV_ONTO_PLUGIN_DIR];
|
|
21
|
-
}
|
|
22
|
-
else {
|
|
23
|
-
process.env[ENV_ONTO_PLUGIN_DIR] = savedEnvOverride;
|
|
24
|
-
}
|
|
25
|
-
if (savedHomeOverride === undefined) {
|
|
26
|
-
delete process.env.HOME;
|
|
27
|
-
}
|
|
28
|
-
else {
|
|
29
|
-
process.env.HOME = savedHomeOverride;
|
|
30
|
-
}
|
|
31
|
-
try {
|
|
32
|
-
rmSync(scratchDir, { recursive: true, force: true });
|
|
33
|
-
}
|
|
34
|
-
catch { }
|
|
35
|
-
});
|
|
36
|
-
describe("resolvePluginPath", () => {
|
|
37
|
-
it("returns null when no env override and no Claude install present", () => {
|
|
38
|
-
// os.homedir() typically caches HOME at process start, so resolvePluginPath
|
|
39
|
-
// may still see the original ~/.claude/plugins/onto/ if it exists.
|
|
40
|
-
// This test asserts the env-override priority over both, by NOT setting it.
|
|
41
|
-
// The base-case "returns null" is harder to assert in environments where
|
|
42
|
-
// ~/.claude/plugins/onto/ exists; we only assert the absence of env crash.
|
|
43
|
-
const result = resolvePluginPath();
|
|
44
|
-
// Either null (clean env) or claude_code_install_default (real install)
|
|
45
|
-
if (result !== null) {
|
|
46
|
-
expect(result.source).toBe("claude_code_install_default");
|
|
47
|
-
}
|
|
48
|
-
});
|
|
49
|
-
it("env override beats default detection", () => {
|
|
50
|
-
const overridePath = mkdtempSync(path.join(tmpdir(), "onto-plugin-override-"));
|
|
51
|
-
try {
|
|
52
|
-
process.env[ENV_ONTO_PLUGIN_DIR] = overridePath;
|
|
53
|
-
const result = resolvePluginPath();
|
|
54
|
-
expect(result).not.toBeNull();
|
|
55
|
-
expect(result.pluginDir).toBe(overridePath);
|
|
56
|
-
expect(result.source).toBe("env_override");
|
|
57
|
-
}
|
|
58
|
-
finally {
|
|
59
|
-
rmSync(overridePath, { recursive: true, force: true });
|
|
60
|
-
}
|
|
61
|
-
});
|
|
62
|
-
it("env override expands ~ to HOME", () => {
|
|
63
|
-
// Create a fake plugin dir under the scratched HOME.
|
|
64
|
-
const fakePluginDir = path.join(scratchDir, "myplugin");
|
|
65
|
-
mkdirSync(fakePluginDir, { recursive: true });
|
|
66
|
-
process.env[ENV_ONTO_PLUGIN_DIR] = "~/myplugin";
|
|
67
|
-
const result = resolvePluginPath();
|
|
68
|
-
expect(result).not.toBeNull();
|
|
69
|
-
expect(result.pluginDir).toBe(fakePluginDir);
|
|
70
|
-
expect(result.source).toBe("env_override");
|
|
71
|
-
});
|
|
72
|
-
});
|
|
73
|
-
describe("resolvePluginRelativePath", () => {
|
|
74
|
-
it("appends relative path to resolved plugin dir", () => {
|
|
75
|
-
const overridePath = mkdtempSync(path.join(tmpdir(), "onto-plugin-rel-"));
|
|
76
|
-
try {
|
|
77
|
-
process.env[ENV_ONTO_PLUGIN_DIR] = overridePath;
|
|
78
|
-
const result = resolvePluginRelativePath(".onto/processes/reconstruct.md");
|
|
79
|
-
expect(result).toBe(path.join(overridePath, ".onto/processes/reconstruct.md"));
|
|
80
|
-
}
|
|
81
|
-
finally {
|
|
82
|
-
rmSync(overridePath, { recursive: true, force: true });
|
|
83
|
-
}
|
|
84
|
-
});
|
|
85
|
-
it("returns null when plugin path cannot be resolved (env unset, no install)", () => {
|
|
86
|
-
// Skip if real ~/.claude/plugins/onto/ exists in the test runner env.
|
|
87
|
-
// We can't reliably test the "returns null" branch in CI environments
|
|
88
|
-
// where Claude Code is installed.
|
|
89
|
-
const result = resolvePluginRelativePath(".onto/processes/reconstruct.md");
|
|
90
|
-
if (result !== null) {
|
|
91
|
-
// Real install present — verify it ends with the relative path.
|
|
92
|
-
expect(result.endsWith(".onto/processes/reconstruct.md")).toBe(true);
|
|
93
|
-
}
|
|
94
|
-
});
|
|
95
|
-
});
|
|
@@ -1,344 +0,0 @@
|
|
|
1
|
-
import { isEvidenceUnverified } from "../../../../scope-runtime/types.js";
|
|
2
|
-
// ─── Main ───
|
|
3
|
-
/**
|
|
4
|
-
* Run Compile Defense — 2-layer verification.
|
|
5
|
-
*
|
|
6
|
-
* Layer 1 (Checklist): Every non-invalidated constraint is in Section 3.
|
|
7
|
-
* Layer 2 (Audit Pass): inject reflected, defer non-interfering,
|
|
8
|
-
* override non-reflected, traceability chain CST→IMPL→CHG→VAL complete.
|
|
9
|
-
*
|
|
10
|
-
* Pure function: no side effects.
|
|
11
|
-
*/
|
|
12
|
-
export function compileDefense(state, buildSpec, deltaSet, validationPlan, brownfieldDetail, brownfieldContext) {
|
|
13
|
-
const violations = [];
|
|
14
|
-
const warnings = [];
|
|
15
|
-
checkLayer1(state, buildSpec, violations);
|
|
16
|
-
checkLayer2(state, buildSpec, deltaSet, validationPlan, violations);
|
|
17
|
-
checkLayer3(state, buildSpec, deltaSet, brownfieldDetail, brownfieldContext, warnings);
|
|
18
|
-
const errors = violations;
|
|
19
|
-
if (errors.length === 0) {
|
|
20
|
-
return { passed: true, warnings };
|
|
21
|
-
}
|
|
22
|
-
return { passed: false, violations: errors, warnings };
|
|
23
|
-
}
|
|
24
|
-
// ─── Layer 1: Checklist ───
|
|
25
|
-
function checkLayer1(state, buildSpec, violations) {
|
|
26
|
-
const section3Ids = new Set(buildSpec.section3.map((e) => e.constraint_id));
|
|
27
|
-
for (const c of state.constraint_pool.constraints) {
|
|
28
|
-
if (c.status === "invalidated")
|
|
29
|
-
continue;
|
|
30
|
-
if (!section3Ids.has(c.constraint_id)) {
|
|
31
|
-
violations.push({
|
|
32
|
-
rule: "L1-checklist",
|
|
33
|
-
detail: `${c.constraint_id ?? "UNKNOWN-CST"} is not referenced in Build Spec Section 3`,
|
|
34
|
-
});
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
// ─── Layer 2: Audit Pass ───
|
|
39
|
-
function checkLayer2(state, buildSpec, deltaSet, validationPlan, violations) {
|
|
40
|
-
const implIds = new Set(buildSpec.section4.map((e) => e.impl_id));
|
|
41
|
-
const changeCstIds = new Set(deltaSet.changes.flatMap((c) => c.related_cst));
|
|
42
|
-
const changeFilePaths = new Set(deltaSet.changes.map((c) => normalizeFilePath(c.file_path)));
|
|
43
|
-
const valCstIds = new Set(validationPlan.map((v) => v.related_cst));
|
|
44
|
-
for (const c of state.constraint_pool.constraints) {
|
|
45
|
-
if (c.status === "invalidated")
|
|
46
|
-
continue;
|
|
47
|
-
const decision = c.decision;
|
|
48
|
-
if (!decision)
|
|
49
|
-
continue;
|
|
50
|
-
switch (decision) {
|
|
51
|
-
case "inject":
|
|
52
|
-
checkInjectReflected(c, buildSpec, implIds, changeCstIds, valCstIds, violations);
|
|
53
|
-
break;
|
|
54
|
-
case "defer":
|
|
55
|
-
checkDeferNonInterfering(c, deltaSet, changeFilePaths, violations);
|
|
56
|
-
break;
|
|
57
|
-
case "override":
|
|
58
|
-
checkOverrideNonReflected(c, deltaSet, changeFilePaths, violations);
|
|
59
|
-
break;
|
|
60
|
-
default:
|
|
61
|
-
violations.push({
|
|
62
|
-
rule: "L2-decision-unexpected",
|
|
63
|
-
detail: `${c.constraint_id ?? "UNKNOWN-CST"} has unexpected decision "${decision ?? "UNKNOWN"}" at compile time`,
|
|
64
|
-
});
|
|
65
|
-
break;
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
// Traceability chain: every IMPL has at least one CHG
|
|
69
|
-
checkImplHasChanges(buildSpec, deltaSet, violations);
|
|
70
|
-
// Reverse traceability: every CHG.related_impl references a valid IMPL
|
|
71
|
-
checkChangesReferenceValidImpls(buildSpec, deltaSet, implIds, violations);
|
|
72
|
-
// inject constraints should have edge cases in validation plan
|
|
73
|
-
checkInjectEdgeCases(state, validationPlan, violations);
|
|
74
|
-
}
|
|
75
|
-
/** inject → must have IMPL, CHG referencing this CST, and VAL item */
|
|
76
|
-
function checkInjectReflected(c, buildSpec, implIds, changeCstIds, valCstIds, violations) {
|
|
77
|
-
// CST → IMPL
|
|
78
|
-
const relatedImpls = buildSpec.section4.filter((impl) => impl.related_cst.includes(c.constraint_id));
|
|
79
|
-
if (relatedImpls.length === 0) {
|
|
80
|
-
violations.push({
|
|
81
|
-
rule: "L2-inject-impl",
|
|
82
|
-
detail: `${c.constraint_id ?? "UNKNOWN-CST"} (inject) has no IMPL in Section 4`,
|
|
83
|
-
});
|
|
84
|
-
}
|
|
85
|
-
// CST → CHG
|
|
86
|
-
if (!changeCstIds.has(c.constraint_id)) {
|
|
87
|
-
violations.push({
|
|
88
|
-
rule: "L2-inject-chg",
|
|
89
|
-
detail: `${c.constraint_id ?? "UNKNOWN-CST"} (inject) has no CHG in delta-set`,
|
|
90
|
-
});
|
|
91
|
-
}
|
|
92
|
-
// CST → VAL
|
|
93
|
-
if (!valCstIds.has(c.constraint_id)) {
|
|
94
|
-
violations.push({
|
|
95
|
-
rule: "L2-inject-val",
|
|
96
|
-
detail: `${c.constraint_id ?? "UNKNOWN-CST"} (inject) has no VAL in validation-plan`,
|
|
97
|
-
});
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
/** defer → source_refs files must not appear in delta-set changes */
|
|
101
|
-
function checkDeferNonInterfering(c, deltaSet, changeFilePaths, violations) {
|
|
102
|
-
for (const ref of c.source_refs) {
|
|
103
|
-
if (changeFilePaths.has(normalizeFilePath(ref.source))) {
|
|
104
|
-
violations.push({
|
|
105
|
-
rule: "L2-defer-interfere",
|
|
106
|
-
detail: `${c.constraint_id ?? "UNKNOWN-CST"} (defer) source_ref "${ref.source ?? "UNKNOWN"}" is modified in delta-set. 간섭 여부를 확인하세요.`,
|
|
107
|
-
});
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
/** override → source_refs files must not have changes related to this CST */
|
|
112
|
-
function checkOverrideNonReflected(c, deltaSet, changeFilePaths, violations) {
|
|
113
|
-
for (const change of deltaSet.changes) {
|
|
114
|
-
if (change.related_cst.includes(c.constraint_id) &&
|
|
115
|
-
c.source_refs.some((ref) => normalizeFilePath(ref.source) === normalizeFilePath(change.file_path))) {
|
|
116
|
-
violations.push({
|
|
117
|
-
rule: "L2-override-reflected",
|
|
118
|
-
detail: `${c.constraint_id ?? "UNKNOWN-CST"} (override) is reflected in delta-set change ${change.change_id ?? "UNKNOWN-CHG"}`,
|
|
119
|
-
});
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
/** Every CHG with non-empty related_impl must reference valid IMPLs in Section 4 */
|
|
124
|
-
function checkChangesReferenceValidImpls(buildSpec, deltaSet, implIds, violations) {
|
|
125
|
-
for (const change of deltaSet.changes) {
|
|
126
|
-
// CHG with empty related_impl is allowed (e.g. defer/override context changes)
|
|
127
|
-
if (change.related_impl.length === 0)
|
|
128
|
-
continue;
|
|
129
|
-
for (const implId of change.related_impl) {
|
|
130
|
-
if (!implIds.has(implId)) {
|
|
131
|
-
violations.push({
|
|
132
|
-
rule: "L2-chg-orphan-impl",
|
|
133
|
-
detail: `${change.change_id ?? "UNKNOWN-CHG"} references ${implId ?? "UNKNOWN-IMPL"} which does not exist in Section 4`,
|
|
134
|
-
});
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
/** Every IMPL must have at least one CHG */
|
|
140
|
-
function checkImplHasChanges(buildSpec, deltaSet, violations) {
|
|
141
|
-
const implsWithChanges = new Set(deltaSet.changes.flatMap((c) => c.related_impl));
|
|
142
|
-
for (const impl of buildSpec.section4) {
|
|
143
|
-
if (!implsWithChanges.has(impl.impl_id)) {
|
|
144
|
-
violations.push({
|
|
145
|
-
rule: "L2-impl-no-chg",
|
|
146
|
-
detail: `${impl.impl_id ?? "UNKNOWN-IMPL"} has no CHG in delta-set`,
|
|
147
|
-
});
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
/** inject constraints should have at least 1 edge_case in validation plan */
|
|
152
|
-
function checkInjectEdgeCases(state, validationPlan, violations) {
|
|
153
|
-
const injectConstraints = state.constraint_pool.constraints.filter((c) => c.status !== "invalidated" && c.decision === "inject");
|
|
154
|
-
for (const c of injectConstraints) {
|
|
155
|
-
const valItem = validationPlan.find((v) => v.related_cst === c.constraint_id);
|
|
156
|
-
if (valItem && (!valItem.edge_cases || valItem.edge_cases.length === 0)) {
|
|
157
|
-
violations.push({
|
|
158
|
-
rule: "L2-inject-edge-case",
|
|
159
|
-
detail: `${c.constraint_id ?? "UNKNOWN-CST"} (inject) has no edge_cases in validation plan item ${valItem.val_id ?? "UNKNOWN-VAL"}`,
|
|
160
|
-
});
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
// ─── Layer 3: Evidence Quality Warnings (non-blocking) ───
|
|
165
|
-
function checkLayer3(state, buildSpec, deltaSet, brownfieldDetail, brownfieldContext, warnings) {
|
|
166
|
-
checkUnverifiedInject(state, warnings);
|
|
167
|
-
checkPolicyChangeRequired(state, warnings);
|
|
168
|
-
checkStateCompleteness(state, buildSpec, brownfieldDetail, warnings);
|
|
169
|
-
checkSharedResource(deltaSet, warnings);
|
|
170
|
-
checkInvariantCoverage(state, buildSpec, deltaSet, brownfieldDetail, warnings);
|
|
171
|
-
checkBrownfieldCoverage(deltaSet, brownfieldContext, warnings);
|
|
172
|
-
}
|
|
173
|
-
/**
|
|
174
|
-
* Warn (not block) when a required+inject constraint has unverified evidence.
|
|
175
|
-
*/
|
|
176
|
-
function checkUnverifiedInject(state, warnings) {
|
|
177
|
-
for (const c of state.constraint_pool.constraints) {
|
|
178
|
-
if (c.status === "invalidated")
|
|
179
|
-
continue;
|
|
180
|
-
if (c.decision !== "inject")
|
|
181
|
-
continue;
|
|
182
|
-
if (c.severity !== "required")
|
|
183
|
-
continue;
|
|
184
|
-
if (isEvidenceUnverified(c.evidence_status)) {
|
|
185
|
-
warnings.push({
|
|
186
|
-
rule: "L3-unverified-inject",
|
|
187
|
-
detail: `${c.constraint_id} (required, inject) has evidence_status="${c.evidence_status}". 정책 문서에서 확인되지 않은 가정이 구현에 포함됩니다.${c.evidence_note ? ` Note: ${c.evidence_note}` : ""}`,
|
|
188
|
-
});
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
|
-
}
|
|
192
|
-
/**
|
|
193
|
-
* Warn (not block) when an inject constraint has requires_policy_change=true.
|
|
194
|
-
* Independent from L3-unverified-inject (evidence quality).
|
|
195
|
-
*/
|
|
196
|
-
function checkPolicyChangeRequired(state, warnings) {
|
|
197
|
-
for (const c of state.constraint_pool.constraints) {
|
|
198
|
-
if (c.status === "invalidated")
|
|
199
|
-
continue;
|
|
200
|
-
if (c.decision !== "inject")
|
|
201
|
-
continue;
|
|
202
|
-
if (!c.requires_policy_change)
|
|
203
|
-
continue;
|
|
204
|
-
warnings.push({
|
|
205
|
-
rule: "L3-policy-change-required",
|
|
206
|
-
detail: `${c.constraint_id ?? "UNKNOWN-CST"} (inject)는 기존 정책 변경을 전제합니다. 구현 전 법무/정책 검토가 필요합니다.${c.evidence_note ? ` 참고: ${c.evidence_note}` : ""}`,
|
|
207
|
-
});
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
/**
|
|
211
|
-
* Warn when brownfieldDetail.enums defines enum values that are not
|
|
212
|
-
* mentioned anywhere in the build spec (constraint summaries, IMPL related_cst,
|
|
213
|
-
* or brownfield sections). Detects missing state mappings
|
|
214
|
-
* (e.g., NOSHOW_BOTH not covered by any implementation).
|
|
215
|
-
*/
|
|
216
|
-
function checkStateCompleteness(state, buildSpec, brownfieldDetail, warnings) {
|
|
217
|
-
if (!brownfieldDetail?.enums || brownfieldDetail.enums.length === 0)
|
|
218
|
-
return;
|
|
219
|
-
// Collect all relevant text from constraints, impl references, and brownfield content
|
|
220
|
-
const constraintText = state.constraint_pool.constraints
|
|
221
|
-
.map((c) => `${c.summary} ${c.selected_option ?? ""}`)
|
|
222
|
-
.join(" ");
|
|
223
|
-
const sectionText = brownfieldDetail.sections
|
|
224
|
-
.map((s) => s.content)
|
|
225
|
-
.join(" ");
|
|
226
|
-
const searchText = `${constraintText} ${sectionText}`;
|
|
227
|
-
for (const enumDef of brownfieldDetail.enums) {
|
|
228
|
-
const uncovered = enumDef.values.filter((val) => !searchText.includes(val));
|
|
229
|
-
if (uncovered.length > 0) {
|
|
230
|
-
warnings.push({
|
|
231
|
-
rule: "L3-state-completeness",
|
|
232
|
-
detail: `${enumDef.name} (source: ${enumDef.source})의 다음 값이 구현 계획에서 언급되지 않습니다: ${uncovered.join(", ")}. 상태 매핑이 누락되었을 수 있습니다.`,
|
|
233
|
-
});
|
|
234
|
-
}
|
|
235
|
-
}
|
|
236
|
-
}
|
|
237
|
-
/**
|
|
238
|
-
* Warn when multiple *separate* CHGs targeting the same file come from different CSTs.
|
|
239
|
-
* A single CHG referencing multiple CSTs is NOT flagged (one change serving multiple constraints is normal).
|
|
240
|
-
*/
|
|
241
|
-
function checkSharedResource(deltaSet, warnings) {
|
|
242
|
-
// Build: file_path → Map<cst_id, Set<change_id>>
|
|
243
|
-
const fileCstChanges = new Map();
|
|
244
|
-
for (const chg of deltaSet.changes) {
|
|
245
|
-
if (chg.related_cst.length === 0)
|
|
246
|
-
continue;
|
|
247
|
-
if (!fileCstChanges.has(chg.file_path)) {
|
|
248
|
-
fileCstChanges.set(chg.file_path, new Map());
|
|
249
|
-
}
|
|
250
|
-
const cstMap = fileCstChanges.get(chg.file_path);
|
|
251
|
-
for (const cst of chg.related_cst) {
|
|
252
|
-
if (!cstMap.has(cst))
|
|
253
|
-
cstMap.set(cst, new Set());
|
|
254
|
-
cstMap.get(cst).add(chg.change_id);
|
|
255
|
-
}
|
|
256
|
-
}
|
|
257
|
-
for (const [filePath, cstMap] of fileCstChanges) {
|
|
258
|
-
// Only warn if there are 2+ CSTs AND they come from different CHGs
|
|
259
|
-
if (cstMap.size < 2)
|
|
260
|
-
continue;
|
|
261
|
-
// Check that at least 2 CSTs have non-overlapping CHG sets
|
|
262
|
-
const chgSets = [...cstMap.values()];
|
|
263
|
-
let hasDistinctSources = false;
|
|
264
|
-
for (let i = 0; i < chgSets.length && !hasDistinctSources; i++) {
|
|
265
|
-
for (let j = i + 1; j < chgSets.length; j++) {
|
|
266
|
-
const overlap = [...chgSets[i]].some(id => chgSets[j].has(id));
|
|
267
|
-
if (!overlap) {
|
|
268
|
-
hasDistinctSources = true;
|
|
269
|
-
break;
|
|
270
|
-
}
|
|
271
|
-
}
|
|
272
|
-
}
|
|
273
|
-
if (hasDistinctSources) {
|
|
274
|
-
const cstIds = [...cstMap.keys()];
|
|
275
|
-
warnings.push({
|
|
276
|
-
rule: "L3-shared-resource",
|
|
277
|
-
detail: `${filePath}을(를) ${cstIds.length}개 CST가 별개의 변경으로 동시에 수정합니다: ${cstIds.join(", ")}. 조합 충돌 여부를 확인하세요.`,
|
|
278
|
-
});
|
|
279
|
-
}
|
|
280
|
-
}
|
|
281
|
-
}
|
|
282
|
-
/**
|
|
283
|
-
* Warn when delta-set changes modify files listed in brownfieldDetail.invariants
|
|
284
|
-
* but the invariant is not mentioned in any constraint or IMPL.
|
|
285
|
-
*/
|
|
286
|
-
function checkInvariantCoverage(state, buildSpec, deltaSet, brownfieldDetail, warnings) {
|
|
287
|
-
if (!brownfieldDetail?.invariants || brownfieldDetail.invariants.length === 0)
|
|
288
|
-
return;
|
|
289
|
-
const changeFilePaths = new Set(deltaSet.changes.map(c => normalizeFilePath(c.file_path)));
|
|
290
|
-
// Build search text from constraints + IMPL references in buildSpec
|
|
291
|
-
const constraintText = state.constraint_pool.constraints
|
|
292
|
-
.map(c => `${c.constraint_id} ${c.summary} ${c.selected_option ?? ""} ${c.decision ?? ""}`)
|
|
293
|
-
.join(" ");
|
|
294
|
-
const implText = buildSpec.section4
|
|
295
|
-
.map(impl => `${impl.impl_id} ${impl.related_cst.join(" ")}`)
|
|
296
|
-
.join(" ");
|
|
297
|
-
const searchText = `${constraintText} ${implText}`;
|
|
298
|
-
for (const inv of brownfieldDetail.invariants) {
|
|
299
|
-
// Check if any affected_files are in the delta-set changes
|
|
300
|
-
const affected = inv.affected_files?.some(f => changeFilePaths.has(normalizeFilePath(f))) ?? false;
|
|
301
|
-
if (!affected)
|
|
302
|
-
continue;
|
|
303
|
-
// Check if the invariant is mentioned in constraints or IMPL
|
|
304
|
-
const mentioned = searchText.includes(inv.name) || searchText.includes(inv.description.slice(0, 30));
|
|
305
|
-
if (!mentioned) {
|
|
306
|
-
warnings.push({
|
|
307
|
-
rule: "L3-invariant-uncovered",
|
|
308
|
-
detail: `불변 제약 "${inv.name}" (${inv.description})의 영향 파일이 delta-set에서 변경되지만, 구현 계획에서 언급되지 않습니다.`,
|
|
309
|
-
});
|
|
310
|
-
}
|
|
311
|
-
}
|
|
312
|
-
}
|
|
313
|
-
// ─── Path normalization for compile-defense ───
|
|
314
|
-
/**
|
|
315
|
-
* Normalize a file path for string comparison.
|
|
316
|
-
* Removes leading ./, trailing /, and collapses consecutive /.
|
|
317
|
-
* Does NOT resolve to absolute paths — keeps relative paths as-is.
|
|
318
|
-
*/
|
|
319
|
-
export function normalizeFilePath(p) {
|
|
320
|
-
return p
|
|
321
|
-
.replace(/^\.\//, "")
|
|
322
|
-
.replace(/\/+/g, "/")
|
|
323
|
-
.replace(/\/$/, "");
|
|
324
|
-
}
|
|
325
|
-
// ─── Layer 3: Brownfield Coverage ───
|
|
326
|
-
/**
|
|
327
|
-
* Warn when delta-set modify/delete targets a file not in brownfield.related_files.
|
|
328
|
-
* This indicates the agent planned a change without scanning the existing code.
|
|
329
|
-
*/
|
|
330
|
-
function checkBrownfieldCoverage(deltaSet, brownfieldContext, warnings) {
|
|
331
|
-
if (!brownfieldContext?.related_files || brownfieldContext.related_files.length === 0)
|
|
332
|
-
return;
|
|
333
|
-
const brownfieldPaths = new Set(brownfieldContext.related_files.map((f) => normalizeFilePath(f.path)));
|
|
334
|
-
const modifyDeleteChanges = deltaSet.changes.filter((c) => c.action === "modify" || c.action === "delete");
|
|
335
|
-
for (const chg of modifyDeleteChanges) {
|
|
336
|
-
const normalized = normalizeFilePath(chg.file_path);
|
|
337
|
-
if (!brownfieldPaths.has(normalized)) {
|
|
338
|
-
warnings.push({
|
|
339
|
-
rule: "L3-modify-not-in-brownfield",
|
|
340
|
-
detail: `${chg.file_path} (${chg.action})가 brownfield.related_files에 등록되지 않았습니다. 기존 코드 구조를 확인했는지 검증하세요.`,
|
|
341
|
-
});
|
|
342
|
-
}
|
|
343
|
-
}
|
|
344
|
-
}
|