@principles/pd-cli 1.152.7 → 1.152.8
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__/runtime-probe-config.test.js +2 -1
- package/dist/commands/__tests__/runtime-probe-config.test.js.map +1 -1
- package/dist/commands/__tests__/version.test.js +104 -0
- package/dist/commands/__tests__/version.test.js.map +1 -1
- package/dist/commands/diagnose.d.ts.map +1 -1
- package/dist/commands/diagnose.js +3 -6
- package/dist/commands/diagnose.js.map +1 -1
- package/dist/commands/pain-retry.d.ts.map +1 -1
- package/dist/commands/pain-retry.js +3 -6
- package/dist/commands/pain-retry.js.map +1 -1
- package/dist/commands/runtime-activation.d.ts.map +1 -1
- package/dist/commands/runtime-activation.js +9 -3
- package/dist/commands/runtime-activation.js.map +1 -1
- package/dist/commands/runtime-internalization-run-once.d.ts.map +1 -1
- package/dist/commands/runtime-internalization-run-once.js +5 -11
- package/dist/commands/runtime-internalization-run-once.js.map +1 -1
- package/dist/commands/runtime-internalization-run-rulehost.d.ts +14 -0
- package/dist/commands/runtime-internalization-run-rulehost.d.ts.map +1 -1
- package/dist/commands/runtime-internalization-run-rulehost.js +67 -15
- package/dist/commands/runtime-internalization-run-rulehost.js.map +1 -1
- package/dist/index.js +0 -12
- package/dist/index.js.map +1 -1
- package/dist/services/__tests__/rulehost-readiness.test.js +0 -3
- package/dist/services/__tests__/rulehost-readiness.test.js.map +1 -1
- package/dist/services/pain-flood-simulation-runner.d.ts.map +1 -1
- package/dist/services/pain-flood-simulation-runner.js +0 -4
- package/dist/services/pain-flood-simulation-runner.js.map +1 -1
- package/dist/services/rulehost-pipeline-runner.d.ts +90 -21
- package/dist/services/rulehost-pipeline-runner.d.ts.map +1 -1
- package/dist/services/rulehost-pipeline-runner.js +328 -24
- package/dist/services/rulehost-pipeline-runner.js.map +1 -1
- package/dist/services/synthetic-baseline-runner.d.ts.map +1 -1
- package/dist/services/synthetic-baseline-runner.js +0 -4
- package/dist/services/synthetic-baseline-runner.js.map +1 -1
- package/dist/services/version-report.d.ts +16 -0
- package/dist/services/version-report.d.ts.map +1 -1
- package/dist/services/version-report.js +37 -2
- package/dist/services/version-report.js.map +1 -1
- package/package.json +1 -1
- package/src/commands/__tests__/runtime-probe-config.test.ts +2 -1
- package/src/commands/__tests__/version.test.ts +110 -0
- package/src/commands/diagnose.ts +3 -6
- package/src/commands/pain-retry.ts +3 -6
- package/src/commands/runtime-activation.ts +9 -3
- package/src/commands/runtime-internalization-run-once.ts +5 -11
- package/src/commands/runtime-internalization-run-rulehost.ts +69 -15
- package/src/index.ts +0 -13
- package/src/services/__tests__/rulehost-readiness.test.ts +0 -3
- package/src/services/pain-flood-simulation-runner.ts +0 -4
- package/src/services/rulehost-pipeline-runner.ts +368 -35
- package/src/services/synthetic-baseline-runner.ts +0 -4
- package/src/services/version-report.ts +52 -2
- package/tests/commands/config-doctor.test.ts +0 -2
- package/tests/commands/pain-evidence.test.ts +1 -1
- package/tests/commands/run-rulehost-handler.test.ts +43 -0
- package/tests/commands/runtime-features.test.ts +0 -1
- package/tests/commands/runtime-internalization-run-once-language.test.ts +0 -1
- package/tests/e2e/cross-package-acceptance.test.ts +13 -3
- package/tests/services/pd-config-loader.test.ts +0 -1
- package/tests/services/rulehost-pipeline-runner.test.ts +378 -12
- package/dist/commands/runtime-internalization-context-trace.d.ts +0 -25
- package/dist/commands/runtime-internalization-context-trace.d.ts.map +0 -1
- package/dist/commands/runtime-internalization-context-trace.js +0 -374
- package/dist/commands/runtime-internalization-context-trace.js.map +0 -1
- package/src/commands/runtime-internalization-context-trace.ts +0 -445
- package/tests/bdd/context-trace.steps.ts +0 -229
- package/tests/commands/runtime-internalization-context-trace.test.ts +0 -110
|
@@ -711,3 +711,46 @@ describe('handleRunRuleHost — PR #1122 behavior-examples fail-fast (CodeRabbit
|
|
|
711
711
|
expect(stdout).toMatch(/Next: fix the code-rule capability issue above/);
|
|
712
712
|
});
|
|
713
713
|
});
|
|
714
|
+
|
|
715
|
+
// ── Owner Decision v1 review fix (Codex P1): identity-gated publication ─────
|
|
716
|
+
|
|
717
|
+
describe('describePublicationOutcome — identity-gated refusal reporting (Codex P1)', () => {
|
|
718
|
+
const baseResult = {
|
|
719
|
+
decision: 'candidate_ready_for_owner_review' as const,
|
|
720
|
+
painId: 'pain-1',
|
|
721
|
+
stages: [],
|
|
722
|
+
scribeTaskId: 'scribe-1',
|
|
723
|
+
ruleArtifactId: 'pi-rule-1' as string | null,
|
|
724
|
+
principleArtifactId: null as string | null,
|
|
725
|
+
approvalId: null as string | null,
|
|
726
|
+
degradationReason: null as string | null,
|
|
727
|
+
};
|
|
728
|
+
|
|
729
|
+
it('flags the identity-blocked state and provides a repair nextAction', async () => {
|
|
730
|
+
const { describePublicationOutcome } = await import('../../src/commands/runtime-internalization-run-rulehost.js');
|
|
731
|
+
const outcome = describePublicationOutcome({
|
|
732
|
+
...baseResult,
|
|
733
|
+
degradationReason: 'identity_binding_unverified: ledger_missing. Rule artifact NOT enqueued for Owner review (governance publication boundary).',
|
|
734
|
+
});
|
|
735
|
+
expect(outcome.blocked).toBe(true);
|
|
736
|
+
expect(outcome.nextAction).toContain('NOT enqueued');
|
|
737
|
+
expect(outcome.nextAction).toContain('re-run');
|
|
738
|
+
});
|
|
739
|
+
|
|
740
|
+
it('does not flag a healthy ready result with a real approval id', async () => {
|
|
741
|
+
const { describePublicationOutcome } = await import('../../src/commands/runtime-internalization-run-rulehost.js');
|
|
742
|
+
const outcome = describePublicationOutcome({ ...baseResult, approvalId: 'apr-1' });
|
|
743
|
+
expect(outcome.blocked).toBe(false);
|
|
744
|
+
});
|
|
745
|
+
|
|
746
|
+
it('text output for the identity-blocked result never claims WAITING for owner review', async () => {
|
|
747
|
+
const { formatTextOutput } = await import('../../src/commands/runtime-internalization-run-rulehost.js');
|
|
748
|
+
const text = formatTextOutput({
|
|
749
|
+
...baseResult,
|
|
750
|
+
degradationReason: 'identity_binding_unverified: ledger_missing. Rule artifact NOT enqueued for Owner review (governance publication boundary).',
|
|
751
|
+
});
|
|
752
|
+
expect(text).toContain('PUBLICATION REFUSED');
|
|
753
|
+
expect(text).not.toContain('WAITING for owner review');
|
|
754
|
+
expect(text).toContain('NOT enqueued for Owner review');
|
|
755
|
+
});
|
|
756
|
+
});
|
|
@@ -72,7 +72,6 @@ function makeWorkspace(outputLanguage?: 'en'): string {
|
|
|
72
72
|
evaluator: { enabled: false },
|
|
73
73
|
rolloutReviewer: { enabled: false },
|
|
74
74
|
correctionObserver: { enabled: false },
|
|
75
|
-
empathyObserver: { enabled: false },
|
|
76
75
|
},
|
|
77
76
|
},
|
|
78
77
|
ui: { diagnostics: { mode: 'simple' } },
|
|
@@ -56,6 +56,7 @@ import {
|
|
|
56
56
|
createPITaskDiagnosticJson,
|
|
57
57
|
} from '@principles/core/runtime-v2';
|
|
58
58
|
import type { PIArtifactSnapshot, RuleHostInput } from '@principles/core/runtime-v2';
|
|
59
|
+
import { addPrincipleToLedger } from '@principles/core/principle-tree-ledger';
|
|
59
60
|
|
|
60
61
|
// ── Scripted adapter (same pattern as rulehost-pipeline-runner.test.ts) ──────
|
|
61
62
|
|
|
@@ -236,11 +237,11 @@ function makeTmpDir(): string {
|
|
|
236
237
|
return dir;
|
|
237
238
|
}
|
|
238
239
|
|
|
239
|
-
async function seedDreamerWithId(sm: RuntimeStateManager, taskId: string, painId: string): Promise<void> {
|
|
240
|
+
async function seedDreamerWithId(sm: RuntimeStateManager, taskId: string, painId: string, candidateId?: string): Promise<void> {
|
|
240
241
|
const baseMetadata = JSON.parse(createPITaskDiagnosticJson({
|
|
241
242
|
dependencyTaskIds: [], channel: 'code_tool_hook', timeoutMs: 1000, inputArtifactRefs: [], outputArtifactRefs: [],
|
|
242
243
|
})) as Record<string, unknown>;
|
|
243
|
-
const diagnosticJson = JSON.stringify({ ...baseMetadata, sourcePainId: painId });
|
|
244
|
+
const diagnosticJson = JSON.stringify({ ...baseMetadata, sourcePainId: painId, ...(candidateId ? { candidateId } : {}) });
|
|
244
245
|
await sm.createTask({ taskId, taskKind: 'dreamer', status: 'pending', attemptCount: 0, maxAttempts: 3, diagnosticJson });
|
|
245
246
|
}
|
|
246
247
|
|
|
@@ -270,8 +271,17 @@ describe('Cross-Package Acceptance Test (PRI-408 P1/P2 fixes) — unsplippable c
|
|
|
270
271
|
tmpDir = makeTmpDir();
|
|
271
272
|
const sm = new RuntimeStateManager({ workspaceDir: tmpDir });
|
|
272
273
|
await sm.initialize();
|
|
273
|
-
|
|
274
|
+
// Owner Decision Experience v1 Phase A: the governance publication boundary
|
|
275
|
+
// requires a verified chain identity (candidateId → unique ledger entry),
|
|
276
|
+
// mirroring what the intake bridge creates in production workspaces.
|
|
277
|
+
await seedDreamerWithId(sm, 'dreamer-xpkg-001', 'pain-xpkg-001', 'cand-xpkg-001');
|
|
274
278
|
await sm.close();
|
|
279
|
+
addPrincipleToLedger(path.join(tmpDir, '.state'), {
|
|
280
|
+
id: 'ledger-xpkg-001', version: 1, text: 'cross-package ledger principle', triggerPattern: '', action: '',
|
|
281
|
+
status: 'candidate', evaluability: 'weak_heuristic', priority: 'P1', scope: 'general',
|
|
282
|
+
valueScore: 0, adherenceRate: 0, painPreventedCount: 0, derivedFromPainIds: ['cand-xpkg-001'],
|
|
283
|
+
ruleIds: [], conflictsWithPrincipleIds: [], createdAt: '2026-09-15T00:00:00.000Z', updatedAt: '2026-09-15T00:00:00.000Z',
|
|
284
|
+
});
|
|
275
285
|
|
|
276
286
|
// ── Step 2: Run RuleHost pipeline → candidate + auto-enqueue (P1 #1) ───
|
|
277
287
|
const adapter = makeAdapter();
|
|
@@ -16,10 +16,11 @@ import { describe, it, expect, afterEach, vi } from 'vitest';
|
|
|
16
16
|
import * as os from 'node:os';
|
|
17
17
|
import * as path from 'node:path';
|
|
18
18
|
import * as fs from 'node:fs';
|
|
19
|
-
import { runRuleHostPipeline } from '../../src/services/rulehost-pipeline-runner.js';
|
|
19
|
+
import { runRuleHostPipeline, backfillScribeIdentity } from '../../src/services/rulehost-pipeline-runner.js';
|
|
20
20
|
import type { CodeRuleCapability } from '../../src/services/rulehost-pipeline-runner.js';
|
|
21
21
|
import type { PDRuntimeAdapter, RunHandle, RunStatus, PIArtifactStore, RuntimeCapabilities, RuntimeHealth, RuntimeArtifactRef, ContextItem, StructuredRunOutput, StartRunInput } from '@principles/core/runtime-v2';
|
|
22
|
-
import { RuntimeStateManager, createPITaskDiagnosticJson } from '@principles/core/runtime-v2';
|
|
22
|
+
import { RuntimeStateManager, createPITaskDiagnosticJson, SqliteApprovalQueueStore } from '@principles/core/runtime-v2';
|
|
23
|
+
import { addPrincipleToLedger, updatePrinciple } from '@principles/core/principle-tree-ledger';
|
|
23
24
|
import { saveHostToolDeclaration } from '@principles/host-runtime';
|
|
24
25
|
|
|
25
26
|
type StageFactory = (taskId: string, priorArtifactId?: string) => unknown;
|
|
@@ -248,11 +249,12 @@ async function seedDreamerWithId(
|
|
|
248
249
|
taskId: string,
|
|
249
250
|
painId: string,
|
|
250
251
|
channel: 'prompt' | 'code_tool_hook' | 'defer_archive' = 'code_tool_hook',
|
|
252
|
+
candidateId?: string,
|
|
251
253
|
): Promise<void> {
|
|
252
254
|
const baseMetadata = JSON.parse(createPITaskDiagnosticJson({
|
|
253
255
|
dependencyTaskIds: [], channel, timeoutMs: 1000, inputArtifactRefs: [], outputArtifactRefs: [],
|
|
254
256
|
})) as Record<string, unknown>;
|
|
255
|
-
const diagnosticJson = JSON.stringify({ ...baseMetadata, sourcePainId: painId });
|
|
257
|
+
const diagnosticJson = JSON.stringify({ ...baseMetadata, sourcePainId: painId, ...(candidateId ? { candidateId } : {}) });
|
|
256
258
|
await sm.createTask({ taskId, taskKind: 'dreamer', status: 'pending', attemptCount: 0, maxAttempts: 3, diagnosticJson });
|
|
257
259
|
}
|
|
258
260
|
|
|
@@ -270,12 +272,18 @@ describe('runRuleHostPipeline (PRI-429) — atomic capability + exact pain match
|
|
|
270
272
|
});
|
|
271
273
|
|
|
272
274
|
// ── Test 1: Capability ON + approved → candidate_ready_for_owner_review ──
|
|
273
|
-
it('capability ON + evaluator approved → candidate_ready_for_owner_review', async () => {
|
|
275
|
+
it('capability ON + evaluator approved → candidate_ready_for_owner_review; scribe identity backfilled on the rule path too (EP002-R4 follow-up #2)', async () => {
|
|
274
276
|
tmpDir = makeTmpDir();
|
|
275
277
|
const sm = new RuntimeStateManager({ workspaceDir: tmpDir });
|
|
276
278
|
await sm.initialize();
|
|
277
|
-
await seedDreamerWithId(sm, 'dreamer-seeded-001', 'pain-test-001');
|
|
279
|
+
await seedDreamerWithId(sm, 'dreamer-seeded-001', 'pain-test-001', 'code_tool_hook', 'cand-001');
|
|
278
280
|
await sm.close();
|
|
281
|
+
addPrincipleToLedger(path.join(tmpDir, '.state'), {
|
|
282
|
+
id: 'ledger-principle-001', version: 1, text: 'test ledger principle', triggerPattern: '', action: '',
|
|
283
|
+
status: 'candidate', evaluability: 'weak_heuristic', priority: 'P1', scope: 'general',
|
|
284
|
+
valueScore: 0, adherenceRate: 0, painPreventedCount: 0, derivedFromPainIds: ['cand-001'],
|
|
285
|
+
ruleIds: [], conflictsWithPrincipleIds: [], createdAt: '2026-09-15T00:00:00.000Z', updatedAt: '2026-09-15T00:00:00.000Z',
|
|
286
|
+
});
|
|
279
287
|
|
|
280
288
|
const adapter = makeAdapter();
|
|
281
289
|
const capability: CodeRuleCapability = { enabled: true, artificerAdapter: adapter };
|
|
@@ -292,6 +300,23 @@ describe('runRuleHostPipeline (PRI-429) — atomic capability + exact pain match
|
|
|
292
300
|
expect(result.ruleArtifactId).not.toBeNull();
|
|
293
301
|
// P1 #1 fix: candidate should be auto-enqueued into the ApprovalQueue
|
|
294
302
|
expect(result.approvalId).not.toBeNull();
|
|
303
|
+
|
|
304
|
+
// EP002-R4 follow-up #2: the scribe artifact carries the LEDGER UUID (not
|
|
305
|
+
// a title) so the evaluator propagates it into the rule artifact and the
|
|
306
|
+
// Console groups the approval by an id the detail page can resolve.
|
|
307
|
+
const verify = new RuntimeStateManager({ workspaceDir: tmpDir });
|
|
308
|
+
await verify.initialize();
|
|
309
|
+
try {
|
|
310
|
+
const scribeArt = await verify.piArtifactStore.getArtifactById(
|
|
311
|
+
(await verify.piArtifactStore.listBySourceTaskId(result.stages.find((s) => s.name === 'scribe')!.taskId!))
|
|
312
|
+
.find((a) => a.artifactKind === 'principle')!.artifactId,
|
|
313
|
+
);
|
|
314
|
+
expect(scribeArt?.sourcePrincipleId).toBe('ledger-principle-001');
|
|
315
|
+
const ruleArt = await verify.piArtifactStore.getArtifactById(result.ruleArtifactId!);
|
|
316
|
+
expect(ruleArt?.sourcePrincipleId).toBe('ledger-principle-001');
|
|
317
|
+
} finally {
|
|
318
|
+
await verify.close();
|
|
319
|
+
}
|
|
295
320
|
}, 60_000);
|
|
296
321
|
|
|
297
322
|
it('adversarial feedback loop drives a second artificer round before creating a candidate', async () => {
|
|
@@ -350,17 +375,29 @@ describe('runRuleHostPipeline (PRI-429) — atomic capability + exact pain match
|
|
|
350
375
|
expect(artificerPrompts[1]).toContain('Prior adversarial replay failures');
|
|
351
376
|
expect(result.decision, JSON.stringify(result)).toBe('candidate_ready_for_owner_review');
|
|
352
377
|
expect(result.ruleArtifactId).toMatch(/^pi-rule-/);
|
|
353
|
-
//
|
|
354
|
-
|
|
378
|
+
// Owner Decision Experience v1 Phase A: this seed carries no candidateId and
|
|
379
|
+
// no ledger principle, so identity binding is unverified (candidate_unresolved)
|
|
380
|
+
// and the governance publication boundary refuses the approval enqueue — the
|
|
381
|
+
// two-round adversarial loop itself is unaffected.
|
|
382
|
+
expect(result.approvalId).toBeNull();
|
|
383
|
+
expect(result.degradationReason ?? '').toContain('identity_binding_unverified');
|
|
355
384
|
}, 60_000);
|
|
356
385
|
|
|
357
386
|
// ── Test 2: Capability OFF (explicitly disabled) → text_principle_only ──
|
|
358
|
-
it('capability OFF (explicitly disabled) → text_principle_only', async () => {
|
|
387
|
+
it('capability OFF (explicitly disabled) → text_principle_only + prompt approval enqueue + identity backfill (PRI-804)', async () => {
|
|
359
388
|
tmpDir = makeTmpDir();
|
|
360
389
|
const sm = new RuntimeStateManager({ workspaceDir: tmpDir });
|
|
361
390
|
await sm.initialize();
|
|
362
|
-
await seedDreamerWithId(sm, 'dreamer-seeded-002', 'pain-test-001');
|
|
391
|
+
await seedDreamerWithId(sm, 'dreamer-seeded-002', 'pain-test-001', 'code_tool_hook', 'cand-002');
|
|
363
392
|
await sm.close();
|
|
393
|
+
// PRI-804(a): seed the ledger with the principle this chain's candidate maps
|
|
394
|
+
// to, mirroring what the intake bridge creates in production workspaces.
|
|
395
|
+
addPrincipleToLedger(path.join(tmpDir, '.state'), {
|
|
396
|
+
id: 'ledger-principle-002', version: 1, text: 'test ledger principle', triggerPattern: '', action: '',
|
|
397
|
+
status: 'candidate', evaluability: 'weak_heuristic', priority: 'P1', scope: 'general',
|
|
398
|
+
valueScore: 0, adherenceRate: 0, painPreventedCount: 0, derivedFromPainIds: ['cand-002'],
|
|
399
|
+
ruleIds: [], conflictsWithPrincipleIds: [], createdAt: '2026-09-15T00:00:00.000Z', updatedAt: '2026-09-15T00:00:00.000Z',
|
|
400
|
+
});
|
|
364
401
|
|
|
365
402
|
const adapter = makeAdapter();
|
|
366
403
|
const capability: CodeRuleCapability = { enabled: false, disabledReason: 'artificer agent disabled in config' };
|
|
@@ -380,6 +417,29 @@ describe('runRuleHostPipeline (PRI-429) — atomic capability + exact pain match
|
|
|
380
417
|
// Adversarial loop stage should be skipped (not present or skipped status).
|
|
381
418
|
const advStage = result.stages.find((s) => s.name === 'adversarial_loop');
|
|
382
419
|
expect(advStage?.status).toBe('skipped');
|
|
420
|
+
|
|
421
|
+
// PRI-804: the text principle must NOT dead-end — it is enqueued into the
|
|
422
|
+
// EXISTING approval queue on the prompt channel for Owner Console review.
|
|
423
|
+
expect(result.approvalId).not.toBeNull();
|
|
424
|
+
expect(result.approvalId).toBe(`apr_prompt_${result.principleArtifactId}`);
|
|
425
|
+
|
|
426
|
+
// Verify the persisted approval row, the PRI-804(a) identity backfill, and
|
|
427
|
+
// the terminal validation marking (real store, real SQLite, real ledger).
|
|
428
|
+
const verify = new RuntimeStateManager({ workspaceDir: tmpDir });
|
|
429
|
+
await verify.initialize();
|
|
430
|
+
try {
|
|
431
|
+
const approvalStore = new SqliteApprovalQueueStore(verify.connection);
|
|
432
|
+
const record = await approvalStore.getById(result.approvalId!);
|
|
433
|
+
expect(record).not.toBeNull();
|
|
434
|
+
expect(record!.status).toBe('pending');
|
|
435
|
+
expect(record!.channel).toBe('prompt');
|
|
436
|
+
expect(record!.artifactId).toBe(result.principleArtifactId);
|
|
437
|
+
const artifact = await verify.piArtifactStore.getArtifactById(result.principleArtifactId!);
|
|
438
|
+
expect(artifact?.sourcePrincipleId).toBe('ledger-principle-002');
|
|
439
|
+
expect(artifact?.validationStatus).toBe('validated');
|
|
440
|
+
} finally {
|
|
441
|
+
await verify.close();
|
|
442
|
+
}
|
|
383
443
|
}, 60_000);
|
|
384
444
|
|
|
385
445
|
// ── Test 3: Capability ON + evaluator rejected → generation_rejected ──
|
|
@@ -626,8 +686,14 @@ describe('runRuleHostPipeline (PRI-429) — atomic capability + exact pain match
|
|
|
626
686
|
expect(dreamerCallCount).toBe(2);
|
|
627
687
|
expect(dreamerStage?.status).toBe('succeeded');
|
|
628
688
|
expect(result.decision).toBe('candidate_ready_for_owner_review');
|
|
629
|
-
//
|
|
630
|
-
|
|
689
|
+
// Owner Decision Experience v1 Phase A: this seed carries NO candidateId,
|
|
690
|
+
// so the chain cannot bind a ledger principle (candidate_unresolved). The
|
|
691
|
+
// rule artifact is produced and preserved, but the governance publication
|
|
692
|
+
// boundary REFUSES to create an Owner approval subject for it.
|
|
693
|
+
expect(result.approvalId).toBeNull();
|
|
694
|
+
expect(result.degradationReason ?? '').toContain('identity_binding_unverified');
|
|
695
|
+
expect(result.degradationReason ?? '').toContain('candidate_unresolved');
|
|
696
|
+
expect(result.ruleArtifactId).not.toBeNull();
|
|
631
697
|
}, 60_000);
|
|
632
698
|
|
|
633
699
|
// ── Test 9 (E fix): retried status exhausted → stage marked 'degraded' ──
|
|
@@ -705,7 +771,6 @@ function writeLanguageConfig(dir: string, outputLanguage?: 'en'): void {
|
|
|
705
771
|
evaluator: { enabled: false },
|
|
706
772
|
rolloutReviewer: { enabled: false },
|
|
707
773
|
correctionObserver: { enabled: false },
|
|
708
|
-
empathyObserver: { enabled: false },
|
|
709
774
|
},
|
|
710
775
|
},
|
|
711
776
|
ui: { diagnostics: { mode: 'simple' } },
|
|
@@ -807,3 +872,304 @@ describe('runRuleHostPipeline — outputLanguage reaches adapter.startRun messag
|
|
|
807
872
|
expect(dreamer?.payload).toContain('dreamer-lang-zh-001');
|
|
808
873
|
}, 60_000);
|
|
809
874
|
});
|
|
875
|
+
|
|
876
|
+
// ── Owner Decision Experience v1 Phase A — identity fix-forward (SPEC §9) ────
|
|
877
|
+
//
|
|
878
|
+
// §9.4 deterministic acceptance slice, exercised against the REAL production
|
|
879
|
+
// path (real RuntimeStateManager, real SQLite, real ledger adapter):
|
|
880
|
+
// success / ledger missing / ambiguous / conflict / write failure / replay.
|
|
881
|
+
// Failure slices must prove: NO approval enqueue, NO activation, NO duplicate
|
|
882
|
+
// ledger — while the generated artifacts stay preserved for later replay.
|
|
883
|
+
|
|
884
|
+
describe('runRuleHostPipeline — Phase A governance publication boundary (identity fix-forward)', () => {
|
|
885
|
+
afterEach(() => {
|
|
886
|
+
vi.restoreAllMocks();
|
|
887
|
+
if (tmpDir) { try { fs.rmSync(tmpDir, { recursive: true, force: true }); } catch { /* ignore */ } tmpDir = ''; }
|
|
888
|
+
});
|
|
889
|
+
|
|
890
|
+
function seedLedger(dir: string, id: string, candidateId: string): void {
|
|
891
|
+
addPrincipleToLedger(path.join(dir, '.state'), {
|
|
892
|
+
id, version: 1, text: `principle ${id}`, triggerPattern: '', action: '',
|
|
893
|
+
status: 'candidate', evaluability: 'weak_heuristic', priority: 'P1', scope: 'general',
|
|
894
|
+
valueScore: 0, adherenceRate: 0, painPreventedCount: 0, derivedFromPainIds: [candidateId],
|
|
895
|
+
ruleIds: [], conflictsWithPrincipleIds: [], createdAt: '2026-09-15T00:00:00.000Z', updatedAt: '2026-09-15T00:00:00.000Z',
|
|
896
|
+
});
|
|
897
|
+
}
|
|
898
|
+
|
|
899
|
+
async function countApprovalsForArtifact(dir: string, artifactId: string): Promise<number> {
|
|
900
|
+
const verify = new RuntimeStateManager({ workspaceDir: dir });
|
|
901
|
+
await verify.initialize();
|
|
902
|
+
try {
|
|
903
|
+
const rows = verify.connection.getDb()
|
|
904
|
+
.prepare('SELECT COUNT(*) AS n FROM approvals WHERE artifact_id = ?').all(artifactId);
|
|
905
|
+
const first = rows[0] as { n: number } | undefined;
|
|
906
|
+
return first?.n ?? 0;
|
|
907
|
+
} finally {
|
|
908
|
+
await verify.close();
|
|
909
|
+
}
|
|
910
|
+
}
|
|
911
|
+
|
|
912
|
+
async function countActivations(dir: string): Promise<number> {
|
|
913
|
+
const verify = new RuntimeStateManager({ workspaceDir: dir });
|
|
914
|
+
await verify.initialize();
|
|
915
|
+
try {
|
|
916
|
+
const rows = verify.connection.getDb().prepare('SELECT COUNT(*) AS n FROM activations').all();
|
|
917
|
+
const first = rows[0] as { n: number } | undefined;
|
|
918
|
+
return first?.n ?? 0;
|
|
919
|
+
} finally {
|
|
920
|
+
await verify.close();
|
|
921
|
+
}
|
|
922
|
+
}
|
|
923
|
+
|
|
924
|
+
async function ledgerPrincipleCount(dir: string): Promise<number> {
|
|
925
|
+
const ledgerPath = path.join(dir, '.state', 'principle_training_state.json');
|
|
926
|
+
if (!fs.existsSync(ledgerPath)) return 0; // no ledger file yet = zero principles
|
|
927
|
+
const parsed = JSON.parse(fs.readFileSync(ledgerPath, 'utf8')) as { _tree?: { principles?: Record<string, unknown> } };
|
|
928
|
+
return Object.keys(parsed._tree?.principles ?? {}).length;
|
|
929
|
+
}
|
|
930
|
+
|
|
931
|
+
it('ledger_missing: rule artifact preserved, but NO approval subject, NO activation, ledger untouched', async () => {
|
|
932
|
+
tmpDir = makeTmpDir();
|
|
933
|
+
const sm = new RuntimeStateManager({ workspaceDir: tmpDir });
|
|
934
|
+
await sm.initialize();
|
|
935
|
+
await seedDreamerWithId(sm, 'dreamer-id-missing', 'pain-id-missing', 'code_tool_hook', 'cand-no-ledger');
|
|
936
|
+
await sm.close();
|
|
937
|
+
// Deliberately NO ledger principle for cand-no-ledger.
|
|
938
|
+
|
|
939
|
+
const adapter = makeAdapter();
|
|
940
|
+
const result = await runRuleHostPipeline({
|
|
941
|
+
workspaceDir: tmpDir, painId: 'pain-id-missing', runtimeAdapter: adapter,
|
|
942
|
+
channel: 'code_tool_hook', pollIntervalMs: 5, timeoutMs: 1000,
|
|
943
|
+
codeRuleCapability: { enabled: true, artificerAdapter: adapter },
|
|
944
|
+
behaviorExamplePack: PIPE_PACK,
|
|
945
|
+
onStoreReady: (store) => { adapter.artifactStore = store; },
|
|
946
|
+
});
|
|
947
|
+
|
|
948
|
+
expect(result.decision, JSON.stringify(result)).toBe('candidate_ready_for_owner_review');
|
|
949
|
+
// The generation chain produced and PRESERVED its artifacts…
|
|
950
|
+
expect(result.ruleArtifactId).not.toBeNull();
|
|
951
|
+
// …but the publication boundary refused to create an Owner approval subject.
|
|
952
|
+
expect(result.approvalId).toBeNull();
|
|
953
|
+
expect(result.degradationReason ?? '').toContain('identity_binding_unverified');
|
|
954
|
+
expect(result.degradationReason ?? '').toContain('ledger_missing');
|
|
955
|
+
expect(await countApprovalsForArtifact(tmpDir, result.ruleArtifactId!)).toBe(0);
|
|
956
|
+
expect(await countActivations(tmpDir)).toBe(0);
|
|
957
|
+
expect(await ledgerPrincipleCount(tmpDir)).toBe(0);
|
|
958
|
+
}, 60_000);
|
|
959
|
+
|
|
960
|
+
it('ledger_ambiguous: two ledger targets for one candidate refuse publication and refuse a silent first-match binding', async () => {
|
|
961
|
+
tmpDir = makeTmpDir();
|
|
962
|
+
const sm = new RuntimeStateManager({ workspaceDir: tmpDir });
|
|
963
|
+
await sm.initialize();
|
|
964
|
+
await seedDreamerWithId(sm, 'dreamer-id-ambiguous', 'pain-id-ambiguous', 'code_tool_hook', 'cand-ambiguous');
|
|
965
|
+
await sm.close();
|
|
966
|
+
seedLedger(tmpDir, 'ledger-A', 'cand-ambiguous');
|
|
967
|
+
seedLedger(tmpDir, 'ledger-B', 'cand-ambiguous');
|
|
968
|
+
|
|
969
|
+
const adapter = makeAdapter();
|
|
970
|
+
const result = await runRuleHostPipeline({
|
|
971
|
+
workspaceDir: tmpDir, painId: 'pain-id-ambiguous', runtimeAdapter: adapter,
|
|
972
|
+
channel: 'code_tool_hook', pollIntervalMs: 5, timeoutMs: 1000,
|
|
973
|
+
codeRuleCapability: { enabled: true, artificerAdapter: adapter },
|
|
974
|
+
behaviorExamplePack: PIPE_PACK,
|
|
975
|
+
onStoreReady: (store) => { adapter.artifactStore = store; },
|
|
976
|
+
});
|
|
977
|
+
|
|
978
|
+
expect(result.decision).toBe('candidate_ready_for_owner_review');
|
|
979
|
+
expect(result.approvalId).toBeNull();
|
|
980
|
+
expect(result.degradationReason ?? '').toContain('ledger_ambiguous');
|
|
981
|
+
expect(await countApprovalsForArtifact(tmpDir, result.ruleArtifactId!)).toBe(0);
|
|
982
|
+
// The scribe artifact must NOT be silently bound to the first match.
|
|
983
|
+
const verify = new RuntimeStateManager({ workspaceDir: tmpDir });
|
|
984
|
+
await verify.initialize();
|
|
985
|
+
try {
|
|
986
|
+
const scribeTaskId = result.stages.find((s) => s.name === 'scribe')!.taskId!;
|
|
987
|
+
const scribeArt = (await verify.piArtifactStore.listBySourceTaskId(scribeTaskId)).find((a) => a.artifactKind === 'principle');
|
|
988
|
+
expect(scribeArt?.sourcePrincipleId).toBeUndefined();
|
|
989
|
+
} finally {
|
|
990
|
+
await verify.close();
|
|
991
|
+
}
|
|
992
|
+
}, 60_000);
|
|
993
|
+
|
|
994
|
+
it('identity_conflict: an existing binding to a different ledger target is never overwritten (§9.1.7)', async () => {
|
|
995
|
+
tmpDir = makeTmpDir();
|
|
996
|
+
const sm = new RuntimeStateManager({ workspaceDir: tmpDir });
|
|
997
|
+
await sm.initialize();
|
|
998
|
+
await seedDreamerWithId(sm, 'dreamer-id-conflict', 'pain-id-conflict', 'code_tool_hook', 'cand-conflict');
|
|
999
|
+
await sm.close();
|
|
1000
|
+
seedLedger(tmpDir, 'ledger-original', 'cand-conflict');
|
|
1001
|
+
|
|
1002
|
+
const adapter = makeAdapter();
|
|
1003
|
+
const first = await runRuleHostPipeline({
|
|
1004
|
+
workspaceDir: tmpDir, painId: 'pain-id-conflict', runtimeAdapter: adapter,
|
|
1005
|
+
channel: 'code_tool_hook', pollIntervalMs: 5, timeoutMs: 1000,
|
|
1006
|
+
codeRuleCapability: { enabled: true, artificerAdapter: adapter },
|
|
1007
|
+
behaviorExamplePack: PIPE_PACK,
|
|
1008
|
+
onStoreReady: (store) => { adapter.artifactStore = store; },
|
|
1009
|
+
});
|
|
1010
|
+
expect(first.approvalId).not.toBeNull();
|
|
1011
|
+
|
|
1012
|
+
// Repoint the candidate: detach it from the original principle so the
|
|
1013
|
+
// chain now resolves to a DIFFERENT (still unique) target. Otherwise the
|
|
1014
|
+
// plural lookup would correctly report ledger_ambiguous, not a conflict.
|
|
1015
|
+
updatePrinciple(path.join(tmpDir, '.state'), 'ledger-original', { derivedFromPainIds: [] });
|
|
1016
|
+
seedLedger(tmpDir, 'ledger-replacement', 'cand-conflict');
|
|
1017
|
+
const verify = new RuntimeStateManager({ workspaceDir: tmpDir });
|
|
1018
|
+
await verify.initialize();
|
|
1019
|
+
try {
|
|
1020
|
+
const scribeTaskId = first.stages.find((s) => s.name === 'scribe')!.taskId!;
|
|
1021
|
+
const binding = await backfillScribeIdentity({
|
|
1022
|
+
stateManager: verify,
|
|
1023
|
+
artifactStore: verify.piArtifactStore,
|
|
1024
|
+
scribeTaskId,
|
|
1025
|
+
dreamerTaskId: 'dreamer-id-conflict',
|
|
1026
|
+
workspaceDir: tmpDir,
|
|
1027
|
+
now: new Date().toISOString(),
|
|
1028
|
+
});
|
|
1029
|
+
expect(binding).toEqual({ status: 'identity_conflict', existingPrincipleId: 'ledger-original', resolvedPrincipleId: 'ledger-replacement' });
|
|
1030
|
+
const scribeArt = (await verify.piArtifactStore.listBySourceTaskId(scribeTaskId)).find((a) => a.artifactKind === 'principle');
|
|
1031
|
+
expect(scribeArt?.sourcePrincipleId).toBe('ledger-original');
|
|
1032
|
+
} finally {
|
|
1033
|
+
await verify.close();
|
|
1034
|
+
}
|
|
1035
|
+
}, 60_000);
|
|
1036
|
+
|
|
1037
|
+
it('binding_write_failed / binding_readback_failed: store failures are structured, never silently accepted', async () => {
|
|
1038
|
+
tmpDir = makeTmpDir();
|
|
1039
|
+
const sm = new RuntimeStateManager({ workspaceDir: tmpDir });
|
|
1040
|
+
await sm.initialize();
|
|
1041
|
+
await seedDreamerWithId(sm, 'dreamer-id-wf', 'pain-id-wf', 'code_tool_hook', 'cand-wf');
|
|
1042
|
+
await sm.close();
|
|
1043
|
+
seedLedger(tmpDir, 'ledger-wf', 'cand-wf');
|
|
1044
|
+
|
|
1045
|
+
// Run once through the real path so a REAL scribe artifact exists.
|
|
1046
|
+
const adapter = makeAdapter();
|
|
1047
|
+
const run = await runRuleHostPipeline({
|
|
1048
|
+
workspaceDir: tmpDir, painId: 'pain-id-wf', runtimeAdapter: adapter,
|
|
1049
|
+
channel: 'prompt', pollIntervalMs: 5, timeoutMs: 1000,
|
|
1050
|
+
onStoreReady: (store) => { adapter.artifactStore = store; },
|
|
1051
|
+
});
|
|
1052
|
+
expect(run.decision).toBe('text_principle_only');
|
|
1053
|
+
|
|
1054
|
+
const verify = new RuntimeStateManager({ workspaceDir: tmpDir });
|
|
1055
|
+
await verify.initialize();
|
|
1056
|
+
const scribeTaskId = run.stages.find((s) => s.name === 'scribe')!.taskId!;
|
|
1057
|
+
try {
|
|
1058
|
+
// The real run already bound + verified — replay must be idempotent.
|
|
1059
|
+
const idempotent = await backfillScribeIdentity({
|
|
1060
|
+
stateManager: verify, artifactStore: verify.piArtifactStore, scribeTaskId,
|
|
1061
|
+
dreamerTaskId: 'dreamer-id-wf', workspaceDir: tmpDir, now: new Date().toISOString(),
|
|
1062
|
+
});
|
|
1063
|
+
expect(idempotent).toEqual({ status: 'already_bound', principleId: 'ledger-wf' });
|
|
1064
|
+
|
|
1065
|
+
// Write failure: upsert throws.
|
|
1066
|
+
const throwingStore = new Proxy(verify.piArtifactStore, {
|
|
1067
|
+
get(target, prop, receiver) {
|
|
1068
|
+
if (prop === 'upsertArtifact') {
|
|
1069
|
+
return async () => { throw new Error('sqlite locked (simulated)'); };
|
|
1070
|
+
}
|
|
1071
|
+
return Reflect.get(target, prop, receiver);
|
|
1072
|
+
},
|
|
1073
|
+
});
|
|
1074
|
+
// For the write-failure slice we need an UNBOUND artifact: use a second,
|
|
1075
|
+
// unbound scribe-shaped artifact created directly in the store.
|
|
1076
|
+
const taskId2 = 'scribe-unbound-task';
|
|
1077
|
+
await verify.createTask({ taskId: taskId2, taskKind: 'scribe', status: 'succeeded', attemptCount: 0, maxAttempts: 3, diagnosticJson: JSON.stringify({ pi_metadata: { channel: 'prompt', dependencyTaskIds: [], timeoutMs: 1000 } }) });
|
|
1078
|
+
await verify.piArtifactStore.createArtifact({
|
|
1079
|
+
artifactId: 'pi-art-unbound-1', artifactKind: 'principle', sourceTaskId: taskId2,
|
|
1080
|
+
lineageArtifactIds: [], validationStatus: 'pending', contentJson: '{}',
|
|
1081
|
+
createdAt: new Date().toISOString(), updatedAt: new Date().toISOString(),
|
|
1082
|
+
});
|
|
1083
|
+
const failed = await backfillScribeIdentity({
|
|
1084
|
+
stateManager: verify, artifactStore: throwingStore, scribeTaskId: taskId2,
|
|
1085
|
+
dreamerTaskId: 'dreamer-id-wf', workspaceDir: tmpDir, now: new Date().toISOString(),
|
|
1086
|
+
});
|
|
1087
|
+
expect(failed.status).toBe('binding_write_failed');
|
|
1088
|
+
|
|
1089
|
+
// Read-back failure: upsert "succeeds" but the store returns a row without
|
|
1090
|
+
// the binding (write lost / wrong row).
|
|
1091
|
+
const staleStore = new Proxy(verify.piArtifactStore, {
|
|
1092
|
+
get(target, prop, receiver) {
|
|
1093
|
+
if (prop === 'getArtifactById') {
|
|
1094
|
+
return async () => null;
|
|
1095
|
+
}
|
|
1096
|
+
return Reflect.get(target, prop, receiver);
|
|
1097
|
+
},
|
|
1098
|
+
});
|
|
1099
|
+
const stale = await backfillScribeIdentity({
|
|
1100
|
+
stateManager: verify, artifactStore: staleStore, scribeTaskId: taskId2,
|
|
1101
|
+
dreamerTaskId: 'dreamer-id-wf', workspaceDir: tmpDir, now: new Date().toISOString(),
|
|
1102
|
+
});
|
|
1103
|
+
expect(stale.status).toBe('binding_readback_failed');
|
|
1104
|
+
} finally {
|
|
1105
|
+
await verify.close();
|
|
1106
|
+
}
|
|
1107
|
+
}, 60_000);
|
|
1108
|
+
|
|
1109
|
+
it('text path: unverified binding preserves the principle artifact but creates NO approval (candidate_unresolved)', async () => {
|
|
1110
|
+
tmpDir = makeTmpDir();
|
|
1111
|
+
const sm = new RuntimeStateManager({ workspaceDir: tmpDir });
|
|
1112
|
+
await sm.initialize();
|
|
1113
|
+
// No candidateId on the seed — candidate_unresolved.
|
|
1114
|
+
await seedDreamerWithId(sm, 'dreamer-text-noid', 'pain-text-noid', 'prompt');
|
|
1115
|
+
await sm.close();
|
|
1116
|
+
|
|
1117
|
+
const adapter = makeAdapter();
|
|
1118
|
+
const result = await runRuleHostPipeline({
|
|
1119
|
+
workspaceDir: tmpDir, painId: 'pain-text-noid', runtimeAdapter: adapter,
|
|
1120
|
+
channel: 'prompt', pollIntervalMs: 5, timeoutMs: 1000,
|
|
1121
|
+
onStoreReady: (store) => { adapter.artifactStore = store; },
|
|
1122
|
+
});
|
|
1123
|
+
|
|
1124
|
+
expect(result.decision).toBe('text_principle_only');
|
|
1125
|
+
expect(result.principleArtifactId).not.toBeNull();
|
|
1126
|
+
expect(result.approvalId).toBeNull();
|
|
1127
|
+
expect(result.degradationReason ?? '').toContain('identity_binding_unverified');
|
|
1128
|
+
expect(result.degradationReason ?? '').toContain('candidate_unresolved');
|
|
1129
|
+
expect(await countApprovalsForArtifact(tmpDir, result.principleArtifactId!)).toBe(0);
|
|
1130
|
+
// The artifact is still marked validated — preserved, publishable later.
|
|
1131
|
+
const verify = new RuntimeStateManager({ workspaceDir: tmpDir });
|
|
1132
|
+
await verify.initialize();
|
|
1133
|
+
try {
|
|
1134
|
+
const artifact = await verify.piArtifactStore.getArtifactById(result.principleArtifactId!);
|
|
1135
|
+
expect(artifact?.validationStatus).toBe('validated');
|
|
1136
|
+
expect(artifact?.sourcePrincipleId).toBeUndefined();
|
|
1137
|
+
} finally {
|
|
1138
|
+
await verify.close();
|
|
1139
|
+
}
|
|
1140
|
+
}, 60_000);
|
|
1141
|
+
|
|
1142
|
+
it('replay after identity repair publishes: seed ledger mid-flight is unnecessary — repair-then-rerun enqueues (§9.1.8)', async () => {
|
|
1143
|
+
tmpDir = makeTmpDir();
|
|
1144
|
+
const sm = new RuntimeStateManager({ workspaceDir: tmpDir });
|
|
1145
|
+
await sm.initialize();
|
|
1146
|
+
await seedDreamerWithId(sm, 'dreamer-repair', 'pain-repair', 'prompt', 'cand-repair');
|
|
1147
|
+
await sm.close();
|
|
1148
|
+
|
|
1149
|
+
const adapter1 = makeAdapter();
|
|
1150
|
+
const refused = await runRuleHostPipeline({
|
|
1151
|
+
workspaceDir: tmpDir, painId: 'pain-repair', runtimeAdapter: adapter1,
|
|
1152
|
+
channel: 'prompt', pollIntervalMs: 5, timeoutMs: 1000,
|
|
1153
|
+
onStoreReady: (store) => { adapter1.artifactStore = store; },
|
|
1154
|
+
});
|
|
1155
|
+
expect(refused.approvalId).toBeNull();
|
|
1156
|
+
|
|
1157
|
+
// Identity repair: the ledger entry for the candidate appears (e.g. intake
|
|
1158
|
+
// completed or the ledger was restored). Replay publishes.
|
|
1159
|
+
seedLedger(tmpDir, 'ledger-repaired', 'cand-repair');
|
|
1160
|
+
const adapter2 = makeAdapter();
|
|
1161
|
+
// Run 2 RESUMES run 1's succeeded dreamer seed (no new dreamer startRun) —
|
|
1162
|
+
// pre-register that call so the scripted philosopher can resolve its
|
|
1163
|
+
// sourceDreamerArtifactId lineage from the shared store.
|
|
1164
|
+
adapter2.startRunCalls.push({ taskId: 'dreamer-repair' });
|
|
1165
|
+
const published = await runRuleHostPipeline({
|
|
1166
|
+
workspaceDir: tmpDir, painId: 'pain-repair', runtimeAdapter: adapter2,
|
|
1167
|
+
channel: 'prompt', pollIntervalMs: 5, timeoutMs: 1000,
|
|
1168
|
+
onStoreReady: (store) => { adapter2.artifactStore = store; },
|
|
1169
|
+
});
|
|
1170
|
+
expect(published.approvalId, JSON.stringify(published, null, 1)).not.toBeNull();
|
|
1171
|
+
expect(published.principleArtifactId).not.toBe(refused.principleArtifactId);
|
|
1172
|
+
// Exactly one ledger principle exists — the pipeline never creates one.
|
|
1173
|
+
expect(await ledgerPrincipleCount(tmpDir)).toBe(1);
|
|
1174
|
+
}, 60_000);
|
|
1175
|
+
});
|
|
@@ -1,25 +0,0 @@
|
|
|
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
|
-
export interface ContextTraceOptions {
|
|
19
|
-
workspace?: string;
|
|
20
|
-
task?: string;
|
|
21
|
-
artifact?: string;
|
|
22
|
-
json?: boolean;
|
|
23
|
-
}
|
|
24
|
-
export declare function handleRuntimeInternalizationContextTrace(opts: ContextTraceOptions): Promise<void>;
|
|
25
|
-
//# sourceMappingURL=runtime-internalization-context-trace.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"runtime-internalization-context-trace.d.ts","sourceRoot":"","sources":["../../src/commands/runtime-internalization-context-trace.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAeH,MAAM,WAAW,mBAAmB;IAClC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAuLD,wBAAsB,wCAAwC,CAAC,IAAI,EAAE,mBAAmB,GAAG,OAAO,CAAC,IAAI,CAAC,CAiOvG"}
|