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,615 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Codex multi-agent fixes — E2E test suite.
|
|
3
|
-
*
|
|
4
|
-
* Run: `npx vitest run src/core-runtime/cli/e2e-codex-multi-agent-fixes.test.ts`
|
|
5
|
-
*
|
|
6
|
-
* Covers:
|
|
7
|
-
* B. OntoConfig codex namespace (config-chain.ts)
|
|
8
|
-
* C. appendExecutorModelArgs codex fallback (review-invoke.ts)
|
|
9
|
-
* D. Synthesize retry (run-review-prompt-execution.ts)
|
|
10
|
-
* E. Coordinator agent prompt — Write tool removed (coordinator-state-machine.ts)
|
|
11
|
-
* F. process.md ToolSearch instruction
|
|
12
|
-
*
|
|
13
|
-
* Isolation strategy:
|
|
14
|
-
* Each test builds minimal tmpdir fixtures. Tests that exercise the
|
|
15
|
-
* prompt execution runner build a full session directory with a mock
|
|
16
|
-
* execution-plan.yaml and mock prompt packets.
|
|
17
|
-
*
|
|
18
|
-
* Format history:
|
|
19
|
-
* Converted from a tsx-run custom minimal test runner to vitest in
|
|
20
|
-
* 2026-04-18 (handoff §2 Priority 2 Phase C). Fixture update included:
|
|
21
|
-
* B-1~B-6 now declare `execution_topology_priority` so atomic profile
|
|
22
|
-
* adoption (PR #96 + PR #113) does not reject the partial-profile
|
|
23
|
-
* fixtures that predated sketch v3.
|
|
24
|
-
*/
|
|
25
|
-
import { describe, it, afterAll } from "vitest";
|
|
26
|
-
import fs from "node:fs";
|
|
27
|
-
import os from "node:os";
|
|
28
|
-
import path from "node:path";
|
|
29
|
-
import { resolveConfigChain } from "../discovery/config-chain.js";
|
|
30
|
-
// ---------------------------------------------------------------------------
|
|
31
|
-
// Test helpers
|
|
32
|
-
// ---------------------------------------------------------------------------
|
|
33
|
-
function assert(condition, message) {
|
|
34
|
-
if (!condition)
|
|
35
|
-
throw new Error(message);
|
|
36
|
-
}
|
|
37
|
-
function assertEqual(actual, expected, message) {
|
|
38
|
-
if (actual !== expected) {
|
|
39
|
-
throw new Error(`${message} — expected ${JSON.stringify(expected)} got ${JSON.stringify(actual)}`);
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
function assertIncludes(text, needle, message) {
|
|
43
|
-
if (!text.includes(needle)) {
|
|
44
|
-
throw new Error(`${message} — text does not include ${JSON.stringify(needle)}`);
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
function assertNotIncludes(text, needle, message) {
|
|
48
|
-
if (text.includes(needle)) {
|
|
49
|
-
throw new Error(`${message} — text unexpectedly includes ${JSON.stringify(needle)}`);
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
// ---------------------------------------------------------------------------
|
|
53
|
-
// Fixture helpers
|
|
54
|
-
// ---------------------------------------------------------------------------
|
|
55
|
-
function makeTmpDir(prefix) {
|
|
56
|
-
return fs.mkdtempSync(path.join(os.tmpdir(), `onto-e2e-cmaf-${prefix}-`));
|
|
57
|
-
}
|
|
58
|
-
function writeYaml(filePath, data) {
|
|
59
|
-
// Minimal YAML serializer sufficient for test fixtures
|
|
60
|
-
const lines = [];
|
|
61
|
-
function renderValue(value, indent) {
|
|
62
|
-
const pad = " ".repeat(indent);
|
|
63
|
-
if (value === null || value === undefined) {
|
|
64
|
-
lines.push("null");
|
|
65
|
-
return;
|
|
66
|
-
}
|
|
67
|
-
if (typeof value === "string") {
|
|
68
|
-
// Use quoted form for safety
|
|
69
|
-
lines.push(`"${value.replace(/"/g, '\\"')}"`);
|
|
70
|
-
return;
|
|
71
|
-
}
|
|
72
|
-
if (typeof value === "number" || typeof value === "boolean") {
|
|
73
|
-
lines.push(String(value));
|
|
74
|
-
return;
|
|
75
|
-
}
|
|
76
|
-
if (Array.isArray(value)) {
|
|
77
|
-
if (value.length === 0) {
|
|
78
|
-
lines.push("[]");
|
|
79
|
-
return;
|
|
80
|
-
}
|
|
81
|
-
lines.push("");
|
|
82
|
-
for (const item of value) {
|
|
83
|
-
const lineStart = `${pad}- `;
|
|
84
|
-
if (typeof item === "object" && item !== null && !Array.isArray(item)) {
|
|
85
|
-
const entries = Object.entries(item);
|
|
86
|
-
let first = true;
|
|
87
|
-
for (const [k, v] of entries) {
|
|
88
|
-
if (first) {
|
|
89
|
-
lines.push(`${lineStart}${k}: `);
|
|
90
|
-
first = false;
|
|
91
|
-
}
|
|
92
|
-
else {
|
|
93
|
-
lines.push(`${pad} ${k}: `);
|
|
94
|
-
}
|
|
95
|
-
renderValue(v, indent + 4);
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
else {
|
|
99
|
-
lines.push(lineStart);
|
|
100
|
-
renderValue(item, indent + 2);
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
return;
|
|
104
|
-
}
|
|
105
|
-
if (typeof value === "object") {
|
|
106
|
-
const entries = Object.entries(value);
|
|
107
|
-
if (entries.length === 0) {
|
|
108
|
-
lines.push("{}");
|
|
109
|
-
return;
|
|
110
|
-
}
|
|
111
|
-
lines.push("");
|
|
112
|
-
for (const [k, v] of entries) {
|
|
113
|
-
lines.push(`${pad}${k}: `);
|
|
114
|
-
renderValue(v, indent + 2);
|
|
115
|
-
}
|
|
116
|
-
return;
|
|
117
|
-
}
|
|
118
|
-
lines.push(String(value));
|
|
119
|
-
}
|
|
120
|
-
for (const [key, value] of Object.entries(data)) {
|
|
121
|
-
lines.push(`${key}: `);
|
|
122
|
-
renderValue(value, 2);
|
|
123
|
-
}
|
|
124
|
-
fs.mkdirSync(path.dirname(filePath), { recursive: true });
|
|
125
|
-
fs.writeFileSync(filePath, lines.join("").replace(/: \n/g, ":\n").replace(/: (\S)/g, ": $1") + "\n", "utf8");
|
|
126
|
-
}
|
|
127
|
-
/** Cleanup directory, ignoring errors. */
|
|
128
|
-
function rmDir(dir) {
|
|
129
|
-
try {
|
|
130
|
-
fs.rmSync(dir, { recursive: true, force: true });
|
|
131
|
-
}
|
|
132
|
-
catch { /* ignore */ }
|
|
133
|
-
}
|
|
134
|
-
const cleanupDirs = [];
|
|
135
|
-
function trackCleanup(dir) {
|
|
136
|
-
cleanupDirs.push(dir);
|
|
137
|
-
return dir;
|
|
138
|
-
}
|
|
139
|
-
// ---------------------------------------------------------------------------
|
|
140
|
-
// B. OntoConfig codex namespace (config-chain.ts)
|
|
141
|
-
// ---------------------------------------------------------------------------
|
|
142
|
-
describe("B. config-chain codex namespace", () => {
|
|
143
|
-
// Fixture note (P9.4, 2026-04-21): each config.yml declares a `review:`
|
|
144
|
-
// axis block so the project side claims profile ownership. Post-P9.4
|
|
145
|
-
// this is no longer a hard requirement — a project with only profile
|
|
146
|
-
// fields (no review block) would also adopt, and a project with only
|
|
147
|
-
// a review block (no profile fields) also adopts via the ownership
|
|
148
|
-
// claim — but keeping the review block in fixtures exercises the
|
|
149
|
-
// canonical user-facing shape. The specific axis values don't affect
|
|
150
|
-
// what these tests assert: they verify that the orthogonal/profile
|
|
151
|
-
// merge correctly surfaces the `codex:` namespace and top-level
|
|
152
|
-
// `model` / `reasoning_effort` values.
|
|
153
|
-
//
|
|
154
|
-
// History: pre-P9.2 the completeness signal was
|
|
155
|
-
// `execution_topology_priority`. Pre-P9.4 the signal was the `review:`
|
|
156
|
-
// axis block via `validateProfileCompleteness` (retired along with
|
|
157
|
-
// `buildBothIncompleteError` in P9.4). P9.5 additionally retired
|
|
158
|
-
// `legacy-field-deprecation.ts` — legacy provider fields in YAML are
|
|
159
|
-
// now silently dropped during type narrowing; these tests still
|
|
160
|
-
// declare `review:` blocks for realism, not for correctness.
|
|
161
|
-
it("B-1: codex namespace parsed from project config", async () => {
|
|
162
|
-
const homeDir = trackCleanup(makeTmpDir("b1h"));
|
|
163
|
-
const projDir = trackCleanup(makeTmpDir("b1p"));
|
|
164
|
-
fs.mkdirSync(path.join(projDir, ".onto"), { recursive: true });
|
|
165
|
-
fs.writeFileSync(path.join(projDir, ".onto", "config.yml"), "review:\n subagent:\n provider: codex\n model_id: gpt-5.4\ncodex:\n model: gpt-5.4\n effort: xhigh\n", "utf8");
|
|
166
|
-
const config = await resolveConfigChain(homeDir, projDir);
|
|
167
|
-
assertEqual(config.codex?.model, "gpt-5.4", "codex.model parsed");
|
|
168
|
-
assertEqual(config.codex?.effort, "xhigh", "codex.effort parsed");
|
|
169
|
-
});
|
|
170
|
-
it("B-2: project codex namespace overrides home", async () => {
|
|
171
|
-
const homeDir = trackCleanup(makeTmpDir("b2h"));
|
|
172
|
-
const projDir = trackCleanup(makeTmpDir("b2p"));
|
|
173
|
-
fs.mkdirSync(path.join(homeDir, ".onto"), { recursive: true });
|
|
174
|
-
fs.writeFileSync(path.join(homeDir, ".onto", "config.yml"), "review:\n subagent:\n provider: codex\n model_id: gpt-5.4\ncodex:\n model: gpt-5.3\n effort: high\n", "utf8");
|
|
175
|
-
fs.mkdirSync(path.join(projDir, ".onto"), { recursive: true });
|
|
176
|
-
fs.writeFileSync(path.join(projDir, ".onto", "config.yml"), "review:\n subagent:\n provider: codex\n model_id: gpt-5.4\ncodex:\n model: gpt-5.4\n effort: xhigh\n", "utf8");
|
|
177
|
-
const config = await resolveConfigChain(homeDir, projDir);
|
|
178
|
-
assertEqual(config.codex?.model, "gpt-5.4", "project codex.model wins");
|
|
179
|
-
assertEqual(config.codex?.effort, "xhigh", "project codex.effort wins");
|
|
180
|
-
});
|
|
181
|
-
it("B-3: top-level model coexists with codex namespace", async () => {
|
|
182
|
-
const homeDir = trackCleanup(makeTmpDir("b3h"));
|
|
183
|
-
const projDir = trackCleanup(makeTmpDir("b3p"));
|
|
184
|
-
fs.mkdirSync(path.join(projDir, ".onto"), { recursive: true });
|
|
185
|
-
fs.writeFileSync(path.join(projDir, ".onto", "config.yml"), "review:\n subagent:\n provider: codex\n model_id: gpt-5.4\nmodel: claude-sonnet-4-20250514\nreasoning_effort: medium\ncodex:\n model: gpt-5.4\n effort: xhigh\n", "utf8");
|
|
186
|
-
const config = await resolveConfigChain(homeDir, projDir);
|
|
187
|
-
assertEqual(config.model, "claude-sonnet-4-20250514", "top-level model");
|
|
188
|
-
assertEqual(config.reasoning_effort, "medium", "top-level reasoning_effort");
|
|
189
|
-
assertEqual(config.codex?.model, "gpt-5.4", "codex.model");
|
|
190
|
-
assertEqual(config.codex?.effort, "xhigh", "codex.effort");
|
|
191
|
-
});
|
|
192
|
-
it("B-4: missing codex namespace → undefined", async () => {
|
|
193
|
-
const homeDir = trackCleanup(makeTmpDir("b4h"));
|
|
194
|
-
const projDir = trackCleanup(makeTmpDir("b4p"));
|
|
195
|
-
fs.mkdirSync(path.join(projDir, ".onto"), { recursive: true });
|
|
196
|
-
fs.writeFileSync(path.join(projDir, ".onto", "config.yml"), "review:\n subagent:\n provider: codex\n model_id: gpt-5.4\nmodel: claude-sonnet-4-20250514\n", "utf8");
|
|
197
|
-
const config = await resolveConfigChain(homeDir, projDir);
|
|
198
|
-
assertEqual(config.codex, undefined, "codex absent → undefined");
|
|
199
|
-
});
|
|
200
|
-
it("B-5: empty codex namespace → empty object", async () => {
|
|
201
|
-
const homeDir = trackCleanup(makeTmpDir("b5h"));
|
|
202
|
-
const projDir = trackCleanup(makeTmpDir("b5p"));
|
|
203
|
-
fs.mkdirSync(path.join(projDir, ".onto"), { recursive: true });
|
|
204
|
-
fs.writeFileSync(path.join(projDir, ".onto", "config.yml"), "review:\n subagent:\n provider: codex\n model_id: gpt-5.4\ncodex: {}\n", "utf8");
|
|
205
|
-
const config = await resolveConfigChain(homeDir, projDir);
|
|
206
|
-
assert(config.codex !== undefined, "codex namespace exists");
|
|
207
|
-
assertEqual(config.codex?.model, undefined, "codex.model undefined");
|
|
208
|
-
assertEqual(config.codex?.effort, undefined, "codex.effort undefined");
|
|
209
|
-
});
|
|
210
|
-
it("B-6: home codex used when project has no config", async () => {
|
|
211
|
-
const homeDir = trackCleanup(makeTmpDir("b6h"));
|
|
212
|
-
const projDir = trackCleanup(makeTmpDir("b6p"));
|
|
213
|
-
fs.mkdirSync(path.join(homeDir, ".onto"), { recursive: true });
|
|
214
|
-
fs.writeFileSync(path.join(homeDir, ".onto", "config.yml"), "review:\n subagent:\n provider: codex\n model_id: gpt-5.4\ncodex:\n model: gpt-5.3\n effort: high\n", "utf8");
|
|
215
|
-
// No .onto/config.yml in project
|
|
216
|
-
const config = await resolveConfigChain(homeDir, projDir);
|
|
217
|
-
assertEqual(config.codex?.model, "gpt-5.3", "home codex.model used");
|
|
218
|
-
assertEqual(config.codex?.effort, "high", "home codex.effort used");
|
|
219
|
-
});
|
|
220
|
-
});
|
|
221
|
-
// ---------------------------------------------------------------------------
|
|
222
|
-
// C. appendExecutorModelArgs codex fallback (review-invoke.ts)
|
|
223
|
-
//
|
|
224
|
-
// We can't import the private function directly, so we test it indirectly
|
|
225
|
-
// through the CLI argv interface by checking the resolved executor config.
|
|
226
|
-
// Strategy: invoke reviewPrepareOnly with --codex and mock executor, then
|
|
227
|
-
// inspect the execution-plan + the runner result to verify model/effort.
|
|
228
|
-
//
|
|
229
|
-
// For isolated unit testing, we duplicate the function's logic and verify.
|
|
230
|
-
// ---------------------------------------------------------------------------
|
|
231
|
-
import { readSingleOptionValueFromArgv } from "../review/review-artifact-utils.js";
|
|
232
|
-
describe("C. codex config fallback", () => {
|
|
233
|
-
function resolveModel(argv, config) {
|
|
234
|
-
const fromArgv = readSingleOptionValueFromArgv(argv, "model");
|
|
235
|
-
return ((typeof fromArgv === "string" && fromArgv.length > 0 ? fromArgv : undefined) ??
|
|
236
|
-
config?.model ??
|
|
237
|
-
config?.codex?.model);
|
|
238
|
-
}
|
|
239
|
-
function resolveEffort(argv, config) {
|
|
240
|
-
const fromArgv = readSingleOptionValueFromArgv(argv, "reasoning-effort");
|
|
241
|
-
return ((typeof fromArgv === "string" && fromArgv.length > 0 ? fromArgv : undefined) ??
|
|
242
|
-
config?.reasoning_effort ??
|
|
243
|
-
config?.codex?.effort);
|
|
244
|
-
}
|
|
245
|
-
it("C-1: CLI flag wins over everything (model)", () => {
|
|
246
|
-
const config = {
|
|
247
|
-
model: "claude-sonnet-4-20250514",
|
|
248
|
-
codex: { model: "gpt-5.3" },
|
|
249
|
-
};
|
|
250
|
-
const result = resolveModel(["--model", "gpt-5.4"], config);
|
|
251
|
-
assertEqual(result, "gpt-5.4", "CLI flag wins");
|
|
252
|
-
});
|
|
253
|
-
it("C-2: top-level config wins over codex namespace", () => {
|
|
254
|
-
const config = {
|
|
255
|
-
model: "claude-sonnet-4-20250514",
|
|
256
|
-
codex: { model: "gpt-5.4" },
|
|
257
|
-
};
|
|
258
|
-
const result = resolveModel([], config);
|
|
259
|
-
assertEqual(result, "claude-sonnet-4-20250514", "top-level wins");
|
|
260
|
-
});
|
|
261
|
-
it("C-3: codex namespace used when top-level absent (model)", () => {
|
|
262
|
-
const config = {
|
|
263
|
-
codex: { model: "gpt-5.4" },
|
|
264
|
-
};
|
|
265
|
-
const result = resolveModel([], config);
|
|
266
|
-
assertEqual(result, "gpt-5.4", "codex.model fallback");
|
|
267
|
-
});
|
|
268
|
-
it("C-4: codex effort used when reasoning_effort absent", () => {
|
|
269
|
-
const config = {
|
|
270
|
-
codex: { effort: "xhigh" },
|
|
271
|
-
};
|
|
272
|
-
const result = resolveEffort([], config);
|
|
273
|
-
assertEqual(result, "xhigh", "codex.effort fallback");
|
|
274
|
-
});
|
|
275
|
-
it("C-5: top-level reasoning_effort wins over codex effort", () => {
|
|
276
|
-
const config = {
|
|
277
|
-
reasoning_effort: "medium",
|
|
278
|
-
codex: { effort: "xhigh" },
|
|
279
|
-
};
|
|
280
|
-
const result = resolveEffort([], config);
|
|
281
|
-
assertEqual(result, "medium", "top-level effort wins");
|
|
282
|
-
});
|
|
283
|
-
it("C-6: CLI reasoning-effort wins over all", () => {
|
|
284
|
-
const config = {
|
|
285
|
-
reasoning_effort: "medium",
|
|
286
|
-
codex: { effort: "xhigh" },
|
|
287
|
-
};
|
|
288
|
-
const result = resolveEffort(["--reasoning-effort", "low"], config);
|
|
289
|
-
assertEqual(result, "low", "CLI flag wins");
|
|
290
|
-
});
|
|
291
|
-
it("C-7: all absent → undefined", () => {
|
|
292
|
-
const config = {};
|
|
293
|
-
assertEqual(resolveModel([], config), undefined, "model undefined");
|
|
294
|
-
assertEqual(resolveEffort([], config), undefined, "effort undefined");
|
|
295
|
-
});
|
|
296
|
-
it("C-8: undefined config → undefined", () => {
|
|
297
|
-
assertEqual(resolveModel([], undefined), undefined, "model no config");
|
|
298
|
-
assertEqual(resolveEffort([], undefined), undefined, "effort no config");
|
|
299
|
-
});
|
|
300
|
-
});
|
|
301
|
-
// ---------------------------------------------------------------------------
|
|
302
|
-
// D. Synthesize retry (run-review-prompt-execution.ts)
|
|
303
|
-
//
|
|
304
|
-
// Strategy: build a minimal session, use always-succeed executor for lenses,
|
|
305
|
-
// and flaky/always-fail executor for synthesize to test the new retry logic.
|
|
306
|
-
// D-4/D-5 pre-write lens outputs to bypass the lens retry loop (10 retries
|
|
307
|
-
// with 8s backoff = too slow for E2E tests).
|
|
308
|
-
// ---------------------------------------------------------------------------
|
|
309
|
-
import { executeReviewPromptExecution } from "./run-review-prompt-execution.js";
|
|
310
|
-
import { writeYamlDocument } from "../review/review-artifact-utils.js";
|
|
311
|
-
describe("D. Synthesize retry", () => {
|
|
312
|
-
const projectRoot = process.cwd();
|
|
313
|
-
const BOUNDARY_DECISION = {
|
|
314
|
-
requested_policy: "denied",
|
|
315
|
-
effective_policy: "denied",
|
|
316
|
-
guarantee_level: "prompt_declared_only",
|
|
317
|
-
notes: [],
|
|
318
|
-
};
|
|
319
|
-
async function buildMinimalSession(prefix) {
|
|
320
|
-
const sessionRoot = trackCleanup(makeTmpDir(prefix));
|
|
321
|
-
const packetRoot = path.join(sessionRoot, "prompt-packets");
|
|
322
|
-
const round1Root = path.join(sessionRoot, "round1");
|
|
323
|
-
fs.mkdirSync(packetRoot, { recursive: true });
|
|
324
|
-
fs.mkdirSync(round1Root, { recursive: true });
|
|
325
|
-
for (const lensId of ["logic", "pragmatics"]) {
|
|
326
|
-
fs.writeFileSync(path.join(packetRoot, `${lensId}.prompt.md`), `# ${lensId} prompt packet\nTest.\n`, "utf8");
|
|
327
|
-
}
|
|
328
|
-
fs.writeFileSync(path.join(packetRoot, "synthesize.prompt.md"), "# Synthesize\nCombine.\n", "utf8");
|
|
329
|
-
const synthesizeOutputPath = path.join(sessionRoot, "synthesis-output.md");
|
|
330
|
-
await writeYamlDocument(path.join(sessionRoot, "execution-plan.yaml"), {
|
|
331
|
-
session_id: `e2e-${prefix}`,
|
|
332
|
-
session_root: sessionRoot,
|
|
333
|
-
execution_realization: "subagent",
|
|
334
|
-
host_runtime: "codex",
|
|
335
|
-
review_mode: "core-axis",
|
|
336
|
-
interpretation_artifact_path: path.join(sessionRoot, "interpretation.yaml"),
|
|
337
|
-
binding_output_path: path.join(sessionRoot, "binding.yaml"),
|
|
338
|
-
session_metadata_path: path.join(sessionRoot, "session-metadata.yaml"),
|
|
339
|
-
execution_preparation_root: path.join(sessionRoot, "execution-preparation"),
|
|
340
|
-
round1_root: round1Root,
|
|
341
|
-
lens_execution_seats: [],
|
|
342
|
-
prompt_packets_root: packetRoot,
|
|
343
|
-
lens_prompt_packet_seats: [
|
|
344
|
-
{
|
|
345
|
-
lens_id: "logic",
|
|
346
|
-
packet_path: path.join(packetRoot, "logic.prompt.md"),
|
|
347
|
-
output_path: path.join(round1Root, "logic.md"),
|
|
348
|
-
},
|
|
349
|
-
{
|
|
350
|
-
lens_id: "pragmatics",
|
|
351
|
-
packet_path: path.join(packetRoot, "pragmatics.prompt.md"),
|
|
352
|
-
output_path: path.join(round1Root, "pragmatics.md"),
|
|
353
|
-
},
|
|
354
|
-
],
|
|
355
|
-
synthesize_prompt_packet_path: path.join(packetRoot, "synthesize.prompt.md"),
|
|
356
|
-
synthesis_output_path: synthesizeOutputPath,
|
|
357
|
-
deliberation_output_path: path.join(sessionRoot, "deliberation.md"),
|
|
358
|
-
execution_result_path: path.join(sessionRoot, "execution-result.yaml"),
|
|
359
|
-
error_log_path: path.join(sessionRoot, "error-log.md"),
|
|
360
|
-
final_output_path: path.join(sessionRoot, "final-output.md"),
|
|
361
|
-
review_record_path: path.join(sessionRoot, "review-record.yaml"),
|
|
362
|
-
boundary_policy: { web_research: "denied", repo_exploration: "denied", recursive_reference_expansion: "denied", source_mutation: "denied" },
|
|
363
|
-
boundary_presentation: { web_research: "denied", repo_exploration: "denied", recursive_reference_expansion: "denied", source_mutation: "denied" },
|
|
364
|
-
boundary_enforcement_profile: { web_research: "prompt_declared_only", repo_exploration: "prompt_declared_only", recursive_reference_expansion: "prompt_declared_only", source_mutation: "prompt_declared_only" },
|
|
365
|
-
effective_boundary_state: {
|
|
366
|
-
web_research: BOUNDARY_DECISION,
|
|
367
|
-
repo_exploration: BOUNDARY_DECISION,
|
|
368
|
-
recursive_reference_expansion: BOUNDARY_DECISION,
|
|
369
|
-
source_mutation: BOUNDARY_DECISION,
|
|
370
|
-
filesystem_scope: { requested_allowed_roots: [projectRoot], effective_allowed_roots: [projectRoot], guarantee_level: "prompt_declared_only", notes: [] },
|
|
371
|
-
},
|
|
372
|
-
});
|
|
373
|
-
return { sessionRoot, synthesizeOutputPath };
|
|
374
|
-
}
|
|
375
|
-
/** Always-succeed executor script (for lenses). */
|
|
376
|
-
function createSucceedScript(dir) {
|
|
377
|
-
const scriptPath = path.join(dir, "succeed-executor.mjs");
|
|
378
|
-
fs.writeFileSync(scriptPath, `
|
|
379
|
-
import fs from "node:fs";
|
|
380
|
-
import path from "node:path";
|
|
381
|
-
const args = process.argv.slice(2);
|
|
382
|
-
const unitId = args[args.indexOf("--unit-id") + 1];
|
|
383
|
-
const unitKind = args[args.indexOf("--unit-kind") + 1];
|
|
384
|
-
const outputPath = args[args.indexOf("--output-path") + 1];
|
|
385
|
-
fs.mkdirSync(path.dirname(outputPath), { recursive: true });
|
|
386
|
-
const output = unitKind === "synthesize"
|
|
387
|
-
? "---\\ndeliberation_status: not_needed\\n---\\n# Synthesize\\nResult.\\n"
|
|
388
|
-
: "# " + unitId + "\\nLens result.\\n";
|
|
389
|
-
fs.writeFileSync(outputPath, output, "utf8");
|
|
390
|
-
`, "utf8");
|
|
391
|
-
return scriptPath;
|
|
392
|
-
}
|
|
393
|
-
/** Flaky synthesize executor: tracks attempts via counter file. */
|
|
394
|
-
function createSynthFlakyScript(dir, mode) {
|
|
395
|
-
const scriptPath = path.join(dir, "synth-flaky.mjs");
|
|
396
|
-
const counterPath = path.join(dir, "synth-counter.txt");
|
|
397
|
-
fs.writeFileSync(scriptPath, `
|
|
398
|
-
import fs from "node:fs";
|
|
399
|
-
import path from "node:path";
|
|
400
|
-
const args = process.argv.slice(2);
|
|
401
|
-
const unitKind = args[args.indexOf("--unit-kind") + 1];
|
|
402
|
-
const unitId = args[args.indexOf("--unit-id") + 1];
|
|
403
|
-
const outputPath = args[args.indexOf("--output-path") + 1];
|
|
404
|
-
const counterPath = ${JSON.stringify(counterPath)};
|
|
405
|
-
const mode = ${JSON.stringify(mode)};
|
|
406
|
-
if (unitKind === "synthesize") {
|
|
407
|
-
let count = 0;
|
|
408
|
-
try { count = parseInt(fs.readFileSync(counterPath, "utf8").trim(), 10); } catch {}
|
|
409
|
-
count++;
|
|
410
|
-
fs.writeFileSync(counterPath, String(count), "utf8");
|
|
411
|
-
if (mode === "always-fail" || (mode === "fail-then-succeed" && count === 1)) {
|
|
412
|
-
process.stderr.write("Simulated synthesize failure (attempt " + count + ")\\n");
|
|
413
|
-
process.exit(1);
|
|
414
|
-
}
|
|
415
|
-
}
|
|
416
|
-
fs.mkdirSync(path.dirname(outputPath), { recursive: true });
|
|
417
|
-
const output = unitKind === "synthesize"
|
|
418
|
-
? "---\\ndeliberation_status: not_needed\\n---\\n# Synthesize\\nResult.\\n"
|
|
419
|
-
: "# " + unitId + "\\nLens.\\n";
|
|
420
|
-
fs.writeFileSync(outputPath, output, "utf8");
|
|
421
|
-
`, "utf8");
|
|
422
|
-
return { scriptPath, counterPath };
|
|
423
|
-
}
|
|
424
|
-
// ── D-1: synthesize succeeds on first attempt ──
|
|
425
|
-
it("D-1: synthesize succeeds on first attempt", async () => {
|
|
426
|
-
const { sessionRoot } = await buildMinimalSession("d1");
|
|
427
|
-
const execDir = trackCleanup(makeTmpDir("d1-exec"));
|
|
428
|
-
const succeedScript = createSucceedScript(execDir);
|
|
429
|
-
const result = await executeReviewPromptExecution({
|
|
430
|
-
projectRoot,
|
|
431
|
-
sessionRoot,
|
|
432
|
-
defaultExecutorConfig: { bin: "node", args: [succeedScript] },
|
|
433
|
-
});
|
|
434
|
-
assertEqual(result.synthesis_executed, true, "synthesis executed");
|
|
435
|
-
assert(!result.halt_reason, "no halt");
|
|
436
|
-
assertEqual(result.executed_lens_count, 2, "2 lenses");
|
|
437
|
-
});
|
|
438
|
-
// ── D-2: synthesize fails first, succeeds on retry ──
|
|
439
|
-
it("D-2: synthesize fails then succeeds on retry", async () => {
|
|
440
|
-
const { sessionRoot } = await buildMinimalSession("d2");
|
|
441
|
-
const execDir = trackCleanup(makeTmpDir("d2-exec"));
|
|
442
|
-
const succeedScript = createSucceedScript(execDir);
|
|
443
|
-
const synthDir = path.join(execDir, "synth");
|
|
444
|
-
fs.mkdirSync(synthDir, { recursive: true });
|
|
445
|
-
const { scriptPath: synthScript, counterPath } = createSynthFlakyScript(synthDir, "fail-then-succeed");
|
|
446
|
-
const result = await executeReviewPromptExecution({
|
|
447
|
-
projectRoot,
|
|
448
|
-
sessionRoot,
|
|
449
|
-
defaultExecutorConfig: { bin: "node", args: [succeedScript] },
|
|
450
|
-
synthesizeExecutorConfig: { bin: "node", args: [synthScript] },
|
|
451
|
-
});
|
|
452
|
-
assertEqual(result.synthesis_executed, true, "synthesis after retry");
|
|
453
|
-
assert(!result.halt_reason, "no halt");
|
|
454
|
-
const attempts = parseInt(fs.readFileSync(counterPath, "utf8").trim(), 10);
|
|
455
|
-
assertEqual(attempts, 2, "2 attempts (1 fail + 1 success)");
|
|
456
|
-
const errorLog = fs.readFileSync(path.join(sessionRoot, "error-log.md"), "utf8");
|
|
457
|
-
assertIncludes(errorLog, "synthesize retry", "retry logged");
|
|
458
|
-
});
|
|
459
|
-
// ── D-3: synthesize fails both attempts → halt ──
|
|
460
|
-
it("D-3: synthesize fails both attempts → halted", async () => {
|
|
461
|
-
const { sessionRoot } = await buildMinimalSession("d3");
|
|
462
|
-
const execDir = trackCleanup(makeTmpDir("d3-exec"));
|
|
463
|
-
const succeedScript = createSucceedScript(execDir);
|
|
464
|
-
const synthDir = path.join(execDir, "synth");
|
|
465
|
-
fs.mkdirSync(synthDir, { recursive: true });
|
|
466
|
-
const { scriptPath: synthScript, counterPath } = createSynthFlakyScript(synthDir, "always-fail");
|
|
467
|
-
const result = await executeReviewPromptExecution({
|
|
468
|
-
projectRoot,
|
|
469
|
-
sessionRoot,
|
|
470
|
-
defaultExecutorConfig: { bin: "node", args: [succeedScript] },
|
|
471
|
-
synthesizeExecutorConfig: { bin: "node", args: [synthScript] },
|
|
472
|
-
});
|
|
473
|
-
assertEqual(result.synthesis_executed, false, "synthesis failed");
|
|
474
|
-
assert(typeof result.halt_reason === "string" && result.halt_reason.length > 0, "halt_reason present");
|
|
475
|
-
assertIncludes(result.halt_reason, "Synthesize execution failed", "halt reason");
|
|
476
|
-
const attempts = parseInt(fs.readFileSync(counterPath, "utf8").trim(), 10);
|
|
477
|
-
assertEqual(attempts, 2, "2 attempts before halt");
|
|
478
|
-
});
|
|
479
|
-
// ── D-4: execution-result artifact written on synthesize halt ──
|
|
480
|
-
it("D-4: execution-result artifact written on synth halt", async () => {
|
|
481
|
-
const { sessionRoot } = await buildMinimalSession("d4");
|
|
482
|
-
const execDir = trackCleanup(makeTmpDir("d4-exec"));
|
|
483
|
-
const succeedScript = createSucceedScript(execDir);
|
|
484
|
-
const synthDir = path.join(execDir, "synth");
|
|
485
|
-
fs.mkdirSync(synthDir, { recursive: true });
|
|
486
|
-
const { scriptPath: synthScript } = createSynthFlakyScript(synthDir, "always-fail");
|
|
487
|
-
await executeReviewPromptExecution({
|
|
488
|
-
projectRoot,
|
|
489
|
-
sessionRoot,
|
|
490
|
-
defaultExecutorConfig: { bin: "node", args: [succeedScript] },
|
|
491
|
-
synthesizeExecutorConfig: { bin: "node", args: [synthScript] },
|
|
492
|
-
});
|
|
493
|
-
const resultPath = path.join(sessionRoot, "execution-result.yaml");
|
|
494
|
-
assert(fs.existsSync(resultPath), "execution-result.yaml created");
|
|
495
|
-
const resultText = fs.readFileSync(resultPath, "utf8");
|
|
496
|
-
assertIncludes(resultText, "halted_partial", "status is halted_partial");
|
|
497
|
-
assertIncludes(resultText, "Synthesize execution failed", "halt_reason in artifact");
|
|
498
|
-
});
|
|
499
|
-
// ── D-5: successful retry still produces correct execution-result ──
|
|
500
|
-
it("D-5: successful retry produces correct execution-result", async () => {
|
|
501
|
-
const { sessionRoot } = await buildMinimalSession("d5");
|
|
502
|
-
const execDir = trackCleanup(makeTmpDir("d5-exec"));
|
|
503
|
-
const succeedScript = createSucceedScript(execDir);
|
|
504
|
-
const synthDir = path.join(execDir, "synth");
|
|
505
|
-
fs.mkdirSync(synthDir, { recursive: true });
|
|
506
|
-
const { scriptPath: synthScript } = createSynthFlakyScript(synthDir, "fail-then-succeed");
|
|
507
|
-
const result = await executeReviewPromptExecution({
|
|
508
|
-
projectRoot,
|
|
509
|
-
sessionRoot,
|
|
510
|
-
defaultExecutorConfig: { bin: "node", args: [succeedScript] },
|
|
511
|
-
synthesizeExecutorConfig: { bin: "node", args: [synthScript] },
|
|
512
|
-
});
|
|
513
|
-
assertEqual(result.synthesis_executed, true, "synthesis executed");
|
|
514
|
-
const resultPath = path.join(sessionRoot, "execution-result.yaml");
|
|
515
|
-
assert(fs.existsSync(resultPath), "execution-result.yaml created");
|
|
516
|
-
const resultText = fs.readFileSync(resultPath, "utf8");
|
|
517
|
-
assertIncludes(resultText, "completed", "status is completed");
|
|
518
|
-
assertNotIncludes(resultText, "halted_partial", "not halted");
|
|
519
|
-
});
|
|
520
|
-
});
|
|
521
|
-
// ---------------------------------------------------------------------------
|
|
522
|
-
// E. Coordinator agent prompt — Write tool removed
|
|
523
|
-
// ---------------------------------------------------------------------------
|
|
524
|
-
describe("E. Coordinator agent prompt", () => {
|
|
525
|
-
// Read the coordinator source to verify prompt template
|
|
526
|
-
const coordinatorSource = fs.readFileSync(path.join(process.cwd(), "src/core-runtime/cli/coordinator-state-machine.ts"), "utf8");
|
|
527
|
-
it("E-1: prompt does NOT contain 'using the Write tool'", () => {
|
|
528
|
-
// Extract the AGENT_PROMPT_TEMPLATE string
|
|
529
|
-
const templateMatch = coordinatorSource.match(/const AGENT_PROMPT_TEMPLATE = `([\s\S]*?)`;/);
|
|
530
|
-
assert(templateMatch !== null, "AGENT_PROMPT_TEMPLATE found in source");
|
|
531
|
-
const template = templateMatch?.[1] ?? "";
|
|
532
|
-
assertNotIncludes(template, "using the Write tool", "prompt should not mention Write tool (Codex incompatible)");
|
|
533
|
-
});
|
|
534
|
-
it("E-2: prompt still instructs writing to output path", () => {
|
|
535
|
-
const templateMatch = coordinatorSource.match(/const AGENT_PROMPT_TEMPLATE = `([\s\S]*?)`;/);
|
|
536
|
-
const template = templateMatch?.[1] ?? "";
|
|
537
|
-
assertIncludes(template, "write the complete output to {output_path}", "output path write instruction preserved");
|
|
538
|
-
});
|
|
539
|
-
it("E-3: prompt contains all required rule keywords", () => {
|
|
540
|
-
const templateMatch = coordinatorSource.match(/const AGENT_PROMPT_TEMPLATE = `([\s\S]*?)`;/);
|
|
541
|
-
const template = templateMatch?.[1] ?? "";
|
|
542
|
-
const requiredPhrases = [
|
|
543
|
-
"prompt packet",
|
|
544
|
-
"Boundary Policy",
|
|
545
|
-
"Effective Boundary State",
|
|
546
|
-
"hard constraints",
|
|
547
|
-
"Do not modify repository files",
|
|
548
|
-
"insufficient access or insufficient evidence",
|
|
549
|
-
];
|
|
550
|
-
for (const phrase of requiredPhrases) {
|
|
551
|
-
assertIncludes(template, phrase, `required phrase: "${phrase}"`);
|
|
552
|
-
}
|
|
553
|
-
});
|
|
554
|
-
it("E-4: buildAgentPrompt replaces all placeholders", () => {
|
|
555
|
-
// Import and call the actual function
|
|
556
|
-
// Since buildAgentPrompt is not exported, verify via template regex
|
|
557
|
-
const templateMatch = coordinatorSource.match(/const AGENT_PROMPT_TEMPLATE = `([\s\S]*?)`;/);
|
|
558
|
-
const template = templateMatch?.[1] ?? "";
|
|
559
|
-
// All placeholders should be {unit_id}, {unit_kind}, {packet_path}, {output_path}
|
|
560
|
-
const placeholders = template.match(/\{[a-z_]+\}/g) ?? [];
|
|
561
|
-
const uniquePlaceholders = [...new Set(placeholders)];
|
|
562
|
-
const expected = new Set(["{unit_id}", "{unit_kind}", "{packet_path}", "{output_path}"]);
|
|
563
|
-
for (const placeholder of uniquePlaceholders) {
|
|
564
|
-
assert(expected.has(placeholder), `unexpected placeholder: ${placeholder}`);
|
|
565
|
-
}
|
|
566
|
-
for (const exp of expected) {
|
|
567
|
-
assert(uniquePlaceholders.includes(exp), `missing expected placeholder: ${exp}`);
|
|
568
|
-
}
|
|
569
|
-
});
|
|
570
|
-
});
|
|
571
|
-
// ---------------------------------------------------------------------------
|
|
572
|
-
// F. process.md ToolSearch instruction
|
|
573
|
-
// ---------------------------------------------------------------------------
|
|
574
|
-
describe("F. process.md ToolSearch", () => {
|
|
575
|
-
const processContent = fs.readFileSync(path.join(process.cwd(), "process.md"), "utf8");
|
|
576
|
-
it("F-1: ToolSearch instruction exists before Team Creation", () => {
|
|
577
|
-
const toolSearchPos = processContent.indexOf('ToolSearch("select:TeamCreate,SendMessage,TeamDelete")');
|
|
578
|
-
const teamCreationPos = processContent.indexOf("#### Team Creation");
|
|
579
|
-
assert(toolSearchPos !== -1, "ToolSearch instruction found");
|
|
580
|
-
assert(teamCreationPos !== -1, "Team Creation section found");
|
|
581
|
-
assert(toolSearchPos < teamCreationPos, "ToolSearch appears before Team Creation");
|
|
582
|
-
});
|
|
583
|
-
it("F-2: ToolSearch section marked as mandatory", () => {
|
|
584
|
-
assertIncludes(processContent, "Tool Availability Check (mandatory", "section marked mandatory");
|
|
585
|
-
});
|
|
586
|
-
it("F-3: deferred tools explanation present", () => {
|
|
587
|
-
assertIncludes(processContent, "deferred tools", "deferred tools concept explained");
|
|
588
|
-
});
|
|
589
|
-
it("F-4: fallback instruction on ToolSearch failure", () => {
|
|
590
|
-
// Find the ToolSearch section
|
|
591
|
-
const sectionStart = processContent.indexOf("#### Tool Availability Check");
|
|
592
|
-
const sectionEnd = processContent.indexOf("#### Team Creation");
|
|
593
|
-
const section = processContent.slice(sectionStart, sectionEnd);
|
|
594
|
-
assertIncludes(section, "Fallback Rules", "fallback instruction on ToolSearch failure");
|
|
595
|
-
});
|
|
596
|
-
it("F-5: once-per-session note present", () => {
|
|
597
|
-
assertIncludes(processContent, "once per conversation session", "once-per-session guidance");
|
|
598
|
-
});
|
|
599
|
-
it("F-6: ToolSearch targets all three team tools", () => {
|
|
600
|
-
const toolSearchLine = processContent.match(/ToolSearch\("select:([^"]+)"\)/);
|
|
601
|
-
assert(toolSearchLine !== null, "ToolSearch call found");
|
|
602
|
-
const tools = (toolSearchLine?.[1] ?? "").split(",");
|
|
603
|
-
assert(tools.includes("TeamCreate"), "TeamCreate in ToolSearch");
|
|
604
|
-
assert(tools.includes("SendMessage"), "SendMessage in ToolSearch");
|
|
605
|
-
assert(tools.includes("TeamDelete"), "TeamDelete in ToolSearch");
|
|
606
|
-
});
|
|
607
|
-
});
|
|
608
|
-
// ---------------------------------------------------------------------------
|
|
609
|
-
// Cleanup
|
|
610
|
-
// ---------------------------------------------------------------------------
|
|
611
|
-
afterAll(() => {
|
|
612
|
-
for (const dir of cleanupDirs) {
|
|
613
|
-
rmDir(dir);
|
|
614
|
-
}
|
|
615
|
-
});
|