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.
Files changed (131) hide show
  1. package/_release/product-identity.json +2 -2
  2. package/codex-adapter/dist/codex-evidence-recorder.d.ts +56 -0
  3. package/codex-adapter/dist/codex-evidence-recorder.js +235 -0
  4. package/codex-adapter/dist/pd-hook.d.ts +6 -0
  5. package/codex-adapter/dist/pd-hook.js +96 -13
  6. package/codex-adapter/package.json +1 -1
  7. package/console/dist/server/index.js +18 -0
  8. package/console/dist/server/models/ActivationsConsoleModel.d.ts +13 -1
  9. package/console/dist/server/models/ActivationsConsoleModel.js +54 -2
  10. package/console/dist/server/models/ApprovalsConsoleModel.d.ts +98 -19
  11. package/console/dist/server/models/ApprovalsConsoleModel.js +338 -29
  12. package/console/dist/server/models/ApprovalsGroupedConsoleModel.d.ts +17 -7
  13. package/console/dist/server/models/ApprovalsGroupedConsoleModel.js +134 -54
  14. package/console/dist/server/models/ReceiptsConsoleModel.d.ts +44 -1
  15. package/console/dist/server/models/ReceiptsConsoleModel.js +102 -0
  16. package/console/dist/server/routes/activations.js +96 -1
  17. package/console/dist/server/routes/approvals-grouped.js +15 -2
  18. package/console/dist/server/routes/approvals.js +40 -2
  19. package/console/dist/server/routes/evidence-outcomes.d.ts +29 -0
  20. package/console/dist/server/routes/evidence-outcomes.js +137 -0
  21. package/console/dist/server/routes/receipts.js +56 -0
  22. package/console/dist/shared/prompt-injection-contract.d.ts +71 -0
  23. package/console/dist/ui/api.d.ts +94 -4
  24. package/console/dist/ui/api.js +277 -8
  25. package/console/dist/ui/i18n/en.json +113 -13
  26. package/console/dist/ui/i18n/zh-CN.json +113 -13
  27. package/console/dist/ui/pages/activation/ActivationPage.js +80 -2
  28. package/console/dist/ui/pages/focus/FocusPage.js +49 -21
  29. package/console/dist/ui/pages/principles/PrincipleDetailPage.js +68 -3
  30. package/console/dist/ui/utils/approval-warning-localization.js +39 -0
  31. package/console/dist/ui/utils/validators.d.ts +10 -1
  32. package/console/dist/ui/utils/validators.js +126 -0
  33. package/console/dist/web/assets/app.css +15 -0
  34. package/console/dist/web/assets/app.js +29 -28
  35. package/core/dist/runtime-v2/activation/activation-dispatcher.d.ts +4 -0
  36. package/core/dist/runtime-v2/activation/activation-dispatcher.d.ts.map +1 -1
  37. package/core/dist/runtime-v2/activation/activation-dispatcher.js +215 -63
  38. package/core/dist/runtime-v2/activation/activation-dispatcher.js.map +1 -1
  39. package/core/dist/runtime-v2/activation/activation-types.d.ts +48 -0
  40. package/core/dist/runtime-v2/activation/activation-types.d.ts.map +1 -1
  41. package/core/dist/runtime-v2/activation/activation-types.js.map +1 -1
  42. package/core/dist/runtime-v2/activation/approval-completion-service.d.ts +9 -0
  43. package/core/dist/runtime-v2/activation/approval-completion-service.d.ts.map +1 -1
  44. package/core/dist/runtime-v2/activation/approval-completion-service.js +4 -1
  45. package/core/dist/runtime-v2/activation/approval-completion-service.js.map +1 -1
  46. package/core/dist/runtime-v2/activation/index.d.ts +4 -2
  47. package/core/dist/runtime-v2/activation/index.d.ts.map +1 -1
  48. package/core/dist/runtime-v2/activation/index.js +4 -1
  49. package/core/dist/runtime-v2/activation/index.js.map +1 -1
  50. package/core/dist/runtime-v2/activation/low-risk-writers.d.ts.map +1 -1
  51. package/core/dist/runtime-v2/activation/low-risk-writers.js +2 -1
  52. package/core/dist/runtime-v2/activation/low-risk-writers.js.map +1 -1
  53. package/core/dist/runtime-v2/activation/prompt-activation-reader-contract.d.ts +11 -0
  54. package/core/dist/runtime-v2/activation/prompt-activation-reader-contract.d.ts.map +1 -1
  55. package/core/dist/runtime-v2/activation/prompt-activation-reader-contract.js +12 -2
  56. package/core/dist/runtime-v2/activation/prompt-activation-reader-contract.js.map +1 -1
  57. package/core/dist/runtime-v2/activation/prompt-replacement.d.ts +79 -0
  58. package/core/dist/runtime-v2/activation/prompt-replacement.d.ts.map +1 -0
  59. package/core/dist/runtime-v2/activation/prompt-replacement.js +171 -0
  60. package/core/dist/runtime-v2/activation/prompt-replacement.js.map +1 -0
  61. package/core/dist/runtime-v2/activation/sqlite-activation-state-store.d.ts +17 -1
  62. package/core/dist/runtime-v2/activation/sqlite-activation-state-store.d.ts.map +1 -1
  63. package/core/dist/runtime-v2/activation/sqlite-activation-state-store.js +132 -0
  64. package/core/dist/runtime-v2/activation/sqlite-activation-state-store.js.map +1 -1
  65. package/core/dist/runtime-v2/index.d.ts +8 -2
  66. package/core/dist/runtime-v2/index.d.ts.map +1 -1
  67. package/core/dist/runtime-v2/index.js +8 -2
  68. package/core/dist/runtime-v2/index.js.map +1 -1
  69. package/core/dist/runtime-v2/internalization/scribe-prompt-builder.d.ts +13 -1
  70. package/core/dist/runtime-v2/internalization/scribe-prompt-builder.d.ts.map +1 -1
  71. package/core/dist/runtime-v2/internalization/scribe-prompt-builder.js +15 -2
  72. package/core/dist/runtime-v2/internalization/scribe-prompt-builder.js.map +1 -1
  73. package/core/dist/runtime-v2/intervention-evidence-normalizer.d.ts +28 -0
  74. package/core/dist/runtime-v2/intervention-evidence-normalizer.d.ts.map +1 -0
  75. package/core/dist/runtime-v2/intervention-evidence-normalizer.js +654 -0
  76. package/core/dist/runtime-v2/intervention-evidence-normalizer.js.map +1 -0
  77. package/core/dist/runtime-v2/receipt-coverage.d.ts +8 -0
  78. package/core/dist/runtime-v2/receipt-coverage.d.ts.map +1 -1
  79. package/core/dist/runtime-v2/receipt-coverage.js +18 -0
  80. package/core/dist/runtime-v2/receipt-coverage.js.map +1 -1
  81. package/core/dist/runtime-v2/store/intervention-evidence-schema.d.ts +6 -0
  82. package/core/dist/runtime-v2/store/intervention-evidence-schema.d.ts.map +1 -0
  83. package/core/dist/runtime-v2/store/intervention-evidence-schema.js +122 -0
  84. package/core/dist/runtime-v2/store/intervention-evidence-schema.js.map +1 -0
  85. package/core/dist/runtime-v2/store/sqlite-connection.d.ts +8 -0
  86. package/core/dist/runtime-v2/store/sqlite-connection.d.ts.map +1 -1
  87. package/core/dist/runtime-v2/store/sqlite-connection.js +62 -3
  88. package/core/dist/runtime-v2/store/sqlite-connection.js.map +1 -1
  89. package/core/dist/runtime-v2/store/sqlite-intervention-evidence-store.d.ts +67 -0
  90. package/core/dist/runtime-v2/store/sqlite-intervention-evidence-store.d.ts.map +1 -0
  91. package/core/dist/runtime-v2/store/sqlite-intervention-evidence-store.js +737 -0
  92. package/core/dist/runtime-v2/store/sqlite-intervention-evidence-store.js.map +1 -0
  93. package/core/dist/runtime-v2/types/event-types.d.ts +6 -0
  94. package/core/dist/runtime-v2/types/event-types.d.ts.map +1 -1
  95. package/core/dist/runtime-v2/types/event-types.js +2 -0
  96. package/core/dist/runtime-v2/types/event-types.js.map +1 -1
  97. package/core/dist/runtime-v2/types/intervention-evidence-contract.d.ts +287 -0
  98. package/core/dist/runtime-v2/types/intervention-evidence-contract.d.ts.map +1 -0
  99. package/core/dist/runtime-v2/types/intervention-evidence-contract.js +84 -0
  100. package/core/dist/runtime-v2/types/intervention-evidence-contract.js.map +1 -0
  101. package/core/package.json +5 -1
  102. package/host-runtime/dist/active-principle-prompt.d.ts +2 -0
  103. package/host-runtime/dist/active-principle-prompt.js +1 -1
  104. package/host-runtime/dist/host-liveness-contract.d.ts +27 -0
  105. package/host-runtime/dist/host-liveness-contract.js +38 -12
  106. package/host-runtime/dist/index.d.ts +4 -0
  107. package/host-runtime/dist/index.js +16 -0
  108. package/host-runtime/dist/intervention-evidence-ingress.d.ts +41 -0
  109. package/host-runtime/dist/intervention-evidence-ingress.js +272 -0
  110. package/host-runtime/dist/prompt-activation-deliverability.d.ts +106 -0
  111. package/host-runtime/dist/prompt-activation-deliverability.js +176 -0
  112. package/host-runtime/dist/prompt-injection-event-evidence.d.ts +51 -0
  113. package/host-runtime/dist/prompt-injection-event-evidence.js +141 -0
  114. package/host-runtime/dist/prompt-injection-projection.d.ts +135 -19
  115. package/host-runtime/dist/prompt-injection-projection.js +224 -20
  116. package/host-runtime/dist/prompt-injection-status.d.ts +44 -0
  117. package/host-runtime/dist/prompt-injection-status.js +147 -0
  118. package/host-runtime/package.json +1 -1
  119. package/package.json +2 -2
  120. package/pd-cli/dist/commands/runtime-activation.d.ts +4 -0
  121. package/pd-cli/dist/commands/runtime-activation.d.ts.map +1 -1
  122. package/pd-cli/dist/commands/runtime-activation.js +142 -23
  123. package/pd-cli/dist/commands/runtime-activation.js.map +1 -1
  124. package/plugin/dist/bundle.js +733 -568
  125. package/plugin/dist/core/intervention-evidence-recorder.d.ts +65 -0
  126. package/plugin/dist/governance-audit.js +2 -2
  127. package/plugin/dist/hooks/gate.d.ts +3 -0
  128. package/plugin/dist/openclaw.plugin.json +1 -1
  129. package/plugin/openclaw.plugin.json +1 -1
  130. package/plugin/package.json +1 -1
  131. package/release-manager/package.json +2 -2
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "schemaVersion": 1,
3
- "productVersion": "2.2.2",
4
- "sourceCommit": "7afed455e39d5062c2febcf0bc319db123453105"
3
+ "productVersion": "2.3.0",
4
+ "sourceCommit": "693e91ab726949844986dcbc2adaa27a5ef53a31"
5
5
  }
@@ -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
- const stderr = [...annotateContextWarnings(result.warnings ?? []).slice(0, 16).map((warning) => diagnostic(warning, 'Inspect PD Workspace state and retry; the hook failed open.')), ...evaluationDiagnostics, ...ingestionDiagnostics];
277
- return { stdout: adapter.encodeOutput(result, event.kind), exitCode: 0, stderr };
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.4.8",
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 {