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,236 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect } from "vitest";
|
|
2
|
-
import { validateReviewConfig } from "./review-config-validator.js";
|
|
3
|
-
// ---------------------------------------------------------------------------
|
|
4
|
-
// validateReviewConfig — Review UX Redesign P1 (2026-04-20)
|
|
5
|
-
// ---------------------------------------------------------------------------
|
|
6
|
-
//
|
|
7
|
-
// These tests lock in three kinds of invariants:
|
|
8
|
-
//
|
|
9
|
-
// (1) Happy paths — every config variation shown in design doc §3.2
|
|
10
|
-
// parses to the expected OntoReviewConfig with no errors.
|
|
11
|
-
//
|
|
12
|
-
// (2) Discriminated-union enforcement — the YAML cast in readConfigAt
|
|
13
|
-
// can silently allow `main-native + model_id`, so the validator
|
|
14
|
-
// must reject it explicitly. Same for foreign providers missing
|
|
15
|
-
// model_id.
|
|
16
|
-
//
|
|
17
|
-
// (3) Cross-field constraints — lens_deliberation=sendmessage-a2a
|
|
18
|
-
// with an external teamlead is statically invalid and must fail
|
|
19
|
-
// at validation time (not runtime).
|
|
20
|
-
// ---------------------------------------------------------------------------
|
|
21
|
-
describe("validateReviewConfig — happy paths", () => {
|
|
22
|
-
it("accepts undefined / null as empty config (universal fallback)", () => {
|
|
23
|
-
const a = validateReviewConfig(undefined);
|
|
24
|
-
expect(a.ok).toBe(true);
|
|
25
|
-
if (a.ok)
|
|
26
|
-
expect(a.config).toEqual({});
|
|
27
|
-
const b = validateReviewConfig(null);
|
|
28
|
-
expect(b.ok).toBe(true);
|
|
29
|
-
if (b.ok)
|
|
30
|
-
expect(b.config).toEqual({});
|
|
31
|
-
});
|
|
32
|
-
it("accepts empty object as empty config", () => {
|
|
33
|
-
const r = validateReviewConfig({});
|
|
34
|
-
expect(r.ok).toBe(true);
|
|
35
|
-
if (r.ok)
|
|
36
|
-
expect(r.config).toEqual({});
|
|
37
|
-
});
|
|
38
|
-
it("accepts universal fallback (teamlead=main, subagent=main-native)", () => {
|
|
39
|
-
const r = validateReviewConfig({
|
|
40
|
-
teamlead: { model: "main" },
|
|
41
|
-
subagent: { provider: "main-native" },
|
|
42
|
-
});
|
|
43
|
-
expect(r.ok).toBe(true);
|
|
44
|
-
if (r.ok) {
|
|
45
|
-
expect(r.config.teamlead).toEqual({ model: "main" });
|
|
46
|
-
expect(r.config.subagent).toEqual({ provider: "main-native" });
|
|
47
|
-
}
|
|
48
|
-
});
|
|
49
|
-
it("accepts Claude Code + codex subagent + effort + concurrency", () => {
|
|
50
|
-
const r = validateReviewConfig({
|
|
51
|
-
teamlead: { model: "main" },
|
|
52
|
-
subagent: { provider: "codex", model_id: "gpt-5.4", effort: "high" },
|
|
53
|
-
max_concurrent_lenses: 6,
|
|
54
|
-
lens_deliberation: "synthesizer-only",
|
|
55
|
-
});
|
|
56
|
-
expect(r.ok).toBe(true);
|
|
57
|
-
if (r.ok) {
|
|
58
|
-
expect(r.config.subagent).toEqual({
|
|
59
|
-
provider: "codex",
|
|
60
|
-
model_id: "gpt-5.4",
|
|
61
|
-
effort: "high",
|
|
62
|
-
});
|
|
63
|
-
expect(r.config.max_concurrent_lenses).toBe(6);
|
|
64
|
-
expect(r.config.lens_deliberation).toBe("synthesizer-only");
|
|
65
|
-
}
|
|
66
|
-
});
|
|
67
|
-
it("accepts Claude Code + a2a deliberation (teamlead=main)", () => {
|
|
68
|
-
const r = validateReviewConfig({
|
|
69
|
-
teamlead: { model: "main" },
|
|
70
|
-
subagent: { provider: "main-native" },
|
|
71
|
-
lens_deliberation: "sendmessage-a2a",
|
|
72
|
-
});
|
|
73
|
-
expect(r.ok).toBe(true);
|
|
74
|
-
});
|
|
75
|
-
it("accepts codex-nested (teamlead=codex external, subagent=codex)", () => {
|
|
76
|
-
const r = validateReviewConfig({
|
|
77
|
-
teamlead: {
|
|
78
|
-
model: { provider: "codex", model_id: "gpt-5.4", effort: "high" },
|
|
79
|
-
},
|
|
80
|
-
subagent: { provider: "codex", model_id: "gpt-5.4" },
|
|
81
|
-
});
|
|
82
|
-
expect(r.ok).toBe(true);
|
|
83
|
-
if (r.ok) {
|
|
84
|
-
expect(r.config.teamlead?.model).toEqual({
|
|
85
|
-
provider: "codex",
|
|
86
|
-
model_id: "gpt-5.4",
|
|
87
|
-
effort: "high",
|
|
88
|
-
});
|
|
89
|
-
}
|
|
90
|
-
});
|
|
91
|
-
it("accepts litellm subagent without effort", () => {
|
|
92
|
-
const r = validateReviewConfig({
|
|
93
|
-
subagent: { provider: "litellm", model_id: "llama-8b" },
|
|
94
|
-
max_concurrent_lenses: 2,
|
|
95
|
-
});
|
|
96
|
-
expect(r.ok).toBe(true);
|
|
97
|
-
if (r.ok) {
|
|
98
|
-
expect(r.config.subagent).toEqual({
|
|
99
|
-
provider: "litellm",
|
|
100
|
-
model_id: "llama-8b",
|
|
101
|
-
});
|
|
102
|
-
}
|
|
103
|
-
});
|
|
104
|
-
});
|
|
105
|
-
describe("validateReviewConfig — structural rejections", () => {
|
|
106
|
-
it("rejects non-object review block", () => {
|
|
107
|
-
const r = validateReviewConfig("string-config");
|
|
108
|
-
expect(r.ok).toBe(false);
|
|
109
|
-
if (!r.ok) {
|
|
110
|
-
expect(r.errors.some((e) => e.path === "review")).toBe(true);
|
|
111
|
-
}
|
|
112
|
-
});
|
|
113
|
-
it("rejects array as review block", () => {
|
|
114
|
-
const r = validateReviewConfig([1, 2, 3]);
|
|
115
|
-
expect(r.ok).toBe(false);
|
|
116
|
-
});
|
|
117
|
-
it("rejects unknown top-level keys", () => {
|
|
118
|
-
const r = validateReviewConfig({ unknown_field: 1 });
|
|
119
|
-
expect(r.ok).toBe(false);
|
|
120
|
-
if (!r.ok) {
|
|
121
|
-
expect(r.errors.some((e) => e.path === "review.unknown_field")).toBe(true);
|
|
122
|
-
}
|
|
123
|
-
});
|
|
124
|
-
it("rejects teamlead without model field", () => {
|
|
125
|
-
const r = validateReviewConfig({ teamlead: {} });
|
|
126
|
-
expect(r.ok).toBe(false);
|
|
127
|
-
if (!r.ok) {
|
|
128
|
-
expect(r.errors.some((e) => e.path === "review.teamlead.model")).toBe(true);
|
|
129
|
-
}
|
|
130
|
-
});
|
|
131
|
-
});
|
|
132
|
-
describe("validateReviewConfig — discriminated-union enforcement", () => {
|
|
133
|
-
it("rejects subagent.provider=main-native with model_id", () => {
|
|
134
|
-
const r = validateReviewConfig({
|
|
135
|
-
subagent: { provider: "main-native", model_id: "anything" },
|
|
136
|
-
});
|
|
137
|
-
expect(r.ok).toBe(false);
|
|
138
|
-
if (!r.ok) {
|
|
139
|
-
expect(r.errors.some((e) => e.path === "review.subagent.model_id")).toBe(true);
|
|
140
|
-
}
|
|
141
|
-
});
|
|
142
|
-
it("rejects subagent.provider=main-native with effort", () => {
|
|
143
|
-
const r = validateReviewConfig({
|
|
144
|
-
subagent: { provider: "main-native", effort: "high" },
|
|
145
|
-
});
|
|
146
|
-
expect(r.ok).toBe(false);
|
|
147
|
-
if (!r.ok) {
|
|
148
|
-
expect(r.errors.some((e) => e.path === "review.subagent.effort")).toBe(true);
|
|
149
|
-
}
|
|
150
|
-
});
|
|
151
|
-
it("rejects foreign subagent without model_id", () => {
|
|
152
|
-
const r = validateReviewConfig({
|
|
153
|
-
subagent: { provider: "codex" },
|
|
154
|
-
});
|
|
155
|
-
expect(r.ok).toBe(false);
|
|
156
|
-
if (!r.ok) {
|
|
157
|
-
expect(r.errors.some((e) => e.path === "review.subagent.model_id")).toBe(true);
|
|
158
|
-
}
|
|
159
|
-
});
|
|
160
|
-
it("rejects unknown subagent provider", () => {
|
|
161
|
-
const r = validateReviewConfig({
|
|
162
|
-
subagent: { provider: "unknown-ai" },
|
|
163
|
-
});
|
|
164
|
-
expect(r.ok).toBe(false);
|
|
165
|
-
if (!r.ok) {
|
|
166
|
-
expect(r.errors.some((e) => e.path === "review.subagent.provider")).toBe(true);
|
|
167
|
-
}
|
|
168
|
-
});
|
|
169
|
-
it("rejects teamlead.model=main-native (only subagent can be main-native)", () => {
|
|
170
|
-
// ExplicitModelSpec type restricts provider to foreign providers only.
|
|
171
|
-
// "main-native" under teamlead.model (as object.provider) must be rejected.
|
|
172
|
-
const r = validateReviewConfig({
|
|
173
|
-
teamlead: {
|
|
174
|
-
model: { provider: "main-native", model_id: "x" },
|
|
175
|
-
},
|
|
176
|
-
});
|
|
177
|
-
expect(r.ok).toBe(false);
|
|
178
|
-
if (!r.ok) {
|
|
179
|
-
expect(r.errors.some((e) => e.path === "review.teamlead.model.provider")).toBe(true);
|
|
180
|
-
}
|
|
181
|
-
});
|
|
182
|
-
it("rejects explicit teamlead without model_id", () => {
|
|
183
|
-
const r = validateReviewConfig({
|
|
184
|
-
teamlead: { model: { provider: "codex" } },
|
|
185
|
-
});
|
|
186
|
-
expect(r.ok).toBe(false);
|
|
187
|
-
if (!r.ok) {
|
|
188
|
-
expect(r.errors.some((e) => e.path === "review.teamlead.model.model_id")).toBe(true);
|
|
189
|
-
}
|
|
190
|
-
});
|
|
191
|
-
});
|
|
192
|
-
describe("validateReviewConfig — scalar axis constraints", () => {
|
|
193
|
-
it("rejects non-integer concurrency", () => {
|
|
194
|
-
const r = validateReviewConfig({ max_concurrent_lenses: 2.5 });
|
|
195
|
-
expect(r.ok).toBe(false);
|
|
196
|
-
});
|
|
197
|
-
it("rejects zero / negative concurrency", () => {
|
|
198
|
-
expect(validateReviewConfig({ max_concurrent_lenses: 0 }).ok).toBe(false);
|
|
199
|
-
expect(validateReviewConfig({ max_concurrent_lenses: -1 }).ok).toBe(false);
|
|
200
|
-
});
|
|
201
|
-
it("rejects non-numeric concurrency (e.g. string)", () => {
|
|
202
|
-
const r = validateReviewConfig({ max_concurrent_lenses: "6" });
|
|
203
|
-
expect(r.ok).toBe(false);
|
|
204
|
-
});
|
|
205
|
-
it("rejects unknown deliberation value", () => {
|
|
206
|
-
const r = validateReviewConfig({ lens_deliberation: "whatever" });
|
|
207
|
-
expect(r.ok).toBe(false);
|
|
208
|
-
if (!r.ok) {
|
|
209
|
-
expect(r.errors.some((e) => e.path === "review.lens_deliberation")).toBe(true);
|
|
210
|
-
}
|
|
211
|
-
});
|
|
212
|
-
});
|
|
213
|
-
describe("validateReviewConfig — cross-field constraints", () => {
|
|
214
|
-
it("rejects sendmessage-a2a with external teamlead", () => {
|
|
215
|
-
const r = validateReviewConfig({
|
|
216
|
-
teamlead: {
|
|
217
|
-
model: { provider: "codex", model_id: "gpt-5.4" },
|
|
218
|
-
},
|
|
219
|
-
subagent: { provider: "main-native" },
|
|
220
|
-
lens_deliberation: "sendmessage-a2a",
|
|
221
|
-
});
|
|
222
|
-
expect(r.ok).toBe(false);
|
|
223
|
-
if (!r.ok) {
|
|
224
|
-
expect(r.errors.some((e) => e.path === "review.lens_deliberation")).toBe(true);
|
|
225
|
-
}
|
|
226
|
-
});
|
|
227
|
-
it("accepts sendmessage-a2a with implicit teamlead (model=main) — absent teamlead block", () => {
|
|
228
|
-
// teamlead 블록 미기재 시 runtime 기본값 = main, 따라서 cross-field 제약 미발동.
|
|
229
|
-
// D=true 검증은 runtime 책임 (P1 syntactic 경계 밖).
|
|
230
|
-
const r = validateReviewConfig({
|
|
231
|
-
subagent: { provider: "main-native" },
|
|
232
|
-
lens_deliberation: "sendmessage-a2a",
|
|
233
|
-
});
|
|
234
|
-
expect(r.ok).toBe(true);
|
|
235
|
-
});
|
|
236
|
-
});
|
|
@@ -1,311 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect } from "vitest";
|
|
2
|
-
import { PR_A_SUPPORTED_TOPOLOGIES, TOPOLOGY_CATALOG, resolveExecutionTopology, } from "./execution-topology-resolver.js";
|
|
3
|
-
import { PR_B_SUPPORTED_TOPOLOGIES } from "../cli/topology-executor-mapping.js";
|
|
4
|
-
import { shapeToTopologyId } from "./shape-to-topology-id.js";
|
|
5
|
-
import { deriveTopologyShape, } from "./topology-shape-derivation.js";
|
|
6
|
-
// ---------------------------------------------------------------------------
|
|
7
|
-
// P8 — 6 Shape × 7 Pipeline Step Smoke Audit
|
|
8
|
-
// ---------------------------------------------------------------------------
|
|
9
|
-
//
|
|
10
|
-
// Purpose: **design-integrity verification** across the 6 canonical
|
|
11
|
-
// TopologyShapes introduced by P1–P5. The audit answers three questions:
|
|
12
|
-
//
|
|
13
|
-
// (1) Can each shape be derived from a valid OntoReviewConfig + signals?
|
|
14
|
-
// (2) Does each shape map to a canonical TopologyId in the existing 10-
|
|
15
|
-
// value catalog (not null, not generic-*)?
|
|
16
|
-
// (3) For each shape, what fraction of the 7-step review pipeline is
|
|
17
|
-
// currently wired for spawn-time execution vs blocked on a future
|
|
18
|
-
// PR (PR-C nested-codex, PR-D agent-teams deliberation)?
|
|
19
|
-
//
|
|
20
|
-
// The test is **hermetic** — no real LLM calls, no spawn. Each table row
|
|
21
|
-
// exercises the dispatch path (resolver + mapping + executor support set)
|
|
22
|
-
// and records the expected state, so regressions surface in CI instead of
|
|
23
|
-
// during a real review invocation.
|
|
24
|
-
//
|
|
25
|
-
// Pipeline steps referenced:
|
|
26
|
-
// 1. interpret — InvocationInterpretation (topology-agnostic)
|
|
27
|
-
// 2. bind — target binding + session creation (topology-agnostic)
|
|
28
|
-
// 3. start-session — session artifact seed (topology-agnostic)
|
|
29
|
-
// 4. materialize — prompt packets (topology-agnostic per sketch v3 §2)
|
|
30
|
-
// 5. dispatch lenses — **topology-specific**, the sole shape-sensitive step
|
|
31
|
-
// 6. synthesize — single-lens context, topology-agnostic
|
|
32
|
-
// 7. complete — session close, topology-agnostic
|
|
33
|
-
//
|
|
34
|
-
// Only step 5 is shape-sensitive. Steps 1-4/6-7 consume the resolved
|
|
35
|
-
// ExecutionTopology but their behaviour is the same for any valid topology.
|
|
36
|
-
// The audit therefore focuses coverage on step 5 while asserting catalog
|
|
37
|
-
// integrity for steps 1-4/6-7.
|
|
38
|
-
// ---------------------------------------------------------------------------
|
|
39
|
-
const CLAUDE_NO_TEAMS = {
|
|
40
|
-
claudeHost: true,
|
|
41
|
-
codexSessionActive: false,
|
|
42
|
-
experimentalAgentTeams: false,
|
|
43
|
-
};
|
|
44
|
-
const CLAUDE_TEAMS = {
|
|
45
|
-
claudeHost: true,
|
|
46
|
-
codexSessionActive: false,
|
|
47
|
-
experimentalAgentTeams: true,
|
|
48
|
-
};
|
|
49
|
-
const CODEX_HOST = {
|
|
50
|
-
claudeHost: false,
|
|
51
|
-
codexSessionActive: true,
|
|
52
|
-
experimentalAgentTeams: false,
|
|
53
|
-
};
|
|
54
|
-
const PLAIN_TERMINAL = {
|
|
55
|
-
claudeHost: false,
|
|
56
|
-
codexSessionActive: false,
|
|
57
|
-
experimentalAgentTeams: false,
|
|
58
|
-
};
|
|
59
|
-
// ---------------------------------------------------------------------------
|
|
60
|
-
// Audit matrix — 6 rows, one per TopologyShape
|
|
61
|
-
// ---------------------------------------------------------------------------
|
|
62
|
-
const AUDIT_MATRIX = [
|
|
63
|
-
{
|
|
64
|
-
shape: "main_native",
|
|
65
|
-
axes: {
|
|
66
|
-
teamlead: { model: "main" },
|
|
67
|
-
subagent: { provider: "main-native" },
|
|
68
|
-
},
|
|
69
|
-
signals: CLAUDE_NO_TEAMS,
|
|
70
|
-
expected_topology_id: "cc-main-agent-subagent",
|
|
71
|
-
expected_spawn_supported: true,
|
|
72
|
-
},
|
|
73
|
-
{
|
|
74
|
-
shape: "main_foreign",
|
|
75
|
-
axes: {
|
|
76
|
-
subagent: { provider: "codex", model_id: "gpt-5.4", effort: "high" },
|
|
77
|
-
},
|
|
78
|
-
signals: CLAUDE_NO_TEAMS,
|
|
79
|
-
expected_topology_id: "cc-main-codex-subprocess",
|
|
80
|
-
expected_spawn_supported: true,
|
|
81
|
-
},
|
|
82
|
-
{
|
|
83
|
-
shape: "main-teams_native",
|
|
84
|
-
axes: {
|
|
85
|
-
subagent: { provider: "main-native" },
|
|
86
|
-
},
|
|
87
|
-
signals: CLAUDE_TEAMS,
|
|
88
|
-
expected_topology_id: "cc-teams-agent-subagent",
|
|
89
|
-
expected_spawn_supported: true,
|
|
90
|
-
},
|
|
91
|
-
{
|
|
92
|
-
shape: "main-teams_foreign",
|
|
93
|
-
axes: {
|
|
94
|
-
subagent: { provider: "codex", model_id: "gpt-5.4", effort: "high" },
|
|
95
|
-
},
|
|
96
|
-
signals: CLAUDE_TEAMS,
|
|
97
|
-
expected_topology_id: "cc-teams-codex-subprocess",
|
|
98
|
-
expected_spawn_supported: true,
|
|
99
|
-
},
|
|
100
|
-
{
|
|
101
|
-
shape: "main-teams_a2a",
|
|
102
|
-
axes: {
|
|
103
|
-
subagent: { provider: "main-native" },
|
|
104
|
-
lens_deliberation: "sendmessage-a2a",
|
|
105
|
-
},
|
|
106
|
-
signals: CLAUDE_TEAMS,
|
|
107
|
-
expected_topology_id: "cc-teams-lens-agent-deliberation",
|
|
108
|
-
expected_spawn_supported: false,
|
|
109
|
-
blocked_on: "PR-D (agent-teams A2A)",
|
|
110
|
-
// Double opt-in gate — cc-teams-lens-agent-deliberation additionally
|
|
111
|
-
// requires this config flag on top of CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1
|
|
112
|
-
// because keeping lens agents alive for A2A materially changes the
|
|
113
|
-
// memory/latency profile (sketch v3 §3).
|
|
114
|
-
config_extras: { lens_agent_teams_mode: true },
|
|
115
|
-
},
|
|
116
|
-
{
|
|
117
|
-
shape: "ext-teamlead_native",
|
|
118
|
-
axes: {
|
|
119
|
-
teamlead: { model: { provider: "codex", model_id: "gpt-5.4" } },
|
|
120
|
-
subagent: { provider: "codex", model_id: "gpt-5.4" },
|
|
121
|
-
},
|
|
122
|
-
signals: PLAIN_TERMINAL,
|
|
123
|
-
expected_topology_id: "codex-nested-subprocess",
|
|
124
|
-
expected_spawn_supported: false,
|
|
125
|
-
blocked_on: "PR-C (ext-codex teamlead)",
|
|
126
|
-
},
|
|
127
|
-
];
|
|
128
|
-
// ---------------------------------------------------------------------------
|
|
129
|
-
// Stage 1 — derivation correctness
|
|
130
|
-
// ---------------------------------------------------------------------------
|
|
131
|
-
describe("P8 audit — stage 1: shape derivation reaches every canonical shape", () => {
|
|
132
|
-
for (const row of AUDIT_MATRIX) {
|
|
133
|
-
it(`${row.shape} derives from axes + signals`, () => {
|
|
134
|
-
const r = deriveTopologyShape(row.axes, row.signals);
|
|
135
|
-
expect(r.ok).toBe(true);
|
|
136
|
-
if (r.ok) {
|
|
137
|
-
expect(r.derived.shape).toBe(row.shape);
|
|
138
|
-
}
|
|
139
|
-
});
|
|
140
|
-
}
|
|
141
|
-
it("every shape in the audit is unique (no drift between runtime and audit matrix)", () => {
|
|
142
|
-
const shapes = new Set(AUDIT_MATRIX.map((r) => r.shape));
|
|
143
|
-
expect(shapes.size).toBe(AUDIT_MATRIX.length);
|
|
144
|
-
expect(shapes.size).toBe(6);
|
|
145
|
-
});
|
|
146
|
-
});
|
|
147
|
-
// ---------------------------------------------------------------------------
|
|
148
|
-
// Stage 2 — shape → TopologyId mapping
|
|
149
|
-
// ---------------------------------------------------------------------------
|
|
150
|
-
describe("P8 audit — stage 2: every shape maps to a canonical TopologyId", () => {
|
|
151
|
-
for (const row of AUDIT_MATRIX) {
|
|
152
|
-
it(`${row.shape} → ${row.expected_topology_id}`, () => {
|
|
153
|
-
const r = deriveTopologyShape(row.axes, row.signals);
|
|
154
|
-
expect(r.ok).toBe(true);
|
|
155
|
-
if (!r.ok)
|
|
156
|
-
return;
|
|
157
|
-
const mapping = shapeToTopologyId({
|
|
158
|
-
shape: r.derived.shape,
|
|
159
|
-
subagent_provider: r.derived.subagent_provider,
|
|
160
|
-
signals: {
|
|
161
|
-
claudeHost: row.signals.claudeHost,
|
|
162
|
-
codexSessionActive: row.signals.codexSessionActive,
|
|
163
|
-
},
|
|
164
|
-
});
|
|
165
|
-
expect(mapping.ok).toBe(true);
|
|
166
|
-
if (mapping.ok) {
|
|
167
|
-
expect(mapping.topology_id).toBe(row.expected_topology_id);
|
|
168
|
-
// Mapped id must exist in the catalog (no drift from TopologyId type).
|
|
169
|
-
expect(TOPOLOGY_CATALOG[mapping.topology_id]).toBeDefined();
|
|
170
|
-
}
|
|
171
|
-
});
|
|
172
|
-
}
|
|
173
|
-
});
|
|
174
|
-
// ---------------------------------------------------------------------------
|
|
175
|
-
// Stage 3 — resolver end-to-end (axis-first branch)
|
|
176
|
-
// ---------------------------------------------------------------------------
|
|
177
|
-
describe("P8 audit — stage 3: resolver end-to-end selects expected topology", () => {
|
|
178
|
-
for (const row of AUDIT_MATRIX) {
|
|
179
|
-
it(`${row.shape}: resolver picks ${row.expected_topology_id} via axis-first`, () => {
|
|
180
|
-
const res = resolveExecutionTopology({
|
|
181
|
-
ontoConfig: { review: row.axes, ...(row.config_extras ?? {}) },
|
|
182
|
-
claudeHost: row.signals.claudeHost,
|
|
183
|
-
codexSessionActive: row.signals.codexSessionActive,
|
|
184
|
-
experimentalAgentTeams: row.signals.experimentalAgentTeams,
|
|
185
|
-
codexAvailable: true, // P8 audit assumes codex is present for codex-flavored shapes
|
|
186
|
-
liteLlmEndpointAvailable: false,
|
|
187
|
-
});
|
|
188
|
-
if (res.type !== "resolved") {
|
|
189
|
-
throw new Error(`expected resolved for shape=${row.shape}, got no_host: ${res.reason.slice(0, 120)}`);
|
|
190
|
-
}
|
|
191
|
-
expect(res.topology.id).toBe(row.expected_topology_id);
|
|
192
|
-
expect(res.topology.plan_trace.some((l) => l.includes("topology source=review-axes"))).toBe(true);
|
|
193
|
-
});
|
|
194
|
-
}
|
|
195
|
-
});
|
|
196
|
-
// ---------------------------------------------------------------------------
|
|
197
|
-
// Stage 4 — spawn-readiness (PR_B_SUPPORTED_TOPOLOGIES)
|
|
198
|
-
// ---------------------------------------------------------------------------
|
|
199
|
-
describe("P8 audit — stage 4: spawn-readiness per shape", () => {
|
|
200
|
-
for (const row of AUDIT_MATRIX) {
|
|
201
|
-
it(`${row.shape}: spawn-supported=${row.expected_spawn_supported}${row.blocked_on ? ` (blocked_on=${row.blocked_on})` : ""}`, () => {
|
|
202
|
-
const supported = PR_B_SUPPORTED_TOPOLOGIES.has(row.expected_topology_id);
|
|
203
|
-
expect(supported).toBe(row.expected_spawn_supported);
|
|
204
|
-
if (!supported) {
|
|
205
|
-
expect(row.blocked_on).toBeDefined();
|
|
206
|
-
}
|
|
207
|
-
});
|
|
208
|
-
}
|
|
209
|
-
it("support sets are monotonically widening (PR_A ⊆ PR_B)", () => {
|
|
210
|
-
for (const id of PR_A_SUPPORTED_TOPOLOGIES) {
|
|
211
|
-
expect(PR_B_SUPPORTED_TOPOLOGIES.has(id)).toBe(true);
|
|
212
|
-
}
|
|
213
|
-
// PR_B strictly widens PR_A. Do not hard-code the delta — PR-C / PR-D
|
|
214
|
-
// will further widen PR_B (or introduce PR_C_SUPPORTED_TOPOLOGIES).
|
|
215
|
-
// The structural invariant (monotonic widening) is what matters here.
|
|
216
|
-
expect(PR_B_SUPPORTED_TOPOLOGIES.size).toBeGreaterThan(PR_A_SUPPORTED_TOPOLOGIES.size);
|
|
217
|
-
});
|
|
218
|
-
it("the 4 spawn-ready shapes cover 5 of the 6 spawn-supported TopologyIds " +
|
|
219
|
-
"(cc-teams-litellm-sessions is reachable via main-teams_foreign with provider=litellm)", () => {
|
|
220
|
-
const spawnReadyIds = new Set(AUDIT_MATRIX.filter((r) => r.expected_spawn_supported).map((r) => r.expected_topology_id));
|
|
221
|
-
// main_native (Claude), main_foreign, main-teams_native, main-teams_foreign
|
|
222
|
-
expect(spawnReadyIds.size).toBe(4);
|
|
223
|
-
// litellm variant is the 5th, reached by flipping subagent.provider
|
|
224
|
-
// to litellm under main-teams_foreign (same shape, different provider).
|
|
225
|
-
const litellmRow = {
|
|
226
|
-
...AUDIT_MATRIX.find((r) => r.shape === "main-teams_foreign"),
|
|
227
|
-
axes: {
|
|
228
|
-
subagent: {
|
|
229
|
-
provider: "litellm",
|
|
230
|
-
model_id: "llama-8b",
|
|
231
|
-
},
|
|
232
|
-
},
|
|
233
|
-
};
|
|
234
|
-
const r = deriveTopologyShape(litellmRow.axes, litellmRow.signals);
|
|
235
|
-
expect(r.ok).toBe(true);
|
|
236
|
-
if (r.ok) {
|
|
237
|
-
expect(r.derived.shape).toBe("main-teams_foreign");
|
|
238
|
-
const mapping = shapeToTopologyId({
|
|
239
|
-
shape: r.derived.shape,
|
|
240
|
-
subagent_provider: r.derived.subagent_provider,
|
|
241
|
-
signals: {
|
|
242
|
-
claudeHost: litellmRow.signals.claudeHost,
|
|
243
|
-
codexSessionActive: litellmRow.signals.codexSessionActive,
|
|
244
|
-
},
|
|
245
|
-
});
|
|
246
|
-
expect(mapping.ok).toBe(true);
|
|
247
|
-
if (mapping.ok) {
|
|
248
|
-
expect(mapping.topology_id).toBe("cc-teams-litellm-sessions");
|
|
249
|
-
expect(PR_B_SUPPORTED_TOPOLOGIES.has(mapping.topology_id)).toBe(true);
|
|
250
|
-
}
|
|
251
|
-
}
|
|
252
|
-
});
|
|
253
|
-
});
|
|
254
|
-
// ---------------------------------------------------------------------------
|
|
255
|
-
// Stage 5 — pipeline step invariants (catalog integrity for steps 1-4, 6-7)
|
|
256
|
-
// ---------------------------------------------------------------------------
|
|
257
|
-
describe("P8 audit — stage 5: pipeline step invariants (topology-agnostic steps)", () => {
|
|
258
|
-
// Steps 1-4, 6-7 consume ExecutionTopology as an opaque snapshot. The
|
|
259
|
-
// audit verifies that the resolved topology always carries the 5
|
|
260
|
-
// load-bearing fields those steps read.
|
|
261
|
-
for (const row of AUDIT_MATRIX) {
|
|
262
|
-
it(`${row.shape}: resolved topology exposes the 6 step-agnostic fields`, () => {
|
|
263
|
-
const res = resolveExecutionTopology({
|
|
264
|
-
ontoConfig: { review: row.axes, ...(row.config_extras ?? {}) },
|
|
265
|
-
claudeHost: row.signals.claudeHost,
|
|
266
|
-
codexSessionActive: row.signals.codexSessionActive,
|
|
267
|
-
experimentalAgentTeams: row.signals.experimentalAgentTeams,
|
|
268
|
-
codexAvailable: true,
|
|
269
|
-
liteLlmEndpointAvailable: false,
|
|
270
|
-
});
|
|
271
|
-
if (res.type !== "resolved") {
|
|
272
|
-
throw new Error(`expected resolved for shape=${row.shape}, got no_host`);
|
|
273
|
-
}
|
|
274
|
-
const t = res.topology;
|
|
275
|
-
// steps 1 (interpret) / 3 (start-session) read topology.id + lens_spawn_mechanism
|
|
276
|
-
expect(typeof t.id).toBe("string");
|
|
277
|
-
expect(typeof t.lens_spawn_mechanism).toBe("string");
|
|
278
|
-
// step 2 (bind) reads teamlead_location
|
|
279
|
-
expect(typeof t.teamlead_location).toBe("string");
|
|
280
|
-
// step 4 (materialize) reads max_concurrent_lenses
|
|
281
|
-
expect(typeof t.max_concurrent_lenses).toBe("number");
|
|
282
|
-
expect(t.max_concurrent_lenses).toBeGreaterThan(0);
|
|
283
|
-
// step 5 (dispatch) reads everything; step 6 (synthesize) reads deliberation_channel
|
|
284
|
-
expect(typeof t.deliberation_channel).toBe("string");
|
|
285
|
-
// step 7 (complete) reads plan_trace
|
|
286
|
-
expect(Array.isArray(t.plan_trace)).toBe(true);
|
|
287
|
-
expect(t.plan_trace.length).toBeGreaterThan(0);
|
|
288
|
-
});
|
|
289
|
-
}
|
|
290
|
-
});
|
|
291
|
-
// ---------------------------------------------------------------------------
|
|
292
|
-
// Stage 6 — catalog non-drift (guards against future refactor regressions)
|
|
293
|
-
// ---------------------------------------------------------------------------
|
|
294
|
-
describe("P8 audit — stage 6: catalog + default priority non-drift", () => {
|
|
295
|
-
it("TOPOLOGY_CATALOG contains every expected_topology_id from the audit", () => {
|
|
296
|
-
for (const row of AUDIT_MATRIX) {
|
|
297
|
-
expect(TOPOLOGY_CATALOG[row.expected_topology_id]).toBeDefined();
|
|
298
|
-
}
|
|
299
|
-
});
|
|
300
|
-
it("TOPOLOGY_CATALOG exposes every audit topology id (post-P9.1 ladder-free invariant)", () => {
|
|
301
|
-
// P9.1 (2026-04-21): DEFAULT_TOPOLOGY_PRIORITY is retired. The catalog
|
|
302
|
-
// is now the SSOT for resolvable TopologyIds — the audit must assert
|
|
303
|
-
// every expected_topology_id is materialized as a catalog entry so
|
|
304
|
-
// the axis-first pipeline can produce it.
|
|
305
|
-
for (const row of AUDIT_MATRIX) {
|
|
306
|
-
expect(TOPOLOGY_CATALOG[row.expected_topology_id]).toBeDefined();
|
|
307
|
-
}
|
|
308
|
-
});
|
|
309
|
-
// Note: shape-name uniqueness is already asserted in Stage 1. Not repeated
|
|
310
|
-
// here — see `"every shape in the audit is unique"` above.
|
|
311
|
-
});
|
|
@@ -1,117 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Review topology shape → TopologyId mapping.
|
|
3
|
-
*
|
|
4
|
-
* # What this module is
|
|
5
|
-
*
|
|
6
|
-
* A pure function that converts the axis-derived `TopologyShape` plus
|
|
7
|
-
* host-context signals into a canonical `TopologyId`.
|
|
8
|
-
*
|
|
9
|
-
* # Why it exists
|
|
10
|
-
*
|
|
11
|
-
* Shape does not uniquely determine TopologyId because several shapes
|
|
12
|
-
* depend on host type:
|
|
13
|
-
*
|
|
14
|
-
* - `main_native` + Claude host → `cc-main-agent-subagent`
|
|
15
|
-
* - `main_native` + Codex host → `codex-main-subprocess`
|
|
16
|
-
* - `main_foreign` (codex) + CC → `cc-main-codex-subprocess`
|
|
17
|
-
* - `main_foreign` (codex) + Codex host → `codex-main-subprocess`
|
|
18
|
-
* - `main-teams_foreign` (codex) → `cc-teams-codex-subprocess`
|
|
19
|
-
*
|
|
20
|
-
* # How it relates
|
|
21
|
-
*
|
|
22
|
-
* - Input: `TopologyShape` (from `topology-shape-derivation.ts`) +
|
|
23
|
-
* `{claudeHost, codexSessionActive}` + optional foreign subagent provider.
|
|
24
|
-
* - Output: a `TopologyId` or a failure reason.
|
|
25
|
-
*/
|
|
26
|
-
// ---------------------------------------------------------------------------
|
|
27
|
-
// Main mapping function
|
|
28
|
-
// ---------------------------------------------------------------------------
|
|
29
|
-
/**
|
|
30
|
-
* Map a shape classification to a canonical TopologyId value.
|
|
31
|
-
*
|
|
32
|
-
* Returns failure when the shape + signal combination has no canonical
|
|
33
|
-
* TopologyId in the current catalog. Failure cases (post-P2):
|
|
34
|
-
* - `main_native` with neither Claude nor Codex host (plain terminal
|
|
35
|
-
* without codex OAuth — truly unreachable).
|
|
36
|
-
* - `main_foreign` with a provider that cannot be handled by the current
|
|
37
|
-
* host. Currently only `codex` is mapped; non-codex LLM model selection
|
|
38
|
-
* belongs to `llm`, not this topology axis.
|
|
39
|
-
*/
|
|
40
|
-
export function shapeToTopologyId(input) {
|
|
41
|
-
const { shape, subagent_provider, signals } = input;
|
|
42
|
-
const trace = [];
|
|
43
|
-
const log = (line) => {
|
|
44
|
-
trace.push(line);
|
|
45
|
-
};
|
|
46
|
-
log(`mapping shape=${shape} subagent_provider=${subagent_provider ?? "null"} ` +
|
|
47
|
-
`claudeHost=${signals.claudeHost} codexSessionActive=${signals.codexSessionActive}`);
|
|
48
|
-
switch (shape) {
|
|
49
|
-
case "main_native": {
|
|
50
|
-
if (signals.claudeHost) {
|
|
51
|
-
log("→ cc-main-agent-subagent (Claude host + native = Agent tool)");
|
|
52
|
-
return { ok: true, topology_id: "cc-main-agent-subagent", trace };
|
|
53
|
-
}
|
|
54
|
-
if (signals.codexSessionActive) {
|
|
55
|
-
log("→ codex-main-subprocess (Codex host + native = codex subprocess)");
|
|
56
|
-
return { ok: true, topology_id: "codex-main-subprocess", trace };
|
|
57
|
-
}
|
|
58
|
-
log("no canonical TopologyId: main_native requires Claude or Codex host");
|
|
59
|
-
return {
|
|
60
|
-
ok: false,
|
|
61
|
-
reason: "main_native shape requires Claude Code host or Codex execution. " +
|
|
62
|
-
"Neither Claude host nor Codex execution was detected.",
|
|
63
|
-
trace,
|
|
64
|
-
};
|
|
65
|
-
}
|
|
66
|
-
case "main_foreign": {
|
|
67
|
-
if (signals.claudeHost && subagent_provider === "codex") {
|
|
68
|
-
log("→ cc-main-codex-subprocess (Claude + main + codex lens)");
|
|
69
|
-
return { ok: true, topology_id: "cc-main-codex-subprocess", trace };
|
|
70
|
-
}
|
|
71
|
-
if (signals.codexSessionActive && subagent_provider === "codex") {
|
|
72
|
-
log("→ codex-main-subprocess (Codex host + codex lens)");
|
|
73
|
-
return { ok: true, topology_id: "codex-main-subprocess", trace };
|
|
74
|
-
}
|
|
75
|
-
log(`no canonical TopologyId: main_foreign with provider=${subagent_provider} ` +
|
|
76
|
-
`requires Claude host, Codex execution, or a different provider`);
|
|
77
|
-
return {
|
|
78
|
-
ok: false,
|
|
79
|
-
reason: `main_foreign shape with provider=${subagent_provider} has no canonical TopologyId. ` +
|
|
80
|
-
"Either (a) enable CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1 for main-teams_foreign, " +
|
|
81
|
-
"(b) use provider=codex under Claude host for cc-main-codex-subprocess, " +
|
|
82
|
-
"or (c) run through Codex for codex-main-subprocess.",
|
|
83
|
-
trace,
|
|
84
|
-
};
|
|
85
|
-
}
|
|
86
|
-
case "main-teams_native": {
|
|
87
|
-
log("→ cc-teams-agent-subagent (TeamCreate + native lens)");
|
|
88
|
-
return { ok: true, topology_id: "cc-teams-agent-subagent", trace };
|
|
89
|
-
}
|
|
90
|
-
case "main-teams_foreign": {
|
|
91
|
-
if (subagent_provider === "codex") {
|
|
92
|
-
log("→ cc-teams-codex-subprocess (TeamCreate + codex lens)");
|
|
93
|
-
return { ok: true, topology_id: "cc-teams-codex-subprocess", trace };
|
|
94
|
-
}
|
|
95
|
-
log(`no canonical TopologyId: main-teams_foreign with provider=${subagent_provider}`);
|
|
96
|
-
return {
|
|
97
|
-
ok: false,
|
|
98
|
-
reason: `main-teams_foreign shape with provider=${subagent_provider} has no canonical TopologyId. ` +
|
|
99
|
-
"Only provider=codex is mapped in the review topology axis. Use llm.provider for API-key/local model selection.",
|
|
100
|
-
trace,
|
|
101
|
-
};
|
|
102
|
-
}
|
|
103
|
-
case "main-teams_deliberation": {
|
|
104
|
-
log("→ cc-teams-lens-agent-deliberation (TeamCreate + native + controlled deliberation)");
|
|
105
|
-
return {
|
|
106
|
-
ok: true,
|
|
107
|
-
topology_id: "cc-teams-lens-agent-deliberation",
|
|
108
|
-
trace,
|
|
109
|
-
};
|
|
110
|
-
}
|
|
111
|
-
case "ext-teamlead_native": {
|
|
112
|
-
// Only codex is supported as external teamlead in the current catalog.
|
|
113
|
-
log("→ codex-nested-subprocess (external codex teamlead + nested codex lens)");
|
|
114
|
-
return { ok: true, topology_id: "codex-nested-subprocess", trace };
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
}
|