principles-disciple 1.8.0 → 1.8.2
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/ADVANCED_CONFIG_ZH.md +97 -0
- package/AGENT_INSTALL.md +173 -0
- package/AGENT_INSTALL_EN.md +173 -0
- package/INSTALL.md +256 -0
- package/SKILL.md +63 -0
- package/docs/COMMAND_REFERENCE.md +76 -0
- package/docs/COMMAND_REFERENCE_EN.md +79 -0
- package/esbuild.config.js +75 -0
- package/openclaw.plugin.json +6 -1
- package/package.json +13 -15
- package/scripts/build-web.mjs +46 -0
- package/scripts/install-dependencies.cjs +47 -0
- package/scripts/sync-plugin.mjs +802 -0
- package/scripts/verify-build.mjs +109 -0
- package/src/agents/nocturnal-dreamer.md +152 -0
- package/src/agents/nocturnal-philosopher.md +138 -0
- package/src/agents/nocturnal-reflector.md +126 -0
- package/src/agents/nocturnal-scribe.md +164 -0
- package/src/commands/capabilities.ts +85 -0
- package/{dist/commands/context.js → src/commands/context.ts} +78 -38
- package/src/commands/evolution-status.ts +146 -0
- package/src/commands/export.ts +111 -0
- package/src/commands/focus.ts +533 -0
- package/src/commands/nocturnal-review.ts +311 -0
- package/src/commands/nocturnal-rollout.ts +763 -0
- package/src/commands/nocturnal-train.ts +1002 -0
- package/{dist/commands/pain.js → src/commands/pain.ts} +68 -49
- package/src/commands/principle-rollback.ts +27 -0
- package/{dist/commands/rollback.js → src/commands/rollback.ts} +44 -12
- package/src/commands/samples.ts +60 -0
- package/src/commands/strategy.ts +38 -0
- package/{dist/commands/thinking-os.js → src/commands/thinking-os.ts} +59 -36
- package/src/commands/workflow-debug.ts +128 -0
- package/{dist/config/defaults/runtime.js → src/config/defaults/runtime.ts} +12 -5
- package/src/config/errors.ts +163 -0
- package/{dist/config/index.d.ts → src/config/index.ts} +2 -1
- package/src/constants/diagnostician.ts +66 -0
- package/src/constants/tools.ts +62 -0
- package/src/core/adaptive-thresholds.ts +476 -0
- package/{dist/core/config-service.js → src/core/config-service.ts} +7 -4
- package/{dist/core/config.js → src/core/config.ts} +158 -46
- package/src/core/control-ui-db.ts +435 -0
- package/{dist/core/detection-funnel.js → src/core/detection-funnel.ts} +36 -21
- package/{dist/core/detection-service.js → src/core/detection-service.ts} +7 -4
- package/{dist/core/dictionary-service.js → src/core/dictionary-service.ts} +7 -4
- package/{dist/core/dictionary.js → src/core/dictionary.ts} +57 -34
- package/src/core/empathy-keyword-matcher.ts +327 -0
- package/src/core/empathy-types.ts +218 -0
- package/src/core/event-log.ts +544 -0
- package/src/core/evolution-engine.ts +612 -0
- package/src/core/evolution-logger.ts +353 -0
- package/src/core/evolution-migration.ts +77 -0
- package/src/core/evolution-reducer.ts +731 -0
- package/src/core/evolution-types.ts +456 -0
- package/src/core/external-training-contract.ts +527 -0
- package/src/core/focus-history.ts +1458 -0
- package/src/core/hygiene/tracker.ts +117 -0
- package/{dist/core/init.js → src/core/init.ts} +39 -26
- package/src/core/local-worker-routing.ts +617 -0
- package/{dist/core/migration.js → src/core/migration.ts} +18 -11
- package/src/core/model-deployment-registry.ts +722 -0
- package/src/core/model-training-registry.ts +813 -0
- package/src/core/nocturnal-arbiter.ts +706 -0
- package/src/core/nocturnal-candidate-scoring.ts +392 -0
- package/src/core/nocturnal-compliance.ts +1075 -0
- package/src/core/nocturnal-dataset.ts +668 -0
- package/src/core/nocturnal-executability.ts +428 -0
- package/src/core/nocturnal-export.ts +390 -0
- package/{dist/core/nocturnal-paths.js → src/core/nocturnal-paths.ts} +49 -23
- package/src/core/nocturnal-trajectory-extractor.ts +484 -0
- package/src/core/nocturnal-trinity.ts +1384 -0
- package/src/core/pain.ts +122 -0
- package/{dist/core/path-resolver.js → src/core/path-resolver.ts} +157 -36
- package/{dist/core/paths.js → src/core/paths.ts} +13 -4
- package/src/core/principle-training-state.ts +450 -0
- package/src/core/profile.ts +226 -0
- package/src/core/promotion-gate.ts +822 -0
- package/{dist/core/risk-calculator.js → src/core/risk-calculator.ts} +42 -16
- package/{dist/core/session-tracker.js → src/core/session-tracker.ts} +185 -63
- package/src/core/shadow-observation-registry.ts +534 -0
- package/{dist/core/system-logger.js → src/core/system-logger.ts} +9 -5
- package/src/core/thinking-models.ts +217 -0
- package/src/core/training-program.ts +630 -0
- package/src/core/trajectory-types.ts +243 -0
- package/src/core/trajectory.ts +1673 -0
- package/{dist/core/workspace-context.js → src/core/workspace-context.ts} +57 -32
- package/src/hooks/bash-risk.ts +171 -0
- package/src/hooks/edit-verification.ts +295 -0
- package/src/hooks/gate-block-helper.ts +160 -0
- package/src/hooks/gate.ts +210 -0
- package/src/hooks/gfi-gate.ts +177 -0
- package/src/hooks/lifecycle.ts +326 -0
- package/{dist/hooks/llm.js → src/hooks/llm.ts} +166 -139
- package/src/hooks/message-sanitize.ts +45 -0
- package/src/hooks/pain.ts +384 -0
- package/src/hooks/progressive-trust-gate.ts +174 -0
- package/src/hooks/prompt.ts +920 -0
- package/src/hooks/subagent.ts +207 -0
- package/src/hooks/thinking-checkpoint.ts +73 -0
- package/src/hooks/trajectory-collector.ts +290 -0
- package/src/http/principles-console-route.ts +716 -0
- package/src/i18n/commands.ts +117 -0
- package/src/index.ts +694 -0
- package/src/service/central-database.ts +831 -0
- package/src/service/control-ui-query-service.ts +888 -0
- package/src/service/evolution-query-service.ts +405 -0
- package/src/service/evolution-worker.ts +1646 -0
- package/src/service/health-query-service.ts +836 -0
- package/{dist/service/nocturnal-runtime.js → src/service/nocturnal-runtime.ts} +263 -36
- package/src/service/nocturnal-service.ts +1015 -0
- package/src/service/nocturnal-target-selector.ts +532 -0
- package/src/service/phase3-input-filter.ts +237 -0
- package/src/service/runtime-summary-service.ts +757 -0
- package/src/service/subagent-workflow/deep-reflect-workflow-manager.ts +513 -0
- package/src/service/subagent-workflow/empathy-observer-workflow-manager.ts +603 -0
- package/src/service/subagent-workflow/index.ts +51 -0
- package/src/service/subagent-workflow/nocturnal-workflow-manager.ts +856 -0
- package/src/service/subagent-workflow/runtime-direct-driver.ts +166 -0
- package/src/service/subagent-workflow/types.ts +378 -0
- package/src/service/subagent-workflow/workflow-store.ts +328 -0
- package/src/service/trajectory-service.ts +15 -0
- package/{dist/tools/critique-prompt.js → src/tools/critique-prompt.ts} +25 -8
- package/src/tools/deep-reflect.ts +349 -0
- package/{dist/tools/model-index.js → src/tools/model-index.ts} +33 -17
- package/src/types/event-types.ts +453 -0
- package/src/types/hygiene-types.ts +31 -0
- package/src/types/principle-tree-schema.ts +244 -0
- package/src/types/runtime-summary.ts +49 -0
- package/src/types.ts +74 -0
- package/src/utils/file-lock.ts +391 -0
- package/{dist/utils/glob-match.js → src/utils/glob-match.ts} +21 -20
- package/{dist/utils/hashing.js → src/utils/hashing.ts} +6 -4
- package/src/utils/io.ts +110 -0
- package/{dist/utils/nlp.js → src/utils/nlp.ts} +19 -12
- package/{dist/utils/plugin-logger.js → src/utils/plugin-logger.ts} +33 -8
- package/src/utils/subagent-probe.ts +94 -0
- package/templates/langs/zh/skills/pd-diagnostician/SKILL.md +70 -1
- package/templates/pain_settings.json +2 -1
- package/tests/README.md +120 -0
- package/tests/build-artifacts.test.ts +111 -0
- package/tests/commands/evolution-status.test.ts +222 -0
- package/tests/commands/evolver.test.ts +22 -0
- package/tests/commands/export.test.ts +78 -0
- package/tests/commands/nocturnal-review.test.ts +448 -0
- package/tests/commands/nocturnal-train.test.ts +97 -0
- package/tests/commands/pain.test.ts +108 -0
- package/tests/commands/samples.test.ts +65 -0
- package/tests/commands/strategy.test.ts +34 -0
- package/tests/commands/thinking-os.test.ts +88 -0
- package/tests/core/adaptive-thresholds.test.ts +261 -0
- package/tests/core/config-service.test.ts +89 -0
- package/tests/core/config.test.ts +90 -0
- package/tests/core/control-ui-db.test.ts +75 -0
- package/tests/core/core-template-guidance.test.ts +21 -0
- package/tests/core/detection-funnel.test.ts +63 -0
- package/tests/core/detection-service.test.ts +50 -0
- package/tests/core/dictionary-service.test.ts +116 -0
- package/tests/core/dictionary.test.ts +168 -0
- package/tests/core/empathy-keyword-matcher.test.ts +209 -0
- package/tests/core/event-log.test.ts +181 -0
- package/tests/core/evolution-e2e.test.ts +58 -0
- package/tests/core/evolution-engine-gate-integration.test.ts +543 -0
- package/tests/core/evolution-engine.test.ts +562 -0
- package/tests/core/evolution-logger.test.ts +148 -0
- package/tests/core/evolution-migration.test.ts +50 -0
- package/tests/core/evolution-paths.test.ts +21 -0
- package/tests/core/evolution-reducer.detector-metadata.test.ts +602 -0
- package/tests/core/evolution-reducer.test.ts +180 -0
- package/tests/core/evolution-types-loop.test.ts +48 -0
- package/tests/core/evolution-user-stories.e2e.test.ts +249 -0
- package/tests/core/external-training-contract.test.ts +463 -0
- package/tests/core/focus-history.test.ts +682 -0
- package/tests/core/init-flatten.test.ts +69 -0
- package/tests/core/init-refactor.test.ts +87 -0
- package/tests/core/init-v1.3.test.ts +46 -0
- package/tests/core/init.test.ts +190 -0
- package/tests/core/local-worker-routing.test.ts +757 -0
- package/tests/core/migration.test.ts +84 -0
- package/tests/core/model-deployment-registry.test.ts +845 -0
- package/tests/core/model-training-registry.test.ts +889 -0
- package/tests/core/nocturnal-arbiter.test.ts +494 -0
- package/tests/core/nocturnal-candidate-scoring.test.ts +400 -0
- package/tests/core/nocturnal-compliance.test.ts +646 -0
- package/tests/core/nocturnal-dataset.test.ts +892 -0
- package/tests/core/nocturnal-executability.test.ts +357 -0
- package/tests/core/nocturnal-export.test.ts +462 -0
- package/tests/core/nocturnal-reviewed-subset-comparison.test.ts +428 -0
- package/tests/core/nocturnal-trajectory-extractor.test.ts +634 -0
- package/tests/core/nocturnal-trinity.test.ts +953 -0
- package/tests/core/pain.test.ts +33 -0
- package/tests/core/path-resolver.test.ts +57 -0
- package/tests/core/paths-refactor.test.ts +42 -0
- package/tests/core/phase7-rollout-integration.test.ts +477 -0
- package/tests/core/principle-training-state.test.ts +712 -0
- package/tests/core/profile.test.ts +56 -0
- package/tests/core/promotion-gate.test.ts +556 -0
- package/tests/core/risk-calculator.test.ts +168 -0
- package/tests/core/session-tracker.test.ts +191 -0
- package/tests/core/training-program.test.ts +472 -0
- package/tests/core/trajectory.test.ts +265 -0
- package/tests/core/workspace-context-factory.test.ts +18 -0
- package/tests/core/workspace-context.test.ts +134 -0
- package/tests/fixtures/nocturnal-reviewed-subset.json +183 -0
- package/tests/fixtures/production-compatibility.test.ts +147 -0
- package/tests/fixtures/production-mock-generator.ts +282 -0
- package/tests/hooks/bash-risk-integration.test.ts +137 -0
- package/tests/hooks/bash-risk.test.ts +81 -0
- package/tests/hooks/edit-verification.test.ts +678 -0
- package/tests/hooks/gate-edit-verification-p1.test.ts +632 -0
- package/tests/hooks/gate-edit-verification.test.ts +435 -0
- package/tests/hooks/gate-pipeline-integration.test.ts +404 -0
- package/tests/hooks/gate.test.ts +271 -0
- package/tests/hooks/gfi-gate-unit.test.ts +422 -0
- package/tests/hooks/gfi-gate.test.ts +669 -0
- package/tests/hooks/lifecycle.test.ts +248 -0
- package/tests/hooks/llm.test.ts +308 -0
- package/tests/hooks/message-sanitize.test.ts +36 -0
- package/tests/hooks/pain.test.ts +141 -0
- package/tests/hooks/progressive-trust-gate.test.ts +277 -0
- package/tests/hooks/prompt.test.ts +1411 -0
- package/tests/hooks/subagent.test.ts +467 -0
- package/tests/hooks/thinking-gate.test.ts +313 -0
- package/tests/http/principles-console-route.test.ts +140 -0
- package/tests/hygiene-tracker.test.ts +77 -0
- package/tests/index.integration.test.ts +179 -0
- package/tests/index.shadow-routing.integration.test.ts +140 -0
- package/tests/index.test.ts +9 -0
- package/tests/integration/empathy-workflow-integration.test.ts +627 -0
- package/tests/service/control-ui-query-service.test.ts +121 -0
- package/tests/service/empathy-observer-workflow-manager.test.ts +176 -0
- package/tests/service/evolution-worker.test.ts +585 -0
- package/tests/service/nocturnal-runtime.test.ts +470 -0
- package/tests/service/nocturnal-service.test.ts +577 -0
- package/tests/service/nocturnal-target-selector.test.ts +615 -0
- package/tests/service/nocturnal-workflow-manager.test.ts +439 -0
- package/tests/service/phase3-input-filter.test.ts +289 -0
- package/tests/service/runtime-summary-service.test.ts +919 -0
- package/tests/task-compliance.test.ts +166 -0
- package/tests/test-utils.ts +48 -0
- package/tests/tools/critique-prompt.test.ts +260 -0
- package/tests/tools/deep-reflect.test.ts +232 -0
- package/tests/tools/model-index.test.ts +246 -0
- package/tests/ui/app.test.tsx +114 -0
- package/tests/utils/file-lock.test.ts +407 -0
- package/tests/utils/hashing.test.ts +32 -0
- package/tests/utils/io.test.ts +39 -0
- package/tests/utils/nlp.test.ts +53 -0
- package/tests/utils/plugin-logger.test.ts +156 -0
- package/tsconfig.json +16 -0
- package/tsconfig.tsbuildinfo +1 -0
- package/ui/src/App.tsx +45 -0
- package/ui/src/api.ts +216 -0
- package/ui/src/charts.tsx +586 -0
- package/ui/src/components/ErrorState.tsx +6 -0
- package/ui/src/components/Loading.tsx +13 -0
- package/ui/src/components/ProtectedRoute.tsx +12 -0
- package/ui/src/components/Shell.tsx +91 -0
- package/ui/src/components/WorkspaceConfig.tsx +146 -0
- package/ui/src/components/index.ts +5 -0
- package/ui/src/context/auth.tsx +80 -0
- package/ui/src/context/theme.tsx +66 -0
- package/ui/src/hooks/useAutoRefresh.ts +39 -0
- package/ui/src/i18n/ui.ts +363 -0
- package/ui/src/main.tsx +16 -0
- package/ui/src/pages/EvolutionPage.tsx +352 -0
- package/ui/src/pages/FeedbackPage.tsx +140 -0
- package/ui/src/pages/GateMonitorPage.tsx +136 -0
- package/ui/src/pages/LoginPage.tsx +88 -0
- package/ui/src/pages/OverviewPage.tsx +238 -0
- package/ui/src/pages/SamplesPage.tsx +174 -0
- package/ui/src/pages/ThinkingModelsPage.tsx +127 -0
- package/ui/src/styles.css +1661 -0
- package/ui/src/types.ts +368 -0
- package/ui/src/utils/format.ts +15 -0
- package/vitest.config.ts +23 -0
- package/dist/commands/capabilities.d.ts +0 -3
- package/dist/commands/capabilities.js +0 -73
- package/dist/commands/context.d.ts +0 -5
- package/dist/commands/evolution-status.d.ts +0 -4
- package/dist/commands/evolution-status.js +0 -117
- package/dist/commands/evolver.d.ts +0 -9
- package/dist/commands/evolver.js +0 -26
- package/dist/commands/export.d.ts +0 -2
- package/dist/commands/export.js +0 -98
- package/dist/commands/focus.d.ts +0 -14
- package/dist/commands/focus.js +0 -457
- package/dist/commands/nocturnal-review.d.ts +0 -24
- package/dist/commands/nocturnal-review.js +0 -265
- package/dist/commands/nocturnal-rollout.d.ts +0 -27
- package/dist/commands/nocturnal-rollout.js +0 -671
- package/dist/commands/nocturnal-train.d.ts +0 -25
- package/dist/commands/nocturnal-train.js +0 -919
- package/dist/commands/pain.d.ts +0 -5
- package/dist/commands/principle-rollback.d.ts +0 -4
- package/dist/commands/principle-rollback.js +0 -22
- package/dist/commands/rollback.d.ts +0 -19
- package/dist/commands/samples.d.ts +0 -2
- package/dist/commands/samples.js +0 -55
- package/dist/commands/strategy.d.ts +0 -3
- package/dist/commands/strategy.js +0 -29
- package/dist/commands/thinking-os.d.ts +0 -2
- package/dist/config/defaults/runtime.d.ts +0 -40
- package/dist/config/errors.d.ts +0 -84
- package/dist/config/errors.js +0 -94
- package/dist/config/index.js +0 -7
- package/dist/constants/diagnostician.d.ts +0 -12
- package/dist/constants/diagnostician.js +0 -56
- package/dist/constants/tools.d.ts +0 -17
- package/dist/constants/tools.js +0 -54
- package/dist/core/adaptive-thresholds.d.ts +0 -186
- package/dist/core/adaptive-thresholds.js +0 -300
- package/dist/core/config-service.d.ts +0 -15
- package/dist/core/config.d.ts +0 -127
- package/dist/core/control-ui-db.d.ts +0 -95
- package/dist/core/control-ui-db.js +0 -292
- package/dist/core/detection-funnel.d.ts +0 -33
- package/dist/core/detection-service.d.ts +0 -15
- package/dist/core/dictionary-service.d.ts +0 -15
- package/dist/core/dictionary.d.ts +0 -38
- package/dist/core/event-log.d.ts +0 -82
- package/dist/core/event-log.js +0 -463
- package/dist/core/evolution-engine.d.ts +0 -118
- package/dist/core/evolution-engine.js +0 -464
- package/dist/core/evolution-logger.d.ts +0 -137
- package/dist/core/evolution-logger.js +0 -256
- package/dist/core/evolution-migration.d.ts +0 -5
- package/dist/core/evolution-migration.js +0 -65
- package/dist/core/evolution-reducer.d.ts +0 -98
- package/dist/core/evolution-reducer.js +0 -465
- package/dist/core/evolution-types.d.ts +0 -287
- package/dist/core/evolution-types.js +0 -78
- package/dist/core/external-training-contract.d.ts +0 -276
- package/dist/core/external-training-contract.js +0 -269
- package/dist/core/focus-history.d.ts +0 -210
- package/dist/core/focus-history.js +0 -1185
- package/dist/core/hygiene/tracker.d.ts +0 -22
- package/dist/core/hygiene/tracker.js +0 -106
- package/dist/core/init.d.ts +0 -12
- package/dist/core/local-worker-routing.d.ts +0 -175
- package/dist/core/local-worker-routing.js +0 -525
- package/dist/core/migration.d.ts +0 -6
- package/dist/core/model-deployment-registry.d.ts +0 -218
- package/dist/core/model-deployment-registry.js +0 -503
- package/dist/core/model-training-registry.d.ts +0 -295
- package/dist/core/model-training-registry.js +0 -475
- package/dist/core/nocturnal-arbiter.d.ts +0 -159
- package/dist/core/nocturnal-arbiter.js +0 -534
- package/dist/core/nocturnal-candidate-scoring.d.ts +0 -137
- package/dist/core/nocturnal-candidate-scoring.js +0 -266
- package/dist/core/nocturnal-compliance.d.ts +0 -175
- package/dist/core/nocturnal-compliance.js +0 -824
- package/dist/core/nocturnal-dataset.d.ts +0 -224
- package/dist/core/nocturnal-dataset.js +0 -443
- package/dist/core/nocturnal-executability.d.ts +0 -85
- package/dist/core/nocturnal-executability.js +0 -331
- package/dist/core/nocturnal-export.d.ts +0 -124
- package/dist/core/nocturnal-export.js +0 -275
- package/dist/core/nocturnal-paths.d.ts +0 -124
- package/dist/core/nocturnal-trajectory-extractor.d.ts +0 -242
- package/dist/core/nocturnal-trajectory-extractor.js +0 -307
- package/dist/core/nocturnal-trinity.d.ts +0 -311
- package/dist/core/nocturnal-trinity.js +0 -880
- package/dist/core/pain.d.ts +0 -4
- package/dist/core/pain.js +0 -70
- package/dist/core/path-resolver.d.ts +0 -46
- package/dist/core/paths.d.ts +0 -65
- package/dist/core/principle-training-state.d.ts +0 -121
- package/dist/core/principle-training-state.js +0 -321
- package/dist/core/profile.d.ts +0 -62
- package/dist/core/profile.js +0 -210
- package/dist/core/promotion-gate.d.ts +0 -238
- package/dist/core/promotion-gate.js +0 -529
- package/dist/core/risk-calculator.d.ts +0 -22
- package/dist/core/session-tracker.d.ts +0 -99
- package/dist/core/shadow-observation-registry.d.ts +0 -217
- package/dist/core/shadow-observation-registry.js +0 -308
- package/dist/core/system-logger.d.ts +0 -8
- package/dist/core/thinking-models.d.ts +0 -38
- package/dist/core/thinking-models.js +0 -170
- package/dist/core/training-program.d.ts +0 -233
- package/dist/core/training-program.js +0 -433
- package/dist/core/trajectory.d.ts +0 -411
- package/dist/core/trajectory.js +0 -1307
- package/dist/core/workspace-context.d.ts +0 -71
- package/dist/hooks/bash-risk.d.ts +0 -57
- package/dist/hooks/bash-risk.js +0 -137
- package/dist/hooks/edit-verification.d.ts +0 -62
- package/dist/hooks/edit-verification.js +0 -256
- package/dist/hooks/gate-block-helper.d.ts +0 -44
- package/dist/hooks/gate-block-helper.js +0 -119
- package/dist/hooks/gate.d.ts +0 -24
- package/dist/hooks/gate.js +0 -173
- package/dist/hooks/gfi-gate.d.ts +0 -40
- package/dist/hooks/gfi-gate.js +0 -113
- package/dist/hooks/lifecycle.d.ts +0 -5
- package/dist/hooks/lifecycle.js +0 -284
- package/dist/hooks/llm.d.ts +0 -12
- package/dist/hooks/message-sanitize.d.ts +0 -3
- package/dist/hooks/message-sanitize.js +0 -37
- package/dist/hooks/pain.d.ts +0 -5
- package/dist/hooks/pain.js +0 -301
- package/dist/hooks/progressive-trust-gate.d.ts +0 -51
- package/dist/hooks/progressive-trust-gate.js +0 -89
- package/dist/hooks/prompt.d.ts +0 -47
- package/dist/hooks/prompt.js +0 -884
- package/dist/hooks/subagent.d.ts +0 -10
- package/dist/hooks/subagent.js +0 -387
- package/dist/hooks/thinking-checkpoint.d.ts +0 -37
- package/dist/hooks/thinking-checkpoint.js +0 -51
- package/dist/hooks/trajectory-collector.d.ts +0 -32
- package/dist/hooks/trajectory-collector.js +0 -256
- package/dist/http/principles-console-route.d.ts +0 -9
- package/dist/http/principles-console-route.js +0 -567
- package/dist/i18n/commands.d.ts +0 -26
- package/dist/i18n/commands.js +0 -116
- package/dist/index.d.ts +0 -7
- package/dist/index.js +0 -581
- package/dist/service/central-database.d.ts +0 -104
- package/dist/service/central-database.js +0 -649
- package/dist/service/control-ui-query-service.d.ts +0 -221
- package/dist/service/control-ui-query-service.js +0 -543
- package/dist/service/empathy-observer-manager.d.ts +0 -52
- package/dist/service/empathy-observer-manager.js +0 -229
- package/dist/service/evolution-query-service.d.ts +0 -155
- package/dist/service/evolution-query-service.js +0 -258
- package/dist/service/evolution-worker.d.ts +0 -101
- package/dist/service/evolution-worker.js +0 -974
- package/dist/service/nocturnal-runtime.d.ts +0 -183
- package/dist/service/nocturnal-service.d.ts +0 -163
- package/dist/service/nocturnal-service.js +0 -787
- package/dist/service/nocturnal-target-selector.d.ts +0 -145
- package/dist/service/nocturnal-target-selector.js +0 -315
- package/dist/service/phase3-input-filter.d.ts +0 -73
- package/dist/service/phase3-input-filter.js +0 -172
- package/dist/service/runtime-summary-service.d.ts +0 -122
- package/dist/service/runtime-summary-service.js +0 -485
- package/dist/service/trajectory-service.d.ts +0 -2
- package/dist/service/trajectory-service.js +0 -15
- package/dist/tools/critique-prompt.d.ts +0 -14
- package/dist/tools/deep-reflect.d.ts +0 -39
- package/dist/tools/deep-reflect.js +0 -350
- package/dist/tools/model-index.d.ts +0 -9
- package/dist/types/event-types.d.ts +0 -306
- package/dist/types/event-types.js +0 -106
- package/dist/types/hygiene-types.d.ts +0 -20
- package/dist/types/hygiene-types.js +0 -12
- package/dist/types/runtime-summary.d.ts +0 -47
- package/dist/types/runtime-summary.js +0 -1
- package/dist/types.d.ts +0 -50
- package/dist/types.js +0 -22
- package/dist/utils/file-lock.d.ts +0 -71
- package/dist/utils/file-lock.js +0 -309
- package/dist/utils/glob-match.d.ts +0 -28
- package/dist/utils/hashing.d.ts +0 -9
- package/dist/utils/io.d.ts +0 -6
- package/dist/utils/io.js +0 -106
- package/dist/utils/nlp.d.ts +0 -9
- package/dist/utils/plugin-logger.d.ts +0 -39
- package/dist/utils/subagent-probe.d.ts +0 -34
- package/dist/utils/subagent-probe.js +0 -81
|
@@ -0,0 +1,953 @@
|
|
|
1
|
+
import { describe, it, expect, vi } from 'vitest';
|
|
2
|
+
import {
|
|
3
|
+
runTrinity,
|
|
4
|
+
runTrinityAsync,
|
|
5
|
+
validateDraftArtifact,
|
|
6
|
+
draftToArtifact,
|
|
7
|
+
DEFAULT_TRINITY_CONFIG,
|
|
8
|
+
type TrinityConfig,
|
|
9
|
+
type DreamerOutput,
|
|
10
|
+
type PhilosopherOutput,
|
|
11
|
+
type TrinityDraftArtifact,
|
|
12
|
+
type TrinityRuntimeAdapter,
|
|
13
|
+
} from '../../src/core/nocturnal-trinity.js';
|
|
14
|
+
import {
|
|
15
|
+
validateDreamerOutput,
|
|
16
|
+
validatePhilosopherOutput,
|
|
17
|
+
validateTrinityDraft,
|
|
18
|
+
} from '../../src/core/nocturnal-arbiter.js';
|
|
19
|
+
|
|
20
|
+
// ---------------------------------------------------------------------------
|
|
21
|
+
// Test Fixtures
|
|
22
|
+
// ---------------------------------------------------------------------------
|
|
23
|
+
|
|
24
|
+
function makeSnapshot(overrides: Partial<{
|
|
25
|
+
failureCount: number;
|
|
26
|
+
totalPainEvents: number;
|
|
27
|
+
totalGateBlocks: number;
|
|
28
|
+
}> = {}): {
|
|
29
|
+
sessionId: string;
|
|
30
|
+
stats: { failureCount: number; totalPainEvents: number; totalGateBlocks: number; totalAssistantTurns: number; totalToolCalls: number };
|
|
31
|
+
} {
|
|
32
|
+
return {
|
|
33
|
+
sessionId: 'session-test-123',
|
|
34
|
+
stats: {
|
|
35
|
+
failureCount: overrides.failureCount ?? 0,
|
|
36
|
+
totalPainEvents: overrides.totalPainEvents ?? 0,
|
|
37
|
+
totalGateBlocks: overrides.totalGateBlocks ?? 0,
|
|
38
|
+
totalAssistantTurns: 5,
|
|
39
|
+
totalToolCalls: 10,
|
|
40
|
+
},
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// ---------------------------------------------------------------------------
|
|
45
|
+
// Tests: validateDreamerOutput
|
|
46
|
+
// ---------------------------------------------------------------------------
|
|
47
|
+
|
|
48
|
+
describe('validateDreamerOutput', () => {
|
|
49
|
+
it('passes a valid Dreamer output with candidates', () => {
|
|
50
|
+
const output = {
|
|
51
|
+
valid: true,
|
|
52
|
+
candidates: [
|
|
53
|
+
{
|
|
54
|
+
candidateIndex: 0,
|
|
55
|
+
badDecision: 'Did something wrong',
|
|
56
|
+
betterDecision: 'Do it right',
|
|
57
|
+
rationale: 'Because the principle says so',
|
|
58
|
+
confidence: 0.9,
|
|
59
|
+
},
|
|
60
|
+
],
|
|
61
|
+
generatedAt: '2026-03-27T12:00:00.000Z',
|
|
62
|
+
};
|
|
63
|
+
const result = validateDreamerOutput(output);
|
|
64
|
+
expect(result.valid).toBe(true);
|
|
65
|
+
expect(result.failures).toHaveLength(0);
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
it('passes a valid Dreamer output with multiple candidates', () => {
|
|
69
|
+
const output = {
|
|
70
|
+
valid: true,
|
|
71
|
+
candidates: [
|
|
72
|
+
{
|
|
73
|
+
candidateIndex: 0,
|
|
74
|
+
badDecision: 'Did something wrong',
|
|
75
|
+
betterDecision: 'Do it right',
|
|
76
|
+
rationale: 'Because the principle says so',
|
|
77
|
+
confidence: 0.9,
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
candidateIndex: 1,
|
|
81
|
+
badDecision: 'Did another wrong thing',
|
|
82
|
+
betterDecision: 'Do it differently',
|
|
83
|
+
rationale: 'Alternative approach is better',
|
|
84
|
+
confidence: 0.8,
|
|
85
|
+
},
|
|
86
|
+
],
|
|
87
|
+
generatedAt: '2026-03-27T12:00:00.000Z',
|
|
88
|
+
};
|
|
89
|
+
const result = validateDreamerOutput(output);
|
|
90
|
+
expect(result.valid).toBe(true);
|
|
91
|
+
expect(result.failures).toHaveLength(0);
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
it('rejects Dreamer output marked invalid', () => {
|
|
95
|
+
const output = {
|
|
96
|
+
valid: false,
|
|
97
|
+
candidates: [],
|
|
98
|
+
reason: 'No signal found',
|
|
99
|
+
generatedAt: '2026-03-27T12:00:00.000Z',
|
|
100
|
+
};
|
|
101
|
+
const result = validateDreamerOutput(output);
|
|
102
|
+
expect(result.valid).toBe(false);
|
|
103
|
+
expect(result.failures.some(f => f.includes('marked invalid'))).toBe(true);
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
it('rejects Dreamer output marked invalid without reason', () => {
|
|
107
|
+
const output = {
|
|
108
|
+
valid: false,
|
|
109
|
+
candidates: [],
|
|
110
|
+
generatedAt: '2026-03-27T12:00:00.000Z',
|
|
111
|
+
};
|
|
112
|
+
const result = validateDreamerOutput(output);
|
|
113
|
+
expect(result.valid).toBe(false);
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
it('rejects Dreamer output without candidates array', () => {
|
|
117
|
+
const output = {
|
|
118
|
+
valid: true,
|
|
119
|
+
generatedAt: '2026-03-27T12:00:00.000Z',
|
|
120
|
+
};
|
|
121
|
+
const result = validateDreamerOutput(output);
|
|
122
|
+
expect(result.valid).toBe(false);
|
|
123
|
+
expect(result.failures.some(f => f.includes('candidates array'))).toBe(true);
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
it('rejects Dreamer candidate missing required fields', () => {
|
|
127
|
+
const output = {
|
|
128
|
+
valid: true,
|
|
129
|
+
candidates: [
|
|
130
|
+
{
|
|
131
|
+
candidateIndex: 0,
|
|
132
|
+
badDecision: 'Has badDecision but missing betterDecision',
|
|
133
|
+
// missing: betterDecision, rationale, confidence
|
|
134
|
+
},
|
|
135
|
+
],
|
|
136
|
+
generatedAt: '2026-03-27T12:00:00.000Z',
|
|
137
|
+
};
|
|
138
|
+
const result = validateDreamerOutput(output);
|
|
139
|
+
expect(result.valid).toBe(false);
|
|
140
|
+
expect(result.failures.some(f => f.includes('betterDecision'))).toBe(true);
|
|
141
|
+
expect(result.failures.some(f => f.includes('rationale'))).toBe(true);
|
|
142
|
+
expect(result.failures.some(f => f.includes('confidence'))).toBe(true);
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
it('rejects Dreamer candidate with invalid confidence (out of range)', () => {
|
|
146
|
+
const output = {
|
|
147
|
+
valid: true,
|
|
148
|
+
candidates: [
|
|
149
|
+
{
|
|
150
|
+
candidateIndex: 0,
|
|
151
|
+
badDecision: 'Wrong',
|
|
152
|
+
betterDecision: 'Right',
|
|
153
|
+
rationale: 'Because',
|
|
154
|
+
confidence: 1.5, // out of range
|
|
155
|
+
},
|
|
156
|
+
],
|
|
157
|
+
generatedAt: '2026-03-27T12:00:00.000Z',
|
|
158
|
+
};
|
|
159
|
+
const result = validateDreamerOutput(output);
|
|
160
|
+
expect(result.valid).toBe(false);
|
|
161
|
+
expect(result.failures.some(f => f.includes('confidence'))).toBe(true);
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
it('rejects Dreamer candidate with duplicate candidateIndex', () => {
|
|
165
|
+
const output = {
|
|
166
|
+
valid: true,
|
|
167
|
+
candidates: [
|
|
168
|
+
{
|
|
169
|
+
candidateIndex: 0,
|
|
170
|
+
badDecision: 'Wrong 1',
|
|
171
|
+
betterDecision: 'Right 1',
|
|
172
|
+
rationale: 'Because 1',
|
|
173
|
+
confidence: 0.9,
|
|
174
|
+
},
|
|
175
|
+
{
|
|
176
|
+
candidateIndex: 0, // duplicate
|
|
177
|
+
badDecision: 'Wrong 2',
|
|
178
|
+
betterDecision: 'Right 2',
|
|
179
|
+
rationale: 'Because 2',
|
|
180
|
+
confidence: 0.8,
|
|
181
|
+
},
|
|
182
|
+
],
|
|
183
|
+
generatedAt: '2026-03-27T12:00:00.000Z',
|
|
184
|
+
};
|
|
185
|
+
const result = validateDreamerOutput(output);
|
|
186
|
+
expect(result.valid).toBe(false);
|
|
187
|
+
expect(result.failures.some(f => f.includes('duplicate'))).toBe(true);
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
it('rejects Dreamer candidate with identical badDecision and betterDecision', () => {
|
|
191
|
+
const output = {
|
|
192
|
+
valid: true,
|
|
193
|
+
candidates: [
|
|
194
|
+
{
|
|
195
|
+
candidateIndex: 0,
|
|
196
|
+
badDecision: 'Do the same thing',
|
|
197
|
+
betterDecision: 'Do the same thing', // identical
|
|
198
|
+
rationale: 'Because it is correct',
|
|
199
|
+
confidence: 0.9,
|
|
200
|
+
},
|
|
201
|
+
],
|
|
202
|
+
generatedAt: '2026-03-27T12:00:00.000Z',
|
|
203
|
+
};
|
|
204
|
+
const result = validateDreamerOutput(output);
|
|
205
|
+
expect(result.valid).toBe(false);
|
|
206
|
+
expect(result.failures.some(f => f.includes('identical'))).toBe(true);
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
it('rejects Dreamer output missing generatedAt', () => {
|
|
210
|
+
const output = {
|
|
211
|
+
valid: true,
|
|
212
|
+
candidates: [
|
|
213
|
+
{
|
|
214
|
+
candidateIndex: 0,
|
|
215
|
+
badDecision: 'Wrong',
|
|
216
|
+
betterDecision: 'Right',
|
|
217
|
+
rationale: 'Because',
|
|
218
|
+
confidence: 0.9,
|
|
219
|
+
},
|
|
220
|
+
],
|
|
221
|
+
// missing generatedAt
|
|
222
|
+
};
|
|
223
|
+
const result = validateDreamerOutput(output);
|
|
224
|
+
expect(result.valid).toBe(false);
|
|
225
|
+
expect(result.failures.some(f => f.includes('generatedAt'))).toBe(true);
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
it('rejects non-object input', () => {
|
|
229
|
+
const result = validateDreamerOutput(null);
|
|
230
|
+
expect(result.valid).toBe(false);
|
|
231
|
+
});
|
|
232
|
+
|
|
233
|
+
it('rejects string input', () => {
|
|
234
|
+
const result = validateDreamerOutput('not an object');
|
|
235
|
+
expect(result.valid).toBe(false);
|
|
236
|
+
});
|
|
237
|
+
});
|
|
238
|
+
|
|
239
|
+
// ---------------------------------------------------------------------------
|
|
240
|
+
// Tests: validatePhilosopherOutput
|
|
241
|
+
// ---------------------------------------------------------------------------
|
|
242
|
+
|
|
243
|
+
describe('validatePhilosopherOutput', () => {
|
|
244
|
+
it('passes a valid Philosopher output', () => {
|
|
245
|
+
const output = {
|
|
246
|
+
valid: true,
|
|
247
|
+
judgments: [
|
|
248
|
+
{
|
|
249
|
+
candidateIndex: 0,
|
|
250
|
+
critique: 'Strong alignment',
|
|
251
|
+
principleAligned: true,
|
|
252
|
+
score: 0.92,
|
|
253
|
+
rank: 1,
|
|
254
|
+
},
|
|
255
|
+
],
|
|
256
|
+
overallAssessment: 'Good candidate set',
|
|
257
|
+
generatedAt: '2026-03-27T12:00:00.000Z',
|
|
258
|
+
};
|
|
259
|
+
const result = validatePhilosopherOutput(output);
|
|
260
|
+
expect(result.valid).toBe(true);
|
|
261
|
+
expect(result.failures).toHaveLength(0);
|
|
262
|
+
});
|
|
263
|
+
|
|
264
|
+
it('rejects Philosopher output marked invalid', () => {
|
|
265
|
+
const output = {
|
|
266
|
+
valid: false,
|
|
267
|
+
judgments: [],
|
|
268
|
+
reason: 'No candidates to judge',
|
|
269
|
+
generatedAt: '2026-03-27T12:00:00.000Z',
|
|
270
|
+
};
|
|
271
|
+
const result = validatePhilosopherOutput(output);
|
|
272
|
+
expect(result.valid).toBe(false);
|
|
273
|
+
});
|
|
274
|
+
|
|
275
|
+
it('rejects Philosopher output without judgments array', () => {
|
|
276
|
+
const output = {
|
|
277
|
+
valid: true,
|
|
278
|
+
overallAssessment: 'Good',
|
|
279
|
+
generatedAt: '2026-03-27T12:00:00.000Z',
|
|
280
|
+
};
|
|
281
|
+
const result = validatePhilosopherOutput(output);
|
|
282
|
+
expect(result.valid).toBe(false);
|
|
283
|
+
expect(result.failures.some(f => f.includes('judgments array'))).toBe(true);
|
|
284
|
+
});
|
|
285
|
+
|
|
286
|
+
it('rejects Philosopher judgment missing required fields', () => {
|
|
287
|
+
const output = {
|
|
288
|
+
valid: true,
|
|
289
|
+
judgments: [
|
|
290
|
+
{
|
|
291
|
+
candidateIndex: 0,
|
|
292
|
+
// missing: critique, principleAligned, score, rank
|
|
293
|
+
},
|
|
294
|
+
],
|
|
295
|
+
overallAssessment: 'Good',
|
|
296
|
+
generatedAt: '2026-03-27T12:00:00.000Z',
|
|
297
|
+
};
|
|
298
|
+
const result = validatePhilosopherOutput(output);
|
|
299
|
+
expect(result.valid).toBe(false);
|
|
300
|
+
});
|
|
301
|
+
|
|
302
|
+
it('rejects Philosopher judgment with invalid score (out of range)', () => {
|
|
303
|
+
const output = {
|
|
304
|
+
valid: true,
|
|
305
|
+
judgments: [
|
|
306
|
+
{
|
|
307
|
+
candidateIndex: 0,
|
|
308
|
+
critique: 'Good',
|
|
309
|
+
principleAligned: true,
|
|
310
|
+
score: 1.5, // out of range
|
|
311
|
+
rank: 1,
|
|
312
|
+
},
|
|
313
|
+
],
|
|
314
|
+
overallAssessment: 'Good',
|
|
315
|
+
generatedAt: '2026-03-27T12:00:00.000Z',
|
|
316
|
+
};
|
|
317
|
+
const result = validatePhilosopherOutput(output);
|
|
318
|
+
expect(result.valid).toBe(false);
|
|
319
|
+
expect(result.failures.some(f => f.includes('score'))).toBe(true);
|
|
320
|
+
});
|
|
321
|
+
|
|
322
|
+
it('rejects Philosopher judgment with invalid rank (must be >= 1)', () => {
|
|
323
|
+
const output = {
|
|
324
|
+
valid: true,
|
|
325
|
+
judgments: [
|
|
326
|
+
{
|
|
327
|
+
candidateIndex: 0,
|
|
328
|
+
critique: 'Good',
|
|
329
|
+
principleAligned: true,
|
|
330
|
+
score: 0.9,
|
|
331
|
+
rank: 0, // invalid
|
|
332
|
+
},
|
|
333
|
+
],
|
|
334
|
+
overallAssessment: 'Good',
|
|
335
|
+
generatedAt: '2026-03-27T12:00:00.000Z',
|
|
336
|
+
};
|
|
337
|
+
const result = validatePhilosopherOutput(output);
|
|
338
|
+
expect(result.valid).toBe(false);
|
|
339
|
+
expect(result.failures.some(f => f.includes('rank'))).toBe(true);
|
|
340
|
+
});
|
|
341
|
+
|
|
342
|
+
it('rejects Philosopher output with non-sequential ranks', () => {
|
|
343
|
+
const output = {
|
|
344
|
+
valid: true,
|
|
345
|
+
judgments: [
|
|
346
|
+
{
|
|
347
|
+
candidateIndex: 0,
|
|
348
|
+
critique: 'Good',
|
|
349
|
+
principleAligned: true,
|
|
350
|
+
score: 0.9,
|
|
351
|
+
rank: 1,
|
|
352
|
+
},
|
|
353
|
+
{
|
|
354
|
+
candidateIndex: 1,
|
|
355
|
+
critique: 'Also good',
|
|
356
|
+
principleAligned: true,
|
|
357
|
+
score: 0.8,
|
|
358
|
+
rank: 3, // should be 2
|
|
359
|
+
},
|
|
360
|
+
],
|
|
361
|
+
overallAssessment: 'Good',
|
|
362
|
+
generatedAt: '2026-03-27T12:00:00.000Z',
|
|
363
|
+
};
|
|
364
|
+
const result = validatePhilosopherOutput(output);
|
|
365
|
+
expect(result.valid).toBe(false);
|
|
366
|
+
expect(result.failures.some(f => f.includes('sequential ranks'))).toBe(true);
|
|
367
|
+
});
|
|
368
|
+
|
|
369
|
+
it('rejects Philosopher output missing overallAssessment', () => {
|
|
370
|
+
const output = {
|
|
371
|
+
valid: true,
|
|
372
|
+
judgments: [
|
|
373
|
+
{
|
|
374
|
+
candidateIndex: 0,
|
|
375
|
+
critique: 'Good',
|
|
376
|
+
principleAligned: true,
|
|
377
|
+
score: 0.9,
|
|
378
|
+
rank: 1,
|
|
379
|
+
},
|
|
380
|
+
],
|
|
381
|
+
// missing overallAssessment
|
|
382
|
+
generatedAt: '2026-03-27T12:00:00.000Z',
|
|
383
|
+
};
|
|
384
|
+
const result = validatePhilosopherOutput(output);
|
|
385
|
+
expect(result.valid).toBe(false);
|
|
386
|
+
expect(result.failures.some(f => f.includes('overallAssessment'))).toBe(true);
|
|
387
|
+
});
|
|
388
|
+
});
|
|
389
|
+
|
|
390
|
+
// ---------------------------------------------------------------------------
|
|
391
|
+
// Tests: validateTrinityDraft
|
|
392
|
+
// ---------------------------------------------------------------------------
|
|
393
|
+
|
|
394
|
+
describe('validateTrinityDraft', () => {
|
|
395
|
+
function makeValidDraft(overrides: Record<string, unknown> = {}): Record<string, unknown> {
|
|
396
|
+
return {
|
|
397
|
+
selectedCandidateIndex: 0,
|
|
398
|
+
badDecision: 'Did something wrong',
|
|
399
|
+
betterDecision: 'Do it right',
|
|
400
|
+
rationale: 'Because the principle says so and this is the right approach',
|
|
401
|
+
sessionId: 'session-test-123',
|
|
402
|
+
principleId: 'T-01',
|
|
403
|
+
sourceSnapshotRef: 'snapshot-test-001',
|
|
404
|
+
telemetry: {
|
|
405
|
+
chainMode: 'trinity',
|
|
406
|
+
dreamerPassed: true,
|
|
407
|
+
philosopherPassed: true,
|
|
408
|
+
scribePassed: true,
|
|
409
|
+
candidateCount: 3,
|
|
410
|
+
selectedCandidateIndex: 0,
|
|
411
|
+
stageFailures: [],
|
|
412
|
+
},
|
|
413
|
+
...overrides,
|
|
414
|
+
};
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
it('passes a valid Trinity draft artifact', () => {
|
|
418
|
+
const draft = makeValidDraft();
|
|
419
|
+
const result = validateTrinityDraft(draft);
|
|
420
|
+
expect(result.valid).toBe(true);
|
|
421
|
+
expect(result.failures).toHaveLength(0);
|
|
422
|
+
});
|
|
423
|
+
|
|
424
|
+
it('rejects draft with missing badDecision', () => {
|
|
425
|
+
const draft = makeValidDraft();
|
|
426
|
+
delete draft.badDecision;
|
|
427
|
+
const result = validateTrinityDraft(draft);
|
|
428
|
+
expect(result.valid).toBe(false);
|
|
429
|
+
expect(result.failures.some(f => f.includes('badDecision'))).toBe(true);
|
|
430
|
+
});
|
|
431
|
+
|
|
432
|
+
it('rejects draft with empty badDecision', () => {
|
|
433
|
+
const draft = makeValidDraft({ badDecision: ' ' });
|
|
434
|
+
const result = validateTrinityDraft(draft);
|
|
435
|
+
expect(result.valid).toBe(false);
|
|
436
|
+
expect(result.failures.some(f => f.includes('badDecision'))).toBe(true);
|
|
437
|
+
});
|
|
438
|
+
|
|
439
|
+
it('rejects draft with short rationale (< 20 chars)', () => {
|
|
440
|
+
const draft = makeValidDraft({ rationale: 'Too short' });
|
|
441
|
+
const result = validateTrinityDraft(draft);
|
|
442
|
+
expect(result.valid).toBe(false);
|
|
443
|
+
expect(result.failures.some(f => f.includes('rationale'))).toBe(true);
|
|
444
|
+
});
|
|
445
|
+
|
|
446
|
+
it('rejects draft with identical badDecision and betterDecision', () => {
|
|
447
|
+
const draft = makeValidDraft({
|
|
448
|
+
badDecision: 'Same thing',
|
|
449
|
+
betterDecision: 'Same thing',
|
|
450
|
+
});
|
|
451
|
+
const result = validateTrinityDraft(draft);
|
|
452
|
+
expect(result.valid).toBe(false);
|
|
453
|
+
expect(result.failures.some(f => f.includes('identical'))).toBe(true);
|
|
454
|
+
});
|
|
455
|
+
|
|
456
|
+
it('rejects draft with invalid telemetry', () => {
|
|
457
|
+
const draft = makeValidDraft({ telemetry: null });
|
|
458
|
+
const result = validateTrinityDraft(draft);
|
|
459
|
+
expect(result.valid).toBe(false);
|
|
460
|
+
expect(result.failures.some(f => f.includes('telemetry'))).toBe(true);
|
|
461
|
+
});
|
|
462
|
+
|
|
463
|
+
it('rejects draft with invalid chainMode in telemetry', () => {
|
|
464
|
+
const draft = makeValidDraft({
|
|
465
|
+
telemetry: {
|
|
466
|
+
chainMode: 'invalid-mode', // must be 'trinity' or 'single-reflector'
|
|
467
|
+
dreamerPassed: true,
|
|
468
|
+
philosopherPassed: true,
|
|
469
|
+
scribePassed: true,
|
|
470
|
+
candidateCount: 3,
|
|
471
|
+
selectedCandidateIndex: 0,
|
|
472
|
+
stageFailures: [],
|
|
473
|
+
},
|
|
474
|
+
});
|
|
475
|
+
const result = validateTrinityDraft(draft);
|
|
476
|
+
expect(result.valid).toBe(false);
|
|
477
|
+
expect(result.failures.some(f => f.includes('chainMode'))).toBe(true);
|
|
478
|
+
});
|
|
479
|
+
});
|
|
480
|
+
|
|
481
|
+
// ---------------------------------------------------------------------------
|
|
482
|
+
// Tests: runTrinity — successful path
|
|
483
|
+
// ---------------------------------------------------------------------------
|
|
484
|
+
|
|
485
|
+
describe('runTrinity', () => {
|
|
486
|
+
it('produces a successful Trinity result with valid snapshot (failure signal)', () => {
|
|
487
|
+
const snapshot = makeSnapshot({ failureCount: 2 });
|
|
488
|
+
const config: TrinityConfig = {
|
|
489
|
+
useTrinity: true,
|
|
490
|
+
maxCandidates: 3,
|
|
491
|
+
useStubs: true, // Use stub implementations
|
|
492
|
+
};
|
|
493
|
+
|
|
494
|
+
const result = runTrinity({ snapshot, principleId: 'T-08', config });
|
|
495
|
+
|
|
496
|
+
expect(result.success).toBe(true);
|
|
497
|
+
expect(result.artifact).toBeDefined();
|
|
498
|
+
expect(result.telemetry.chainMode).toBe('trinity');
|
|
499
|
+
expect(result.telemetry.dreamerPassed).toBe(true);
|
|
500
|
+
expect(result.telemetry.philosopherPassed).toBe(true);
|
|
501
|
+
expect(result.telemetry.scribePassed).toBe(true);
|
|
502
|
+
expect(result.telemetry.candidateCount).toBeGreaterThan(0);
|
|
503
|
+
expect(result.telemetry.selectedCandidateIndex).toBeGreaterThanOrEqual(0);
|
|
504
|
+
expect(result.failures).toHaveLength(0);
|
|
505
|
+
expect(result.fallbackOccurred).toBe(false);
|
|
506
|
+
});
|
|
507
|
+
|
|
508
|
+
it('produces a successful Trinity result with pain signal', () => {
|
|
509
|
+
const snapshot = makeSnapshot({ totalPainEvents: 3 });
|
|
510
|
+
const config: TrinityConfig = {
|
|
511
|
+
useTrinity: true,
|
|
512
|
+
maxCandidates: 3,
|
|
513
|
+
useStubs: true,
|
|
514
|
+
};
|
|
515
|
+
|
|
516
|
+
const result = runTrinity({ snapshot, principleId: 'T-08', config });
|
|
517
|
+
|
|
518
|
+
expect(result.success).toBe(true);
|
|
519
|
+
expect(result.artifact).toBeDefined();
|
|
520
|
+
});
|
|
521
|
+
|
|
522
|
+
it('produces a successful Trinity result with gate block signal', () => {
|
|
523
|
+
const snapshot = makeSnapshot({ totalGateBlocks: 1 });
|
|
524
|
+
const config: TrinityConfig = {
|
|
525
|
+
useTrinity: true,
|
|
526
|
+
maxCandidates: 3,
|
|
527
|
+
useStubs: true,
|
|
528
|
+
};
|
|
529
|
+
|
|
530
|
+
const result = runTrinity({ snapshot, principleId: 'T-03', config });
|
|
531
|
+
|
|
532
|
+
expect(result.success).toBe(true);
|
|
533
|
+
expect(result.artifact).toBeDefined();
|
|
534
|
+
});
|
|
535
|
+
|
|
536
|
+
it('respects maxCandidates config', () => {
|
|
537
|
+
const snapshot = makeSnapshot({ failureCount: 5 });
|
|
538
|
+
const config: TrinityConfig = {
|
|
539
|
+
useTrinity: true,
|
|
540
|
+
maxCandidates: 2,
|
|
541
|
+
useStubs: true,
|
|
542
|
+
};
|
|
543
|
+
|
|
544
|
+
const result = runTrinity({ snapshot, principleId: 'T-08', config });
|
|
545
|
+
|
|
546
|
+
expect(result.success).toBe(true);
|
|
547
|
+
expect(result.telemetry.candidateCount).toBeLessThanOrEqual(2);
|
|
548
|
+
});
|
|
549
|
+
});
|
|
550
|
+
|
|
551
|
+
// ---------------------------------------------------------------------------
|
|
552
|
+
// Tests: runTrinity — failure paths
|
|
553
|
+
// ---------------------------------------------------------------------------
|
|
554
|
+
|
|
555
|
+
describe('runTrinity — failure paths', () => {
|
|
556
|
+
it('fails when snapshot has no signal and generates no candidates', () => {
|
|
557
|
+
// Snapshot with all zero stats - stub will fail to generate candidates
|
|
558
|
+
const snapshot = makeSnapshot({
|
|
559
|
+
failureCount: 0,
|
|
560
|
+
totalPainEvents: 0,
|
|
561
|
+
totalGateBlocks: 0,
|
|
562
|
+
});
|
|
563
|
+
const config: TrinityConfig = {
|
|
564
|
+
useTrinity: true,
|
|
565
|
+
maxCandidates: 3,
|
|
566
|
+
useStubs: true,
|
|
567
|
+
};
|
|
568
|
+
|
|
569
|
+
const result = runTrinity({ snapshot, principleId: 'T-08', config });
|
|
570
|
+
|
|
571
|
+
expect(result.success).toBe(false);
|
|
572
|
+
expect(result.failures.length).toBeGreaterThan(0);
|
|
573
|
+
expect(result.failures[0].stage).toBe('dreamer');
|
|
574
|
+
expect(result.telemetry.dreamerPassed).toBe(false);
|
|
575
|
+
});
|
|
576
|
+
});
|
|
577
|
+
|
|
578
|
+
// ---------------------------------------------------------------------------
|
|
579
|
+
// Tests: validateDraftArtifact
|
|
580
|
+
// ---------------------------------------------------------------------------
|
|
581
|
+
|
|
582
|
+
describe('validateDraftArtifact', () => {
|
|
583
|
+
function makeValidArtifact(): TrinityDraftArtifact {
|
|
584
|
+
return {
|
|
585
|
+
selectedCandidateIndex: 0,
|
|
586
|
+
badDecision: 'Did something wrong',
|
|
587
|
+
betterDecision: 'Do it right',
|
|
588
|
+
rationale: 'Because the principle says so and this is the correct approach',
|
|
589
|
+
sessionId: 'session-test-123',
|
|
590
|
+
principleId: 'T-01',
|
|
591
|
+
sourceSnapshotRef: 'snapshot-test-001',
|
|
592
|
+
telemetry: {
|
|
593
|
+
chainMode: 'trinity',
|
|
594
|
+
dreamerPassed: true,
|
|
595
|
+
philosopherPassed: true,
|
|
596
|
+
scribePassed: true,
|
|
597
|
+
candidateCount: 3,
|
|
598
|
+
selectedCandidateIndex: 0,
|
|
599
|
+
stageFailures: [],
|
|
600
|
+
},
|
|
601
|
+
};
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
it('passes a valid TrinityDraftArtifact', () => {
|
|
605
|
+
const artifact = makeValidArtifact();
|
|
606
|
+
const result = validateDraftArtifact(artifact);
|
|
607
|
+
expect(result.valid).toBe(true);
|
|
608
|
+
expect(result.failures).toHaveLength(0);
|
|
609
|
+
});
|
|
610
|
+
|
|
611
|
+
it('rejects artifact with missing badDecision', () => {
|
|
612
|
+
const artifact = makeValidArtifact();
|
|
613
|
+
delete (artifact as Record<string, unknown>).badDecision;
|
|
614
|
+
const result = validateDraftArtifact(artifact);
|
|
615
|
+
expect(result.valid).toBe(false);
|
|
616
|
+
});
|
|
617
|
+
|
|
618
|
+
it('rejects artifact with empty betterDecision', () => {
|
|
619
|
+
const artifact = makeValidArtifact();
|
|
620
|
+
artifact.betterDecision = ' ';
|
|
621
|
+
const result = validateDraftArtifact(artifact);
|
|
622
|
+
expect(result.valid).toBe(false);
|
|
623
|
+
});
|
|
624
|
+
|
|
625
|
+
it('rejects artifact with short rationale', () => {
|
|
626
|
+
const artifact = makeValidArtifact();
|
|
627
|
+
artifact.rationale = 'Too short';
|
|
628
|
+
const result = validateDraftArtifact(artifact);
|
|
629
|
+
expect(result.valid).toBe(false);
|
|
630
|
+
});
|
|
631
|
+
|
|
632
|
+
it('rejects artifact with identical badDecision and betterDecision', () => {
|
|
633
|
+
const artifact = makeValidArtifact();
|
|
634
|
+
artifact.badDecision = 'Same';
|
|
635
|
+
artifact.betterDecision = 'Same';
|
|
636
|
+
const result = validateDraftArtifact(artifact);
|
|
637
|
+
expect(result.valid).toBe(false);
|
|
638
|
+
expect(result.failures.some(f => f.includes('identical'))).toBe(true);
|
|
639
|
+
});
|
|
640
|
+
});
|
|
641
|
+
|
|
642
|
+
// ---------------------------------------------------------------------------
|
|
643
|
+
// Tests: draftToArtifact
|
|
644
|
+
// ---------------------------------------------------------------------------
|
|
645
|
+
|
|
646
|
+
describe('draftToArtifact', () => {
|
|
647
|
+
it('converts TrinityDraftArtifact to NocturnalArtifact-compatible structure', () => {
|
|
648
|
+
const draft: TrinityDraftArtifact = {
|
|
649
|
+
selectedCandidateIndex: 1,
|
|
650
|
+
badDecision: 'Did something wrong',
|
|
651
|
+
betterDecision: 'Do it right',
|
|
652
|
+
rationale: 'Because the principle says so',
|
|
653
|
+
sessionId: 'session-test-123',
|
|
654
|
+
principleId: 'T-01',
|
|
655
|
+
sourceSnapshotRef: 'snapshot-test-001',
|
|
656
|
+
telemetry: {
|
|
657
|
+
chainMode: 'trinity',
|
|
658
|
+
dreamerPassed: true,
|
|
659
|
+
philosopherPassed: true,
|
|
660
|
+
scribePassed: true,
|
|
661
|
+
candidateCount: 3,
|
|
662
|
+
selectedCandidateIndex: 1,
|
|
663
|
+
stageFailures: [],
|
|
664
|
+
},
|
|
665
|
+
};
|
|
666
|
+
|
|
667
|
+
const artifact = draftToArtifact(draft);
|
|
668
|
+
|
|
669
|
+
expect(artifact.artifactId).toBeDefined(); // Generated UUID
|
|
670
|
+
expect(artifact.sessionId).toBe('session-test-123');
|
|
671
|
+
expect(artifact.principleId).toBe('T-01');
|
|
672
|
+
expect(artifact.badDecision).toBe('Did something wrong');
|
|
673
|
+
expect(artifact.betterDecision).toBe('Do it right');
|
|
674
|
+
expect(artifact.rationale).toBe('Because the principle says so');
|
|
675
|
+
expect(artifact.sourceSnapshotRef).toBe('snapshot-test-001');
|
|
676
|
+
expect(artifact.createdAt).toBeDefined(); // Current timestamp
|
|
677
|
+
});
|
|
678
|
+
});
|
|
679
|
+
|
|
680
|
+
// ---------------------------------------------------------------------------
|
|
681
|
+
// Tests: DEFAULT_TRINITY_CONFIG
|
|
682
|
+
// ---------------------------------------------------------------------------
|
|
683
|
+
|
|
684
|
+
describe('DEFAULT_TRINITY_CONFIG', () => {
|
|
685
|
+
it('has sensible defaults', () => {
|
|
686
|
+
expect(DEFAULT_TRINITY_CONFIG.useTrinity).toBe(true);
|
|
687
|
+
expect(DEFAULT_TRINITY_CONFIG.maxCandidates).toBe(3);
|
|
688
|
+
expect(DEFAULT_TRINITY_CONFIG.useStubs).toBe(false); // real subagent execution is now the default
|
|
689
|
+
});
|
|
690
|
+
});
|
|
691
|
+
|
|
692
|
+
// ---------------------------------------------------------------------------
|
|
693
|
+
// Tests: runTrinity — useStubs=false without adapter (sync failure)
|
|
694
|
+
// ---------------------------------------------------------------------------
|
|
695
|
+
|
|
696
|
+
describe('runTrinity — useStubs=false without adapter', () => {
|
|
697
|
+
it('fails with clear error when useStubs=false but no runtimeAdapter provided', () => {
|
|
698
|
+
const snapshot = makeSnapshot({ failureCount: 2 });
|
|
699
|
+
const config: TrinityConfig = {
|
|
700
|
+
useTrinity: true,
|
|
701
|
+
maxCandidates: 3,
|
|
702
|
+
useStubs: false, // No adapter provided!
|
|
703
|
+
};
|
|
704
|
+
|
|
705
|
+
const result = runTrinity({ snapshot, principleId: 'T-08', config });
|
|
706
|
+
|
|
707
|
+
expect(result.success).toBe(false);
|
|
708
|
+
expect(result.failures.length).toBeGreaterThan(0);
|
|
709
|
+
expect(result.failures[0].stage).toBe('dreamer');
|
|
710
|
+
expect(result.failures[0].reason).toContain('runtimeAdapter');
|
|
711
|
+
expect(result.telemetry.usedStubs).toBe(false);
|
|
712
|
+
expect(result.telemetry.dreamerPassed).toBe(false);
|
|
713
|
+
});
|
|
714
|
+
});
|
|
715
|
+
|
|
716
|
+
// ---------------------------------------------------------------------------
|
|
717
|
+
// Tests: runTrinityAsync — with mock runtime adapter
|
|
718
|
+
// ---------------------------------------------------------------------------
|
|
719
|
+
|
|
720
|
+
describe('runTrinityAsync — with mock runtime adapter', () => {
|
|
721
|
+
function makeMockAdapter(overrides: Partial<{
|
|
722
|
+
dreamerOutput: DreamerOutput;
|
|
723
|
+
philosopherOutput: PhilosopherOutput;
|
|
724
|
+
scribeArtifact: TrinityDraftArtifact | null;
|
|
725
|
+
closeCalled: boolean;
|
|
726
|
+
}> = {}): TrinityRuntimeAdapter & { closeCalled: boolean } {
|
|
727
|
+
const defaultDreamerOutput: DreamerOutput = {
|
|
728
|
+
valid: true,
|
|
729
|
+
candidates: [
|
|
730
|
+
{
|
|
731
|
+
candidateIndex: 0,
|
|
732
|
+
badDecision: 'Did something wrong',
|
|
733
|
+
betterDecision: 'Do it right',
|
|
734
|
+
rationale: 'Because the principle says so',
|
|
735
|
+
confidence: 0.9,
|
|
736
|
+
},
|
|
737
|
+
],
|
|
738
|
+
generatedAt: new Date().toISOString(),
|
|
739
|
+
};
|
|
740
|
+
|
|
741
|
+
const defaultPhilosopherOutput: PhilosopherOutput = {
|
|
742
|
+
valid: true,
|
|
743
|
+
judgments: [
|
|
744
|
+
{
|
|
745
|
+
candidateIndex: 0,
|
|
746
|
+
critique: 'Good alignment',
|
|
747
|
+
principleAligned: true,
|
|
748
|
+
score: 0.92,
|
|
749
|
+
rank: 1,
|
|
750
|
+
},
|
|
751
|
+
],
|
|
752
|
+
overallAssessment: 'Good candidate',
|
|
753
|
+
generatedAt: new Date().toISOString(),
|
|
754
|
+
};
|
|
755
|
+
|
|
756
|
+
const defaultScribeArtifact: TrinityDraftArtifact = {
|
|
757
|
+
selectedCandidateIndex: 0,
|
|
758
|
+
badDecision: 'Did something wrong',
|
|
759
|
+
betterDecision: 'Do it right',
|
|
760
|
+
rationale: 'Because the principle says so and this is the right approach',
|
|
761
|
+
sessionId: 'session-test-123',
|
|
762
|
+
principleId: 'T-01',
|
|
763
|
+
sourceSnapshotRef: 'snapshot-test-001',
|
|
764
|
+
telemetry: {
|
|
765
|
+
chainMode: 'trinity',
|
|
766
|
+
usedStubs: false,
|
|
767
|
+
dreamerPassed: true,
|
|
768
|
+
philosopherPassed: true,
|
|
769
|
+
scribePassed: true,
|
|
770
|
+
candidateCount: 1,
|
|
771
|
+
selectedCandidateIndex: 0,
|
|
772
|
+
stageFailures: [],
|
|
773
|
+
},
|
|
774
|
+
};
|
|
775
|
+
|
|
776
|
+
return {
|
|
777
|
+
closeCalled: overrides.closeCalled ?? false,
|
|
778
|
+
invokeDreamer: vi.fn().mockResolvedValue(overrides.dreamerOutput ?? defaultDreamerOutput),
|
|
779
|
+
invokePhilosopher: vi.fn().mockResolvedValue(overrides.philosopherOutput ?? defaultPhilosopherOutput),
|
|
780
|
+
invokeScribe: vi.fn().mockResolvedValue(
|
|
781
|
+
overrides.scribeArtifact === null ? null : (overrides.scribeArtifact ?? defaultScribeArtifact)
|
|
782
|
+
),
|
|
783
|
+
close: vi.fn().mockResolvedValue(undefined),
|
|
784
|
+
} as unknown as TrinityRuntimeAdapter & { closeCalled: boolean; invokeDreamer: ReturnType<typeof vi.fn>; invokePhilosopher: ReturnType<typeof vi.fn>; invokeScribe: ReturnType<typeof vi.fn> };
|
|
785
|
+
}
|
|
786
|
+
|
|
787
|
+
it('uses runtime adapter when useStubs=false with adapter provided', async () => {
|
|
788
|
+
const snapshot = makeSnapshot({ failureCount: 2 });
|
|
789
|
+
const adapter = makeMockAdapter();
|
|
790
|
+
const config: TrinityConfig = {
|
|
791
|
+
useTrinity: true,
|
|
792
|
+
maxCandidates: 3,
|
|
793
|
+
useStubs: false,
|
|
794
|
+
runtimeAdapter: adapter,
|
|
795
|
+
};
|
|
796
|
+
|
|
797
|
+
const result = await runTrinityAsync({ snapshot, principleId: 'T-08', config });
|
|
798
|
+
|
|
799
|
+
expect(result.success).toBe(true);
|
|
800
|
+
expect(adapter.invokeDreamer).toHaveBeenCalledWith(snapshot, 'T-08', 3);
|
|
801
|
+
expect(adapter.invokePhilosopher).toHaveBeenCalled();
|
|
802
|
+
expect(adapter.invokeScribe).toHaveBeenCalled();
|
|
803
|
+
expect(result.telemetry.usedStubs).toBe(false);
|
|
804
|
+
expect(result.telemetry.dreamerPassed).toBe(true);
|
|
805
|
+
expect(result.telemetry.philosopherPassed).toBe(true);
|
|
806
|
+
expect(result.telemetry.scribePassed).toBe(true);
|
|
807
|
+
});
|
|
808
|
+
|
|
809
|
+
it('fails closed when Dreamer stage returns invalid output', async () => {
|
|
810
|
+
const snapshot = makeSnapshot({ failureCount: 2 });
|
|
811
|
+
const adapter = makeMockAdapter({
|
|
812
|
+
dreamerOutput: { valid: false, candidates: [], reason: 'No signal found', generatedAt: new Date().toISOString() },
|
|
813
|
+
});
|
|
814
|
+
const config: TrinityConfig = {
|
|
815
|
+
useTrinity: true,
|
|
816
|
+
maxCandidates: 3,
|
|
817
|
+
useStubs: false,
|
|
818
|
+
runtimeAdapter: adapter,
|
|
819
|
+
};
|
|
820
|
+
|
|
821
|
+
const result = await runTrinityAsync({ snapshot, principleId: 'T-08', config });
|
|
822
|
+
|
|
823
|
+
expect(result.success).toBe(false);
|
|
824
|
+
expect(result.failures.length).toBeGreaterThan(0);
|
|
825
|
+
expect(result.failures[0].stage).toBe('dreamer');
|
|
826
|
+
expect(result.telemetry.dreamerPassed).toBe(false);
|
|
827
|
+
expect(result.telemetry.philosopherPassed).toBe(false);
|
|
828
|
+
expect(result.telemetry.scribePassed).toBe(false);
|
|
829
|
+
});
|
|
830
|
+
|
|
831
|
+
it('fails closed when Philosopher stage returns invalid output', async () => {
|
|
832
|
+
const snapshot = makeSnapshot({ failureCount: 2 });
|
|
833
|
+
const adapter = makeMockAdapter({
|
|
834
|
+
philosopherOutput: { valid: false, judgments: [], overallAssessment: '', reason: 'No candidates', generatedAt: new Date().toISOString() },
|
|
835
|
+
});
|
|
836
|
+
const config: TrinityConfig = {
|
|
837
|
+
useTrinity: true,
|
|
838
|
+
maxCandidates: 3,
|
|
839
|
+
useStubs: false,
|
|
840
|
+
runtimeAdapter: adapter,
|
|
841
|
+
};
|
|
842
|
+
|
|
843
|
+
const result = await runTrinityAsync({ snapshot, principleId: 'T-08', config });
|
|
844
|
+
|
|
845
|
+
expect(result.success).toBe(false);
|
|
846
|
+
expect(result.failures.some(f => f.stage === 'dreamer')).toBe(false); // Dreamer passed
|
|
847
|
+
expect(result.failures.some(f => f.stage === 'philosopher')).toBe(true);
|
|
848
|
+
expect(result.telemetry.dreamerPassed).toBe(true);
|
|
849
|
+
expect(result.telemetry.philosopherPassed).toBe(false);
|
|
850
|
+
});
|
|
851
|
+
|
|
852
|
+
it('fails closed when Scribe stage returns null', async () => {
|
|
853
|
+
const snapshot = makeSnapshot({ failureCount: 2 });
|
|
854
|
+
const adapter = makeMockAdapter({ scribeArtifact: null });
|
|
855
|
+
const config: TrinityConfig = {
|
|
856
|
+
useTrinity: true,
|
|
857
|
+
maxCandidates: 3,
|
|
858
|
+
useStubs: false,
|
|
859
|
+
runtimeAdapter: adapter,
|
|
860
|
+
};
|
|
861
|
+
|
|
862
|
+
const result = await runTrinityAsync({ snapshot, principleId: 'T-08', config });
|
|
863
|
+
|
|
864
|
+
expect(result.success).toBe(false);
|
|
865
|
+
expect(result.failures.some(f => f.stage === 'scribe')).toBe(true);
|
|
866
|
+
expect(result.telemetry.dreamerPassed).toBe(true);
|
|
867
|
+
expect(result.telemetry.philosopherPassed).toBe(true);
|
|
868
|
+
expect(result.telemetry.scribePassed).toBe(false);
|
|
869
|
+
});
|
|
870
|
+
|
|
871
|
+
it('calls adapter.close() after successful execution', async () => {
|
|
872
|
+
const snapshot = makeSnapshot({ failureCount: 2 });
|
|
873
|
+
const adapter = makeMockAdapter();
|
|
874
|
+
const config: TrinityConfig = {
|
|
875
|
+
useTrinity: true,
|
|
876
|
+
maxCandidates: 3,
|
|
877
|
+
useStubs: false,
|
|
878
|
+
runtimeAdapter: adapter,
|
|
879
|
+
};
|
|
880
|
+
|
|
881
|
+
await runTrinityAsync({ snapshot, principleId: 'T-08', config });
|
|
882
|
+
|
|
883
|
+
expect(adapter.close).toHaveBeenCalled();
|
|
884
|
+
});
|
|
885
|
+
|
|
886
|
+
it('calls adapter.close() even when execution fails', async () => {
|
|
887
|
+
const snapshot = makeSnapshot({ failureCount: 2 });
|
|
888
|
+
const adapter = makeMockAdapter({
|
|
889
|
+
dreamerOutput: { valid: false, candidates: [], reason: 'No signal', generatedAt: new Date().toISOString() },
|
|
890
|
+
});
|
|
891
|
+
const config: TrinityConfig = {
|
|
892
|
+
useTrinity: true,
|
|
893
|
+
maxCandidates: 3,
|
|
894
|
+
useStubs: false,
|
|
895
|
+
runtimeAdapter: adapter,
|
|
896
|
+
};
|
|
897
|
+
|
|
898
|
+
await runTrinityAsync({ snapshot, principleId: 'T-08', config });
|
|
899
|
+
|
|
900
|
+
expect(adapter.close).toHaveBeenCalled();
|
|
901
|
+
});
|
|
902
|
+
|
|
903
|
+
it('produces artifact compatible with draftToArtifact', async () => {
|
|
904
|
+
const snapshot = makeSnapshot({ failureCount: 2 });
|
|
905
|
+
const adapter = makeMockAdapter();
|
|
906
|
+
const config: TrinityConfig = {
|
|
907
|
+
useTrinity: true,
|
|
908
|
+
maxCandidates: 3,
|
|
909
|
+
useStubs: false,
|
|
910
|
+
runtimeAdapter: adapter,
|
|
911
|
+
};
|
|
912
|
+
|
|
913
|
+
const result = await runTrinityAsync({ snapshot, principleId: 'T-08', config });
|
|
914
|
+
|
|
915
|
+
expect(result.success).toBe(true);
|
|
916
|
+
expect(result.artifact).toBeDefined();
|
|
917
|
+
const artifact = draftToArtifact(result.artifact!);
|
|
918
|
+
expect(artifact.artifactId).toBeDefined();
|
|
919
|
+
expect(artifact.sessionId).toBe('session-test-123');
|
|
920
|
+
expect(artifact.principleId).toBe('T-01');
|
|
921
|
+
expect(artifact.badDecision).toBeDefined();
|
|
922
|
+
expect(artifact.betterDecision).toBeDefined();
|
|
923
|
+
});
|
|
924
|
+
});
|
|
925
|
+
|
|
926
|
+
// ---------------------------------------------------------------------------
|
|
927
|
+
// Tests: runTrinityAsync — useStubs=true still uses stubs
|
|
928
|
+
// ---------------------------------------------------------------------------
|
|
929
|
+
|
|
930
|
+
describe('runTrinityAsync — useStubs=true uses synchronous stubs', () => {
|
|
931
|
+
it('still uses stub implementations when useStubs=true even with adapter', async () => {
|
|
932
|
+
const snapshot = makeSnapshot({ failureCount: 2 });
|
|
933
|
+
const adapter = {
|
|
934
|
+
invokeDreamer: vi.fn().mockResolvedValue({ valid: true, candidates: [], generatedAt: new Date().toISOString() }),
|
|
935
|
+
invokePhilosopher: vi.fn().mockResolvedValue({ valid: true, judgments: [], overallAssessment: '', generatedAt: new Date().toISOString() }),
|
|
936
|
+
invokeScribe: vi.fn().mockResolvedValue(null),
|
|
937
|
+
};
|
|
938
|
+
const config: TrinityConfig = {
|
|
939
|
+
useTrinity: true,
|
|
940
|
+
maxCandidates: 3,
|
|
941
|
+
useStubs: true, // Explicitly use stubs
|
|
942
|
+
runtimeAdapter: adapter as unknown as TrinityRuntimeAdapter,
|
|
943
|
+
};
|
|
944
|
+
|
|
945
|
+
// With stubs, adapter is ignored - stub produces success with failureCount signal
|
|
946
|
+
const result = await runTrinityAsync({ snapshot, principleId: 'T-08', config });
|
|
947
|
+
|
|
948
|
+
expect(result.success).toBe(true); // Stub succeeds because snapshot has failureCount
|
|
949
|
+
expect(adapter.invokeDreamer).not.toHaveBeenCalled(); // Adapter NOT called
|
|
950
|
+
expect(adapter.invokePhilosopher).not.toHaveBeenCalled();
|
|
951
|
+
expect(adapter.invokeScribe).not.toHaveBeenCalled();
|
|
952
|
+
});
|
|
953
|
+
});
|