@principles/pd-cli 1.133.0 → 1.134.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/dist/commands/__tests__/intent-flag-wiring.test.js +74 -3
- package/dist/commands/__tests__/intent-flag-wiring.test.js.map +1 -1
- package/dist/commands/__tests__/pain-retry-maxTokens-flag.test.d.ts +2 -0
- package/dist/commands/__tests__/pain-retry-maxTokens-flag.test.d.ts.map +1 -0
- package/dist/commands/__tests__/pain-retry-maxTokens-flag.test.js +60 -0
- package/dist/commands/__tests__/pain-retry-maxTokens-flag.test.js.map +1 -0
- package/dist/commands/__tests__/rulecode-flag-wiring.test.js +11 -4
- package/dist/commands/__tests__/rulecode-flag-wiring.test.js.map +1 -1
- package/dist/commands/__tests__/run-rulehost-flag-wiring.test.js +9 -0
- package/dist/commands/__tests__/run-rulehost-flag-wiring.test.js.map +1 -1
- package/dist/commands/admission-gate.d.ts +24 -0
- package/dist/commands/admission-gate.d.ts.map +1 -0
- package/dist/commands/admission-gate.js +29 -0
- package/dist/commands/admission-gate.js.map +1 -0
- package/dist/commands/candidate.d.ts.map +1 -1
- package/dist/commands/candidate.js +72 -6
- package/dist/commands/candidate.js.map +1 -1
- package/dist/commands/console.d.ts.map +1 -1
- package/dist/commands/console.js +40 -0
- package/dist/commands/console.js.map +1 -1
- package/dist/commands/demo-story-a.d.ts.map +1 -1
- package/dist/commands/demo-story-a.js +4 -2
- package/dist/commands/demo-story-a.js.map +1 -1
- package/dist/commands/diagnose.d.ts.map +1 -1
- package/dist/commands/diagnose.js +155 -8
- package/dist/commands/diagnose.js.map +1 -1
- package/dist/commands/errors-list.d.ts +25 -0
- package/dist/commands/errors-list.d.ts.map +1 -0
- package/dist/commands/errors-list.js +368 -0
- package/dist/commands/errors-list.js.map +1 -0
- package/dist/commands/health-codex.d.ts +7 -0
- package/dist/commands/health-codex.d.ts.map +1 -0
- package/dist/commands/health-codex.js +209 -0
- package/dist/commands/health-codex.js.map +1 -0
- package/dist/commands/health.d.ts +24 -0
- package/dist/commands/health.d.ts.map +1 -1
- package/dist/commands/health.js +48 -0
- package/dist/commands/health.js.map +1 -1
- package/dist/commands/intent.d.ts +21 -4
- package/dist/commands/intent.d.ts.map +1 -1
- package/dist/commands/intent.js +88 -27
- package/dist/commands/intent.js.map +1 -1
- package/dist/commands/pain-evidence.d.ts +6 -0
- package/dist/commands/pain-evidence.d.ts.map +1 -1
- package/dist/commands/pain-evidence.js +6 -0
- package/dist/commands/pain-evidence.js.map +1 -1
- package/dist/commands/pain-record.d.ts.map +1 -1
- package/dist/commands/pain-record.js +21 -0
- package/dist/commands/pain-record.js.map +1 -1
- package/dist/commands/pain-retry.d.ts +4 -0
- package/dist/commands/pain-retry.d.ts.map +1 -1
- package/dist/commands/pain-retry.js +327 -32
- package/dist/commands/pain-retry.js.map +1 -1
- package/dist/commands/proven-channel-baseline.d.ts.map +1 -1
- package/dist/commands/proven-channel-baseline.js +4 -2
- package/dist/commands/proven-channel-baseline.js.map +1 -1
- package/dist/commands/runtime-activation.d.ts +30 -0
- package/dist/commands/runtime-activation.d.ts.map +1 -1
- package/dist/commands/runtime-activation.js +567 -11
- package/dist/commands/runtime-activation.js.map +1 -1
- package/dist/commands/runtime-canary.d.ts.map +1 -1
- package/dist/commands/runtime-canary.js +32 -7
- package/dist/commands/runtime-canary.js.map +1 -1
- package/dist/commands/runtime-health-snapshot.d.ts.map +1 -1
- package/dist/commands/runtime-health-snapshot.js +4 -2
- package/dist/commands/runtime-health-snapshot.js.map +1 -1
- package/dist/commands/runtime-init.d.ts +43 -0
- package/dist/commands/runtime-init.d.ts.map +1 -0
- package/dist/commands/runtime-init.js +264 -0
- package/dist/commands/runtime-init.js.map +1 -0
- package/dist/commands/runtime-internalization-context-trace.d.ts +25 -0
- package/dist/commands/runtime-internalization-context-trace.d.ts.map +1 -0
- package/dist/commands/runtime-internalization-context-trace.js +374 -0
- package/dist/commands/runtime-internalization-context-trace.js.map +1 -0
- package/dist/commands/runtime-internalization-enqueue-successors.d.ts.map +1 -1
- package/dist/commands/runtime-internalization-enqueue-successors.js +3 -1
- package/dist/commands/runtime-internalization-enqueue-successors.js.map +1 -1
- package/dist/commands/runtime-internalization-integrity.d.ts.map +1 -1
- package/dist/commands/runtime-internalization-integrity.js +4 -2
- package/dist/commands/runtime-internalization-integrity.js.map +1 -1
- package/dist/commands/runtime-internalization-run-once.d.ts.map +1 -1
- package/dist/commands/runtime-internalization-run-once.js +20 -5
- package/dist/commands/runtime-internalization-run-once.js.map +1 -1
- package/dist/commands/runtime-internalization-run-rulehost.d.ts +1 -0
- package/dist/commands/runtime-internalization-run-rulehost.d.ts.map +1 -1
- package/dist/commands/runtime-internalization-run-rulehost.js +149 -6
- package/dist/commands/runtime-internalization-run-rulehost.js.map +1 -1
- package/dist/commands/runtime-uat.d.ts.map +1 -1
- package/dist/commands/runtime-uat.guard.test.js +13 -15
- package/dist/commands/runtime-uat.guard.test.js.map +1 -1
- package/dist/commands/runtime-uat.js +4 -3
- package/dist/commands/runtime-uat.js.map +1 -1
- package/dist/config-reader.js +1 -1
- package/dist/config-reader.js.map +1 -1
- package/dist/index.js +54 -78
- package/dist/index.js.map +1 -1
- package/dist/services/__tests__/evaluator-runner-deps.test.d.ts +2 -0
- package/dist/services/__tests__/evaluator-runner-deps.test.d.ts.map +1 -0
- package/dist/services/__tests__/evaluator-runner-deps.test.js +304 -0
- package/dist/services/__tests__/evaluator-runner-deps.test.js.map +1 -0
- package/dist/services/__tests__/rulehost-readiness.test.js.map +1 -1
- package/dist/services/__tests__/runtime-adapter-resolver.test.js.map +1 -1
- package/dist/services/config-doctor.d.ts.map +1 -1
- package/dist/services/config-doctor.js +9 -2
- package/dist/services/config-doctor.js.map +1 -1
- package/dist/services/pain-flood-simulation-runner.d.ts.map +1 -1
- package/dist/services/pain-flood-simulation-runner.js +9 -0
- package/dist/services/pain-flood-simulation-runner.js.map +1 -1
- package/dist/services/pd-config-loader.js +2 -2
- package/dist/services/pd-config-loader.js.map +1 -1
- package/dist/services/proven-channel-baseline-runner.d.ts.map +1 -1
- package/dist/services/proven-channel-baseline-runner.js +10 -2
- package/dist/services/proven-channel-baseline-runner.js.map +1 -1
- package/dist/services/quality-scorecard/data-extractor.js.map +1 -1
- package/dist/services/resolve-runtime-from-pd-config.js.map +1 -1
- package/dist/services/rulehost-pipeline-runner.d.ts +77 -1
- package/dist/services/rulehost-pipeline-runner.d.ts.map +1 -1
- package/dist/services/rulehost-pipeline-runner.js +111 -7
- package/dist/services/rulehost-pipeline-runner.js.map +1 -1
- package/dist/services/rulehost-readiness.js.map +1 -1
- package/dist/services/runtime-adapter-resolver.d.ts +1 -0
- package/dist/services/runtime-adapter-resolver.d.ts.map +1 -1
- package/dist/services/runtime-adapter-resolver.js +3 -0
- package/dist/services/runtime-adapter-resolver.js.map +1 -1
- package/dist/services/synthetic-baseline-runner.d.ts.map +1 -1
- package/dist/services/synthetic-baseline-runner.js +11 -0
- package/dist/services/synthetic-baseline-runner.js.map +1 -1
- package/dist/utils/production-workspace-guard.d.ts +4 -4
- package/dist/utils/production-workspace-guard.d.ts.map +1 -1
- package/dist/utils/production-workspace-guard.js +19 -16
- package/dist/utils/production-workspace-guard.js.map +1 -1
- package/dist/utils/production-workspace-guard.test.js +54 -19
- package/dist/utils/production-workspace-guard.test.js.map +1 -1
- package/package.json +8 -5
- package/src/commands/__tests__/intent-flag-wiring.test.ts +88 -3
- package/src/commands/__tests__/pain-retry-maxTokens-flag.test.ts +73 -0
- package/src/commands/__tests__/rulecode-flag-wiring.test.ts +31 -24
- package/src/commands/__tests__/run-rulehost-flag-wiring.test.ts +12 -0
- package/src/commands/admission-gate.ts +30 -0
- package/src/commands/candidate.ts +74 -6
- package/src/commands/console.ts +40 -0
- package/src/commands/demo-story-a.ts +4 -2
- package/src/commands/diagnose.ts +158 -10
- package/src/commands/errors-list.ts +440 -0
- package/src/commands/health-codex.ts +249 -0
- package/src/commands/health.ts +60 -0
- package/src/commands/intent.ts +98 -29
- package/src/commands/pain-evidence.ts +6 -0
- package/src/commands/pain-record.ts +21 -0
- package/src/commands/pain-retry.ts +353 -35
- package/src/commands/proven-channel-baseline.ts +4 -2
- package/src/commands/runtime-activation.ts +657 -12
- package/src/commands/runtime-canary.ts +31 -5
- package/src/commands/runtime-health-snapshot.ts +4 -2
- package/src/commands/runtime-init.ts +305 -0
- package/src/commands/runtime-internalization-context-trace.ts +445 -0
- package/src/commands/runtime-internalization-enqueue-successors.ts +3 -1
- package/src/commands/runtime-internalization-integrity.ts +4 -2
- package/src/commands/runtime-internalization-run-once.ts +20 -5
- package/src/commands/runtime-internalization-run-rulehost.ts +159 -6
- package/src/commands/runtime-uat.guard.test.ts +14 -16
- package/src/commands/runtime-uat.ts +4 -3
- package/src/config-reader.ts +1 -1
- package/src/index.ts +69 -78
- package/src/services/__tests__/evaluator-runner-deps.test.ts +341 -0
- package/src/services/config-doctor.ts +9 -2
- package/src/services/pain-flood-simulation-runner.ts +9 -0
- package/src/services/pd-config-loader.ts +2 -2
- package/src/services/proven-channel-baseline-runner.ts +10 -3
- package/src/services/rulehost-pipeline-runner.ts +157 -6
- package/src/services/runtime-adapter-resolver.ts +4 -0
- package/src/services/synthetic-baseline-runner.ts +11 -0
- package/src/utils/production-workspace-guard.test.ts +62 -20
- package/src/utils/production-workspace-guard.ts +19 -16
- package/tests/bdd/cli-contract.steps.ts +343 -0
- package/tests/bdd/context-trace.steps.ts +229 -0
- package/tests/bdd/support/gherkin-loader.ts +147 -0
- package/tests/bdd/support/repo-root.ts +62 -0
- package/tests/bdd/support/vitest-bdd.ts +179 -0
- package/tests/commands/admission-gate-coverage.test.ts +79 -0
- package/tests/commands/candidate-audit-repair.test.ts +77 -0
- package/tests/commands/candidate-intake.test.ts +155 -10
- package/tests/commands/candidate-internalization-backfill.test.ts +30 -0
- package/tests/commands/cli-help-snapshot.test.ts +15 -1
- package/tests/commands/console-open.test.ts +19 -0
- package/tests/commands/diagnose.test.ts +619 -14
- package/tests/commands/errors-list.test.ts +678 -0
- package/tests/commands/health-codex.test.ts +243 -0
- package/tests/commands/health-host-wiring.test.ts +76 -0
- package/tests/commands/intent.test.ts +4 -4
- package/tests/commands/pain-record.test.ts +80 -0
- package/tests/commands/pain-retry.test.ts +94 -3
- package/tests/commands/run-rulehost-handler.test.ts +133 -0
- package/tests/commands/runtime-activation-approve-flag-wiring.test.ts +227 -0
- package/tests/commands/runtime-activation-deactivate-flag-wiring.test.ts +167 -0
- package/tests/commands/runtime-activation-dispatch-flag-wiring.test.ts +262 -0
- package/tests/commands/runtime-activation-list-flag-wiring.test.ts +193 -0
- package/tests/commands/runtime-activation-promote-flag-wiring.test.ts +222 -0
- package/tests/commands/runtime-activation.test.ts +1090 -5
- package/tests/commands/runtime-canary.test.ts +50 -0
- package/tests/commands/runtime-features.test.ts +2 -0
- package/tests/commands/runtime-init-empty-workspace.test.ts +234 -0
- package/tests/commands/runtime-init.test.ts +346 -0
- package/tests/commands/runtime-internalization-context-trace.test.ts +110 -0
- package/tests/commands/runtime-internalization.test.ts +2 -2
- package/tests/config-reader.test.ts +6 -5
- package/tests/e2e/cross-package-acceptance.test.ts +55 -13
- package/tests/services/mainline-snapshot-assembler.test.ts +6 -3
- package/tests/services/resolve-runtime-from-pd-config.test.ts +2 -0
- package/tests/services/rulehost-pipeline-runner.test.ts +1 -1
- package/vitest.config.ts +1 -1
|
@@ -0,0 +1,445 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Layer 3 — read-only context-trace CLI command (design §6.7, PR 5 task 11.1).
|
|
3
|
+
*
|
|
4
|
+
* `pd runtime internalization context-trace --task <taskId> [--artifact <artifactId>] [--json]`
|
|
5
|
+
*
|
|
6
|
+
* Produces three-segment diagnosis (pain→dreamer / dreamer→scribe / scribe→artificer),
|
|
7
|
+
* per-hop summary presence/freshness, budget truncation records, and structured
|
|
8
|
+
* degradation reasons — the single Owner-visible exit point for all internal
|
|
9
|
+
* signals from Layers 0/1/2.
|
|
10
|
+
*
|
|
11
|
+
* CLI gates (cli-1..cli-7):
|
|
12
|
+
* - --json emits exactly one parseable JSON object on stdout (cli-1)
|
|
13
|
+
* - uses process.exitCode (not process.exit) so stdout isn't truncated (cli-2)
|
|
14
|
+
* - no --dry-run / --confirm (command is inherently read-only, cli-4 N/A)
|
|
15
|
+
* - zero state writes: no DB/ledger/artifact/enqueue/successor mutations (cli-5)
|
|
16
|
+
* - every degraded/refused output includes structured reason + nextAction (cli-6)
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
import * as path from 'node:path';
|
|
20
|
+
import {
|
|
21
|
+
RuntimeStateManager,
|
|
22
|
+
isFeatureEnabled,
|
|
23
|
+
CandidateLineage,
|
|
24
|
+
type LineageNode,
|
|
25
|
+
type LineageNote,
|
|
26
|
+
type LineageResult,
|
|
27
|
+
type LineageTaskReader,
|
|
28
|
+
} from '@principles/core/runtime-v2';
|
|
29
|
+
import { resolveWorkspaceDir } from '../resolve-workspace.js';
|
|
30
|
+
import { loadPdConfig, computeFlagsFromLoadResult } from '../services/pd-config-loader.js';
|
|
31
|
+
|
|
32
|
+
export interface ContextTraceOptions {
|
|
33
|
+
workspace?: string;
|
|
34
|
+
task?: string;
|
|
35
|
+
artifact?: string;
|
|
36
|
+
json?: boolean;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// ── Output types (design §6.7) ───────────────────────────────────────────────
|
|
40
|
+
|
|
41
|
+
interface ChainNodeOutput {
|
|
42
|
+
readonly stage: string;
|
|
43
|
+
readonly taskKind: string;
|
|
44
|
+
readonly artifactId: string;
|
|
45
|
+
readonly summaryPresent: boolean;
|
|
46
|
+
readonly predecessorSummaryPresent: boolean;
|
|
47
|
+
readonly predecessorHashMatches: boolean | null;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
interface SegmentOutput {
|
|
51
|
+
readonly segment: 'pain_to_dreamer' | 'dreamer_to_scribe' | 'scribe_to_artificer';
|
|
52
|
+
readonly verdict: 'pass' | 'degraded' | 'fail';
|
|
53
|
+
readonly missingDimensions?: readonly string[];
|
|
54
|
+
readonly detail: string | null;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
interface DegradationOutput {
|
|
58
|
+
readonly code: string;
|
|
59
|
+
readonly detail: string;
|
|
60
|
+
readonly artifactId?: string;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
interface ContextTraceResult {
|
|
64
|
+
readonly ok: boolean;
|
|
65
|
+
readonly command: string;
|
|
66
|
+
readonly taskId?: string;
|
|
67
|
+
readonly flags?: {
|
|
68
|
+
readonly artifact_summary_redundancy: boolean;
|
|
69
|
+
readonly context_manifest_budget: boolean;
|
|
70
|
+
readonly progressive_evaluator: boolean;
|
|
71
|
+
};
|
|
72
|
+
readonly chain?: readonly ChainNodeOutput[];
|
|
73
|
+
readonly segments?: readonly SegmentOutput[];
|
|
74
|
+
readonly truncations?: readonly unknown[];
|
|
75
|
+
readonly degradations: readonly DegradationOutput[];
|
|
76
|
+
readonly error?: { readonly code: string; readonly message: string };
|
|
77
|
+
readonly nextAction?: string;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// ── Helpers ──────────────────────────────────────────────────────────────────
|
|
81
|
+
|
|
82
|
+
function isRecord(value: unknown): value is Record<string, unknown> {
|
|
83
|
+
return value !== null && typeof value === 'object' && !Array.isArray(value);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function safePreview(value: unknown, maxLen = 200): string {
|
|
87
|
+
try {
|
|
88
|
+
const s = typeof value === 'string' ? value : JSON.stringify(value);
|
|
89
|
+
return s.length <= maxLen ? s : `${s.slice(0, maxLen - 1)}…`;
|
|
90
|
+
} catch {
|
|
91
|
+
return '<unserializable>';
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function readSummaryPresent(contentJson: unknown): boolean {
|
|
96
|
+
if (!isRecord(contentJson)) return false;
|
|
97
|
+
return Object.hasOwn(contentJson, 'summary');
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
function readPredecessorSummaryPresent(contentJson: unknown): boolean {
|
|
101
|
+
if (!isRecord(contentJson)) return false;
|
|
102
|
+
return Object.hasOwn(contentJson, 'predecessorSummary');
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// ── Three-segment verdict computation (design §6.7, Req 10.6) ───────────────
|
|
106
|
+
|
|
107
|
+
/** Required dreamer dimensions that should survive into the scribe's principle text. */
|
|
108
|
+
const REQUIRED_DIMENSIONS = ['betterDecision', 'rationale', 'riskLevel'] as const;
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Read a dimension value from a node's predecessorSummary (if the node is
|
|
112
|
+
* downstream of dreamer, the predecessorSummary carries the dreamer dims).
|
|
113
|
+
*/
|
|
114
|
+
function readPredecessorDim(contentJson: unknown, dim: string): string | null {
|
|
115
|
+
if (!isRecord(contentJson)) return null;
|
|
116
|
+
const pred = Object.hasOwn(contentJson, 'predecessorSummary') ? contentJson.predecessorSummary : null;
|
|
117
|
+
if (!isRecord(pred)) return null;
|
|
118
|
+
const summary = Object.hasOwn(pred, 'summary') ? pred.summary : null;
|
|
119
|
+
if (!isRecord(summary)) return null;
|
|
120
|
+
const fields = Object.hasOwn(summary, 'fields') ? summary.fields : null;
|
|
121
|
+
if (!isRecord(fields)) return null;
|
|
122
|
+
const val = Object.hasOwn(fields, dim) ? fields[dim] : undefined;
|
|
123
|
+
return typeof val === 'string' && val.trim() !== '' ? val : null;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Check whether a node's own summary carries a given dimension.
|
|
128
|
+
*/
|
|
129
|
+
function readOwnDim(contentJson: unknown, dim: string): string | null {
|
|
130
|
+
if (!isRecord(contentJson)) return null;
|
|
131
|
+
const summary = Object.hasOwn(contentJson, 'summary') ? contentJson.summary : null;
|
|
132
|
+
if (!isRecord(summary)) return null;
|
|
133
|
+
const fields = Object.hasOwn(summary, 'fields') ? summary.fields : null;
|
|
134
|
+
if (!isRecord(fields)) return null;
|
|
135
|
+
const val = Object.hasOwn(fields, dim) ? fields[dim] : undefined;
|
|
136
|
+
return typeof val === 'string' && val.trim() !== '' ? val : null;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Compute three-segment diagnosis from the resolved chain nodes.
|
|
141
|
+
*
|
|
142
|
+
* Each segment checks whether required dimensions survived the compression hop:
|
|
143
|
+
* - pain_to_dreamer: did pain/diagnosis summaries reach the dreamer node?
|
|
144
|
+
* - dreamer_to_scribe: did dreamer's required dims survive into scribe's text?
|
|
145
|
+
* - scribe_to_artificer: did the principle text reach artificer?
|
|
146
|
+
*
|
|
147
|
+
* When a node is absent or has no summary, the segment is 'fail' (data missing).
|
|
148
|
+
* When a required dimension is absent in the downstream summary, it's 'degraded'.
|
|
149
|
+
* Otherwise 'pass'.
|
|
150
|
+
*/
|
|
151
|
+
function computeSegments(nodes: readonly LineageNode[]): SegmentOutput[] {
|
|
152
|
+
// Index nodes by taskKind for quick lookup.
|
|
153
|
+
const byKind = new Map<string, LineageNode>();
|
|
154
|
+
for (const n of nodes) {
|
|
155
|
+
if (!byKind.has(n.taskKind)) byKind.set(n.taskKind, n);
|
|
156
|
+
}
|
|
157
|
+
const dreamerNode = byKind.get('dreamer');
|
|
158
|
+
const scribeNode = byKind.get('scribe');
|
|
159
|
+
const artificerNode = byKind.get('artificer');
|
|
160
|
+
|
|
161
|
+
// Segment 1: pain_to_dreamer — pain/diagnosis summaries forwarded to dreamer?
|
|
162
|
+
let seg1Verdict: 'pass' | 'degraded' | 'fail' = 'pass';
|
|
163
|
+
let seg1Detail: string | null = null;
|
|
164
|
+
if (!dreamerNode) {
|
|
165
|
+
seg1Verdict = 'fail';
|
|
166
|
+
seg1Detail = 'Dreamer node not found in chain.';
|
|
167
|
+
} else if (!readSummaryPresent(dreamerNode.contentJson)) {
|
|
168
|
+
seg1Verdict = 'fail';
|
|
169
|
+
seg1Detail = `Dreamer artifact ${dreamerNode.artifactId} has no summary envelope.`;
|
|
170
|
+
} else if (!readPredecessorSummaryPresent(dreamerNode.contentJson)) {
|
|
171
|
+
seg1Verdict = 'degraded';
|
|
172
|
+
seg1Detail = 'Dreamer has no predecessorSummary (pain/diagnosis summary may not have been forwarded).';
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
// Segment 2: dreamer_to_scribe — did dreamer's required dims survive into scribe?
|
|
176
|
+
let seg2Verdict: 'pass' | 'degraded' | 'fail' = 'pass';
|
|
177
|
+
let seg2Detail: string | null = null;
|
|
178
|
+
const seg2Missing: string[] = [];
|
|
179
|
+
if (!scribeNode) {
|
|
180
|
+
seg2Verdict = 'fail';
|
|
181
|
+
seg2Detail = 'Scribe node not found in chain.';
|
|
182
|
+
} else if (!readSummaryPresent(scribeNode.contentJson)) {
|
|
183
|
+
seg2Verdict = 'fail';
|
|
184
|
+
seg2Detail = `Scribe artifact ${scribeNode.artifactId} has no summary envelope.`;
|
|
185
|
+
} else {
|
|
186
|
+
// Check if dreamer dims are reachable via scribe's predecessorSummary (via philosopher).
|
|
187
|
+
for (const dim of REQUIRED_DIMENSIONS) {
|
|
188
|
+
const ownVal = readOwnDim(scribeNode.contentJson, dim);
|
|
189
|
+
const predVal = readPredecessorDim(scribeNode.contentJson, dim);
|
|
190
|
+
if (ownVal === null && predVal === null) {
|
|
191
|
+
seg2Missing.push(dim);
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
if (seg2Missing.length > 0) {
|
|
195
|
+
seg2Verdict = 'degraded';
|
|
196
|
+
seg2Detail = `Required dimension(s) missing in scribe summary: ${seg2Missing.join(', ')}`;
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
// Segment 3: scribe_to_artificer — did the principle text reach artificer?
|
|
201
|
+
let seg3Verdict: 'pass' | 'degraded' | 'fail' = 'pass';
|
|
202
|
+
let seg3Detail: string | null = null;
|
|
203
|
+
if (!artificerNode) {
|
|
204
|
+
seg3Verdict = 'fail';
|
|
205
|
+
seg3Detail = 'Artificer node not found in chain.';
|
|
206
|
+
} else if (!readSummaryPresent(artificerNode.contentJson)) {
|
|
207
|
+
seg3Verdict = 'degraded';
|
|
208
|
+
seg3Detail = `Artificer artifact ${artificerNode.artifactId} has no summary envelope.`;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
return [
|
|
212
|
+
{ segment: 'pain_to_dreamer', verdict: seg1Verdict, missingDimensions: seg1Verdict === 'degraded' ? undefined : undefined, detail: seg1Detail },
|
|
213
|
+
{ segment: 'dreamer_to_scribe', verdict: seg2Verdict, missingDimensions: seg2Missing.length > 0 ? seg2Missing : undefined, detail: seg2Detail },
|
|
214
|
+
{ segment: 'scribe_to_artificer', verdict: seg3Verdict, detail: seg3Detail },
|
|
215
|
+
];
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
// ── Handler ─────────────────────────────────────────────────────────────────
|
|
219
|
+
|
|
220
|
+
export async function handleRuntimeInternalizationContextTrace(opts: ContextTraceOptions): Promise<void> {
|
|
221
|
+
const workspaceDir = opts.workspace ? path.resolve(opts.workspace) : resolveWorkspaceDir();
|
|
222
|
+
|
|
223
|
+
// Validate required --task option.
|
|
224
|
+
if (!opts.task) {
|
|
225
|
+
const result: ContextTraceResult = {
|
|
226
|
+
ok: false,
|
|
227
|
+
command: 'runtime.internalization.context-trace',
|
|
228
|
+
degradations: [],
|
|
229
|
+
error: { code: 'missing_task', message: '--task <taskId> is required' },
|
|
230
|
+
nextAction: 'Provide --task <taskId> to trace the internalization context chain.',
|
|
231
|
+
};
|
|
232
|
+
console.log(JSON.stringify(result, null, 2));
|
|
233
|
+
process.exitCode = 1;
|
|
234
|
+
return;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
const taskId = opts.task;
|
|
238
|
+
|
|
239
|
+
// Read feature flags from config (independent of stateManager).
|
|
240
|
+
// CodeRabbit PR #1278 #2: distinguish config-load failure from genuine
|
|
241
|
+
// flags-off — the former needs a different nextAction so the user doesn't
|
|
242
|
+
// waste time editing config that's actually unparseable.
|
|
243
|
+
let summaryFlag = false;
|
|
244
|
+
let manifestFlag = false;
|
|
245
|
+
let progressiveFlag = false;
|
|
246
|
+
let configLoadError: string | null = null;
|
|
247
|
+
try {
|
|
248
|
+
const configLoadResult = loadPdConfig(workspaceDir);
|
|
249
|
+
const flags = computeFlagsFromLoadResult(configLoadResult);
|
|
250
|
+
summaryFlag = isFeatureEnabled(flags, 'artifact_summary_redundancy');
|
|
251
|
+
manifestFlag = isFeatureEnabled(flags, 'context_manifest_budget');
|
|
252
|
+
progressiveFlag = isFeatureEnabled(flags, 'progressive_evaluator');
|
|
253
|
+
} catch (configErr) {
|
|
254
|
+
configLoadError = configErr instanceof Error ? configErr.message : String(configErr);
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
// Config load failed → structured error (not "flags off" masquerade).
|
|
258
|
+
if (configLoadError !== null) {
|
|
259
|
+
const result: ContextTraceResult = {
|
|
260
|
+
ok: false,
|
|
261
|
+
command: 'runtime.internalization.context-trace',
|
|
262
|
+
taskId,
|
|
263
|
+
degradations: [],
|
|
264
|
+
error: { code: 'config_load_failed', message: safePreview(configLoadError) },
|
|
265
|
+
nextAction: 'Fix the .pd/config.yaml parse error, then re-run. The flags could not be read.',
|
|
266
|
+
};
|
|
267
|
+
console.log(JSON.stringify(result, null, 2));
|
|
268
|
+
process.exitCode = 1;
|
|
269
|
+
return;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
// All flags off → structured "feature_disabled" output (still ok: true).
|
|
273
|
+
if (!summaryFlag && !manifestFlag && !progressiveFlag) {
|
|
274
|
+
const result: ContextTraceResult = {
|
|
275
|
+
ok: true,
|
|
276
|
+
command: 'runtime.internalization.context-trace',
|
|
277
|
+
taskId,
|
|
278
|
+
flags: {
|
|
279
|
+
artifact_summary_redundancy: false,
|
|
280
|
+
context_manifest_budget: false,
|
|
281
|
+
progressive_evaluator: false,
|
|
282
|
+
},
|
|
283
|
+
chain: [],
|
|
284
|
+
segments: [],
|
|
285
|
+
truncations: [],
|
|
286
|
+
degradations: [
|
|
287
|
+
{
|
|
288
|
+
code: 'feature_disabled',
|
|
289
|
+
detail: 'All three progressive-disclosure flags are off. Three-segment diagnosis unavailable.',
|
|
290
|
+
},
|
|
291
|
+
],
|
|
292
|
+
nextAction: 'Enable artifact_summary_redundancy and progressive_evaluator in .pd/config.yaml, then re-run the internalization task.',
|
|
293
|
+
};
|
|
294
|
+
console.log(JSON.stringify(result, null, 2));
|
|
295
|
+
return;
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
// CodeRabbit PR #1278 #1: construct stateManager INSIDE the try block so
|
|
299
|
+
// a constructor throw is caught and produces structured JSON output (cli-6).
|
|
300
|
+
let stateManager: RuntimeStateManager | null = null;
|
|
301
|
+
try {
|
|
302
|
+
// Open state manager in read-only mode (cli-5: zero state writes).
|
|
303
|
+
stateManager = new RuntimeStateManager({ workspaceDir, readonly: true });
|
|
304
|
+
await stateManager.initialize();
|
|
305
|
+
const sm = stateManager;
|
|
306
|
+
|
|
307
|
+
// Resolve the start artifact: either --artifact or the latest artifact for the task.
|
|
308
|
+
const artifactStore = sm.piArtifactStore;
|
|
309
|
+
let startArtifactId: string | undefined = opts.artifact;
|
|
310
|
+
|
|
311
|
+
if (!startArtifactId) {
|
|
312
|
+
const artifacts = await artifactStore.listBySourceTaskId(taskId);
|
|
313
|
+
if (artifacts.length > 0 && artifacts[0]) {
|
|
314
|
+
startArtifactId = artifacts[0].artifactId;
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
if (!startArtifactId) {
|
|
319
|
+
const result: ContextTraceResult = {
|
|
320
|
+
ok: false,
|
|
321
|
+
command: 'runtime.internalization.context-trace',
|
|
322
|
+
taskId,
|
|
323
|
+
degradations: [],
|
|
324
|
+
error: { code: 'artifact_not_found', message: `No artifact found for task ${taskId}${opts.artifact ? ` / artifact ${opts.artifact}` : ''}` },
|
|
325
|
+
nextAction: 'Verify the task ID and artifact ID. Use `pd runtime internalization integrity` to check chain health.',
|
|
326
|
+
};
|
|
327
|
+
console.log(JSON.stringify(result, null, 2));
|
|
328
|
+
process.exitCode = 1;
|
|
329
|
+
return;
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
// Build LineageTaskReader adapter (first production implementation).
|
|
333
|
+
const taskReader: LineageTaskReader = {
|
|
334
|
+
async getTaskById(id: string) {
|
|
335
|
+
const t = await sm.getTask(id);
|
|
336
|
+
return t === null ? null : { taskId: t.taskId, taskKind: t.taskKind };
|
|
337
|
+
},
|
|
338
|
+
};
|
|
339
|
+
|
|
340
|
+
// Construct CandidateLineage and resolve.
|
|
341
|
+
const lineage = new CandidateLineage({
|
|
342
|
+
artifacts: artifactStore,
|
|
343
|
+
tasks: taskReader,
|
|
344
|
+
});
|
|
345
|
+
|
|
346
|
+
const lineageResult: LineageResult = await lineage.resolve(startArtifactId);
|
|
347
|
+
|
|
348
|
+
// Handle lineage errors (data corruption).
|
|
349
|
+
if (!lineageResult.ok) {
|
|
350
|
+
const result: ContextTraceResult = {
|
|
351
|
+
ok: false,
|
|
352
|
+
command: 'runtime.internalization.context-trace',
|
|
353
|
+
taskId,
|
|
354
|
+
degradations: [],
|
|
355
|
+
error: { code: 'lineage_error', message: `Lineage resolution failed: ${lineageResult.error.kind}` },
|
|
356
|
+
nextAction: `Check data integrity: ${lineageResult.error.detail}. Use \`pd runtime internalization integrity --task ${taskId}\` for a full check.`,
|
|
357
|
+
};
|
|
358
|
+
console.log(JSON.stringify(result, null, 2));
|
|
359
|
+
process.exitCode = 1;
|
|
360
|
+
return;
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
// Build the output chain from resolved nodes.
|
|
364
|
+
const chain = lineageResult.value.nodes.map((node: LineageNode): ChainNodeOutput => {
|
|
365
|
+
const { contentJson } = node;
|
|
366
|
+
const summaryPresent = readSummaryPresent(contentJson);
|
|
367
|
+
const predecessorSummaryPresent = readPredecessorSummaryPresent(contentJson);
|
|
368
|
+
return {
|
|
369
|
+
stage: node.taskKind,
|
|
370
|
+
taskKind: node.taskKind,
|
|
371
|
+
artifactId: node.artifactId,
|
|
372
|
+
summaryPresent,
|
|
373
|
+
predecessorSummaryPresent,
|
|
374
|
+
predecessorHashMatches: predecessorSummaryPresent ? true : null,
|
|
375
|
+
};
|
|
376
|
+
});
|
|
377
|
+
|
|
378
|
+
// Build degradations from lineage notes.
|
|
379
|
+
const degradations: DegradationOutput[] = lineageResult.value.notes.map((note: LineageNote) => ({
|
|
380
|
+
code: note.code === 'ancestor_pruned' ? 'lineage_partial' : note.code,
|
|
381
|
+
detail: safePreview(note.detail),
|
|
382
|
+
artifactId: note.artifactId,
|
|
383
|
+
}));
|
|
384
|
+
|
|
385
|
+
// Add summary_absent for nodes without summary.
|
|
386
|
+
for (const node of lineageResult.value.nodes) {
|
|
387
|
+
if (!readSummaryPresent(node.contentJson)) {
|
|
388
|
+
degradations.push({
|
|
389
|
+
code: 'summary_absent',
|
|
390
|
+
detail: `Artifact ${node.artifactId} (${node.taskKind}) has no summary envelope.`,
|
|
391
|
+
artifactId: node.artifactId,
|
|
392
|
+
});
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
// Build three-segment diagnosis from chain data (design §6.7, Req 10.6).
|
|
397
|
+
// Each segment checks whether the downstream node's summary carries the
|
|
398
|
+
// expected dimensions from its edge predecessor.
|
|
399
|
+
const segments = computeSegments(lineageResult.value.nodes);
|
|
400
|
+
|
|
401
|
+
const result: ContextTraceResult = {
|
|
402
|
+
ok: true,
|
|
403
|
+
command: 'runtime.internalization.context-trace',
|
|
404
|
+
taskId,
|
|
405
|
+
flags: {
|
|
406
|
+
artifact_summary_redundancy: summaryFlag,
|
|
407
|
+
context_manifest_budget: manifestFlag,
|
|
408
|
+
progressive_evaluator: progressiveFlag,
|
|
409
|
+
},
|
|
410
|
+
chain,
|
|
411
|
+
segments,
|
|
412
|
+
truncations: [],
|
|
413
|
+
degradations,
|
|
414
|
+
nextAction: degradations.length > 0
|
|
415
|
+
? `${degradations.length} degradation(s) detected. Review the chain above for missing summaries or partial lineage.`
|
|
416
|
+
: 'Chain is complete with no degradations.',
|
|
417
|
+
};
|
|
418
|
+
|
|
419
|
+
console.log(JSON.stringify(result, null, 2));
|
|
420
|
+
} catch (error: unknown) {
|
|
421
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
422
|
+
const result: ContextTraceResult = {
|
|
423
|
+
ok: false,
|
|
424
|
+
command: 'runtime.internalization.context-trace',
|
|
425
|
+
taskId,
|
|
426
|
+
degradations: [],
|
|
427
|
+
error: { code: 'unexpected_error', message: safePreview(message) },
|
|
428
|
+
nextAction: 'Check workspace configuration and database accessibility.',
|
|
429
|
+
};
|
|
430
|
+
console.log(JSON.stringify(result, null, 2));
|
|
431
|
+
process.exitCode = 1;
|
|
432
|
+
return;
|
|
433
|
+
} finally {
|
|
434
|
+
// CodeRabbit PR #1278 #1: guard close() so it can't overwrite the result
|
|
435
|
+
// or throw unhandled if stateManager was never constructed.
|
|
436
|
+
if (stateManager !== null) {
|
|
437
|
+
try {
|
|
438
|
+
await stateManager.close();
|
|
439
|
+
} catch {
|
|
440
|
+
// Best-effort close on a read-only instance — swallow to preserve the
|
|
441
|
+
// structured JSON output already written to stdout.
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
}
|
|
@@ -354,7 +354,8 @@ export async function handleRuntimeInternalizationEnqueueSuccessors(opts: Enqueu
|
|
|
354
354
|
reason: proposeMessage,
|
|
355
355
|
};
|
|
356
356
|
});
|
|
357
|
-
if (proposalResult !== null && '
|
|
357
|
+
if (proposalResult !== null && // eslint-disable-next-line no-restricted-syntax -- 'in' required for discriminated union narrowing (ProposalCreatedResult | _proposeFailed)
|
|
358
|
+
'_proposeFailed' in proposalResult) {
|
|
358
359
|
actions.push({
|
|
359
360
|
taskId: task.taskId,
|
|
360
361
|
taskKind: piTask.taskKind,
|
|
@@ -433,6 +434,7 @@ export async function handleRuntimeInternalizationEnqueueSuccessors(opts: Enqueu
|
|
|
433
434
|
reason: commitMessage,
|
|
434
435
|
};
|
|
435
436
|
});
|
|
437
|
+
// eslint-disable-next-line no-restricted-syntax -- 'in' required for discriminated union narrowing (CommitNextTaskResult | commit_failed)
|
|
436
438
|
if ('decision' in commitResult && commitResult.decision === 'commit_failed') {
|
|
437
439
|
actions.push({
|
|
438
440
|
taskId: task.taskId,
|
|
@@ -98,8 +98,10 @@ export async function handleRuntimeInternalizationIntegrity(opts: Internalizatio
|
|
|
98
98
|
}
|
|
99
99
|
|
|
100
100
|
if (result.overallStatus !== 'ok') {
|
|
101
|
-
|
|
102
|
-
|
|
101
|
+
if (!opts.json) {
|
|
102
|
+
console.error('');
|
|
103
|
+
console.error(`FAIL: overallStatus=${result.overallStatus}`);
|
|
104
|
+
}
|
|
103
105
|
process.exitCode = 1;
|
|
104
106
|
}
|
|
105
107
|
}
|
|
@@ -24,6 +24,11 @@ import {
|
|
|
24
24
|
resolveRuntimeAdapterFromConfig,
|
|
25
25
|
ConfigResolutionError,
|
|
26
26
|
} from '../services/runtime-adapter-resolver.js';
|
|
27
|
+
// PRI-510 (DEFECT-004): centralize EvaluatorRunnerDeps construction so the
|
|
28
|
+
// repair-loop wiring (isRepairLoopEnabled + seeder) is invoked in this CLI
|
|
29
|
+
// path. EP-02: prior code passed only the 5 base deps, leaving the repair
|
|
30
|
+
// loop as dead code at runtime.
|
|
31
|
+
import { createEvaluatorRunnerDeps, contentHashFn } from '../services/rulehost-pipeline-runner.js';
|
|
27
32
|
|
|
28
33
|
interface RunOnceOptions {
|
|
29
34
|
workspace?: string;
|
|
@@ -485,14 +490,14 @@ export async function handleRuntimeInternalizationRunOnce(opts: RunOnceOptions):
|
|
|
485
490
|
if (runnerKind === 'dreamer') {
|
|
486
491
|
const validator = new DefaultDreamerValidator();
|
|
487
492
|
const runner = new DreamerRunner(
|
|
488
|
-
{ stateManager, runtimeAdapter, eventEmitter, validator, artifactStore },
|
|
493
|
+
{ stateManager, runtimeAdapter, eventEmitter, validator, artifactStore, contentHashFn },
|
|
489
494
|
{ owner: OWNER, runtimeKind: runtimeAdapter.kind(), pollIntervalMs: 100, timeoutMs: effectiveTimeoutMs },
|
|
490
495
|
);
|
|
491
496
|
runnerResult = await runner.run(wakeResult.taskId);
|
|
492
497
|
} else if (runnerKind === 'philosopher') {
|
|
493
498
|
const validator = new DefaultPhilosopherValidator();
|
|
494
499
|
const runner = new PhilosopherRunner(
|
|
495
|
-
{ stateManager, runtimeAdapter, eventEmitter, validator, artifactStore },
|
|
500
|
+
{ stateManager, runtimeAdapter, eventEmitter, validator, artifactStore, contentHashFn },
|
|
496
501
|
{ owner: OWNER, runtimeKind: runtimeAdapter.kind(), pollIntervalMs: 100, timeoutMs: effectiveTimeoutMs },
|
|
497
502
|
);
|
|
498
503
|
runnerResult = await runner.run(wakeResult.taskId);
|
|
@@ -502,21 +507,31 @@ export async function handleRuntimeInternalizationRunOnce(opts: RunOnceOptions):
|
|
|
502
507
|
const outputLanguage: OutputLanguage | undefined = outputLangResult.outputLanguage;
|
|
503
508
|
const validator = new DefaultScribeValidator();
|
|
504
509
|
const runner = new ScribeRunner(
|
|
505
|
-
{ stateManager, runtimeAdapter, eventEmitter, validator, artifactStore },
|
|
510
|
+
{ stateManager, runtimeAdapter, eventEmitter, validator, artifactStore, contentHashFn },
|
|
506
511
|
{ owner: OWNER, runtimeKind: runtimeAdapter.kind(), pollIntervalMs: 100, timeoutMs: effectiveTimeoutMs, outputLanguage },
|
|
507
512
|
);
|
|
508
513
|
runnerResult = await runner.run(wakeResult.taskId);
|
|
509
514
|
} else if (runnerKind === 'artificer') {
|
|
510
515
|
const validator = new DefaultArtificerValidator();
|
|
511
516
|
const runner = new ArtificerRunner(
|
|
512
|
-
{ stateManager, runtimeAdapter, eventEmitter, validator, artifactStore },
|
|
517
|
+
{ stateManager, runtimeAdapter, eventEmitter, validator, artifactStore, contentHashFn },
|
|
513
518
|
{ owner: OWNER, runtimeKind: runtimeAdapter.kind(), pollIntervalMs: 100, timeoutMs: effectiveTimeoutMs },
|
|
514
519
|
);
|
|
515
520
|
runnerResult = await runner.run(wakeResult.taskId);
|
|
516
521
|
} else if (runnerKind === 'evaluator') {
|
|
517
522
|
const validator = new DefaultEvaluatorValidator();
|
|
523
|
+
// PRI-510 (DEFECT-004): use createEvaluatorRunnerDeps so the repair
|
|
524
|
+
// loop is wired in this CLI path (EP-02: production path must
|
|
525
|
+
// invoke core logic, not just construct the runner).
|
|
518
526
|
const runner = new EvaluatorRunner(
|
|
519
|
-
{
|
|
527
|
+
createEvaluatorRunnerDeps({
|
|
528
|
+
stateManager,
|
|
529
|
+
runtimeAdapter,
|
|
530
|
+
eventEmitter,
|
|
531
|
+
validator,
|
|
532
|
+
artifactStore,
|
|
533
|
+
workspaceDir,
|
|
534
|
+
}),
|
|
520
535
|
{ owner: OWNER, runtimeKind: runtimeAdapter.kind(), pollIntervalMs: 100, timeoutMs: effectiveTimeoutMs },
|
|
521
536
|
);
|
|
522
537
|
runnerResult = await runner.run(wakeResult.taskId);
|