@ngockhoale/ukit 3.0.6 → 3.0.8
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/CHANGELOG.md +16 -0
- package/package.json +1 -1
- package/scripts/bench/data-foundation.mjs +562 -0
- package/src/core/observability/adapters/common.js +75 -0
- package/src/core/observability/adapters/contextAdapter.js +55 -0
- package/src/core/observability/adapters/decisionAdapter.js +61 -0
- package/src/core/observability/adapters/routeAdapter.js +135 -0
- package/src/core/observability/analytics/digest.js +186 -0
- package/src/core/observability/analytics/fingerprints.js +126 -0
- package/src/core/observability/analytics/opportunities.js +329 -0
- package/src/core/observability/analytics/rebuild.js +56 -0
- package/src/core/observability/analytics/summary.js +298 -0
- package/src/core/observability/emit/config.js +29 -0
- package/src/core/observability/emit/recorder.js +297 -0
- package/src/core/observability/evaluation/aiPacket.js +230 -0
- package/src/core/observability/evaluation/optimizationKnowledge.js +172 -0
- package/src/core/observability/evaluation/replay.js +143 -0
- package/src/core/observability/evaluation/scorecard.js +445 -0
- package/src/core/observability/privacy/allowlist.js +185 -0
- package/src/core/observability/privacy/redaction.js +113 -0
- package/src/core/observability/privacy/sanitizeForSupport.js +133 -0
- package/src/core/observability/privacy/sanitizeObserved.js +134 -0
- package/src/core/observability/rollout.js +155 -0
- package/src/core/observability/schema/constants.js +66 -0
- package/src/core/observability/schema/registry.js +223 -0
- package/src/core/observability/schema/validate.js +227 -0
- package/src/core/observability/segments/internal.js +241 -0
- package/src/core/observability/segments/readSegments.js +215 -0
- package/src/core/observability/segments/recovery.js +123 -0
- package/src/core/observability/segments/retention.js +381 -0
- package/src/core/observability/support/import.js +402 -0
- package/src/core/observability/support/manifest.js +135 -0
- package/src/core/observability/support/paths.js +94 -0
- package/src/core/observability/support/projector.js +483 -0
- package/src/core/observability/support/renderer.js +130 -0
- package/src/core/observability/support/retention.js +155 -0
- package/template_project/.omp/RULES.md +6 -6
- package/template_project/.omp/config.yml +6 -0
- package/template_project/instructions/overlays/omp-rules.md +6 -6
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* optimizationKnowledge.js (TASK-013, SPEC §5 DF-FR02/DF-FR12, §7, §8) —
|
|
3
|
+
* append-only optimization knowledge base.
|
|
4
|
+
*
|
|
5
|
+
* createOptimizationStore({ root, clock? })
|
|
6
|
+
* → { recordOptimization(entry): { id }, listOptimizations(filter?), storePath }
|
|
7
|
+
*
|
|
8
|
+
* Persists the evidence-linked optimization lineage — hypothesis →
|
|
9
|
+
* pre-registered experiment → guardrails → decision → rollback — as an
|
|
10
|
+
* append-only JSONL file under the observability storage root. Records are
|
|
11
|
+
* immutable once written: a reversal is a NEW record linked via
|
|
12
|
+
* `supersedes`, never a rewrite, and negative results are never erased.
|
|
13
|
+
*
|
|
14
|
+
* Provenance layers (DF-FR02) stay separate: `provenance.source` must name
|
|
15
|
+
* one of PROVENANCE_SOURCES. A finding with no evidence refs or an unknown
|
|
16
|
+
* provenance source is stored with `decision: 'unsupported'` — evaluator
|
|
17
|
+
* opinion is recorded, never promoted to fact or policy.
|
|
18
|
+
*
|
|
19
|
+
* Invariants (SPEC §12, DF-FR12):
|
|
20
|
+
* - `decision: 'promoted'` or `applied: true` REQUIRE
|
|
21
|
+
* `controlled_rollout.evidence_refs` — no promotion from token
|
|
22
|
+
* reduction alone; violating entries throw TypeError.
|
|
23
|
+
* - `decision: 'unsupported'` records can never carry `applied: true`.
|
|
24
|
+
* - This module writes ONLY inside `root` — no runtime config, no
|
|
25
|
+
* learning artifacts, no automatic application of anything.
|
|
26
|
+
*/
|
|
27
|
+
|
|
28
|
+
import fs from 'node:fs';
|
|
29
|
+
import path from 'node:path';
|
|
30
|
+
import crypto from 'node:crypto';
|
|
31
|
+
|
|
32
|
+
export const OPTIMIZATION_STORE_FILE = 'optimization-kb.jsonl';
|
|
33
|
+
|
|
34
|
+
export const DECISIONS = Object.freeze([
|
|
35
|
+
'hypothesis',
|
|
36
|
+
'promoted',
|
|
37
|
+
'rejected',
|
|
38
|
+
'rolled_back',
|
|
39
|
+
'unsupported',
|
|
40
|
+
]);
|
|
41
|
+
|
|
42
|
+
/** The four provenance layers of DF-FR02 — anything else is unsupported. */
|
|
43
|
+
export const PROVENANCE_SOURCES = Object.freeze([
|
|
44
|
+
'observed_fact',
|
|
45
|
+
'derived_metric',
|
|
46
|
+
'evaluated_judgment',
|
|
47
|
+
'optimization_decision',
|
|
48
|
+
]);
|
|
49
|
+
|
|
50
|
+
function isPlainObject(value) {
|
|
51
|
+
return value !== null && typeof value === 'object' && !Array.isArray(value);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function stringList(value) {
|
|
55
|
+
if (!Array.isArray(value)) return [];
|
|
56
|
+
return [...new Set(value.filter((v) => typeof v === 'string' && v.length > 0))].sort();
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function dataCopy(value, fallback) {
|
|
60
|
+
if (value === undefined) return fallback;
|
|
61
|
+
return JSON.parse(JSON.stringify(value));
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function hasControlledRolloutEvidence(entry) {
|
|
65
|
+
return (
|
|
66
|
+
isPlainObject(entry.controlled_rollout) &&
|
|
67
|
+
Array.isArray(entry.controlled_rollout.evidence_refs) &&
|
|
68
|
+
entry.controlled_rollout.evidence_refs.some((r) => typeof r === 'string' && r.length > 0)
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function countExistingLines(storePath) {
|
|
73
|
+
try {
|
|
74
|
+
const text = fs.readFileSync(storePath, 'utf8');
|
|
75
|
+
if (text.length === 0) return 0;
|
|
76
|
+
return text.endsWith('\n') ? text.split('\n').length - 1 : text.split('\n').length;
|
|
77
|
+
} catch {
|
|
78
|
+
return 0;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export function createOptimizationStore({ root, clock } = {}) {
|
|
83
|
+
if (typeof root !== 'string' || root.length === 0) {
|
|
84
|
+
throw new TypeError('createOptimizationStore: root must be a non-empty directory path');
|
|
85
|
+
}
|
|
86
|
+
const storePath = path.join(root, OPTIMIZATION_STORE_FILE);
|
|
87
|
+
const now = typeof clock === 'function' ? clock : () => new Date().toISOString();
|
|
88
|
+
|
|
89
|
+
function recordOptimization(entry) {
|
|
90
|
+
if (!isPlainObject(entry)) {
|
|
91
|
+
throw new TypeError('recordOptimization: entry must be an object');
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
const evidenceRefs = stringList(entry.evidence_refs);
|
|
95
|
+
const provenanceSource =
|
|
96
|
+
isPlainObject(entry.provenance) && typeof entry.provenance.source === 'string'
|
|
97
|
+
? entry.provenance.source
|
|
98
|
+
: null;
|
|
99
|
+
const supported = evidenceRefs.length > 0 && PROVENANCE_SOURCES.includes(provenanceSource);
|
|
100
|
+
|
|
101
|
+
let decision = DECISIONS.includes(entry.decision) ? entry.decision : 'hypothesis';
|
|
102
|
+
let applied = entry.applied === true;
|
|
103
|
+
|
|
104
|
+
if (!supported) {
|
|
105
|
+
// Evaluator opinion without evidence/provenance is stored but can
|
|
106
|
+
// never be promoted or applied — the invariant is enforced here.
|
|
107
|
+
decision = 'unsupported';
|
|
108
|
+
applied = false;
|
|
109
|
+
} else if ((decision === 'promoted' || applied) && !hasControlledRolloutEvidence(entry)) {
|
|
110
|
+
throw new TypeError(
|
|
111
|
+
'recordOptimization: decision promoted / applied requires controlled_rollout.evidence_refs',
|
|
112
|
+
);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
const core = {
|
|
116
|
+
opportunity_id: typeof entry.opportunity_id === 'string' ? entry.opportunity_id : null,
|
|
117
|
+
hypothesis: typeof entry.hypothesis === 'string' ? entry.hypothesis : null,
|
|
118
|
+
baseline: dataCopy(entry.baseline, null),
|
|
119
|
+
variant: dataCopy(entry.variant, null),
|
|
120
|
+
evidence_refs: evidenceRefs,
|
|
121
|
+
guardrail: dataCopy(entry.guardrail, null),
|
|
122
|
+
decision,
|
|
123
|
+
applied,
|
|
124
|
+
controlled_rollout: dataCopy(entry.controlled_rollout, null),
|
|
125
|
+
provenance: { source: provenanceSource },
|
|
126
|
+
versions: dataCopy(entry.versions, {}),
|
|
127
|
+
rollback_criterion:
|
|
128
|
+
typeof entry.rollback_criterion === 'string' ? entry.rollback_criterion : null,
|
|
129
|
+
supersedes: stringList(entry.supersedes),
|
|
130
|
+
created_at: now(),
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
const seq = countExistingLines(storePath) + 1;
|
|
134
|
+
const digest = crypto
|
|
135
|
+
.createHash('sha256')
|
|
136
|
+
.update(`${seq}:${JSON.stringify(core)}`)
|
|
137
|
+
.digest('hex')
|
|
138
|
+
.slice(0, 12);
|
|
139
|
+
const record = { id: `opt-${seq}-${digest}`, ...core };
|
|
140
|
+
|
|
141
|
+
fs.mkdirSync(root, { recursive: true });
|
|
142
|
+
fs.appendFileSync(storePath, `${JSON.stringify(record)}\n`, 'utf8');
|
|
143
|
+
return { id: record.id };
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
function listOptimizations(filter = {}) {
|
|
147
|
+
let text;
|
|
148
|
+
try {
|
|
149
|
+
text = fs.readFileSync(storePath, 'utf8');
|
|
150
|
+
} catch {
|
|
151
|
+
return [];
|
|
152
|
+
}
|
|
153
|
+
const records = [];
|
|
154
|
+
for (const line of text.split('\n')) {
|
|
155
|
+
if (line.length === 0) continue;
|
|
156
|
+
try {
|
|
157
|
+
const parsed = JSON.parse(line);
|
|
158
|
+
if (isPlainObject(parsed)) records.push(parsed);
|
|
159
|
+
} catch {
|
|
160
|
+
// Corrupt line: skip — the KB degrades, it never throws on read.
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
const { decision, opportunity_id } = isPlainObject(filter) ? filter : {};
|
|
164
|
+
return records.filter(
|
|
165
|
+
(r) =>
|
|
166
|
+
(decision === undefined || r.decision === decision) &&
|
|
167
|
+
(opportunity_id === undefined || r.opportunity_id === opportunity_id),
|
|
168
|
+
);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
return { recordOptimization, listOptimizations, storePath };
|
|
172
|
+
}
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* replay.js (TASK-014, SPEC §5 DF-FR08/DF-FR12, §8) — honest replay fidelity.
|
|
3
|
+
*
|
|
4
|
+
* replayCase(goldenCase, { policyId }): ReplayResult
|
|
5
|
+
*
|
|
6
|
+
* Replay is a READ-ONLY, deterministic operation: it materializes the
|
|
7
|
+
* recorded run for the requested policy into canonical envelope records and
|
|
8
|
+
* returns them for static evaluation. It NEVER executes imported content,
|
|
9
|
+
* never calls a model, and never writes to any store — no fs, no clock, no
|
|
10
|
+
* randomness. The same (case, policyId) always produces the same records.
|
|
11
|
+
*
|
|
12
|
+
* Fidelity tags (declared by the case, never inferred):
|
|
13
|
+
* POLICY — recorded under the named policy variant; full causal claim
|
|
14
|
+
* within the recorded episode.
|
|
15
|
+
* CONTEXT — recorded context replay (e.g. bundle-sourced evidence);
|
|
16
|
+
* imported content is inert data, evaluated statically only.
|
|
17
|
+
* SIMULATED — recorded inputs/versions replayed without a live host;
|
|
18
|
+
* user acceptance is not observable → quality stays `unknown`
|
|
19
|
+
* and no full causal effect may be claimed.
|
|
20
|
+
*
|
|
21
|
+
* Compact run encoding (golden fixture format): each record carries the
|
|
22
|
+
* canonical field names plus `dt_ms` — the millisecond offset from the
|
|
23
|
+
* episode start. replayCase materializes `monotonic_ns`, `wall_time_utc`,
|
|
24
|
+
* `record_id`, `trace_id`, `execution_id` and the shared envelope fields
|
|
25
|
+
* deterministically; explicit canonical values always win.
|
|
26
|
+
*/
|
|
27
|
+
|
|
28
|
+
export const REPLAY_TAGS = Object.freeze(['POLICY', 'CONTEXT', 'SIMULATED']);
|
|
29
|
+
|
|
30
|
+
export const REPLAY_LIMITATIONS = Object.freeze({
|
|
31
|
+
POLICY: Object.freeze([]),
|
|
32
|
+
CONTEXT: Object.freeze(['imported_content_static_only']),
|
|
33
|
+
SIMULATED: Object.freeze([
|
|
34
|
+
'recorded_inputs_only',
|
|
35
|
+
'no_user_acceptance_observable',
|
|
36
|
+
'no_full_causal_claim',
|
|
37
|
+
]),
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
const REPLAY_EPOCH_MS = Date.UTC(2026, 0, 1, 0, 0, 0);
|
|
41
|
+
const REPLAY_WRITER = 'writer-replay';
|
|
42
|
+
const REPLAY_BOOT = 'boot-replay';
|
|
43
|
+
const REPLAY_SESSION = 'session-replay';
|
|
44
|
+
const REPLAY_PROJECT = 'project-replay';
|
|
45
|
+
|
|
46
|
+
function isPlainObject(value) {
|
|
47
|
+
return value !== null && typeof value === 'object' && !Array.isArray(value);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function asTag(value) {
|
|
51
|
+
return REPLAY_TAGS.includes(value) ? value : 'POLICY';
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Resolve the run for `policyId`. `run.same_as` aliases another policy's run
|
|
56
|
+
* (one hop) so identical variants do not duplicate record bytes.
|
|
57
|
+
*/
|
|
58
|
+
function resolveRun(runs, policyId) {
|
|
59
|
+
if (!isPlainObject(runs)) return null;
|
|
60
|
+
let run = runs[policyId];
|
|
61
|
+
if (isPlainObject(run) && typeof run.same_as === 'string') {
|
|
62
|
+
run = runs[run.same_as];
|
|
63
|
+
}
|
|
64
|
+
return isPlainObject(run) && Array.isArray(run.records) ? run : null;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Materialize one compact record into a canonical envelope record.
|
|
69
|
+
* Deterministic: ids and clocks derive from (caseId, policyId, index, dt_ms).
|
|
70
|
+
*/
|
|
71
|
+
function materializeRecord(raw, ctx, index) {
|
|
72
|
+
const record = isPlainObject(raw) ? { ...raw } : {};
|
|
73
|
+
const dtMs = typeof record.dt_ms === 'number' && Number.isFinite(record.dt_ms)
|
|
74
|
+
? record.dt_ms
|
|
75
|
+
: index;
|
|
76
|
+
delete record.dt_ms;
|
|
77
|
+
|
|
78
|
+
if (typeof record.record_type !== 'string') record.record_type = 'fact';
|
|
79
|
+
if (typeof record.schema_version !== 'number') record.schema_version = 1;
|
|
80
|
+
if (typeof record.record_id !== 'string') {
|
|
81
|
+
record.record_id = `rec-${ctx.caseId}-${ctx.policyId}-${String(index + 1).padStart(4, '0')}`;
|
|
82
|
+
}
|
|
83
|
+
if (typeof record.trace_id !== 'string') record.trace_id = ctx.traceId;
|
|
84
|
+
if (typeof record.execution_id !== 'string') record.execution_id = ctx.executionId;
|
|
85
|
+
if (typeof record.session_id !== 'string') record.session_id = REPLAY_SESSION;
|
|
86
|
+
if (typeof record.project_ref !== 'string') record.project_ref = REPLAY_PROJECT;
|
|
87
|
+
if (typeof record.boot_id !== 'string') record.boot_id = REPLAY_BOOT;
|
|
88
|
+
if (typeof record.writer_id !== 'string') record.writer_id = REPLAY_WRITER;
|
|
89
|
+
if (typeof record.sequence !== 'number') record.sequence = index + 1;
|
|
90
|
+
if (typeof record.wall_time_utc !== 'string') {
|
|
91
|
+
record.wall_time_utc = new Date(REPLAY_EPOCH_MS + dtMs).toISOString();
|
|
92
|
+
}
|
|
93
|
+
if (typeof record.monotonic_ns !== 'number') record.monotonic_ns = dtMs * 1e6;
|
|
94
|
+
if (typeof record.importance !== 'string') record.importance = 'normal';
|
|
95
|
+
if (typeof record.privacy_class !== 'string') record.privacy_class = 'public';
|
|
96
|
+
if (!isPlainObject(record.payload)) record.payload = {};
|
|
97
|
+
return record;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* @param {object} goldenCase — golden case with `runs` and optional
|
|
102
|
+
* `fidelity.tag` / `provenance` / `imported_content`.
|
|
103
|
+
* @param {{ policyId?: string }} [options]
|
|
104
|
+
* @returns {{ ok: true, case_id, tag, limitations, records, provenance }
|
|
105
|
+
* | { ok: false, reason, case_id, tag, limitations }}
|
|
106
|
+
*/
|
|
107
|
+
export function replayCase(goldenCase, { policyId } = {}) {
|
|
108
|
+
const caseId = isPlainObject(goldenCase) && typeof goldenCase.case_id === 'string'
|
|
109
|
+
? goldenCase.case_id
|
|
110
|
+
: 'unknown';
|
|
111
|
+
const tag = asTag(isPlainObject(goldenCase) && goldenCase.fidelity && goldenCase.fidelity.tag);
|
|
112
|
+
const limitations = [...REPLAY_LIMITATIONS[tag]];
|
|
113
|
+
const provenance = isPlainObject(goldenCase) && isPlainObject(goldenCase.provenance)
|
|
114
|
+
? { ...goldenCase.provenance }
|
|
115
|
+
: {};
|
|
116
|
+
if (provenance.source === 'support_bundle' && !limitations.includes('imported_content_static_only')) {
|
|
117
|
+
limitations.push('imported_content_static_only');
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
const fail = (reason) => ({ ok: false, reason, case_id: caseId, tag, limitations });
|
|
121
|
+
if (!isPlainObject(goldenCase)) return fail('invalid_case');
|
|
122
|
+
if (typeof policyId !== 'string' || policyId.length === 0) return fail('missing_policy');
|
|
123
|
+
|
|
124
|
+
const run = resolveRun(goldenCase.runs, policyId);
|
|
125
|
+
if (!run) return fail('missing_run');
|
|
126
|
+
|
|
127
|
+
const ctx = {
|
|
128
|
+
caseId,
|
|
129
|
+
policyId,
|
|
130
|
+
traceId: `trace-${caseId}-${policyId}`,
|
|
131
|
+
executionId: `exec-${caseId}-${policyId}`,
|
|
132
|
+
};
|
|
133
|
+
const records = run.records.map((raw, index) => materializeRecord(raw, ctx, index));
|
|
134
|
+
|
|
135
|
+
return {
|
|
136
|
+
ok: true,
|
|
137
|
+
case_id: caseId,
|
|
138
|
+
tag,
|
|
139
|
+
limitations,
|
|
140
|
+
records,
|
|
141
|
+
provenance: { ...provenance, policy_id: policyId },
|
|
142
|
+
};
|
|
143
|
+
}
|