@principles/core 1.169.0 → 1.171.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 (60) hide show
  1. package/README.md +38 -0
  2. package/dist/index.d.ts +0 -1
  3. package/dist/index.d.ts.map +1 -1
  4. package/dist/index.js +0 -2
  5. package/dist/index.js.map +1 -1
  6. package/dist/pain-signal.d.ts +11 -71
  7. package/dist/pain-signal.d.ts.map +1 -1
  8. package/dist/pain-signal.js +10 -120
  9. package/dist/pain-signal.js.map +1 -1
  10. package/dist/principle-tree-ledger.d.ts +4 -87
  11. package/dist/principle-tree-ledger.d.ts.map +1 -1
  12. package/dist/principle-tree-ledger.js +51 -148
  13. package/dist/principle-tree-ledger.js.map +1 -1
  14. package/dist/runtime-v2/__tests__/architecture-regression.test.js +178 -4
  15. package/dist/runtime-v2/__tests__/architecture-regression.test.js.map +1 -1
  16. package/dist/runtime-v2/__tests__/barrel-io-cleanup.test.d.ts +12 -0
  17. package/dist/runtime-v2/__tests__/barrel-io-cleanup.test.d.ts.map +1 -0
  18. package/dist/runtime-v2/__tests__/barrel-io-cleanup.test.js +46 -0
  19. package/dist/runtime-v2/__tests__/barrel-io-cleanup.test.js.map +1 -0
  20. package/dist/runtime-v2/__tests__/io-deletion.test.d.ts +12 -0
  21. package/dist/runtime-v2/__tests__/io-deletion.test.d.ts.map +1 -0
  22. package/dist/runtime-v2/__tests__/io-deletion.test.js +92 -0
  23. package/dist/runtime-v2/__tests__/io-deletion.test.js.map +1 -0
  24. package/dist/runtime-v2/__tests__/ledger-codec.test.d.ts +2 -0
  25. package/dist/runtime-v2/__tests__/ledger-codec.test.d.ts.map +1 -0
  26. package/dist/runtime-v2/__tests__/ledger-codec.test.js +133 -0
  27. package/dist/runtime-v2/__tests__/ledger-codec.test.js.map +1 -0
  28. package/dist/runtime-v2/__tests__/ledger-store.test.d.ts +2 -0
  29. package/dist/runtime-v2/__tests__/ledger-store.test.d.ts.map +1 -0
  30. package/dist/runtime-v2/__tests__/ledger-store.test.js +65 -0
  31. package/dist/runtime-v2/__tests__/ledger-store.test.js.map +1 -0
  32. package/dist/runtime-v2/__tests__/pain-signal-unification.test.d.ts +2 -0
  33. package/dist/runtime-v2/__tests__/pain-signal-unification.test.d.ts.map +1 -0
  34. package/dist/runtime-v2/__tests__/pain-signal-unification.test.js +150 -0
  35. package/dist/runtime-v2/__tests__/pain-signal-unification.test.js.map +1 -0
  36. package/dist/runtime-v2/index.d.ts +1 -2
  37. package/dist/runtime-v2/index.d.ts.map +1 -1
  38. package/dist/runtime-v2/index.js +4 -2
  39. package/dist/runtime-v2/index.js.map +1 -1
  40. package/dist/runtime-v2/principle-tree/ledger-codec.d.ts +30 -0
  41. package/dist/runtime-v2/principle-tree/ledger-codec.d.ts.map +1 -0
  42. package/dist/runtime-v2/principle-tree/ledger-codec.js +154 -0
  43. package/dist/runtime-v2/principle-tree/ledger-codec.js.map +1 -0
  44. package/dist/runtime-v2/types/index.d.ts +2 -0
  45. package/dist/runtime-v2/types/index.d.ts.map +1 -1
  46. package/dist/runtime-v2/types/index.js +1 -0
  47. package/dist/runtime-v2/types/index.js.map +1 -1
  48. package/dist/runtime-v2/types/ledger-store.d.ts +101 -0
  49. package/dist/runtime-v2/types/ledger-store.d.ts.map +1 -0
  50. package/dist/runtime-v2/types/ledger-store.js +15 -0
  51. package/dist/runtime-v2/types/ledger-store.js.map +1 -0
  52. package/dist/runtime-v2/types/pain-signal.d.ts +5 -3
  53. package/dist/runtime-v2/types/pain-signal.d.ts.map +1 -1
  54. package/dist/runtime-v2/types/pain-signal.js +23 -3
  55. package/dist/runtime-v2/types/pain-signal.js.map +1 -1
  56. package/package.json +4 -4
  57. package/dist/io.d.ts +0 -35
  58. package/dist/io.d.ts.map +0 -1
  59. package/dist/io.js +0 -95
  60. package/dist/io.js.map +0 -1
