@principles/core 1.274.4 → 1.275.0

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 (35) hide show
  1. package/dist/runtime-v2/__tests__/pain-ingress-persistence.test.d.ts +2 -0
  2. package/dist/runtime-v2/__tests__/pain-ingress-persistence.test.d.ts.map +1 -0
  3. package/dist/runtime-v2/__tests__/pain-ingress-persistence.test.js +276 -0
  4. package/dist/runtime-v2/__tests__/pain-ingress-persistence.test.js.map +1 -0
  5. package/dist/runtime-v2/__tests__/pain-ingress-shared-semantics.test.d.ts +2 -0
  6. package/dist/runtime-v2/__tests__/pain-ingress-shared-semantics.test.d.ts.map +1 -0
  7. package/dist/runtime-v2/__tests__/pain-ingress-shared-semantics.test.js +131 -0
  8. package/dist/runtime-v2/__tests__/pain-ingress-shared-semantics.test.js.map +1 -0
  9. package/dist/runtime-v2/__tests__/pain-outcome-convergence.test.d.ts +2 -0
  10. package/dist/runtime-v2/__tests__/pain-outcome-convergence.test.d.ts.map +1 -0
  11. package/dist/runtime-v2/__tests__/pain-outcome-convergence.test.js +126 -0
  12. package/dist/runtime-v2/__tests__/pain-outcome-convergence.test.js.map +1 -0
  13. package/dist/runtime-v2/__tests__/pain-signal-bridge-execute-pending.test.js +95 -0
  14. package/dist/runtime-v2/__tests__/pain-signal-bridge-execute-pending.test.js.map +1 -1
  15. package/dist/runtime-v2/index.d.ts +9 -1
  16. package/dist/runtime-v2/index.d.ts.map +1 -1
  17. package/dist/runtime-v2/index.js +6 -0
  18. package/dist/runtime-v2/index.js.map +1 -1
  19. package/dist/runtime-v2/pain-ingress-payload.d.ts +207 -0
  20. package/dist/runtime-v2/pain-ingress-payload.d.ts.map +1 -0
  21. package/dist/runtime-v2/pain-ingress-payload.js +340 -0
  22. package/dist/runtime-v2/pain-ingress-payload.js.map +1 -0
  23. package/dist/runtime-v2/pain-ingress.d.ts +61 -0
  24. package/dist/runtime-v2/pain-ingress.d.ts.map +1 -0
  25. package/dist/runtime-v2/pain-ingress.js +163 -0
  26. package/dist/runtime-v2/pain-ingress.js.map +1 -0
  27. package/dist/runtime-v2/pain-signal-bridge.d.ts +39 -1
  28. package/dist/runtime-v2/pain-signal-bridge.d.ts.map +1 -1
  29. package/dist/runtime-v2/pain-signal-bridge.js +163 -8
  30. package/dist/runtime-v2/pain-signal-bridge.js.map +1 -1
  31. package/dist/runtime-v2/pain-to-principle-service.d.ts +8 -1
  32. package/dist/runtime-v2/pain-to-principle-service.d.ts.map +1 -1
  33. package/dist/runtime-v2/pain-to-principle-service.js +3 -0
  34. package/dist/runtime-v2/pain-to-principle-service.js.map +1 -1
  35. package/package.json +1 -1
