@principles/pd-cli 1.154.0 → 1.154.3
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/build-trajectory-evidence.d.ts +21 -0
- package/dist/commands/build-trajectory-evidence.d.ts.map +1 -1
- package/dist/commands/build-trajectory-evidence.js +136 -24
- package/dist/commands/build-trajectory-evidence.js.map +1 -1
- package/dist/commands/candidate.d.ts +6 -4
- package/dist/commands/candidate.d.ts.map +1 -1
- package/dist/commands/candidate.js +150 -34
- package/dist/commands/candidate.js.map +1 -1
- package/dist/commands/diagnose.d.ts.map +1 -1
- package/dist/commands/diagnose.js +54 -4
- package/dist/commands/diagnose.js.map +1 -1
- package/dist/commands/health.d.ts.map +1 -1
- package/dist/commands/health.js +61 -0
- package/dist/commands/health.js.map +1 -1
- package/dist/commands/pain-record.d.ts.map +1 -1
- package/dist/commands/pain-record.js +43 -7
- package/dist/commands/pain-record.js.map +1 -1
- package/dist/commands/pain-retry.d.ts.map +1 -1
- package/dist/commands/pain-retry.js +51 -2
- 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 +6 -0
- package/dist/commands/runtime-activation.js.map +1 -1
- package/dist/services/reuse-gated-intake.d.ts +14 -0
- package/dist/services/reuse-gated-intake.d.ts.map +1 -0
- package/dist/services/reuse-gated-intake.js +53 -0
- package/dist/services/reuse-gated-intake.js.map +1 -0
- package/dist/services/workspace-telemetry.d.ts +16 -0
- package/dist/services/workspace-telemetry.d.ts.map +1 -0
- package/dist/services/workspace-telemetry.js +24 -0
- package/dist/services/workspace-telemetry.js.map +1 -0
- package/package.json +3 -3
|
@@ -47,4 +47,25 @@ export type TrajectoryEvidenceAcquisition = {
|
|
|
47
47
|
* - `empty_trajectory` — real session, no usable evidence rows.
|
|
48
48
|
*/
|
|
49
49
|
export declare function acquireTrajectoryEvidenceFromDb(stateDir: string, sessionId: string | undefined, workspaceDir?: string): TrajectoryEvidenceAcquisition;
|
|
50
|
+
/**
|
|
51
|
+
* PRI-941 Option A (Owner-approved) — Codex-scoped evidence acquisition for
|
|
52
|
+
* `pd pain record --host codex`.
|
|
53
|
+
*
|
|
54
|
+
* Boundary discipline (PRI-940/941 audits): this function reads ONLY the
|
|
55
|
+
* `tool_calls` failure rows (the already-authorized PRI-624 tool-governance
|
|
56
|
+
* evidence surface) for the caller-supplied Codex root session. Conversation
|
|
57
|
+
* tables (`user_turns` / `assistant_turns`) are NEVER queried here — they
|
|
58
|
+
* remain ingestion-exclusive behind the G2A consent boundary — and rollout
|
|
59
|
+
* transcript files are never opened. Binding authority stays with the
|
|
60
|
+
* caller-supplied PRI-743 lineage tuple: no sessions-table check runs, so an
|
|
61
|
+
* `unavailable` result never carries a binding claim.
|
|
62
|
+
*
|
|
63
|
+
* Outcomes:
|
|
64
|
+
* - `available` — ≥1 failure row → real behavior-trace entries;
|
|
65
|
+
* - `trajectory_unavailable` — no trajectory.db in this workspace;
|
|
66
|
+
* - `evidence_read_failed` — the DB exists but cannot be opened/read;
|
|
67
|
+
* - `empty_trajectory` — DB readable, zero failure rows for the session
|
|
68
|
+
* (detail: `codex_tool_calls_empty`).
|
|
69
|
+
*/
|
|
70
|
+
export declare function acquireCodexToolFailureEvidenceFromDb(stateDir: string, sessionId: string | undefined, workspaceDir?: string): TrajectoryEvidenceAcquisition;
|
|
50
71
|
//# sourceMappingURL=build-trajectory-evidence.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"build-trajectory-evidence.d.ts","sourceRoot":"","sources":["../../src/commands/build-trajectory-evidence.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAUH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,6BAA6B,CAAC;AAErE;;;;;;;;;;;;;;GAcG;AACH,MAAM,MAAM,6BAA6B,GACrC;IAAE,MAAM,EAAE,WAAW,CAAC;IAAC,OAAO,EAAE,iBAAiB,EAAE,CAAA;CAAE,GACrD;IACE,MAAM,EAAE,aAAa,CAAC;IACtB,UAAU,EAAE,wBAAwB,GAAG,mBAAmB,GAAG,kBAAkB,GAAG,sBAAsB,CAAC;IACzG,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,UAAU,GAAG,YAAY,CAAC;CACpC,CAAC;
|
|
1
|
+
{"version":3,"file":"build-trajectory-evidence.d.ts","sourceRoot":"","sources":["../../src/commands/build-trajectory-evidence.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAUH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,6BAA6B,CAAC;AAErE;;;;;;;;;;;;;;GAcG;AACH,MAAM,MAAM,6BAA6B,GACrC;IAAE,MAAM,EAAE,WAAW,CAAC;IAAC,OAAO,EAAE,iBAAiB,EAAE,CAAA;CAAE,GACrD;IACE,MAAM,EAAE,aAAa,CAAC;IACtB,UAAU,EAAE,wBAAwB,GAAG,mBAAmB,GAAG,kBAAkB,GAAG,sBAAsB,CAAC;IACzG,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,UAAU,GAAG,YAAY,CAAC;CACpC,CAAC;AAqMN;;;;;;;;;;;;GAYG;AACH,wBAAgB,+BAA+B,CAC7C,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,MAAM,GAAG,SAAS,EAC7B,YAAY,CAAC,EAAE,MAAM,GACpB,6BAA6B,CAgF/B;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,qCAAqC,CACnD,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,MAAM,GAAG,SAAS,EAC7B,YAAY,CAAC,EAAE,MAAM,GACpB,6BAA6B,CAyD/B"}
|
|
@@ -20,6 +20,51 @@ const PLACEHOLDER_SOURCE_REFS = new Set([
|
|
|
20
20
|
'tool_call_failure:unavailable',
|
|
21
21
|
'trajectory:empty',
|
|
22
22
|
]);
|
|
23
|
+
/**
|
|
24
|
+
* PRI-941 Option A — the SINGLE reader of `tool_calls` failure rows, shared by
|
|
25
|
+
* the OpenClaw acquisition (collectEvidenceFromDb) and the Codex-scoped
|
|
26
|
+
* acquisition (acquireCodexToolFailureEvidenceFromDb) so the two hosts can
|
|
27
|
+
* never drift. Never throws: a missing/unreadable `tool_calls` table is
|
|
28
|
+
* reported through `readFailed` and the caller owns placeholder handling.
|
|
29
|
+
*/
|
|
30
|
+
function readToolFailureEvidence(db, sessionId, workspaceDir) {
|
|
31
|
+
const entries = [];
|
|
32
|
+
let readFailed = false;
|
|
33
|
+
try {
|
|
34
|
+
const failedToolCalls = db.prepare(`
|
|
35
|
+
SELECT tool_name, error_type, exit_code, result_preview, created_at
|
|
36
|
+
FROM (
|
|
37
|
+
SELECT tool_name, error_type, exit_code, result_preview, created_at
|
|
38
|
+
FROM tool_calls
|
|
39
|
+
WHERE session_id = ? AND outcome = 'failure'
|
|
40
|
+
ORDER BY created_at DESC
|
|
41
|
+
LIMIT 3
|
|
42
|
+
)
|
|
43
|
+
ORDER BY created_at ASC
|
|
44
|
+
`).all(sessionId);
|
|
45
|
+
for (const tc of failedToolCalls) {
|
|
46
|
+
const toolName = typeof tc.tool_name === 'string' ? tc.tool_name : 'unknown';
|
|
47
|
+
const errorType = typeof tc.error_type === 'string' ? tc.error_type : 'unknown';
|
|
48
|
+
const exitCode = tc.exit_code != null ? String(tc.exit_code) : 'N/A';
|
|
49
|
+
// Enhanced: append resultPreview when available. PRI-941 Owner review:
|
|
50
|
+
// the preview enters UNSLICED — every truncation (redact-then-bound)
|
|
51
|
+
// is owned by sanitizeString on the COMPLETE composed note. Pre-slicing
|
|
52
|
+
// here could cut a credential across the sanitizer's token-pattern
|
|
53
|
+
// threshold and let the fragment escape redaction.
|
|
54
|
+
const resultPreview = typeof tc.result_preview === 'string' ? tc.result_preview : null;
|
|
55
|
+
const previewSuffix = resultPreview ? ` | ${resultPreview}` : '';
|
|
56
|
+
const note = `Tool ${toolName} failed: ${errorType} (exitCode: ${exitCode})${previewSuffix}`;
|
|
57
|
+
entries.push({
|
|
58
|
+
sourceRef: `tool_call_failure:${String(tc.created_at ?? 'unknown')}`,
|
|
59
|
+
note: sanitizeString(note, workspaceDir),
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
catch {
|
|
64
|
+
readFailed = true;
|
|
65
|
+
}
|
|
66
|
+
return { entries, readFailed };
|
|
67
|
+
}
|
|
23
68
|
/**
|
|
24
69
|
* Collect evidence entries from an open trajectory.db for one session.
|
|
25
70
|
* Shared by the typed acquisition API and the legacy array wrapper so the
|
|
@@ -95,36 +140,26 @@ function collectEvidenceFromDb(db, sessionId, workspaceDir) {
|
|
|
95
140
|
}
|
|
96
141
|
// PRI-358: Try to read failed tool_calls (last 3 failures, chronological order)
|
|
97
142
|
try {
|
|
98
|
-
const
|
|
99
|
-
|
|
100
|
-
FROM (
|
|
101
|
-
SELECT tool_name, error_type, exit_code, result_preview, created_at
|
|
102
|
-
FROM tool_calls
|
|
103
|
-
WHERE session_id = ? AND outcome = 'failure'
|
|
104
|
-
ORDER BY created_at DESC
|
|
105
|
-
LIMIT 3
|
|
106
|
-
)
|
|
107
|
-
ORDER BY created_at ASC
|
|
108
|
-
`).all(sessionId);
|
|
109
|
-
for (const tc of failedToolCalls) {
|
|
143
|
+
const toolFailure = readToolFailureEvidence(db, sessionId, workspaceDir);
|
|
144
|
+
for (const entry of toolFailure.entries) {
|
|
110
145
|
if (evidence.length >= MAX_EVIDENCE_ENTRIES)
|
|
111
146
|
break;
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
}
|
|
147
|
+
evidence.push(entry);
|
|
148
|
+
}
|
|
149
|
+
if (toolFailure.readFailed) {
|
|
150
|
+
readFailed = true;
|
|
151
|
+
// tool_calls table may not exist — degrade gracefully (only when no other evidence)
|
|
152
|
+
if (evidence.length === 0) {
|
|
153
|
+
evidence.push({
|
|
154
|
+
sourceRef: 'tool_call_failure:unavailable',
|
|
155
|
+
note: 'trajectory_tool_calls_unavailable',
|
|
156
|
+
});
|
|
157
|
+
}
|
|
123
158
|
}
|
|
124
159
|
}
|
|
125
160
|
catch {
|
|
161
|
+
// defensive: readToolFailureEvidence never throws (internally caught)
|
|
126
162
|
readFailed = true;
|
|
127
|
-
// tool_calls table may not exist — degrade gracefully (only when no other evidence)
|
|
128
163
|
if (evidence.length === 0) {
|
|
129
164
|
evidence.push({
|
|
130
165
|
sourceRef: 'tool_call_failure:unavailable',
|
|
@@ -236,4 +271,81 @@ export function acquireTrajectoryEvidenceFromDb(stateDir, sessionId, workspaceDi
|
|
|
236
271
|
db.close();
|
|
237
272
|
}
|
|
238
273
|
}
|
|
274
|
+
/**
|
|
275
|
+
* PRI-941 Option A (Owner-approved) — Codex-scoped evidence acquisition for
|
|
276
|
+
* `pd pain record --host codex`.
|
|
277
|
+
*
|
|
278
|
+
* Boundary discipline (PRI-940/941 audits): this function reads ONLY the
|
|
279
|
+
* `tool_calls` failure rows (the already-authorized PRI-624 tool-governance
|
|
280
|
+
* evidence surface) for the caller-supplied Codex root session. Conversation
|
|
281
|
+
* tables (`user_turns` / `assistant_turns`) are NEVER queried here — they
|
|
282
|
+
* remain ingestion-exclusive behind the G2A consent boundary — and rollout
|
|
283
|
+
* transcript files are never opened. Binding authority stays with the
|
|
284
|
+
* caller-supplied PRI-743 lineage tuple: no sessions-table check runs, so an
|
|
285
|
+
* `unavailable` result never carries a binding claim.
|
|
286
|
+
*
|
|
287
|
+
* Outcomes:
|
|
288
|
+
* - `available` — ≥1 failure row → real behavior-trace entries;
|
|
289
|
+
* - `trajectory_unavailable` — no trajectory.db in this workspace;
|
|
290
|
+
* - `evidence_read_failed` — the DB exists but cannot be opened/read;
|
|
291
|
+
* - `empty_trajectory` — DB readable, zero failure rows for the session
|
|
292
|
+
* (detail: `codex_tool_calls_empty`).
|
|
293
|
+
*/
|
|
294
|
+
export function acquireCodexToolFailureEvidenceFromDb(stateDir, sessionId, workspaceDir) {
|
|
295
|
+
if (!sessionId || sessionId === 'cli' || sessionId === 'unknown') {
|
|
296
|
+
return {
|
|
297
|
+
status: 'unavailable',
|
|
298
|
+
reasonCode: 'session_not_found',
|
|
299
|
+
detail: sessionId ? `sentinel_session_id:${sessionId}` : 'missing_session_id',
|
|
300
|
+
binding: 'unverified',
|
|
301
|
+
};
|
|
302
|
+
}
|
|
303
|
+
const dbPath = path.join(stateDir, 'trajectory.db');
|
|
304
|
+
if (!fs.existsSync(dbPath)) {
|
|
305
|
+
return {
|
|
306
|
+
status: 'unavailable',
|
|
307
|
+
reasonCode: 'trajectory_unavailable',
|
|
308
|
+
detail: 'trajectory_db_missing',
|
|
309
|
+
binding: 'unverified',
|
|
310
|
+
};
|
|
311
|
+
}
|
|
312
|
+
let db;
|
|
313
|
+
try {
|
|
314
|
+
db = new Database(dbPath, { readonly: true });
|
|
315
|
+
}
|
|
316
|
+
catch (err) {
|
|
317
|
+
return {
|
|
318
|
+
status: 'unavailable',
|
|
319
|
+
reasonCode: 'evidence_read_failed',
|
|
320
|
+
detail: `trajectory_db_unreadable: ${err instanceof Error ? err.message : String(err)}`,
|
|
321
|
+
binding: 'unverified',
|
|
322
|
+
};
|
|
323
|
+
}
|
|
324
|
+
try {
|
|
325
|
+
const toolFailure = readToolFailureEvidence(db, sessionId, workspaceDir);
|
|
326
|
+
// PRI-941 review F2 (rc-9 precision): a missing/unreadable tool_calls
|
|
327
|
+
// table is a DIFFERENT fact from "zero failure rows" — report it as
|
|
328
|
+
// evidence_read_failed, mirroring the sibling OpenClaw acquisition.
|
|
329
|
+
if (toolFailure.readFailed) {
|
|
330
|
+
return {
|
|
331
|
+
status: 'unavailable',
|
|
332
|
+
reasonCode: 'evidence_read_failed',
|
|
333
|
+
detail: 'codex_tool_calls_unreadable',
|
|
334
|
+
binding: 'unverified',
|
|
335
|
+
};
|
|
336
|
+
}
|
|
337
|
+
if (toolFailure.entries.length === 0) {
|
|
338
|
+
return {
|
|
339
|
+
status: 'unavailable',
|
|
340
|
+
reasonCode: 'empty_trajectory',
|
|
341
|
+
detail: 'codex_tool_calls_empty',
|
|
342
|
+
binding: 'unverified',
|
|
343
|
+
};
|
|
344
|
+
}
|
|
345
|
+
return { status: 'available', entries: toolFailure.entries };
|
|
346
|
+
}
|
|
347
|
+
finally {
|
|
348
|
+
db.close();
|
|
349
|
+
}
|
|
350
|
+
}
|
|
239
351
|
//# sourceMappingURL=build-trajectory-evidence.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"build-trajectory-evidence.js","sourceRoot":"","sources":["../../src/commands/build-trajectory-evidence.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,QAAQ,MAAM,gBAAgB,CAAC;AACtC,OAAO,KAAK,EAAE,MAAM,IAAI,CAAC;AACzB,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAC7B,OAAO,EACL,oBAAoB,EACpB,uBAAuB,EACvB,cAAc,GACf,MAAM,6BAA6B,CAAC;AA2BrC,gFAAgF;AAChF,MAAM,uBAAuB,GAAG,IAAI,GAAG,CAAC;IACtC,oBAAoB;IACpB,2BAA2B;IAC3B,wBAAwB;IACxB,+BAA+B;IAC/B,kBAAkB;CACnB,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"build-trajectory-evidence.js","sourceRoot":"","sources":["../../src/commands/build-trajectory-evidence.ts"],"names":[],"mappings":"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"}
|
|
@@ -95,10 +95,12 @@ export declare function handleCandidateReview(opts: CandidateReviewOptions): Pro
|
|
|
95
95
|
/**
|
|
96
96
|
* pd candidate audit --workspace <path> [--json]
|
|
97
97
|
*
|
|
98
|
-
*
|
|
99
|
-
*
|
|
100
|
-
*
|
|
101
|
-
*
|
|
98
|
+
* Delegates the judgment to the core auditCandidateLedgerConsistency so every
|
|
99
|
+
* surface (pd candidate audit, pd health, operator health) applies the SAME
|
|
100
|
+
* reuse-aware rules (PRI-917 / R7): reuse resolutions and non-Principle-Ledger
|
|
101
|
+
* kinds are not "missing"; only a consumed principle-kind candidate with no
|
|
102
|
+
* resolution anywhere is true drift.
|
|
103
|
+
* Exits non-zero if any consumed candidate is truly missing from the ledger.
|
|
102
104
|
*/
|
|
103
105
|
export declare function handleCandidateAudit(opts: CandidateAuditOptions): Promise<void>;
|
|
104
106
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"candidate.d.ts","sourceRoot":"","sources":["../../src/commands/candidate.ts"],"names":[],"mappings":"AAgBA,OAAO,EACL,mBAAmB,EA0BpB,MAAM,6BAA6B,CAAC;
|
|
1
|
+
{"version":3,"file":"candidate.d.ts","sourceRoot":"","sources":["../../src/commands/candidate.ts"],"names":[],"mappings":"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"}
|
|
@@ -14,13 +14,15 @@
|
|
|
14
14
|
*/
|
|
15
15
|
import { randomUUID } from 'crypto';
|
|
16
16
|
import * as path from 'path';
|
|
17
|
-
import { RuntimeStateManager,
|
|
17
|
+
import { RuntimeStateManager, candidateList, candidateShow, CandidateIntakeService, CandidateIntakeError, INTAKE_ERROR_CODES, decideInternalizationRoute, buildDreamerSeedFromCandidate, findExistingDreamerTask, parseSeedSourcePainId, PrincipleTreeLedgerAdapter,
|
|
18
18
|
// PRI-917 PR3A: the review surface consumes the SAME proposal/semantics
|
|
19
19
|
// machinery as the intake gate (audit C4 — one implementation, no drift).
|
|
20
|
-
buildReuseProposal, buildReuseShortlist, extractIntakeRecommendation, isPrincipleLedgerEligibleKind, resolveOwnerIdentity, defaultOwnerIdentityHomeDir, ReuseEvaluationRunner, ReuseEvaluationError,
|
|
20
|
+
buildReuseProposal, buildReuseShortlist, extractIntakeRecommendation, isPrincipleLedgerEligibleKind, resolveOwnerIdentity, defaultOwnerIdentityHomeDir, ReuseEvaluationRunner, ReuseEvaluationError, createBridgeTelemetryEventEmitter, auditCandidateLedgerConsistency, } from '@principles/core/runtime-v2';
|
|
21
21
|
import { loadLedger, getLedgerFilePathPublic } from '@principles/core/principle-tree-ledger';
|
|
22
22
|
import { resolveWorkspaceDir } from '../resolve-workspace.js';
|
|
23
|
+
import { createWorkspaceTelemetryEmitter } from '../services/workspace-telemetry.js';
|
|
23
24
|
import { loadPdConfig } from '../services/pd-config-loader.js';
|
|
25
|
+
import { createReuseGatedIntakeService } from '../services/reuse-gated-intake.js';
|
|
24
26
|
import { resolveRuntimeAdapterFromConfig } from '../services/runtime-adapter-resolver.js';
|
|
25
27
|
import { resolvePromptFullPipelineSeedMode } from '../services/pd-config-loader.js';
|
|
26
28
|
import { createRemediationResult, remediationAction } from './remediation-output.js';
|
|
@@ -455,6 +457,60 @@ async function reportReuseResolution(opts) {
|
|
|
455
457
|
console.log(` Candidate Status: ${consumedState === 'already_consumed' ? 'already consumed (INV-R07 replay)' : 'consumed'}`);
|
|
456
458
|
console.log(' Evidence: recorded on the Principle\'s reuseEvidence (append-only)\n');
|
|
457
459
|
}
|
|
460
|
+
// ── Shared park reporting (R7 gate-bypass fix, adhoc-20261007) ────────────────
|
|
461
|
+
/**
|
|
462
|
+
* Emit the park observation (`reuse_gate_triggered`) on the durable
|
|
463
|
+
* workspace telemetry sink, mirroring the bridge / diagnose / pain-retry
|
|
464
|
+
* paths (PRI-939 Option A). A manual-command park must be observable in the
|
|
465
|
+
* same place the automatic ones are — telemetry is how parked candidates are
|
|
466
|
+
* audited (R7 Wave-2 gate audit).
|
|
467
|
+
*/
|
|
468
|
+
function emitReuseGateParkedTelemetry(workspaceDir, candidateId, recommended) {
|
|
469
|
+
createBridgeTelemetryEventEmitter(createWorkspaceTelemetryEmitter(workspaceDir)).emitTelemetry({
|
|
470
|
+
eventType: 'reuse_gate_triggered',
|
|
471
|
+
traceId: candidateId,
|
|
472
|
+
timestamp: new Date().toISOString(),
|
|
473
|
+
payload: {
|
|
474
|
+
candidateId,
|
|
475
|
+
...(recommended?.selectedPrincipleId !== undefined ? { selectedPrincipleId: recommended.selectedPrincipleId } : {}),
|
|
476
|
+
...(recommended ? { confidence: recommended.confidence, recommendation: recommended.recommendation } : {}),
|
|
477
|
+
},
|
|
478
|
+
});
|
|
479
|
+
}
|
|
480
|
+
/**
|
|
481
|
+
* Report a `reuse_pending_owner` intake result from the MANUAL paths
|
|
482
|
+
* (`pd candidate intake` / `pd candidate repair`): the gate suspects a
|
|
483
|
+
* semantic duplicate, so nothing was written and the candidate awaits the
|
|
484
|
+
* Owner. Exit code stays 0 — a park is the gate working, not a command
|
|
485
|
+
* failure (same posture as diagnose / pain-retry / the bridge: park is not
|
|
486
|
+
* counted as intake failure). cli-6: the result carries a structured reason
|
|
487
|
+
* and the executable next action (`pd candidate review --decide`).
|
|
488
|
+
*/
|
|
489
|
+
function reportReusePark(opts) {
|
|
490
|
+
const recommended = opts.result.reuseRecommendation?.status === 'recommended' ? opts.result.reuseRecommendation : undefined;
|
|
491
|
+
emitReuseGateParkedTelemetry(opts.workspaceDir, opts.candidateId, recommended);
|
|
492
|
+
const review = {
|
|
493
|
+
candidateId: opts.candidateId,
|
|
494
|
+
status: 'review_required',
|
|
495
|
+
reason: 'reuse_review_required',
|
|
496
|
+
reusedPrincipleId: recommended?.selectedPrincipleId,
|
|
497
|
+
...(recommended ? { confidence: recommended.confidence } : {}),
|
|
498
|
+
message: opts.result.message,
|
|
499
|
+
nextAction: `pd candidate review --candidate-id ${opts.candidateId} --decide reuse|create --reason "..."`,
|
|
500
|
+
};
|
|
501
|
+
if (opts.json) {
|
|
502
|
+
console.log(JSON.stringify(review, null, 2));
|
|
503
|
+
return;
|
|
504
|
+
}
|
|
505
|
+
console.log(`\nPrinciple Candidate ${opts.commandLabel}: ${opts.candidateId} — reuse review required\n`);
|
|
506
|
+
console.log(` Candidate: ${opts.candidateId}`);
|
|
507
|
+
if (recommended?.selectedPrincipleId !== undefined) {
|
|
508
|
+
console.log(` Suspected Duplicate Of: ${recommended.selectedPrincipleId} (confidence ${recommended.confidence})`);
|
|
509
|
+
}
|
|
510
|
+
console.log(` Status: review_required (no Principle was created)`);
|
|
511
|
+
console.log(` Message: ${review.message}`);
|
|
512
|
+
console.log(` Next Action: ${review.nextAction}\n`);
|
|
513
|
+
}
|
|
458
514
|
async function evaluateReuseProposal(workspaceDir, claim, entries) {
|
|
459
515
|
const configLoad = loadPdConfig(workspaceDir);
|
|
460
516
|
const effective = configLoad.ok ? configLoad.effective : configLoad.defaults;
|
|
@@ -639,7 +695,12 @@ export async function handleCandidateIntake(opts) {
|
|
|
639
695
|
try {
|
|
640
696
|
await stateManager.initialize();
|
|
641
697
|
const ledgerAdapter = new PrincipleTreeLedgerAdapter({ stateDir: path.join(workspaceDir, '.state') });
|
|
642
|
-
|
|
698
|
+
// R7 gate-bypass fix (adhoc-20261007): construct through the shared gated
|
|
699
|
+
// assembly so the manual intake path runs the Reuse Review Gate exactly
|
|
700
|
+
// like diagnose / pain-retry / the bridge. A bare construction left
|
|
701
|
+
// reuseCheck='not_configured' and let semantic duplicates go straight to
|
|
702
|
+
// CREATE (R7 Wave-2 audit D-1, P0).
|
|
703
|
+
const service = createReuseGatedIntakeService({ stateManager, ledgerAdapter, workspaceDir });
|
|
643
704
|
// Fetch candidate once for admission gate check and downstream paths.
|
|
644
705
|
const candidate = await stateManager.getCandidate(opts.candidateId);
|
|
645
706
|
if (!candidate) {
|
|
@@ -720,6 +781,20 @@ export async function handleCandidateIntake(opts) {
|
|
|
720
781
|
await reportReuseResolution({ stateManager, candidateId: opts.candidateId, result: intakeResult, json: opts.json === true });
|
|
721
782
|
return;
|
|
722
783
|
}
|
|
784
|
+
if (intakeResult.outcome === 'refused' && intakeResult.reason === 'reuse_pending_owner') {
|
|
785
|
+
// R7 gate-bypass fix: the Reuse Review Gate parked this candidate as a
|
|
786
|
+
// suspected duplicate. No ledger entry was written and the candidate
|
|
787
|
+
// stays pending for the Owner — do NOT mark it consumed. cli-5: this
|
|
788
|
+
// path performs no state mutation at all.
|
|
789
|
+
reportReusePark({
|
|
790
|
+
workspaceDir,
|
|
791
|
+
candidateId: opts.candidateId,
|
|
792
|
+
result: intakeResult,
|
|
793
|
+
json: opts.json === true,
|
|
794
|
+
commandLabel: 'Intake',
|
|
795
|
+
});
|
|
796
|
+
return;
|
|
797
|
+
}
|
|
723
798
|
if (intakeResult.outcome === 'refused') {
|
|
724
799
|
throw new CandidateIntakeError(INTAKE_ERROR_CODES.INPUT_INVALID, `Principle Ledger write refused: ${intakeResult.message}`, { candidateId: opts.candidateId, reason: intakeResult.reason });
|
|
725
800
|
}
|
|
@@ -906,10 +981,13 @@ export async function handleCandidateReview(opts) {
|
|
|
906
981
|
// Owner's verdict lives exclusively in Principle.reuseEvidence[]) and
|
|
907
982
|
// no intake outcome reads them. Emitted only when the capability
|
|
908
983
|
// actually ran (disabled or nothing-to-evaluate emits nothing).
|
|
984
|
+
// PRI-939 Option A: persist allowlisted events (reuse_evaluation_unavailable)
|
|
985
|
+
// to the workspace sink instead of the unsubscribed singleton.
|
|
986
|
+
const workspaceTelemetry = createWorkspaceTelemetryEmitter(workspaceDir);
|
|
909
987
|
if (evaluation !== null) {
|
|
910
988
|
const timestamp = new Date().toISOString();
|
|
911
989
|
if (evaluation.status === 'recommended') {
|
|
912
|
-
|
|
990
|
+
workspaceTelemetry.emitTelemetry({
|
|
913
991
|
eventType: 'reuse_evaluation_recommended',
|
|
914
992
|
traceId: opts.candidateId,
|
|
915
993
|
timestamp,
|
|
@@ -924,7 +1002,7 @@ export async function handleCandidateReview(opts) {
|
|
|
924
1002
|
});
|
|
925
1003
|
}
|
|
926
1004
|
else {
|
|
927
|
-
|
|
1005
|
+
workspaceTelemetry.emitTelemetry({
|
|
928
1006
|
eventType: 'reuse_evaluation_unavailable',
|
|
929
1007
|
traceId: opts.candidateId,
|
|
930
1008
|
timestamp,
|
|
@@ -1024,35 +1102,32 @@ export async function handleCandidateReview(opts) {
|
|
|
1024
1102
|
/**
|
|
1025
1103
|
* pd candidate audit --workspace <path> [--json]
|
|
1026
1104
|
*
|
|
1027
|
-
*
|
|
1028
|
-
*
|
|
1029
|
-
*
|
|
1030
|
-
*
|
|
1105
|
+
* Delegates the judgment to the core auditCandidateLedgerConsistency so every
|
|
1106
|
+
* surface (pd candidate audit, pd health, operator health) applies the SAME
|
|
1107
|
+
* reuse-aware rules (PRI-917 / R7): reuse resolutions and non-Principle-Ledger
|
|
1108
|
+
* kinds are not "missing"; only a consumed principle-kind candidate with no
|
|
1109
|
+
* resolution anywhere is true drift.
|
|
1110
|
+
* Exits non-zero if any consumed candidate is truly missing from the ledger.
|
|
1031
1111
|
*/
|
|
1032
1112
|
export async function handleCandidateAudit(opts) {
|
|
1033
1113
|
const workspaceDir = resolveWorkspaceDir(opts.workspace);
|
|
1034
|
-
let conn;
|
|
1035
1114
|
try {
|
|
1036
1115
|
const dbPath = path.join(workspaceDir, '.pd', 'state.db');
|
|
1037
1116
|
const ledgerStateDir = path.join(workspaceDir, '.state');
|
|
1038
1117
|
const ledgerPath = getLedgerFilePathPublic(ledgerStateDir);
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
const missingLedgerEntryIds = [];
|
|
1046
|
-
for (const candidateId of consumedIds) {
|
|
1047
|
-
const found = Object.values(ledgerPrinciples).some((p) => p.derivedFromPainIds.includes(candidateId));
|
|
1048
|
-
if (!found) {
|
|
1049
|
-
missingLedgerEntryIds.push(candidateId);
|
|
1050
|
-
}
|
|
1118
|
+
const audit = await auditCandidateLedgerConsistency(workspaceDir);
|
|
1119
|
+
if (audit.status === 'error') {
|
|
1120
|
+
console.error(`Audit failed: ${audit.reason ?? 'could not read candidate/ledger state'}`);
|
|
1121
|
+
console.error('Next action: open this workspace once with the PD runtime to create/migrate state.db, then retry the audit.');
|
|
1122
|
+
process.exit(1);
|
|
1123
|
+
return;
|
|
1051
1124
|
}
|
|
1052
1125
|
const result = {
|
|
1053
|
-
status:
|
|
1054
|
-
consumedCount:
|
|
1055
|
-
missingLedgerEntryIds,
|
|
1126
|
+
status: audit.status,
|
|
1127
|
+
consumedCount: audit.consumedCount,
|
|
1128
|
+
missingLedgerEntryIds: audit.missingLedgerEntryIds ?? [],
|
|
1129
|
+
reusedResolvedCount: audit.reusedResolvedCount ?? 0,
|
|
1130
|
+
nonLedgerKindCount: audit.nonLedgerKindCount ?? 0,
|
|
1056
1131
|
checkedLedgerPath: ledgerPath,
|
|
1057
1132
|
checkedDbPath: dbPath,
|
|
1058
1133
|
};
|
|
@@ -1062,6 +1137,8 @@ export async function handleCandidateAudit(opts) {
|
|
|
1062
1137
|
else {
|
|
1063
1138
|
console.log(`\nCandidate Audit Results\n`);
|
|
1064
1139
|
console.log(` consumedCount: ${result.consumedCount}`);
|
|
1140
|
+
console.log(` reusedResolvedCount: ${result.reusedResolvedCount}`);
|
|
1141
|
+
console.log(` nonLedgerKindCount: ${result.nonLedgerKindCount}`);
|
|
1065
1142
|
console.log(` checkedLedgerPath: ${result.checkedLedgerPath}`);
|
|
1066
1143
|
console.log(` checkedDbPath: ${result.checkedDbPath}`);
|
|
1067
1144
|
console.log(` status: ${result.status}`);
|
|
@@ -1070,7 +1147,7 @@ export async function handleCandidateAudit(opts) {
|
|
|
1070
1147
|
result.missingLedgerEntryIds.forEach(id => console.log(` - ${id}`));
|
|
1071
1148
|
}
|
|
1072
1149
|
else {
|
|
1073
|
-
console.log(`\n All consumed candidates have ledger
|
|
1150
|
+
console.log(`\n All consumed candidates have ledger resolutions.`);
|
|
1074
1151
|
}
|
|
1075
1152
|
console.log('');
|
|
1076
1153
|
}
|
|
@@ -1082,12 +1159,6 @@ export async function handleCandidateAudit(opts) {
|
|
|
1082
1159
|
console.error(`Audit failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
1083
1160
|
process.exit(1);
|
|
1084
1161
|
}
|
|
1085
|
-
finally {
|
|
1086
|
-
try {
|
|
1087
|
-
conn?.close();
|
|
1088
|
-
}
|
|
1089
|
-
catch { /* best-effort close */ }
|
|
1090
|
-
}
|
|
1091
1162
|
}
|
|
1092
1163
|
// ── Repair ─────────────────────────────────────────────────────────────────────
|
|
1093
1164
|
/**
|
|
@@ -1138,7 +1209,11 @@ export async function handleCandidateRepair(opts) {
|
|
|
1138
1209
|
return;
|
|
1139
1210
|
}
|
|
1140
1211
|
const ledgerAdapter = new PrincipleTreeLedgerAdapter({ stateDir: path.join(workspaceDir, '.state') });
|
|
1141
|
-
|
|
1212
|
+
// R7 gate-bypass fix (adhoc-20261007): repair re-intakes through the same
|
|
1213
|
+
// gated assembly — otherwise "restore the missing ledger entry" became an
|
|
1214
|
+
// unconditional duplicate-CREATE for orphaned cleanup candidates (R7
|
|
1215
|
+
// Wave-2 audit D-1 §3.3).
|
|
1216
|
+
const service = createReuseGatedIntakeService({ stateManager, ledgerAdapter, workspaceDir });
|
|
1142
1217
|
// Check if already in ledger
|
|
1143
1218
|
const existing = ledgerAdapter.existsForCandidate(opts.candidateId);
|
|
1144
1219
|
if (existing) {
|
|
@@ -1164,6 +1239,20 @@ export async function handleCandidateRepair(opts) {
|
|
|
1164
1239
|
// a write-boundary refusal means the candidate is not principle-eligible —
|
|
1165
1240
|
// fail loud rather than reporting a "repaired" entry that does not exist.
|
|
1166
1241
|
const intakeResult = await service.intake(opts.candidateId);
|
|
1242
|
+
if (intakeResult.outcome === 'refused' && intakeResult.reason === 'reuse_pending_owner') {
|
|
1243
|
+
// R7 gate-bypass fix: the gate suspects a semantic duplicate — restoring
|
|
1244
|
+
// the entry would recreate a near-duplicate Principle. No write happened;
|
|
1245
|
+
// the Owner resolves it via the review channel. cli-5: no mutation on
|
|
1246
|
+
// this path (candidate stays consumed, ledger untouched).
|
|
1247
|
+
reportReusePark({
|
|
1248
|
+
workspaceDir,
|
|
1249
|
+
candidateId: opts.candidateId,
|
|
1250
|
+
result: intakeResult,
|
|
1251
|
+
json: opts.json === true,
|
|
1252
|
+
commandLabel: 'Repair',
|
|
1253
|
+
});
|
|
1254
|
+
return;
|
|
1255
|
+
}
|
|
1167
1256
|
if (intakeResult.outcome === 'refused') {
|
|
1168
1257
|
throw new CandidateIntakeError(INTAKE_ERROR_CODES.INPUT_INVALID, `Ledger repair refused: ${intakeResult.message}`, { candidateId: opts.candidateId, reason: intakeResult.reason });
|
|
1169
1258
|
}
|
|
@@ -1353,7 +1442,11 @@ export async function handleCandidateInternalizationBackfill(opts) {
|
|
|
1353
1442
|
}
|
|
1354
1443
|
}
|
|
1355
1444
|
const ledgerAdapter = new PrincipleTreeLedgerAdapter({ stateDir: path.join(workspaceDir, '.state') });
|
|
1356
|
-
|
|
1445
|
+
// R7 gate-bypass fix (adhoc-20261007): --include-pending intakes parked
|
|
1446
|
+
// (reuse_review_required) candidates too — the worst bypass, because it
|
|
1447
|
+
// consumed the very state the gate created to await the Owner (R7 Wave-2
|
|
1448
|
+
// audit D-1 §3.4). Same gated assembly as every other intake path.
|
|
1449
|
+
const intakeService = createReuseGatedIntakeService({ stateManager, ledgerAdapter, workspaceDir });
|
|
1357
1450
|
for (const row of pendingRows) {
|
|
1358
1451
|
const candidateId = row.candidate_id;
|
|
1359
1452
|
const candidate = await stateManager.getCandidate(candidateId);
|
|
@@ -1417,6 +1510,29 @@ export async function handleCandidateInternalizationBackfill(opts) {
|
|
|
1417
1510
|
// Statuses are deliberately reused from the existing model (SPEC v2.1 §7
|
|
1418
1511
|
// "禁止执行者自行创造新状态"): 'deferred' + 'skipped' rather than a new
|
|
1419
1512
|
// status value.
|
|
1513
|
+
//
|
|
1514
|
+
// R7 gate-bypass fix: a park (reuse_pending_owner) is a DIFFERENT
|
|
1515
|
+
// refusal — the candidate is a suspected duplicate awaiting the Owner.
|
|
1516
|
+
// It must NOT be reported as "no action required" and must NOT be
|
|
1517
|
+
// counted as an intake failure: the gate worked. The candidate stays
|
|
1518
|
+
// pending; only `pd candidate review --decide` resolves it (cli-6).
|
|
1519
|
+
if (intakeResult.outcome === 'refused' && intakeResult.reason === 'reuse_pending_owner') {
|
|
1520
|
+
const recommended = intakeResult.reuseRecommendation?.status === 'recommended' ? intakeResult.reuseRecommendation : undefined;
|
|
1521
|
+
emitReuseGateParkedTelemetry(workspaceDir, candidateId, recommended);
|
|
1522
|
+
output.deferred++;
|
|
1523
|
+
output.results.push({
|
|
1524
|
+
candidateId,
|
|
1525
|
+
route: decision.route,
|
|
1526
|
+
status: 'deferred',
|
|
1527
|
+
reason: `reuse_review_required: candidate is a suspected duplicate${recommended?.selectedPrincipleId !== undefined ? ` of Principle ${recommended.selectedPrincipleId}` : ''} — parked for Owner review`,
|
|
1528
|
+
statusBefore: 'pending',
|
|
1529
|
+
statusAfter: 'pending',
|
|
1530
|
+
intakeDecision: 'skipped',
|
|
1531
|
+
seedDecision: 'skipped',
|
|
1532
|
+
nextAction: `pd candidate review --candidate-id ${candidateId} --decide reuse|create --reason "..."`,
|
|
1533
|
+
});
|
|
1534
|
+
continue;
|
|
1535
|
+
}
|
|
1420
1536
|
if (intakeResult.outcome === 'refused') {
|
|
1421
1537
|
output.results.push({ candidateId, route: decision.route, status: 'deferred', reason: intakeResult.message, statusBefore: 'pending', statusAfter: 'pending', intakeDecision: 'skipped', seedDecision: 'skipped', nextAction: 'No action required: this candidate kind does not target the Principle Ledger.' });
|
|
1422
1538
|
continue;
|