@@ -12,148 +12,64 @@
12
12
  */
13
13
  import * as fs from 'fs';
14
14
  import * as path from 'path';
15
- import { atomicWriteFileSync } from './io.js';
15
+ import { TREE_NAMESPACE } from './runtime-v2/types/ledger-store.js';
16
+ // PRI-443: Pure parse/serialize functions extracted to codec module
17
+ import { uniqueStrings, createEmptyTree, parseHybridLedger, serializeLedger, } from './runtime-v2/principle-tree/ledger-codec.js';
18
+ export { TREE_NAMESPACE };
16
19
  const PRINCIPLE_TRAINING_FILE = 'principle_training_state.json';
17
20
  // ---------------------------------------------------------------------------
18
- // Constants
21
+ // Atomic file write (inlined PRI-443 Phase 4)
19
22
  // ---------------------------------------------------------------------------
20
- export const TREE_NAMESPACE = '_tree';
21
- const VALID_EVALUABILITIES = ['deterministic', 'weak_heuristic', 'manual_only'];
22
- const VALID_INTERNALIZATION_STATUSES = [
23
- 'prompt_only', 'needs_training', 'in_training',
24
- 'deployed_pending_eval', 'internalized', 'regressed',
25
- ];
26
- // ---------------------------------------------------------------------------
27
- // Helpers
28
- // ---------------------------------------------------------------------------
29
- function isRecord(value) {
30
- return typeof value === 'object' && value !== null && !Array.isArray(value);
31
- }
32
- function stringArray(value) {
33
- return Array.isArray(value) ? value.filter((e) => typeof e === 'string') : [];
34
- }
35
- function clampFloat(value, opts) {
36
- if (typeof value !== 'number' || !Number.isFinite(value))
37
- return opts.fallback;
38
- return Math.max(opts.min, Math.min(opts.max, value));
39
- }
40
- function clampInt(value, opts) {
41
- if (typeof value !== 'number' || !Number.isFinite(value))
42
- return opts.fallback;
43
- return Math.max(opts.min, Math.min(opts.max, Math.round(value)));
44
- }
45
- function uniqueStrings(values) {
46
- return Array.from(new Set(values));
47
- }
48
- // ---------------------------------------------------------------------------
49
- // Parsers
50
- // ---------------------------------------------------------------------------
51
- function parseLegacyTrainingStore(raw) {
52
- if (!isRecord(raw))
53
- return {};
54
- const result = {};
55
- for (const [principleId, candidate] of Object.entries(raw)) {
56
- if (principleId === TREE_NAMESPACE || !isRecord(candidate))
57
- continue;
58
- if (candidate.principleId !== principleId)
59
- continue;
60
- result[principleId] = {
61
- principleId,
62
- evaluability: VALID_EVALUABILITIES.includes(candidate.evaluability)
63
- ? candidate.evaluability
64
- : 'manual_only',
65
- applicableOpportunityCount: clampInt(candidate.applicableOpportunityCount, { min: 0, max: Infinity, fallback: 0 }),
66
- observedViolationCount: clampInt(candidate.observedViolationCount, { min: 0, max: Infinity, fallback: 0 }),
67
- complianceRate: clampFloat(candidate.complianceRate, { min: 0, max: 1, fallback: 0 }),
68
- violationTrend: clampFloat(candidate.violationTrend, { min: -1, max: 1, fallback: 0 }),
69
- generatedSampleCount: clampInt(candidate.generatedSampleCount, { min: 0, max: Infinity, fallback: 0 }),
70
- approvedSampleCount: clampInt(candidate.approvedSampleCount, { min: 0, max: Infinity, fallback: 0 }),
71
- includedTrainRunIds: stringArray(candidate.includedTrainRunIds),
72
- deployedCheckpointIds: stringArray(candidate.deployedCheckpointIds),
73
- lastEvalScore: typeof candidate.lastEvalScore === 'number' && Number.isFinite(candidate.lastEvalScore)
74
- ? clampFloat(candidate.lastEvalScore, { min: 0, max: 1, fallback: 0 }) : undefined,
75
- internalizationStatus: VALID_INTERNALIZATION_STATUSES.includes(candidate.internalizationStatus)
76
- ? candidate.internalizationStatus
77
- : 'prompt_only',
78
- };
79
- }
80
- return result;
81
- }
82
- function parsePrinciples(raw) {
83
- if (!isRecord(raw))
84
- return {};
85
- const principles = {};
86
- for (const [id, value] of Object.entries(raw)) {
87
- if (!isRecord(value))
88
- continue;
89
- principles[id] = {
90
- ...value,
91
- id,
92
- ruleIds: stringArray(value.ruleIds),
93
- conflictsWithPrincipleIds: stringArray(value.conflictsWithPrincipleIds),
94
- derivedFromPainIds: stringArray(value.derivedFromPainIds),
95
- };
96
- }
97
- return principles;
98
- }
99
- function parseRules(raw) {
100
- if (!isRecord(raw))
101
- return {};
102
- const rules = {};
103
- for (const [id, value] of Object.entries(raw)) {
104
- if (!isRecord(value))
105
- continue;
106
- rules[id] = {
107
- ...value,
108
- id,
109
- principleId: typeof value.principleId === 'string' ? value.principleId : '',
110
- implementationIds: stringArray(value.implementationIds),
111
- };
112
- }
113
- return rules;
114
- }
115
- function parseImplementations(raw) {
116
- if (!isRecord(raw))
117
- return {};
118
- const implementations = {};
119
- for (const [id, value] of Object.entries(raw)) {
120
- if (!isRecord(value) || typeof value.ruleId !== 'string')
121
- continue;
122
- implementations[id] = { ...value, id, ruleId: value.ruleId };
23
+ //
24
+ // Previously exported from ./io.ts. Inlined here as a private helper because
25
+ // this is the ONLY consumer in principles-core. The openclaw-plugin has its
26
+ // own copy at src/utils/io.ts.
27
+ //
28
+ // Crash-safe: writes to a .tmp file then renames. On Windows, retries with
29
+ // exponential backoff on EPERM/EBUSY/EACCES to handle transient file locks.
30
+ const RENAME_MAX_RETRIES = 3;
31
+ const RENAME_BASE_DELAY_MS = 50;
32
+ function atomicWriteFileSync(filePath, data) {
33
+ const tmpPath = filePath + '.tmp';
34
+ fs.writeFileSync(tmpPath, data, 'utf8');
35
+ let lastError;
36
+ for (let attempt = 0; attempt < RENAME_MAX_RETRIES; attempt++) {
37
+ try {
38
+ fs.renameSync(tmpPath, filePath);
39
+ return;
40
+ }
41
+ catch (err) {
42
+ lastError = err;
43
+ const { code } = err;
44
+ // Only retry on Windows transient lock errors
45
+ if (code === 'EPERM' || code === 'EBUSY' || code === 'EACCES') {
46
+ if (attempt < RENAME_MAX_RETRIES - 1) {
47
+ const delay = RENAME_BASE_DELAY_MS * Math.pow(2, attempt);
48
+ // Synchronous sleep using a tight spin with accessSync yield
49
+ const waitUntil = Date.now() + delay;
50
+ while (Date.now() < waitUntil) {
51
+ try {
52
+ fs.accessSync(tmpPath);
53
+ }
54
+ catch { /* ignore */ }
55
+ }
56
+ }
57
+ continue;
58
+ }
59
+ // Non-retryable error throw immediately
60
+ break;
61
+ }
123
62
  }
124
- return implementations;
125
- }
126
- function parseMetrics(raw) {
127
- if (!isRecord(raw))
128
- return {};
129
- const metrics = {};
130
- for (const [id, value] of Object.entries(raw)) {
131
- if (!isRecord(value))
132
- continue;
133
- metrics[id] = { ...value, principleId: typeof value.principleId === 'string' ? value.principleId : id };
63
+ // Clean up temp file on failure
64
+ try {
65
+ fs.unlinkSync(tmpPath);
134
66
  }
135
- return metrics;
67
+ catch { /* best effort */ }
68
+ throw lastError ?? new Error('atomicWriteFileSync: rename failed');
136
69
  }
137
70
  // ---------------------------------------------------------------------------
138
- // Store factory
71
+ // Ledger file I/O (the only non-pure part of this module)
139
72
  // ---------------------------------------------------------------------------
140
- function createEmptyTree() {
141
- return { principles: {}, rules: {}, implementations: {}, metrics: {}, lastUpdated: new Date(0).toISOString() };
142
- }
143
- // ---------------------------------------------------------------------------
144
- // Parsers
145
- // ---------------------------------------------------------------------------
146
- function parseTree(raw) {
147
- if (!isRecord(raw))
148
- return createEmptyTree();
149
- return {
150
- principles: parsePrinciples(raw.principles),
151
- rules: parseRules(raw.rules),
152
- implementations: parseImplementations(raw.implementations),
153
- metrics: parseMetrics(raw.metrics),
154
- lastUpdated: typeof raw.lastUpdated === 'string' ? raw.lastUpdated : new Date(0).toISOString(),
155
- };
156
- }
157
73
  function getLedgerFilePath(stateDir) {
158
74
  return path.join(stateDir, PRINCIPLE_TRAINING_FILE);
159
75
  }
@@ -167,25 +83,12 @@ function readLedgerFromFile(filePath) {
167
83
  return { trainingStore: {}, tree: createEmptyTree() };
168
84
  }
169
85
  const parsed = JSON.parse(content);
170
- if (!isRecord(parsed))
171
- return { trainingStore: {}, tree: createEmptyTree() };
172
- const trainingStoreRaw = parsed.trainingStore ?? parsed;
173
- const treeRaw = parsed[TREE_NAMESPACE] ?? parsed.tree;
174
- return {
175
- trainingStore: parseLegacyTrainingStore(trainingStoreRaw),
176
- tree: parseTree(treeRaw),
177
- };
86
+ return parseHybridLedger(parsed);
178
87
  }
179
88
  catch {
180
89
  return { trainingStore: {}, tree: createEmptyTree() };
181
90
  }
182
91
  }
183
- function serializeLedger(store) {
184
- return JSON.stringify({
185
- ...store.trainingStore,
186
- [TREE_NAMESPACE]: { ...store.tree, lastUpdated: new Date().toISOString() },
187
- }, null, 2);
188
- }
189
92
  // ---------------------------------------------------------------------------
190
93
  // Ledger mutations (synchronous — safe for single-process use)
191
94
  // ---------------------------------------------------------------------------
@@ -1 +1 @@
1
- {"version":3,"file":"principle-tree-ledger.js","sourceRoot":"","sources":["../src/principle-tree-ledger.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"principle-tree-ledger.js","sourceRoot":"","sources":["../src/principle-tree-ledger.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAE,MAAM,IAAI,CAAC;AACzB,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAe7B,OAAO,EAAE,cAAc,EAAE,MAAM,oCAAoC,CAAC;AAEpE,oEAAoE;AACpE,OAAO,EACL,aAAa,EACb,eAAe,EACf,iBAAiB,EACjB,eAAe,GAChB,MAAM,6CAA6C,CAAC;AAgBrD,OAAO,EAAE,cAAc,EAAE,CAAC;AAE1B,MAAM,uBAAuB,GAAG,+BAA+B,CAAC;AAEhE,8EAA8E;AAC9E,8CAA8C;AAC9C,8EAA8E;AAC9E,EAAE;AACF,6EAA6E;AAC7E,4EAA4E;AAC5E,+BAA+B;AAC/B,EAAE;AACF,2EAA2E;AAC3E,4EAA4E;AAE5E,MAAM,kBAAkB,GAAG,CAAC,CAAC;AAC7B,MAAM,oBAAoB,GAAG,EAAE,CAAC;AAEhC,SAAS,mBAAmB,CAAC,QAAgB,EAAE,IAAY;IACzD,MAAM,OAAO,GAAG,QAAQ,GAAG,MAAM,CAAC;IAClC,EAAE,CAAC,aAAa,CAAC,OAAO,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC;IAExC,IAAI,SAA4B,CAAC;IACjC,KAAK,IAAI,OAAO,GAAG,CAAC,EAAE,OAAO,GAAG,kBAAkB,EAAE,OAAO,EAAE,EAAE,CAAC;QAC9D,IAAI,CAAC;YACH,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;YACjC,OAAO;QACT,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,SAAS,GAAG,GAAY,CAAC;YACzB,MAAM,EAAC,IAAI,EAAC,GAAI,GAAyB,CAAC;YAC1C,8CAA8C;YAC9C,IAAI,IAAI,KAAK,OAAO,IAAI,IAAI,KAAK,OAAO,IAAI,IAAI,KAAK,QAAQ,EAAE,CAAC;gBAC9D,IAAI,OAAO,GAAG,kBAAkB,GAAG,CAAC,EAAE,CAAC;oBACrC,MAAM,KAAK,GAAG,oBAAoB,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC;oBAC1D,6DAA6D;oBAC7D,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC;oBACrC,OAAO,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,EAAE,CAAC;wBAC9B,IAAI,CAAC;4BAAC,EAAE,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;wBAAC,CAAC;wBAAC,MAAM,CAAC,CAAC,YAAY,CAAC,CAAC;oBACxD,CAAC;gBACH,CAAC;gBACD,SAAS;YACX,CAAC;YACD,0CAA0C;YAC1C,MAAM;QACR,CAAC;IACH,CAAC;IAED,gCAAgC;IAChC,IAAI,CAAC;QAAC,EAAE,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;IAAC,CAAC;IAAC,MAAM,CAAC,CAAC,iBAAiB,CAAC,CAAC;IAC3D,MAAM,SAAS,IAAI,IAAI,KAAK,CAAC,oCAAoC,CAAC,CAAC;AACrE,CAAC;AAED,8EAA8E;AAC9E,0DAA0D;AAC1D,8EAA8E;AAE9E,SAAS,iBAAiB,CAAC,QAAgB;IACzC,OAAO,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,uBAAuB,CAAC,CAAC;AACtD,CAAC;AAED,SAAS,kBAAkB,CAAC,QAAgB;IAC1C,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC7B,OAAO,EAAE,aAAa,EAAE,EAAE,EAAE,IAAI,EAAE,eAAe,EAAE,EAAE,CAAC;IACxD,CAAC;IACD,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,EAAE,CAAC,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;QACnD,IAAI,CAAC,OAAO,IAAI,OAAO,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC;YACtC,OAAO,EAAE,aAAa,EAAE,EAAE,EAAE,IAAI,EAAE,eAAe,EAAE,EAAE,CAAC;QACxD,CAAC;QACD,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAY,CAAC;QAC9C,OAAO,iBAAiB,CAAC,MAAM,CAAC,CAAC;IACnC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,aAAa,EAAE,EAAE,EAAE,IAAI,EAAE,eAAe,EAAE,EAAE,CAAC;IACxD,CAAC;AACH,CAAC;AAED,8EAA8E;AAC9E,+DAA+D;AAC/D,8EAA8E;AAE9E;;;GAGG;AACH,SAAS,YAAY,CAAI,QAAgB,EAAE,MAAuC;IAChF,MAAM,QAAQ,GAAG,iBAAiB,CAAC,QAAQ,CAAC,CAAC;IAC7C,MAAM,KAAK,GAAG,kBAAkB,CAAC,QAAQ,CAAC,CAAC;IAC3C,MAAM,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;IAC7B,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;IACnC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC;QAAE,EAAE,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAChE,mBAAmB,CAAC,QAAQ,EAAE,eAAe,CAAC,KAAK,CAAC,CAAC,CAAC;IACtD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,8EAA8E;AAC9E,aAAa;AACb,8EAA8E;AAE9E,MAAM,UAAU,UAAU,CAAC,QAAgB;IACzC,OAAO,kBAAkB,CAAC,iBAAiB,CAAC,QAAQ,CAAC,CAAC,CAAC;AACzD,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,QAAgB,EAAE,KAAwB;IACnE,YAAY,CAAC,QAAQ,EAAE,CAAC,OAAO,EAAE,EAAE;QACjC,OAAO,CAAC,aAAa,GAAG,KAAK,CAAC,aAAa,CAAC;QAC5C,OAAO,CAAC,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC;IAC5B,CAAC,CAAC,CAAC;AACL,CAAC;AAED,MAAM,UAAU,oBAAoB,CAAC,QAAgB,EAAE,SAA0B;IAC/E,OAAO,YAAY,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,EAAE;QACtC,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,SAAS,CAAC;QAChD,KAAK,CAAC,IAAI,CAAC,WAAW,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;QAClD,OAAO,SAAS,CAAC;IACnB,CAAC,CAAC,CAAC;AACL,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,QAAgB,EAAE,WAAmB,EAAE,OAAiC;IACtG,OAAO,YAAY,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,EAAE;QACtC,MAAM,QAAQ,GAAG,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,WAAW,CAAC,CAAC;QACpD,IAAI,CAAC,QAAQ;YAAE,MAAM,IAAI,KAAK,CAAC,oCAAoC,WAAW,IAAI,CAAC,CAAC;QACpF,MAAM,IAAI,GAAoB;YAC5B,GAAG,QAAQ;YACX,GAAG,OAAO;YACV,EAAE,EAAE,WAAW;YACf,OAAO,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,aAAa,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,OAAO;YAC5E,yBAAyB,EAAE,OAAO,CAAC,yBAAyB;gBAC1D,CAAC,CAAC,aAAa,CAAC,OAAO,CAAC,yBAAyB,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,yBAAyB;YACzF,kBAAkB,EAAE,OAAO,CAAC,kBAAkB;gBAC5C,CAAC,CAAC,aAAa,CAAC,OAAO,CAAC,kBAAkB,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,kBAAkB;SAC5E,CAAC;QACF,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,WAAW,CAAC,GAAG,IAAI,CAAC;QAC1C,OAAO,IAAI,CAAC;IACd,CAAC,CAAC,CAAC;AACL,CAAC;AAED,MAAM,UAAU,2BAA2B,CAAC,QAAgB,EAAE,WAAmB,EAAE,OAA8B;IAC/G,OAAO,YAAY,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,EAAE;QACtC,MAAM,IAAI,GAA0B,EAAE,GAAG,OAAO,EAAE,WAAW,EAAE,CAAC;QAChE,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,GAAG,IAAI,CAAC;QACvC,OAAO,IAAI,CAAC;IACd,CAAC,CAAC,CAAC;AACL,CAAC;AAED,MAAM,UAAU,uBAAuB,CAAC,QAAgB;IACtD,OAAO,iBAAiB,CAAC,QAAQ,CAAC,CAAC;AACrC,CAAC"}
@@ -5,6 +5,8 @@
5
5
  * Add entries here whenever a new service/read-model boundary is established.
6
6
  */
7
7
  import { describe, it, expect, beforeAll } from 'vitest';
8
+ import * as fsSync from 'fs';
9
+ import * as pathSync from 'path';
8
10
  // ── Source-file existence ──────────────────────────────────────────────────
9
11
  const REQUIRED_SOURCE_FILES = [
10
12
  'pain-to-principle-service.ts',
@@ -2427,7 +2429,8 @@ describe('PRI-139 L1 Hard Cap & LRU Eviction', () => {
2427
2429
  it('LedgerPrinciple includes lastTriggeredAt field', async () => {
2428
2430
  const { readFileSync } = await import('node:fs');
2429
2431
  const { resolve } = await import('node:path');
2430
- const src = readFileSync(resolve(__dirname, '..', '..', 'principle-tree-ledger.ts'), 'utf-8');
2432
+ // PRI-443: type moved to pure module
2433
+ const src = readFileSync(resolve(__dirname, '..', 'types', 'ledger-store.ts'), 'utf-8');
2431
2434
  expect(src).toContain('lastTriggeredAt');
2432
2435
  });
2433
2436
  it('PruningHealthSummary includes activeL1Count and l1Cap fields', async () => {
@@ -3022,11 +3025,18 @@ describe('PRI-416: type single-ownership guards', () => {
3022
3025
  });
3023
3026
  it('HybridLedgerStore is defined exactly once in core/src/', () => {
3024
3027
  const hits = findDefinitions(/export\s+interface\s+HybridLedgerStore\s*\{/);
3025
- expect(hits).toEqual(['principle-tree-ledger.ts']);
3028
+ expect(hits).toEqual(['runtime-v2/types/ledger-store.ts']);
3026
3029
  });
3027
- it('atomicWriteFileSync is defined exactly once in core/src/', () => {
3030
+ it('atomicWriteFileSync is NOT exported from any core/src/ file (PRI-443 Phase 4)', () => {
3031
+ // After PRI-443 Phase 4, atomicWriteFileSync is inlined as a PRIVATE helper
3032
+ // inside principle-tree-ledger.ts. It must NOT be exported from core.
3028
3033
  const hits = findDefinitions(/export\s+function\s+atomicWriteFileSync\s*\(/);
3029
- expect(hits).toEqual(['io.ts']);
3034
+ expect(hits).toEqual([]);
3035
+ });
3036
+ it('atomicWriteFileSync is defined exactly once as a private function in principle-tree-ledger.ts (PRI-443 Phase 4)', () => {
3037
+ // The function is now a private (non-exported) helper inlined in principle-tree-ledger.ts
3038
+ const hits = findDefinitions(/function\s+atomicWriteFileSync\s*\(/);
3039
+ expect(hits).toEqual(['principle-tree-ledger.ts']);
3030
3040
  });
3031
3041
  });
3032
3042
  // ── PRI-416: Barrel Cap Guards ────────────────────────────────────────────────
@@ -3054,4 +3064,168 @@ describe('PRI-416: barrel cap guards', () => {
3054
3064
  expect(exportLines.length).toBeLessThanOrEqual(BARREL_MAX_EXPORT_LINES);
3055
3065
  });
3056
3066
  });
3067
+ // ── PRI-443: Pure module boundary guards ──────────────────────────────────────
3068
+ //
3069
+ // Phases 1-3 extracted pure types/codecs/schema out of I/O modules. These guards
3070
+ // ensure those pure modules never regress to importing fs/path, and that the
3071
+ // runtime-v2 barrel never re-exports I/O functions from principle-tree-ledger.
3072
+ describe('PRI-443: pure module boundary guards', () => {
3073
+ const FORBIDDEN_PURE_IMPORTS = [
3074
+ "from 'fs'",
3075
+ 'from "fs"',
3076
+ "from 'node:fs'",
3077
+ 'from "node:fs"',
3078
+ "from 'path'",
3079
+ 'from "path"',
3080
+ "from 'node:path'",
3081
+ 'from "node:path"',
3082
+ ];
3083
+ async function readSrc(relPath) {
3084
+ const fsMod = await import('fs'); // eslint-disable-line @typescript-eslint/consistent-type-imports
3085
+ const pathMod = await import('path'); // eslint-disable-line @typescript-eslint/consistent-type-imports
3086
+ const full = pathMod.resolve(__dirname, '..', relPath);
3087
+ return fsMod.readFileSync(full, 'utf-8');
3088
+ }
3089
+ it('runtime-v2/types/ledger-store.ts has zero fs/path imports (pure types module)', async () => {
3090
+ const src = await readSrc('types/ledger-store.ts');
3091
+ for (const pat of FORBIDDEN_PURE_IMPORTS) {
3092
+ expect(src).not.toContain(pat);
3093
+ }
3094
+ });
3095
+ it('runtime-v2/principle-tree/ledger-codec.ts has zero fs/path imports (pure codec module)', async () => {
3096
+ const src = await readSrc('principle-tree/ledger-codec.ts');
3097
+ for (const pat of FORBIDDEN_PURE_IMPORTS) {
3098
+ expect(src).not.toContain(pat);
3099
+ }
3100
+ });
3101
+ it('runtime-v2/types/pain-signal.ts has zero fs/path imports (pure schema module)', async () => {
3102
+ const src = await readSrc('types/pain-signal.ts');
3103
+ for (const pat of FORBIDDEN_PURE_IMPORTS) {
3104
+ expect(src).not.toContain(pat);
3105
+ }
3106
+ });
3107
+ it('runtime-v2/index.ts barrel does NOT export I/O functions from principle-tree-ledger', async () => {
3108
+ const src = await readSrc('index.ts');
3109
+ // I/O functions must not be re-exported through the pure-types barrel.
3110
+ expect(src).not.toMatch(/export\s+\{[^}]*\bloadLedger\b[^}]*\}\s*from\s*['"]\.\.\/principle-tree-ledger/);
3111
+ expect(src).not.toMatch(/export\s+\{[^}]*\bsaveLedger\b[^}]*\}\s*from\s*['"]\.\.\/principle-tree-ledger/);
3112
+ expect(src).not.toMatch(/export\s+\{[^}]*\bgetLedgerFilePathPublic\b[^}]*\}\s*from\s*['"]\.\.\/principle-tree-ledger/);
3113
+ expect(src).not.toMatch(/export\s+\{[^}]*\bupdatePrinciple\b[^}]*\}\s*from\s*['"]\.\.\/principle-tree-ledger/);
3114
+ expect(src).not.toMatch(/export\s+\{[^}]*\batomicWriteFileSync\b[^}]*\}\s*from\s*['"]\.\.\/principle-tree-ledger/);
3115
+ });
3116
+ it('runtime-v2/index.ts barrel re-exports LedgerTreeStore type from pure types module, not from principle-tree-ledger', async () => {
3117
+ const src = await readSrc('index.ts');
3118
+ // The type must come from the pure types module (./types/ledger-store.js),
3119
+ // NOT from the I/O module (../principle-tree-ledger.js).
3120
+ expect(src).toMatch(/export\s+type\s+\{\s*LedgerTreeStore\s*\}\s*from\s*['"]\.\/types\/ledger-store\.js['"]/);
3121
+ expect(src).not.toMatch(/export\s+type\s+\{\s*LedgerTreeStore\s*\}\s*from\s*['"]\.\.\/principle-tree-ledger\.js['"]/);
3122
+ });
3123
+ });
3124
+ // ── PRI-450: Core I/O whitelist guard ──────────────────────────────────────────
3125
+ //
3126
+ // Scans all production (.ts, non-test) files under packages/principles-core/src/
3127
+ // for fs/path imports and verifies they match an explicit whitelist. Any new file
3128
+ // that needs I/O must be added to ALLOWED_IO_FILES here — otherwise CI fails.
3129
+ // This forces developers to explain "why does this file need I/O?" in their PR.
3130
+ describe('PRI-450: core I/O whitelist guard', () => {
3131
+ // Whitelist of production files allowed to import fs/path.
3132
+ // Paths are relative to packages/principles-core/src/.
3133
+ const ALLOWED_IO_FILES = new Set([
3134
+ 'principle-tree-ledger.ts',
3135
+ 'evolution-store.ts',
3136
+ 'trajectory-store.ts',
3137
+ 'workflow-funnel-loader.ts',
3138
+ 'runtime-v2/store/sqlite-connection.ts',
3139
+ 'runtime-v2/store/runtime-state-manager.ts',
3140
+ 'runtime-v2/adapter/openclaw-cli-runtime-adapter.ts',
3141
+ 'runtime-v2/candidate-audit.ts',
3142
+ 'runtime-v2/pain-signal-observability.ts',
3143
+ 'runtime-v2/internalization-chain-integrity-read-model.ts',
3144
+ 'runtime-v2/internalization-integrity-remediation.ts',
3145
+ 'runtime-v2/operator-health-read-model.ts',
3146
+ 'runtime-v2/pain-chain-read-model.ts',
3147
+ 'runtime-v2/pruning-read-model.ts',
3148
+ 'runtime-v2/pruning-review-log.ts',
3149
+ 'runtime-v2/schema-conformance-read-model.ts',
3150
+ ]);
3151
+ // Extract all import module paths from source code.
3152
+ // Handles: import ... from 'mod', import 'mod' (side-effect), and multiline imports.
3153
+ // Reuses the same pattern proven in the PRI-215 extractImportModulePaths helper.
3154
+ function extractImportPaths(src) {
3155
+ const paths = [];
3156
+ for (const m of src.matchAll(/import\s+[\s\S]*?from\s+['"]([^'"]+)['"]/g)) {
3157
+ if (m[1] != null)
3158
+ paths.push(m[1]);
3159
+ }
3160
+ for (const m of src.matchAll(/import\s+['"]([^'"]+)['"]/g)) {
3161
+ if (m[1] != null && !paths.includes(m[1]))
3162
+ paths.push(m[1]);
3163
+ }
3164
+ return paths;
3165
+ }
3166
+ // Check if any import path references fs or path (including sub-paths like fs/promises).
3167
+ function importsFsOrPath(src) {
3168
+ const paths = extractImportPaths(src);
3169
+ return paths.some((p) => p === 'fs' || p.startsWith('fs/') ||
3170
+ p === 'node:fs' || p.startsWith('node:fs/') ||
3171
+ p === 'path' || p.startsWith('path/') ||
3172
+ p === 'node:path' || p.startsWith('node:path/'));
3173
+ }
3174
+ function collectTsFiles(dir, acc) {
3175
+ const entries = fsSync.readdirSync(dir, { withFileTypes: true });
3176
+ for (const entry of entries) {
3177
+ const fullPath = pathSync.join(dir, entry.name);
3178
+ if (entry.isDirectory()) {
3179
+ collectTsFiles(fullPath, acc);
3180
+ }
3181
+ else if (entry.isFile() &&
3182
+ entry.name.endsWith('.ts') &&
3183
+ !entry.name.endsWith('.test.ts') &&
3184
+ !entry.name.endsWith('.spec.ts')) {
3185
+ acc.push(fullPath);
3186
+ }
3187
+ }
3188
+ }
3189
+ it('core/src/ production files: only whitelisted files import fs/path', () => {
3190
+ const coreSrcDir = pathSync.resolve(__dirname, '..', '..');
3191
+ const allFiles = [];
3192
+ collectTsFiles(coreSrcDir, allFiles);
3193
+ const violations = [];
3194
+ for (const filePath of allFiles) {
3195
+ const content = fsSync.readFileSync(filePath, 'utf-8');
3196
+ if (importsFsOrPath(content)) {
3197
+ const relPath = pathSync.relative(coreSrcDir, filePath).replace(/\\/g, '/');
3198
+ if (!ALLOWED_IO_FILES.has(relPath)) {
3199
+ violations.push(relPath);
3200
+ }
3201
+ }
3202
+ }
3203
+ expect(violations).toEqual([]);
3204
+ });
3205
+ it('ALLOWED_IO_FILES whitelist entries all exist on disk', () => {
3206
+ const coreSrcDir = pathSync.resolve(__dirname, '..', '..');
3207
+ const missing = [];
3208
+ for (const relPath of ALLOWED_IO_FILES) {
3209
+ const fullPath = pathSync.join(coreSrcDir, ...relPath.split('/'));
3210
+ if (!fsSync.existsSync(fullPath)) {
3211
+ missing.push(relPath);
3212
+ }
3213
+ }
3214
+ expect(missing).toEqual([]);
3215
+ });
3216
+ it('importsFsOrPath detects sub-path imports (fs/promises) and side-effect imports', () => {
3217
+ // Sub-path import
3218
+ expect(importsFsOrPath(`import { mkdir } from 'node:fs/promises';`)).toBe(true);
3219
+ expect(importsFsOrPath(`import { posix } from 'path/posix';`)).toBe(true);
3220
+ // Side-effect import
3221
+ expect(importsFsOrPath(`import 'fs';`)).toBe(true);
3222
+ expect(importsFsOrPath(`import "node:path";`)).toBe(true);
3223
+ // Standard import
3224
+ expect(importsFsOrPath(`import * as fs from 'fs';`)).toBe(true);
3225
+ expect(importsFsOrPath(`import { resolve } from 'node:path';`)).toBe(true);
3226
+ // Non-fs/path imports
3227
+ expect(importsFsOrPath(`import { foo } from 'bar';`)).toBe(false);
3228
+ expect(importsFsOrPath(``)).toBe(false);
3229
+ });
3230
+ });
3057
3231
  //# sourceMappingURL=architecture-regression.test.js.map