@@ -0,0 +1,207 @@
1
+ /**
2
+ * Pain Ingress shared invariants + persisted payload contract — PRI-642.
3
+ *
4
+ * This module is THE single source for:
5
+ * - the report field parsers (origin / correlation / evidence / score)
6
+ * shared by write-time evaluation and persisted-payload re-entry;
7
+ * - the origin/correlation invariant (`validateOriginCorrelationInvariant`)
8
+ * — the valid-combination rules of SPEC §8.2 that must never diverge
9
+ * between write time and re-entry;
10
+ * - the sentinel session constant (frozen decision #4);
11
+ * - the versioned `painIngress.v1` persisted namespace (SPEC §9) written
12
+ * by PainSignalBridge.buildDiagnosticJson beside the legacy top-level
13
+ * fields, and re-validated by executePendingDiagnosis / retry paths.
14
+ *
15
+ * INVARIANT EQUIVALENCE (review blocker 2): re-entry validation is NOT
16
+ * weaker than write-time validation. parsePainIngressV1Payload shares the
17
+ * field parsers and the invariant with evaluatePainIngress
18
+ * (pain-ingress.ts), so every state illegal at write time — sentinel
19
+ * session ids, empty "available" evidence, impossible origin/correlation
20
+ * combinations — is also rejected on re-entry.
21
+ *
22
+ * Legacy compatibility (SPEC §9): payloads WITHOUT a painIngress.v1 block
23
+ * keep the tolerant legacy normalization branch in pain-signal-bridge.ts;
24
+ * this strictness applies only to payloads CLAIMING the v1 namespace.
25
+ *
26
+ * Pure module — no I/O. @principles/host-runtime and other adapters depend
27
+ * on core; core depends on no adapter.
28
+ */
29
+ import type { PainProvenance } from './admission-gate.js';
30
+ export declare const PAIN_INGRESS_PAYLOAD_VERSION = "v1";
31
+ export type PainIngressOriginV1 = {
32
+ kind: 'owner_manual';
33
+ channel: 'openclaw_command' | 'cli_explicit_session' | 'external_cli_unbound';
34
+ } | {
35
+ kind: 'automatic_hook';
36
+ source: string;
37
+ };
38
+ export type PainIngressCorrelationV1 = {
39
+ status: 'bound';
40
+ hostKind: 'openclaw';
41
+ sessionId: string;
42
+ traceId?: string;
43
+ } | {
44
+ status: 'bound';
45
+ hostKind: 'codex';
46
+ rootSessionId: string;
47
+ rolloutIdentity: string;
48
+ logicalObservationKey: string;
49
+ hostTurnId: string;
50
+ traceId?: string;
51
+ } | {
52
+ status: 'unbound';
53
+ reason: 'external_cli' | 'missing_host_session';
54
+ };
55
+ export type PainIngressEvidenceClassV1 = {
56
+ status: 'available';
57
+ entryCount: number;
58
+ } | {
59
+ status: 'unavailable';
60
+ reason: 'trajectory_unavailable' | 'session_not_found' | 'empty_trajectory' | 'evidence_read_failed' | 'evidence_invalid'
61
+ /** Unbound Owner reports never consult a trajectory — no evidence is sought. */
62
+ | 'not_applicable_unbound';
63
+ };
64
+ export type PainEvidenceUnavailableReason = 'trajectory_unavailable' | 'session_not_found' | 'empty_trajectory' | 'evidence_read_failed' | 'evidence_invalid'
65
+ /** Unbound Owner reports never consult a trajectory — no evidence is sought. */
66
+ | 'not_applicable_unbound';
67
+ export interface IngressEvidenceEntry {
68
+ kind: 'behavior_trace' | 'system_event';
69
+ sourceRef: string;
70
+ note: string;
71
+ }
72
+ export type PainEvidenceBundle = {
73
+ status: 'available';
74
+ entries: readonly [IngressEvidenceEntry, ...IngressEvidenceEntry[]];
75
+ } | {
76
+ status: 'unavailable';
77
+ reason: PainEvidenceUnavailableReason;
78
+ };
79
+ export type PainOrigin = PainIngressOriginV1;
80
+ export type PainCorrelation = PainIngressCorrelationV1;
81
+ export interface PainIngressReport {
82
+ identity: {
83
+ kind: 'manual_pain_id';
84
+ painId: string;
85
+ } | {
86
+ kind: 'host_observation';
87
+ observationId: string;
88
+ };
89
+ painType: 'tool_failure' | 'subagent_error' | 'user_frustration';
90
+ source: string;
91
+ reason: string;
92
+ score?: number;
93
+ origin: PainOrigin;
94
+ correlation: PainCorrelation;
95
+ evidence: PainEvidenceBundle;
96
+ }
97
+ export declare function isRecord(value: unknown): value is Record<string, unknown>;
98
+ /**
99
+ * Sentinel session ids are never real correlations (frozen decision #4).
100
+ * Import this constant instead of re-declaring the set in another module.
101
+ */
102
+ export declare const SENTINEL_SESSION_IDS: ReadonlySet<string>;
103
+ export declare function isSentinelSessionId(value: string): boolean;
104
+ export declare function parseOrigin(value: unknown): PainOrigin | null;
105
+ /**
106
+ * THE correlation parser — used by report validation (write time) and the
107
+ * persisted-payload validator (re-entry) so sentinel rejection and lineage
108
+ * completeness cannot drift between the two.
109
+ */
110
+ export declare function parseCorrelation(value: unknown): {
111
+ value: PainCorrelation;
112
+ error?: undefined;
113
+ } | {
114
+ value?: undefined;
115
+ error: string;
116
+ };
117
+ export declare function parseEvidence(value: unknown): {
118
+ value: PainEvidenceBundle;
119
+ error?: undefined;
120
+ } | {
121
+ value?: undefined;
122
+ error: string;
123
+ };
124
+ /** rc-3/rc-9: a present-but-invalid score is rejected, not silently dropped. */
125
+ export declare function parseScore(value: unknown): {
126
+ score: number | undefined;
127
+ scoreInvalid?: undefined;
128
+ } | {
129
+ score: undefined;
130
+ scoreInvalid: true;
131
+ };
132
+ export type PainIngressParseResult = {
133
+ ok: true;
134
+ report: PainIngressReport;
135
+ } | {
136
+ ok: false;
137
+ reasonCode: string;
138
+ message: string;
139
+ };
140
+ /**
141
+ * Validate an untrusted report (parsed JSON / host payload) into a typed
142
+ * PainIngressReport. Fails loud with a structured reasonCode (rc-3); uses
143
+ * the SAME field parsers and invariant as the persisted-payload validator
144
+ * (rc-1/rc-2/rc-3/rc-4).
145
+ */
146
+ export declare function parsePainIngressReport(input: unknown): PainIngressParseResult;
147
+ /**
148
+ * Origin/correlation combinations the matrix (SPEC §8.2) declares invalid.
149
+ * Shared by evaluatePainIngress (write time) and parsePainIngressV1Payload
150
+ * (re-entry) so an illegal state can never become legal across a
151
+ * persistence round trip. Returns a reasonCode string when invalid, null
152
+ * when the combination is valid.
153
+ */
154
+ export declare function validateOriginCorrelationInvariant(origin: PainOrigin, correlation: PainCorrelation): string | null;
155
+ /**
156
+ * The persisted v1 block. Evidence ENTRIES are intentionally not duplicated
157
+ * here — they remain in the legacy top-level `evidence` field; this block
158
+ * records their validated classification only (SPEC §9: one versioned
159
+ * namespace for the rev-2 facts, legacy fields stay authoritative for
160
+ * their own consumers).
161
+ */
162
+ export interface PainIngressV1Payload {
163
+ version: typeof PAIN_INGRESS_PAYLOAD_VERSION;
164
+ origin: PainIngressOriginV1;
165
+ correlation: PainIngressCorrelationV1;
166
+ evidenceClass: PainIngressEvidenceClassV1;
167
+ }
168
+ export type PainIngressV1ParseResult = {
169
+ ok: true;
170
+ payload: PainIngressV1Payload;
171
+ } | {
172
+ ok: false;
173
+ reasonCode: string;
174
+ };
175
+ /**
176
+ * Runtime validation of an untrusted persisted painIngress block
177
+ * (rc-1/rc-2/rc-3). Shares parseOrigin/parseCorrelation and the
178
+ * origin/correlation invariant with the write-time evaluator, so sentinel
179
+ * sessions, incomplete Codex lineage and impossible combinations are
180
+ * rejected identically at write time and on re-entry.
181
+ */
182
+ export declare function parsePainIngressV1Payload(value: unknown): PainIngressV1ParseResult;
183
+ /**
184
+ * Derive the legacy provenance from validated rev-2 facts (SPEC §8.3).
185
+ * Adapters do not supply provenance independently; this is the one
186
+ * derivation shared by writers and re-entry validation.
187
+ */
188
+ export declare function deriveProvenanceFromIngressFacts(origin: PainIngressOriginV1, correlation: PainIngressCorrelationV1): PainProvenance;
189
+ /**
190
+ * Re-entry consistency check between the nested v1 block and the legacy
191
+ * top-level fields produced by the same builder (SPEC §9, §12.2.4).
192
+ * Returns null when consistent; a reasonCode string otherwise.
193
+ *
194
+ * Coverage (review blocker 2 closure): every dimension of the
195
+ * nested/top-level contract is asserted — provenance, host session id,
196
+ * evidence count, evidence availability class, and host binding
197
+ * state. A v1 block with unavailable evidence cannot coexist with
198
+ * legacy top-level entries; an unbound v1 block cannot coexist with
199
+ * a legacy sessionIdHint.
200
+ */
201
+ export declare function checkIngressTopLevelConsistency(input: {
202
+ payload: PainIngressV1Payload;
203
+ topLevelProvenance: unknown;
204
+ topLevelSessionIdHint: unknown;
205
+ topLevelEvidenceCount: number;
206
+ }): string | null;
207
+ //# sourceMappingURL=pain-ingress-payload.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pain-ingress-payload.d.ts","sourceRoot":"","sources":["../../src/runtime-v2/pain-ingress-payload.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,340 @@
1
+ /**
2
+ * Pain Ingress shared invariants + persisted payload contract — PRI-642.
3
+ *
4
+ * This module is THE single source for:
5
+ * - the report field parsers (origin / correlation / evidence / score)
6
+ * shared by write-time evaluation and persisted-payload re-entry;
7
+ * - the origin/correlation invariant (`validateOriginCorrelationInvariant`)
8
+ * — the valid-combination rules of SPEC §8.2 that must never diverge
9
+ * between write time and re-entry;
10
+ * - the sentinel session constant (frozen decision #4);
11
+ * - the versioned `painIngress.v1` persisted namespace (SPEC §9) written
12
+ * by PainSignalBridge.buildDiagnosticJson beside the legacy top-level
13
+ * fields, and re-validated by executePendingDiagnosis / retry paths.
14
+ *
15
+ * INVARIANT EQUIVALENCE (review blocker 2): re-entry validation is NOT
16
+ * weaker than write-time validation. parsePainIngressV1Payload shares the
17
+ * field parsers and the invariant with evaluatePainIngress
18
+ * (pain-ingress.ts), so every state illegal at write time — sentinel
19
+ * session ids, empty "available" evidence, impossible origin/correlation
20
+ * combinations — is also rejected on re-entry.
21
+ *
22
+ * Legacy compatibility (SPEC §9): payloads WITHOUT a painIngress.v1 block
23
+ * keep the tolerant legacy normalization branch in pain-signal-bridge.ts;
24
+ * this strictness applies only to payloads CLAIMING the v1 namespace.
25
+ *
26
+ * Pure module — no I/O. @principles/host-runtime and other adapters depend
27
+ * on core; core depends on no adapter.
28
+ */
29
+ import { normalizePainProvenance } from './admission-gate.js';
30
+ export const PAIN_INGRESS_PAYLOAD_VERSION = 'v1';
31
+ // ── Shared invariants and parsers (ONE implementation for write time AND
32
+ // re-entry) ───────────────────────────────────────────────────────────────
33
+ export function isRecord(value) {
34
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
35
+ }
36
+ function hasOwnString(obj, key) {
37
+ return Object.hasOwn(obj, key) && typeof obj[key] === 'string' && (obj[key]).length > 0;
38
+ }
39
+ /**
40
+ * Sentinel session ids are never real correlations (frozen decision #4).
41
+ * Import this constant instead of re-declaring the set in another module.
42
+ */
43
+ export const SENTINEL_SESSION_IDS = new Set(['cli', 'unknown']);
44
+ export function isSentinelSessionId(value) {
45
+ return SENTINEL_SESSION_IDS.has(value);
46
+ }
47
+ export function parseOrigin(value) {
48
+ if (!isRecord(value))
49
+ return null;
50
+ if (value.kind === 'owner_manual') {
51
+ const { channel } = value;
52
+ if (channel === 'openclaw_command' || channel === 'cli_explicit_session' || channel === 'external_cli_unbound') {
53
+ return { kind: 'owner_manual', channel };
54
+ }
55
+ return null;
56
+ }
57
+ if (value.kind === 'automatic_hook' && typeof value.source === 'string' && value.source.length > 0) {
58
+ return { kind: 'automatic_hook', source: value.source };
59
+ }
60
+ return null;
61
+ }
62
+ /**
63
+ * THE correlation parser — used by report validation (write time) and the
64
+ * persisted-payload validator (re-entry) so sentinel rejection and lineage
65
+ * completeness cannot drift between the two.
66
+ */
67
+ export function parseCorrelation(value) {
68
+ if (!isRecord(value))
69
+ return { error: 'correlation_invalid' };
70
+ if (value.status === 'unbound') {
71
+ if (value.reason === 'external_cli' || value.reason === 'missing_host_session') {
72
+ return { value: { status: 'unbound', reason: value.reason } };
73
+ }
74
+ return { error: 'correlation_invalid' };
75
+ }
76
+ if (value.status !== 'bound')
77
+ return { error: 'correlation_invalid' };
78
+ if (value.hostKind === 'openclaw') {
79
+ if (!hasOwnString(value, 'sessionId'))
80
+ return { error: 'correlation_invalid' };
81
+ if (isSentinelSessionId(value.sessionId))
82
+ return { error: 'session_sentinel_invalid' };
83
+ const correlation = { status: 'bound', hostKind: 'openclaw', sessionId: value.sessionId };
84
+ if (typeof value.traceId === 'string')
85
+ correlation.traceId = value.traceId;
86
+ return { value: correlation };
87
+ }
88
+ if (value.hostKind === 'codex') {
89
+ if (!hasOwnString(value, 'rootSessionId'))
90
+ return { error: 'codex_lineage_incomplete' };
91
+ if (!hasOwnString(value, 'rolloutIdentity'))
92
+ return { error: 'codex_lineage_incomplete' };
93
+ if (!hasOwnString(value, 'logicalObservationKey'))
94
+ return { error: 'codex_lineage_incomplete' };
95
+ if (!hasOwnString(value, 'hostTurnId'))
96
+ return { error: 'codex_lineage_incomplete' };
97
+ const correlation = {
98
+ status: 'bound',
99
+ hostKind: 'codex',
100
+ rootSessionId: value.rootSessionId,
101
+ rolloutIdentity: value.rolloutIdentity,
102
+ logicalObservationKey: value.logicalObservationKey,
103
+ hostTurnId: value.hostTurnId,
104
+ };
105
+ if (typeof value.traceId === 'string')
106
+ correlation.traceId = value.traceId;
107
+ return { value: correlation };
108
+ }
109
+ return { error: 'correlation_invalid' };
110
+ }
111
+ const EVIDENCE_UNAVAILABLE_REASONS = [
112
+ 'trajectory_unavailable',
113
+ 'session_not_found',
114
+ 'empty_trajectory',
115
+ 'evidence_read_failed',
116
+ 'evidence_invalid',
117
+ 'not_applicable_unbound',
118
+ ];
119
+ function isEvidenceUnavailableReason(value) {
120
+ return EVIDENCE_UNAVAILABLE_REASONS.includes(value);
121
+ }
122
+ export function parseEvidence(value) {
123
+ if (!isRecord(value))
124
+ return { error: 'evidence_invalid' };
125
+ if (value.status === 'available') {
126
+ if (!Array.isArray(value.entries) || value.entries.length === 0)
127
+ return { error: 'evidence_invalid' };
128
+ const entries = [];
129
+ for (const entry of value.entries) {
130
+ if (!isRecord(entry))
131
+ return { error: 'evidence_invalid' };
132
+ if (entry.kind !== 'behavior_trace' && entry.kind !== 'system_event')
133
+ return { error: 'evidence_invalid' };
134
+ if (typeof entry.sourceRef !== 'string' || entry.sourceRef.length === 0)
135
+ return { error: 'evidence_invalid' };
136
+ if (typeof entry.note !== 'string')
137
+ return { error: 'evidence_invalid' };
138
+ entries.push({ kind: entry.kind, sourceRef: entry.sourceRef, note: entry.note });
139
+ }
140
+ return { value: { status: 'available', entries: entries } };
141
+ }
142
+ const reasons = EVIDENCE_UNAVAILABLE_REASONS;
143
+ if (value.status === 'unavailable' && reasons.includes(value.reason)) {
144
+ return { value: { status: 'unavailable', reason: value.reason } };
145
+ }
146
+ return { error: 'evidence_invalid' };
147
+ }
148
+ /** rc-3/rc-9: a present-but-invalid score is rejected, not silently dropped. */
149
+ export function parseScore(value) {
150
+ if (value === undefined)
151
+ return { score: undefined };
152
+ if (typeof value !== 'number' || !Number.isFinite(value) || value < 0 || value > 100) {
153
+ return { score: undefined, scoreInvalid: true };
154
+ }
155
+ return { score: value };
156
+ }
157
+ /**
158
+ * Validate an untrusted report (parsed JSON / host payload) into a typed
159
+ * PainIngressReport. Fails loud with a structured reasonCode (rc-3); uses
160
+ * the SAME field parsers and invariant as the persisted-payload validator
161
+ * (rc-1/rc-2/rc-3/rc-4).
162
+ */
163
+ export function parsePainIngressReport(input) {
164
+ if (!isRecord(input)) {
165
+ return { ok: false, reasonCode: 'report_invalid', message: 'ingress report must be an object' };
166
+ }
167
+ if (!isRecord(input.identity))
168
+ return { ok: false, reasonCode: 'identity_invalid', message: 'identity must be an object' };
169
+ if (input.identity.kind === 'manual_pain_id') {
170
+ if (!hasOwnString(input.identity, 'painId'))
171
+ return { ok: false, reasonCode: 'identity_invalid', message: 'manual_pain_id requires painId' };
172
+ }
173
+ else if (input.identity.kind === 'host_observation') {
174
+ if (!hasOwnString(input.identity, 'observationId'))
175
+ return { ok: false, reasonCode: 'identity_invalid', message: 'host_observation requires observationId' };
176
+ }
177
+ else {
178
+ return { ok: false, reasonCode: 'identity_invalid', message: 'identity.kind must be manual_pain_id or host_observation' };
179
+ }
180
+ const painTypes = ['tool_failure', 'subagent_error', 'user_frustration'];
181
+ if (!painTypes.includes(input.painType)) {
182
+ return { ok: false, reasonCode: 'pain_type_invalid', message: 'painType must be tool_failure | subagent_error | user_frustration' };
183
+ }
184
+ if (!hasOwnString(input, 'source'))
185
+ return { ok: false, reasonCode: 'source_invalid', message: 'source is required' };
186
+ if (!hasOwnString(input, 'reason'))
187
+ return { ok: false, reasonCode: 'reason_invalid', message: 'reason is required' };
188
+ const origin = parseOrigin(input.origin);
189
+ if (origin === null)
190
+ return { ok: false, reasonCode: 'origin_invalid', message: 'origin must be owner_manual{channel} or automatic_hook{source}' };
191
+ const correlation = parseCorrelation(input.correlation);
192
+ if (correlation.error !== undefined) {
193
+ return { ok: false, reasonCode: correlation.error, message: `correlation rejected: ${correlation.error}` };
194
+ }
195
+ const evidence = parseEvidence(input.evidence);
196
+ if (evidence.error !== undefined) {
197
+ return { ok: false, reasonCode: evidence.error, message: `evidence rejected: ${evidence.error}` };
198
+ }
199
+ // rc-3/rc-9: a present-but-invalid score is rejected, not silently dropped.
200
+ const { score, scoreInvalid } = parseScore(input.score);
201
+ if (scoreInvalid) {
202
+ return { ok: false, reasonCode: 'score_invalid', message: 'score must be a number between 0 and 100' };
203
+ }
204
+ return {
205
+ ok: true,
206
+ report: {
207
+ identity: input.identity,
208
+ painType: input.painType,
209
+ source: input.source,
210
+ reason: input.reason,
211
+ score,
212
+ origin,
213
+ correlation: correlation.value,
214
+ evidence: evidence.value,
215
+ },
216
+ };
217
+ }
218
+ /**
219
+ * Origin/correlation combinations the matrix (SPEC §8.2) declares invalid.
220
+ * Shared by evaluatePainIngress (write time) and parsePainIngressV1Payload
221
+ * (re-entry) so an illegal state can never become legal across a
222
+ * persistence round trip. Returns a reasonCode string when invalid, null
223
+ * when the combination is valid.
224
+ */
225
+ export function validateOriginCorrelationInvariant(origin, correlation) {
226
+ if (origin.kind !== 'owner_manual')
227
+ return null;
228
+ if (origin.channel === 'external_cli_unbound' && correlation.status === 'bound') {
229
+ return 'origin_correlation_mismatch';
230
+ }
231
+ if (origin.channel === 'cli_explicit_session' && correlation.status === 'unbound') {
232
+ return 'origin_correlation_mismatch';
233
+ }
234
+ return null;
235
+ }
236
+ /**
237
+ * Persisted mirror of the write-time evidence bundle classification
238
+ * (PainEvidenceBundle). `available` requires entryCount >= 1 — the same
239
+ * invariant the write-time bundle enforces (a non-empty entries tuple), so
240
+ * an "available with zero entries" state can never pass here.
241
+ */
242
+ function parseEvidenceClass(value) {
243
+ if (!isRecord(value))
244
+ return null;
245
+ if (value.status === 'available') {
246
+ if (Object.hasOwn(value, 'entryCount') && typeof value.entryCount === 'number' && Number.isInteger(value.entryCount) && value.entryCount >= 1) {
247
+ return { status: 'available', entryCount: value.entryCount };
248
+ }
249
+ return null;
250
+ }
251
+ if (value.status === 'unavailable' && isEvidenceUnavailableReason(value.reason)) {
252
+ return { status: 'unavailable', reason: value.reason };
253
+ }
254
+ return null;
255
+ }
256
+ /**
257
+ * Runtime validation of an untrusted persisted painIngress block
258
+ * (rc-1/rc-2/rc-3). Shares parseOrigin/parseCorrelation and the
259
+ * origin/correlation invariant with the write-time evaluator, so sentinel
260
+ * sessions, incomplete Codex lineage and impossible combinations are
261
+ * rejected identically at write time and on re-entry.
262
+ */
263
+ export function parsePainIngressV1Payload(value) {
264
+ if (!isRecord(value))
265
+ return { ok: false, reasonCode: 'ingress_payload_invalid' };
266
+ if (value.version !== PAIN_INGRESS_PAYLOAD_VERSION)
267
+ return { ok: false, reasonCode: 'ingress_payload_version_unsupported' };
268
+ const origin = parseOrigin(value.origin);
269
+ if (origin === null)
270
+ return { ok: false, reasonCode: 'ingress_origin_invalid' };
271
+ const correlation = parseCorrelation(value.correlation);
272
+ if (correlation.error !== undefined)
273
+ return { ok: false, reasonCode: correlation.error };
274
+ const evidenceClass = parseEvidenceClass(value.evidenceClass);
275
+ if (evidenceClass === null)
276
+ return { ok: false, reasonCode: 'ingress_evidence_class_invalid' };
277
+ const invariantViolation = validateOriginCorrelationInvariant(origin, correlation.value);
278
+ if (invariantViolation !== null)
279
+ return { ok: false, reasonCode: invariantViolation };
280
+ return { ok: true, payload: { version: PAIN_INGRESS_PAYLOAD_VERSION, origin, correlation: correlation.value, evidenceClass } };
281
+ }
282
+ /**
283
+ * Derive the legacy provenance from validated rev-2 facts (SPEC §8.3).
284
+ * Adapters do not supply provenance independently; this is the one
285
+ * derivation shared by writers and re-entry validation.
286
+ */
287
+ export function deriveProvenanceFromIngressFacts(origin, correlation) {
288
+ if (origin.kind === 'automatic_hook')
289
+ return 'automatic_hook';
290
+ if (correlation.status === 'bound')
291
+ return 'host_context_bound';
292
+ return 'owner_reported_no_host_trace';
293
+ }
294
+ /**
295
+ * Re-entry consistency check between the nested v1 block and the legacy
296
+ * top-level fields produced by the same builder (SPEC §9, §12.2.4).
297
+ * Returns null when consistent; a reasonCode string otherwise.
298
+ *
299
+ * Coverage (review blocker 2 closure): every dimension of the
300
+ * nested/top-level contract is asserted — provenance, host session id,
301
+ * evidence count, evidence availability class, and host binding
302
+ * state. A v1 block with unavailable evidence cannot coexist with
303
+ * legacy top-level entries; an unbound v1 block cannot coexist with
304
+ * a legacy sessionIdHint.
305
+ */
306
+ export function checkIngressTopLevelConsistency(input) {
307
+ const { payload, topLevelProvenance, topLevelSessionIdHint, topLevelEvidenceCount } = input;
308
+ const expectedProvenance = deriveProvenanceFromIngressFacts(payload.origin, payload.correlation);
309
+ const actualProvenance = typeof topLevelProvenance === 'string' ? normalizePainProvenance(topLevelProvenance) : undefined;
310
+ if (actualProvenance !== expectedProvenance) {
311
+ return 'ingress_payload_mismatch:provenance';
312
+ }
313
+ // Unbound v1 must not coexist with a non-empty top-level session hint
314
+ // (the host would have inferred a real binding at write time).
315
+ if (payload.correlation.status === 'unbound') {
316
+ if (topLevelSessionIdHint !== null && topLevelSessionIdHint !== undefined && topLevelSessionIdHint !== '') {
317
+ return 'ingress_payload_mismatch:unbound_session_hint';
318
+ }
319
+ }
320
+ // Bound v1 (OpenClaw) → the host and the v1 must agree on the session id.
321
+ if (payload.correlation.status === 'bound' && payload.correlation.hostKind === 'openclaw') {
322
+ if (topLevelSessionIdHint !== payload.correlation.sessionId) {
323
+ return 'ingress_payload_mismatch:session';
324
+ }
325
+ }
326
+ // evidenceClass ↔ top-level evidence count: an unavailable v1 cannot
327
+ // coexist with legacy entries; an available v1 must match the count.
328
+ if (payload.evidenceClass.status === 'unavailable') {
329
+ if (topLevelEvidenceCount !== 0) {
330
+ return 'ingress_payload_mismatch:unavailable_evidence_count';
331
+ }
332
+ }
333
+ else {
334
+ if (payload.evidenceClass.entryCount !== topLevelEvidenceCount) {
335
+ return 'ingress_payload_mismatch:evidence_count';
336
+ }
337
+ }
338
+ return null;
339
+ }
340
+ //# sourceMappingURL=pain-ingress-payload.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pain-ingress-payload.js","sourceRoot":"","sources":["../../src/runtime-v2/pain-ingress-payload.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,61 @@
1
+ import type { PainIngressV1Payload, PainIngressReport, IngressEvidenceEntry } from './pain-ingress-payload.js';
2
+ import type { PainProvenance } from './admission-gate.js';
3
+ export { SENTINEL_SESSION_IDS, isSentinelSessionId, parsePainIngressReport, validateOriginCorrelationInvariant, } from './pain-ingress-payload.js';
4
+ export type { PainOrigin, PainCorrelation, IngressEvidenceEntry, PainEvidenceBundle, PainEvidenceUnavailableReason, PainIngressReport, PainIngressParseResult, PainIngressV1Payload, } from './pain-ingress-payload.js';
5
+ /**
6
+ * The legacy write-side shape handed to PainToPrincipleService. Derived by
7
+ * the ingress — callers do not assemble provenance/evidence themselves.
8
+ */
9
+ export interface LegacyPainSubmission {
10
+ painId: string;
11
+ painType: PainIngressReport['painType'];
12
+ source: string;
13
+ reason: string;
14
+ score?: number;
15
+ sessionId?: string;
16
+ agentId?: string;
17
+ traceId?: string;
18
+ provenance: PainProvenance;
19
+ hostKind?: 'openclaw' | 'codex';
20
+ evidence: IngressEvidenceEntry[];
21
+ /** Versioned rev-2 facts persisted beside the legacy top-level fields. */
22
+ painIngress: PainIngressV1Payload;
23
+ }
24
+ export type PainIngressDecision = {
25
+ action: 'submit';
26
+ legacy: LegacyPainSubmission;
27
+ painIngress: PainIngressV1Payload;
28
+ warnings: string[];
29
+ reasonCode?: undefined;
30
+ } | {
31
+ /** Explicit degradation: submission is still allowed (honest empty evidence + warning). */
32
+ action: 'degrade';
33
+ reasonCode: string;
34
+ warning: string;
35
+ nextAction: string;
36
+ legacy: LegacyPainSubmission;
37
+ painIngress: PainIngressV1Payload;
38
+ } | {
39
+ action: 'refuse';
40
+ reasonCode: string;
41
+ warning: string;
42
+ nextAction: string;
43
+ } | {
44
+ /**
45
+ * Automatic signal without binding/evidence — no LLM, no diagnostic
46
+ * task. `legacy` still carries the derived (empty-evidence) submission
47
+ * shape so host funnels can keep their observability projection via
48
+ * the bridge's empty-evidence short-circuit (SPEC §12.2.1/§12.2.2).
49
+ */
50
+ action: 'observation_only';
51
+ reasonCode: string;
52
+ note: string;
53
+ legacy: LegacyPainSubmission;
54
+ painIngress: PainIngressV1Payload;
55
+ };
56
+ /**
57
+ * Decide the pre-LLM action for a validated report, per SPEC §8.2. Pure —
58
+ * no I/O, no persistence, no identity minting.
59
+ */
60
+ export declare function evaluatePainIngress(report: PainIngressReport): PainIngressDecision;
61
+ //# sourceMappingURL=pain-ingress.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pain-ingress.d.ts","sourceRoot":"","sources":["../../src/runtime-v2/pain-ingress.ts"],"names":[],"mappings":"AA0BA,OAAO,KAAK,EACV,oBAAoB,EACpB,iBAAiB,EAEjB,oBAAoB,EACrB,MAAM,2BAA2B,CAAC;AACnC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAI1D,OAAO,EACL,oBAAoB,EACpB,mBAAmB,EACnB,sBAAsB,EACtB,kCAAkC,GACnC,MAAM,2BAA2B,CAAC;AACnC,YAAY,EACV,UAAU,EACV,eAAe,EACf,oBAAoB,EACpB,kBAAkB,EAClB,6BAA6B,EAC7B,iBAAiB,EACjB,sBAAsB,EACtB,oBAAoB,GACrB,MAAM,2BAA2B,CAAC;AAEnC;;;GAGG;AACH,MAAM,WAAW,oBAAoB;IACnC,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,iBAAiB,CAAC,UAAU,CAAC,CAAC;IACxC,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,cAAc,CAAC;IAC3B,QAAQ,CAAC,EAAE,UAAU,GAAG,OAAO,CAAC;IAChC,QAAQ,EAAE,oBAAoB,EAAE,CAAC;IACjC,0EAA0E;IAC1E,WAAW,EAAE,oBAAoB,CAAC;CACnC;AAED,MAAM,MAAM,mBAAmB,GAC3B;IAAE,MAAM,EAAE,QAAQ,CAAC;IAAC,MAAM,EAAE,oBAAoB,CAAC;IAAC,WAAW,EAAE,oBAAoB,CAAC;IAAC,QAAQ,EAAE,MAAM,EAAE,CAAC;IAAC,UAAU,CAAC,EAAE,SAAS,CAAA;CAAE,GACjI;IACE,2FAA2F;IAC3F,MAAM,EAAE,SAAS,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,oBAAoB,CAAC;IAC7B,WAAW,EAAE,oBAAoB,CAAC;CACnC,GACD;IAAE,MAAM,EAAE,QAAQ,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,GAC7E;IACE;;;;;OAKG;IACH,MAAM,EAAE,kBAAkB,CAAC;IAC3B,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,oBAAoB,CAAC;IAC7B,WAAW,EAAE,oBAAoB,CAAC;CACnC,CAAC;AAuDN;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,iBAAiB,GAAG,mBAAmB,CAkFlF"}