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,195 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect } from "vitest";
|
|
2
|
-
import { applySet, SUPPORTED_SET_PATHS } from "./onto-config-key-path.js";
|
|
3
|
-
// ---------------------------------------------------------------------------
|
|
4
|
-
// applySet — Review UX Redesign P5 (2026-04-21)
|
|
5
|
-
// ---------------------------------------------------------------------------
|
|
6
|
-
//
|
|
7
|
-
// These tests cover the coercion + discriminated-union invariants the
|
|
8
|
-
// `onto config set` and `edit` subcommands depend on:
|
|
9
|
-
//
|
|
10
|
-
// (1) Happy paths for each supported key, round-tripping through the
|
|
11
|
-
// expected OntoReviewConfig shape.
|
|
12
|
-
// (2) Discriminated-union preservation — switching subagent.provider
|
|
13
|
-
// from `main-native` to a foreign value adds model_id/effort slots;
|
|
14
|
-
// switching back to `main-native` drops them.
|
|
15
|
-
// (3) Value coercion errors (integers, enums) returned as `ok: false`
|
|
16
|
-
// with a clear error string — caller forwards verbatim to the user.
|
|
17
|
-
// (4) Unsupported paths return an error pointing to `edit` for richer
|
|
18
|
-
// spec objects.
|
|
19
|
-
// ---------------------------------------------------------------------------
|
|
20
|
-
describe("applySet — supported paths declared", () => {
|
|
21
|
-
it("SUPPORTED_SET_PATHS matches README / help text exactly", () => {
|
|
22
|
-
expect(SUPPORTED_SET_PATHS).toEqual([
|
|
23
|
-
"teamlead.model",
|
|
24
|
-
"subagent.provider",
|
|
25
|
-
"subagent.model_id",
|
|
26
|
-
"subagent.effort",
|
|
27
|
-
"max_concurrent_lenses",
|
|
28
|
-
"lens_deliberation",
|
|
29
|
-
]);
|
|
30
|
-
});
|
|
31
|
-
});
|
|
32
|
-
describe("applySet — teamlead.model", () => {
|
|
33
|
-
it("accepts `main` literal", () => {
|
|
34
|
-
const r = applySet({}, "teamlead.model", "main");
|
|
35
|
-
expect(r.ok).toBe(true);
|
|
36
|
-
if (r.ok)
|
|
37
|
-
expect(r.config.teamlead).toEqual({ model: "main" });
|
|
38
|
-
});
|
|
39
|
-
it("rejects foreign teamlead values and points to `edit`", () => {
|
|
40
|
-
const r = applySet({}, "teamlead.model", "codex");
|
|
41
|
-
expect(r.ok).toBe(false);
|
|
42
|
-
if (!r.ok)
|
|
43
|
-
expect(r.error).toMatch(/edit/);
|
|
44
|
-
});
|
|
45
|
-
});
|
|
46
|
-
describe("applySet — subagent.provider (discriminated-union preservation)", () => {
|
|
47
|
-
it("main-native → main-native is idempotent", () => {
|
|
48
|
-
const r = applySet({ subagent: { provider: "main-native" } }, "subagent.provider", "main-native");
|
|
49
|
-
expect(r.ok).toBe(true);
|
|
50
|
-
if (r.ok)
|
|
51
|
-
expect(r.config.subagent).toEqual({ provider: "main-native" });
|
|
52
|
-
});
|
|
53
|
-
it("main-native → codex preserves (empty) model_id slot", () => {
|
|
54
|
-
const r = applySet({ subagent: { provider: "main-native" } }, "subagent.provider", "codex");
|
|
55
|
-
expect(r.ok).toBe(true);
|
|
56
|
-
if (r.ok) {
|
|
57
|
-
expect(r.config.subagent).toEqual({ provider: "codex", model_id: "" });
|
|
58
|
-
}
|
|
59
|
-
});
|
|
60
|
-
it("codex → litellm carries over model_id + effort (user may prune later)", () => {
|
|
61
|
-
const r = applySet({
|
|
62
|
-
subagent: { provider: "codex", model_id: "gpt-5.4", effort: "high" },
|
|
63
|
-
}, "subagent.provider", "litellm");
|
|
64
|
-
expect(r.ok).toBe(true);
|
|
65
|
-
if (r.ok) {
|
|
66
|
-
expect(r.config.subagent).toEqual({
|
|
67
|
-
provider: "litellm",
|
|
68
|
-
model_id: "gpt-5.4",
|
|
69
|
-
effort: "high",
|
|
70
|
-
});
|
|
71
|
-
}
|
|
72
|
-
});
|
|
73
|
-
it("codex → main-native drops model_id + effort (union branch change)", () => {
|
|
74
|
-
const r = applySet({
|
|
75
|
-
subagent: { provider: "codex", model_id: "gpt-5.4", effort: "high" },
|
|
76
|
-
}, "subagent.provider", "main-native");
|
|
77
|
-
expect(r.ok).toBe(true);
|
|
78
|
-
if (r.ok)
|
|
79
|
-
expect(r.config.subagent).toEqual({ provider: "main-native" });
|
|
80
|
-
});
|
|
81
|
-
it("rejects unknown provider", () => {
|
|
82
|
-
const r = applySet({}, "subagent.provider", "hal9000");
|
|
83
|
-
expect(r.ok).toBe(false);
|
|
84
|
-
});
|
|
85
|
-
});
|
|
86
|
-
describe("applySet — subagent.model_id", () => {
|
|
87
|
-
it("requires a foreign provider to be set first", () => {
|
|
88
|
-
const r = applySet({ subagent: { provider: "main-native" } }, "subagent.model_id", "gpt-5.4");
|
|
89
|
-
expect(r.ok).toBe(false);
|
|
90
|
-
if (!r.ok)
|
|
91
|
-
expect(r.error).toMatch(/foreign provider/);
|
|
92
|
-
});
|
|
93
|
-
it("rejects empty model_id", () => {
|
|
94
|
-
const r = applySet({
|
|
95
|
-
subagent: { provider: "codex", model_id: "prev" },
|
|
96
|
-
}, "subagent.model_id", "");
|
|
97
|
-
expect(r.ok).toBe(false);
|
|
98
|
-
});
|
|
99
|
-
it("sets model_id on codex subagent", () => {
|
|
100
|
-
const r = applySet({ subagent: { provider: "codex", model_id: "" } }, "subagent.model_id", "gpt-5.4");
|
|
101
|
-
expect(r.ok).toBe(true);
|
|
102
|
-
if (r.ok) {
|
|
103
|
-
expect(r.config.subagent).toEqual({
|
|
104
|
-
provider: "codex",
|
|
105
|
-
model_id: "gpt-5.4",
|
|
106
|
-
});
|
|
107
|
-
}
|
|
108
|
-
});
|
|
109
|
-
it("preserves effort when updating model_id", () => {
|
|
110
|
-
const r = applySet({
|
|
111
|
-
subagent: { provider: "codex", model_id: "gpt-5.4", effort: "high" },
|
|
112
|
-
}, "subagent.model_id", "gpt-5.4-preview");
|
|
113
|
-
expect(r.ok).toBe(true);
|
|
114
|
-
if (r.ok) {
|
|
115
|
-
expect(r.config.subagent).toEqual({
|
|
116
|
-
provider: "codex",
|
|
117
|
-
model_id: "gpt-5.4-preview",
|
|
118
|
-
effort: "high",
|
|
119
|
-
});
|
|
120
|
-
}
|
|
121
|
-
});
|
|
122
|
-
});
|
|
123
|
-
describe("applySet — subagent.effort", () => {
|
|
124
|
-
it("requires a foreign provider", () => {
|
|
125
|
-
const r = applySet({ subagent: { provider: "main-native" } }, "subagent.effort", "high");
|
|
126
|
-
expect(r.ok).toBe(false);
|
|
127
|
-
});
|
|
128
|
-
it("sets effort on a foreign subagent", () => {
|
|
129
|
-
const r = applySet({ subagent: { provider: "codex", model_id: "gpt-5.4" } }, "subagent.effort", "xhigh");
|
|
130
|
-
expect(r.ok).toBe(true);
|
|
131
|
-
if (r.ok) {
|
|
132
|
-
expect(r.config.subagent).toEqual({
|
|
133
|
-
provider: "codex",
|
|
134
|
-
model_id: "gpt-5.4",
|
|
135
|
-
effort: "xhigh",
|
|
136
|
-
});
|
|
137
|
-
}
|
|
138
|
-
});
|
|
139
|
-
});
|
|
140
|
-
describe("applySet — max_concurrent_lenses", () => {
|
|
141
|
-
it("accepts positive integer", () => {
|
|
142
|
-
const r = applySet({}, "max_concurrent_lenses", "9");
|
|
143
|
-
expect(r.ok).toBe(true);
|
|
144
|
-
if (r.ok)
|
|
145
|
-
expect(r.config.max_concurrent_lenses).toBe(9);
|
|
146
|
-
});
|
|
147
|
-
it("rejects zero / negative / float / non-numeric", () => {
|
|
148
|
-
expect(applySet({}, "max_concurrent_lenses", "0").ok).toBe(false);
|
|
149
|
-
expect(applySet({}, "max_concurrent_lenses", "-1").ok).toBe(false);
|
|
150
|
-
expect(applySet({}, "max_concurrent_lenses", "2.5").ok).toBe(false);
|
|
151
|
-
expect(applySet({}, "max_concurrent_lenses", "six").ok).toBe(false);
|
|
152
|
-
});
|
|
153
|
-
});
|
|
154
|
-
describe("applySet — lens_deliberation", () => {
|
|
155
|
-
it("accepts synthesizer-only", () => {
|
|
156
|
-
const r = applySet({}, "lens_deliberation", "synthesizer-only");
|
|
157
|
-
expect(r.ok).toBe(true);
|
|
158
|
-
if (r.ok)
|
|
159
|
-
expect(r.config.lens_deliberation).toBe("synthesizer-only");
|
|
160
|
-
});
|
|
161
|
-
it("accepts sendmessage-a2a", () => {
|
|
162
|
-
const r = applySet({}, "lens_deliberation", "sendmessage-a2a");
|
|
163
|
-
expect(r.ok).toBe(true);
|
|
164
|
-
if (r.ok)
|
|
165
|
-
expect(r.config.lens_deliberation).toBe("sendmessage-a2a");
|
|
166
|
-
});
|
|
167
|
-
it("rejects unknown deliberation value", () => {
|
|
168
|
-
const r = applySet({}, "lens_deliberation", "loud");
|
|
169
|
-
expect(r.ok).toBe(false);
|
|
170
|
-
});
|
|
171
|
-
});
|
|
172
|
-
describe("applySet — unsupported paths", () => {
|
|
173
|
-
it("rejects unknown key path with hint to `edit`", () => {
|
|
174
|
-
const r = applySet({}, "review_mode", "full");
|
|
175
|
-
expect(r.ok).toBe(false);
|
|
176
|
-
if (!r.ok) {
|
|
177
|
-
expect(r.error).toMatch(/edit/);
|
|
178
|
-
expect(r.error).toMatch(/Supported paths/);
|
|
179
|
-
}
|
|
180
|
-
});
|
|
181
|
-
it("rejects nested teamlead.model.provider path (use edit)", () => {
|
|
182
|
-
const r = applySet({}, "teamlead.model.provider", "codex");
|
|
183
|
-
expect(r.ok).toBe(false);
|
|
184
|
-
});
|
|
185
|
-
});
|
|
186
|
-
describe("applySet — purity", () => {
|
|
187
|
-
it("does not mutate the input config", () => {
|
|
188
|
-
const original = {
|
|
189
|
-
subagent: { provider: "codex", model_id: "gpt-5.4", effort: "high" },
|
|
190
|
-
};
|
|
191
|
-
const snapshot = structuredClone(original);
|
|
192
|
-
applySet(original, "subagent.provider", "main-native");
|
|
193
|
-
expect(original).toEqual(snapshot);
|
|
194
|
-
});
|
|
195
|
-
});
|
|
@@ -1,108 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Review UX Redesign P5 — `onto config validate` / `onto config show`
|
|
3
|
-
* preview helper.
|
|
4
|
-
*
|
|
5
|
-
* # What this module is
|
|
6
|
-
*
|
|
7
|
-
* A pure function that takes a validated `OntoReviewConfig` + host signals
|
|
8
|
-
* and returns a deterministic textual preview showing:
|
|
9
|
-
* (a) which topology shape the config would derive to,
|
|
10
|
-
* (b) which canonical `TopologyId` that shape would map to under the
|
|
11
|
-
* current environment, and
|
|
12
|
-
* (c) the exact validation or mapping point that would stop execution.
|
|
13
|
-
*
|
|
14
|
-
* # Why it exists
|
|
15
|
-
*
|
|
16
|
-
* The onboard + config-edit UX promise is "what you configured is what
|
|
17
|
-
* runs". Without a preview step, users only see the runtime outcome after
|
|
18
|
-
* starting a review (via the `[topology]` STDERR trace). This helper
|
|
19
|
-
* surfaces the derivation BEFORE any review call, making config-time and
|
|
20
|
-
* run-time answer the same question with the same inputs.
|
|
21
|
-
*
|
|
22
|
-
* # How it relates
|
|
23
|
-
*
|
|
24
|
-
* - Input: validated `OntoReviewConfig` (from `validateReviewConfig`) +
|
|
25
|
-
* detected axes (from `detectReviewAxes`).
|
|
26
|
-
* - Output: a typed `Preview` object (topology id, shape) plus
|
|
27
|
-
* a rendered string for CLI display.
|
|
28
|
-
* - Shares derivation/mapping logic with `resolveAxisFirstTopology` so
|
|
29
|
-
* the preview and the runtime can never drift.
|
|
30
|
-
*/
|
|
31
|
-
import { shapeToTopologyId } from "../review/shape-to-topology-id.js";
|
|
32
|
-
import { deriveTopologyShape, } from "../review/topology-shape-derivation.js";
|
|
33
|
-
// ---------------------------------------------------------------------------
|
|
34
|
-
// Main
|
|
35
|
-
// ---------------------------------------------------------------------------
|
|
36
|
-
/**
|
|
37
|
-
* Run derivation + mapping preview. Mirrors the
|
|
38
|
-
* runtime resolver's axis-first path so the output matches what the user
|
|
39
|
-
* would see in `[topology]` STDERR during a real review invocation.
|
|
40
|
-
*/
|
|
41
|
-
export function previewTopologyDerivation(config, signals) {
|
|
42
|
-
const trace = [];
|
|
43
|
-
const derivation = deriveTopologyShape(config, signals);
|
|
44
|
-
for (const line of derivation.ok ? derivation.derived.trace : derivation.trace) {
|
|
45
|
-
trace.push(`derive: ${line}`);
|
|
46
|
-
}
|
|
47
|
-
if (!derivation.ok) {
|
|
48
|
-
return {
|
|
49
|
-
ok: false,
|
|
50
|
-
reason: derivation.reasons[0] ?? "topology shape derivation failed",
|
|
51
|
-
trace,
|
|
52
|
-
};
|
|
53
|
-
}
|
|
54
|
-
const mapping = shapeToTopologyId({
|
|
55
|
-
shape: derivation.derived.shape,
|
|
56
|
-
subagent_provider: derivation.derived.subagent_provider,
|
|
57
|
-
signals: {
|
|
58
|
-
claudeHost: signals.claudeHost,
|
|
59
|
-
codexSessionActive: signals.codexSessionActive,
|
|
60
|
-
},
|
|
61
|
-
});
|
|
62
|
-
for (const line of mapping.trace) {
|
|
63
|
-
trace.push(`map: ${line}`);
|
|
64
|
-
}
|
|
65
|
-
if (!mapping.ok) {
|
|
66
|
-
return {
|
|
67
|
-
ok: false,
|
|
68
|
-
reason: mapping.reason,
|
|
69
|
-
trace,
|
|
70
|
-
};
|
|
71
|
-
}
|
|
72
|
-
trace.push(`result: shape=${derivation.derived.shape} topology=${mapping.topology_id}`);
|
|
73
|
-
return {
|
|
74
|
-
ok: true,
|
|
75
|
-
shape: derivation.derived.shape,
|
|
76
|
-
topology_id: mapping.topology_id,
|
|
77
|
-
trace,
|
|
78
|
-
};
|
|
79
|
-
}
|
|
80
|
-
// ---------------------------------------------------------------------------
|
|
81
|
-
// Rendering
|
|
82
|
-
// ---------------------------------------------------------------------------
|
|
83
|
-
/**
|
|
84
|
-
* Render a preview result as a human-readable block for CLI display.
|
|
85
|
-
* Handles both success and failure outputs. Keep the format stable — the
|
|
86
|
-
* onboard prose and `onto config` output use the same template so the
|
|
87
|
-
* user learns one visual vocabulary.
|
|
88
|
-
*/
|
|
89
|
-
export function renderPreview(result) {
|
|
90
|
-
const lines = [];
|
|
91
|
-
if (result.ok) {
|
|
92
|
-
lines.push("## Topology derivation preview");
|
|
93
|
-
lines.push("");
|
|
94
|
-
lines.push(` shape: ${result.shape}`);
|
|
95
|
-
lines.push(` topology_id: ${result.topology_id}`);
|
|
96
|
-
}
|
|
97
|
-
else {
|
|
98
|
-
lines.push("## Topology derivation preview — FAILED");
|
|
99
|
-
lines.push("");
|
|
100
|
-
lines.push(` reason: ${result.reason}`);
|
|
101
|
-
}
|
|
102
|
-
lines.push("");
|
|
103
|
-
lines.push(" Trace:");
|
|
104
|
-
for (const line of result.trace) {
|
|
105
|
-
lines.push(` ${line}`);
|
|
106
|
-
}
|
|
107
|
-
return lines.join("\n");
|
|
108
|
-
}
|
|
@@ -1,132 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect } from "vitest";
|
|
2
|
-
import { previewTopologyDerivation, renderPreview, } from "./onto-config-preview.js";
|
|
3
|
-
// ---------------------------------------------------------------------------
|
|
4
|
-
// previewTopologyDerivation — Review UX Redesign P5 (2026-04-21)
|
|
5
|
-
// ---------------------------------------------------------------------------
|
|
6
|
-
//
|
|
7
|
-
// These tests verify that the preview helper mirrors the runtime resolver's
|
|
8
|
-
// axis-first path:
|
|
9
|
-
//
|
|
10
|
-
// (1) Happy path — a valid config + suitable host → correct shape +
|
|
11
|
-
// canonical TopologyId + degraded=false.
|
|
12
|
-
// (2) Derivation failure (a2a + no teams) → degrades to main_native.
|
|
13
|
-
// (3) Mapping failure (main_foreign + litellm) → degrades to main_native.
|
|
14
|
-
// (4) No Claude, no Codex → main_native unmappable → preview fails
|
|
15
|
-
// (runtime would fall through to legacy ladder / no_host).
|
|
16
|
-
// (5) renderPreview produces a stable human-readable block for CLI use.
|
|
17
|
-
// ---------------------------------------------------------------------------
|
|
18
|
-
const CLAUDE_NO_TEAMS = {
|
|
19
|
-
claudeHost: true,
|
|
20
|
-
codexSessionActive: false,
|
|
21
|
-
experimentalAgentTeams: false,
|
|
22
|
-
};
|
|
23
|
-
const CLAUDE_TEAMS = {
|
|
24
|
-
claudeHost: true,
|
|
25
|
-
codexSessionActive: false,
|
|
26
|
-
experimentalAgentTeams: true,
|
|
27
|
-
};
|
|
28
|
-
const CODEX_HOST = {
|
|
29
|
-
claudeHost: false,
|
|
30
|
-
codexSessionActive: true,
|
|
31
|
-
experimentalAgentTeams: false,
|
|
32
|
-
};
|
|
33
|
-
const NEITHER = {
|
|
34
|
-
claudeHost: false,
|
|
35
|
-
codexSessionActive: false,
|
|
36
|
-
experimentalAgentTeams: false,
|
|
37
|
-
};
|
|
38
|
-
describe("previewTopologyDerivation — happy paths", () => {
|
|
39
|
-
it("empty config + Claude host → main_native / cc-main-agent-subagent", () => {
|
|
40
|
-
const r = previewTopologyDerivation({}, CLAUDE_NO_TEAMS);
|
|
41
|
-
expect(r.ok).toBe(true);
|
|
42
|
-
if (r.ok) {
|
|
43
|
-
expect(r.shape).toBe("main_native");
|
|
44
|
-
expect(r.topology_id).toBe("cc-main-agent-subagent");
|
|
45
|
-
expect(r.degraded).toBe(false);
|
|
46
|
-
}
|
|
47
|
-
});
|
|
48
|
-
it("teams + main-native → main-teams_native / cc-teams-agent-subagent", () => {
|
|
49
|
-
const config = {
|
|
50
|
-
teamlead: { model: "main" },
|
|
51
|
-
subagent: { provider: "main-native" },
|
|
52
|
-
};
|
|
53
|
-
const r = previewTopologyDerivation(config, CLAUDE_TEAMS);
|
|
54
|
-
expect(r.ok).toBe(true);
|
|
55
|
-
if (r.ok) {
|
|
56
|
-
expect(r.shape).toBe("main-teams_native");
|
|
57
|
-
expect(r.topology_id).toBe("cc-teams-agent-subagent");
|
|
58
|
-
expect(r.degraded).toBe(false);
|
|
59
|
-
}
|
|
60
|
-
});
|
|
61
|
-
it("Codex host + main-native → main_native / codex-main-subprocess", () => {
|
|
62
|
-
const r = previewTopologyDerivation({ subagent: { provider: "main-native" } }, CODEX_HOST);
|
|
63
|
-
expect(r.ok).toBe(true);
|
|
64
|
-
if (r.ok) {
|
|
65
|
-
expect(r.shape).toBe("main_native");
|
|
66
|
-
expect(r.topology_id).toBe("codex-main-subprocess");
|
|
67
|
-
}
|
|
68
|
-
});
|
|
69
|
-
});
|
|
70
|
-
describe("previewTopologyDerivation — degrade paths", () => {
|
|
71
|
-
it("a2a without teams → degrades to main_native", () => {
|
|
72
|
-
const config = {
|
|
73
|
-
subagent: { provider: "main-native" },
|
|
74
|
-
lens_deliberation: "sendmessage-a2a",
|
|
75
|
-
};
|
|
76
|
-
const r = previewTopologyDerivation(config, CLAUDE_NO_TEAMS);
|
|
77
|
-
expect(r.ok).toBe(true);
|
|
78
|
-
if (r.ok) {
|
|
79
|
-
expect(r.degraded).toBe(true);
|
|
80
|
-
expect(r.shape).toBe("main_native");
|
|
81
|
-
expect(r.topology_id).toBe("cc-main-agent-subagent");
|
|
82
|
-
expect(r.trace.some((l) => l.startsWith("degrade:"))).toBe(true);
|
|
83
|
-
}
|
|
84
|
-
});
|
|
85
|
-
it("main_foreign + litellm (Claude host) → degrades to main_native", () => {
|
|
86
|
-
const config = {
|
|
87
|
-
subagent: { provider: "litellm", model_id: "llama-8b" },
|
|
88
|
-
};
|
|
89
|
-
const r = previewTopologyDerivation(config, CLAUDE_NO_TEAMS);
|
|
90
|
-
expect(r.ok).toBe(true);
|
|
91
|
-
if (r.ok) {
|
|
92
|
-
expect(r.degraded).toBe(true);
|
|
93
|
-
expect(r.topology_id).toBe("cc-main-agent-subagent");
|
|
94
|
-
expect(r.trace.some((l) => l.includes("main_foreign(litellm)"))).toBe(true);
|
|
95
|
-
}
|
|
96
|
-
});
|
|
97
|
-
});
|
|
98
|
-
describe("previewTopologyDerivation — total failure (no host)", () => {
|
|
99
|
-
it("main_native unmappable → preview fails with explanatory reason", () => {
|
|
100
|
-
const r = previewTopologyDerivation({}, NEITHER);
|
|
101
|
-
expect(r.ok).toBe(false);
|
|
102
|
-
if (!r.ok) {
|
|
103
|
-
expect(r.reason).toContain("main_native fallback");
|
|
104
|
-
expect(r.trace.some((l) => l.includes("unmappable"))).toBe(true);
|
|
105
|
-
}
|
|
106
|
-
});
|
|
107
|
-
});
|
|
108
|
-
describe("renderPreview — human-readable output", () => {
|
|
109
|
-
it("success block includes shape + topology_id + trace", () => {
|
|
110
|
-
const r = previewTopologyDerivation({}, CLAUDE_NO_TEAMS);
|
|
111
|
-
const text = renderPreview(r);
|
|
112
|
-
expect(text).toContain("Topology derivation preview");
|
|
113
|
-
expect(text).toContain("shape:");
|
|
114
|
-
expect(text).toContain("cc-main-agent-subagent");
|
|
115
|
-
expect(text).toContain("Trace:");
|
|
116
|
-
});
|
|
117
|
-
it("degraded block includes (degraded) marker and fallback note", () => {
|
|
118
|
-
const config = {
|
|
119
|
-
subagent: { provider: "litellm", model_id: "llama-8b" },
|
|
120
|
-
};
|
|
121
|
-
const r = previewTopologyDerivation(config, CLAUDE_NO_TEAMS);
|
|
122
|
-
const text = renderPreview(r);
|
|
123
|
-
expect(text).toContain("(degraded)");
|
|
124
|
-
expect(text).toContain("P3 universal fallback");
|
|
125
|
-
});
|
|
126
|
-
it("failure block includes reason + FAILED header", () => {
|
|
127
|
-
const r = previewTopologyDerivation({}, NEITHER);
|
|
128
|
-
const text = renderPreview(r);
|
|
129
|
-
expect(text).toContain("FAILED");
|
|
130
|
-
expect(text).toContain("reason:");
|
|
131
|
-
});
|
|
132
|
-
});
|
|
@@ -1,118 +0,0 @@
|
|
|
1
|
-
import path from "node:path";
|
|
2
|
-
import { fileExists, readYamlDocument } from "../review/review-artifact-utils.js";
|
|
3
|
-
import { adoptProfile, mergeOrthogonalFields, } from "./config-profile.js";
|
|
4
|
-
async function readConfigAt(dir) {
|
|
5
|
-
const configPath = path.join(dir, ".onto", "config.yml");
|
|
6
|
-
if (!(await fileExists(configPath))) {
|
|
7
|
-
return {};
|
|
8
|
-
}
|
|
9
|
-
const raw = await readYamlDocument(configPath);
|
|
10
|
-
if (raw === null || typeof raw !== "object") {
|
|
11
|
-
return {};
|
|
12
|
-
}
|
|
13
|
-
assertKnownConfigKeys(raw, configPath);
|
|
14
|
-
return raw;
|
|
15
|
-
}
|
|
16
|
-
const TOP_LEVEL_CONFIG_KEYS = [
|
|
17
|
-
"llm",
|
|
18
|
-
"review",
|
|
19
|
-
"review_mode",
|
|
20
|
-
"max_concurrent_lenses",
|
|
21
|
-
"domain",
|
|
22
|
-
"secondary_domains",
|
|
23
|
-
"domains",
|
|
24
|
-
"excluded_names",
|
|
25
|
-
"max_listing_depth",
|
|
26
|
-
"max_listing_entries",
|
|
27
|
-
"max_embed_lines",
|
|
28
|
-
"output_language",
|
|
29
|
-
"learning_extract_mode",
|
|
30
|
-
"main_llm",
|
|
31
|
-
"lens_agent_teams_mode",
|
|
32
|
-
];
|
|
33
|
-
function assertKnownConfigKeys(raw, configPath) {
|
|
34
|
-
const allowed = new Set(TOP_LEVEL_CONFIG_KEYS);
|
|
35
|
-
const unknown = Object.keys(raw).filter((key) => !allowed.has(key));
|
|
36
|
-
if (unknown.length === 0)
|
|
37
|
-
return;
|
|
38
|
-
throw new Error([
|
|
39
|
-
`Unsupported .onto config key(s) in ${configPath}: ${unknown.join(", ")}`,
|
|
40
|
-
"Supported top-level keys:",
|
|
41
|
-
` ${TOP_LEVEL_CONFIG_KEYS.join(", ")}`,
|
|
42
|
-
"LLM selection belongs under:",
|
|
43
|
-
" llm:",
|
|
44
|
-
" auth: oauth | api_key | local",
|
|
45
|
-
" provider: openai | anthropic | grok | lmstudio",
|
|
46
|
-
" model: <model-id>",
|
|
47
|
-
" effort: high",
|
|
48
|
-
" base_url: <optional>",
|
|
49
|
-
].join("\n"));
|
|
50
|
-
}
|
|
51
|
-
/**
|
|
52
|
-
* Orthogonal-only config chain resolver.
|
|
53
|
-
*
|
|
54
|
-
* # What this is
|
|
55
|
-
*
|
|
56
|
-
* Reads home + project `.onto/config.yml`, merges ONLY the orthogonal
|
|
57
|
-
* fields (output_language, domains, review_mode, learning_extract_mode,
|
|
58
|
-
* etc. — see `config-profile.ts:PROFILE_FIELDS` for the complement set),
|
|
59
|
-
* and returns the merged partial config without running `adoptProfile`.
|
|
60
|
-
*
|
|
61
|
-
* # Why this exists
|
|
62
|
-
*
|
|
63
|
-
* Callers that only need a single orthogonal field (e.g.,
|
|
64
|
-
* `resolveReviewSessionExtractMode` reading `learning_extract_mode`) do
|
|
65
|
-
* NOT need provider-profile validation. Routing them through
|
|
66
|
-
* `resolveConfigChain` caused false fail-fast throws once PR #96's atomic
|
|
67
|
-
* profile adoption started rejecting "no provider profile declared"
|
|
68
|
-
* configs — a test/tooling fixture that cares only about orthogonal
|
|
69
|
-
* settings would be blocked by an unrelated profile gate.
|
|
70
|
-
*
|
|
71
|
-
* # How it relates
|
|
72
|
-
*
|
|
73
|
-
* Same underlying `readConfigAt` + `mergeOrthogonalFields` that
|
|
74
|
-
* `resolveConfigChain` uses, sequenced without profile adoption.
|
|
75
|
-
* Callers that need a full config continue to use `resolveConfigChain`.
|
|
76
|
-
*/
|
|
77
|
-
export async function resolveOrthogonalConfigChain(ontoHome, projectRoot) {
|
|
78
|
-
const homeConfig = await readConfigAt(ontoHome);
|
|
79
|
-
const sameRoot = ontoHome === projectRoot;
|
|
80
|
-
const projectConfig = sameRoot ? homeConfig : await readConfigAt(projectRoot);
|
|
81
|
-
return mergeOrthogonalFields(homeConfig, projectConfig);
|
|
82
|
-
}
|
|
83
|
-
/**
|
|
84
|
-
* Config chain resolver (home + project) with atomic profile adoption.
|
|
85
|
-
*
|
|
86
|
-
* # Behavior
|
|
87
|
-
*
|
|
88
|
-
* - Project declares any profile fields → project owns the profile atomically.
|
|
89
|
-
* - Project declares none, home declares some → global profile adopted silently.
|
|
90
|
-
* - Neither side declares any profile fields → empty profile returned.
|
|
91
|
-
*
|
|
92
|
-
* Orthogonal fields (output_language, domains, review_mode, listing limits,
|
|
93
|
-
* learning_extract_mode, etc.) continue to merge last-wins — they do not
|
|
94
|
-
* carry cross-provider semantics.
|
|
95
|
-
*
|
|
96
|
-
* # Why atomic adoption still runs
|
|
97
|
-
*
|
|
98
|
-
* Atomic ownership prevents mixed provider state from different config files.
|
|
99
|
-
* `extractProfileFields` + `adoptProfile` transfer PROFILE_FIELDS as a group
|
|
100
|
-
* from exactly one source.
|
|
101
|
-
*/
|
|
102
|
-
export async function resolveConfigChain(ontoHome, projectRoot) {
|
|
103
|
-
const homeConfig = await readConfigAt(ontoHome);
|
|
104
|
-
const sameRoot = ontoHome === projectRoot;
|
|
105
|
-
const projectConfig = sameRoot ? homeConfig : await readConfigAt(projectRoot);
|
|
106
|
-
const homePath = path.join(ontoHome, ".onto", "config.yml");
|
|
107
|
-
const projectPath = path.join(projectRoot, ".onto", "config.yml");
|
|
108
|
-
const adoption = adoptProfile({
|
|
109
|
-
home: homeConfig,
|
|
110
|
-
project: projectConfig,
|
|
111
|
-
homePath,
|
|
112
|
-
projectPath,
|
|
113
|
-
sameRoot,
|
|
114
|
-
});
|
|
115
|
-
const orthogonal = mergeOrthogonalFields(homeConfig, projectConfig);
|
|
116
|
-
const merged = { ...orthogonal, ...adoption.profile };
|
|
117
|
-
return merged;
|
|
118
|
-
}
|
|
@@ -1,103 +0,0 @@
|
|
|
1
|
-
import { afterEach, describe, expect, it } from "vitest";
|
|
2
|
-
import fs from "node:fs";
|
|
3
|
-
import os from "node:os";
|
|
4
|
-
import path from "node:path";
|
|
5
|
-
import { resolveConfigChain } from "./config-chain.js";
|
|
6
|
-
// ---------------------------------------------------------------------------
|
|
7
|
-
// config-chain — P9.5 graceful-ignore regression guard (2026-04-21).
|
|
8
|
-
//
|
|
9
|
-
// P9.5 retired `legacy-field-deprecation.ts`. Legacy provider-profile
|
|
10
|
-
// fields (host_runtime, execution_realization, execution_mode,
|
|
11
|
-
// executor_realization, api_provider) in YAML no longer throw
|
|
12
|
-
// `LegacyFieldRemovedError` at config load. The OntoConfig type omits
|
|
13
|
-
// them, so typed code cannot read them; Record-cast paths can still
|
|
14
|
-
// see the values, but no production consumer does so — the fields are
|
|
15
|
-
// effectively inert.
|
|
16
|
-
//
|
|
17
|
-
// These tests lock in the graceful-ignore contract so a future refactor
|
|
18
|
-
// that reintroduces a throw surfaces as a test failure, and so the
|
|
19
|
-
// "config loads + downstream path still works" invariant is explicit.
|
|
20
|
-
// ---------------------------------------------------------------------------
|
|
21
|
-
const cleanupDirs = [];
|
|
22
|
-
function makeTmpDir(prefix) {
|
|
23
|
-
const dir = fs.mkdtempSync(path.join(os.tmpdir(), `onto-p95-${prefix}-`));
|
|
24
|
-
cleanupDirs.push(dir);
|
|
25
|
-
return dir;
|
|
26
|
-
}
|
|
27
|
-
function writeConfig(dir, yaml) {
|
|
28
|
-
fs.mkdirSync(path.join(dir, ".onto"), { recursive: true });
|
|
29
|
-
fs.writeFileSync(path.join(dir, ".onto", "config.yml"), yaml, "utf8");
|
|
30
|
-
}
|
|
31
|
-
afterEach(() => {
|
|
32
|
-
while (cleanupDirs.length > 0) {
|
|
33
|
-
const dir = cleanupDirs.pop();
|
|
34
|
-
if (dir) {
|
|
35
|
-
try {
|
|
36
|
-
fs.rmSync(dir, { recursive: true, force: true });
|
|
37
|
-
}
|
|
38
|
-
catch {
|
|
39
|
-
/* ignore */
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
});
|
|
44
|
-
describe("resolveConfigChain — P9.5 legacy field graceful ignore", () => {
|
|
45
|
-
it("legacy-only project config → loads without throw; OntoConfig type omits legacy keys", async () => {
|
|
46
|
-
// Pre-P9.5: `host_runtime: codex` + no `review:` block threw
|
|
47
|
-
// LegacyFieldRemovedError. Post-P9.5: loads successfully.
|
|
48
|
-
const homeDir = makeTmpDir("legacy-h");
|
|
49
|
-
const projDir = makeTmpDir("legacy-p");
|
|
50
|
-
writeConfig(projDir, "host_runtime: codex\napi_provider: codex\n");
|
|
51
|
-
// Must not throw. The promise resolving is the primary invariant.
|
|
52
|
-
const config = await resolveConfigChain(homeDir, projDir);
|
|
53
|
-
expect(config).toBeDefined();
|
|
54
|
-
// The OntoConfig type omits the legacy fields — typed access via
|
|
55
|
-
// `config.host_runtime` would be a TypeScript error. No runtime
|
|
56
|
-
// consumer reads these values; they remain in the underlying
|
|
57
|
-
// Record only for Record-cast backward compatibility.
|
|
58
|
-
expect(config.review).toBeUndefined();
|
|
59
|
-
expect(config.codex).toBeUndefined();
|
|
60
|
-
});
|
|
61
|
-
it("legacy fields + review block → config loads, review block survives and is authoritative", async () => {
|
|
62
|
-
const homeDir = makeTmpDir("mixed-h");
|
|
63
|
-
const projDir = makeTmpDir("mixed-p");
|
|
64
|
-
writeConfig(projDir, [
|
|
65
|
-
"host_runtime: anthropic", // legacy ghost field — not consumed
|
|
66
|
-
"review:",
|
|
67
|
-
" subagent:",
|
|
68
|
-
" provider: codex",
|
|
69
|
-
" model_id: gpt-5.4",
|
|
70
|
-
"codex:",
|
|
71
|
-
" model: gpt-5.4",
|
|
72
|
-
].join("\n"));
|
|
73
|
-
const config = await resolveConfigChain(homeDir, projDir);
|
|
74
|
-
// Review block (orthogonal) + codex namespace (profile) are the
|
|
75
|
-
// authoritative sources post-P9.5.
|
|
76
|
-
expect(config.review?.subagent?.provider).toBe("codex");
|
|
77
|
-
expect(config.codex?.model).toBe("gpt-5.4");
|
|
78
|
-
});
|
|
79
|
-
it("legacy-only home + absent project → home profile adopted via atomic adoption", async () => {
|
|
80
|
-
// Home has legacy-only YAML + a codex namespace. Pre-P9.5 the
|
|
81
|
-
// legacy throw would fire before adoption ran. Post-P9.5 adoption
|
|
82
|
-
// sees `hasAnyProfileField(home) === true` (via `codex`) and picks
|
|
83
|
-
// up the home profile; legacy fields are inert.
|
|
84
|
-
const homeDir = makeTmpDir("home-legacy-h");
|
|
85
|
-
const projDir = makeTmpDir("home-legacy-p");
|
|
86
|
-
writeConfig(homeDir, ["host_runtime: codex", "codex:", " model: gpt-5.4"].join("\n"));
|
|
87
|
-
// No project config.
|
|
88
|
-
const config = await resolveConfigChain(homeDir, projDir);
|
|
89
|
-
expect(config.codex?.model).toBe("gpt-5.4");
|
|
90
|
-
});
|
|
91
|
-
it("completely empty configs → loads without throw (resolver owns no_host fail-fast downstream)", async () => {
|
|
92
|
-
// Pre-P9.4 `buildBothIncompleteError` threw; pre-P9.5
|
|
93
|
-
// `LegacyFieldRemovedError` threw when legacy present. Post-P9.5
|
|
94
|
-
// config load never throws for these cases — the topology resolver
|
|
95
|
-
// is the sole fail-fast point via `no_host`.
|
|
96
|
-
const homeDir = makeTmpDir("empty-h");
|
|
97
|
-
const projDir = makeTmpDir("empty-p");
|
|
98
|
-
const config = await resolveConfigChain(homeDir, projDir);
|
|
99
|
-
expect(config).toBeDefined();
|
|
100
|
-
expect(config.codex).toBeUndefined();
|
|
101
|
-
expect(config.review).toBeUndefined();
|
|
102
|
-
});
|
|
103
|
-
});
|