@vortex-os/base 0.11.0 → 0.12.1

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.
@@ -0,0 +1,292 @@
1
+ import {
2
+ parseFrontmatter
3
+ } from "./chunk-T53UWSTR.js";
4
+
5
+ // ../plugins/session-rituals/dist/failures.js
6
+ import { mkdir, readdir, readFile, stat, writeFile } from "fs/promises";
7
+ import { existsSync } from "fs";
8
+ import { join } from "path";
9
+ var FAILURES_DIR = "_failures";
10
+ function ladderStage(count) {
11
+ if (count >= 3)
12
+ return "promote";
13
+ if (count === 2)
14
+ return "gate";
15
+ return "recorded";
16
+ }
17
+ var KEY_RE = /^[a-z0-9][a-z0-9-]{1,62}[a-z0-9]$/;
18
+ function isValidFailureKey(key) {
19
+ return KEY_RE.test(key) && !key.includes("--");
20
+ }
21
+ function cleanLine(s, max = 200) {
22
+ const cleaned = s.replace(/[\u0000-\u001f\u007f]/g, " ").replace(/\s+/g, " ").trim();
23
+ return cleaned.length > max ? cleaned.slice(0, max - 1) + "\u2026" : cleaned;
24
+ }
25
+ function cleanToken(s, fallback, max = 40) {
26
+ if (!s)
27
+ return fallback;
28
+ const t = cleanLine(s, max).toLowerCase().replace(/[^a-z0-9_-]/g, "");
29
+ return t.length > 0 ? t : fallback;
30
+ }
31
+ function pad2(n) {
32
+ return String(n).padStart(2, "0");
33
+ }
34
+ function ordinal(n) {
35
+ const mod100 = n % 100;
36
+ if (mod100 >= 11 && mod100 <= 13)
37
+ return `${n}th`;
38
+ switch (n % 10) {
39
+ case 1:
40
+ return `${n}st`;
41
+ case 2:
42
+ return `${n}nd`;
43
+ case 3:
44
+ return `${n}rd`;
45
+ default:
46
+ return `${n}th`;
47
+ }
48
+ }
49
+ function isoDate(d) {
50
+ return `${d.getFullYear()}-${pad2(d.getMonth() + 1)}-${pad2(d.getDate())}`;
51
+ }
52
+ async function recordFailure(dataDir, input, now = /* @__PURE__ */ new Date()) {
53
+ const key = (input.key ?? "").trim().toLowerCase();
54
+ if (!isValidFailureKey(key)) {
55
+ throw new Error(`invalid recurrence key ${JSON.stringify(input.key)} \u2014 use stable kebab-case ([a-z0-9-], 3..64 chars), named after the ROOT CAUSE so repeats share the key.`);
56
+ }
57
+ const what = cleanLine(input.what ?? "");
58
+ if (!what) {
59
+ throw new Error("`--what` is required \u2014 one line describing what failed.");
60
+ }
61
+ const signal = cleanToken(input.signal, "self_detected");
62
+ const severity = cleanToken(input.severity, "medium");
63
+ const rule = input.rule ? cleanToken(input.rule, "", 80) : "";
64
+ const evidence = (input.evidence ?? []).map((e) => cleanLine(e, 300)).filter((e) => e.length > 0);
65
+ const dir = join(dataDir, FAILURES_DIR);
66
+ await mkdir(dir, { recursive: true });
67
+ const date = isoDate(now);
68
+ const hhmm = `${pad2(now.getHours())}${pad2(now.getMinutes())}`;
69
+ const fmLines = [
70
+ "---",
71
+ "type: failure",
72
+ `recurrence_key: ${key}`,
73
+ `signal: ${signal}`,
74
+ `severity: ${severity}`,
75
+ "status: open",
76
+ `created: ${date}`,
77
+ ...rule ? [`rule: ${rule}`] : [],
78
+ "---",
79
+ "",
80
+ `# ${what}`,
81
+ ""
82
+ ];
83
+ if (evidence.length > 0) {
84
+ fmLines.push("## Evidence", "");
85
+ for (const e of evidence)
86
+ fmLines.push(`- ${e}`);
87
+ fmLines.push("");
88
+ }
89
+ let name = "";
90
+ let path = "";
91
+ for (let i = 1; ; i++) {
92
+ name = i === 1 ? `${date}_${hhmm}-${key}.md` : `${date}_${hhmm}-${key}-${i}.md`;
93
+ path = join(dir, name);
94
+ try {
95
+ await writeFile(path, fmLines.join("\n"), { encoding: "utf8", flag: "wx" });
96
+ break;
97
+ } catch (e) {
98
+ if (e.code !== "EEXIST" || i >= 99)
99
+ throw e;
100
+ }
101
+ }
102
+ const scan = await scanFailures(dataDir);
103
+ const group = scan.groups.find((g) => g.key === key);
104
+ const count = group?.count ?? 1;
105
+ const stage = ladderStage(count);
106
+ const note = stage === "promote" ? `${ordinal(count)} open occurrence of "${key}" \u2014 ladder stage PROMOTE: propose a deterministic guard to the user (hook / pre-commit / wrapper). Never self-install.` : stage === "gate" ? group?.rule ? `2nd open occurrence of "${key}" \u2014 ladder stage GATE: the covering rule's write-time gate is now mandatory (rule: ${group.rule}).` : `2nd open occurrence of "${key}" \u2014 recurring with no covering rule named yet: link one with --rule, or propose a new memory rule, before this escalates further.` : `first open occurrence of "${key}" recorded.`;
107
+ return { path, relPath: `${FAILURES_DIR}/${name}`, key, count, stage, note };
108
+ }
109
+ var MAX_SCAN_ENTRIES = 2e3;
110
+ var MAX_ENTRY_BYTES = 64 * 1024;
111
+ async function scanFailures(dataDir) {
112
+ const dir = join(dataDir, FAILURES_DIR);
113
+ if (!existsSync(dir))
114
+ return { groups: [], totalOpen: 0, totalResolved: 0 };
115
+ let names;
116
+ try {
117
+ names = (await readdir(dir)).filter((n) => n.endsWith(".md") && !n.startsWith("_")).sort((a, b) => b.localeCompare(a)).slice(0, MAX_SCAN_ENTRIES);
118
+ } catch {
119
+ return { groups: [], totalOpen: 0, totalResolved: 0 };
120
+ }
121
+ const entries = [];
122
+ let resolved = 0;
123
+ for (const name of names) {
124
+ try {
125
+ if ((await stat(join(dir, name))).size > MAX_ENTRY_BYTES)
126
+ continue;
127
+ const raw = await readFile(join(dir, name), "utf8");
128
+ const fm = parseFrontmatter(raw)?.frontmatter;
129
+ const key = typeof fm?.recurrence_key === "string" ? fm.recurrence_key.trim().toLowerCase() : "";
130
+ if (!isValidFailureKey(key))
131
+ continue;
132
+ const statusRaw = typeof fm?.status === "string" ? fm.status.trim().toLowerCase() : "open";
133
+ const status = statusRaw === "resolved" ? "resolved" : "open";
134
+ if (status === "resolved") {
135
+ resolved++;
136
+ continue;
137
+ }
138
+ const title = cleanLine(raw.split(/\r?\n/).find((l) => l.startsWith("# "))?.slice(2) ?? name, 120);
139
+ const created = typeof fm?.created === "string" ? fm.created.trim() : "";
140
+ const date = /^\d{4}-\d{2}-\d{2}/.test(created) ? created.slice(0, 10) : name.match(/^(\d{4}-\d{2}-\d{2})/)?.[1] ?? "";
141
+ entries.push({
142
+ relPath: `${FAILURES_DIR}/${name}`,
143
+ key,
144
+ title,
145
+ signal: cleanToken(typeof fm?.signal === "string" ? fm.signal : void 0, "self_detected"),
146
+ severity: cleanToken(typeof fm?.severity === "string" ? fm.severity : void 0, "medium"),
147
+ status,
148
+ date,
149
+ rule: typeof fm?.rule === "string" && fm.rule.trim() ? cleanToken(fm.rule, "", 80) || null : null
150
+ });
151
+ } catch {
152
+ }
153
+ }
154
+ const byKey = /* @__PURE__ */ new Map();
155
+ for (const e of entries) {
156
+ const list = byKey.get(e.key) ?? [];
157
+ list.push(e);
158
+ byKey.set(e.key, list);
159
+ }
160
+ const groups = [...byKey.entries()].map(([key, list]) => {
161
+ const sorted = [...list].sort((a, b) => a.relPath.localeCompare(b.relPath));
162
+ return {
163
+ key,
164
+ count: sorted.length,
165
+ stage: ladderStage(sorted.length),
166
+ lastDate: sorted[sorted.length - 1].date,
167
+ rule: sorted.find((e) => e.rule)?.rule ?? null,
168
+ titles: sorted.map((e) => e.title),
169
+ entries: sorted
170
+ };
171
+ });
172
+ groups.sort((a, b) => b.count - a.count || b.lastDate.localeCompare(a.lastDate) || a.key.localeCompare(b.key));
173
+ return { groups, totalOpen: entries.length, totalResolved: resolved };
174
+ }
175
+ var MAX_REPORT_WARNINGS = 4;
176
+ function failureReportSlice(scan) {
177
+ const hot = scan.groups.filter((g) => g.count >= 2);
178
+ return {
179
+ warnings: hot.slice(0, MAX_REPORT_WARNINGS).map((g) => ({
180
+ key: g.key,
181
+ count: g.count,
182
+ stage: g.stage,
183
+ rule: g.rule,
184
+ lastDate: g.lastDate
185
+ })),
186
+ totalOpen: scan.totalOpen,
187
+ omitted: Math.max(0, hot.length - MAX_REPORT_WARNINGS)
188
+ };
189
+ }
190
+ var GUARD_DENIAL_KEY = "literal-control-bytes";
191
+ var GUARD_DEDUP_MINUTES = 10;
192
+ async function recordGuardDenial(dataDir, what, now = /* @__PURE__ */ new Date()) {
193
+ try {
194
+ const dir = join(dataDir, FAILURES_DIR);
195
+ if (existsSync(dir)) {
196
+ const names = (await readdir(dir)).filter((n) => n.endsWith(".md") && n.includes(`-${GUARD_DENIAL_KEY}`));
197
+ for (const n of names) {
198
+ const m = n.match(/^(\d{4})-(\d{2})-(\d{2})_(\d{2})(\d{2})/);
199
+ if (!m)
200
+ continue;
201
+ const t = new Date(+m[1], +m[2] - 1, +m[3], +m[4], +m[5]);
202
+ if (Math.abs(now.getTime() - t.getTime()) < GUARD_DEDUP_MINUTES * 6e4) {
203
+ return null;
204
+ }
205
+ }
206
+ }
207
+ return await recordFailure(dataDir, { key: GUARD_DENIAL_KEY, what, signal: "guard_denied" }, now);
208
+ } catch {
209
+ return null;
210
+ }
211
+ }
212
+ function parseRecordArgs(args) {
213
+ let key = "";
214
+ let what = "";
215
+ let signal;
216
+ let severity;
217
+ let rule;
218
+ const evidence = [];
219
+ for (let i = 0; i < args.length; i++) {
220
+ const t = args[i];
221
+ const next = () => {
222
+ if (i + 1 >= args.length)
223
+ throw new Error(`missing value after ${t}`);
224
+ return args[++i];
225
+ };
226
+ switch (t) {
227
+ case "--key":
228
+ key = next();
229
+ break;
230
+ case "--what":
231
+ what = next();
232
+ break;
233
+ case "--signal":
234
+ signal = next();
235
+ break;
236
+ case "--severity":
237
+ severity = next();
238
+ break;
239
+ case "--rule":
240
+ rule = next();
241
+ break;
242
+ case "--evidence":
243
+ evidence.push(next());
244
+ break;
245
+ default:
246
+ throw new Error(`unknown flag ${JSON.stringify(t)} \u2014 see \`vortex failure\` usage.`);
247
+ }
248
+ }
249
+ return { key, what, signal, severity, rule, evidence };
250
+ }
251
+ var FAILURE_USAGE = '[vortex] failure \u2014 the failure ledger (data/_failures/), evidence store of the self-improvement loop.\n vortex failure record --key <root-cause-kebab-key> --what "<one line>"\n [--signal user_pushback|tool_error|test_failure|cross_check_miss|guard_denied|self_detected]\n [--severity low|medium|high] [--rule <memory-slug>] [--evidence <path-or-link>]...\n vortex failure list \u2014 open groups by recurrence key with ladder stage (recorded \u2192 gate \u2192 promote)\n';
252
+ async function runFailureCli(argv, dataDir, out, err) {
253
+ const sub = argv[0];
254
+ if (sub === "record") {
255
+ const input = parseRecordArgs(argv.slice(1));
256
+ const result = await recordFailure(dataDir, input);
257
+ out(JSON.stringify(result, null, 2) + "\n");
258
+ return 0;
259
+ }
260
+ if (sub === "list") {
261
+ const scan = await scanFailures(dataDir);
262
+ const view = {
263
+ totalOpen: scan.totalOpen,
264
+ totalResolved: scan.totalResolved,
265
+ groups: scan.groups.map((g) => ({
266
+ key: g.key,
267
+ count: g.count,
268
+ stage: g.stage,
269
+ lastDate: g.lastDate,
270
+ rule: g.rule,
271
+ entries: g.entries.map((e) => ({ relPath: e.relPath, date: e.date, title: e.title, signal: e.signal, severity: e.severity }))
272
+ }))
273
+ };
274
+ out(JSON.stringify(view, null, 2) + "\n");
275
+ return 0;
276
+ }
277
+ err(FAILURE_USAGE);
278
+ return sub === void 0 || sub === "--help" ? 0 : 1;
279
+ }
280
+
281
+ export {
282
+ FAILURES_DIR,
283
+ ladderStage,
284
+ isValidFailureKey,
285
+ recordFailure,
286
+ scanFailures,
287
+ failureReportSlice,
288
+ GUARD_DENIAL_KEY,
289
+ recordGuardDenial,
290
+ runFailureCli
291
+ };
292
+ //# sourceMappingURL=chunk-UV76ZEDC.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../plugins/session-rituals/src/failures.ts"],"sourcesContent":["/**\n * Failure ledger (`data/_failures/`) — the evidence store of the\n * self-improvement loop.\n *\n * The problem this solves: behavioral rules live in `data/_memory/`, but a rule\n * loaded at session start is *passive knowledge* — at action time the model's\n * active context is full of the task and the rule slips. The documented result\n * is the same failure recurring despite a registered rule. The fix is not\n * another rule; it is a LEDGER that makes recurrence countable by a machine,\n * plus an escalation ladder that turns counts into stronger defenses:\n *\n * 1st occurrence → record (append-only file, one per occurrence)\n * 2nd (rule held) → the rule's write-time gate becomes MANDATORY\n * 3rd+ → propose promoting to a deterministic guard (hook /\n * pre-commit / wrapper) — always a PROPOSAL; the user\n * approves, nothing self-installs\n *\n * Design notes:\n * - One markdown file per occurrence (`YYYY-MM-DD_HHMM-<key>.md`), frontmatter\n * carries the machine-read fields; the body is for humans. Append-only —\n * resolving a pattern flips `status` on its entries, never deletes.\n * - `recurrence_key` is the grouping identity: a stable kebab-case name for\n * the ROOT CAUSE (e.g. `literal-control-bytes`), not the symptom of the day.\n * Same cause → same key, that is what makes counting honest.\n * - Recording is an agent ritual (auto, append-only, one-line note to the\n * user — AI-RULES \"Default behaviors\"); deterministic guards may also append\n * here directly so counting never depends on the failing agent noticing.\n * - The session-start report surfaces groups at 2+ open occurrences with their\n * ladder stage, so escalation never depends on human memory either.\n */\n\nimport { mkdir, readdir, readFile, stat, writeFile } from \"node:fs/promises\";\nimport { existsSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { parseFrontmatter } from \"@vortex-os/core\";\n\n/** Directory name under `data/` holding the ledger. */\nexport const FAILURES_DIR = \"_failures\";\n\n/** Ladder stages by open-occurrence count. */\nexport type LadderStage = \"recorded\" | \"gate\" | \"promote\";\n\n/** Stage for a given open-occurrence count (1 → recorded, 2 → gate, 3+ → promote). */\nexport function ladderStage(count: number): LadderStage {\n if (count >= 3) return \"promote\";\n if (count === 2) return \"gate\";\n return \"recorded\";\n}\n\n/** One ledger entry (one occurrence), as read back from disk. */\nexport interface FailureEntry {\n /** Path relative to the data dir (`_failures/2026-06-11_0210-….md`). */\n readonly relPath: string;\n readonly key: string;\n readonly title: string;\n readonly signal: string;\n readonly severity: string;\n readonly status: \"open\" | \"resolved\";\n /** `YYYY-MM-DD` from frontmatter `created` (falls back to the filename). */\n readonly date: string;\n /** Related rule (memory slug) named at record time, or null. */\n readonly rule: string | null;\n}\n\n/** All occurrences sharing a recurrence key, with the derived ladder stage. */\nexport interface FailureGroup {\n readonly key: string;\n /** OPEN occurrences only — resolved history no longer escalates. */\n readonly count: number;\n readonly stage: LadderStage;\n readonly lastDate: string;\n /** First non-null rule named across the group's entries. */\n readonly rule: string | null;\n readonly titles: readonly string[];\n readonly entries: readonly FailureEntry[];\n}\n\nexport interface FailureScan {\n /** Open groups, most occurrences first (ties: most recent first). */\n readonly groups: readonly FailureGroup[];\n readonly totalOpen: number;\n readonly totalResolved: number;\n}\n\nexport interface RecordFailureInput {\n /** Stable kebab-case root-cause key (`[a-z0-9-]`, 3..64 chars). */\n readonly key: string;\n /** One-line description of what happened. */\n readonly what: string;\n /** Signal class — free short token; conventional values: user_pushback, tool_error, test_failure, cross_check_miss, guard_denied, self_detected. */\n readonly signal?: string;\n /** low | medium | high (free token, those are the conventional values). */\n readonly severity?: string;\n /** Memory slug of the rule that already covered this (if any). */\n readonly rule?: string;\n /** Evidence pointers (paths, links) — recorded as a list in the body. */\n readonly evidence?: readonly string[];\n}\n\nexport interface RecordFailureResult {\n readonly path: string;\n readonly relPath: string;\n readonly key: string;\n /** Open occurrences for this key AFTER this record (i.e. includes it). */\n readonly count: number;\n readonly stage: LadderStage;\n /** Agent-facing one-liner explaining the ladder consequence of this count. */\n readonly note: string;\n}\n\nconst KEY_RE = /^[a-z0-9][a-z0-9-]{1,62}[a-z0-9]$/;\n\n/** Validate a recurrence key: stable kebab-case, filename-safe by construction. */\nexport function isValidFailureKey(key: string): boolean {\n return KEY_RE.test(key) && !key.includes(\"--\");\n}\n\n/** Strip control chars / newlines and collapse whitespace so a value can sit in frontmatter or a filename-adjacent field. */\nfunction cleanLine(s: string, max = 200): string {\n // eslint-disable-next-line no-control-regex\n const cleaned = s.replace(/[\\u0000-\\u001f\\u007f]/g, \" \").replace(/\\s+/g, \" \").trim();\n return cleaned.length > max ? cleaned.slice(0, max - 1) + \"…\" : cleaned;\n}\n\n/** Conservative token cleaner for signal/severity/rule fields. */\nfunction cleanToken(s: string | undefined, fallback: string, max = 40): string {\n if (!s) return fallback;\n const t = cleanLine(s, max).toLowerCase().replace(/[^a-z0-9_-]/g, \"\");\n return t.length > 0 ? t : fallback;\n}\n\nfunction pad2(n: number): string {\n return String(n).padStart(2, \"0\");\n}\n\n/** English ordinal (1st/2nd/3rd/4th…, teens stay -th). */\nfunction ordinal(n: number): string {\n const mod100 = n % 100;\n if (mod100 >= 11 && mod100 <= 13) return `${n}th`;\n switch (n % 10) {\n case 1: return `${n}st`;\n case 2: return `${n}nd`;\n case 3: return `${n}rd`;\n default: return `${n}th`;\n }\n}\n\nfunction isoDate(d: Date): string {\n return `${d.getFullYear()}-${pad2(d.getMonth() + 1)}-${pad2(d.getDate())}`;\n}\n\n/**\n * Append one occurrence to the ledger. Creates `data/_failures/` on first use.\n * Never overwrites: a same-minute collision for the same key gets a numeric\n * suffix. Returns the post-write open count + ladder stage for the key so the\n * caller (agent) can relay \"this is the Nth time\" in its one-line note.\n */\nexport async function recordFailure(\n dataDir: string,\n input: RecordFailureInput,\n now: Date = new Date(),\n): Promise<RecordFailureResult> {\n const key = (input.key ?? \"\").trim().toLowerCase();\n if (!isValidFailureKey(key)) {\n throw new Error(\n `invalid recurrence key ${JSON.stringify(input.key)} — use stable kebab-case ([a-z0-9-], 3..64 chars), named after the ROOT CAUSE so repeats share the key.`,\n );\n }\n const what = cleanLine(input.what ?? \"\");\n if (!what) {\n throw new Error(\"`--what` is required — one line describing what failed.\");\n }\n const signal = cleanToken(input.signal, \"self_detected\");\n const severity = cleanToken(input.severity, \"medium\");\n const rule = input.rule ? cleanToken(input.rule, \"\", 80) : \"\";\n const evidence = (input.evidence ?? []).map((e) => cleanLine(e, 300)).filter((e) => e.length > 0);\n\n const dir = join(dataDir, FAILURES_DIR);\n await mkdir(dir, { recursive: true });\n\n const date = isoDate(now);\n const hhmm = `${pad2(now.getHours())}${pad2(now.getMinutes())}`;\n\n const fmLines = [\n \"---\",\n \"type: failure\",\n `recurrence_key: ${key}`,\n `signal: ${signal}`,\n `severity: ${severity}`,\n \"status: open\",\n `created: ${date}`,\n ...(rule ? [`rule: ${rule}`] : []),\n \"---\",\n \"\",\n `# ${what}`,\n \"\",\n ];\n if (evidence.length > 0) {\n fmLines.push(\"## Evidence\", \"\");\n for (const e of evidence) fmLines.push(`- ${e}`);\n fmLines.push(\"\");\n }\n\n // Exclusive create (`wx`) with a suffix-retry loop: two same-minute records\n // can race past an exists-check, so the CHECK IS the write — EEXIST never\n // overwrites, it just moves to the next suffix.\n let name = \"\";\n let path = \"\";\n for (let i = 1; ; i++) {\n name = i === 1 ? `${date}_${hhmm}-${key}.md` : `${date}_${hhmm}-${key}-${i}.md`;\n path = join(dir, name);\n try {\n await writeFile(path, fmLines.join(\"\\n\"), { encoding: \"utf8\", flag: \"wx\" });\n break;\n } catch (e) {\n if ((e as NodeJS.ErrnoException).code !== \"EEXIST\" || i >= 99) throw e;\n }\n }\n\n const scan = await scanFailures(dataDir);\n const group = scan.groups.find((g) => g.key === key);\n const count = group?.count ?? 1;\n const stage = ladderStage(count);\n const note =\n stage === \"promote\"\n ? `${ordinal(count)} open occurrence of \"${key}\" — ladder stage PROMOTE: propose a deterministic guard to the user (hook / pre-commit / wrapper). Never self-install.`\n : stage === \"gate\"\n ? group?.rule\n ? `2nd open occurrence of \"${key}\" — ladder stage GATE: the covering rule's write-time gate is now mandatory (rule: ${group.rule}).`\n : `2nd open occurrence of \"${key}\" — recurring with no covering rule named yet: link one with --rule, or propose a new memory rule, before this escalates further.`\n : `first open occurrence of \"${key}\" recorded.`;\n return { path, relPath: `${FAILURES_DIR}/${name}`, key, count, stage, note };\n}\n\n/**\n * Read the whole ledger and group open occurrences by recurrence key.\n * Tolerant by design: a malformed file is skipped (the ledger must never make\n * session start fail), and an empty/missing directory is an empty scan.\n */\n/** Scan bounds: the session-start hook runs this — a huge ledger must not slow it. */\nconst MAX_SCAN_ENTRIES = 2000;\nconst MAX_ENTRY_BYTES = 64 * 1024;\n\nexport async function scanFailures(dataDir: string): Promise<FailureScan> {\n const dir = join(dataDir, FAILURES_DIR);\n if (!existsSync(dir)) return { groups: [], totalOpen: 0, totalResolved: 0 };\n\n let names: string[];\n try {\n // Newest first BEFORE the cap (filenames sort chronologically), so a huge\n // ledger drops the oldest entries — never the current recurrence or the\n // entry recordFailure() just wrote.\n names = (await readdir(dir))\n .filter((n) => n.endsWith(\".md\") && !n.startsWith(\"_\"))\n .sort((a, b) => b.localeCompare(a))\n .slice(0, MAX_SCAN_ENTRIES);\n } catch {\n return { groups: [], totalOpen: 0, totalResolved: 0 };\n }\n\n const entries: FailureEntry[] = [];\n let resolved = 0;\n for (const name of names) {\n try {\n if ((await stat(join(dir, name))).size > MAX_ENTRY_BYTES) continue; // not a ledger entry\n const raw = await readFile(join(dir, name), \"utf8\");\n const fm = parseFrontmatter(raw)?.frontmatter as Record<string, unknown> | undefined;\n const key = typeof fm?.recurrence_key === \"string\" ? fm.recurrence_key.trim().toLowerCase() : \"\";\n if (!isValidFailureKey(key)) continue;\n const statusRaw = typeof fm?.status === \"string\" ? fm.status.trim().toLowerCase() : \"open\";\n const status: FailureEntry[\"status\"] = statusRaw === \"resolved\" ? \"resolved\" : \"open\";\n if (status === \"resolved\") {\n resolved++;\n continue;\n }\n const title = cleanLine(raw.split(/\\r?\\n/).find((l) => l.startsWith(\"# \"))?.slice(2) ?? name, 120);\n const created = typeof fm?.created === \"string\" ? fm.created.trim() : \"\";\n const date = /^\\d{4}-\\d{2}-\\d{2}/.test(created) ? created.slice(0, 10) : (name.match(/^(\\d{4}-\\d{2}-\\d{2})/)?.[1] ?? \"\");\n entries.push({\n relPath: `${FAILURES_DIR}/${name}`,\n key,\n title,\n signal: cleanToken(typeof fm?.signal === \"string\" ? fm.signal : undefined, \"self_detected\"),\n severity: cleanToken(typeof fm?.severity === \"string\" ? fm.severity : undefined, \"medium\"),\n status,\n date,\n rule: typeof fm?.rule === \"string\" && fm.rule.trim() ? cleanToken(fm.rule, \"\", 80) || null : null,\n });\n } catch {\n // unreadable entry — skip; the ledger stays best-effort readable\n }\n }\n\n const byKey = new Map<string, FailureEntry[]>();\n for (const e of entries) {\n const list = byKey.get(e.key) ?? [];\n list.push(e);\n byKey.set(e.key, list);\n }\n const groups: FailureGroup[] = [...byKey.entries()].map(([key, list]) => {\n const sorted = [...list].sort((a, b) => a.relPath.localeCompare(b.relPath));\n return {\n key,\n count: sorted.length,\n stage: ladderStage(sorted.length),\n lastDate: sorted[sorted.length - 1]!.date,\n rule: sorted.find((e) => e.rule)?.rule ?? null,\n titles: sorted.map((e) => e.title),\n entries: sorted,\n };\n });\n groups.sort((a, b) => b.count - a.count || b.lastDate.localeCompare(a.lastDate) || a.key.localeCompare(b.key));\n return { groups, totalOpen: entries.length, totalResolved: resolved };\n}\n\n/** Compact, report-ready view: groups needing attention (2+ open occurrences). */\nexport interface FailureReportSlice {\n readonly warnings: readonly {\n readonly key: string;\n readonly count: number;\n readonly stage: LadderStage;\n readonly rule: string | null;\n readonly lastDate: string;\n }[];\n readonly totalOpen: number;\n readonly omitted: number;\n}\n\nconst MAX_REPORT_WARNINGS = 4;\n\n/** Slice a scan down to what the session-start report shows (stage gate/promote only, capped). */\nexport function failureReportSlice(scan: FailureScan): FailureReportSlice {\n const hot = scan.groups.filter((g) => g.count >= 2);\n return {\n warnings: hot.slice(0, MAX_REPORT_WARNINGS).map((g) => ({\n key: g.key,\n count: g.count,\n stage: g.stage,\n rule: g.rule,\n lastDate: g.lastDate,\n })),\n totalOpen: scan.totalOpen,\n omitted: Math.max(0, hot.length - MAX_REPORT_WARNINGS),\n };\n}\n\n// ---------------------------------------------------------------------------\n// Guard-originated entries — deterministic denials record themselves.\n// ---------------------------------------------------------------------------\n\n/** The fixed recurrence key for write-guard denials (one failure class → one key). */\nexport const GUARD_DENIAL_KEY = \"literal-control-bytes\";\n\n/** Denials within this window count as ONE incident (the model retrying), not new occurrences. */\nconst GUARD_DEDUP_MINUTES = 10;\n\n/**\n * Record a write-guard denial into the ledger — called by the guard itself, so\n * counting NEVER depends on the failing agent noticing and self-reporting\n * (the documented stall mode of self-report-only ledgers). Best-effort and\n * silent: returns null when skipped (recent same-incident entry, or any\n * error) — a ledger problem must never affect the deny itself.\n */\nexport async function recordGuardDenial(\n dataDir: string,\n what: string,\n now: Date = new Date(),\n): Promise<RecordFailureResult | null> {\n try {\n const dir = join(dataDir, FAILURES_DIR);\n if (existsSync(dir)) {\n const names = (await readdir(dir)).filter(\n (n) => n.endsWith(\".md\") && n.includes(`-${GUARD_DENIAL_KEY}`),\n );\n for (const n of names) {\n const m = n.match(/^(\\d{4})-(\\d{2})-(\\d{2})_(\\d{2})(\\d{2})/);\n if (!m) continue;\n const t = new Date(+m[1]!, +m[2]! - 1, +m[3]!, +m[4]!, +m[5]!);\n if (Math.abs(now.getTime() - t.getTime()) < GUARD_DEDUP_MINUTES * 60_000) {\n return null; // same incident, retried — already counted\n }\n }\n }\n return await recordFailure(\n dataDir,\n { key: GUARD_DENIAL_KEY, what, signal: \"guard_denied\" },\n now,\n );\n } catch {\n return null;\n }\n}\n\n// ---------------------------------------------------------------------------\n// CLI entry — `vortex failure record|list`\n// ---------------------------------------------------------------------------\n\n/** Parse `--flag value` argv into the record input (`--evidence` repeats). */\nfunction parseRecordArgs(args: readonly string[]): RecordFailureInput {\n let key = \"\";\n let what = \"\";\n let signal: string | undefined;\n let severity: string | undefined;\n let rule: string | undefined;\n const evidence: string[] = [];\n for (let i = 0; i < args.length; i++) {\n const t = args[i]!;\n const next = (): string => {\n if (i + 1 >= args.length) throw new Error(`missing value after ${t}`);\n return args[++i]!;\n };\n switch (t) {\n case \"--key\":\n key = next();\n break;\n case \"--what\":\n what = next();\n break;\n case \"--signal\":\n signal = next();\n break;\n case \"--severity\":\n severity = next();\n break;\n case \"--rule\":\n rule = next();\n break;\n case \"--evidence\":\n evidence.push(next());\n break;\n default:\n throw new Error(`unknown flag ${JSON.stringify(t)} — see \\`vortex failure\\` usage.`);\n }\n }\n return { key, what, signal, severity, rule, evidence };\n}\n\nconst FAILURE_USAGE =\n \"[vortex] failure — the failure ledger (data/_failures/), evidence store of the self-improvement loop.\\n\" +\n \" vortex failure record --key <root-cause-kebab-key> --what \\\"<one line>\\\"\\n\" +\n \" [--signal user_pushback|tool_error|test_failure|cross_check_miss|guard_denied|self_detected]\\n\" +\n \" [--severity low|medium|high] [--rule <memory-slug>] [--evidence <path-or-link>]...\\n\" +\n \" vortex failure list — open groups by recurrence key with ladder stage (recorded → gate → promote)\\n\";\n\n/**\n * Run the failure-ledger CLI. `record` appends one occurrence and reports the\n * post-write count + ladder stage (so the agent can relay \"Nth time\"); `list`\n * prints the grouped open ledger. Results are JSON on stdout.\n */\nexport async function runFailureCli(\n argv: readonly string[],\n dataDir: string,\n out: (s: string) => void,\n err: (s: string) => void,\n): Promise<number> {\n const sub = argv[0];\n if (sub === \"record\") {\n const input = parseRecordArgs(argv.slice(1));\n const result = await recordFailure(dataDir, input);\n out(JSON.stringify(result, null, 2) + \"\\n\");\n return 0;\n }\n if (sub === \"list\") {\n const scan = await scanFailures(dataDir);\n const view = {\n totalOpen: scan.totalOpen,\n totalResolved: scan.totalResolved,\n groups: scan.groups.map((g) => ({\n key: g.key,\n count: g.count,\n stage: g.stage,\n lastDate: g.lastDate,\n rule: g.rule,\n entries: g.entries.map((e) => ({ relPath: e.relPath, date: e.date, title: e.title, signal: e.signal, severity: e.severity })),\n })),\n };\n out(JSON.stringify(view, null, 2) + \"\\n\");\n return 0;\n }\n err(FAILURE_USAGE);\n return sub === undefined || sub === \"--help\" ? 0 : 1;\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,25 @@
1
+ import {
2
+ FAILURES_DIR,
3
+ GUARD_DENIAL_KEY,
4
+ failureReportSlice,
5
+ isValidFailureKey,
6
+ ladderStage,
7
+ recordFailure,
8
+ recordGuardDenial,
9
+ runFailureCli,
10
+ scanFailures
11
+ } from "./chunk-UV76ZEDC.js";
12
+ import "./chunk-T53UWSTR.js";
13
+ import "./chunk-PZ5AY32C.js";
14
+ export {
15
+ FAILURES_DIR,
16
+ GUARD_DENIAL_KEY,
17
+ failureReportSlice,
18
+ isValidFailureKey,
19
+ ladderStage,
20
+ recordFailure,
21
+ recordGuardDenial,
22
+ runFailureCli,
23
+ scanFailures
24
+ };
25
+ //# sourceMappingURL=failures-PMURLMVB.js.map
@@ -0,0 +1,23 @@
1
+ import {
2
+ GUARD_WRITE_COMMAND,
3
+ GUARD_WRITE_MATCHER,
4
+ buildDenyDecision,
5
+ findControlChar,
6
+ guardWriteDecision,
7
+ resolveInstanceRoot,
8
+ runGuardCli,
9
+ scanToolInput
10
+ } from "./chunk-2FVNWW77.js";
11
+ import "./chunk-T53UWSTR.js";
12
+ import "./chunk-PZ5AY32C.js";
13
+ export {
14
+ GUARD_WRITE_COMMAND,
15
+ GUARD_WRITE_MATCHER,
16
+ buildDenyDecision,
17
+ findControlChar,
18
+ guardWriteDecision,
19
+ resolveInstanceRoot,
20
+ runGuardCli,
21
+ scanToolInput
22
+ };
23
+ //# sourceMappingURL=guard-IMJR6ET7.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}