create-principles-disciple 1.144.20 → 1.144.22
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/_release/product-identity.json +2 -2
- package/codex-adapter/dist/codex-evidence-recorder.d.ts +56 -0
- package/codex-adapter/dist/codex-evidence-recorder.js +235 -0
- package/codex-adapter/dist/pd-hook.d.ts +6 -0
- package/codex-adapter/dist/pd-hook.js +96 -13
- package/codex-adapter/package.json +1 -1
- package/console/dist/server/index.js +18 -0
- package/console/dist/server/models/ActivationsConsoleModel.d.ts +13 -1
- package/console/dist/server/models/ActivationsConsoleModel.js +54 -2
- package/console/dist/server/models/ApprovalsConsoleModel.d.ts +98 -19
- package/console/dist/server/models/ApprovalsConsoleModel.js +338 -29
- package/console/dist/server/models/ApprovalsGroupedConsoleModel.d.ts +17 -7
- package/console/dist/server/models/ApprovalsGroupedConsoleModel.js +134 -54
- package/console/dist/server/models/ReceiptsConsoleModel.d.ts +44 -1
- package/console/dist/server/models/ReceiptsConsoleModel.js +102 -0
- package/console/dist/server/routes/activations.js +96 -1
- package/console/dist/server/routes/approvals-grouped.js +15 -2
- package/console/dist/server/routes/approvals.js +40 -2
- package/console/dist/server/routes/evidence-outcomes.d.ts +29 -0
- package/console/dist/server/routes/evidence-outcomes.js +137 -0
- package/console/dist/server/routes/receipts.js +56 -0
- package/console/dist/shared/prompt-injection-contract.d.ts +71 -0
- package/console/dist/ui/api.d.ts +94 -4
- package/console/dist/ui/api.js +277 -8
- package/console/dist/ui/i18n/en.json +113 -13
- package/console/dist/ui/i18n/zh-CN.json +113 -13
- package/console/dist/ui/pages/activation/ActivationPage.js +80 -2
- package/console/dist/ui/pages/focus/FocusPage.js +49 -21
- package/console/dist/ui/pages/principles/PrincipleDetailPage.js +68 -3
- package/console/dist/ui/utils/approval-warning-localization.js +39 -0
- package/console/dist/ui/utils/validators.d.ts +10 -1
- package/console/dist/ui/utils/validators.js +126 -0
- package/console/dist/web/assets/app.css +15 -0
- package/console/dist/web/assets/app.js +29 -28
- package/core/dist/runtime-v2/activation/activation-dispatcher.d.ts +4 -0
- package/core/dist/runtime-v2/activation/activation-dispatcher.d.ts.map +1 -1
- package/core/dist/runtime-v2/activation/activation-dispatcher.js +215 -63
- package/core/dist/runtime-v2/activation/activation-dispatcher.js.map +1 -1
- package/core/dist/runtime-v2/activation/activation-types.d.ts +48 -0
- package/core/dist/runtime-v2/activation/activation-types.d.ts.map +1 -1
- package/core/dist/runtime-v2/activation/activation-types.js.map +1 -1
- package/core/dist/runtime-v2/activation/approval-completion-service.d.ts +9 -0
- package/core/dist/runtime-v2/activation/approval-completion-service.d.ts.map +1 -1
- package/core/dist/runtime-v2/activation/approval-completion-service.js +4 -1
- package/core/dist/runtime-v2/activation/approval-completion-service.js.map +1 -1
- package/core/dist/runtime-v2/activation/index.d.ts +4 -2
- package/core/dist/runtime-v2/activation/index.d.ts.map +1 -1
- package/core/dist/runtime-v2/activation/index.js +4 -1
- package/core/dist/runtime-v2/activation/index.js.map +1 -1
- package/core/dist/runtime-v2/activation/low-risk-writers.d.ts.map +1 -1
- package/core/dist/runtime-v2/activation/low-risk-writers.js +2 -1
- package/core/dist/runtime-v2/activation/low-risk-writers.js.map +1 -1
- package/core/dist/runtime-v2/activation/prompt-activation-reader-contract.d.ts +11 -0
- package/core/dist/runtime-v2/activation/prompt-activation-reader-contract.d.ts.map +1 -1
- package/core/dist/runtime-v2/activation/prompt-activation-reader-contract.js +12 -2
- package/core/dist/runtime-v2/activation/prompt-activation-reader-contract.js.map +1 -1
- package/core/dist/runtime-v2/activation/prompt-replacement.d.ts +79 -0
- package/core/dist/runtime-v2/activation/prompt-replacement.d.ts.map +1 -0
- package/core/dist/runtime-v2/activation/prompt-replacement.js +171 -0
- package/core/dist/runtime-v2/activation/prompt-replacement.js.map +1 -0
- package/core/dist/runtime-v2/activation/sqlite-activation-state-store.d.ts +17 -1
- package/core/dist/runtime-v2/activation/sqlite-activation-state-store.d.ts.map +1 -1
- package/core/dist/runtime-v2/activation/sqlite-activation-state-store.js +132 -0
- package/core/dist/runtime-v2/activation/sqlite-activation-state-store.js.map +1 -1
- package/core/dist/runtime-v2/index.d.ts +8 -2
- package/core/dist/runtime-v2/index.d.ts.map +1 -1
- package/core/dist/runtime-v2/index.js +8 -2
- package/core/dist/runtime-v2/index.js.map +1 -1
- package/core/dist/runtime-v2/internalization/scribe-prompt-builder.d.ts +13 -1
- package/core/dist/runtime-v2/internalization/scribe-prompt-builder.d.ts.map +1 -1
- package/core/dist/runtime-v2/internalization/scribe-prompt-builder.js +15 -2
- package/core/dist/runtime-v2/internalization/scribe-prompt-builder.js.map +1 -1
- package/core/dist/runtime-v2/intervention-evidence-normalizer.d.ts +28 -0
- package/core/dist/runtime-v2/intervention-evidence-normalizer.d.ts.map +1 -0
- package/core/dist/runtime-v2/intervention-evidence-normalizer.js +654 -0
- package/core/dist/runtime-v2/intervention-evidence-normalizer.js.map +1 -0
- package/core/dist/runtime-v2/receipt-coverage.d.ts +8 -0
- package/core/dist/runtime-v2/receipt-coverage.d.ts.map +1 -1
- package/core/dist/runtime-v2/receipt-coverage.js +18 -0
- package/core/dist/runtime-v2/receipt-coverage.js.map +1 -1
- package/core/dist/runtime-v2/store/intervention-evidence-schema.d.ts +6 -0
- package/core/dist/runtime-v2/store/intervention-evidence-schema.d.ts.map +1 -0
- package/core/dist/runtime-v2/store/intervention-evidence-schema.js +122 -0
- package/core/dist/runtime-v2/store/intervention-evidence-schema.js.map +1 -0
- package/core/dist/runtime-v2/store/sqlite-connection.d.ts +8 -0
- package/core/dist/runtime-v2/store/sqlite-connection.d.ts.map +1 -1
- package/core/dist/runtime-v2/store/sqlite-connection.js +62 -3
- package/core/dist/runtime-v2/store/sqlite-connection.js.map +1 -1
- package/core/dist/runtime-v2/store/sqlite-intervention-evidence-store.d.ts +67 -0
- package/core/dist/runtime-v2/store/sqlite-intervention-evidence-store.d.ts.map +1 -0
- package/core/dist/runtime-v2/store/sqlite-intervention-evidence-store.js +737 -0
- package/core/dist/runtime-v2/store/sqlite-intervention-evidence-store.js.map +1 -0
- package/core/dist/runtime-v2/types/event-types.d.ts +6 -0
- package/core/dist/runtime-v2/types/event-types.d.ts.map +1 -1
- package/core/dist/runtime-v2/types/event-types.js +2 -0
- package/core/dist/runtime-v2/types/event-types.js.map +1 -1
- package/core/dist/runtime-v2/types/intervention-evidence-contract.d.ts +287 -0
- package/core/dist/runtime-v2/types/intervention-evidence-contract.d.ts.map +1 -0
- package/core/dist/runtime-v2/types/intervention-evidence-contract.js +84 -0
- package/core/dist/runtime-v2/types/intervention-evidence-contract.js.map +1 -0
- package/core/package.json +5 -1
- package/host-runtime/dist/active-principle-prompt.d.ts +2 -0
- package/host-runtime/dist/active-principle-prompt.js +1 -1
- package/host-runtime/dist/host-liveness-contract.d.ts +27 -0
- package/host-runtime/dist/host-liveness-contract.js +38 -12
- package/host-runtime/dist/index.d.ts +4 -0
- package/host-runtime/dist/index.js +16 -0
- package/host-runtime/dist/intervention-evidence-ingress.d.ts +41 -0
- package/host-runtime/dist/intervention-evidence-ingress.js +272 -0
- package/host-runtime/dist/prompt-activation-deliverability.d.ts +106 -0
- package/host-runtime/dist/prompt-activation-deliverability.js +176 -0
- package/host-runtime/dist/prompt-injection-event-evidence.d.ts +51 -0
- package/host-runtime/dist/prompt-injection-event-evidence.js +141 -0
- package/host-runtime/dist/prompt-injection-projection.d.ts +135 -19
- package/host-runtime/dist/prompt-injection-projection.js +224 -20
- package/host-runtime/dist/prompt-injection-status.d.ts +44 -0
- package/host-runtime/dist/prompt-injection-status.js +147 -0
- package/host-runtime/package.json +1 -1
- package/package.json +2 -2
- package/pd-cli/dist/commands/runtime-activation.d.ts +4 -0
- package/pd-cli/dist/commands/runtime-activation.d.ts.map +1 -1
- package/pd-cli/dist/commands/runtime-activation.js +142 -23
- package/pd-cli/dist/commands/runtime-activation.js.map +1 -1
- package/plugin/dist/bundle.js +733 -568
- package/plugin/dist/core/intervention-evidence-recorder.d.ts +65 -0
- package/plugin/dist/governance-audit.js +2 -2
- package/plugin/dist/hooks/gate.d.ts +3 -0
- package/plugin/dist/openclaw.plugin.json +1 -1
- package/plugin/openclaw.plugin.json +1 -1
- package/plugin/package.json +1 -1
- package/release-manager/package.json +2 -2
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import type { InterventionCapabilityDeclaration } from '@principles/core/runtime-v2';
|
|
2
|
+
/** Evidence adapter surface version (major-series label; exact package version lives in package.json). */
|
|
3
|
+
export declare const CODEX_EVIDENCE_ADAPTER_VERSION = "codex-adapter@2";
|
|
4
|
+
export type EvidenceWarn = (diagnosticLine: string) => void;
|
|
5
|
+
/**
|
|
6
|
+
* Codex capability matrix (SPEC §13.6) — declared, never inferred from
|
|
7
|
+
* record absence. 'supported' requires a proof note; Unknown is an honest
|
|
8
|
+
* state, not a failure (ADR-0027 §2.4).
|
|
9
|
+
*/
|
|
10
|
+
export declare function codexCapabilityDeclarations(): InterventionCapabilityDeclaration[];
|
|
11
|
+
export interface CodexPromptDeliveryEvidenceInput {
|
|
12
|
+
workspaceDir: string;
|
|
13
|
+
sessionId: string;
|
|
14
|
+
/** Codex turn_id as carried by the injected-event runId (optional). */
|
|
15
|
+
turnId?: string;
|
|
16
|
+
/** Index-aligned per-principle injection facts from the injected event. */
|
|
17
|
+
injected: readonly {
|
|
18
|
+
principleId: string;
|
|
19
|
+
activationId: string;
|
|
20
|
+
artifactId?: string;
|
|
21
|
+
}[];
|
|
22
|
+
evidenceEnabled: boolean;
|
|
23
|
+
warn: EvidenceWarn;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Record one agent-context delivery attempt per injected principle after the
|
|
27
|
+
* raw injected-event line has been appended to the durable Codex event log —
|
|
28
|
+
* confirmation 'submitted', outcome 'attempted'.
|
|
29
|
+
*/
|
|
30
|
+
export declare function recordCodexPromptDeliveryEvidence(input: CodexPromptDeliveryEvidenceInput): void;
|
|
31
|
+
export interface CodexDenyEvidenceInput {
|
|
32
|
+
workspaceDir: string;
|
|
33
|
+
sessionId?: string;
|
|
34
|
+
toolUseId?: string;
|
|
35
|
+
toolName: string;
|
|
36
|
+
activationId?: string;
|
|
37
|
+
principleId?: string;
|
|
38
|
+
ruleId?: string;
|
|
39
|
+
reason?: string;
|
|
40
|
+
evidenceEnabled: boolean;
|
|
41
|
+
warn: EvidenceWarn;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Record the enforcement chain for an ATTRIBUTED deny that was successfully
|
|
45
|
+
* encoded to the Codex stdout channel. The proof boundary is the encoded
|
|
46
|
+
* permissionDecision — PD does not claim the host executed anything broader.
|
|
47
|
+
* Currently dormant while v2 rule enforcement is suspended (PRI-780), but
|
|
48
|
+
* wired so an attributed deny is recorded honestly if one ever occurs.
|
|
49
|
+
*
|
|
50
|
+
* Episode identity requires the per-call toolUseId. Without it the chain is
|
|
51
|
+
* skipped: a hash fallback would mint an episode with NO native event key,
|
|
52
|
+
* which the normalizer rejects (episode_requires_native_event_key) and drops
|
|
53
|
+
* the WHOLE batch. (Codex deny episodes only ever carry toolCallId — unlike
|
|
54
|
+
* OpenClaw they never see a runId — so there is no legitimate fallback here.)
|
|
55
|
+
*/
|
|
56
|
+
export declare function recordCodexDenyEvidence(input: CodexDenyEvidenceInput): void;
|
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Codex Evidence Recorder — the Codex source adapter for the PD v2 Phase 1
|
|
3
|
+
* evidence ledger (ADR-0027). Mirrors the OpenClaw recorder but keeps the
|
|
4
|
+
* Codex honesty boundaries: the subprocess stdout channel proves
|
|
5
|
+
* 'submitted', never host consumption; v2 rule enforcement stays suspended
|
|
6
|
+
* (PRI-780 — no context provider), so enforcement delivery and
|
|
7
|
+
* runtime_verified application are declared Unknown, not Supported; there
|
|
8
|
+
* is no self-report capture channel on Codex — Unsupported, not faked.
|
|
9
|
+
*
|
|
10
|
+
* All writes flow through the shared host-runtime ingress (SPEC §13.7 单一
|
|
11
|
+
* 入口). Best-effort: degradation produces a bounded stderr diagnostic and
|
|
12
|
+
* never changes the hook result.
|
|
13
|
+
*/
|
|
14
|
+
import { getInterventionEvidenceIngress } from '@principles/host-runtime';
|
|
15
|
+
/** Evidence adapter surface version (major-series label; exact package version lives in package.json). */
|
|
16
|
+
export const CODEX_EVIDENCE_ADAPTER_VERSION = 'codex-adapter@2';
|
|
17
|
+
/**
|
|
18
|
+
* Codex capability matrix (SPEC §13.6) — declared, never inferred from
|
|
19
|
+
* record absence. 'supported' requires a proof note; Unknown is an honest
|
|
20
|
+
* state, not a failure (ADR-0027 §2.4).
|
|
21
|
+
*/
|
|
22
|
+
export function codexCapabilityDeclarations() {
|
|
23
|
+
return [
|
|
24
|
+
{
|
|
25
|
+
hostKind: 'codex', capability: 'agent_context_delivery', status: 'supported',
|
|
26
|
+
adapterVersion: CODEX_EVIDENCE_ADAPTER_VERSION, channel: 'pd-hook:UserPromptSubmit',
|
|
27
|
+
maxConfirmation: 'submitted',
|
|
28
|
+
note: 'additionalContext encoded into the hook stdout hookSpecificOutput; host consumption is not confirmable',
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
hostKind: 'codex', capability: 'enforcement_delivery', status: 'unknown',
|
|
32
|
+
adapterVersion: CODEX_EVIDENCE_ADAPTER_VERSION, channel: 'pd-hook:PreToolUse',
|
|
33
|
+
note: 'v2 rule context provider not injected (PRI-780); live rule enforcement stays suspended — no runtime_loaded claims',
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
hostKind: 'codex', capability: 'application_runtime_verified', status: 'unknown',
|
|
37
|
+
adapterVersion: CODEX_EVIDENCE_ADAPTER_VERSION, channel: 'pd-hook:PreToolUse',
|
|
38
|
+
note: 'an attributed deny would be recorded after successful stdout encoding; enforcement currently suspended (PRI-780)',
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
hostKind: 'codex', capability: 'application_self_report', status: 'unsupported',
|
|
42
|
+
adapterVersion: CODEX_EVIDENCE_ADAPTER_VERSION, channel: 'pd-hook',
|
|
43
|
+
note: 'no self-report capture channel exists on the Codex host; nothing is claimed',
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
hostKind: 'codex', capability: 'behavior_observation', status: 'unknown',
|
|
47
|
+
adapterVersion: CODEX_EVIDENCE_ADAPTER_VERSION, channel: 'pd-hook:PreToolUse',
|
|
48
|
+
note: 'tool episodes are recorded only on attributed gate interventions, which are currently suspended (PRI-780)',
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
hostKind: 'codex', capability: 'outcome_observation', status: 'unknown',
|
|
52
|
+
adapterVersion: CODEX_EVIDENCE_ADAPTER_VERSION, channel: 'console',
|
|
53
|
+
note: 'no automated outcome source; Phase 1 outcomes enter via Owner console input only',
|
|
54
|
+
},
|
|
55
|
+
];
|
|
56
|
+
}
|
|
57
|
+
function appendCodexBatch(workspaceDir, observations, warn) {
|
|
58
|
+
if (observations.length === 0)
|
|
59
|
+
return;
|
|
60
|
+
const ingress = getInterventionEvidenceIngress();
|
|
61
|
+
const batch = {
|
|
62
|
+
evidenceScopeId: ingress.evidenceScopeIdFor(workspaceDir),
|
|
63
|
+
sourceKind: 'codex_pd_hook_event_log',
|
|
64
|
+
adapterVersion: CODEX_EVIDENCE_ADAPTER_VERSION,
|
|
65
|
+
recordedAt: new Date().toISOString(),
|
|
66
|
+
observations,
|
|
67
|
+
capabilityDeclarations: codexCapabilityDeclarations(),
|
|
68
|
+
};
|
|
69
|
+
const result = ingress.appendObservationBatch({ workspaceDir, batch });
|
|
70
|
+
if (!result.ok) {
|
|
71
|
+
warn(`[PD:Evidence] codex append degraded: ${result.reason ?? 'unknown'}; next: ${result.nextAction ?? 'replay from durable source'}`);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Record one agent-context delivery attempt per injected principle after the
|
|
76
|
+
* raw injected-event line has been appended to the durable Codex event log —
|
|
77
|
+
* confirmation 'submitted', outcome 'attempted'.
|
|
78
|
+
*/
|
|
79
|
+
export function recordCodexPromptDeliveryEvidence(input) {
|
|
80
|
+
if (!input.evidenceEnabled || input.injected.length === 0)
|
|
81
|
+
return;
|
|
82
|
+
const ingress = getInterventionEvidenceIngress();
|
|
83
|
+
const observations = [];
|
|
84
|
+
for (const entry of input.injected) {
|
|
85
|
+
const observationKey = `codex|delivery|agent_context|${input.sessionId}|${input.turnId ?? '-'}|${entry.activationId}`;
|
|
86
|
+
const sourceLocator = `codex-pd-hook-event-log:${input.sessionId}`;
|
|
87
|
+
const existing = ingress.existingObservationRefs(input.workspaceDir, {
|
|
88
|
+
sourceKind: 'codex_pd_hook_event_log', sourceLocator, observationKey,
|
|
89
|
+
principleId: entry.principleId, activationId: entry.activationId, ...(entry.artifactId ? { artifactId: entry.artifactId } : {}),
|
|
90
|
+
});
|
|
91
|
+
const activationRef = existing?.activationRef ?? ingress.resolveActivationOccurrenceRef(input.workspaceDir, entry.activationId);
|
|
92
|
+
if (!activationRef) {
|
|
93
|
+
input.warn(`[PD:Evidence] codex prompt delivery skipped for activation ${entry.activationId}: occurrence snapshot unresolvable`);
|
|
94
|
+
continue;
|
|
95
|
+
}
|
|
96
|
+
if (entry.artifactId !== undefined && activationRef.artifactId !== entry.artifactId) {
|
|
97
|
+
input.warn(`[PD:Evidence] codex prompt delivery skipped for activation ${entry.activationId}: source artifact does not match occurrence`);
|
|
98
|
+
continue;
|
|
99
|
+
}
|
|
100
|
+
const contentRef = existing?.contentRef ?? ingress.resolveInterventionContentRef(input.workspaceDir, activationRef, entry.principleId);
|
|
101
|
+
observations.push({
|
|
102
|
+
observationKey,
|
|
103
|
+
sourceLocator,
|
|
104
|
+
kind: 'delivery',
|
|
105
|
+
nativeRefs: {
|
|
106
|
+
hostKind: 'codex',
|
|
107
|
+
sessionId: input.sessionId,
|
|
108
|
+
...(input.turnId ? { turnId: input.turnId } : {}),
|
|
109
|
+
},
|
|
110
|
+
principleId: entry.principleId,
|
|
111
|
+
contentRef: {
|
|
112
|
+
principleId: entry.principleId,
|
|
113
|
+
...(activationRef.artifactId ? { artifactId: activationRef.artifactId } : {}),
|
|
114
|
+
...(contentRef ? { payloadDigest: contentRef.payloadDigest } : {}),
|
|
115
|
+
resolution: contentRef ? 'resolved' : 'revision_reference_unresolved',
|
|
116
|
+
},
|
|
117
|
+
activationRef,
|
|
118
|
+
payload: { targetKind: 'agent_context', confirmation: 'submitted', outcome: 'attempted' },
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
appendCodexBatch(input.workspaceDir, observations, input.warn);
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Record the enforcement chain for an ATTRIBUTED deny that was successfully
|
|
125
|
+
* encoded to the Codex stdout channel. The proof boundary is the encoded
|
|
126
|
+
* permissionDecision — PD does not claim the host executed anything broader.
|
|
127
|
+
* Currently dormant while v2 rule enforcement is suspended (PRI-780), but
|
|
128
|
+
* wired so an attributed deny is recorded honestly if one ever occurs.
|
|
129
|
+
*
|
|
130
|
+
* Episode identity requires the per-call toolUseId. Without it the chain is
|
|
131
|
+
* skipped: a hash fallback would mint an episode with NO native event key,
|
|
132
|
+
* which the normalizer rejects (episode_requires_native_event_key) and drops
|
|
133
|
+
* the WHOLE batch. (Codex deny episodes only ever carry toolCallId — unlike
|
|
134
|
+
* OpenClaw they never see a runId — so there is no legitimate fallback here.)
|
|
135
|
+
*/
|
|
136
|
+
export function recordCodexDenyEvidence(input) {
|
|
137
|
+
if (!input.activationId || !input.principleId)
|
|
138
|
+
return;
|
|
139
|
+
if (!input.toolUseId) {
|
|
140
|
+
input.warn('[PD:Evidence] codex deny chain skipped: no toolUseId — episode identity would lack a native event key');
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
if (!input.evidenceEnabled)
|
|
144
|
+
return;
|
|
145
|
+
const ingress = getInterventionEvidenceIngress();
|
|
146
|
+
const toolKey = input.toolUseId;
|
|
147
|
+
const sessionPart = input.sessionId ?? '-';
|
|
148
|
+
const deliveryKey = `codex|delivery|enforcement|${sessionPart}|${toolKey}|${input.activationId}`;
|
|
149
|
+
const sourceLocator = `codex-pd-hook-event-log:${sessionPart}`;
|
|
150
|
+
const existing = ingress.existingObservationRefs(input.workspaceDir, {
|
|
151
|
+
sourceKind: 'codex_pd_hook_event_log', sourceLocator, observationKey: deliveryKey,
|
|
152
|
+
principleId: input.principleId, activationId: input.activationId,
|
|
153
|
+
});
|
|
154
|
+
const activationRef = existing?.activationRef ?? ingress.resolveActivationOccurrenceRef(input.workspaceDir, input.activationId);
|
|
155
|
+
if (!activationRef) {
|
|
156
|
+
input.warn(`[PD:Evidence] codex deny chain skipped for activation ${input.activationId}: occurrence snapshot unresolvable`);
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
const episodeKey = `codex|episode|${sessionPart}|${toolKey}`;
|
|
160
|
+
const content = existing?.contentRef ?? ingress.resolveInterventionContentRef(input.workspaceDir, activationRef, input.principleId);
|
|
161
|
+
const contentRef = {
|
|
162
|
+
principleId: input.principleId,
|
|
163
|
+
...(activationRef.artifactId ? { artifactId: activationRef.artifactId } : {}),
|
|
164
|
+
...(content ? { payloadDigest: content.payloadDigest } : {}),
|
|
165
|
+
resolution: content ? 'resolved' : 'revision_reference_unresolved',
|
|
166
|
+
};
|
|
167
|
+
const observations = [
|
|
168
|
+
{
|
|
169
|
+
observationKey: deliveryKey,
|
|
170
|
+
sourceLocator,
|
|
171
|
+
kind: 'delivery',
|
|
172
|
+
nativeRefs: {
|
|
173
|
+
hostKind: 'codex',
|
|
174
|
+
...(input.sessionId ? { sessionId: input.sessionId } : {}),
|
|
175
|
+
...(input.toolUseId ? { toolCallId: input.toolUseId } : {}),
|
|
176
|
+
toolName: input.toolName,
|
|
177
|
+
},
|
|
178
|
+
principleId: input.principleId,
|
|
179
|
+
contentRef,
|
|
180
|
+
activationRef,
|
|
181
|
+
payload: { targetKind: 'runtime_enforcement', confirmation: 'runtime_loaded', outcome: 'delivered' },
|
|
182
|
+
},
|
|
183
|
+
{
|
|
184
|
+
observationKey: `codex|application|runtime_verified|${sessionPart}|${toolKey}|${input.activationId}`,
|
|
185
|
+
sourceLocator: `codex-pd-hook-event-log:${sessionPart}`,
|
|
186
|
+
kind: 'application',
|
|
187
|
+
nativeRefs: {
|
|
188
|
+
hostKind: 'codex',
|
|
189
|
+
...(input.sessionId ? { sessionId: input.sessionId } : {}),
|
|
190
|
+
...(input.toolUseId ? { toolCallId: input.toolUseId } : {}),
|
|
191
|
+
toolName: input.toolName,
|
|
192
|
+
},
|
|
193
|
+
principleId: input.principleId,
|
|
194
|
+
activationRef,
|
|
195
|
+
episodeKey,
|
|
196
|
+
payload: { proofMethod: 'runtime_verified', action: 'tool_blocked', enforcementBoundary: 'codex_permission_decision_encoded' },
|
|
197
|
+
},
|
|
198
|
+
{
|
|
199
|
+
observationKey: episodeKey,
|
|
200
|
+
sourceLocator: `codex-pd-hook-event-log:${sessionPart}`,
|
|
201
|
+
kind: 'behavior_episode',
|
|
202
|
+
nativeRefs: {
|
|
203
|
+
hostKind: 'codex',
|
|
204
|
+
...(input.sessionId ? { sessionId: input.sessionId } : {}),
|
|
205
|
+
...(input.toolUseId ? { toolCallId: input.toolUseId } : {}),
|
|
206
|
+
toolName: input.toolName,
|
|
207
|
+
},
|
|
208
|
+
payload: {
|
|
209
|
+
status: 'closed',
|
|
210
|
+
actionSummary: `${input.toolName} denied by rule ${input.ruleId ?? 'unknown'}`,
|
|
211
|
+
resultSummary: 'deny encoded to Codex permission decision',
|
|
212
|
+
},
|
|
213
|
+
},
|
|
214
|
+
{
|
|
215
|
+
observationKey: `codex|effect|${sessionPart}|${toolKey}|${input.activationId}`,
|
|
216
|
+
sourceLocator: `codex-pd-hook-event-log:${sessionPart}`,
|
|
217
|
+
kind: 'effect',
|
|
218
|
+
nativeRefs: {
|
|
219
|
+
hostKind: 'codex',
|
|
220
|
+
...(input.sessionId ? { sessionId: input.sessionId } : {}),
|
|
221
|
+
...(input.toolUseId ? { toolCallId: input.toolUseId } : {}),
|
|
222
|
+
toolName: input.toolName,
|
|
223
|
+
},
|
|
224
|
+
principleId: input.principleId,
|
|
225
|
+
episodeKey,
|
|
226
|
+
contentRef,
|
|
227
|
+
activationRef,
|
|
228
|
+
payload: {
|
|
229
|
+
status: 'observed',
|
|
230
|
+
observationSummary: `rule ${input.ruleId ?? 'unknown'} denied ${input.toolName}`,
|
|
231
|
+
},
|
|
232
|
+
},
|
|
233
|
+
];
|
|
234
|
+
appendCodexBatch(input.workspaceDir, observations, input.warn);
|
|
235
|
+
}
|
|
@@ -5,6 +5,12 @@ export interface PdHookResult {
|
|
|
5
5
|
exitCode: number;
|
|
6
6
|
stderr: string[];
|
|
7
7
|
}
|
|
8
|
+
/** PD v2 Phase 1: evidence context the emitter needs (subprocess-local). */
|
|
9
|
+
export interface CodexEvidenceContext {
|
|
10
|
+
workspaceDir: string;
|
|
11
|
+
evidenceEnabled: boolean;
|
|
12
|
+
warn: (diagnosticLine: string) => void;
|
|
13
|
+
}
|
|
8
14
|
export declare function annotateContextWarnings(warnings: readonly string[]): string[];
|
|
9
15
|
export declare function processHookInvocation(rawStdin: string, _env?: EnvMap, cwd?: string): Promise<PdHookResult>;
|
|
10
16
|
export {};
|
|
@@ -12,6 +12,16 @@ import { CodexHooksHostAdapter } from './host-adapter.js';
|
|
|
12
12
|
import { CodexDecoderError, CodexEncoderError } from './codec/index.js';
|
|
13
13
|
import { ingestCodexConversation } from './ingestion/ingestion.js';
|
|
14
14
|
import { runGovernanceAdmission } from './ingestion/admission.js';
|
|
15
|
+
import { recordCodexPromptDeliveryEvidence, recordCodexDenyEvidence } from './codex-evidence-recorder.js';
|
|
16
|
+
const MAX_DIAGNOSTIC = 500;
|
|
17
|
+
function diagnostic(reason, nextAction) {
|
|
18
|
+
const boundedReason = reason.replace(/\s+/g, ' ').trim().slice(0, MAX_DIAGNOSTIC);
|
|
19
|
+
const boundedNextAction = nextAction.replace(/\s+/g, ' ').trim().slice(0, MAX_DIAGNOSTIC);
|
|
20
|
+
return `[PD] status=degraded reason=${boundedReason} nextAction=${boundedNextAction}`;
|
|
21
|
+
}
|
|
22
|
+
function errorMessage(error) {
|
|
23
|
+
return error instanceof Error ? error.message.slice(0, MAX_DIAGNOSTIC) : 'unknown_error';
|
|
24
|
+
}
|
|
15
25
|
function redactStringFields(data) {
|
|
16
26
|
// rc-8: telemetry is redacted string-field by string field (same policy as
|
|
17
27
|
// the OpenClaw EventLog redactEventData) — shared by every emitter here.
|
|
@@ -27,7 +37,7 @@ function redactStringFields(data) {
|
|
|
27
37
|
* writer, so the Codex host path stays independent of the OpenClaw plugin
|
|
28
38
|
* (codex-adapter must not depend on principles-disciple — bundle guard).
|
|
29
39
|
*/
|
|
30
|
-
function codexEventEmitter(stateDir) {
|
|
40
|
+
function codexEventEmitter(stateDir, evidence) {
|
|
31
41
|
return {
|
|
32
42
|
recordRuntimeV2ActivationsInjected(data) {
|
|
33
43
|
appendEventLogLine(stateDir, {
|
|
@@ -37,6 +47,31 @@ function codexEventEmitter(stateDir) {
|
|
|
37
47
|
sessionId: data.sessionId,
|
|
38
48
|
data,
|
|
39
49
|
});
|
|
50
|
+
// PD v2 Phase 1: the durable source line is appended — now record the
|
|
51
|
+
// normalized agent-context delivery attempts (submitted, not delivered).
|
|
52
|
+
// Degrades to a bounded diagnostic; never affects the hook result.
|
|
53
|
+
if (evidence) {
|
|
54
|
+
try {
|
|
55
|
+
const injected = data.principleIds
|
|
56
|
+
.map((principleId, index) => ({
|
|
57
|
+
principleId,
|
|
58
|
+
activationId: data.activationIds[index] ?? '',
|
|
59
|
+
artifactId: data.artifactIds[index],
|
|
60
|
+
}))
|
|
61
|
+
.filter((entry) => entry.activationId.length > 0);
|
|
62
|
+
recordCodexPromptDeliveryEvidence({
|
|
63
|
+
workspaceDir: evidence.workspaceDir,
|
|
64
|
+
sessionId: data.sessionId,
|
|
65
|
+
...(data.runId ? { turnId: data.runId } : {}),
|
|
66
|
+
injected,
|
|
67
|
+
evidenceEnabled: evidence.evidenceEnabled,
|
|
68
|
+
warn: evidence.warn,
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
catch (error) {
|
|
72
|
+
evidence.warn(diagnostic(`codex_evidence_delivery_failed:${errorMessage(error)}`, 'The raw injected event is durable; replay is safe. The hook result is unaffected.'));
|
|
73
|
+
}
|
|
74
|
+
}
|
|
40
75
|
},
|
|
41
76
|
recordToolCall(sessionId, data) {
|
|
42
77
|
appendEventLogLine(stateDir, {
|
|
@@ -49,15 +84,6 @@ function codexEventEmitter(stateDir) {
|
|
|
49
84
|
},
|
|
50
85
|
};
|
|
51
86
|
}
|
|
52
|
-
const MAX_DIAGNOSTIC = 500;
|
|
53
|
-
function diagnostic(reason, nextAction) {
|
|
54
|
-
const boundedReason = reason.replace(/\s+/g, ' ').trim().slice(0, MAX_DIAGNOSTIC);
|
|
55
|
-
const boundedNextAction = nextAction.replace(/\s+/g, ' ').trim().slice(0, MAX_DIAGNOSTIC);
|
|
56
|
-
return `[PD] status=degraded reason=${boundedReason} nextAction=${boundedNextAction}`;
|
|
57
|
-
}
|
|
58
|
-
function errorMessage(error) {
|
|
59
|
-
return error instanceof Error ? error.message.slice(0, MAX_DIAGNOSTIC) : 'unknown_error';
|
|
60
|
-
}
|
|
61
87
|
/**
|
|
62
88
|
* PRI-813: admissible evaluation entry = the CANONICAL core schema guard
|
|
63
89
|
* (rc-1/rc-2, P4: no hand-rolled field copy that could drift from the
|
|
@@ -253,6 +279,15 @@ export async function processHookInvocation(rawStdin, _env = process.env, cwd =
|
|
|
253
279
|
const ingestionDiagnostics = ingestionEnabled
|
|
254
280
|
? await runConversationIngestion({ rawPayload: parsed, kind: event.kind, workspaceDir: resolution.workspaceDir, env: _env })
|
|
255
281
|
: [];
|
|
282
|
+
// PD v2 Phase 1: evidence context for this subprocess invocation. The
|
|
283
|
+
// ledger flag follows the OpenClaw convention (principle_receipt_ledger
|
|
284
|
+
// gates normalized evidence writes).
|
|
285
|
+
const evidenceDiagnostics = [];
|
|
286
|
+
const evidenceContext = {
|
|
287
|
+
workspaceDir: resolution.workspaceDir,
|
|
288
|
+
evidenceEnabled: flags.principle_receipt_ledger?.enabled === true,
|
|
289
|
+
warn: (line) => evidenceDiagnostics.push(diagnostic(line.replace(/^\[PD:Evidence\] /, 'codex_evidence:'), 'Inspect workspace state.db evidence ledger; the durable raw source allows safe replay.')),
|
|
290
|
+
};
|
|
256
291
|
// PRI-750: emit shared-path injection/tool events with the host's natural
|
|
257
292
|
// turn/tool ids (turn_id → runId, tool_use_id → toolCallId) through the core
|
|
258
293
|
// event-JSONL writer (same events_*.jsonl format as the OpenClaw EventLog;
|
|
@@ -262,7 +297,7 @@ export async function processHookInvocation(rawStdin, _env = process.env, cwd =
|
|
|
262
297
|
projectDir: requestedCwd,
|
|
263
298
|
hostKind: 'codex',
|
|
264
299
|
toolSemantics: CODEX_TOOL_SEMANTICS,
|
|
265
|
-
events: codexEventEmitter(path.join(resolution.workspaceDir, '.state')),
|
|
300
|
+
events: codexEventEmitter(path.join(resolution.workspaceDir, '.state'), evidenceContext),
|
|
266
301
|
// PRI-780 (revised after Codex review round 2 P1): NO context provider —
|
|
267
302
|
// v2 rules stay SUSPENDED on Codex (never loaded context-blind). See
|
|
268
303
|
// annotateContextWarnings for the structured unsupported declaration.
|
|
@@ -273,8 +308,56 @@ export async function processHookInvocation(rawStdin, _env = process.env, cwd =
|
|
|
273
308
|
// rulehost_evaluated rows, so shadow evidence never reached the
|
|
274
309
|
// promotion pipeline.
|
|
275
310
|
const evaluationDiagnostics = recordRuleHostEvaluations(path.join(resolution.workspaceDir, '.state'), event.context.sessionId, result.metadata?.evaluations);
|
|
276
|
-
|
|
277
|
-
|
|
311
|
+
// PD v2 Phase 1: encode BEFORE recording an attributed deny — a
|
|
312
|
+
// runtime_verified application claims only what reached the stdout
|
|
313
|
+
// channel (codex_permission_decision_encoded boundary). Dormant while
|
|
314
|
+
// v2 enforcement is suspended (PRI-780); wired honestly for the day it
|
|
315
|
+
// is not.
|
|
316
|
+
const encoded = adapter.encodeOutput(result, event.kind);
|
|
317
|
+
if (result.decision === 'deny') {
|
|
318
|
+
try {
|
|
319
|
+
let liveActivationId;
|
|
320
|
+
const evaluations = result.metadata?.evaluations;
|
|
321
|
+
if (Array.isArray(evaluations)) {
|
|
322
|
+
for (const entry of evaluations) {
|
|
323
|
+
if (typeof entry !== 'object' || entry === null)
|
|
324
|
+
continue;
|
|
325
|
+
const record = entry;
|
|
326
|
+
if (record.activationMode === 'live' && typeof record.activationId === 'string' && record.activationId.length > 0) {
|
|
327
|
+
({ activationId: liveActivationId } = record);
|
|
328
|
+
break;
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
const { metadata } = result;
|
|
333
|
+
const principleId = typeof metadata?.principleId === 'string' ? metadata.principleId : undefined;
|
|
334
|
+
const ruleId = typeof metadata?.ruleId === 'string' ? metadata.ruleId : undefined;
|
|
335
|
+
const rawPayload = parsed;
|
|
336
|
+
const toolName = typeof rawPayload?.tool_name === 'string'
|
|
337
|
+
? String(rawPayload.tool_name)
|
|
338
|
+
: 'unknown-tool';
|
|
339
|
+
const toolUseId = typeof rawPayload?.tool_use_id === 'string'
|
|
340
|
+
? String(rawPayload.tool_use_id)
|
|
341
|
+
: undefined;
|
|
342
|
+
recordCodexDenyEvidence({
|
|
343
|
+
workspaceDir: resolution.workspaceDir,
|
|
344
|
+
sessionId: event.context.sessionId,
|
|
345
|
+
...(toolUseId ? { toolUseId } : {}),
|
|
346
|
+
toolName,
|
|
347
|
+
activationId: liveActivationId,
|
|
348
|
+
principleId,
|
|
349
|
+
ruleId,
|
|
350
|
+
reason: result.reason,
|
|
351
|
+
evidenceEnabled: evidenceContext.evidenceEnabled,
|
|
352
|
+
warn: evidenceContext.warn,
|
|
353
|
+
});
|
|
354
|
+
}
|
|
355
|
+
catch (error) {
|
|
356
|
+
evidenceDiagnostics.push(diagnostic(`codex_evidence_deny_failed:${errorMessage(error)}`, 'The deny decision was already encoded; evidence replay from the durable source is safe.'));
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
const stderr = [...annotateContextWarnings(result.warnings ?? []).slice(0, 16).map((warning) => diagnostic(warning, 'Inspect PD Workspace state and retry; the hook failed open.')), ...evaluationDiagnostics, ...evidenceDiagnostics, ...ingestionDiagnostics];
|
|
360
|
+
return { stdout: encoded, exitCode: 0, stderr };
|
|
278
361
|
}
|
|
279
362
|
catch (error) {
|
|
280
363
|
const reason = error instanceof CodexEncoderError ? error.reason : `runtime_failed:${errorMessage(error)}`;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@principles/codex-adapter",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"description": "Codex CLI host adapter for Principles Disciple — implements HostAdapter interface for OpenAI Codex CLI's stdin/stdout JSON hook model (ADR-0020).",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -22,6 +22,7 @@ import { handleReceiptsRoute, disposeReceiptsModels } from './routes/receipts.js
|
|
|
22
22
|
import { handleApprovalsGroupedRoute, disposeApprovalsGroupedModels } from './routes/approvals-grouped.js';
|
|
23
23
|
import { handleGovernanceRoute, handleGovernanceExperienceRoute, resolveOwnerConfigSnapshot, disposeGovernanceModels } from './routes/governance.js';
|
|
24
24
|
import { handleOwnerDecisionsRoute } from './routes/owner-decisions.js';
|
|
25
|
+
import { handleEvidenceOutcomesRoute } from './routes/evidence-outcomes.js';
|
|
25
26
|
import { handleOwnerDecisionInboxRoute, handleOwnerDecisionViewRoute, handleOwnerDecisionLibraryRoute, parseOwnerDecisionViewSubPath } from './routes/owner-decision.js';
|
|
26
27
|
import { handleOwnerIdentityRoute } from './routes/owner-identity.js';
|
|
27
28
|
import { handleEvidenceChainRoute, disposeEvidenceChainModels } from './routes/evidence-chain.js';
|
|
@@ -525,6 +526,23 @@ function handleRequest(services) {
|
|
|
525
526
|
asyncHandler(() => handleEvidenceChainRoute(req, res, services.workspaceDir))(req, res);
|
|
526
527
|
return;
|
|
527
528
|
}
|
|
529
|
+
// PD v2 Phase 1: POST /api/v1/evidence/outcomes — Owner outcome feedback
|
|
530
|
+
// into the normalized evidence ledger. Identity derived server-side,
|
|
531
|
+
// same rule as owner-decisions (configured owner or authenticated
|
|
532
|
+
// console operator; never a body-supplied identity).
|
|
533
|
+
if (urlPath === '/api/v1/evidence/outcomes') {
|
|
534
|
+
const eoIdentity = resolveOwnerIdentity(process.env, defaultOwnerIdentityHomeDir());
|
|
535
|
+
const { ownerId, credentialId } = eoIdentity;
|
|
536
|
+
const authEnabledForOwner = services.authConfig.isEnabled()
|
|
537
|
+
&& ownerId !== null && credentialId !== null;
|
|
538
|
+
asyncHandler(() => handleEvidenceOutcomesRoute(req, res, {
|
|
539
|
+
workspaceDir: services.workspaceDir,
|
|
540
|
+
ownerIdentity: authEnabledForOwner
|
|
541
|
+
? { ownerId, credentialId }
|
|
542
|
+
: null,
|
|
543
|
+
}))(req, res);
|
|
544
|
+
return;
|
|
545
|
+
}
|
|
528
546
|
// GET /api/health
|
|
529
547
|
if (urlPath === '/api/health') {
|
|
530
548
|
asyncHandler(() => handleHealthRoute(req, res, {
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import type { ActivationStatusRecord, PromotionReadinessResult, ActivationControlState, ActivationDecisionRecord, GlobalRuleCodePause, OwnerPromotionActor, OwnerPromotionResult } from '@principles/core/runtime-v2';
|
|
2
|
+
import { type PromptInjectionTargetHost } from '@principles/host-runtime';
|
|
3
|
+
import type { PromptActivationInjectionStatusWire, PromptInjectionRouteSummaryWire } from '../../shared/prompt-injection-contract.js';
|
|
2
4
|
import { type GovernanceAuditWriter } from 'principles-disciple/governance-audit';
|
|
3
5
|
/**
|
|
4
6
|
* PRI-491 — owner-observable activation record.
|
|
@@ -48,6 +50,14 @@ export interface ActivationRecord {
|
|
|
48
50
|
enforcement?: 'eligible' | 'safety_isolated';
|
|
49
51
|
legacyDecisionUnknown?: boolean;
|
|
50
52
|
ownerReviewDueAt?: string;
|
|
53
|
+
/**
|
|
54
|
+
* PD_PROMPT_CAPACITY_V1 R-A3: current injection status for LIVE prompt
|
|
55
|
+
* activations — positive single-item evidence per row (oversized carries
|
|
56
|
+
* its own reason, window_excluded means it fits but the window is full).
|
|
57
|
+
* Absent for non-prompt channels, deactivated rows, and when the status
|
|
58
|
+
* reader itself degrades (see ActivationsResponse.promptInjectionRoute).
|
|
59
|
+
*/
|
|
60
|
+
promptInjection?: PromptActivationInjectionStatusWire;
|
|
51
61
|
}
|
|
52
62
|
export interface ActivationsResponse {
|
|
53
63
|
activations: ActivationRecord[];
|
|
@@ -57,6 +67,8 @@ export interface ActivationsResponse {
|
|
|
57
67
|
reason?: string;
|
|
58
68
|
/** Present when status is 'degraded' — next operator action. */
|
|
59
69
|
nextAction?: string;
|
|
70
|
+
/** R-A3/AC-01: route context for the per-activation injection statuses. */
|
|
71
|
+
promptInjectionRoute?: PromptInjectionRouteSummaryWire;
|
|
60
72
|
}
|
|
61
73
|
export interface RuleCodeOwnerReview {
|
|
62
74
|
activation: ActivationStatusRecord;
|
|
@@ -137,7 +149,7 @@ export declare class ActivationsConsoleModel {
|
|
|
137
149
|
private readonly workspaceDir;
|
|
138
150
|
private readonly governanceAuditWriter;
|
|
139
151
|
constructor(workspaceDir: string, governanceAuditWriter?: GovernanceAuditWriter);
|
|
140
|
-
getActivations(): Promise<ActivationsResponse>;
|
|
152
|
+
getActivations(targetHost?: PromptInjectionTargetHost): Promise<ActivationsResponse>;
|
|
141
153
|
getOwnerReview(activationId: string, ownerIdentityConfigured?: boolean, ownerActor?: OwnerPromotionActor): Promise<RuleCodeOwnerReview>;
|
|
142
154
|
continueObserving(activationId: string, input: OwnerMutationInput): Promise<{
|
|
143
155
|
decisionId: string;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { SqliteConnection, SqliteActivationStateStore, SqlitePIArtifactStore, extractPrincipleId, extractEvidenceRefs, PromotionReadinessReader, RuleHostWriter, createProductionGateDeps, SqliteActivationSafetyStore, isFeatureEnabled, RuleCodeOwnerDecisionService, collectOpenClawPromotionChecks, summarizeRuleCodeShadowEvents, buildPromotionEvidenceSnapshot, } from '@principles/core/runtime-v2';
|
|
2
|
-
import { resolvePromotionHostLiveness, resolveWorkspaceHostToolSemantics } from '@principles/host-runtime';
|
|
2
|
+
import { resolvePromotionHostLiveness, resolveWorkspaceHostToolSemantics, readPromptActivationInjectionStatuses } from '@principles/host-runtime';
|
|
3
3
|
import { loadPdConfig, computeFlagsFromLoadResult } from '../config/pd-config-store.js';
|
|
4
4
|
import * as fs from 'node:fs';
|
|
5
5
|
import * as path from 'node:path';
|
|
@@ -160,7 +160,7 @@ export class ActivationsConsoleModel {
|
|
|
160
160
|
this.workspaceDir = workspaceDir;
|
|
161
161
|
this.governanceAuditWriter = governanceAuditWriter;
|
|
162
162
|
}
|
|
163
|
-
async getActivations() {
|
|
163
|
+
async getActivations(targetHost) {
|
|
164
164
|
const stateDbPath = path.join(this.workspaceDir, '.pd', 'state.db');
|
|
165
165
|
if (!fs.existsSync(stateDbPath)) {
|
|
166
166
|
return { activations: [], status: 'degraded', reason: 'state.db not found — workspace may not be initialized', nextAction: 'Run pd runtime diagnostics to check workspace state' };
|
|
@@ -314,6 +314,56 @@ export class ActivationsConsoleModel {
|
|
|
314
314
|
}
|
|
315
315
|
return enriched;
|
|
316
316
|
});
|
|
317
|
+
// PD_PROMPT_CAPACITY_V1 R-A3: per-live-prompt-activation injection
|
|
318
|
+
// status with positive single-item evidence. Degradation is observable
|
|
319
|
+
// (route summary carries the reason) and never turns a row "healthy"
|
|
320
|
+
// by omission (rc-9 / AC-06).
|
|
321
|
+
let promptInjectionRoute;
|
|
322
|
+
let statusByActivation;
|
|
323
|
+
try {
|
|
324
|
+
const report = await readPromptActivationInjectionStatuses({ workspaceDir: this.workspaceDir, targetHost });
|
|
325
|
+
promptInjectionRoute = {
|
|
326
|
+
status: report.route.status,
|
|
327
|
+
...(report.route.hostKind !== undefined ? { hostKind: report.route.hostKind } : {}),
|
|
328
|
+
...(report.route.route !== undefined ? { route: report.route.route } : {}),
|
|
329
|
+
flagEnabled: report.route.flagEnabled,
|
|
330
|
+
...(report.route.unconfirmedReason !== undefined ? { unconfirmedReason: report.route.unconfirmedReason } : {}),
|
|
331
|
+
...(report.route.nextAction !== undefined ? { nextAction: report.route.nextAction } : {}),
|
|
332
|
+
...(report.globalReason !== undefined ? { globalReason: report.globalReason } : {}),
|
|
333
|
+
};
|
|
334
|
+
statusByActivation = new Map(report.statuses.map((entry) => [
|
|
335
|
+
entry.activationId,
|
|
336
|
+
{
|
|
337
|
+
activationId: entry.activationId,
|
|
338
|
+
status: entry.status,
|
|
339
|
+
...(entry.inCurrentWindow !== undefined ? { inCurrentWindow: entry.inCurrentWindow } : {}),
|
|
340
|
+
...(entry.costChars !== undefined ? { costChars: entry.costChars } : {}),
|
|
341
|
+
...(entry.budget !== undefined ? { budget: entry.budget } : {}),
|
|
342
|
+
...(entry.budgetScope !== undefined ? { budgetScope: entry.budgetScope } : {}),
|
|
343
|
+
...(entry.route !== undefined ? { route: entry.route } : {}),
|
|
344
|
+
...(entry.reason !== undefined ? { reason: entry.reason } : {}),
|
|
345
|
+
...(entry.perHostFits !== undefined
|
|
346
|
+
? { perHostFits: entry.perHostFits.map((fit) => ({ hostKind: fit.hostKind, fits: fit.fits })) }
|
|
347
|
+
: {}),
|
|
348
|
+
},
|
|
349
|
+
]));
|
|
350
|
+
}
|
|
351
|
+
catch (err) {
|
|
352
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
353
|
+
promptInjectionRoute = {
|
|
354
|
+
status: 'unconfirmed',
|
|
355
|
+
flagEnabled: false,
|
|
356
|
+
unconfirmedReason: `injection_status_reader_failed: ${message}`,
|
|
357
|
+
nextAction: 'check workspace .pd/state.db readability and the host declarations',
|
|
358
|
+
};
|
|
359
|
+
}
|
|
360
|
+
for (const fact of facts) {
|
|
361
|
+
if (fact.channel === 'prompt' && fact.status !== 'deactivated') {
|
|
362
|
+
const entry = statusByActivation?.get(fact.activationId);
|
|
363
|
+
if (entry !== undefined)
|
|
364
|
+
fact.promptInjection = entry;
|
|
365
|
+
}
|
|
366
|
+
}
|
|
317
367
|
// rc-9: surface dangling references instead of silently returning a degraded list.
|
|
318
368
|
if (danglingArtifactIds.size > 0) {
|
|
319
369
|
return {
|
|
@@ -321,11 +371,13 @@ export class ActivationsConsoleModel {
|
|
|
321
371
|
status: 'degraded',
|
|
322
372
|
reason: `${danglingArtifactIds.size} activation(s) reference non-existent artifact_id(s): ${Array.from(danglingArtifactIds).join(', ')}`,
|
|
323
373
|
nextAction: 'Run pd runtime internalization integrity to check for orphaned activations',
|
|
374
|
+
promptInjectionRoute,
|
|
324
375
|
};
|
|
325
376
|
}
|
|
326
377
|
return {
|
|
327
378
|
activations: facts,
|
|
328
379
|
status: 'ok',
|
|
380
|
+
promptInjectionRoute,
|
|
329
381
|
};
|
|
330
382
|
}
|
|
331
383
|
finally {
|