principles-disciple 1.72.0 → 1.74.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/INSTALL.md +1 -3
- package/openclaw.plugin.json +10 -5
- package/package.json +17 -19
- package/scripts/acceptance-test.mjs +16 -73
- package/scripts/sync-plugin.mjs +382 -77
- package/src/commands/archive-impl.ts +2 -1
- package/src/commands/capabilities.ts +2 -2
- package/src/commands/context.ts +2 -2
- package/src/commands/disable-impl.ts +2 -1
- package/src/commands/evolution-status.ts +16 -16
- package/src/commands/export.ts +12 -67
- package/src/commands/pain.ts +91 -1
- package/src/commands/principle-rollback.ts +2 -1
- package/src/commands/promote-impl.ts +7 -43
- package/src/commands/rollback-impl.ts +2 -1
- package/src/commands/rollback.ts +2 -1
- package/src/commands/samples.ts +2 -1
- package/src/commands/thinking-os.ts +2 -1
- package/src/config/errors.ts +18 -2
- package/src/constants/diagnostician.ts +2 -2
- package/src/constants/tools.ts +2 -1
- package/src/core/__tests__/focus-history.test.ts +210 -0
- package/src/core/config.ts +1 -1
- package/src/core/correction-cue-learner.ts +2 -136
- package/src/core/correction-types.ts +16 -88
- package/src/core/dictionary.ts +19 -20
- package/src/core/empathy-keyword-matcher.ts +17 -289
- package/src/core/empathy-types.ts +18 -229
- package/src/core/event-log.ts +29 -132
- package/src/core/evolution-reducer.ts +21 -2
- package/src/core/evolution-types.ts +76 -464
- package/src/core/file-store.ts +80 -0
- package/src/core/focus-history.ts +228 -955
- package/src/core/local-worker-routing.ts +34 -314
- package/src/core/merge-gate-audit.ts +0 -195
- package/src/core/migration.ts +0 -1
- package/src/core/pain-diagnostic-gate.ts +154 -0
- package/src/core/pain-signal.ts +21 -138
- package/src/core/pain.ts +15 -88
- package/src/core/path-resolver.ts +0 -1
- package/src/core/paths.ts +0 -1
- package/src/core/pd-task-reconciler.ts +26 -115
- package/src/core/pd-task-service.ts +9 -9
- package/src/core/pd-task-types.ts +23 -127
- package/src/core/principle-compiler/__tests__/compiler-replay-gate.test.ts +174 -0
- package/src/core/principle-compiler/code-validator.ts +15 -42
- package/src/core/principle-compiler/compiler.ts +100 -15
- package/src/core/principle-compiler/index.ts +5 -2
- package/src/core/principle-compiler/template-generator.ts +4 -104
- package/src/core/principle-injection.ts +10 -202
- package/src/core/principle-internalization/filesystem-lifecycle-datasource.ts +42 -0
- package/src/core/principle-internalization/lifecycle-read-model.ts +39 -242
- package/src/core/principle-internalization/principle-lifecycle-service.ts +12 -10
- package/src/core/principle-tree-ledger-adapter.ts +145 -0
- package/src/core/principle-tree-ledger.ts +8 -6
- package/src/core/reflection/reflection-context.ts +14 -109
- package/src/core/replay-engine.ts +8 -500
- package/src/core/rule-host-helpers.ts +5 -35
- package/src/core/rule-host-types.ts +10 -82
- package/src/core/rule-host.ts +6 -63
- package/src/core/runtime-v2-prompt-activation-reader.ts +231 -0
- package/src/core/session-tracker.ts +87 -101
- package/src/core/shadow-observation-registry.ts +19 -48
- package/src/core/trajectory.ts +3 -1
- package/src/core/workflow-funnel-loader.ts +62 -68
- package/src/core/workspace-context.ts +46 -0
- package/src/core/workspace-dir-service.ts +1 -1
- package/src/core/workspace-dir-validation.ts +18 -9
- package/src/hooks/AGENTS.md +1 -1
- package/src/hooks/gate-block-helper.ts +71 -64
- package/src/hooks/gate.ts +183 -31
- package/src/hooks/lifecycle.ts +30 -32
- package/src/hooks/llm.ts +60 -32
- package/src/hooks/pain.ts +297 -103
- package/src/hooks/prompt.ts +400 -440
- package/src/hooks/subagent.ts +2 -29
- package/src/i18n/commands.ts +2 -10
- package/src/index.ts +95 -85
- package/src/openclaw-sdk.ts +311 -0
- package/src/service/central-database.ts +8 -4
- package/src/service/evolution-queue-migration.ts +2 -1
- package/src/service/evolution-worker.ts +163 -1786
- package/src/service/internalization-trigger-adapter.ts +302 -0
- package/src/service/keyword-optimization-service.ts +4 -4
- package/src/service/monitoring-query-service.ts +1 -215
- package/src/service/queue-io.ts +60 -331
- package/src/service/runtime-summary-service.ts +59 -16
- package/src/service/subagent-workflow/index.ts +0 -41
- package/src/service/subagent-workflow/types.ts +9 -120
- package/src/service/subagent-workflow/workflow-store.ts +2 -119
- package/src/service/workflow-watchdog.ts +0 -43
- package/src/types/event-payload.ts +16 -74
- package/src/types/event-types.ts +38 -547
- package/src/types/hygiene-types.ts +7 -30
- package/src/types/principle-tree-schema.ts +20 -222
- package/src/types/queue.ts +15 -70
- package/src/types/runtime-summary.ts +5 -49
- package/src/utils/io.ts +8 -20
- package/src/utils/retry.ts +1 -1
- package/src/utils/shadow-fingerprint.ts +2 -2
- package/src/utils/workspace-resolver.ts +50 -0
- package/templates/langs/en/core/AGENTS.md +7 -7
- package/templates/langs/en/core/BOOT.md +1 -1
- package/templates/langs/en/core/HEARTBEAT.md +2 -2
- package/templates/langs/en/principles/THINKING_OS.md +3 -2
- package/templates/langs/en/skills/ai-sprint-orchestration/references/agent-registry.json +1 -72
- package/templates/langs/en/skills/ai-sprint-orchestration/references/specs/bugfix-complex-template.json +6 -6
- package/templates/langs/en/skills/ai-sprint-orchestration/references/specs/feature-complex-template.json +6 -6
- package/templates/langs/en/skills/ai-sprint-orchestration/references/specs/workflow-validation-minimal-verify.json +2 -12
- package/templates/langs/en/skills/ai-sprint-orchestration/references/specs/workflow-validation-minimal.json +2 -12
- package/templates/langs/en/skills/ai-sprint-orchestration/scripts/run.mjs +51 -15
- package/templates/langs/en/skills/evolve-task/SKILL.md +3 -3
- package/templates/langs/en/skills/pd-cli-operator/SKILL.md +67 -0
- package/templates/langs/en/skills/pd-diagnostician/SKILL.md +1 -1
- package/templates/langs/en/skills/pd-mentor/SKILL.md +2 -3
- package/templates/langs/en/skills/pd-pain-signal/SKILL.md +17 -39
- package/templates/langs/en/skills/pd-runtime-v2/SKILL.md +61 -0
- package/templates/langs/zh/core/AGENTS.md +7 -7
- package/templates/langs/zh/core/BOOT.md +1 -1
- package/templates/langs/zh/core/HEARTBEAT.md +2 -2
- package/templates/langs/zh/principles/THINKING_OS.md +3 -2
- package/templates/langs/zh/skills/ai-sprint-orchestration/references/agent-registry.json +1 -72
- package/templates/langs/zh/skills/ai-sprint-orchestration/references/specs/bugfix-complex-template.json +6 -6
- package/templates/langs/zh/skills/ai-sprint-orchestration/references/specs/feature-complex-template.json +6 -6
- package/templates/langs/zh/skills/ai-sprint-orchestration/references/specs/nocturnal-trinity-quality-enhancement.json +8 -8
- package/templates/langs/zh/skills/ai-sprint-orchestration/references/specs/workflow-validation-minimal-verify.json +2 -12
- package/templates/langs/zh/skills/ai-sprint-orchestration/references/specs/workflow-validation-minimal.json +2 -12
- package/templates/langs/zh/skills/ai-sprint-orchestration/scripts/run.mjs +51 -15
- package/templates/langs/zh/skills/ai-sprint-orchestration/test/run.test.mjs +21 -5
- package/templates/langs/zh/skills/evolve-task/SKILL.md +4 -4
- package/templates/langs/zh/skills/pd-cli-operator/SKILL.md +67 -0
- package/templates/langs/zh/skills/pd-diagnostician/SKILL.md +1 -1
- package/templates/langs/zh/skills/pd-mentor/SKILL.md +2 -3
- package/templates/langs/zh/skills/pd-pain-signal/SKILL.md +17 -38
- package/templates/langs/zh/skills/pd-runtime-v2/SKILL.md +61 -0
- package/tests/build-artifacts.test.ts +1 -3
- package/tests/commands/evolution-status.test.ts +0 -118
- package/tests/core/bootstrap-rules.test.ts +1 -1
- package/tests/core/config.test.ts +1 -1
- package/tests/core/event-log.test.ts +35 -0
- package/tests/core/evolution-engine.test.ts +610 -0
- package/tests/core/file-store.test.ts +102 -0
- package/tests/core/focus-history.test.ts +203 -11
- package/tests/core/merge-gate-audit.test.ts +2 -169
- package/tests/core/migration.test.ts +7 -7
- package/tests/core/model-deployment-registry.test.ts +7 -1
- package/tests/core/model-training-registry.test.ts +19 -0
- package/tests/core/observability.test.ts +0 -1
- package/tests/core/pain-diagnostic-gate.test.ts +498 -0
- package/tests/core/pain.test.ts +0 -1
- package/tests/core/path-resolver.test.ts +1 -1
- package/tests/core/paths-refactor.test.ts +0 -22
- package/tests/core/principle-internalization/deprecated-readiness.test.ts +2 -2
- package/tests/core/principle-internalization/lifecycle-metrics.test.ts +2 -2
- package/tests/core/principle-internalization/{internalization-routing-policy.test.ts → lifecycle-routing-policy.test.ts} +6 -6
- package/tests/core/principle-internalization/lineage-source-retired.test.ts +56 -0
- package/tests/core/principle-internalization/principle-lifecycle-service.test.ts +1 -23
- package/tests/core/principle-tree-ledger-adapter.test.ts +253 -0
- package/tests/core/reflection-context.test.ts +0 -14
- package/tests/core/replay-engine.test.ts +127 -215
- package/tests/core/rule-host-helpers.test.ts +2 -2
- package/tests/core/rule-implementation-runtime.test.ts +0 -27
- package/tests/core/workflow-funnel-loader.test.ts +162 -0
- package/tests/core/workspace-context.test.ts +2 -2
- package/tests/core/workspace-dir-validation.test.ts +8 -1
- package/tests/core-anti-growth.test.ts +191 -0
- package/tests/hook-workspace-nextaction-contract.test.ts +42 -0
- package/tests/hooks/confirm-first-removal.test.ts +188 -0
- package/tests/hooks/gate-auto-correct-shadow.test.ts +310 -0
- package/tests/hooks/gate-auto-correct.test.ts +665 -0
- package/tests/hooks/gate-no-path-write-tool.test.ts +172 -0
- package/tests/hooks/gate-rule-host-pipeline.test.ts +2 -1
- package/tests/hooks/pain.test.ts +269 -12
- package/tests/hooks/prompt-characterization.test.ts +500 -0
- package/tests/hooks/prompt-size-guard.test.ts +32 -17
- package/tests/hooks/runtime-v2-prompt-activation.test.ts +869 -0
- package/tests/index.test.ts +94 -1
- package/tests/integration/auto-entry-gate.test.ts +248 -0
- package/tests/integration/internalization-trigger-guard.test.ts +69 -0
- package/tests/integration/m8-legacy-paths.test.ts +63 -0
- package/tests/integration/runtime-v2-pain-guard.test.ts +125 -0
- package/tests/plugin-config-resolution-cutover.test.ts +359 -0
- package/tests/runtime-v2-discovery-guard.test.ts +154 -0
- package/tests/service/central-database.test.ts +457 -0
- package/tests/service/evolution-worker.correction-observer.test.ts +173 -0
- package/tests/service/evolution-worker.timeout.test.ts +11 -129
- package/tests/service/internalization-trigger-adapter.test.ts +251 -0
- package/tests/service/monitoring-query-service.test.ts +1 -47
- package/tests/service/queue-io.test.ts +1 -62
- package/tests/service/runtime-summary-service.test.ts +3 -1
- package/tests/service/workflow-watchdog.test.ts +0 -91
- package/tests/utils/file-lock.test.ts +5 -3
- package/tests/utils/session-key.test.ts +52 -0
- package/tests/utils/subagent-probe.test.ts +48 -1
- package/vitest.config.ts +4 -11
- package/.planning/codebase/ARCHITECTURE.md +0 -157
- package/.planning/codebase/CONCERNS.md +0 -145
- package/.planning/codebase/CONVENTIONS.md +0 -148
- package/.planning/codebase/INTEGRATIONS.md +0 -81
- package/.planning/codebase/STACK.md +0 -87
- package/.planning/codebase/STRUCTURE.md +0 -193
- package/.planning/codebase/TESTING.md +0 -243
- package/.planning/phases/01-basic-visualization/01-GAP-CLOSURE-VERIFICATION.md +0 -113
- package/docs/COMMAND_REFERENCE.md +0 -76
- package/docs/COMMAND_REFERENCE_EN.md +0 -79
- package/scripts/build-web.mjs +0 -46
- package/scripts/diagnose-nocturnal.mjs +0 -537
- package/scripts/seed-nocturnal-scenarios.mjs +0 -384
- package/src/commands/nocturnal-review.ts +0 -322
- package/src/commands/nocturnal-rollout.ts +0 -790
- package/src/commands/nocturnal-train.ts +0 -986
- package/src/commands/pd-reflect.ts +0 -88
- package/src/core/adaptive-thresholds.ts +0 -478
- package/src/core/diagnostician-task-store.ts +0 -192
- package/src/core/nocturnal-arbiter.ts +0 -715
- package/src/core/nocturnal-artifact-lineage.ts +0 -116
- package/src/core/nocturnal-artificer.ts +0 -257
- package/src/core/nocturnal-candidate-scoring.ts +0 -530
- package/src/core/nocturnal-compliance.ts +0 -1146
- package/src/core/nocturnal-dataset.ts +0 -763
- package/src/core/nocturnal-executability.ts +0 -428
- package/src/core/nocturnal-export.ts +0 -499
- package/src/core/nocturnal-paths.ts +0 -240
- package/src/core/nocturnal-reasoning-deriver.ts +0 -343
- package/src/core/nocturnal-rule-implementation-validator.ts +0 -246
- package/src/core/nocturnal-snapshot-contract.ts +0 -99
- package/src/core/nocturnal-trajectory-extractor.ts +0 -512
- package/src/core/nocturnal-trinity-types.ts +0 -218
- package/src/core/nocturnal-trinity.ts +0 -2680
- package/src/core/principle-internalization/deprecated-readiness.ts +0 -93
- package/src/core/principle-internalization/internalization-routing-policy.ts +0 -208
- package/src/core/principle-internalization/lifecycle-metrics.ts +0 -152
- package/src/http/principles-console-route.ts +0 -709
- package/src/service/central-health-service.ts +0 -49
- package/src/service/central-overview-service.ts +0 -138
- package/src/service/control-ui-query-service.ts +0 -900
- package/src/service/cooldown-strategy.ts +0 -97
- package/src/service/evolution-pain-context.ts +0 -79
- package/src/service/evolution-query-service.ts +0 -407
- package/src/service/health-query-service.ts +0 -1038
- package/src/service/nocturnal-config.ts +0 -214
- package/src/service/nocturnal-runtime.ts +0 -734
- package/src/service/nocturnal-service.ts +0 -1605
- package/src/service/nocturnal-target-selector.ts +0 -545
- package/src/service/sleep-cycle.ts +0 -157
- package/src/service/startup-reconciler.ts +0 -112
- package/src/service/subagent-workflow/correction-observer-types.ts +0 -82
- package/src/service/subagent-workflow/correction-observer-workflow-manager.ts +0 -250
- package/src/service/subagent-workflow/deep-reflect-workflow-manager.ts +0 -1
- package/src/service/subagent-workflow/dynamic-timeout.ts +0 -30
- package/src/service/subagent-workflow/empathy-observer-workflow-manager.ts +0 -268
- package/src/service/subagent-workflow/nocturnal-workflow-manager.ts +0 -795
- package/src/service/subagent-workflow/runtime-direct-driver.ts +0 -268
- package/src/service/subagent-workflow/workflow-manager-base.ts +0 -580
- package/src/tools/write-pain-flag.ts +0 -215
- package/templates/langs/en/skills/plan-script/SKILL.md +0 -32
- package/templates/langs/zh/skills/plan-script/SKILL.md +0 -32
- package/tests/commands/nocturnal-review.test.ts +0 -448
- package/tests/commands/nocturnal-train.test.ts +0 -97
- package/tests/commands/pd-reflect.test.ts +0 -49
- package/tests/core/adaptive-thresholds.test.ts +0 -261
- package/tests/core/nocturnal-arbiter.test.ts +0 -559
- package/tests/core/nocturnal-artifact-lineage.test.ts +0 -53
- package/tests/core/nocturnal-artificer.test.ts +0 -241
- package/tests/core/nocturnal-candidate-scoring.test.ts +0 -532
- package/tests/core/nocturnal-compliance-p-principles.test.ts +0 -133
- package/tests/core/nocturnal-compliance.test.ts +0 -646
- package/tests/core/nocturnal-dataset.test.ts +0 -892
- package/tests/core/nocturnal-e2e.test.ts +0 -234
- package/tests/core/nocturnal-executability.test.ts +0 -357
- package/tests/core/nocturnal-export.test.ts +0 -517
- package/tests/core/nocturnal-reasoning-deriver.test.ts +0 -372
- package/tests/core/nocturnal-reviewed-subset-comparison.test.ts +0 -428
- package/tests/core/nocturnal-rule-implementation-validator.test.ts +0 -127
- package/tests/core/nocturnal-snapshot-contract.test.ts +0 -121
- package/tests/core/nocturnal-trajectory-extractor.test.ts +0 -634
- package/tests/core/nocturnal-trinity.test.ts +0 -2053
- package/tests/core/pain-auto-repair.test.ts +0 -96
- package/tests/core/pain-integration.test.ts +0 -510
- package/tests/fixtures/nocturnal-reviewed-subset.json +0 -183
- package/tests/http/principles-console-route.test.ts +0 -162
- package/tests/integration/chaos-resilience.test.ts +0 -348
- package/tests/integration/empathy-workflow-integration.test.ts +0 -626
- package/tests/integration/pain-diagnostician-loop.e2e.test.ts +0 -380
- package/tests/service/control-ui-query-service.test.ts +0 -121
- package/tests/service/cooldown-strategy.test.ts +0 -164
- package/tests/service/data-endpoints-regression.test.ts +0 -834
- package/tests/service/empathy-observer-workflow-manager.test.ts +0 -175
- package/tests/service/evolution-worker.nocturnal.test.ts +0 -601
- package/tests/service/nocturnal-runtime-hardening.test.ts +0 -118
- package/tests/service/nocturnal-runtime.test.ts +0 -473
- package/tests/service/nocturnal-service-code-candidate.test.ts +0 -330
- package/tests/service/nocturnal-target-selector.test.ts +0 -615
- package/tests/service/startup-reconciler.test.ts +0 -148
- package/tests/tools/write-pain-flag.test.ts +0 -358
- package/ui/src/App.tsx +0 -45
- package/ui/src/api.ts +0 -220
- package/ui/src/charts.tsx +0 -955
- package/ui/src/components/ErrorState.tsx +0 -6
- package/ui/src/components/Loading.tsx +0 -13
- package/ui/src/components/ProtectedRoute.tsx +0 -12
- package/ui/src/components/Shell.tsx +0 -91
- package/ui/src/components/WorkspaceConfig.tsx +0 -178
- package/ui/src/components/index.ts +0 -5
- package/ui/src/context/auth.tsx +0 -80
- package/ui/src/context/theme.tsx +0 -66
- package/ui/src/hooks/useAutoRefresh.ts +0 -39
- package/ui/src/i18n/ui.ts +0 -473
- package/ui/src/main.tsx +0 -16
- package/ui/src/pages/EvolutionPage.tsx +0 -333
- package/ui/src/pages/FeedbackPage.tsx +0 -138
- package/ui/src/pages/GateMonitorPage.tsx +0 -136
- package/ui/src/pages/LoginPage.tsx +0 -89
- package/ui/src/pages/OverviewPage.tsx +0 -599
- package/ui/src/pages/SamplesPage.tsx +0 -174
- package/ui/src/pages/ThinkingModelsPage.tsx +0 -702
- package/ui/src/styles.css +0 -2020
- package/ui/src/types.ts +0 -384
- package/ui/src/utils/format.ts +0 -15
|
@@ -2,38 +2,32 @@
|
|
|
2
2
|
* Local Worker Routing Policy — Task Classification and Routing Decisions
|
|
3
3
|
* ======================================================================
|
|
4
4
|
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
5
|
+
* Phase: PRI-74 Routing Guidance Migration (follow-up to PRI-75 Prompt Injection SDK Migration)
|
|
6
|
+
*
|
|
7
|
+
* This file is a THIN ADAPTER.
|
|
8
|
+
* Pure classification logic lives in @principles/core/prompt-builder/routing-guidance.ts.
|
|
9
|
+
* This file handles I/O (deployment registry, promotion state) and combines
|
|
10
|
+
* pure classification with deployment checks.
|
|
8
11
|
*
|
|
9
12
|
* ARCHITECTURE:
|
|
10
|
-
* -
|
|
11
|
-
* -
|
|
12
|
-
* actually routing the task based on the RoutingDecision returned here
|
|
13
|
-
* - All decisions are deterministic and based on structured input fields
|
|
14
|
-
* - No model inference, no learning, no dynamic adaptation
|
|
13
|
+
* - Pure: classifyTaskKind, buildReason, buildBlockers, keyword constants → core
|
|
14
|
+
* - I/O: getDeployment, isRoutingEnabledForProfile, isCheckpointDeployable, getPromotionState → plugin
|
|
15
15
|
*
|
|
16
16
|
* TASK CLASSIFICATION TAXONOMY:
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
17
|
+
* Pure-classification output from classifyTaskKind() in @principles/core/prompt-builder/routing-guidance.ts:
|
|
18
|
+
* reader_eligible — clearly suitable for local-reader
|
|
19
|
+
* editor_eligible — clearly suitable for local-editor
|
|
20
|
+
* high_entropy_disallowed — high-complexity tasks that must stay on main agent
|
|
21
|
+
* ambiguous_scope — tasks that are unclear and need main-agent judgment
|
|
22
|
+
* Plugin layer adds I/O-bound categories via deployment checks in classifyTask():
|
|
23
|
+
* profile_mismatch — target profile incompatible with task classification
|
|
24
|
+
* deployment_unavailable — no enabled deployment exists for the target profile
|
|
25
25
|
*
|
|
26
26
|
* FAIL-CLOSED PRINCIPLE:
|
|
27
27
|
* - When in doubt → stay_main
|
|
28
28
|
* - Unclear intent → stay_main
|
|
29
29
|
* - High complexity → stay_main
|
|
30
30
|
* - No enabled deployment → stay_main
|
|
31
|
-
*
|
|
32
|
-
* DESIGN CONSTRAINTS:
|
|
33
|
-
* - No actual task execution
|
|
34
|
-
* - No automatic learning or route optimization
|
|
35
|
-
* - No Trinity or adaptive threshold logic
|
|
36
|
-
* - Routing decisions are fully explainable (return `reason` + `blockers[]`)
|
|
37
31
|
*/
|
|
38
32
|
|
|
39
33
|
import type { WorkerProfile } from './model-deployment-registry.js';
|
|
@@ -44,58 +38,16 @@ import {
|
|
|
44
38
|
import { isCheckpointDeployable } from './model-training-registry.js';
|
|
45
39
|
import { getPromotionState } from './promotion-gate.js';
|
|
46
40
|
|
|
47
|
-
//
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
* by treating it as ambiguous (stay_main).
|
|
55
|
-
*/
|
|
56
|
-
export interface RoutingInput {
|
|
57
|
-
/**
|
|
58
|
-
* A short label or name for the task intent.
|
|
59
|
-
* E.g., "read_file", "edit_config", "debug_memory_leak", "design_system"
|
|
60
|
-
*/
|
|
61
|
-
taskIntent?: string;
|
|
62
|
-
|
|
63
|
-
/**
|
|
64
|
-
* Natural-language description of the task.
|
|
65
|
-
* The classifier examines this for keywords indicating complexity/risk.
|
|
66
|
-
*/
|
|
67
|
-
taskDescription?: string;
|
|
68
|
-
|
|
69
|
-
/**
|
|
70
|
-
* Specific tools requested or implied by the task.
|
|
71
|
-
* These are examined for risk signals (e.g., bash, rm, git push).
|
|
72
|
-
*/
|
|
73
|
-
requestedTools?: string[];
|
|
74
|
-
|
|
75
|
-
/**
|
|
76
|
-
* Specific files involved or targeted.
|
|
77
|
-
* Examined for risk-path indicators (e.g., .git/, node_modules, production configs).
|
|
78
|
-
*/
|
|
79
|
-
requestedFiles?: string[];
|
|
80
|
-
|
|
81
|
-
/**
|
|
82
|
-
* Shape of expected output.
|
|
83
|
-
* E.g., "json", "markdown", "one_line", "full_report"
|
|
84
|
-
*/
|
|
85
|
-
expectedOutputShape?: string;
|
|
86
|
-
|
|
87
|
-
/**
|
|
88
|
-
* Complexity hints for the task.
|
|
89
|
-
* E.g., ["multi_step", "cross_file", "ambiguous", "requires_planning"]
|
|
90
|
-
*/
|
|
91
|
-
complexityHints?: string[];
|
|
41
|
+
// Core pure functions — migrated to @principles/core/prompt-builder
|
|
42
|
+
import {
|
|
43
|
+
type RoutingInput as CoreRoutingInput,
|
|
44
|
+
classifyTaskKind as coreClassifyTaskKind,
|
|
45
|
+
buildReason as coreBuildReason,
|
|
46
|
+
buildBlockers as coreBuildBlockers,
|
|
47
|
+
} from '@principles/core/prompt-builder';
|
|
92
48
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
* If omitted, both profiles are evaluated and the best match is returned.
|
|
96
|
-
*/
|
|
97
|
-
targetProfile?: WorkerProfile;
|
|
98
|
-
}
|
|
49
|
+
// Re-export RoutingInput from core for backward compatibility with existing imports
|
|
50
|
+
export type { RoutingInput } from '@principles/core/prompt-builder';
|
|
99
51
|
|
|
100
52
|
// ---------------------------------------------------------------------------
|
|
101
53
|
// Routing Decision Contract
|
|
@@ -180,238 +132,6 @@ export interface RoutingDecision {
|
|
|
180
132
|
|
|
181
133
|
}
|
|
182
134
|
|
|
183
|
-
// ---------------------------------------------------------------------------
|
|
184
|
-
// Keyword Classifiers
|
|
185
|
-
// ---------------------------------------------------------------------------
|
|
186
|
-
|
|
187
|
-
/**
|
|
188
|
-
* Keywords that indicate a task is suitable for `local-reader`.
|
|
189
|
-
* Matched against taskIntent + taskDescription.
|
|
190
|
-
*/
|
|
191
|
-
const READER_KEYWORDS = [
|
|
192
|
-
'read', 'view', 'show', 'get', 'find', 'search', 'grep', 'look',
|
|
193
|
-
'inspect', 'examine', 'list', 'cat', 'head', 'tail', 'diff',
|
|
194
|
-
'summary', 'summarize', 'extract', 'parse', 'review',
|
|
195
|
-
'check', 'verify', 'status', 'describe', 'explain_what',
|
|
196
|
-
'browse', 'fetch', 'show_content', 'file_content', 'code_read',
|
|
197
|
-
];
|
|
198
|
-
|
|
199
|
-
/**
|
|
200
|
-
* Keywords that indicate a task is suitable for `local-editor`.
|
|
201
|
-
* Matched against taskIntent + taskDescription.
|
|
202
|
-
*/
|
|
203
|
-
const EDITOR_KEYWORDS = [
|
|
204
|
-
'edit', 'update', 'modify', 'change', 'fix', 'patch', 'replace',
|
|
205
|
-
'add', 'remove', 'delete', 'insert', 'rewrite', 'refactor',
|
|
206
|
-
'apply', 'execute', 'run', 'transform', 'convert', 'migrate',
|
|
207
|
-
'write', 'create_file', 'append', 'touch', 'rename',
|
|
208
|
-
];
|
|
209
|
-
|
|
210
|
-
/**
|
|
211
|
-
* Keywords that indicate HIGH ENTROPY — tasks that must stay on main agent.
|
|
212
|
-
* These indicate open-ended, multi-step, or ambiguous tasks.
|
|
213
|
-
*/
|
|
214
|
-
const HIGH_ENTROPY_KEYWORDS = [
|
|
215
|
-
'design', 'architect', 'plan', 'strategy', 'roadmap', 'propose',
|
|
216
|
-
'research', 'investigate', 'explore', 'evaluate', 'compare',
|
|
217
|
-
'decide', 'choose', 'recommend', 'suggest', 'analyze_tradeoffs',
|
|
218
|
-
'unclear', 'vague', 'ambiguous', 'open_ended', 'multiple_options',
|
|
219
|
-
'architecture', 'system_design', 'high_level', 'blueprint',
|
|
220
|
-
'thinking', 'reasoning', '思考', '分析', '设计',
|
|
221
|
-
];
|
|
222
|
-
|
|
223
|
-
// ---------------------------------------------------------------------------
|
|
224
|
-
// Classification Helpers
|
|
225
|
-
// ---------------------------------------------------------------------------
|
|
226
|
-
|
|
227
|
-
/**
|
|
228
|
-
* Simple case-insensitive keyword match.
|
|
229
|
-
*/
|
|
230
|
-
function containsKeyword(text: string | undefined, keywords: string[]): boolean {
|
|
231
|
-
if (!text) return false;
|
|
232
|
-
const lower = text.toLowerCase();
|
|
233
|
-
return keywords.some((kw) => lower.includes(kw));
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
/**
|
|
237
|
-
* Compute a combined text from all input fields for keyword scanning.
|
|
238
|
-
*/
|
|
239
|
-
function computeCombinedText(input: RoutingInput): string {
|
|
240
|
-
const parts: string[] = [];
|
|
241
|
-
if (input.taskIntent) parts.push(input.taskIntent);
|
|
242
|
-
if (input.taskDescription) parts.push(input.taskDescription);
|
|
243
|
-
if (input.expectedOutputShape) parts.push(input.expectedOutputShape);
|
|
244
|
-
if (input.complexityHints) parts.push(input.complexityHints.join(' '));
|
|
245
|
-
return parts.join(' ').toLowerCase();
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
// ---------------------------------------------------------------------------
|
|
249
|
-
// Core Classification Logic
|
|
250
|
-
// ---------------------------------------------------------------------------
|
|
251
|
-
|
|
252
|
-
/**
|
|
253
|
-
* Classify the task based on its input fields.
|
|
254
|
-
* Returns a raw classification category (before deployment check).
|
|
255
|
-
*/
|
|
256
|
-
function classifyTaskKind(input: RoutingInput): RoutingDecision['classification'] {
|
|
257
|
-
const text = computeCombinedText(input);
|
|
258
|
-
const { taskIntent, taskDescription, requestedFiles, complexityHints } = input;
|
|
259
|
-
|
|
260
|
-
// --- Step 1: High-entropy keyword detection ---
|
|
261
|
-
if (complexityHints?.some((h) =>
|
|
262
|
-
['multi_step', 'cross_file', 'ambiguous', 'requires_planning', 'open_ended', 'unclear'].includes(h)
|
|
263
|
-
)) {
|
|
264
|
-
return 'high_entropy_disallowed';
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
if (containsKeyword(text, HIGH_ENTROPY_KEYWORDS)) {
|
|
268
|
-
return 'high_entropy_disallowed';
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
if (containsKeyword(taskIntent, ['design', 'architect', 'plan', 'propose']) ||
|
|
272
|
-
containsKeyword(taskDescription, ['design', 'architect', 'plan', 'propose'])) {
|
|
273
|
-
return 'high_entropy_disallowed';
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
// --- Step 2: Reader eligibility ---
|
|
277
|
-
const intentIsReader = containsKeyword(taskIntent, READER_KEYWORDS);
|
|
278
|
-
const descIsReader = containsKeyword(taskDescription, READER_KEYWORDS);
|
|
279
|
-
|
|
280
|
-
if (intentIsReader && (descIsReader || !taskDescription)) {
|
|
281
|
-
return 'reader_eligible';
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
// --- Step 3: Editor eligibility ---
|
|
285
|
-
const uniqueFiles = requestedFiles
|
|
286
|
-
? [...new Set(requestedFiles.filter((f) => f.trim().length > 0))]
|
|
287
|
-
: [];
|
|
288
|
-
const intentIsEditor = containsKeyword(taskIntent, EDITOR_KEYWORDS);
|
|
289
|
-
const descIsEditor = containsKeyword(taskDescription, EDITOR_KEYWORDS);
|
|
290
|
-
|
|
291
|
-
if (intentIsEditor && (descIsEditor || !taskDescription)) {
|
|
292
|
-
if (uniqueFiles.length >= 4) {
|
|
293
|
-
return 'high_entropy_disallowed';
|
|
294
|
-
}
|
|
295
|
-
return 'editor_eligible';
|
|
296
|
-
}
|
|
297
|
-
|
|
298
|
-
// --- Step 4: Ambiguous scope ---
|
|
299
|
-
if (taskDescription && taskDescription.trim().length > 0) {
|
|
300
|
-
const trimmed = taskDescription.trim();
|
|
301
|
-
if (trimmed.length < 20 || ['todo', 'fix', 'improve', 'change', 'update', 'something'].includes(trimmed.toLowerCase())) {
|
|
302
|
-
return 'ambiguous_scope';
|
|
303
|
-
}
|
|
304
|
-
if (/\b(why|how|should|could|would|what if|should we|whether to)\b/i.test(trimmed)) {
|
|
305
|
-
return 'ambiguous_scope';
|
|
306
|
-
}
|
|
307
|
-
}
|
|
308
|
-
|
|
309
|
-
if (!taskIntent && !taskDescription) {
|
|
310
|
-
return 'ambiguous_scope';
|
|
311
|
-
}
|
|
312
|
-
|
|
313
|
-
return 'ambiguous_scope';
|
|
314
|
-
}
|
|
315
|
-
|
|
316
|
-
/**
|
|
317
|
-
* Build the reason string for a given classification.
|
|
318
|
-
*/
|
|
319
|
-
function buildReason(
|
|
320
|
-
classification: RoutingDecision['classification'],
|
|
321
|
-
input: RoutingInput
|
|
322
|
-
): string {
|
|
323
|
-
const { taskIntent, taskDescription } = input;
|
|
324
|
-
|
|
325
|
-
switch (classification) {
|
|
326
|
-
case 'reader_eligible':
|
|
327
|
-
return `Task "${taskIntent || taskDescription || '(unnamed)'}" is classified as reader_eligible. ` +
|
|
328
|
-
`Keywords indicate focused reading, inspection, or information retrieval. ` +
|
|
329
|
-
`No high-entropy or risk signals detected.`;
|
|
330
|
-
|
|
331
|
-
case 'editor_eligible':
|
|
332
|
-
return `Task "${taskIntent || taskDescription || '(unnamed)'}" is classified as editor_eligible. ` +
|
|
333
|
-
`Keywords indicate bounded editing, modification, or repair. ` +
|
|
334
|
-
`No high-entropy or risk signals detected.`;
|
|
335
|
-
|
|
336
|
-
case 'high_entropy_disallowed': {
|
|
337
|
-
const uniqueFiles = input.requestedFiles
|
|
338
|
-
? [...new Set(input.requestedFiles.filter((f) => f.trim().length > 0))]
|
|
339
|
-
: [];
|
|
340
|
-
const isLargeScaleEdit = uniqueFiles.length >= 4;
|
|
341
|
-
if (isLargeScaleEdit) {
|
|
342
|
-
return `Task "${taskIntent || taskDescription || '(unnamed)'}" is blocked as high_entropy_disallowed. ` +
|
|
343
|
-
`Editing ${uniqueFiles.length} files simultaneously exceeds the bounded-scope limit for local-editor. ` +
|
|
344
|
-
`Large-scale multi-file edits require the main agent's coordination and risk judgment.`;
|
|
345
|
-
}
|
|
346
|
-
return `Task "${taskIntent || taskDescription || '(unnamed)'}" is blocked as high_entropy_disallowed. ` +
|
|
347
|
-
`Keywords indicate open-ended planning, architecture design, or ambiguous multi-step work. ` +
|
|
348
|
-
`These tasks require the main agent's full reasoning capability.`;
|
|
349
|
-
}
|
|
350
|
-
|
|
351
|
-
case 'ambiguous_scope':
|
|
352
|
-
return `Task "${taskIntent || taskDescription || '(unnamed)'}" is blocked as ambiguous_scope. ` +
|
|
353
|
-
`The task description is too vague, too short, or contains open-ended question words. ` +
|
|
354
|
-
`Main agent must clarify scope before delegation.`;
|
|
355
|
-
|
|
356
|
-
case 'profile_mismatch':
|
|
357
|
-
return `Task profile does not match the requested target profile. ` +
|
|
358
|
-
`The task's natural classification is incompatible with the specified worker profile. ` +
|
|
359
|
-
`Main agent must re-route or choose a compatible profile.`;
|
|
360
|
-
|
|
361
|
-
case 'deployment_unavailable':
|
|
362
|
-
return `No enabled deployment available for routing. ` +
|
|
363
|
-
`Either no checkpoint is bound to the profile, or routing has been disabled. ` +
|
|
364
|
-
`Main agent must handle this task.`;
|
|
365
|
-
}
|
|
366
|
-
}
|
|
367
|
-
|
|
368
|
-
/**
|
|
369
|
-
* Build the blockers list for a given classification.
|
|
370
|
-
*/
|
|
371
|
-
function buildBlockers(
|
|
372
|
-
classification: RoutingDecision['classification'],
|
|
373
|
-
input: RoutingInput
|
|
374
|
-
): string[] {
|
|
375
|
-
switch (classification) {
|
|
376
|
-
case 'reader_eligible':
|
|
377
|
-
return [];
|
|
378
|
-
case 'editor_eligible':
|
|
379
|
-
return [];
|
|
380
|
-
case 'high_entropy_disallowed': {
|
|
381
|
-
const uniqueFiles = input.requestedFiles
|
|
382
|
-
? [...new Set(input.requestedFiles.filter((f) => f.trim().length > 0))]
|
|
383
|
-
: [];
|
|
384
|
-
const isLargeScaleEdit = uniqueFiles.length >= 4;
|
|
385
|
-
return [
|
|
386
|
-
isLargeScaleEdit
|
|
387
|
-
? `large-scale multi-file edit detected (${uniqueFiles.length} files): scope too broad for local-editor`
|
|
388
|
-
: 'task contains high-entropy keywords (design/plan/architect/investigate)',
|
|
389
|
-
'complexity hint indicates multi-step or open-ended work',
|
|
390
|
-
'main agent required for full reasoning and judgment',
|
|
391
|
-
];
|
|
392
|
-
}
|
|
393
|
-
case 'ambiguous_scope':
|
|
394
|
-
return [
|
|
395
|
-
'task description too vague or generic',
|
|
396
|
-
'task intent not provided or unclear',
|
|
397
|
-
'open-ended question words detected',
|
|
398
|
-
'main agent must clarify scope before delegation',
|
|
399
|
-
];
|
|
400
|
-
case 'profile_mismatch':
|
|
401
|
-
return [
|
|
402
|
-
'task natural profile incompatible with requested target profile',
|
|
403
|
-
'main agent must re-route or select a compatible profile',
|
|
404
|
-
];
|
|
405
|
-
|
|
406
|
-
case 'deployment_unavailable':
|
|
407
|
-
return [
|
|
408
|
-
'no enabled deployment found for target profile',
|
|
409
|
-
'routing may be disabled in deployment registry',
|
|
410
|
-
'main agent must handle task directly',
|
|
411
|
-
];
|
|
412
|
-
}
|
|
413
|
-
}
|
|
414
|
-
|
|
415
135
|
// ---------------------------------------------------------------------------
|
|
416
136
|
// Public API
|
|
417
137
|
// ---------------------------------------------------------------------------
|
|
@@ -421,8 +141,8 @@ function buildBlockers(
|
|
|
421
141
|
*
|
|
422
142
|
* This is the main entry point for routing policy evaluation.
|
|
423
143
|
* It:
|
|
424
|
-
* 1. Classifies the task kind based on keywords and heuristics
|
|
425
|
-
* 2. Checks deployment availability for the target profile
|
|
144
|
+
* 1. Classifies the task kind based on keywords and heuristics (core pure function)
|
|
145
|
+
* 2. Checks deployment availability for the target profile (plugin I/O)
|
|
426
146
|
* 3. Returns a fully explainable RoutingDecision
|
|
427
147
|
*
|
|
428
148
|
* @param input - The routing input describing the task
|
|
@@ -430,11 +150,11 @@ function buildBlockers(
|
|
|
430
150
|
* @returns RoutingDecision with classification, reason, blockers, and routing verdict
|
|
431
151
|
*/
|
|
432
152
|
export function classifyTask(
|
|
433
|
-
input:
|
|
153
|
+
input: CoreRoutingInput,
|
|
434
154
|
stateDir: string
|
|
435
155
|
): RoutingDecision {
|
|
436
|
-
// --- Determine the raw task classification ---
|
|
437
|
-
const classification =
|
|
156
|
+
// --- Determine the raw task classification (delegated to core pure function) ---
|
|
157
|
+
const classification = coreClassifyTaskKind(input);
|
|
438
158
|
|
|
439
159
|
// --- Determine the target profile ---
|
|
440
160
|
// If input specifies a target, use it. Otherwise, pick based on classification.
|
|
@@ -485,9 +205,9 @@ export function classifyTask(
|
|
|
485
205
|
};
|
|
486
206
|
}
|
|
487
207
|
|
|
488
|
-
// --- Build the decision ---
|
|
489
|
-
const blockers =
|
|
490
|
-
const reason =
|
|
208
|
+
// --- Build the decision (delegated to core pure functions) ---
|
|
209
|
+
const blockers = coreBuildBlockers(classification, input);
|
|
210
|
+
const reason = coreBuildReason(classification, input);
|
|
491
211
|
|
|
492
212
|
// FAIL-CLOSED: route_local only if:
|
|
493
213
|
// 1. Classification is eligible (reader_eligible or editor_eligible)
|
|
@@ -586,7 +306,7 @@ export function classifyTask(
|
|
|
586
306
|
* Equivalent to calling classifyTask with targetProfile set.
|
|
587
307
|
*/
|
|
588
308
|
export function canRouteToProfile(
|
|
589
|
-
input:
|
|
309
|
+
input: CoreRoutingInput,
|
|
590
310
|
stateDir: string,
|
|
591
311
|
profile: WorkerProfile
|
|
592
312
|
): boolean {
|
|
@@ -1,10 +1,6 @@
|
|
|
1
1
|
import * as fs from 'fs';
|
|
2
2
|
import * as path from 'path';
|
|
3
3
|
import { getImplementationAssetRoot } from './code-implementation-storage.js';
|
|
4
|
-
import { listDatasetRecords } from './nocturnal-dataset.js';
|
|
5
|
-
import { listArtifactLineageRecords } from './nocturnal-artifact-lineage.js';
|
|
6
|
-
import { listExports, verifyExportIntegrity } from './nocturnal-export.js';
|
|
7
|
-
import { OpenClawTrinityRuntimeAdapter } from './nocturnal-trinity.js';
|
|
8
4
|
import { resolvePdPath } from './paths.js';
|
|
9
5
|
import type { ReplayReport } from './replay-engine.js';
|
|
10
6
|
|
|
@@ -30,11 +26,6 @@ export interface MergeGateAuditReport {
|
|
|
30
26
|
};
|
|
31
27
|
}
|
|
32
28
|
|
|
33
|
-
function isWithinDir(parentDir: string, candidatePath: string): boolean {
|
|
34
|
-
const relative = path.relative(path.resolve(parentDir), path.resolve(candidatePath));
|
|
35
|
-
return relative === '' || (!relative.startsWith('..') && !path.isAbsolute(relative));
|
|
36
|
-
}
|
|
37
|
-
|
|
38
29
|
function computeOverallStatus(checks: MergeGateAuditCheck[]): MergeGateAuditStatus {
|
|
39
30
|
if (checks.some((check) => check.status === 'block')) {
|
|
40
31
|
return 'block';
|
|
@@ -109,169 +100,6 @@ function auditQueuePathContract(workspaceDir: string): MergeGateAuditCheck {
|
|
|
109
100
|
};
|
|
110
101
|
}
|
|
111
102
|
|
|
112
|
-
function auditRuntimeAdapterContract(): MergeGateAuditCheck {
|
|
113
|
-
// Check the prototype surface only — do NOT instantiate the adapter.
|
|
114
|
-
// Instantiation triggers cleanupStaleTempDirs() which scans os.tmpdir()
|
|
115
|
-
// and could have side effects (removing stale temp dirs of other processes).
|
|
116
|
-
const hasSurface =
|
|
117
|
-
typeof OpenClawTrinityRuntimeAdapter.prototype.isRuntimeAvailable === 'function' &&
|
|
118
|
-
typeof OpenClawTrinityRuntimeAdapter.prototype.getLastFailureReason === 'function';
|
|
119
|
-
|
|
120
|
-
if (!hasSurface) {
|
|
121
|
-
return {
|
|
122
|
-
id: 'runtime_adapter_contract',
|
|
123
|
-
status: 'block',
|
|
124
|
-
summary: 'OpenClaw runtime adapter does not expose the expected contract-check surface.',
|
|
125
|
-
};
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
return {
|
|
129
|
-
id: 'runtime_adapter_contract',
|
|
130
|
-
status: 'pass',
|
|
131
|
-
summary: 'OpenClaw runtime adapter exposes the expected contract-check surface (isRuntimeAvailable, getLastFailureReason).',
|
|
132
|
-
};
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
function auditDatasetArtifactIntegrity(workspaceDir: string): MergeGateAuditCheck {
|
|
136
|
-
const records = listDatasetRecords(workspaceDir);
|
|
137
|
-
if (records.length === 0) {
|
|
138
|
-
return {
|
|
139
|
-
id: 'dataset_artifact_integrity',
|
|
140
|
-
status: 'defer',
|
|
141
|
-
summary: 'No dataset records found. Dataset artifact integrity cannot be verified yet.',
|
|
142
|
-
};
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
const missingArtifacts: string[] = [];
|
|
146
|
-
const outOfWorkspaceArtifacts: string[] = [];
|
|
147
|
-
|
|
148
|
-
for (const record of records) {
|
|
149
|
-
if (!fs.existsSync(record.artifactPath)) {
|
|
150
|
-
missingArtifacts.push(record.sampleFingerprint);
|
|
151
|
-
continue;
|
|
152
|
-
}
|
|
153
|
-
if (!isWithinDir(workspaceDir, record.artifactPath)) {
|
|
154
|
-
outOfWorkspaceArtifacts.push(record.sampleFingerprint);
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
if (missingArtifacts.length > 0 || outOfWorkspaceArtifacts.length > 0) {
|
|
159
|
-
return {
|
|
160
|
-
id: 'dataset_artifact_integrity',
|
|
161
|
-
status: 'block',
|
|
162
|
-
summary: 'Dataset registry points to missing artifacts or paths outside the workspace boundary.',
|
|
163
|
-
details: {
|
|
164
|
-
recordCount: records.length,
|
|
165
|
-
missingArtifacts,
|
|
166
|
-
outOfWorkspaceArtifacts,
|
|
167
|
-
},
|
|
168
|
-
};
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
return {
|
|
172
|
-
id: 'dataset_artifact_integrity',
|
|
173
|
-
status: 'pass',
|
|
174
|
-
summary: 'All dataset artifacts exist and remain inside the workspace boundary.',
|
|
175
|
-
details: {
|
|
176
|
-
recordCount: records.length,
|
|
177
|
-
},
|
|
178
|
-
};
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
function auditArtifactLineageIntegrity(workspaceDir: string): MergeGateAuditCheck {
|
|
182
|
-
const records = listArtifactLineageRecords(workspaceDir);
|
|
183
|
-
if (records.length === 0) {
|
|
184
|
-
return {
|
|
185
|
-
id: 'artifact_lineage_integrity',
|
|
186
|
-
status: 'defer',
|
|
187
|
-
summary: 'No artifact lineage records found. Lineage integrity cannot be verified yet.',
|
|
188
|
-
};
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
const missingStoragePaths: string[] = [];
|
|
192
|
-
const outOfWorkspaceStoragePaths: string[] = [];
|
|
193
|
-
|
|
194
|
-
for (const record of records) {
|
|
195
|
-
if (!fs.existsSync(record.storagePath)) {
|
|
196
|
-
missingStoragePaths.push(record.artifactId);
|
|
197
|
-
continue;
|
|
198
|
-
}
|
|
199
|
-
if (!isWithinDir(workspaceDir, record.storagePath)) {
|
|
200
|
-
outOfWorkspaceStoragePaths.push(record.artifactId);
|
|
201
|
-
}
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
if (missingStoragePaths.length > 0 || outOfWorkspaceStoragePaths.length > 0) {
|
|
205
|
-
return {
|
|
206
|
-
id: 'artifact_lineage_integrity',
|
|
207
|
-
status: 'block',
|
|
208
|
-
summary: 'Artifact lineage points to missing files or paths outside the workspace boundary.',
|
|
209
|
-
details: {
|
|
210
|
-
recordCount: records.length,
|
|
211
|
-
missingStoragePaths,
|
|
212
|
-
outOfWorkspaceStoragePaths,
|
|
213
|
-
},
|
|
214
|
-
};
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
return {
|
|
218
|
-
id: 'artifact_lineage_integrity',
|
|
219
|
-
status: 'pass',
|
|
220
|
-
summary: 'All lineage storage paths exist and remain inside the workspace boundary.',
|
|
221
|
-
details: {
|
|
222
|
-
recordCount: records.length,
|
|
223
|
-
},
|
|
224
|
-
};
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
function auditOrpoExportIntegrity(workspaceDir: string): MergeGateAuditCheck {
|
|
228
|
-
const exports = listExports(workspaceDir);
|
|
229
|
-
if (exports.length === 0) {
|
|
230
|
-
return {
|
|
231
|
-
id: 'orpo_export_integrity',
|
|
232
|
-
status: 'defer',
|
|
233
|
-
summary: 'No ORPO exports found. Export integrity cannot be verified yet.',
|
|
234
|
-
};
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
const invalidExportIds: string[] = [];
|
|
238
|
-
const missingExportFiles: string[] = [];
|
|
239
|
-
|
|
240
|
-
for (const manifest of exports) {
|
|
241
|
-
if (!fs.existsSync(manifest.exportPath)) {
|
|
242
|
-
missingExportFiles.push(manifest.exportId);
|
|
243
|
-
continue;
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
const integrity = verifyExportIntegrity(workspaceDir, manifest.exportId);
|
|
247
|
-
if (!integrity || !integrity.valid) {
|
|
248
|
-
invalidExportIds.push(manifest.exportId);
|
|
249
|
-
}
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
if (invalidExportIds.length > 0 || missingExportFiles.length > 0) {
|
|
253
|
-
return {
|
|
254
|
-
id: 'orpo_export_integrity',
|
|
255
|
-
status: 'block',
|
|
256
|
-
summary: 'ORPO export manifests or payloads failed integrity verification.',
|
|
257
|
-
details: {
|
|
258
|
-
exportCount: exports.length,
|
|
259
|
-
invalidExportIds,
|
|
260
|
-
missingExportFiles,
|
|
261
|
-
},
|
|
262
|
-
};
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
return {
|
|
266
|
-
id: 'orpo_export_integrity',
|
|
267
|
-
status: 'pass',
|
|
268
|
-
summary: 'All ORPO exports pass manifest fingerprint verification.',
|
|
269
|
-
details: {
|
|
270
|
-
exportCount: exports.length,
|
|
271
|
-
},
|
|
272
|
-
};
|
|
273
|
-
}
|
|
274
|
-
|
|
275
103
|
function isReplayReportShape(value: unknown): value is ReplayReport {
|
|
276
104
|
if (!value || typeof value !== 'object') {
|
|
277
105
|
return false;
|
|
@@ -287,9 +115,6 @@ function isReplayReportShape(value: unknown): value is ReplayReport {
|
|
|
287
115
|
);
|
|
288
116
|
}
|
|
289
117
|
|
|
290
|
-
/**
|
|
291
|
-
* Collect all replay report file paths under the implementations directory.
|
|
292
|
-
*/
|
|
293
118
|
function collectReplayReportPaths(stateDir: string): string[] {
|
|
294
119
|
const implementationsRoot = path.join(stateDir, 'principles', 'implementations');
|
|
295
120
|
if (!fs.existsSync(implementationsRoot)) return [];
|
|
@@ -313,9 +138,6 @@ function collectReplayReportPaths(stateDir: string): string[] {
|
|
|
313
138
|
return paths;
|
|
314
139
|
}
|
|
315
140
|
|
|
316
|
-
/**
|
|
317
|
-
* Result of validating a single replay report file.
|
|
318
|
-
*/
|
|
319
141
|
type ReplayValidationCategory =
|
|
320
142
|
| 'io_error'
|
|
321
143
|
| 'malformed'
|
|
@@ -324,9 +146,6 @@ type ReplayValidationCategory =
|
|
|
324
146
|
| 'empty_needs_review'
|
|
325
147
|
| 'valid';
|
|
326
148
|
|
|
327
|
-
/**
|
|
328
|
-
* Check if the parsed replay report has a valid evidenceSummary shape.
|
|
329
|
-
*/
|
|
330
149
|
function hasValidEvidenceSummary(parsed: unknown): boolean {
|
|
331
150
|
if (!parsed || typeof parsed !== 'object') return false;
|
|
332
151
|
const report = parsed as Partial<ReplayReport>;
|
|
@@ -338,11 +157,7 @@ function hasValidEvidenceSummary(parsed: unknown): boolean {
|
|
|
338
157
|
return typeof (summary as Partial<ReplayReport['evidenceSummary']>).totalSamples === 'number';
|
|
339
158
|
}
|
|
340
159
|
|
|
341
|
-
/**
|
|
342
|
-
* Validate a single replay report file and return its category.
|
|
343
|
-
*/
|
|
344
160
|
function validateSingleReplayReport(reportPath: string): ReplayValidationCategory {
|
|
345
|
-
|
|
346
161
|
let rawContent: string;
|
|
347
162
|
try {
|
|
348
163
|
rawContent = fs.readFileSync(reportPath, 'utf-8');
|
|
@@ -350,7 +165,6 @@ function validateSingleReplayReport(reportPath: string): ReplayValidationCategor
|
|
|
350
165
|
return 'io_error';
|
|
351
166
|
}
|
|
352
167
|
|
|
353
|
-
|
|
354
168
|
let parsed: unknown;
|
|
355
169
|
try {
|
|
356
170
|
parsed = JSON.parse(rawContent);
|
|
@@ -366,7 +180,6 @@ function validateSingleReplayReport(reportPath: string): ReplayValidationCategor
|
|
|
366
180
|
return 'missing_evidence_summary';
|
|
367
181
|
}
|
|
368
182
|
|
|
369
|
-
|
|
370
183
|
const evidenceSummary = parsed.evidenceSummary;
|
|
371
184
|
if (parsed.overallDecision === 'pass' && evidenceSummary.totalSamples === 0) {
|
|
372
185
|
return 'unsupported_pass';
|
|
@@ -379,9 +192,6 @@ function validateSingleReplayReport(reportPath: string): ReplayValidationCategor
|
|
|
379
192
|
return 'valid';
|
|
380
193
|
}
|
|
381
194
|
|
|
382
|
-
/**
|
|
383
|
-
* Categorize all replay report files by validation outcome.
|
|
384
|
-
*/
|
|
385
195
|
interface ReplayValidationResults {
|
|
386
196
|
ioErrorReports: string[];
|
|
387
197
|
malformedReports: string[];
|
|
@@ -417,7 +227,6 @@ function categorizeReplayReports(reportPaths: string[]): ReplayValidationResults
|
|
|
417
227
|
case 'empty_needs_review':
|
|
418
228
|
results.emptyEvidenceNeedsReview.push(reportPath);
|
|
419
229
|
break;
|
|
420
|
-
// 'valid' — no action needed
|
|
421
230
|
}
|
|
422
231
|
}
|
|
423
232
|
|
|
@@ -473,10 +282,6 @@ export function runMergeGateAudit(workspaceDir: string, stateDir: string): Merge
|
|
|
473
282
|
const checks: MergeGateAuditCheck[] = [
|
|
474
283
|
auditPainFlagPathContract(workspaceDir),
|
|
475
284
|
auditQueuePathContract(workspaceDir),
|
|
476
|
-
auditRuntimeAdapterContract(),
|
|
477
|
-
auditDatasetArtifactIntegrity(workspaceDir),
|
|
478
|
-
auditArtifactLineageIntegrity(workspaceDir),
|
|
479
|
-
auditOrpoExportIntegrity(workspaceDir),
|
|
480
285
|
auditReplayEvidenceIntegrity(stateDir),
|
|
481
286
|
];
|
|
482
287
|
|
package/src/core/migration.ts
CHANGED
|
@@ -19,7 +19,6 @@ export function migrateDirectoryStructure(api: OpenClawPluginApi, workspaceDir:
|
|
|
19
19
|
{ legacy: path.join(legacyDocsDir, 'PRINCIPLES.md'), newKey: 'PRINCIPLES' },
|
|
20
20
|
{ legacy: path.join(legacyDocsDir, 'THINKING_OS.md'), newKey: 'THINKING_OS' },
|
|
21
21
|
{ legacy: path.join(legacyDocsDir, 'DECISION_POLICY.json'), newKey: 'DECISION_POLICY' },
|
|
22
|
-
{ legacy: path.join(legacyDocsDir, 'PLAN.md'), newKey: 'PLAN' },
|
|
23
22
|
{ legacy: path.join(legacyDocsDir, 'evolution_queue.json'), newKey: 'EVOLUTION_QUEUE' },
|
|
24
23
|
{ legacy: path.join(legacyDocsDir, '.pain_flag'), newKey: 'PAIN_FLAG' },
|
|
25
24
|
{ legacy: path.join(legacyDocsDir, 'SYSTEM_CAPABILITIES.json'), newKey: 'SYSTEM_CAPABILITIES' },
|