progmune-runtime 2.1.0 → 2.1.2

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.
@@ -27,6 +27,8 @@ const protocol_registry_1 = require("./protocol-registry");
27
27
  const branch_ledger_1 = require("./branch-ledger");
28
28
  // ── Proposal Generation ──
29
29
  /** Generate repair proposals for all detected violations in a ledger. */
30
+ /** Generate repair proposals for all detected violations. */
31
+ /** @requires VIOLATIONS @produces REPAIR_PROPOSALS */
30
32
  function suggestRepairs(violations, ir, protocols) {
31
33
  const proposals = [];
32
34
  for (const v of violations) {
@@ -43,6 +45,7 @@ function suggestRepairs(violations, ir, protocols) {
43
45
  return proposals;
44
46
  }
45
47
  /** Protocol violation repair: use SSG fixPath to suggest insertions. */
48
+ /** Generate repair proposals for SSG protocol violations. */
46
49
  function suggestProtocolRepair(rejection, ir) {
47
50
  const proposals = [];
48
51
  if (rejection.fixPath && rejection.fixPath.length > 0) {
@@ -94,6 +97,7 @@ function suggestProtocolRepair(rejection, ir) {
94
97
  return proposals;
95
98
  }
96
99
  /** Invariant violation repair: use rebuildState to compute correct transition data. */
100
+ /** Generate repair proposals for invariant consistency violations. */
97
101
  function suggestInvariantRepair(violation, ledger, namespaceInitialStates = (0, protocol_registry_1.getNsInit)()) {
98
102
  const proposals = [];
99
103
  if (violation.invariant === "before-consistency") {
@@ -223,6 +227,7 @@ function suggestGenericRepair(violation, ir) {
223
227
  /** Convert an accepted repair proposal into a new Branch.
224
228
  * Creates a child branch with the proposed fix applied.
225
229
  * The original ledger is never modified. */
230
+ /** Convert an accepted repair proposal into a new branch. */
226
231
  function applyProposalAsBranch(proposal, parentBranch, currentLedger, ir) {
227
232
  const branch = (0, branch_ledger_1.createBranch)(parentBranch, "repair_attempt");
228
233
  switch (proposal.strategy) {
@@ -275,6 +280,7 @@ function applyProposalAsBranch(proposal, parentBranch, currentLedger, ir) {
275
280
  // ── Validation ──
276
281
  /** Validate a repair proposal: does applying it fix the violation?
277
282
  * Returns true if a re-check passes after applying the proposal. */
283
+ /** Validate whether a repair proposal fixes the violation. */
278
284
  function validateProposal(proposal, currentLedger, namespaceInitialStates = (0, protocol_registry_1.getNsInit)()) {
279
285
  let proposedLedger;
280
286
  switch (proposal.strategy) {
@@ -298,6 +304,8 @@ function validateProposal(proposal, currentLedger, namespaceInitialStates = (0,
298
304
  }
299
305
  // ── Summary ──
300
306
  /** Generate a comprehensive repair summary from a ledger and IR context. */
307
+ /** Generate a comprehensive repair summary with minimal fix set. */
308
+ /** @requires LEDGER_DATA @produces REPAIR_SUMMARY */
301
309
  function generateRepairSummary(ledger, ir, protocols, namespaceInitialStates = (0, protocol_registry_1.getNsInit)()) {
302
310
  const consistency = (0, ssg_validator_1.checkLedgerConsistency)(ledger, namespaceInitialStates);
303
311
  const allProposals = [];
@@ -319,6 +327,8 @@ function generateRepairSummary(ledger, ir, protocols, namespaceInitialStates = (
319
327
  * This is the authoritative "minimal fix set" — applying these proposals in order
320
328
  * should resolve all detected violations without redundant fixes.
321
329
  */
330
+ /** Get the minimal set of repair proposals by deduplication. */
331
+ /** @requires REPAIR_PROPOSALS @produces MINIMAL_FIX_SET */
322
332
  function getMinimalFixSet(proposals) {
323
333
  const seen = new Map();
324
334
  for (const p of proposals) {
@@ -25,6 +25,8 @@ const isStrict = () => STRICT;
25
25
  // ── Assertions ──
26
26
  /** Assert full ledger passes Invariant-0 + Invariant-1.
27
27
  * Throws InvariantViolationError with the first violation's details. */
28
+ /** Assert a ledger passes all invariant checks. */
29
+ /** @requires LEDGER_DATA @produces CONSISTENCY_CHECK */
28
30
  function assertLedgerConsistency(ledger, namespaceInitialStates = (0, protocol_registry_1.getNsInit)()) {
29
31
  if (ledger.length === 0)
30
32
  return;
@@ -51,6 +53,8 @@ function assertLedgerConsistency(ledger, namespaceInitialStates = (0, protocol_r
51
53
  }
52
54
  /** Assert a single transition's delta consistency.
53
55
  * Checks that applying acquire/invalidate to statesBefore produces statesAfter. */
56
+ /** Assert a single transition has consistent state deltas. */
57
+ /** @requires TRANSITION @produces DELTA_CHECK */
54
58
  function assertDeltaConsistency(transition) {
55
59
  if (!transition.valid)
56
60
  return;
@@ -111,6 +115,8 @@ function assertDeltaConsistency(transition) {
111
115
  }
112
116
  }
113
117
  /** Assert rule hashes match — detects when validation rules changed under a ledger. */
118
+ /** Assert rule hashes match to detect rule changes. */
119
+ /** @requires EXPECTED_HASH @produces HASH_MATCH_RESULT */
114
120
  function assertRuleHashMatch(expected, actual, context) {
115
121
  if (expected === actual)
116
122
  return;
@@ -126,6 +132,7 @@ function assertRuleHashMatch(expected, actual, context) {
126
132
  });
127
133
  }
128
134
  /** Assert transition indices are strictly monotonic (no duplicates, non-decreasing). */
135
+ /** Assert transition indices are strictly monotonic. */
129
136
  function assertTransitionOrder(ledger) {
130
137
  if (ledger.length <= 1)
131
138
  return;
@@ -144,6 +151,8 @@ function assertTransitionOrder(ledger) {
144
151
  }
145
152
  }
146
153
  /** Convenience: run all invariant checks on a ledger. Does not throw if all pass. */
154
+ /** Run all invariant checks on a ledger. */
155
+ /** @requires LEDGER_DATA @produces INVARIANT_RESULT */
147
156
  function assertLedgerInvariants(ledger, namespaceInitialStates = (0, protocol_registry_1.getNsInit)(), expectedRuleHash) {
148
157
  assertTransitionOrder(ledger);
149
158
  assertLedgerConsistency(ledger, namespaceInitialStates);
package/dist/runtime.js CHANGED
@@ -37,6 +37,7 @@ exports.runAndCheck = runAndCheck;
37
37
  const child_process_1 = require("child_process");
38
38
  const fs = __importStar(require("fs"));
39
39
  const path = __importStar(require("path"));
40
+ /** @requires COMMAND @produces EXECUTION_RESULT */
40
41
  function runAndCheck(code) {
41
42
  // 把临时文件写入 test-login 目录,使用它的 tsconfig 编译
42
43
  const tmpDir = path.resolve("test-login");
@@ -127,6 +127,7 @@ async function batchScoreFuncs(funcs, goal) {
127
127
  }
128
128
  return result;
129
129
  }
130
+ /** @requires INTENT @produces ACTION_PLAN */
130
131
  async function searchPlan(intent, beamWidth = 2, maxDepth = 6) {
131
132
  (0, llm_1.resetCallCount)();
132
133
  staticScoreCache.clear();
@@ -50,6 +50,7 @@ function ensureDir(dir) {
50
50
  fs.mkdirSync(dir, { recursive: true });
51
51
  }
52
52
  /** 从 IR 数据创建快照 */
53
+ /** @requires IR_DATA @produces SNAPSHOT */
53
54
  function createSnapshot(ir, intent, sessionId) {
54
55
  const functions = ir.map((f) => ({
55
56
  name: f.name,
@@ -69,6 +70,7 @@ function createSnapshot(ir, intent, sessionId) {
69
70
  };
70
71
  }
71
72
  /** 持久化快照 */
73
+ /** @requires SNAPSHOT @produces SNAPSHOT_ID */
72
74
  function saveSnapshot(snapshot) {
73
75
  ensureDir(SNAPSHOT_DIR);
74
76
  fs.writeFileSync(path.join(SNAPSHOT_DIR, `${snapshot.id}.json`), JSON.stringify(snapshot, null, 2));
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.countResolved = countResolved;
4
+ exports.formatSessionCounts = formatSessionCounts;
5
+ /** Count resolved vs unresolved sessions in a session list.
6
+ * @requires SESSION_LIST @produces RESOLVED_COUNT
7
+ * @tags session, count, statistics
8
+ */
9
+ function countResolved(sessions) {
10
+ const resolved = sessions.filter((s) => s.resolved).length;
11
+ return { resolved, unresolved: sessions.length - resolved, total: sessions.length };
12
+ }
13
+ /** Get a summary of session counts as a formatted string.
14
+ * @requires RESOLVED_COUNT @produces FORMATTED_COUNT
15
+ * @tags session, format, report
16
+ */
17
+ function formatSessionCounts(counts) {
18
+ return `${counts.resolved}/${counts.total} resolved, ${counts.unresolved} unresolved`;
19
+ }
@@ -98,6 +98,7 @@ function deepEqualSnapshots(a, b) {
98
98
  return true;
99
99
  }
100
100
  // ── rebuildState: pure fold over ledger → per-namespace state snapshot ──
101
+ /** @requires LEDGER_DATA @produces STATE_SNAPSHOT */
101
102
  function rebuildState(ledger, namespaceInitialStates = new Map([["_global", "INIT"]])) {
102
103
  const stateMap = fromSnapshot({});
103
104
  for (const [ns, initState] of namespaceInitialStates) {
@@ -131,6 +132,7 @@ function computeDelta(beforeSnap, afterSnap, namespace) {
131
132
  return { acquired, invalidated };
132
133
  }
133
134
  // ── findFixPathStatic: BFS state graph search (extracted from class) ──
135
+ /** @requires CURRENT_STATES @produces FIX_PATH */
134
136
  function findFixPathStatic(rules, namespace, current, targetPreStates) {
135
137
  const nsFuncs = [];
136
138
  for (const [fn, rule] of rules) {
@@ -184,6 +186,7 @@ function findFixPathStatic(rules, namespace, current, targetPreStates) {
184
186
  return path;
185
187
  }
186
188
  // ── validateTransition: pure function, stateless ──
189
+ /** @requires TRANSITION_CONTEXT @produces VALIDATION_RESULT */
187
190
  function validateTransition(ctx, candidateFunctionName, actionIndex, rules, namespaceInitialStates, ruleHash) {
188
191
  const currentState = ctx.currentState;
189
192
  const rule = rules.get(candidateFunctionName);
@@ -281,6 +284,7 @@ function validateTransition(ctx, candidateFunctionName, actionIndex, rules, name
281
284
  return { valid: true, transition };
282
285
  }
283
286
  // ── checkLedgerConsistency: Invariant-0 + Invariant-1 over full ledger ──
287
+ /** @requires LEDGER_DATA @produces CONSISTENCY_RESULT */
284
288
  function checkLedgerConsistency(ledger, namespaceInitialStates = new Map([["_global", "INIT"]])) {
285
289
  const violations = [];
286
290
  const running = fromSnapshot({});
@@ -348,6 +352,7 @@ function checkLedgerConsistency(ledger, namespaceInitialStates = new Map([["_glo
348
352
  return { consistent: violations.length === 0, violations };
349
353
  }
350
354
  // ── hashRules: stable hash of rule set for constraint snapshot (P1) ──
355
+ /** @requires RULES @produces RULE_HASH */
351
356
  function hashRules(rules) {
352
357
  const sorted = [...rules.entries()]
353
358
  .sort(([a], [b]) => a.localeCompare(b))
@@ -361,6 +366,7 @@ function hashRules(rules) {
361
366
  return crypto.createHash("sha256").update(JSON.stringify(sorted)).digest("hex").slice(0, 16);
362
367
  }
363
368
  /** Compute a deterministic SHA256 hash of an entire ledger (P1: Tamper-evident integrity). */
369
+ /** @requires LEDGER_DATA @produces LEDGER_HASH */
364
370
  function hashLedger(ledger) {
365
371
  const canonical = ledger.map(t => ({
366
372
  actionIndex: t.actionIndex,
@@ -376,6 +382,7 @@ function hashLedger(ledger) {
376
382
  return crypto.createHash("sha256").update(JSON.stringify(canonical)).digest("hex").slice(0, 16);
377
383
  }
378
384
  /** Compare two ledgers and identify structural differences. */
385
+ /** @requires TWO_LEDGERS @produces LEDGER_DIFF */
379
386
  function diffLedgers(ledgerA, ledgerB) {
380
387
  const hash = (t) => crypto.createHash("sha256").update(JSON.stringify({
381
388
  i: t.actionIndex, f: t.function, n: t.namespace,
@@ -617,6 +624,7 @@ exports.StateMachineValidator = StateMachineValidator;
617
624
  // Standalone presentation utilities (formerly static methods)
618
625
  // ═══════════════════════════════════════════════════════════════
619
626
  /** Format an SSG rejection as a human-readable multi-line string. */
627
+ /** @requires SSG_REJECTION @produces EXPLANATION */
620
628
  function explainRejection(rejection) {
621
629
  const nsLabel = rejection.namespace && rejection.namespace !== DEFAULT_NAMESPACE
622
630
  ? ` [namespace: ${rejection.namespace}]` : '';
package/dist/stdlib.js ADDED
@@ -0,0 +1,205 @@
1
+ "use strict";
2
+ /**
3
+ * Progmune Standard Library — general-purpose utilities for external tasks.
4
+ * Each function has @requires/@produces for Capability Graph integration.
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.isValidEmail = isValidEmail;
8
+ exports.truncate = truncate;
9
+ exports.camelToSnake = camelToSnake;
10
+ exports.capitalizeWords = capitalizeWords;
11
+ exports.countSubstring = countSubstring;
12
+ exports.removeWhitespace = removeWhitespace;
13
+ exports.mostFrequent = mostFrequent;
14
+ exports.unique = unique;
15
+ exports.chunk = chunk;
16
+ exports.arrayDiff = arrayDiff;
17
+ exports.average = average;
18
+ exports.median = median;
19
+ exports.roundTo = roundTo;
20
+ exports.isPrime = isPrime;
21
+ exports.randomInt = randomInt;
22
+ exports.deepClone = deepClone;
23
+ exports.pick = pick;
24
+ exports.deepMerge = deepMerge;
25
+ exports.hasRequiredFields = hasRequiredFields;
26
+ exports.isPlainObject = isPlainObject;
27
+ exports.parseSemver = parseSemver;
28
+ exports.formatDuration = formatDuration;
29
+ exports.formatFileSize = formatFileSize;
30
+ exports.toQueryString = toQueryString;
31
+ exports.retry = retry;
32
+ exports.debounce = debounce;
33
+ // ── String ──
34
+ /** @requires STRING @produces VALIDATION_RESULT @tags string, email, validation */
35
+ function isValidEmail(str) {
36
+ return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(str);
37
+ }
38
+ /** @requires STRING @produces TRUNCATED_STRING @tags string, format */
39
+ function truncate(str, maxLen, ellipsis = "...") {
40
+ return str.length <= maxLen ? str : str.slice(0, maxLen - ellipsis.length) + ellipsis;
41
+ }
42
+ /** @requires STRING @produces FORMATTED_STRING @tags string, case, format */
43
+ function camelToSnake(str) {
44
+ return str.replace(/[A-Z]/g, (c) => "_" + c.toLowerCase());
45
+ }
46
+ /** @requires STRING @produces FORMATTED_STRING @tags string, case, format */
47
+ function capitalizeWords(str) {
48
+ return str.replace(/\b\w/g, (c) => c.toUpperCase());
49
+ }
50
+ /** @requires STRING @produces COUNT @tags string, count */
51
+ function countSubstring(str, sub) {
52
+ if (!sub)
53
+ return 0;
54
+ let count = 0, pos = 0;
55
+ while ((pos = str.indexOf(sub, pos)) !== -1) {
56
+ count++;
57
+ pos += sub.length;
58
+ }
59
+ return count;
60
+ }
61
+ /** @requires STRING @produces CLEANED_STRING @tags string, format */
62
+ function removeWhitespace(str) {
63
+ return str.replace(/\s+/g, "");
64
+ }
65
+ // ── Array ──
66
+ /** @requires ARRAY @produces ELEMENT @tags array, statistics */
67
+ function mostFrequent(arr) {
68
+ if (arr.length === 0)
69
+ return null;
70
+ const counts = new Map();
71
+ for (const item of arr)
72
+ counts.set(item, (counts.get(item) || 0) + 1);
73
+ return [...counts.entries()].sort((a, b) => b[1] - a[1])[0][0];
74
+ }
75
+ /** @requires ARRAY @produces ARRAY @tags array, dedupe */
76
+ function unique(arr) { return [...new Set(arr)]; }
77
+ /** @requires ARRAY @produces ARRAY @tags array, chunk */
78
+ function chunk(arr, size) {
79
+ const result = [];
80
+ for (let i = 0; i < arr.length; i += size)
81
+ result.push(arr.slice(i, i + size));
82
+ return result;
83
+ }
84
+ /** @requires ARRAY @produces ARRAY @tags array, difference */
85
+ function arrayDiff(a, b) {
86
+ const setB = new Set(b);
87
+ return a.filter(x => !setB.has(x));
88
+ }
89
+ // ── Math ──
90
+ /** @requires NUMBERS @produces AVERAGE @tags math, statistics */
91
+ function average(nums) {
92
+ return nums.length === 0 ? 0 : nums.reduce((a, b) => a + b, 0) / nums.length;
93
+ }
94
+ /** @requires NUMBERS @produces MEDIAN @tags math, statistics */
95
+ function median(nums) {
96
+ if (nums.length === 0)
97
+ return 0;
98
+ const sorted = [...nums].sort((a, b) => a - b);
99
+ const mid = Math.floor(sorted.length / 2);
100
+ return sorted.length % 2 ? sorted[mid] : (sorted[mid - 1] + sorted[mid]) / 2;
101
+ }
102
+ /** @requires NUMBER @produces ROUNDED_NUMBER @tags math, format */
103
+ function roundTo(num, decimals) {
104
+ const factor = Math.pow(10, decimals);
105
+ return Math.round(num * factor) / factor;
106
+ }
107
+ /** @requires NUMBER @produces PRIME_CHECK @tags math, validation */
108
+ function isPrime(n) {
109
+ if (n < 2)
110
+ return false;
111
+ for (let i = 2; i <= Math.sqrt(n); i++)
112
+ if (n % i === 0)
113
+ return false;
114
+ return true;
115
+ }
116
+ /** @requires NUMBERS @produces RANDOM_INT @tags math, random */
117
+ function randomInt(min, max) {
118
+ return Math.floor(Math.random() * (max - min + 1)) + min;
119
+ }
120
+ // ── Object ──
121
+ /** @requires OBJECT @produces CLONED_OBJECT @tags object, clone */
122
+ function deepClone(obj) {
123
+ return JSON.parse(JSON.stringify(obj));
124
+ }
125
+ /** @requires OBJECT @produces PICKED_OBJECT @tags object, filter */
126
+ function pick(obj, keys) {
127
+ const result = {};
128
+ for (const k of keys)
129
+ if (k in obj)
130
+ result[k] = obj[k];
131
+ return result;
132
+ }
133
+ /** @requires OBJECTS @produces MERGED_OBJECT @tags object, merge */
134
+ function deepMerge(...objects) {
135
+ return objects.reduce((acc, obj) => {
136
+ for (const key of Object.keys(obj || {})) {
137
+ acc[key] = typeof obj[key] === "object" && !Array.isArray(obj[key])
138
+ ? deepMerge(acc[key] || {}, obj[key]) : obj[key];
139
+ }
140
+ return acc;
141
+ }, {});
142
+ }
143
+ // ── Validation ──
144
+ /** @requires OBJECT @produces VALIDATION_RESULT @tags validation, schema */
145
+ function hasRequiredFields(obj, fields) {
146
+ return fields.every(f => obj && obj[f] !== undefined && obj[f] !== null);
147
+ }
148
+ /** @requires ANY @produces VALIDATION_RESULT @tags validation, type */
149
+ function isPlainObject(val) {
150
+ return val !== null && typeof val === "object" && !Array.isArray(val);
151
+ }
152
+ /** @requires STRING @produces PARSED_VERSION @tags validation, semver */
153
+ function parseSemver(version) {
154
+ const match = version.match(/^(\d+)\.(\d+)\.(\d+)/);
155
+ if (!match)
156
+ return null;
157
+ return { major: +match[1], minor: +match[2], patch: +match[3] };
158
+ }
159
+ // ── Formatting ──
160
+ /** @requires NUMBER @produces FORMATTED_STRING @tags format, duration */
161
+ function formatDuration(ms) {
162
+ if (ms < 1000)
163
+ return `${ms}ms`;
164
+ if (ms < 60000)
165
+ return `${(ms / 1000).toFixed(1)}s`;
166
+ const mins = Math.floor(ms / 60000);
167
+ const secs = Math.round((ms % 60000) / 1000);
168
+ return `${mins}m ${secs}s`;
169
+ }
170
+ /** @requires NUMBER @produces FORMATTED_STRING @tags format, file */
171
+ function formatFileSize(bytes) {
172
+ if (bytes < 1024)
173
+ return `${bytes}B`;
174
+ if (bytes < 1048576)
175
+ return `${(bytes / 1024).toFixed(1)}KB`;
176
+ return `${(bytes / 1048576).toFixed(1)}MB`;
177
+ }
178
+ /** @requires OBJECT @produces QUERY_STRING @tags web, format */
179
+ function toQueryString(obj) {
180
+ return Object.entries(obj)
181
+ .map(([k, v]) => `${encodeURIComponent(k)}=${encodeURIComponent(v)}`)
182
+ .join("&");
183
+ }
184
+ // ── Async ──
185
+ /** @requires FUNCTION @produces RETRY_RESULT @tags async, retry */
186
+ async function retry(fn, maxRetries = 3) {
187
+ for (let i = 0; i < maxRetries; i++) {
188
+ try {
189
+ return await fn();
190
+ }
191
+ catch (e) {
192
+ if (i === maxRetries - 1)
193
+ throw e;
194
+ }
195
+ }
196
+ throw new Error("unreachable");
197
+ }
198
+ /** @requires FUNCTION @produces DEBOUNCED_FUNCTION @tags async, debounce */
199
+ function debounce(fn, delay) {
200
+ let timer;
201
+ return ((...args) => {
202
+ clearTimeout(timer);
203
+ timer = setTimeout(() => fn(...args), delay);
204
+ });
205
+ }
package/dist/utils.js CHANGED
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.jaccardSimilarity = jaccardSimilarity;
4
4
  exports.extractKeywords = extractKeywords;
5
5
  // 计算两个字符串的简单 Jaccard 相似度(基于字符二元组)
6
+ /** @requires STRING_A @produces SIMILARITY_SCORE */
6
7
  function jaccardSimilarity(a, b) {
7
8
  const bigrams = (s) => {
8
9
  const bgs = new Set();
@@ -17,6 +18,7 @@ function jaccardSimilarity(a, b) {
17
18
  return intersection.size / (union.size || 1);
18
19
  }
19
20
  // 从意图中提取关键词
21
+ /** @requires TEXT @produces KEYWORDS */
20
22
  function extractKeywords(intent) {
21
23
  return intent.split(/[\s,。!?,]+/).filter(w => w.length > 1).map(w => w.toLowerCase());
22
24
  }
package/dist/validator.js CHANGED
@@ -150,6 +150,7 @@ function checkVariableFlow(actions) {
150
150
  * 校验单个动作的合法性(函数存在、类型匹配、参数数量)。
151
151
  * @protocol namespace=dev_pipeline pre_states=["IR_EXTRACTED"] post_states=["ACTION_VALIDATED"]
152
152
  */
153
+ /** @requires ACTION @produces VALIDATION_RESULT */
153
154
  function validateAction(action, actionIndex) {
154
155
  const functions = loadIR();
155
156
  const errors = [];
@@ -229,6 +230,7 @@ function validateAction(action, actionIndex) {
229
230
  * 批量校验动作序列 + 变量流向分析。
230
231
  * @protocol namespace=dev_pipeline pre_states=["ACTION_VALIDATED"] post_states=["SEQUENCE_VALIDATED"] invalidate=["ACTION_VALIDATED"]
231
232
  */
233
+ /** @requires ACTIONS @produces VALIDATION_RESULT */
232
234
  function validateActionSequence(actions) {
233
235
  const errors = [];
234
236
  const violations = [];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "progmune-runtime",
3
- "version": "2.1.0",
3
+ "version": "2.1.2",
4
4
  "description": "Progmune Runtime — Program Immunology: Constraint-Guided Program Synthesis Runtime",
5
5
  "main": "dist/mcp-server.mjs",
6
6
  "bin": {