@ngockhoale/ukit 3.0.5 → 3.0.7

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 (43) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/package.json +1 -1
  3. package/scripts/bench/data-foundation.mjs +562 -0
  4. package/src/core/observability/adapters/common.js +75 -0
  5. package/src/core/observability/adapters/contextAdapter.js +55 -0
  6. package/src/core/observability/adapters/decisionAdapter.js +61 -0
  7. package/src/core/observability/adapters/routeAdapter.js +135 -0
  8. package/src/core/observability/analytics/digest.js +186 -0
  9. package/src/core/observability/analytics/fingerprints.js +126 -0
  10. package/src/core/observability/analytics/opportunities.js +329 -0
  11. package/src/core/observability/analytics/rebuild.js +56 -0
  12. package/src/core/observability/analytics/summary.js +298 -0
  13. package/src/core/observability/emit/config.js +29 -0
  14. package/src/core/observability/emit/recorder.js +297 -0
  15. package/src/core/observability/evaluation/aiPacket.js +230 -0
  16. package/src/core/observability/evaluation/optimizationKnowledge.js +172 -0
  17. package/src/core/observability/evaluation/replay.js +143 -0
  18. package/src/core/observability/evaluation/scorecard.js +445 -0
  19. package/src/core/observability/privacy/allowlist.js +185 -0
  20. package/src/core/observability/privacy/redaction.js +113 -0
  21. package/src/core/observability/privacy/sanitizeForSupport.js +133 -0
  22. package/src/core/observability/privacy/sanitizeObserved.js +134 -0
  23. package/src/core/observability/rollout.js +155 -0
  24. package/src/core/observability/schema/constants.js +66 -0
  25. package/src/core/observability/schema/registry.js +223 -0
  26. package/src/core/observability/schema/validate.js +227 -0
  27. package/src/core/observability/segments/internal.js +241 -0
  28. package/src/core/observability/segments/readSegments.js +215 -0
  29. package/src/core/observability/segments/recovery.js +123 -0
  30. package/src/core/observability/segments/retention.js +381 -0
  31. package/src/core/observability/support/import.js +402 -0
  32. package/src/core/observability/support/manifest.js +135 -0
  33. package/src/core/observability/support/paths.js +94 -0
  34. package/src/core/observability/support/projector.js +483 -0
  35. package/src/core/observability/support/renderer.js +130 -0
  36. package/src/core/observability/support/retention.js +155 -0
  37. package/src/core/runtimeConfig.js +6 -3
  38. package/src/decision/client.js +11 -3
  39. package/template_project/.claude/ukit/index/unic-decision.mjs +6 -2
  40. package/template_project/.omp/RULES.md +6 -6
  41. package/template_project/.omp/config.yml +6 -0
  42. package/template_project/docs/UKIT_INTERNALS.md +9 -0
  43. 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
+ }