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
|
@@ -1,108 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Template Generator
|
|
2
|
+
* Template Generator — Re-export from @principles/core
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
* `export function evaluate(input)` that can be loaded at runtime.
|
|
7
|
-
*
|
|
8
|
-
* SECURITY: All interpolated values use JSON.stringify or safe helpers
|
|
9
|
-
* to prevent code injection through principleId, coversCondition, or regex patterns.
|
|
10
|
-
*/
|
|
11
|
-
|
|
12
|
-
export interface PainPattern {
|
|
13
|
-
toolName: string;
|
|
14
|
-
pathRegex?: string;
|
|
15
|
-
commandRegex?: string;
|
|
16
|
-
contentRegex?: string;
|
|
17
|
-
errorType?: string;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
/**
|
|
21
|
-
* Derives the auto-rule display name from a principle ID.
|
|
22
|
-
*/
|
|
23
|
-
function toAutoName(principleId: string): string {
|
|
24
|
-
return `Auto_${principleId}`;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
/**
|
|
28
|
-
* Derives the auto-rule ID from a principle ID.
|
|
29
|
-
* Must match ledger-registrar convention: "P_066" => "R_P_066_auto"
|
|
30
|
-
*/
|
|
31
|
-
function toAutoRuleId(principleId: string): string {
|
|
32
|
-
return `R_${principleId}_auto`;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
/**
|
|
36
|
-
* Builds a single `if` branch for a pain pattern.
|
|
37
|
-
*
|
|
38
|
-
* SECURITY: Uses `new RegExp(JSON.stringify(...))` instead of regex literals
|
|
39
|
-
* to prevent code injection through pathRegex/commandRegex/contentRegex values.
|
|
40
|
-
* principleId in reason uses JSON.stringify to prevent string breakout.
|
|
4
|
+
* PRI-44: Pure template generation logic moved to core.
|
|
5
|
+
* This file re-exports for backward compatibility.
|
|
41
6
|
*/
|
|
42
|
-
function buildBranch(principleId: string, pattern: PainPattern): string {
|
|
43
|
-
const conditions: string[] = [];
|
|
44
|
-
|
|
45
|
-
conditions.push(`input.action.toolName === ${JSON.stringify(pattern.toolName)}`);
|
|
46
|
-
|
|
47
|
-
if (pattern.pathRegex) {
|
|
48
|
-
conditions.push(`new RegExp(${JSON.stringify(pattern.pathRegex)}).test(input.action.normalizedPath || '')`);
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
if (pattern.commandRegex) {
|
|
52
|
-
conditions.push(`new RegExp(${JSON.stringify(pattern.commandRegex)}).test(input.action.paramsSummary.command || '')`);
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
if (pattern.contentRegex) {
|
|
56
|
-
conditions.push(
|
|
57
|
-
`new RegExp(${JSON.stringify(pattern.contentRegex)}).test(input.action.paramsSummary.content || input.action.paramsSummary.new_string || '')`,
|
|
58
|
-
);
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
const guard = conditions.join(' && ');
|
|
62
|
-
const reason = `[${principleId}] Blocked by auto-generated rule`;
|
|
63
|
-
|
|
64
|
-
return (
|
|
65
|
-
` if (${guard}) {\n` +
|
|
66
|
-
` return { decision: 'block', matched: true, reason: ${JSON.stringify(reason)} };\n` +
|
|
67
|
-
` }`
|
|
68
|
-
);
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
/**
|
|
72
|
-
* Generates sandbox-ready JS code from a principle ID and pain patterns.
|
|
73
|
-
*
|
|
74
|
-
* Returns `null` when `patterns` is empty.
|
|
75
|
-
*/
|
|
76
|
-
export function generateFromTemplate(
|
|
77
|
-
principleId: string,
|
|
78
|
-
coversCondition: string,
|
|
79
|
-
patterns: PainPattern[],
|
|
80
|
-
): string | null {
|
|
81
|
-
if (patterns.length === 0) {
|
|
82
|
-
return null;
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
const name = toAutoName(principleId);
|
|
86
|
-
const ruleId = toAutoRuleId(principleId);
|
|
87
|
-
const compiledAt = new Date().toISOString();
|
|
88
|
-
|
|
89
|
-
const branches = patterns
|
|
90
|
-
.map((p) => buildBranch(principleId, p))
|
|
91
|
-
.join('\n');
|
|
92
7
|
|
|
93
|
-
|
|
94
|
-
`// Auto-generated by Principle Compiler\n` +
|
|
95
|
-
`export const meta = {\n` +
|
|
96
|
-
` name: ${JSON.stringify(name)},\n` +
|
|
97
|
-
` version: '1.0.0',\n` +
|
|
98
|
-
` ruleId: ${JSON.stringify(ruleId)},\n` +
|
|
99
|
-
` coversCondition: ${JSON.stringify(coversCondition)},\n` +
|
|
100
|
-
` compiledAt: ${JSON.stringify(compiledAt)},\n` +
|
|
101
|
-
` sourcePrincipleId: ${JSON.stringify(principleId)},\n` +
|
|
102
|
-
`};\n\n` +
|
|
103
|
-
`export function evaluate(input) {\n` +
|
|
104
|
-
`${branches}\n` +
|
|
105
|
-
` return { matched: false };\n` +
|
|
106
|
-
`}\n`
|
|
107
|
-
);
|
|
108
|
-
}
|
|
8
|
+
export { generateFromTemplate, type PainPattern } from '@principles/core/runtime-v2';
|
|
@@ -1,208 +1,16 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Principle Injection — Budget-Aware Principle Selection
|
|
3
|
-
* ========================================================
|
|
4
3
|
*
|
|
5
|
-
*
|
|
6
|
-
* prioritizing by priority tier (P0 > P1 > P2) and recency, while ensuring
|
|
7
|
-
* at least one P0 principle is included when available.
|
|
4
|
+
* Phase: PRI-75 Prompt Injection SDK Migration Phase 2
|
|
8
5
|
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
* - Within same priority, sorts by recency (createdAt descending)
|
|
12
|
-
* - Selects principles until the cumulative character budget is exceeded
|
|
13
|
-
* - Guarantees at least one P0 principle is included if any exist
|
|
14
|
-
* - Returns the selected principles and total character usage
|
|
15
|
-
*
|
|
16
|
-
* This replaces the previous hardcoded slice(-3)/slice(0,5) approach in
|
|
17
|
-
* prompt.ts with a budget-aware, priority-respecting selection algorithm.
|
|
18
|
-
*/
|
|
19
|
-
|
|
20
|
-
import type { PrinciplePriority } from '../types/principle-tree-schema.js';
|
|
21
|
-
|
|
22
|
-
// ---------------------------------------------------------------------------
|
|
23
|
-
// Types
|
|
24
|
-
// ---------------------------------------------------------------------------
|
|
25
|
-
|
|
26
|
-
/**
|
|
27
|
-
* Minimal principle shape required for injection selection.
|
|
28
|
-
* Accepts both evolution-types.Principle and principle-tree-schema.Principle.
|
|
29
|
-
*/
|
|
30
|
-
export interface InjectablePrinciple {
|
|
31
|
-
id: string;
|
|
32
|
-
text: string;
|
|
33
|
-
/** Priority level. Defaults to 'P1' if not set by the source. */
|
|
34
|
-
priority?: PrinciplePriority;
|
|
35
|
-
createdAt: string;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
/**
|
|
39
|
-
* Result of principle selection for injection.
|
|
40
|
-
*/
|
|
41
|
-
export interface PrincipleSelectionResult {
|
|
42
|
-
/** Selected principles in injection order (priority-first, then recency) */
|
|
43
|
-
selected: InjectablePrinciple[];
|
|
44
|
-
/** Total character count of selected principles' formatted output */
|
|
45
|
-
totalChars: number;
|
|
46
|
-
/** Number of principles by priority tier */
|
|
47
|
-
breakdown: {
|
|
48
|
-
p0: number;
|
|
49
|
-
p1: number;
|
|
50
|
-
p2: number;
|
|
51
|
-
};
|
|
52
|
-
/** Whether at least one P0 principle was included */
|
|
53
|
-
hasP0: boolean;
|
|
54
|
-
/** Whether the selection was truncated due to budget */
|
|
55
|
-
wasTruncated: boolean;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
// ---------------------------------------------------------------------------
|
|
59
|
-
// Priority Ordering
|
|
60
|
-
// ---------------------------------------------------------------------------
|
|
61
|
-
|
|
62
|
-
const PRIORITY_ORDER: Record<PrinciplePriority, number> = {
|
|
63
|
-
P0: 0,
|
|
64
|
-
P1: 1,
|
|
65
|
-
P2: 2,
|
|
66
|
-
};
|
|
67
|
-
|
|
68
|
-
/**
|
|
69
|
-
* Compare two principles for sorting.
|
|
70
|
-
* Primary: priority (P0 < P1 < P2 — lower is higher priority).
|
|
71
|
-
* Secondary: recency (newer createdAt first).
|
|
72
|
-
*/
|
|
73
|
-
function comparePrinciples(a: InjectablePrinciple, b: InjectablePrinciple): number {
|
|
74
|
-
const priorityA = PRIORITY_ORDER[a.priority ?? 'P1'] ?? 99;
|
|
75
|
-
const priorityB = PRIORITY_ORDER[b.priority ?? 'P1'] ?? 99;
|
|
76
|
-
|
|
77
|
-
if (priorityA !== priorityB) {
|
|
78
|
-
return priorityA - priorityB;
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
// Same priority: sort by recency (newer first)
|
|
82
|
-
return b.createdAt.localeCompare(a.createdAt);
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
// ---------------------------------------------------------------------------
|
|
86
|
-
// Formatting
|
|
87
|
-
// ---------------------------------------------------------------------------
|
|
88
|
-
|
|
89
|
-
/**
|
|
90
|
-
* Format a single principle for injection.
|
|
91
|
-
* Returns the formatted string including ID and text.
|
|
92
|
-
*
|
|
93
|
-
* Format: "- [ID] text" (matches existing prompt.ts format)
|
|
6
|
+
* This file is now a thin re-export layer.
|
|
7
|
+
* All pure logic lives in @principles/core/prompt-builder/principle-selection.ts.
|
|
94
8
|
*/
|
|
95
|
-
export function formatPrinciple(p: InjectablePrinciple): string {
|
|
96
|
-
return `- [${p.id}] ${p.text}`;
|
|
97
|
-
}
|
|
98
9
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
// ---------------------------------------------------------------------------
|
|
107
|
-
// Selection Algorithm
|
|
108
|
-
// ---------------------------------------------------------------------------
|
|
109
|
-
|
|
110
|
-
/**
|
|
111
|
-
* Select principles for prompt injection within a character budget.
|
|
112
|
-
*
|
|
113
|
-
* Algorithm:
|
|
114
|
-
* 1. Sort all principles by priority (P0 > P1 > P2), then by recency
|
|
115
|
-
* 2. Iterate through sorted principles, accumulating character count
|
|
116
|
-
* 3. Stop when adding the next principle would exceed budgetChars
|
|
117
|
-
* 4. Ensure at least one P0 principle is included (even if it exceeds budget)
|
|
118
|
-
*
|
|
119
|
-
* @param principles - All available principles to select from
|
|
120
|
-
* @param budgetChars - Maximum character budget for formatted output
|
|
121
|
-
* @returns Selection result with chosen principles and metadata
|
|
122
|
-
*/
|
|
123
|
-
export function selectPrinciplesForInjection(
|
|
124
|
-
principles: InjectablePrinciple[],
|
|
125
|
-
budgetChars: number,
|
|
126
|
-
): PrincipleSelectionResult {
|
|
127
|
-
if (principles.length === 0) {
|
|
128
|
-
return {
|
|
129
|
-
selected: [],
|
|
130
|
-
totalChars: 0,
|
|
131
|
-
breakdown: { p0: 0, p1: 0, p2: 0 },
|
|
132
|
-
hasP0: false,
|
|
133
|
-
wasTruncated: false,
|
|
134
|
-
};
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
// Sort by priority then recency
|
|
138
|
-
const sorted = [...principles].sort(comparePrinciples);
|
|
139
|
-
|
|
140
|
-
const selected: InjectablePrinciple[] = [];
|
|
141
|
-
let totalChars = 0;
|
|
142
|
-
let p0Included = false;
|
|
143
|
-
let wasTruncated = false;
|
|
144
|
-
|
|
145
|
-
for (const principle of sorted) {
|
|
146
|
-
const cost = formattedLength(principle);
|
|
147
|
-
|
|
148
|
-
// Check if adding this principle would exceed budget
|
|
149
|
-
if (totalChars + cost > budgetChars) {
|
|
150
|
-
// Special case: if no P0 has been included yet, force-include the first P0
|
|
151
|
-
// even if it exceeds the budget (P0 principles are critical)
|
|
152
|
-
if (!p0Included && principle.priority === 'P0') {
|
|
153
|
-
selected.push(principle);
|
|
154
|
-
totalChars += cost;
|
|
155
|
-
p0Included = true;
|
|
156
|
-
wasTruncated = true;
|
|
157
|
-
// Continue to try to fit more principles after this forced inclusion
|
|
158
|
-
continue;
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
wasTruncated = true;
|
|
162
|
-
break;
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
selected.push(principle);
|
|
166
|
-
totalChars += cost;
|
|
167
|
-
if (principle.priority === 'P0') {
|
|
168
|
-
p0Included = true;
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
// Safety net: if we went through all principles and still no P0 included
|
|
173
|
-
// (because P0 was beyond budget threshold), force-include the first P0
|
|
174
|
-
if (!p0Included) {
|
|
175
|
-
const firstP0 = sorted.find(p => p.priority === 'P0');
|
|
176
|
-
if (firstP0 && !selected.includes(firstP0)) {
|
|
177
|
-
// Insert P0 at the beginning of selected (highest priority)
|
|
178
|
-
selected.unshift(firstP0);
|
|
179
|
-
totalChars += formattedLength(firstP0);
|
|
180
|
-
p0Included = true;
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
const breakdown = {
|
|
185
|
-
p0: selected.filter(p => (p.priority ?? 'P1') === 'P0').length,
|
|
186
|
-
p1: selected.filter(p => (p.priority ?? 'P1') === 'P1').length,
|
|
187
|
-
p2: selected.filter(p => (p.priority ?? 'P1') === 'P2').length,
|
|
188
|
-
};
|
|
189
|
-
|
|
190
|
-
return {
|
|
191
|
-
selected,
|
|
192
|
-
totalChars,
|
|
193
|
-
breakdown,
|
|
194
|
-
hasP0: p0Included,
|
|
195
|
-
wasTruncated,
|
|
196
|
-
};
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
// ---------------------------------------------------------------------------
|
|
200
|
-
// Default Budget
|
|
201
|
-
// ---------------------------------------------------------------------------
|
|
202
|
-
|
|
203
|
-
/**
|
|
204
|
-
* Default character budget for principle injection.
|
|
205
|
-
* 4000 characters is ~800 tokens, leaving ample room for other prompt sections
|
|
206
|
-
* within the 10K character injection limit.
|
|
207
|
-
*/
|
|
208
|
-
export const DEFAULT_PRINCIPLE_BUDGET = 4000;
|
|
10
|
+
// Re-exported from core for backward compatibility with existing imports
|
|
11
|
+
export {
|
|
12
|
+
formatPrinciple,
|
|
13
|
+
selectPrinciplesForInjection,
|
|
14
|
+
DEFAULT_PRINCIPLE_BUDGET,
|
|
15
|
+
} from '@principles/core/prompt-builder';
|
|
16
|
+
export type { InjectablePrinciple, PrincipleSelectionResult } from '@principles/core/prompt-builder';
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import type { LifecycleDatasource } from '@principles/core/runtime-v2';
|
|
2
|
+
import type { LedgerTreeStore, ReplayReport, ArtifactLineageRecord } from '@principles/core/runtime-v2';
|
|
3
|
+
import { loadLedger } from '../principle-tree-ledger.js';
|
|
4
|
+
import { ReplayEngine } from '../replay-engine.js';
|
|
5
|
+
|
|
6
|
+
export class LineageSourceRetiredError extends Error {
|
|
7
|
+
constructor() {
|
|
8
|
+
super(
|
|
9
|
+
'Artifact lineage source retired in PRI-230. ' +
|
|
10
|
+
'The nocturnal-artifact-lineage module has been deleted; ' +
|
|
11
|
+
'this datasource cannot provide lineage records. ' +
|
|
12
|
+
'Callers must handle this error explicitly rather than interpreting an empty result as "no lineage".'
|
|
13
|
+
);
|
|
14
|
+
this.name = 'LineageSourceRetiredError';
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export class FilesystemLifecycleDatasource implements LifecycleDatasource {
|
|
19
|
+
private _engine?: ReplayEngine;
|
|
20
|
+
|
|
21
|
+
constructor(
|
|
22
|
+
private readonly workspaceDir: string,
|
|
23
|
+
private readonly stateDir: string,
|
|
24
|
+
) {}
|
|
25
|
+
|
|
26
|
+
private get engine(): ReplayEngine {
|
|
27
|
+
if (!this._engine) this._engine = new ReplayEngine(this.workspaceDir, this.stateDir);
|
|
28
|
+
return this._engine;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
loadLedger(): LedgerTreeStore {
|
|
32
|
+
return loadLedger(this.stateDir).tree as unknown as LedgerTreeStore;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
listReplayReports(implementationId: string): ReplayReport[] {
|
|
36
|
+
return this.engine.listReports(implementationId);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
listLineageRecords(_kind: 'behavioral-sample' | 'rule-implementation-candidate'): ArtifactLineageRecord[] {
|
|
40
|
+
throw new LineageSourceRetiredError();
|
|
41
|
+
}
|
|
42
|
+
}
|
|
@@ -1,243 +1,40 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
export interface ImplementationLifecycleEvidence {
|
|
43
|
-
implementation: Implementation;
|
|
44
|
-
latestReplayReport: ReplayReport | null;
|
|
45
|
-
replayHistoryCount: number;
|
|
46
|
-
lineageRecords: ArtifactLineageRecord[];
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
export interface RuleLifecycleEvidence {
|
|
50
|
-
rule: LedgerRule;
|
|
51
|
-
implementations: ImplementationLifecycleEvidence[];
|
|
52
|
-
replayEvidence: RuleReplayEvidence;
|
|
53
|
-
liveEvidence: RuleLiveEvidence;
|
|
54
|
-
lineageEvidence: RuleLineageEvidence;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
export interface PrincipleLifecycleEvidence {
|
|
58
|
-
principle: LedgerPrinciple;
|
|
59
|
-
rules: RuleLifecycleEvidence[];
|
|
60
|
-
summary: {
|
|
61
|
-
replayReportCount: number;
|
|
62
|
-
activeImplementationCount: number;
|
|
63
|
-
candidateImplementationCount: number;
|
|
64
|
-
disabledImplementationCount: number;
|
|
65
|
-
archivedImplementationCount: number;
|
|
66
|
-
distinctPainSignalCount: number;
|
|
67
|
-
distinctGateBlockCount: number;
|
|
68
|
-
repeatedErrorSignal: number;
|
|
69
|
-
};
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
export interface LifecycleReadModel {
|
|
73
|
-
generatedAt: string;
|
|
74
|
-
principles: PrincipleLifecycleEvidence[];
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
function toClassificationTotals(summary: ClassificationSummary[]): LifecycleClassificationTotals {
|
|
78
|
-
return summary.reduce<LifecycleClassificationTotals>(
|
|
79
|
-
(totals, entry) => ({
|
|
80
|
-
total: totals.total + entry.total,
|
|
81
|
-
passed: totals.passed + entry.passed,
|
|
82
|
-
failed: totals.failed + entry.failed,
|
|
83
|
-
}),
|
|
84
|
-
{ total: 0, passed: 0, failed: 0 },
|
|
85
|
-
);
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
function countByLifecycle(implementations: Implementation[], lifecycleState: ImplementationLifecycleState): number {
|
|
89
|
-
return implementations.filter((implementation) => implementation.lifecycleState === lifecycleState).length;
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
function hasDurablePenalty(implementation: Implementation): boolean {
|
|
93
|
-
if (implementation.lifecycleState === 'disabled' || implementation.lifecycleState === 'archived') {
|
|
94
|
-
return true;
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
return typeof implementation.disabledReason === 'string' && implementation.disabledReason.trim().length > 0;
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
function hasRollbackEvidence(implementation: Implementation): boolean {
|
|
101
|
-
return typeof implementation.previousActive === 'string' && implementation.previousActive.length > 0;
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
function createRuleReplayEvidence(reports: { implementationId: string; report: ReplayReport }[]): RuleReplayEvidence {
|
|
105
|
-
return {
|
|
106
|
-
reportCount: reports.length,
|
|
107
|
-
latestReports: reports.map((entry) => entry.report),
|
|
108
|
-
painNegative: toClassificationTotals(reports.map((entry) => entry.report.replayResults.painNegative)),
|
|
109
|
-
successPositive: toClassificationTotals(reports.map((entry) => entry.report.replayResults.successPositive)),
|
|
110
|
-
principleAnchor: toClassificationTotals(reports.map((entry) => entry.report.replayResults.principleAnchor)),
|
|
111
|
-
passingImplementationIds: reports
|
|
112
|
-
.filter((entry) => entry.report.overallDecision === 'pass')
|
|
113
|
-
.map((entry) => entry.implementationId),
|
|
114
|
-
failingImplementationIds: reports
|
|
115
|
-
.filter((entry) => entry.report.overallDecision === 'fail')
|
|
116
|
-
.map((entry) => entry.implementationId),
|
|
117
|
-
needsReviewImplementationIds: reports
|
|
118
|
-
.filter((entry) => entry.report.overallDecision === 'needs-review')
|
|
119
|
-
.map((entry) => entry.implementationId),
|
|
120
|
-
};
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
function createRuleLineageEvidence(records: ArtifactLineageRecord[]): RuleLineageEvidence {
|
|
124
|
-
const painIds = new Set<string>();
|
|
125
|
-
const gateBlockIds = new Set<string>();
|
|
126
|
-
|
|
127
|
-
for (const record of records) {
|
|
128
|
-
for (const painId of record.sourcePainIds) {
|
|
129
|
-
painIds.add(painId);
|
|
130
|
-
}
|
|
131
|
-
for (const gateBlockId of record.sourceGateBlockIds) {
|
|
132
|
-
gateBlockIds.add(gateBlockId);
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
const latestCreatedAt =
|
|
137
|
-
records.length > 0
|
|
138
|
-
? records
|
|
139
|
-
.map((record) => record.createdAt)
|
|
140
|
-
.sort((left, right) => new Date(right).getTime() - new Date(left).getTime())[0]
|
|
141
|
-
: undefined;
|
|
142
|
-
|
|
143
|
-
return {
|
|
144
|
-
records,
|
|
145
|
-
distinctPainSignalCount: painIds.size,
|
|
146
|
-
distinctGateBlockCount: gateBlockIds.size,
|
|
147
|
-
repeatedErrorSignal: painIds.size + gateBlockIds.size,
|
|
148
|
-
latestCreatedAt,
|
|
149
|
-
};
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
function createRuleLiveEvidence(
|
|
153
|
-
implementations: Implementation[],
|
|
154
|
-
replayEvidence: RuleReplayEvidence,
|
|
155
|
-
): RuleLiveEvidence {
|
|
156
|
-
const activeImplementations = implementations.filter((implementation) => implementation.lifecycleState === 'active');
|
|
157
|
-
|
|
158
|
-
return {
|
|
159
|
-
activeCount: countByLifecycle(implementations, 'active'),
|
|
160
|
-
candidateCount: countByLifecycle(implementations, 'candidate'),
|
|
161
|
-
disabledCount: countByLifecycle(implementations, 'disabled'),
|
|
162
|
-
archivedCount: countByLifecycle(implementations, 'archived'),
|
|
163
|
-
durablePenaltyCount: implementations.filter((implementation) => hasDurablePenalty(implementation)).length,
|
|
164
|
-
rollbackEvidenceCount: implementations.filter((implementation) => hasRollbackEvidence(implementation)).length,
|
|
165
|
-
hasActiveImplementation: activeImplementations.length > 0,
|
|
166
|
-
hasPassingActiveImplementation: activeImplementations.some((implementation) =>
|
|
167
|
-
replayEvidence.passingImplementationIds.includes(implementation.id),
|
|
168
|
-
),
|
|
169
|
-
};
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
export function buildLifecycleReadModel(workspaceDir: string, stateDir: string): LifecycleReadModel {
|
|
173
|
-
const ledger = loadLedger(stateDir);
|
|
174
|
-
const replayEngine = new ReplayEngine(workspaceDir, stateDir);
|
|
175
|
-
const lineageRecords = listArtifactLineageRecords(workspaceDir, 'rule-implementation-candidate');
|
|
176
|
-
|
|
177
|
-
const principles = Object.values(ledger.tree.principles)
|
|
178
|
-
.map((principle): PrincipleLifecycleEvidence => {
|
|
179
|
-
const rules = principle.ruleIds
|
|
180
|
-
.map((ruleId) => ledger.tree.rules[ruleId])
|
|
181
|
-
.filter((rule): rule is LedgerRule => rule !== undefined)
|
|
182
|
-
.map((rule): RuleLifecycleEvidence => {
|
|
183
|
-
const implementations = rule.implementationIds
|
|
184
|
-
.map((implementationId) => ledger.tree.implementations[implementationId])
|
|
185
|
-
.filter((implementation): implementation is Implementation => implementation !== undefined);
|
|
186
|
-
|
|
187
|
-
const implementationEvidence: ImplementationLifecycleEvidence[] = implementations.map((implementation) => {
|
|
188
|
-
const reports = replayEngine.listReports(implementation.id);
|
|
189
|
-
const implementationLineage = lineageRecords.filter(
|
|
190
|
-
(record) => record.ruleId === rule.id || record.implementationId === implementation.id,
|
|
191
|
-
);
|
|
192
|
-
|
|
193
|
-
return {
|
|
194
|
-
implementation,
|
|
195
|
-
latestReplayReport: reports[0] ?? null,
|
|
196
|
-
replayHistoryCount: reports.length,
|
|
197
|
-
lineageRecords: implementationLineage,
|
|
198
|
-
};
|
|
199
|
-
});
|
|
200
|
-
|
|
201
|
-
const replayEvidence = createRuleReplayEvidence(
|
|
202
|
-
implementationEvidence
|
|
203
|
-
.filter((entry) => entry.latestReplayReport !== null)
|
|
204
|
-
.map((entry) => ({
|
|
205
|
-
implementationId: entry.implementation.id,
|
|
206
|
-
report: entry.latestReplayReport as ReplayReport,
|
|
207
|
-
})),
|
|
208
|
-
);
|
|
209
|
-
const ruleLineageRecords = lineageRecords.filter((record) => record.ruleId === rule.id);
|
|
210
|
-
const lineageEvidence = createRuleLineageEvidence(ruleLineageRecords);
|
|
211
|
-
const liveEvidence = createRuleLiveEvidence(implementations, replayEvidence);
|
|
212
|
-
|
|
213
|
-
return {
|
|
214
|
-
rule,
|
|
215
|
-
implementations: implementationEvidence,
|
|
216
|
-
replayEvidence,
|
|
217
|
-
liveEvidence,
|
|
218
|
-
lineageEvidence,
|
|
219
|
-
};
|
|
220
|
-
});
|
|
221
|
-
|
|
222
|
-
return {
|
|
223
|
-
principle,
|
|
224
|
-
rules,
|
|
225
|
-
summary: {
|
|
226
|
-
replayReportCount: rules.reduce((sum, rule) => sum + rule.replayEvidence.reportCount, 0),
|
|
227
|
-
activeImplementationCount: rules.reduce((sum, rule) => sum + rule.liveEvidence.activeCount, 0),
|
|
228
|
-
candidateImplementationCount: rules.reduce((sum, rule) => sum + rule.liveEvidence.candidateCount, 0),
|
|
229
|
-
disabledImplementationCount: rules.reduce((sum, rule) => sum + rule.liveEvidence.disabledCount, 0),
|
|
230
|
-
archivedImplementationCount: rules.reduce((sum, rule) => sum + rule.liveEvidence.archivedCount, 0),
|
|
231
|
-
distinctPainSignalCount: rules.reduce((sum, rule) => sum + rule.lineageEvidence.distinctPainSignalCount, 0),
|
|
232
|
-
distinctGateBlockCount: rules.reduce((sum, rule) => sum + rule.lineageEvidence.distinctGateBlockCount, 0),
|
|
233
|
-
repeatedErrorSignal: rules.reduce((sum, rule) => sum + rule.lineageEvidence.repeatedErrorSignal, 0),
|
|
234
|
-
},
|
|
235
|
-
};
|
|
236
|
-
})
|
|
237
|
-
.sort((left, right) => left.principle.id.localeCompare(right.principle.id));
|
|
238
|
-
|
|
239
|
-
return {
|
|
240
|
-
generatedAt: new Date().toISOString(),
|
|
241
|
-
principles,
|
|
242
|
-
};
|
|
1
|
+
/**
|
|
2
|
+
* Lifecycle read model — re-export facade (PRI-56).
|
|
3
|
+
*
|
|
4
|
+
* All computation lives in @principles/core/runtime-v2.
|
|
5
|
+
* This file re-exports types, the core builder, and provides
|
|
6
|
+
* a backward-compatible path-based wrapper for existing consumers.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
// Re-export lifecycle types from core (PRI-51)
|
|
10
|
+
export type {
|
|
11
|
+
LifecycleClassificationTotals,
|
|
12
|
+
RuleReplayEvidence,
|
|
13
|
+
RuleLiveEvidence,
|
|
14
|
+
RuleLineageEvidence,
|
|
15
|
+
ImplementationLifecycleEvidence,
|
|
16
|
+
RuleLifecycleEvidence,
|
|
17
|
+
PrincipleLifecycleEvidence,
|
|
18
|
+
LifecycleReadModel,
|
|
19
|
+
} from '@principles/core/runtime-v2';
|
|
20
|
+
|
|
21
|
+
// Re-export core builder (PRI-56)
|
|
22
|
+
export { buildLifecycleReadModel } from '@principles/core/runtime-v2';
|
|
23
|
+
|
|
24
|
+
// Re-export adapter interface (PRI-56)
|
|
25
|
+
export type { LifecycleDatasource } from '@principles/core/runtime-v2';
|
|
26
|
+
|
|
27
|
+
// Re-export filesystem implementation (PRI-56)
|
|
28
|
+
export { FilesystemLifecycleDatasource, LineageSourceRetiredError } from './filesystem-lifecycle-datasource.js';
|
|
29
|
+
|
|
30
|
+
import { buildLifecycleReadModel } from '@principles/core/runtime-v2';
|
|
31
|
+
import { FilesystemLifecycleDatasource } from './filesystem-lifecycle-datasource.js';
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Backward-compatible wrapper — accepts directory paths like the original API.
|
|
35
|
+
* Existing consumers (lifecycle-refresh, evolution-status, nocturnal-service)
|
|
36
|
+
* continue using this without changes.
|
|
37
|
+
*/
|
|
38
|
+
export function buildLifecycleReadModelFromPaths(workspaceDir: string, stateDir: string) {
|
|
39
|
+
return buildLifecycleReadModel(new FilesystemLifecycleDatasource(workspaceDir, stateDir));
|
|
243
40
|
}
|