onto-mcp 0.3.2 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.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 +135 -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 +149 -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 +207 -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,246 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect, beforeEach, afterEach, vi } from "vitest";
|
|
2
|
-
import { resolveExecutionTopology, } from "./execution-topology-resolver.js";
|
|
3
|
-
function args(overrides) {
|
|
4
|
-
return {
|
|
5
|
-
ontoConfig: {},
|
|
6
|
-
env: {},
|
|
7
|
-
claudeHost: false,
|
|
8
|
-
experimentalAgentTeams: false,
|
|
9
|
-
codexAvailable: false,
|
|
10
|
-
codexSessionActive: false,
|
|
11
|
-
liteLlmEndpointAvailable: false,
|
|
12
|
-
...overrides,
|
|
13
|
-
};
|
|
14
|
-
}
|
|
15
|
-
function expectResolved(res) {
|
|
16
|
-
if (res.type !== "resolved") {
|
|
17
|
-
throw new Error(`expected resolved, got no_host: ${res.reason.slice(0, 120)}`);
|
|
18
|
-
}
|
|
19
|
-
return res;
|
|
20
|
-
}
|
|
21
|
-
describe("resolveExecutionTopology — axis-first happy paths", () => {
|
|
22
|
-
let stderrSpy;
|
|
23
|
-
beforeEach(() => {
|
|
24
|
-
stderrSpy = vi.spyOn(process.stderr, "write").mockImplementation(() => true);
|
|
25
|
-
});
|
|
26
|
-
afterEach(() => {
|
|
27
|
-
stderrSpy.mockRestore();
|
|
28
|
-
});
|
|
29
|
-
it("Claude host + main-native axes → cc-main-agent-subagent", () => {
|
|
30
|
-
const res = resolveExecutionTopology(args({
|
|
31
|
-
ontoConfig: {
|
|
32
|
-
review: {
|
|
33
|
-
teamlead: { model: "main" },
|
|
34
|
-
subagent: { provider: "main-native" },
|
|
35
|
-
},
|
|
36
|
-
},
|
|
37
|
-
claudeHost: true,
|
|
38
|
-
}));
|
|
39
|
-
const r = expectResolved(res);
|
|
40
|
-
expect(r.topology.id).toBe("cc-main-agent-subagent");
|
|
41
|
-
expect(r.topology.plan_trace.some((l) => l.includes("topology source=review-axes")))
|
|
42
|
-
.toBe(true);
|
|
43
|
-
expect(r.topology.plan_trace.some((l) => l.includes("derived TopologyId=cc-main-agent-subagent")))
|
|
44
|
-
.toBe(true);
|
|
45
|
-
});
|
|
46
|
-
it("Claude host + codex subagent → cc-main-codex-subprocess", () => {
|
|
47
|
-
const res = resolveExecutionTopology(args({
|
|
48
|
-
ontoConfig: {
|
|
49
|
-
review: {
|
|
50
|
-
subagent: { provider: "codex", model_id: "gpt-5.4" },
|
|
51
|
-
},
|
|
52
|
-
},
|
|
53
|
-
claudeHost: true,
|
|
54
|
-
codexAvailable: true, // required by cc-main-codex-subprocess downstream check
|
|
55
|
-
}));
|
|
56
|
-
const r = expectResolved(res);
|
|
57
|
-
expect(r.topology.id).toBe("cc-main-codex-subprocess");
|
|
58
|
-
});
|
|
59
|
-
it("Codex host + main-native → codex-main-subprocess", () => {
|
|
60
|
-
const res = resolveExecutionTopology(args({
|
|
61
|
-
ontoConfig: {
|
|
62
|
-
review: {
|
|
63
|
-
subagent: { provider: "main-native" },
|
|
64
|
-
},
|
|
65
|
-
},
|
|
66
|
-
codexSessionActive: true,
|
|
67
|
-
codexAvailable: true, // required by codex-main-subprocess downstream check
|
|
68
|
-
}));
|
|
69
|
-
const r = expectResolved(res);
|
|
70
|
-
expect(r.topology.id).toBe("codex-main-subprocess");
|
|
71
|
-
});
|
|
72
|
-
it("Claude + teams + native + a2a → cc-teams-lens-agent-deliberation", () => {
|
|
73
|
-
const res = resolveExecutionTopology(args({
|
|
74
|
-
ontoConfig: {
|
|
75
|
-
review: {
|
|
76
|
-
subagent: { provider: "main-native" },
|
|
77
|
-
lens_deliberation: "sendmessage-a2a",
|
|
78
|
-
},
|
|
79
|
-
// The resolver's own requirement check for the deliberation
|
|
80
|
-
// topology ALSO inspects `lens_agent_teams_mode`. Set true so
|
|
81
|
-
// the topology passes the downstream requirement gate.
|
|
82
|
-
lens_agent_teams_mode: true,
|
|
83
|
-
},
|
|
84
|
-
claudeHost: true,
|
|
85
|
-
experimentalAgentTeams: true,
|
|
86
|
-
}));
|
|
87
|
-
const r = expectResolved(res);
|
|
88
|
-
expect(r.topology.id).toBe("cc-teams-lens-agent-deliberation");
|
|
89
|
-
});
|
|
90
|
-
it("external codex teamlead → codex-nested-subprocess", () => {
|
|
91
|
-
const res = resolveExecutionTopology(args({
|
|
92
|
-
ontoConfig: {
|
|
93
|
-
review: {
|
|
94
|
-
teamlead: { model: { provider: "codex", model_id: "gpt-5.4" } },
|
|
95
|
-
subagent: { provider: "codex", model_id: "gpt-5.4" },
|
|
96
|
-
},
|
|
97
|
-
},
|
|
98
|
-
// codex-nested-subprocess requires codex available + no CC session
|
|
99
|
-
codexAvailable: true,
|
|
100
|
-
claudeHost: false,
|
|
101
|
-
codexSessionActive: false,
|
|
102
|
-
}));
|
|
103
|
-
const r = expectResolved(res);
|
|
104
|
-
expect(r.topology.id).toBe("codex-nested-subprocess");
|
|
105
|
-
});
|
|
106
|
-
});
|
|
107
|
-
describe("resolveExecutionTopology — P3 universal fallback (degrade to main_native)", () => {
|
|
108
|
-
let stderrSpy;
|
|
109
|
-
beforeEach(() => {
|
|
110
|
-
stderrSpy = vi.spyOn(process.stderr, "write").mockImplementation(() => true);
|
|
111
|
-
});
|
|
112
|
-
afterEach(() => {
|
|
113
|
-
stderrSpy.mockRestore();
|
|
114
|
-
});
|
|
115
|
-
it("invalid review block degrades to main_native (NOT legacy ladder)", () => {
|
|
116
|
-
// Validator rejects `main-native + model_id`. Under P3, the degrade
|
|
117
|
-
// path maps `main_native` shape against Claude host →
|
|
118
|
-
// `cc-main-agent-subagent`. `execution_topology_priority` must NOT
|
|
119
|
-
// be consulted (we verify by including a distinct entry that would
|
|
120
|
-
// otherwise win).
|
|
121
|
-
const res = resolveExecutionTopology(args({
|
|
122
|
-
ontoConfig: {
|
|
123
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
124
|
-
review: {
|
|
125
|
-
subagent: { provider: "main-native", model_id: "x" },
|
|
126
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
127
|
-
},
|
|
128
|
-
},
|
|
129
|
-
claudeHost: true,
|
|
130
|
-
codexSessionActive: true,
|
|
131
|
-
codexAvailable: true,
|
|
132
|
-
}));
|
|
133
|
-
const r = expectResolved(res);
|
|
134
|
-
expect(r.topology.id).toBe("cc-main-agent-subagent");
|
|
135
|
-
expect(r.topology.plan_trace.some((l) => l.includes("validation failed"))).toBe(true);
|
|
136
|
-
expect(r.topology.plan_trace.some((l) => l.includes("degraded: requested=<validation-failed> → actual=main_native"))).toBe(true);
|
|
137
|
-
// source = review-axes because the degrade produced a single-entry
|
|
138
|
-
// TopologyId through the axis-first path; the legacy priority array
|
|
139
|
-
// was acknowledged (see "ignored" trace line) but never consulted.
|
|
140
|
-
expect(r.topology.plan_trace.some((l) => l.includes("topology source=review-axes"))).toBe(true);
|
|
141
|
-
});
|
|
142
|
-
it("derivation failure (a2a without teams) degrades to main_native", () => {
|
|
143
|
-
// sendmessage-a2a requested but CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=0.
|
|
144
|
-
// Derivation emits a violation — P3 degrade takes over, maps
|
|
145
|
-
// main_native to the Claude host → cc-main-agent-subagent.
|
|
146
|
-
const res = resolveExecutionTopology(args({
|
|
147
|
-
ontoConfig: {
|
|
148
|
-
review: {
|
|
149
|
-
subagent: { provider: "main-native" },
|
|
150
|
-
lens_deliberation: "sendmessage-a2a",
|
|
151
|
-
},
|
|
152
|
-
},
|
|
153
|
-
claudeHost: true,
|
|
154
|
-
codexSessionActive: true,
|
|
155
|
-
codexAvailable: true,
|
|
156
|
-
experimentalAgentTeams: false,
|
|
157
|
-
}));
|
|
158
|
-
const r = expectResolved(res);
|
|
159
|
-
expect(r.topology.id).toBe("cc-main-agent-subagent");
|
|
160
|
-
expect(r.topology.plan_trace.some((l) => l.includes("shape derivation failed"))).toBe(true);
|
|
161
|
-
expect(r.topology.plan_trace.some((l) => l.includes("degraded: requested=a2a-deliberation → actual=main_native"))).toBe(true);
|
|
162
|
-
expect(r.topology.plan_trace.some((l) => l.includes("topology source=review-axes"))).toBe(true);
|
|
163
|
-
});
|
|
164
|
-
it("axis mapping failure (main_foreign + litellm) degrades to main_native", () => {
|
|
165
|
-
// main_foreign shape with provider=litellm has NO TopologyId in the
|
|
166
|
-
// catalog (only codex mapped). P3 degrades to main_native, which
|
|
167
|
-
// under Claude host maps to cc-main-agent-subagent.
|
|
168
|
-
const res = resolveExecutionTopology(args({
|
|
169
|
-
ontoConfig: {
|
|
170
|
-
review: {
|
|
171
|
-
subagent: { provider: "litellm", model_id: "gpt-4o" },
|
|
172
|
-
},
|
|
173
|
-
},
|
|
174
|
-
claudeHost: true,
|
|
175
|
-
codexSessionActive: true,
|
|
176
|
-
codexAvailable: true,
|
|
177
|
-
}));
|
|
178
|
-
const r = expectResolved(res);
|
|
179
|
-
expect(r.topology.id).toBe("cc-main-agent-subagent");
|
|
180
|
-
expect(r.topology.plan_trace.some((l) => l.includes("mapping failed"))).toBe(true);
|
|
181
|
-
expect(r.topology.plan_trace.some((l) => l.includes("degraded: requested=main_foreign(litellm) → actual=main_native"))).toBe(true);
|
|
182
|
-
expect(r.topology.plan_trace.some((l) => l.includes("topology source=review-axes"))).toBe(true);
|
|
183
|
-
});
|
|
184
|
-
it("everything fails (main_native also unmappable) → no_host fail-fast", () => {
|
|
185
|
-
// P9.1 (2026-04-21): legacy priority ladder is retired. When axis
|
|
186
|
-
// derivation fails AND the `main_native` degrade cannot map (neither
|
|
187
|
-
// Claude nor Codex host), the resolver returns `no_host`. The
|
|
188
|
-
// `execution_topology_priority` array, even when pointing at an id
|
|
189
|
-
// whose prerequisites are met (here: codex-nested-subprocess via
|
|
190
|
-
// codex binary), is NOT consulted — ladder walking no longer exists.
|
|
191
|
-
const res = resolveExecutionTopology(args({
|
|
192
|
-
ontoConfig: {
|
|
193
|
-
review: {
|
|
194
|
-
subagent: { provider: "main-native" },
|
|
195
|
-
},
|
|
196
|
-
},
|
|
197
|
-
claudeHost: false,
|
|
198
|
-
codexSessionActive: false,
|
|
199
|
-
codexAvailable: true,
|
|
200
|
-
}));
|
|
201
|
-
if (res.type !== "no_host") {
|
|
202
|
-
throw new Error(`expected no_host, got resolved topology id=${res.topology.id}`);
|
|
203
|
-
}
|
|
204
|
-
expect(res.plan_trace.some((l) => l.includes("mapping failed"))).toBe(true);
|
|
205
|
-
expect(res.plan_trace.some((l) => l.includes("degraded: requested=main_native → actual=main_native"))).toBe(true);
|
|
206
|
-
expect(res.plan_trace.some((l) => l.includes("degrade-fallback: main_native unmappable"))).toBe(true);
|
|
207
|
-
expect(res.plan_trace.some((l) => l.includes("no topology resolved (axis-first + main_native fallback both failed)"))).toBe(true);
|
|
208
|
-
// Negative: the retired ladder's "priority source=config" log shape
|
|
209
|
-
// must NOT surface — any regression would revive the dead path.
|
|
210
|
-
expect(res.plan_trace.some((l) => l.includes("priority source="))).toBe(false);
|
|
211
|
-
// Regression guard (PR #161 review): when `config.review` is present
|
|
212
|
-
// but its internal degrade exhausts, the outer resolver must NOT
|
|
213
|
-
// invoke a second `attemptMainNativeDegrade` with a misleading
|
|
214
|
-
// `<review-block-absent>` label. Exactly one `degraded: requested=`
|
|
215
|
-
// line should appear, and it must not carry that sentinel.
|
|
216
|
-
expect(res.plan_trace.filter((l) => l.includes("degraded: requested=")).length).toBe(1);
|
|
217
|
-
expect(res.plan_trace.some((l) => l.includes("<review-block-absent>"))).toBe(false);
|
|
218
|
-
});
|
|
219
|
-
});
|
|
220
|
-
describe("resolveExecutionTopology — review absent → main_native degrade", () => {
|
|
221
|
-
let stderrSpy;
|
|
222
|
-
beforeEach(() => {
|
|
223
|
-
stderrSpy = vi.spyOn(process.stderr, "write").mockImplementation(() => true);
|
|
224
|
-
});
|
|
225
|
-
afterEach(() => {
|
|
226
|
-
stderrSpy.mockRestore();
|
|
227
|
-
});
|
|
228
|
-
it("no review block + CC host → main_native degrade → cc-main-agent-subagent", () => {
|
|
229
|
-
// P9.1 (2026-04-21): when `config.review` is absent, the resolver
|
|
230
|
-
// no longer walks the legacy priority ladder. It goes directly to
|
|
231
|
-
// the universal `main_native` degrade path with
|
|
232
|
-
// requested=<review-block-absent>. The degrade maps main_native
|
|
233
|
-
// against the Claude host → cc-main-agent-subagent.
|
|
234
|
-
const res = resolveExecutionTopology(args({
|
|
235
|
-
ontoConfig: {},
|
|
236
|
-
claudeHost: true,
|
|
237
|
-
}));
|
|
238
|
-
const r = expectResolved(res);
|
|
239
|
-
expect(r.topology.id).toBe("cc-main-agent-subagent");
|
|
240
|
-
// No axis-first trace: the review block was absent, so we never
|
|
241
|
-
// entered the axis pipeline — only the direct degrade.
|
|
242
|
-
expect(r.topology.plan_trace.some((l) => l.includes("review-axes: "))).toBe(false);
|
|
243
|
-
expect(r.topology.plan_trace.some((l) => l.includes("degraded: requested=<review-block-absent>"))).toBe(true);
|
|
244
|
-
expect(r.topology.plan_trace.some((l) => l.includes("topology source=fallback-main-native"))).toBe(true);
|
|
245
|
-
});
|
|
246
|
-
});
|
|
@@ -1,401 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Execution Topology Resolver — axis-first only (P9.1, 2026-04-21).
|
|
3
|
-
*
|
|
4
|
-
* # What this module is
|
|
5
|
-
*
|
|
6
|
-
* Single seat for selecting ONE canonical execution topology for a review
|
|
7
|
-
* session. Topology is the top-level decision — teamlead location + lens
|
|
8
|
-
* spawn mechanism + deliberation channel.
|
|
9
|
-
*
|
|
10
|
-
* # Why it exists
|
|
11
|
-
*
|
|
12
|
-
* `config.review` is the canonical execution intent. Invalid or unsupported
|
|
13
|
-
* axes fail loudly.
|
|
14
|
-
*
|
|
15
|
-
* # How it relates
|
|
16
|
-
*
|
|
17
|
-
* - `resolveExecutionTopology()` — run axis-first derivation →
|
|
18
|
-
* prerequisite check → return topology or `no_host`. Emits `[topology]`
|
|
19
|
-
* STDERR for every branch (mirrors `[plan]` pattern from PR #96).
|
|
20
|
-
* - `TOPOLOGY_CATALOG` — metadata for the 8 canonical options.
|
|
21
|
-
* - `DIRECT_SPAWN_SUPPORTED_TOPOLOGIES` — spawn-time support set.
|
|
22
|
-
*
|
|
23
|
-
* # Design reference
|
|
24
|
-
*
|
|
25
|
-
* - P9 handoff: `project_review_ux_redesign_p9_handoff.md` (memory)
|
|
26
|
-
* - Completion doc: `development-records/evolve/20260421-review-ux-redesign-completion.md`
|
|
27
|
-
* - Sketch v3: `development-records/evolve/20260418-execution-topology-priority-sketch.md`
|
|
28
|
-
*/
|
|
29
|
-
import { detectClaudeCodeEnvSignal, detectCodexBinaryAvailable, detectCodexEnvSignal, } from "../discovery/host-detection.js";
|
|
30
|
-
import { validateReviewConfig } from "./review-config-validator.js";
|
|
31
|
-
import { deriveTopologyShape, } from "./topology-shape-derivation.js";
|
|
32
|
-
import { shapeToTopologyId } from "./shape-to-topology-id.js";
|
|
33
|
-
/**
|
|
34
|
-
* Canonical metadata for each topology option.
|
|
35
|
-
*
|
|
36
|
-
* Per sketch v3 §3: once a topology id is chosen, all other attributes
|
|
37
|
-
* (teamlead location, spawn mechanism, max concurrency, transport rank,
|
|
38
|
-
* deliberation channel) are static. Principal cannot override them
|
|
39
|
-
* individually — they must change the topology id.
|
|
40
|
-
*
|
|
41
|
-
* `execution_topology_overrides` in config allows per-topology
|
|
42
|
-
* `max_concurrent_lenses` adjustment only. Other fields are immutable.
|
|
43
|
-
*/
|
|
44
|
-
export const TOPOLOGY_CATALOG = {
|
|
45
|
-
"cc-teams-lens-agent-deliberation": {
|
|
46
|
-
id: "cc-teams-lens-agent-deliberation",
|
|
47
|
-
teamlead_location: "claude-teamcreate",
|
|
48
|
-
lens_spawn_mechanism: "claude-teamcreate-member",
|
|
49
|
-
max_concurrent_lenses: 10,
|
|
50
|
-
transport_rank: "S2",
|
|
51
|
-
deliberation_channel: "controlled-lens-deliberation",
|
|
52
|
-
},
|
|
53
|
-
"cc-teams-agent-subagent": {
|
|
54
|
-
id: "cc-teams-agent-subagent",
|
|
55
|
-
teamlead_location: "claude-teamcreate",
|
|
56
|
-
lens_spawn_mechanism: "claude-agent-tool",
|
|
57
|
-
max_concurrent_lenses: 10,
|
|
58
|
-
transport_rank: "S2",
|
|
59
|
-
deliberation_channel: "controlled-lens-deliberation",
|
|
60
|
-
},
|
|
61
|
-
"cc-teams-codex-subprocess": {
|
|
62
|
-
id: "cc-teams-codex-subprocess",
|
|
63
|
-
teamlead_location: "claude-teamcreate",
|
|
64
|
-
lens_spawn_mechanism: "codex-subprocess",
|
|
65
|
-
max_concurrent_lenses: 5,
|
|
66
|
-
transport_rank: "S0",
|
|
67
|
-
deliberation_channel: "controlled-lens-deliberation",
|
|
68
|
-
},
|
|
69
|
-
"cc-main-agent-subagent": {
|
|
70
|
-
id: "cc-main-agent-subagent",
|
|
71
|
-
teamlead_location: "onto-main",
|
|
72
|
-
lens_spawn_mechanism: "claude-agent-tool",
|
|
73
|
-
max_concurrent_lenses: 10,
|
|
74
|
-
transport_rank: "S2",
|
|
75
|
-
deliberation_channel: "controlled-lens-deliberation",
|
|
76
|
-
},
|
|
77
|
-
"cc-main-codex-subprocess": {
|
|
78
|
-
id: "cc-main-codex-subprocess",
|
|
79
|
-
teamlead_location: "onto-main",
|
|
80
|
-
lens_spawn_mechanism: "codex-subprocess",
|
|
81
|
-
max_concurrent_lenses: 5,
|
|
82
|
-
transport_rank: "S0",
|
|
83
|
-
deliberation_channel: "controlled-lens-deliberation",
|
|
84
|
-
},
|
|
85
|
-
"codex-nested-subprocess": {
|
|
86
|
-
id: "codex-nested-subprocess",
|
|
87
|
-
teamlead_location: "codex-subprocess",
|
|
88
|
-
lens_spawn_mechanism: "codex-subprocess",
|
|
89
|
-
max_concurrent_lenses: 5,
|
|
90
|
-
transport_rank: "S0",
|
|
91
|
-
deliberation_channel: "controlled-lens-deliberation",
|
|
92
|
-
},
|
|
93
|
-
"codex-main-subprocess": {
|
|
94
|
-
id: "codex-main-subprocess",
|
|
95
|
-
teamlead_location: "onto-main",
|
|
96
|
-
lens_spawn_mechanism: "codex-subprocess",
|
|
97
|
-
max_concurrent_lenses: 5,
|
|
98
|
-
transport_rank: "S0",
|
|
99
|
-
deliberation_channel: "controlled-lens-deliberation",
|
|
100
|
-
},
|
|
101
|
-
};
|
|
102
|
-
/**
|
|
103
|
-
* Topology ids whose spawn path is implemented in the direct executor path.
|
|
104
|
-
*/
|
|
105
|
-
export const DIRECT_SPAWN_SUPPORTED_TOPOLOGIES = new Set([
|
|
106
|
-
"cc-main-agent-subagent",
|
|
107
|
-
"cc-main-codex-subprocess",
|
|
108
|
-
"codex-main-subprocess",
|
|
109
|
-
]);
|
|
110
|
-
// ---------------------------------------------------------------------------
|
|
111
|
-
// Observability
|
|
112
|
-
// ---------------------------------------------------------------------------
|
|
113
|
-
/**
|
|
114
|
-
* Emit a `[topology]` prefixed decision line to STDERR.
|
|
115
|
-
*
|
|
116
|
-
* Parallels the `[plan]`, `[model-call]`, `[plan:executor]` prefixes.
|
|
117
|
-
* `[topology]` sits at the top
|
|
118
|
-
* of the layer stack: a reviewer scanning STDERR sees `[topology]` first
|
|
119
|
-
* (macro decision) then `[plan]` (projection details) then `[model-call]`
|
|
120
|
-
* (per-request invocation).
|
|
121
|
-
*
|
|
122
|
-
* No suppressor env var: topology decisions are load-bearing for review
|
|
123
|
-
* reproducibility. Tests capture via `vi.spyOn(process.stderr, "write")`.
|
|
124
|
-
*/
|
|
125
|
-
function emitTopologyLog(line) {
|
|
126
|
-
process.stderr.write(`[topology] ${line}\n`);
|
|
127
|
-
}
|
|
128
|
-
/**
|
|
129
|
-
* Evaluate whether the given topology id's prerequisites are satisfied by
|
|
130
|
-
* the current detection signals. Returns a `{ ok, reason }` pair: `reason`
|
|
131
|
-
* is populated for both branches so trace output explains matches AND skips.
|
|
132
|
-
*/
|
|
133
|
-
function checkTopologyRequirements(id, signals) {
|
|
134
|
-
switch (id) {
|
|
135
|
-
case "cc-teams-lens-agent-deliberation": {
|
|
136
|
-
if (!signals.claudeHost)
|
|
137
|
-
return { ok: false, reason: "need CLAUDECODE=1" };
|
|
138
|
-
if (!signals.experimentalAgentTeams) {
|
|
139
|
-
return { ok: false, reason: "need CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1" };
|
|
140
|
-
}
|
|
141
|
-
if (!signals.lensAgentTeamsMode) {
|
|
142
|
-
return { ok: false, reason: "need config.lens_agent_teams_mode=true" };
|
|
143
|
-
}
|
|
144
|
-
return { ok: true, reason: "CLAUDECODE + experimental-teams + lens_agent_teams_mode all set" };
|
|
145
|
-
}
|
|
146
|
-
case "cc-teams-agent-subagent": {
|
|
147
|
-
if (!signals.claudeHost)
|
|
148
|
-
return { ok: false, reason: "need CLAUDECODE=1" };
|
|
149
|
-
if (!signals.experimentalAgentTeams) {
|
|
150
|
-
return { ok: false, reason: "need CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1" };
|
|
151
|
-
}
|
|
152
|
-
return { ok: true, reason: "CLAUDECODE + experimental-teams set" };
|
|
153
|
-
}
|
|
154
|
-
case "cc-teams-codex-subprocess": {
|
|
155
|
-
if (!signals.claudeHost)
|
|
156
|
-
return { ok: false, reason: "need CLAUDECODE=1" };
|
|
157
|
-
if (!signals.experimentalAgentTeams) {
|
|
158
|
-
return { ok: false, reason: "need CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1" };
|
|
159
|
-
}
|
|
160
|
-
if (!signals.codexAvailable) {
|
|
161
|
-
return { ok: false, reason: "need codex binary + ~/.codex/auth.json" };
|
|
162
|
-
}
|
|
163
|
-
return { ok: true, reason: "CLAUDECODE + experimental-teams + codex binary all set" };
|
|
164
|
-
}
|
|
165
|
-
case "cc-main-agent-subagent": {
|
|
166
|
-
if (!signals.claudeHost)
|
|
167
|
-
return { ok: false, reason: "need CLAUDECODE=1" };
|
|
168
|
-
return { ok: true, reason: "CLAUDECODE=1 detected" };
|
|
169
|
-
}
|
|
170
|
-
case "cc-main-codex-subprocess": {
|
|
171
|
-
if (!signals.claudeHost)
|
|
172
|
-
return { ok: false, reason: "need CLAUDECODE=1" };
|
|
173
|
-
if (!signals.codexAvailable) {
|
|
174
|
-
return { ok: false, reason: "need codex binary + ~/.codex/auth.json" };
|
|
175
|
-
}
|
|
176
|
-
return { ok: true, reason: "CLAUDECODE + codex binary both present" };
|
|
177
|
-
}
|
|
178
|
-
case "codex-nested-subprocess": {
|
|
179
|
-
if (!signals.codexAvailable) {
|
|
180
|
-
return { ok: false, reason: "need codex binary + ~/.codex/auth.json" };
|
|
181
|
-
}
|
|
182
|
-
return { ok: true, reason: "codex binary present (host-agnostic)" };
|
|
183
|
-
}
|
|
184
|
-
case "codex-main-subprocess": {
|
|
185
|
-
if (!signals.codexSessionActive) {
|
|
186
|
-
return { ok: false, reason: "need Codex execution request or CLI session signal (CODEX_THREAD_ID / CODEX_CI)" };
|
|
187
|
-
}
|
|
188
|
-
if (!signals.codexAvailable) {
|
|
189
|
-
return { ok: false, reason: "need codex binary + ~/.codex/auth.json" };
|
|
190
|
-
}
|
|
191
|
-
return { ok: true, reason: "codex execution/session + codex binary both present" };
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
|
-
}
|
|
195
|
-
// ---------------------------------------------------------------------------
|
|
196
|
-
// Main resolver
|
|
197
|
-
// ---------------------------------------------------------------------------
|
|
198
|
-
/**
|
|
199
|
-
* Derive a single ExecutionTopology for this review session.
|
|
200
|
-
*
|
|
201
|
-
* Decision surface:
|
|
202
|
-
* 1. `config.review` must be present.
|
|
203
|
-
* 2. The axis block must validate and map to a known topology.
|
|
204
|
-
* 3. The chosen topology must satisfy its environment requirements.
|
|
205
|
-
*
|
|
206
|
-
* After a TopologyId is resolved, `checkTopologyRequirements` still runs
|
|
207
|
-
* against it — the axis/shape pipeline gates on host presence only, while
|
|
208
|
-
* `checkTopologyRequirements` covers the full signal set (codex binary,
|
|
209
|
-
* experimental flag, etc). A requirement miss yields `no_host`.
|
|
210
|
-
*
|
|
211
|
-
* Returns:
|
|
212
|
-
* - `{ type: "resolved", topology }` — resolved id passed its requirements.
|
|
213
|
-
* - `{ type: "no_host", plan_trace, reason }`
|
|
214
|
-
*/
|
|
215
|
-
export function resolveExecutionTopology(args) {
|
|
216
|
-
const env = args.env ?? process.env;
|
|
217
|
-
const trace = [];
|
|
218
|
-
const log = (line) => {
|
|
219
|
-
emitTopologyLog(line);
|
|
220
|
-
trace.push(line);
|
|
221
|
-
};
|
|
222
|
-
const signals = {
|
|
223
|
-
claudeHost: args.claudeHost ?? detectClaudeCodeEnvSignal(),
|
|
224
|
-
experimentalAgentTeams: args.experimentalAgentTeams ?? env.CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS === "1",
|
|
225
|
-
lensAgentTeamsMode: args.ontoConfig.lens_agent_teams_mode === true,
|
|
226
|
-
codexAvailable: args.codexAvailable ?? detectCodexBinaryAvailable(),
|
|
227
|
-
codexSessionActive: (args.codexSessionActive ?? detectCodexEnvSignal()) ||
|
|
228
|
-
args.codexExecutionRequested === true,
|
|
229
|
-
};
|
|
230
|
-
log(`signals: claudeHost=${signals.claudeHost} experimental=${signals.experimentalAgentTeams} ` +
|
|
231
|
-
`lens_agent_teams_mode=${signals.lensAgentTeamsMode} codex=${signals.codexAvailable} ` +
|
|
232
|
-
`codex_session=${signals.codexSessionActive}`);
|
|
233
|
-
const axisFirstId = resolveAxisFirstTopology(args.ontoConfig, signals, log);
|
|
234
|
-
if (!axisFirstId) {
|
|
235
|
-
log("no topology resolved");
|
|
236
|
-
return {
|
|
237
|
-
type: "no_host",
|
|
238
|
-
plan_trace: trace,
|
|
239
|
-
reason: buildNoTopologyReason(signals),
|
|
240
|
-
};
|
|
241
|
-
}
|
|
242
|
-
log(`topology source=review-axes id=${axisFirstId}`);
|
|
243
|
-
const check = checkTopologyRequirements(axisFirstId, signals);
|
|
244
|
-
if (!check.ok) {
|
|
245
|
-
log(`${axisFirstId}: skip — ${check.reason}`);
|
|
246
|
-
log("derived topology failed detailed requirements check");
|
|
247
|
-
return {
|
|
248
|
-
type: "no_host",
|
|
249
|
-
plan_trace: trace,
|
|
250
|
-
reason: buildNoTopologyReason(signals),
|
|
251
|
-
};
|
|
252
|
-
}
|
|
253
|
-
log(`${axisFirstId}: matched — ${check.reason}`);
|
|
254
|
-
const metadata = applyReviewConcurrencyOverride(TOPOLOGY_CATALOG[axisFirstId], args.ontoConfig.review?.max_concurrent_lenses, log);
|
|
255
|
-
return {
|
|
256
|
-
type: "resolved",
|
|
257
|
-
topology: { ...metadata, plan_trace: trace },
|
|
258
|
-
};
|
|
259
|
-
}
|
|
260
|
-
/**
|
|
261
|
-
* Apply `review.max_concurrent_lenses` (Axis C) on top of the catalog
|
|
262
|
-
* default. P9.2 (2026-04-21) made this the canonical override seat — the
|
|
263
|
-
* previous `execution_topology_overrides` map was removed. Non-positive
|
|
264
|
-
* values are ignored (fall back to catalog default) with a warning log.
|
|
265
|
-
*/
|
|
266
|
-
function applyReviewConcurrencyOverride(metadata, requested, log) {
|
|
267
|
-
if (requested === undefined)
|
|
268
|
-
return metadata;
|
|
269
|
-
// The TypeScript type already narrows `requested` to `number`, but
|
|
270
|
-
// YAML parsing can yield `"6"` (string) or other non-numeric shapes
|
|
271
|
-
// for this field. The runtime typeof check is defensive against that
|
|
272
|
-
// parse-time coercion, not against typed in-process call sites.
|
|
273
|
-
if (typeof requested !== "number" || requested <= 0) {
|
|
274
|
-
log(`${metadata.id}: review.max_concurrent_lenses=${requested} ignored (must be positive integer)`);
|
|
275
|
-
return metadata;
|
|
276
|
-
}
|
|
277
|
-
if (requested === metadata.max_concurrent_lenses)
|
|
278
|
-
return metadata;
|
|
279
|
-
log(`${metadata.id}: override max_concurrent_lenses ${metadata.max_concurrent_lenses} → ${requested} (via review.max_concurrent_lenses)`);
|
|
280
|
-
return { ...metadata, max_concurrent_lenses: requested };
|
|
281
|
-
}
|
|
282
|
-
// ---------------------------------------------------------------------------
|
|
283
|
-
// Error message composition
|
|
284
|
-
// ---------------------------------------------------------------------------
|
|
285
|
-
function buildNoTopologyReason(signals) {
|
|
286
|
-
const lines = [];
|
|
287
|
-
lines.push("Execution topology 를 도출할 수 없습니다.");
|
|
288
|
-
lines.push("");
|
|
289
|
-
lines.push("현재 환경 시그널:");
|
|
290
|
-
lines.push(` - Claude Code 세션 (CLAUDECODE=1): ${signals.claudeHost}`);
|
|
291
|
-
lines.push(` - Experimental Agent Teams: ${signals.experimentalAgentTeams}`);
|
|
292
|
-
lines.push(` - Lens Agent Teams mode (config): ${signals.lensAgentTeamsMode}`);
|
|
293
|
-
lines.push(` - Codex 바이너리 + ~/.codex/auth.json: ${signals.codexAvailable}`);
|
|
294
|
-
lines.push(` - Codex 실행 요청 / CLI 세션 (CODEX_THREAD_ID / CODEX_CI): ${signals.codexSessionActive}`);
|
|
295
|
-
lines.push("");
|
|
296
|
-
lines.push("해결 방법 (한 가지 선택):");
|
|
297
|
-
lines.push(" 1. Claude Code 세션에서 실행");
|
|
298
|
-
lines.push(" 2. codex CLI 설치 + `codex login` 구성");
|
|
299
|
-
lines.push(" 3. `.onto/config.yml` 의 `review:` axis block 을 현재 환경에서 실행 가능한 형태로 조정");
|
|
300
|
-
return lines.join("\n");
|
|
301
|
-
}
|
|
302
|
-
// ---------------------------------------------------------------------------
|
|
303
|
-
// Spawn-time support check
|
|
304
|
-
// ---------------------------------------------------------------------------
|
|
305
|
-
/**
|
|
306
|
-
* Error thrown when a resolver picks an option this install cannot spawn.
|
|
307
|
-
*
|
|
308
|
-
* The resolver itself never throws — it always returns a resolution.
|
|
309
|
-
* Callers dispatching to executors call `assertDirectSpawnSupported(topology)`
|
|
310
|
-
* before attempting to spawn.
|
|
311
|
-
*/
|
|
312
|
-
export class UnsupportedTopologyError extends Error {
|
|
313
|
-
topologyId;
|
|
314
|
-
constructor(topologyId) {
|
|
315
|
-
super(buildUnsupportedTopologyMessage(topologyId));
|
|
316
|
-
this.topologyId = topologyId;
|
|
317
|
-
this.name = "UnsupportedTopologyError";
|
|
318
|
-
}
|
|
319
|
-
}
|
|
320
|
-
function buildUnsupportedTopologyMessage(id) {
|
|
321
|
-
const supported = [...DIRECT_SPAWN_SUPPORTED_TOPOLOGIES].join(", ");
|
|
322
|
-
const requiredSurface = id === "cc-teams-agent-subagent" ||
|
|
323
|
-
id === "cc-teams-codex-subprocess"
|
|
324
|
-
? "TeamCreate coordinator execution"
|
|
325
|
-
: id === "codex-nested-subprocess"
|
|
326
|
-
? "external codex teamlead execution"
|
|
327
|
-
: id === "cc-teams-lens-agent-deliberation"
|
|
328
|
-
? "controlled deliberation transport"
|
|
329
|
-
: "provider adapter design";
|
|
330
|
-
return [
|
|
331
|
-
`ExecutionTopology id="${id}" 는 현 설치에서 직접 spawn 할 수 없습니다. 필요한 실행 표면: ${requiredSurface}.`,
|
|
332
|
-
"지원되는 topology:",
|
|
333
|
-
...[...DIRECT_SPAWN_SUPPORTED_TOPOLOGIES].map((s) => ` - ${s}`),
|
|
334
|
-
"",
|
|
335
|
-
`Direct spawn 지원 옵션: ${supported}`,
|
|
336
|
-
].join("\n");
|
|
337
|
-
}
|
|
338
|
-
/**
|
|
339
|
-
* Guard used by spawn-time code. Throws `UnsupportedTopologyError` when the
|
|
340
|
-
* resolved topology is not wired for direct spawn in the current install.
|
|
341
|
-
*/
|
|
342
|
-
export function assertDirectSpawnSupported(topology) {
|
|
343
|
-
if (!DIRECT_SPAWN_SUPPORTED_TOPOLOGIES.has(topology.id)) {
|
|
344
|
-
throw new UnsupportedTopologyError(topology.id);
|
|
345
|
-
}
|
|
346
|
-
}
|
|
347
|
-
// ---------------------------------------------------------------------------
|
|
348
|
-
// P2 axis-first helper (Review UX Redesign)
|
|
349
|
-
// ---------------------------------------------------------------------------
|
|
350
|
-
/**
|
|
351
|
-
* Attempt to derive a `TopologyId` from the `review:` axis block.
|
|
352
|
-
*/
|
|
353
|
-
function resolveAxisFirstTopology(config, signals, log) {
|
|
354
|
-
const reviewBlock = config.review;
|
|
355
|
-
if (reviewBlock === undefined) {
|
|
356
|
-
return null;
|
|
357
|
-
}
|
|
358
|
-
const validation = validateReviewConfig(reviewBlock);
|
|
359
|
-
if (!validation.ok) {
|
|
360
|
-
log("review-axes: validation failed");
|
|
361
|
-
for (const err of validation.errors) {
|
|
362
|
-
log(`review-axes: invalid — ${err.path}: ${err.message}`);
|
|
363
|
-
}
|
|
364
|
-
return null;
|
|
365
|
-
}
|
|
366
|
-
const derivationSignals = {
|
|
367
|
-
claudeHost: signals.claudeHost,
|
|
368
|
-
codexSessionActive: signals.codexSessionActive,
|
|
369
|
-
experimentalAgentTeams: signals.experimentalAgentTeams,
|
|
370
|
-
lensAgentTeamsMode: signals.lensAgentTeamsMode,
|
|
371
|
-
};
|
|
372
|
-
const derivation = deriveTopologyShape(validation.config, derivationSignals);
|
|
373
|
-
for (const line of derivation.ok ? derivation.derived.trace : derivation.trace) {
|
|
374
|
-
log(`review-axes: ${line}`);
|
|
375
|
-
}
|
|
376
|
-
if (!derivation.ok) {
|
|
377
|
-
log("review-axes: shape derivation failed");
|
|
378
|
-
for (const reason of derivation.reasons) {
|
|
379
|
-
log(`review-axes: ${reason}`);
|
|
380
|
-
}
|
|
381
|
-
return null;
|
|
382
|
-
}
|
|
383
|
-
const mapping = shapeToTopologyId({
|
|
384
|
-
shape: derivation.derived.shape,
|
|
385
|
-
subagent_provider: derivation.derived.subagent_provider,
|
|
386
|
-
signals: {
|
|
387
|
-
claudeHost: signals.claudeHost,
|
|
388
|
-
codexSessionActive: signals.codexSessionActive,
|
|
389
|
-
},
|
|
390
|
-
});
|
|
391
|
-
for (const line of mapping.trace) {
|
|
392
|
-
log(`review-axes: ${line}`);
|
|
393
|
-
}
|
|
394
|
-
if (!mapping.ok) {
|
|
395
|
-
log("review-axes: shape→TopologyId mapping failed");
|
|
396
|
-
log(`review-axes: ${mapping.reason}`);
|
|
397
|
-
return null;
|
|
398
|
-
}
|
|
399
|
-
log(`review-axes: derived TopologyId=${mapping.topology_id}`);
|
|
400
|
-
return mapping.topology_id;
|
|
401
|
-
}
|