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,201 +0,0 @@
|
|
|
1
|
-
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
|
2
|
-
import { tryResolveTopologyForHandoff, tryTopologyDerivedExecutor, } from "./review-invoke.js";
|
|
3
|
-
// ---------------------------------------------------------------------------
|
|
4
|
-
// P9.3-m1 Resolver caching invariants (2026-04-21):
|
|
5
|
-
//
|
|
6
|
-
// `runReviewInvokeCli` resolves `resolveExecutionTopology` exactly once
|
|
7
|
-
// per invocation and threads the result as `cached` to 3 downstream
|
|
8
|
-
// consumers. This file protects the cache plumbing from future
|
|
9
|
-
// regressions — a caller that accidentally drops the `cached` argument
|
|
10
|
-
// (reverting to the 3x resolver-call pattern) would re-emit the full
|
|
11
|
-
// `[topology]` STDERR trace, which these tests assert does NOT happen.
|
|
12
|
-
//
|
|
13
|
-
// The `[topology] signals:` line is the most stable counter because
|
|
14
|
-
// `resolveExecutionTopology` emits it exactly once at the very start of
|
|
15
|
-
// each invocation (see execution-topology-resolver.ts:413). When the
|
|
16
|
-
// helpers honour `cached`, they skip the resolver entirely and this
|
|
17
|
-
// line MUST NOT appear.
|
|
18
|
-
// ---------------------------------------------------------------------------
|
|
19
|
-
const FAKE_HOME = "/tmp/fake-onto-home";
|
|
20
|
-
const CACHED_LITELLM_TOPOLOGY = {
|
|
21
|
-
id: "cc-teams-litellm-sessions",
|
|
22
|
-
teamlead_location: "claude-teamcreate",
|
|
23
|
-
lens_spawn_mechanism: "litellm-http",
|
|
24
|
-
max_concurrent_lenses: 3,
|
|
25
|
-
transport_rank: "S2",
|
|
26
|
-
deliberation_channel: "synthesizer-only",
|
|
27
|
-
plan_trace: ["cached-by-runReviewInvokeCli"],
|
|
28
|
-
};
|
|
29
|
-
const CACHED_CC_MAIN_TOPOLOGY = {
|
|
30
|
-
id: "cc-main-agent-subagent",
|
|
31
|
-
teamlead_location: "onto-main",
|
|
32
|
-
lens_spawn_mechanism: "claude-agent-tool",
|
|
33
|
-
max_concurrent_lenses: 3,
|
|
34
|
-
transport_rank: "S0",
|
|
35
|
-
deliberation_channel: "synthesizer-only",
|
|
36
|
-
plan_trace: ["cached-by-runReviewInvokeCli"],
|
|
37
|
-
};
|
|
38
|
-
describe("tryResolveTopologyForHandoff — cached topology bypass", () => {
|
|
39
|
-
const originalEnv = { ...process.env };
|
|
40
|
-
let stderrSpy;
|
|
41
|
-
beforeEach(() => {
|
|
42
|
-
delete process.env.CLAUDECODE;
|
|
43
|
-
delete process.env.CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS;
|
|
44
|
-
stderrSpy = vi.spyOn(process.stderr, "write").mockImplementation(() => true);
|
|
45
|
-
});
|
|
46
|
-
afterEach(() => {
|
|
47
|
-
stderrSpy.mockRestore();
|
|
48
|
-
for (const k of Object.keys(process.env)) {
|
|
49
|
-
if (!(k in originalEnv))
|
|
50
|
-
delete process.env[k];
|
|
51
|
-
}
|
|
52
|
-
for (const [k, v] of Object.entries(originalEnv)) {
|
|
53
|
-
process.env[k] = v;
|
|
54
|
-
}
|
|
55
|
-
});
|
|
56
|
-
function signalsTraceLines() {
|
|
57
|
-
return stderrSpy.mock.calls
|
|
58
|
-
.map((c) => String(c[0]))
|
|
59
|
-
.filter((l) => l.startsWith("[topology] signals:"));
|
|
60
|
-
}
|
|
61
|
-
it("cached=ExecutionTopology → descriptor returned without re-running resolver", () => {
|
|
62
|
-
const descriptor = tryResolveTopologyForHandoff({}, CACHED_LITELLM_TOPOLOGY);
|
|
63
|
-
expect(descriptor).not.toBeNull();
|
|
64
|
-
expect(descriptor.id).toBe("cc-teams-litellm-sessions");
|
|
65
|
-
expect(descriptor.teamlead_location).toBe("claude-teamcreate");
|
|
66
|
-
expect(signalsTraceLines()).toHaveLength(0);
|
|
67
|
-
});
|
|
68
|
-
it("cached=null → returns null without re-running resolver", () => {
|
|
69
|
-
const descriptor = tryResolveTopologyForHandoff({}, null);
|
|
70
|
-
expect(descriptor).toBeNull();
|
|
71
|
-
expect(signalsTraceLines()).toHaveLength(0);
|
|
72
|
-
});
|
|
73
|
-
it("cached=undefined → legacy behaviour (resolver runs, emits signals)", () => {
|
|
74
|
-
// Two-argument call path preserved for test-harness compatibility;
|
|
75
|
-
// this branch is what existing tests exercise.
|
|
76
|
-
tryResolveTopologyForHandoff({});
|
|
77
|
-
expect(signalsTraceLines()).toHaveLength(1);
|
|
78
|
-
});
|
|
79
|
-
});
|
|
80
|
-
describe("tryTopologyDerivedExecutor — cached topology bypass", () => {
|
|
81
|
-
const originalEnv = { ...process.env };
|
|
82
|
-
let stderrSpy;
|
|
83
|
-
beforeEach(() => {
|
|
84
|
-
delete process.env.CLAUDECODE;
|
|
85
|
-
delete process.env.CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS;
|
|
86
|
-
stderrSpy = vi.spyOn(process.stderr, "write").mockImplementation(() => true);
|
|
87
|
-
});
|
|
88
|
-
afterEach(() => {
|
|
89
|
-
stderrSpy.mockRestore();
|
|
90
|
-
for (const k of Object.keys(process.env)) {
|
|
91
|
-
if (!(k in originalEnv))
|
|
92
|
-
delete process.env[k];
|
|
93
|
-
}
|
|
94
|
-
for (const [k, v] of Object.entries(originalEnv)) {
|
|
95
|
-
process.env[k] = v;
|
|
96
|
-
}
|
|
97
|
-
});
|
|
98
|
-
function signalsTraceLines() {
|
|
99
|
-
return stderrSpy.mock.calls
|
|
100
|
-
.map((c) => String(c[0]))
|
|
101
|
-
.filter((l) => l.startsWith("[topology] signals:"));
|
|
102
|
-
}
|
|
103
|
-
it("cached=ExecutionTopology (binary-backed) → executor returned without re-running resolver", () => {
|
|
104
|
-
const result = tryTopologyDerivedExecutor({ llm_base_url: "http://localhost:4000" }, FAKE_HOME, CACHED_LITELLM_TOPOLOGY);
|
|
105
|
-
expect(result).not.toBeNull();
|
|
106
|
-
expect(result.bin).toBe("node");
|
|
107
|
-
expect(result.args[0]).toContain("inline-http-review-unit-executor.js");
|
|
108
|
-
expect(signalsTraceLines()).toHaveLength(0);
|
|
109
|
-
});
|
|
110
|
-
it("cached=ExecutionTopology (no standalone binary) → null without re-running resolver", () => {
|
|
111
|
-
const result = tryTopologyDerivedExecutor({}, FAKE_HOME, CACHED_CC_MAIN_TOPOLOGY);
|
|
112
|
-
expect(result).toBeNull();
|
|
113
|
-
expect(signalsTraceLines()).toHaveLength(0);
|
|
114
|
-
});
|
|
115
|
-
it("cached=null → null without re-running resolver", () => {
|
|
116
|
-
const result = tryTopologyDerivedExecutor({}, FAKE_HOME, null);
|
|
117
|
-
expect(result).toBeNull();
|
|
118
|
-
expect(signalsTraceLines()).toHaveLength(0);
|
|
119
|
-
});
|
|
120
|
-
it("cached=undefined → legacy behaviour (resolver runs, emits signals)", () => {
|
|
121
|
-
process.env.CLAUDECODE = "1";
|
|
122
|
-
tryTopologyDerivedExecutor({}, FAKE_HOME);
|
|
123
|
-
expect(signalsTraceLines()).toHaveLength(1);
|
|
124
|
-
});
|
|
125
|
-
});
|
|
126
|
-
// ---------------------------------------------------------------------------
|
|
127
|
-
// Integration-layer invariant: exercise the 3-consumer contract that
|
|
128
|
-
// `runReviewInvokeCli` depends on. The stderr-based tests above prove
|
|
129
|
-
// the helper-level contract; these tests prove the full-dispatch
|
|
130
|
-
// consumer sequence (tryResolveTopologyForHandoff + tryTopologyDerivedExecutor
|
|
131
|
-
// twice — the shape invoked by resolveExecutorConfig for default +
|
|
132
|
-
// synthesize) adds up to ZERO resolver invocations when the cache is
|
|
133
|
-
// threaded. If a future refactor drops the `cached` argument from any
|
|
134
|
-
// consumer, the signals-line count will jump from 0 to 1-or-more and
|
|
135
|
-
// this test will fail — catching the very regression class MINOR-1 of
|
|
136
|
-
// the P9.3-m1 review flagged.
|
|
137
|
-
// ---------------------------------------------------------------------------
|
|
138
|
-
describe("runReviewInvokeCli full-dispatch consumer sequence — invariant", () => {
|
|
139
|
-
const originalEnv = { ...process.env };
|
|
140
|
-
let stderrSpy;
|
|
141
|
-
beforeEach(() => {
|
|
142
|
-
delete process.env.CLAUDECODE;
|
|
143
|
-
delete process.env.CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS;
|
|
144
|
-
stderrSpy = vi.spyOn(process.stderr, "write").mockImplementation(() => true);
|
|
145
|
-
});
|
|
146
|
-
afterEach(() => {
|
|
147
|
-
stderrSpy.mockRestore();
|
|
148
|
-
for (const k of Object.keys(process.env)) {
|
|
149
|
-
if (!(k in originalEnv))
|
|
150
|
-
delete process.env[k];
|
|
151
|
-
}
|
|
152
|
-
for (const [k, v] of Object.entries(originalEnv)) {
|
|
153
|
-
process.env[k] = v;
|
|
154
|
-
}
|
|
155
|
-
});
|
|
156
|
-
function signalsTraceCount() {
|
|
157
|
-
return stderrSpy.mock.calls
|
|
158
|
-
.map((c) => String(c[0]))
|
|
159
|
-
.filter((l) => l.startsWith("[topology] signals:")).length;
|
|
160
|
-
}
|
|
161
|
-
it("3 consumers with shared cachedTopology → resolver runs 0 times", () => {
|
|
162
|
-
// Simulate the runReviewInvokeCli full-dispatch sequence:
|
|
163
|
-
// 1. runReviewInvokeCli resolves once at the top (we fabricate the
|
|
164
|
-
// result here as `cachedTopology` — NOT included in the spy count).
|
|
165
|
-
// 2. tryResolveTopologyForHandoff(config, cachedTopology) — coordinator_start
|
|
166
|
-
// path would have called this but it returns earlier; included here
|
|
167
|
-
// for completeness of the 3-consumer contract.
|
|
168
|
-
// 3. tryTopologyDerivedExecutor ×2 (default + synthesize via
|
|
169
|
-
// resolveExecutorConfig).
|
|
170
|
-
const cachedTopology = CACHED_LITELLM_TOPOLOGY;
|
|
171
|
-
const config = { llm_base_url: "http://localhost:4000" };
|
|
172
|
-
tryResolveTopologyForHandoff(config, cachedTopology);
|
|
173
|
-
tryTopologyDerivedExecutor(config, FAKE_HOME, cachedTopology);
|
|
174
|
-
tryTopologyDerivedExecutor(config, FAKE_HOME, cachedTopology);
|
|
175
|
-
// ZERO resolver calls: cache bypassed all 3 consumers.
|
|
176
|
-
expect(signalsTraceCount()).toBe(0);
|
|
177
|
-
});
|
|
178
|
-
it("regression probe: 3 consumers with cached=undefined → resolver runs 3 times", () => {
|
|
179
|
-
// This is the PRE-fix behaviour. If someone accidentally reverts the
|
|
180
|
-
// caching (drops the `cached` argument from all 3 consumers), the
|
|
181
|
-
// count would be 3 — proving the test catches the exact regression.
|
|
182
|
-
process.env.CLAUDECODE = "1";
|
|
183
|
-
const config = { llm_base_url: "http://localhost:4000" };
|
|
184
|
-
tryResolveTopologyForHandoff(config);
|
|
185
|
-
tryTopologyDerivedExecutor(config, FAKE_HOME);
|
|
186
|
-
tryTopologyDerivedExecutor(config, FAKE_HOME);
|
|
187
|
-
expect(signalsTraceCount()).toBe(3);
|
|
188
|
-
});
|
|
189
|
-
it("3 consumers with cachedTopology=null → resolver runs 0 times, all return null", () => {
|
|
190
|
-
// `null` propagation: all 3 consumers see cached=null and short-circuit
|
|
191
|
-
// without invoking the resolver.
|
|
192
|
-
const config = { llm_base_url: "http://localhost:4000" };
|
|
193
|
-
const descriptor = tryResolveTopologyForHandoff(config, null);
|
|
194
|
-
const exec1 = tryTopologyDerivedExecutor(config, FAKE_HOME, null);
|
|
195
|
-
const exec2 = tryTopologyDerivedExecutor(config, FAKE_HOME, null);
|
|
196
|
-
expect(descriptor).toBeNull();
|
|
197
|
-
expect(exec1).toBeNull();
|
|
198
|
-
expect(exec2).toBeNull();
|
|
199
|
-
expect(signalsTraceCount()).toBe(0);
|
|
200
|
-
});
|
|
201
|
-
});
|
|
@@ -1,192 +0,0 @@
|
|
|
1
|
-
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
|
2
|
-
import { tryTopologyDerivedExecutor } from "./review-invoke.js";
|
|
3
|
-
// ---------------------------------------------------------------------------
|
|
4
|
-
// Topology-derived executor dispatch invariants (P9.3, 2026-04-21):
|
|
5
|
-
//
|
|
6
|
-
// (1) Dispatch is always attempted — the former opt-in gate
|
|
7
|
-
// (`execution_topology_priority` pre-P9.1, `config.review` presence
|
|
8
|
-
// in P9.2) is removed. Resolver's universal `main_native` degrade
|
|
9
|
-
// guarantees a viable topology whenever a host is reachable.
|
|
10
|
-
// (2) Resolved topology whose lens_spawn_mechanism has a standalone
|
|
11
|
-
// binary → returns the mapped ReviewUnitExecutorConfig (caller
|
|
12
|
-
// appends subagent/model args as usual).
|
|
13
|
-
// (3) Resolved topology whose mechanism has NO standalone binary
|
|
14
|
-
// (claude-agent-tool, claude-teamcreate-member, codex-nested's
|
|
15
|
-
// teamlead location) → returns null (fall through to coordinator
|
|
16
|
-
// or dedicated orchestrators).
|
|
17
|
-
// (4) No reachable host (resolver returns `no_host`) → returns null.
|
|
18
|
-
// (5) `[plan:executor]` STDERR line emitted on successful topology
|
|
19
|
-
// derivation, so operators can see topology → binary mapping.
|
|
20
|
-
// ---------------------------------------------------------------------------
|
|
21
|
-
const FAKE_HOME = "/tmp/fake-onto-home";
|
|
22
|
-
function withInjectedSignals(config, overrides = {}) {
|
|
23
|
-
// `tryTopologyDerivedExecutor` reads env implicitly via
|
|
24
|
-
// resolveExecutionTopology; most tests need CLAUDECODE=1 to satisfy
|
|
25
|
-
// the cc-main-* requirement. Tests manipulate process.env directly.
|
|
26
|
-
return config;
|
|
27
|
-
}
|
|
28
|
-
describe("tryTopologyDerivedExecutor — null paths (fall through)", () => {
|
|
29
|
-
const originalEnv = { ...process.env };
|
|
30
|
-
beforeEach(() => {
|
|
31
|
-
delete process.env.CLAUDECODE;
|
|
32
|
-
delete process.env.CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS;
|
|
33
|
-
});
|
|
34
|
-
afterEach(() => {
|
|
35
|
-
for (const k of Object.keys(process.env)) {
|
|
36
|
-
if (!(k in originalEnv))
|
|
37
|
-
delete process.env[k];
|
|
38
|
-
}
|
|
39
|
-
for (const [k, v] of Object.entries(originalEnv)) {
|
|
40
|
-
process.env[k] = v;
|
|
41
|
-
}
|
|
42
|
-
});
|
|
43
|
-
it("no config.review block + no host → null (resolver returns no_host)", () => {
|
|
44
|
-
// P9.3 (2026-04-21): dispatch attempts axis-first resolution for
|
|
45
|
-
// every review invocation. Without CLAUDECODE / codex signals the
|
|
46
|
-
// resolver's main_native degrade cannot map → no_host → null.
|
|
47
|
-
const result = tryTopologyDerivedExecutor({}, FAKE_HOME);
|
|
48
|
-
expect(result).toBeNull();
|
|
49
|
-
});
|
|
50
|
-
it("no config.review block + CC host → null (cc-main-agent-subagent has no standalone binary)", () => {
|
|
51
|
-
// P9.3 invariant: even without a review block the resolver maps
|
|
52
|
-
// main_native → cc-main-agent-subagent under CLAUDECODE=1. That
|
|
53
|
-
// topology's mechanism is claude-agent-tool which has no
|
|
54
|
-
// standalone binary, so dispatch falls through to coordinator.
|
|
55
|
-
process.env.CLAUDECODE = "1";
|
|
56
|
-
const result = tryTopologyDerivedExecutor({}, FAKE_HOME);
|
|
57
|
-
expect(result).toBeNull();
|
|
58
|
-
});
|
|
59
|
-
it("missing ontoHome → null (required to resolve executor path)", () => {
|
|
60
|
-
process.env.CLAUDECODE = "1";
|
|
61
|
-
const result = tryTopologyDerivedExecutor({ review: { subagent: { provider: "main-native" } } }, undefined);
|
|
62
|
-
expect(result).toBeNull();
|
|
63
|
-
});
|
|
64
|
-
it("review axis resolves to claude-agent-tool (cc-main-agent-subagent) → null (coordinator handoff is the seat)", () => {
|
|
65
|
-
process.env.CLAUDECODE = "1";
|
|
66
|
-
const result = tryTopologyDerivedExecutor({ review: { subagent: { provider: "main-native" } } }, FAKE_HOME);
|
|
67
|
-
expect(result).toBeNull();
|
|
68
|
-
});
|
|
69
|
-
it("review axis resolves but no host signals → null (no_host case)", () => {
|
|
70
|
-
// CLAUDECODE unset, no codex signals. Axis block derives to
|
|
71
|
-
// main_native shape but the mapping is unreachable — no_host.
|
|
72
|
-
const result = tryTopologyDerivedExecutor({ review: { subagent: { provider: "main-native" } } }, FAKE_HOME);
|
|
73
|
-
expect(result).toBeNull();
|
|
74
|
-
});
|
|
75
|
-
it("review axis resolves to codex-nested-subprocess → null (PR-H dispatch branch is the seat)", () => {
|
|
76
|
-
// Nested codex requires only codexAvailable; but the mapping module
|
|
77
|
-
// rejects it (its teamlead is codex-subprocess, not a per-lens binary).
|
|
78
|
-
// Without CLAUDECODE and with no real codex binary on the test
|
|
79
|
-
// machine's PATH the resolver will return no_host; that's fine —
|
|
80
|
-
// the test asserts null regardless, which is correct PR-F behaviour
|
|
81
|
-
// for nested topology anyway.
|
|
82
|
-
const result = tryTopologyDerivedExecutor({
|
|
83
|
-
review: {
|
|
84
|
-
teamlead: { model: { provider: "codex", model_id: "gpt-5.4" } },
|
|
85
|
-
subagent: { provider: "codex", model_id: "gpt-5.4" },
|
|
86
|
-
},
|
|
87
|
-
}, FAKE_HOME);
|
|
88
|
-
expect(result).toBeNull();
|
|
89
|
-
});
|
|
90
|
-
});
|
|
91
|
-
describe("tryTopologyDerivedExecutor — successful derivation", () => {
|
|
92
|
-
const originalEnv = { ...process.env };
|
|
93
|
-
let stderrSpy;
|
|
94
|
-
beforeEach(() => {
|
|
95
|
-
delete process.env.CLAUDECODE;
|
|
96
|
-
delete process.env.CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS;
|
|
97
|
-
stderrSpy = vi.spyOn(process.stderr, "write").mockImplementation(() => true);
|
|
98
|
-
});
|
|
99
|
-
afterEach(() => {
|
|
100
|
-
stderrSpy.mockRestore();
|
|
101
|
-
for (const k of Object.keys(process.env)) {
|
|
102
|
-
if (!(k in originalEnv))
|
|
103
|
-
delete process.env[k];
|
|
104
|
-
}
|
|
105
|
-
for (const [k, v] of Object.entries(originalEnv)) {
|
|
106
|
-
process.env[k] = v;
|
|
107
|
-
}
|
|
108
|
-
});
|
|
109
|
-
function topologyLogLines() {
|
|
110
|
-
return stderrSpy.mock.calls
|
|
111
|
-
.map((c) => String(c[0]))
|
|
112
|
-
.filter((l) => l.startsWith("[plan:executor]"));
|
|
113
|
-
}
|
|
114
|
-
it("cc-teams-litellm-sessions axis block → litellm executor binary", () => {
|
|
115
|
-
process.env.CLAUDECODE = "1";
|
|
116
|
-
// P9.2 (2026-04-21): topology is selected exclusively through the
|
|
117
|
-
// `config.review` axis block — legacy `execution_topology_priority`
|
|
118
|
-
// field was removed from OntoConfig.
|
|
119
|
-
const axisConfig = {
|
|
120
|
-
review: {
|
|
121
|
-
subagent: { provider: "litellm", model_id: "gpt-4o" },
|
|
122
|
-
},
|
|
123
|
-
llm_base_url: "http://localhost:4000",
|
|
124
|
-
};
|
|
125
|
-
// Without experimental flag, teams shape cannot activate → axis-first
|
|
126
|
-
// fails → degrade to main_native → cc-main-agent-subagent (no
|
|
127
|
-
// standalone binary) → null.
|
|
128
|
-
const result = tryTopologyDerivedExecutor(withInjectedSignals(axisConfig), FAKE_HOME);
|
|
129
|
-
expect(result).toBeNull();
|
|
130
|
-
process.env.CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS = "1";
|
|
131
|
-
const result2 = tryTopologyDerivedExecutor(withInjectedSignals(axisConfig), FAKE_HOME);
|
|
132
|
-
expect(result2).not.toBeNull();
|
|
133
|
-
expect(result2.bin).toBe("node");
|
|
134
|
-
expect(result2.args[0]).toContain("inline-http-review-unit-executor.js");
|
|
135
|
-
expect(result2.args[0]).toContain(FAKE_HOME);
|
|
136
|
-
});
|
|
137
|
-
it("successful derivation emits [plan:executor] STDERR", () => {
|
|
138
|
-
process.env.CLAUDECODE = "1";
|
|
139
|
-
process.env.CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS = "1";
|
|
140
|
-
tryTopologyDerivedExecutor({
|
|
141
|
-
review: {
|
|
142
|
-
subagent: { provider: "litellm", model_id: "gpt-4o" },
|
|
143
|
-
},
|
|
144
|
-
llm_base_url: "http://localhost:4000",
|
|
145
|
-
}, FAKE_HOME);
|
|
146
|
-
const lines = topologyLogLines();
|
|
147
|
-
expect(lines.length).toBe(1);
|
|
148
|
-
expect(lines[0]).toContain("topology=cc-teams-litellm-sessions");
|
|
149
|
-
expect(lines[0]).toContain("bin=node");
|
|
150
|
-
expect(lines[0]).toContain("inline-http-review-unit-executor.js");
|
|
151
|
-
});
|
|
152
|
-
it("no [plan:executor] line when topology falls through", () => {
|
|
153
|
-
// cc-main-agent-subagent has no standalone binary → fall through,
|
|
154
|
-
// so no [plan:executor] line should be emitted for this derivation.
|
|
155
|
-
// The resolver picks cc-main-agent-subagent via the axis block.
|
|
156
|
-
process.env.CLAUDECODE = "1";
|
|
157
|
-
tryTopologyDerivedExecutor({ review: { subagent: { provider: "main-native" } } }, FAKE_HOME);
|
|
158
|
-
expect(topologyLogLines()).toHaveLength(0);
|
|
159
|
-
});
|
|
160
|
-
});
|
|
161
|
-
describe("tryTopologyDerivedExecutor — axis-first decides (P9.2)", () => {
|
|
162
|
-
const originalEnv = { ...process.env };
|
|
163
|
-
beforeEach(() => {
|
|
164
|
-
delete process.env.CLAUDECODE;
|
|
165
|
-
delete process.env.CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS;
|
|
166
|
-
vi.spyOn(process.stderr, "write").mockImplementation(() => true);
|
|
167
|
-
});
|
|
168
|
-
afterEach(() => {
|
|
169
|
-
vi.restoreAllMocks();
|
|
170
|
-
for (const k of Object.keys(process.env)) {
|
|
171
|
-
if (!(k in originalEnv))
|
|
172
|
-
delete process.env[k];
|
|
173
|
-
}
|
|
174
|
-
for (const [k, v] of Object.entries(originalEnv)) {
|
|
175
|
-
process.env[k] = v;
|
|
176
|
-
}
|
|
177
|
-
});
|
|
178
|
-
it("review axis selects the binary-backed topology when declared", () => {
|
|
179
|
-
process.env.CLAUDECODE = "1";
|
|
180
|
-
process.env.CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS = "1";
|
|
181
|
-
// Axis block declares subagent=litellm → shape=main-teams_foreign →
|
|
182
|
-
// TopologyId=cc-teams-litellm-sessions (standalone binary).
|
|
183
|
-
const result = tryTopologyDerivedExecutor({
|
|
184
|
-
review: {
|
|
185
|
-
subagent: { provider: "litellm", model_id: "gpt-4o" },
|
|
186
|
-
},
|
|
187
|
-
llm_base_url: "http://localhost:4000",
|
|
188
|
-
}, FAKE_HOME);
|
|
189
|
-
expect(result).not.toBeNull();
|
|
190
|
-
expect(result.args[0]).toContain("inline-http-review-unit-executor.js");
|
|
191
|
-
});
|
|
192
|
-
});
|
|
@@ -1,168 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Session Root Guard — DD-8 (Step 11a).
|
|
3
|
-
*
|
|
4
|
-
* Design authority:
|
|
5
|
-
* - learn-phase3-design-v9.md DD-8 (.layout-version.yaml + runtime gate)
|
|
6
|
-
* - learn-phase3-design-v5.md DD-8 (UF-SYN-05/06 — marker rename + version gate)
|
|
7
|
-
* - learn-phase3-design-v4.md DD-8 (case taxonomy: new user / legacy / mixed)
|
|
8
|
-
*
|
|
9
|
-
* Responsibility:
|
|
10
|
-
* - Inspect `<projectRoot>/.onto/.layout-version.yaml` and decide whether
|
|
11
|
-
* the session layout is ready for Phase 3 commands (promote /
|
|
12
|
-
* reclassify-insights / migrate-session-roots).
|
|
13
|
-
* - Detect legacy session directories that match the pre-v3 pattern
|
|
14
|
-
* (`.onto/sessions/{id}/` directly, no `review/` subdir).
|
|
15
|
-
* - Surface 4 cases with deterministic actions:
|
|
16
|
-
* 1. New user (no marker, no legacy) → write marker, allow
|
|
17
|
-
* 2. Legacy + no marker → MigrationRequiredError
|
|
18
|
-
* 3. Marker present + legacy still exists → warn but allow (operator
|
|
19
|
-
* should re-run migration)
|
|
20
|
-
* 4. Marker present + no legacy → allow
|
|
21
|
-
* - Reject the marker when its layout_version doesn't match SUPPORTED.
|
|
22
|
-
*
|
|
23
|
-
* Modes:
|
|
24
|
-
* - "enforce" (default): write marker on first run, throw on legacy.
|
|
25
|
-
* - "inspect": pure read, no I/O writes, no throw. Used by diagnostics
|
|
26
|
-
* that should not trigger migration as a side effect.
|
|
27
|
-
*
|
|
28
|
-
* Why a separate module:
|
|
29
|
-
* - Phase 3 commands (promote, reclassify-insights) call this from src/cli.ts
|
|
30
|
-
* before doing anything else, so the gate is the first thing they hit.
|
|
31
|
-
* - The migrate-session-roots command also uses inspectMigrationStatus()
|
|
32
|
-
* to compute what would be migrated.
|
|
33
|
-
*/
|
|
34
|
-
import fs from "node:fs";
|
|
35
|
-
import path from "node:path";
|
|
36
|
-
import { REGISTRY } from "../learning/shared/artifact-registry.js";
|
|
37
|
-
// ---------------------------------------------------------------------------
|
|
38
|
-
// Constants
|
|
39
|
-
// ---------------------------------------------------------------------------
|
|
40
|
-
export const SUPPORTED_LAYOUT_VERSION = "v3";
|
|
41
|
-
export const LAYOUT_MARKER_FILENAME = ".layout-version.yaml";
|
|
42
|
-
const KNOWN_SESSION_SUBDIRS = ["review", "promote", "reclassify-insights"];
|
|
43
|
-
/** Legacy session id pattern: YYYYMMDD-{6+ hex}. */
|
|
44
|
-
const LEGACY_SESSION_PATTERN = /^\d{8}-[a-f0-9]{6,}$/;
|
|
45
|
-
// ---------------------------------------------------------------------------
|
|
46
|
-
// Path helpers
|
|
47
|
-
// ---------------------------------------------------------------------------
|
|
48
|
-
export function getLayoutMarkerPath(projectRoot) {
|
|
49
|
-
return path.join(projectRoot, ".onto", LAYOUT_MARKER_FILENAME);
|
|
50
|
-
}
|
|
51
|
-
export function getSessionsDir(projectRoot) {
|
|
52
|
-
return path.join(projectRoot, ".onto", "sessions");
|
|
53
|
-
}
|
|
54
|
-
/**
|
|
55
|
-
* Pure read of layout marker + legacy directory enumeration.
|
|
56
|
-
*
|
|
57
|
-
* Performs no I/O writes and never throws on missing files. The caller
|
|
58
|
-
* decides what to do with the resulting status.
|
|
59
|
-
*/
|
|
60
|
-
export function inspectMigrationStatus(projectRoot) {
|
|
61
|
-
const markerPath = getLayoutMarkerPath(projectRoot);
|
|
62
|
-
const status = {
|
|
63
|
-
marker_present: false,
|
|
64
|
-
marker_path: markerPath,
|
|
65
|
-
marker_compatible: false,
|
|
66
|
-
marker_layout_version: null,
|
|
67
|
-
legacy_session_count: 0,
|
|
68
|
-
legacy_session_ids: [],
|
|
69
|
-
};
|
|
70
|
-
if (fs.existsSync(markerPath)) {
|
|
71
|
-
status.marker_present = true;
|
|
72
|
-
try {
|
|
73
|
-
const marker = REGISTRY.loadFromFile("layout_version", markerPath);
|
|
74
|
-
status.marker_layout_version = marker.layout_version;
|
|
75
|
-
status.marker_compatible = marker.layout_version === SUPPORTED_LAYOUT_VERSION;
|
|
76
|
-
}
|
|
77
|
-
catch {
|
|
78
|
-
// Marker file exists but is malformed. Treat as incompatible.
|
|
79
|
-
status.marker_compatible = false;
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
const sessionsDir = getSessionsDir(projectRoot);
|
|
83
|
-
if (fs.existsSync(sessionsDir)) {
|
|
84
|
-
const entries = fs.readdirSync(sessionsDir, { withFileTypes: true });
|
|
85
|
-
const legacy = entries.filter((e) => e.isDirectory() &&
|
|
86
|
-
!KNOWN_SESSION_SUBDIRS.includes(e.name) &&
|
|
87
|
-
LEGACY_SESSION_PATTERN.test(e.name));
|
|
88
|
-
status.legacy_session_count = legacy.length;
|
|
89
|
-
status.legacy_session_ids = legacy.map((e) => e.name).sort();
|
|
90
|
-
}
|
|
91
|
-
return status;
|
|
92
|
-
}
|
|
93
|
-
// ---------------------------------------------------------------------------
|
|
94
|
-
// Marker writer
|
|
95
|
-
// ---------------------------------------------------------------------------
|
|
96
|
-
export function writeLayoutMarker(projectRoot) {
|
|
97
|
-
const markerPath = getLayoutMarkerPath(projectRoot);
|
|
98
|
-
fs.mkdirSync(path.dirname(markerPath), { recursive: true });
|
|
99
|
-
const marker = {
|
|
100
|
-
schema_version: "1",
|
|
101
|
-
layout_version: SUPPORTED_LAYOUT_VERSION,
|
|
102
|
-
written_at: new Date().toISOString(),
|
|
103
|
-
};
|
|
104
|
-
REGISTRY.saveToFile("layout_version", markerPath, marker);
|
|
105
|
-
}
|
|
106
|
-
// ---------------------------------------------------------------------------
|
|
107
|
-
// Errors
|
|
108
|
-
// ---------------------------------------------------------------------------
|
|
109
|
-
export class MigrationRequiredError extends Error {
|
|
110
|
-
status;
|
|
111
|
-
constructor(message, status) {
|
|
112
|
-
super(message);
|
|
113
|
-
this.status = status;
|
|
114
|
-
this.name = "MigrationRequiredError";
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
export class IncompatibleLayoutError extends Error {
|
|
118
|
-
status;
|
|
119
|
-
constructor(message, status) {
|
|
120
|
-
super(message);
|
|
121
|
-
this.status = status;
|
|
122
|
-
this.name = "IncompatibleLayoutError";
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
/**
|
|
126
|
-
* Phase 3 command entry guard. Call from src/cli.ts BEFORE any promote /
|
|
127
|
-
* reclassify-insights / promote --apply / migrate-session-roots subcommand.
|
|
128
|
-
*
|
|
129
|
-
* Returns the inspected status so callers can log or branch on it.
|
|
130
|
-
*
|
|
131
|
-
* Throws:
|
|
132
|
-
* - `MigrationRequiredError` when legacy sessions exist without a marker
|
|
133
|
-
* (case 2). The operator must run `onto migrate-session-roots`.
|
|
134
|
-
* - `IncompatibleLayoutError` when the marker exists but its
|
|
135
|
-
* layout_version is not the supported one (forward-compat guard).
|
|
136
|
-
*/
|
|
137
|
-
export function ensureSessionRootsMigrated(projectRoot, mode = "enforce") {
|
|
138
|
-
const status = inspectMigrationStatus(projectRoot);
|
|
139
|
-
if (mode === "inspect")
|
|
140
|
-
return status;
|
|
141
|
-
// Case 1: new user — write marker and allow.
|
|
142
|
-
if (!status.marker_present && status.legacy_session_count === 0) {
|
|
143
|
-
writeLayoutMarker(projectRoot);
|
|
144
|
-
return inspectMigrationStatus(projectRoot);
|
|
145
|
-
}
|
|
146
|
-
// Case 2: legacy + no marker — hard fail.
|
|
147
|
-
if (!status.marker_present && status.legacy_session_count > 0) {
|
|
148
|
-
const sample = status.legacy_session_ids.slice(0, 5).join(", ");
|
|
149
|
-
const more = status.legacy_session_count > 5
|
|
150
|
-
? ` ... and ${status.legacy_session_count - 5} more`
|
|
151
|
-
: "";
|
|
152
|
-
throw new MigrationRequiredError(`Legacy session roots detected (${status.legacy_session_count} session(s)). ` +
|
|
153
|
-
`Run 'onto migrate-session-roots' before continuing.\n` +
|
|
154
|
-
`Affected: ${sample}${more}`, status);
|
|
155
|
-
}
|
|
156
|
-
// Case 3: marker present + legacy still exists — warn (re-run migration).
|
|
157
|
-
if (status.marker_present && status.legacy_session_count > 0) {
|
|
158
|
-
process.stderr.write(`[onto] warning: ${status.legacy_session_count} legacy session(s) found ` +
|
|
159
|
-
`despite layout marker. Re-run 'onto migrate-session-roots' to clean up.\n`);
|
|
160
|
-
}
|
|
161
|
-
// Case 4: marker present + no legacy → check version compat.
|
|
162
|
-
if (status.marker_present && !status.marker_compatible) {
|
|
163
|
-
throw new IncompatibleLayoutError(`Layout marker version "${status.marker_layout_version}" is not ` +
|
|
164
|
-
`supported (expected "${SUPPORTED_LAYOUT_VERSION}"). ` +
|
|
165
|
-
`Upgrade Phase 3 tooling or restore a compatible marker.`, status);
|
|
166
|
-
}
|
|
167
|
-
return status;
|
|
168
|
-
}
|