@principles/pd-cli 1.154.1 → 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 +144 -32
- package/dist/commands/candidate.js.map +1 -1
- package/dist/commands/pain-record.d.ts.map +1 -1
- package/dist/commands/pain-record.js +33 -7
- package/dist/commands/pain-record.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/package.json +2 -2
|
@@ -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,
|
|
1
|
+
{"version":3,"file":"candidate.d.ts","sourceRoot":"","sources":["../../src/commands/candidate.ts"],"names":[],"mappings":"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"}
|
|
@@ -14,14 +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, } from '@principles/core/runtime-v2';
|
|
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
23
|
import { createWorkspaceTelemetryEmitter } from '../services/workspace-telemetry.js';
|
|
24
24
|
import { loadPdConfig } from '../services/pd-config-loader.js';
|
|
25
|
+
import { createReuseGatedIntakeService } from '../services/reuse-gated-intake.js';
|
|
25
26
|
import { resolveRuntimeAdapterFromConfig } from '../services/runtime-adapter-resolver.js';
|
|
26
27
|
import { resolvePromptFullPipelineSeedMode } from '../services/pd-config-loader.js';
|
|
27
28
|
import { createRemediationResult, remediationAction } from './remediation-output.js';
|
|
@@ -456,6 +457,60 @@ async function reportReuseResolution(opts) {
|
|
|
456
457
|
console.log(` Candidate Status: ${consumedState === 'already_consumed' ? 'already consumed (INV-R07 replay)' : 'consumed'}`);
|
|
457
458
|
console.log(' Evidence: recorded on the Principle\'s reuseEvidence (append-only)\n');
|
|
458
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
|
+
}
|
|
459
514
|
async function evaluateReuseProposal(workspaceDir, claim, entries) {
|
|
460
515
|
const configLoad = loadPdConfig(workspaceDir);
|
|
461
516
|
const effective = configLoad.ok ? configLoad.effective : configLoad.defaults;
|
|
@@ -640,7 +695,12 @@ export async function handleCandidateIntake(opts) {
|
|
|
640
695
|
try {
|
|
641
696
|
await stateManager.initialize();
|
|
642
697
|
const ledgerAdapter = new PrincipleTreeLedgerAdapter({ stateDir: path.join(workspaceDir, '.state') });
|
|
643
|
-
|
|
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 });
|
|
644
704
|
// Fetch candidate once for admission gate check and downstream paths.
|
|
645
705
|
const candidate = await stateManager.getCandidate(opts.candidateId);
|
|
646
706
|
if (!candidate) {
|
|
@@ -721,6 +781,20 @@ export async function handleCandidateIntake(opts) {
|
|
|
721
781
|
await reportReuseResolution({ stateManager, candidateId: opts.candidateId, result: intakeResult, json: opts.json === true });
|
|
722
782
|
return;
|
|
723
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
|
+
}
|
|
724
798
|
if (intakeResult.outcome === 'refused') {
|
|
725
799
|
throw new CandidateIntakeError(INTAKE_ERROR_CODES.INPUT_INVALID, `Principle Ledger write refused: ${intakeResult.message}`, { candidateId: opts.candidateId, reason: intakeResult.reason });
|
|
726
800
|
}
|
|
@@ -1028,35 +1102,32 @@ export async function handleCandidateReview(opts) {
|
|
|
1028
1102
|
/**
|
|
1029
1103
|
* pd candidate audit --workspace <path> [--json]
|
|
1030
1104
|
*
|
|
1031
|
-
*
|
|
1032
|
-
*
|
|
1033
|
-
*
|
|
1034
|
-
*
|
|
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.
|
|
1035
1111
|
*/
|
|
1036
1112
|
export async function handleCandidateAudit(opts) {
|
|
1037
1113
|
const workspaceDir = resolveWorkspaceDir(opts.workspace);
|
|
1038
|
-
let conn;
|
|
1039
1114
|
try {
|
|
1040
1115
|
const dbPath = path.join(workspaceDir, '.pd', 'state.db');
|
|
1041
1116
|
const ledgerStateDir = path.join(workspaceDir, '.state');
|
|
1042
1117
|
const ledgerPath = getLedgerFilePathPublic(ledgerStateDir);
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
const missingLedgerEntryIds = [];
|
|
1050
|
-
for (const candidateId of consumedIds) {
|
|
1051
|
-
const found = Object.values(ledgerPrinciples).some((p) => p.derivedFromPainIds.includes(candidateId));
|
|
1052
|
-
if (!found) {
|
|
1053
|
-
missingLedgerEntryIds.push(candidateId);
|
|
1054
|
-
}
|
|
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;
|
|
1055
1124
|
}
|
|
1056
1125
|
const result = {
|
|
1057
|
-
status:
|
|
1058
|
-
consumedCount:
|
|
1059
|
-
missingLedgerEntryIds,
|
|
1126
|
+
status: audit.status,
|
|
1127
|
+
consumedCount: audit.consumedCount,
|
|
1128
|
+
missingLedgerEntryIds: audit.missingLedgerEntryIds ?? [],
|
|
1129
|
+
reusedResolvedCount: audit.reusedResolvedCount ?? 0,
|
|
1130
|
+
nonLedgerKindCount: audit.nonLedgerKindCount ?? 0,
|
|
1060
1131
|
checkedLedgerPath: ledgerPath,
|
|
1061
1132
|
checkedDbPath: dbPath,
|
|
1062
1133
|
};
|
|
@@ -1066,6 +1137,8 @@ export async function handleCandidateAudit(opts) {
|
|
|
1066
1137
|
else {
|
|
1067
1138
|
console.log(`\nCandidate Audit Results\n`);
|
|
1068
1139
|
console.log(` consumedCount: ${result.consumedCount}`);
|
|
1140
|
+
console.log(` reusedResolvedCount: ${result.reusedResolvedCount}`);
|
|
1141
|
+
console.log(` nonLedgerKindCount: ${result.nonLedgerKindCount}`);
|
|
1069
1142
|
console.log(` checkedLedgerPath: ${result.checkedLedgerPath}`);
|
|
1070
1143
|
console.log(` checkedDbPath: ${result.checkedDbPath}`);
|
|
1071
1144
|
console.log(` status: ${result.status}`);
|
|
@@ -1074,7 +1147,7 @@ export async function handleCandidateAudit(opts) {
|
|
|
1074
1147
|
result.missingLedgerEntryIds.forEach(id => console.log(` - ${id}`));
|
|
1075
1148
|
}
|
|
1076
1149
|
else {
|
|
1077
|
-
console.log(`\n All consumed candidates have ledger
|
|
1150
|
+
console.log(`\n All consumed candidates have ledger resolutions.`);
|
|
1078
1151
|
}
|
|
1079
1152
|
console.log('');
|
|
1080
1153
|
}
|
|
@@ -1086,12 +1159,6 @@ export async function handleCandidateAudit(opts) {
|
|
|
1086
1159
|
console.error(`Audit failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
1087
1160
|
process.exit(1);
|
|
1088
1161
|
}
|
|
1089
|
-
finally {
|
|
1090
|
-
try {
|
|
1091
|
-
conn?.close();
|
|
1092
|
-
}
|
|
1093
|
-
catch { /* best-effort close */ }
|
|
1094
|
-
}
|
|
1095
1162
|
}
|
|
1096
1163
|
// ── Repair ─────────────────────────────────────────────────────────────────────
|
|
1097
1164
|
/**
|
|
@@ -1142,7 +1209,11 @@ export async function handleCandidateRepair(opts) {
|
|
|
1142
1209
|
return;
|
|
1143
1210
|
}
|
|
1144
1211
|
const ledgerAdapter = new PrincipleTreeLedgerAdapter({ stateDir: path.join(workspaceDir, '.state') });
|
|
1145
|
-
|
|
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 });
|
|
1146
1217
|
// Check if already in ledger
|
|
1147
1218
|
const existing = ledgerAdapter.existsForCandidate(opts.candidateId);
|
|
1148
1219
|
if (existing) {
|
|
@@ -1168,6 +1239,20 @@ export async function handleCandidateRepair(opts) {
|
|
|
1168
1239
|
// a write-boundary refusal means the candidate is not principle-eligible —
|
|
1169
1240
|
// fail loud rather than reporting a "repaired" entry that does not exist.
|
|
1170
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
|
+
}
|
|
1171
1256
|
if (intakeResult.outcome === 'refused') {
|
|
1172
1257
|
throw new CandidateIntakeError(INTAKE_ERROR_CODES.INPUT_INVALID, `Ledger repair refused: ${intakeResult.message}`, { candidateId: opts.candidateId, reason: intakeResult.reason });
|
|
1173
1258
|
}
|
|
@@ -1357,7 +1442,11 @@ export async function handleCandidateInternalizationBackfill(opts) {
|
|
|
1357
1442
|
}
|
|
1358
1443
|
}
|
|
1359
1444
|
const ledgerAdapter = new PrincipleTreeLedgerAdapter({ stateDir: path.join(workspaceDir, '.state') });
|
|
1360
|
-
|
|
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 });
|
|
1361
1450
|
for (const row of pendingRows) {
|
|
1362
1451
|
const candidateId = row.candidate_id;
|
|
1363
1452
|
const candidate = await stateManager.getCandidate(candidateId);
|
|
@@ -1421,6 +1510,29 @@ export async function handleCandidateInternalizationBackfill(opts) {
|
|
|
1421
1510
|
// Statuses are deliberately reused from the existing model (SPEC v2.1 §7
|
|
1422
1511
|
// "禁止执行者自行创造新状态"): 'deferred' + 'skipped' rather than a new
|
|
1423
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
|
+
}
|
|
1424
1536
|
if (intakeResult.outcome === 'refused') {
|
|
1425
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.' });
|
|
1426
1538
|
continue;
|