@dzhechkov/keysarium 1.5.39 → 1.5.41

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/.dz-manifest.json CHANGED
@@ -3,17 +3,9 @@
3
3
  "version": 1,
4
4
  "pack": "keysarium",
5
5
  "files": [
6
- {
7
- "path": ".npmignore",
8
- "sha256": "9317ffe4ed40056088019932546f9c61314dc12771936facac6c1a223850ba1a"
9
- },
10
- {
11
- "path": "CHANGELOG.md",
12
- "sha256": "eea09507de22a829358a02a818a62767d36addeb585ec42a29d3ada8be2e3f7f"
13
- },
14
6
  {
15
7
  "path": "README.md",
16
- "sha256": "546283f9b70fe63fbe404fc80bd78e66c898522dfcbf10efb684f13f4a89a77d"
8
+ "sha256": "55a9e601a7028333e77dd2ee0f8eec201f053cd970deb8f58ecfa7cf06987cf4"
17
9
  },
18
10
  {
19
11
  "path": "README.ru.md",
@@ -23,21 +15,9 @@
23
15
  "path": "bin/cli.js",
24
16
  "sha256": "a210174d6b63d053f7744757972d31acb0f4d9c59f8dacff7b62872a19ebd31a"
25
17
  },
26
- {
27
- "path": "install.sh",
28
- "sha256": "9631575645f93ca8a65aa2f346da7253cd6ffa6394e36c13a2bf0d7eb605387f"
29
- },
30
18
  {
31
19
  "path": "package.json",
32
- "sha256": "6e7bd27dbde362b7a252abca1ce6fb6412798af0160a88ed4cbd0ddf106e58c8"
33
- },
34
- {
35
- "path": "scripts/sync-templates.js",
36
- "sha256": "2dbbe71d5454c5be20c4460330b7b3ec77dc78d498d99d7226fe474ed2fd1101"
37
- },
38
- {
39
- "path": "sources.json",
40
- "sha256": "e36d98d8438c8ef9bc872843aeabc087c8b7a9fc52ed5a50568d28306d26b876"
20
+ "sha256": "9371c3fe3922382a7871224941fb0bae838dfcbeb750bd55a662e4c27a1e1af7"
41
21
  },
42
22
  {
43
23
  "path": "src/cli.js",
@@ -365,7 +345,7 @@
365
345
  },
366
346
  {
367
347
  "path": "templates/.claude/skills/feature-adr/SKILL.md",
368
- "sha256": "bdedfed69d985eb6969f158a72d92f63c6b1b993008c3661f7ffc2c6a7ccfbae"
348
+ "sha256": "67eb730c815e6b8f9b9b61084c67ceb85440548f00b21f52187d16e81e3d7af8"
369
349
  },
370
350
  {
371
351
  "path": "templates/.claude/skills/feature-adr/examples/sample-feature-output.md",
@@ -401,7 +381,7 @@
401
381
  },
402
382
  {
403
383
  "path": "templates/.claude/skills/feature-adr/modules/06-implementation-plan.md",
404
- "sha256": "3903e2694ad47782914b35869bbf19c5f0803b6dafdcfb629df343a5ff00d1b9"
384
+ "sha256": "b3efdfa1d44f4c51ff46551b5827066955c1f0bfee212d371ac1e2fb1c99980f"
405
385
  },
406
386
  {
407
387
  "path": "templates/.claude/skills/feature-adr/modules/07-code.md",
@@ -501,7 +481,7 @@
501
481
  },
502
482
  {
503
483
  "path": "templates/.claude/skills/feature-adr/scripts/check-plan-completeness.mjs",
504
- "sha256": "2e1afeb8cbc08ce872fc8280a0809e7712ee76879d08b48caa5a0d4082cb8647"
484
+ "sha256": "eddf116620050e80b88497ace026fb8e0a12986f94f216181480c7daa0e08be4"
505
485
  },
506
486
  {
507
487
  "path": "templates/.claude/skills/frontend-design/LICENSE.txt",
@@ -1005,5 +985,5 @@
1005
985
  }
1006
986
  ]
1007
987
  },
1008
- "signature": "XoglxxyxKFLcXDz2N8wZzIPbdDffl6Mo5OQwgXt1cIZT1dmM/xHe/s70VsMxlFUiYTgQwYyxjHctP33tG/P+DA=="
988
+ "signature": "AXc5drN9RLQVp4PK9QbjYylVG4nQruSrJQZV4KPQ2JY3/Xif4oZzOxlUOQ1JA5+HRppGUvGnnMtTN8c35rDkDw=="
1009
989
  }
package/README.md CHANGED
@@ -419,6 +419,12 @@ deliberately excluded — "skeleton first" is nonsense there.
419
419
 
420
420
  ## Status
421
421
 
422
+ `1.5.41` — refreshes the bundled `feature-adr` gate script with the C6 amendment-integrity fix (each
423
+ amendment scoped to its own block; closes a false refusal on markers below the old three-line window
424
+ AND a false pass where a testless amendment borrowed its neighbour's marker). No keysarium behaviour
425
+ changes. See `@dzhechkov/skills-feature-adr@1.5.3`.
426
+
427
+
422
428
  `1.5.38` — a fix to the bundled `feature-adr` gate script in `templates/`, no pipeline change.
423
429
 
424
430
  The bundled K2 plan-completeness gate now tells an **ABSENT** `00_complexity_assessment.md` from a
@@ -427,5 +433,5 @@ carrying no acid table is an honest SKIP. Both used to report as a clean skip, s
427
433
  silently switched itself off whenever Step 0 wrote nothing — MEASURED 2026-08-21, 66 of 199 features
428
434
  carried that file and the last four in a row did not.
429
435
 
430
- `1.5.39` — the bundled `feature-adr` Step-8 module now describes the amendment gate as the command
436
+ `1.5.41` — the bundled `feature-adr` Step-8 module now describes the amendment gate as the command
431
437
  `dz amendment-check` instead of a judgement the reviewer is asked to make. Text only; no pipeline change.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dzhechkov/keysarium",
3
- "version": "1.5.39",
3
+ "version": "1.5.41",
4
4
  "description": "AI Case Research Toolkit for Claude Code — full 7-phase pipeline with feature-adr, dream cycles, background workers, multi-platform support, reward learning, and Cloud.ru AI Factory mapping (--ai-factory flag)",
5
5
  "main": "src/cli.js",
6
6
  "bin": {
@@ -51,5 +51,6 @@
51
51
  },
52
52
  "publishConfig": {
53
53
  "access": "public"
54
- }
54
+ },
55
+ "scripts": {}
55
56
  }
package/sbom.json CHANGED
@@ -9,33 +9,13 @@
9
9
  }
10
10
  },
11
11
  "components": [
12
- {
13
- "type": "file",
14
- "name": ".npmignore",
15
- "hashes": [
16
- {
17
- "alg": "SHA-256",
18
- "content": "9317ffe4ed40056088019932546f9c61314dc12771936facac6c1a223850ba1a"
19
- }
20
- ]
21
- },
22
- {
23
- "type": "file",
24
- "name": "CHANGELOG.md",
25
- "hashes": [
26
- {
27
- "alg": "SHA-256",
28
- "content": "eea09507de22a829358a02a818a62767d36addeb585ec42a29d3ada8be2e3f7f"
29
- }
30
- ]
31
- },
32
12
  {
33
13
  "type": "file",
34
14
  "name": "README.md",
35
15
  "hashes": [
36
16
  {
37
17
  "alg": "SHA-256",
38
- "content": "546283f9b70fe63fbe404fc80bd78e66c898522dfcbf10efb684f13f4a89a77d"
18
+ "content": "55a9e601a7028333e77dd2ee0f8eec201f053cd970deb8f58ecfa7cf06987cf4"
39
19
  }
40
20
  ]
41
21
  },
@@ -59,43 +39,13 @@
59
39
  }
60
40
  ]
61
41
  },
62
- {
63
- "type": "file",
64
- "name": "install.sh",
65
- "hashes": [
66
- {
67
- "alg": "SHA-256",
68
- "content": "9631575645f93ca8a65aa2f346da7253cd6ffa6394e36c13a2bf0d7eb605387f"
69
- }
70
- ]
71
- },
72
42
  {
73
43
  "type": "file",
74
44
  "name": "package.json",
75
45
  "hashes": [
76
46
  {
77
47
  "alg": "SHA-256",
78
- "content": "6e7bd27dbde362b7a252abca1ce6fb6412798af0160a88ed4cbd0ddf106e58c8"
79
- }
80
- ]
81
- },
82
- {
83
- "type": "file",
84
- "name": "scripts/sync-templates.js",
85
- "hashes": [
86
- {
87
- "alg": "SHA-256",
88
- "content": "2dbbe71d5454c5be20c4460330b7b3ec77dc78d498d99d7226fe474ed2fd1101"
89
- }
90
- ]
91
- },
92
- {
93
- "type": "file",
94
- "name": "sources.json",
95
- "hashes": [
96
- {
97
- "alg": "SHA-256",
98
- "content": "e36d98d8438c8ef9bc872843aeabc087c8b7a9fc52ed5a50568d28306d26b876"
48
+ "content": "9371c3fe3922382a7871224941fb0bae838dfcbeb750bd55a662e4c27a1e1af7"
99
49
  }
100
50
  ]
101
51
  },
@@ -915,7 +865,7 @@
915
865
  "hashes": [
916
866
  {
917
867
  "alg": "SHA-256",
918
- "content": "bdedfed69d985eb6969f158a72d92f63c6b1b993008c3661f7ffc2c6a7ccfbae"
868
+ "content": "67eb730c815e6b8f9b9b61084c67ceb85440548f00b21f52187d16e81e3d7af8"
919
869
  }
920
870
  ]
921
871
  },
@@ -1005,7 +955,7 @@
1005
955
  "hashes": [
1006
956
  {
1007
957
  "alg": "SHA-256",
1008
- "content": "3903e2694ad47782914b35869bbf19c5f0803b6dafdcfb629df343a5ff00d1b9"
958
+ "content": "b3efdfa1d44f4c51ff46551b5827066955c1f0bfee212d371ac1e2fb1c99980f"
1009
959
  }
1010
960
  ]
1011
961
  },
@@ -1255,7 +1205,7 @@
1255
1205
  "hashes": [
1256
1206
  {
1257
1207
  "alg": "SHA-256",
1258
- "content": "2e1afeb8cbc08ce872fc8280a0809e7712ee76879d08b48caa5a0d4082cb8647"
1208
+ "content": "eddf116620050e80b88497ace026fb8e0a12986f94f216181480c7daa0e08be4"
1259
1209
  }
1260
1210
  ]
1261
1211
  },
@@ -100,6 +100,9 @@ ROUTER → REQUIREMENTS → RESEARCH → ADR → QCSD SWARM
100
100
  SPARC-GOAP PLAN
101
101
  (all)
102
102
  │
103
+ K1 NAME-AVAILABILITY GATE
104
+ (every new command/module/export)
105
+ │
103
106
  K2 PLAN-COMPLETENESS GATE
104
107
  (all — exit 0 or Step 7 waits)
105
108
  │
@@ -147,6 +150,27 @@ Step | S | M | L | XL | Model | Agentic QE Skill
147
150
  10 Delivery Gate (OPT-IN) | o | o | o | o | cross-family of coder | 4 planes: regressions ‖ security ‖ code-quality ‖ product-honesty (o = runs only when explicitly requested; absent ⇒ byte-identical) |
148
151
  ```
149
152
 
153
+ ### K1 name-availability gate (Step-6/7 boundary, MANDATORY, every new name)
154
+
155
+ Before Step 7 writes a line, every NEW name the plan introduces is checked:
156
+
157
+ ```bash
158
+ dz name-check --command <cmd> --module <basename> --export <a,b,c>
159
+ ```
160
+
161
+ `exit 0` → proceed · `exit 1` → rename in the plan first · `exit 2` → NOT ESTABLISHED (the sweep
162
+ found nothing of that kind — fix the invocation, never read it as free).
163
+
164
+ **Why this is a gate and not advice.** Twice on 2026-08-23/24 a collision broke the build outright —
165
+ `dz retro` was already a command and its star re-export clash stopped the CLI from importing at all;
166
+ `decideProvenance` was already an export. Both were answerable before any code. The check costs one
167
+ command; the miss costs a rename across every artifact of the feature. An agent's intention to
168
+ remember is layer 4 on the cost-of-detection ladder, and this line exists because that layer failed
169
+ twice in one day.
170
+
171
+ The check reads workspace SOURCE, never `dist` — a stale build answers "free" confidently. Its honest
172
+ limit is printed on the passing path: a re-export under a different name stays the build's job.
173
+
150
174
  ### K2 plan-completeness gate (Step-6/7 boundary, MANDATORY, all tiers)
151
175
 
152
176
  Step 7 does not start until the plan passes a SCRIPT — not a reviewer's impression:
@@ -185,6 +185,11 @@ Create `features/<slug>/06_implementation_plan.md` with:
185
185
  - `## Amendments` — every correction folded into this plan (a Step-3.5 CONDITIONAL condition, a
186
186
  challenge-panel confirmed finding, a user checkpoint steer) as a fixed-shape row:
187
187
  `AM-N (source): <change>. Confirmation: <property> → test `test_name` (fails if reverted).`
188
+ The row is MACHINE-READ by the K2 C6 gate: the `→ test \`name\`` marker (or `superseded by AM-N`)
189
+ must sit inside that amendment's OWN block — anywhere between its `AM-N` line and the line where
190
+ the NEXT `AM-N` begins. Multi-line amendments are fine; what is NOT fine is putting a marker after
191
+ the following amendment has already started, because it then belongs to that one. A bare range
192
+ like `AM-1..AM-4` never opens a row.
188
193
  A safeguard amendment's named test must prove it TRIGGERS on a real input, not merely that its code
189
194
  path exists. Step 8 verifies every named test exists and is non-vacuous (`dz discrimination-check`).
190
195
 
@@ -292,6 +292,91 @@ if (acidArg) {
292
292
  } else if (acidTokens.length === 0) skips.push('C4: no acid corpus declared (no --acid, no `| A<n> |` table in 00_complexity_assessment.md) — acid-naming check SKIPPED');
293
293
  else for (const t of acidTokens) if (!new RegExp(`\\b${t.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}\\b`, 'i').test(plan)) failures.push(`C4: acid token "${safe(t)}" (from ${acidSource}) not named in the plan`);
294
294
 
295
+ // ── C6 amendment integrity (backlog 72b89e14, seams б/в/г) ──────────────────────────────────────
296
+ // The measured shape: AM-rows living OUTSIDE `## Amendments` were invisible to every gate; four
297
+ // amendments named no test at all; a retracted amendment (AM-23 cancelling AM-20) left the old one
298
+ // standing. One deterministic check for all three: every AM-token belongs to the section, and every
299
+ // AM row in the section carries `→ test ...` OR an explicit `superseded by AM-N`.
300
+ {
301
+ // Line-scan, not regex-over-document: \Z is Python, and $-lookahead under /m matches every
302
+ // line end — a section with no FOLLOWING heading silently failed to parse (caught by the
303
+ // fixture the moment the tests ran).
304
+ const planLines = plan.split('\n');
305
+ let sectionStart = -1, sectionEnd = -1, cursor = 0;
306
+ for (const pl of planLines) {
307
+ if (sectionStart < 0 && /^##\s*Amendments\s*$/.test(pl)) sectionStart = cursor + pl.length + 1;
308
+ else if (sectionStart >= 0 && sectionEnd < 0 && /^##\s/.test(pl)) sectionEnd = cursor;
309
+ cursor += pl.length + 1;
310
+ }
311
+ if (sectionStart >= 0 && sectionEnd < 0) sectionEnd = plan.length;
312
+ const amSection = sectionStart >= 0 ? plan.slice(sectionStart, sectionEnd) : '';
313
+ // Only a DEFINITION-shaped line counts as a stray: a list item opening with the AM token.
314
+ // A mid-prose REFERENCE («per 01_requirements.md (AM-1..AM-6)», «(AM-1: the clause stays
315
+ // dropped)») cites an amendment defined in ANOTHER artifact and is legitimate — the first cut
316
+ // failed the real wave1 corpus on exactly that (caught by the standing acid test).
317
+ {
318
+ let cursor2 = 0;
319
+ for (const pl of planLines) {
320
+ const isDef = /^\s*(?:[-*|]\s*)\*{0,2}AM-(?:CP-)?\d+\b/.test(pl);
321
+ const inSection = sectionStart >= 0 && cursor2 >= sectionStart && cursor2 < sectionEnd;
322
+ if (isDef && !inSection) {
323
+ const tok = (/AM-(?:CP-)?\d+/.exec(pl) || ['AM-?'])[0];
324
+ failures.push(`C6: ${tok} is DEFINED outside the \`## Amendments\` section (line: "${pl.trim().slice(0, 80)}") — an amendment outside the section is invisible to every downstream reader`);
325
+ }
326
+ cursor2 += pl.length + 1;
327
+ }
328
+ }
329
+ if (sectionStart >= 0) {
330
+ // Each amendment's confirmation is looked for in ITS OWN BLOCK: from its definition line to the
331
+ // line where the NEXT amendment begins. Three defects die with the old three-line window
332
+ // (MEASURED 2026-08-25 against the 142-plan corpus — 292 C6 failures before, 33 after, and ZERO
333
+ // rows newly caught that pass today):
334
+ // • FALSE REFUSAL — a marker on the `Confirmation:` line 4+ lines down was invisible, so plans
335
+ // that DID name their test were rejected (7 per run, twice in one day, on a user's machine).
336
+ // • FALSE PASS — the window is three LINES, not one amendment, so `- AM-1 testless` followed by
337
+ // `- AM-2 … -> test x` PASSED: AM-1 borrowed its neighbour's marker. That is the safety half,
338
+ // and it is why the boundary is the next DEFINITION rather than a blank line — a blank line
339
+ // does not separate adjacent bullet rows.
340
+ // • A substring seek (`amSection.indexOf(lnRaw)`) let a duplicated line read someone else's
341
+ // window. Indices remove that hazard for free.
342
+ // The boundary is not invented: parseAmendments() in harness-core/src/amendment-trace.ts has used
343
+ // the same next-definition bound all along, so this also ends a divergence between two checkers.
344
+ const secLines = amSection.split('\n');
345
+ // The bullet stays OPTIONAL: requiring it drops 104 of the corpus's 347 real AM rows out of the
346
+ // check entirely (MEASURED). The `(?!\s*\.)` guard is what refuses a wrapped `AM-1..AM-4;`
347
+ // range preamble, which used to open a phantom amendment and double-count AM-1 — it costs 0 rows.
348
+ const DEF = /^(?:[-*|]\s*)?\*{0,2}(AM-(?:CP-)?\d+)\*{0,2}\b(?!\s*\.)/;
349
+ // `tests?` — the two-id form `-> tests \`a\` and \`b\`` is corpus-canonical and is what
350
+ // amendment-trace.ts parses; matching only the singular turned two currently-green rows red.
351
+ const MARK = /\u2192\s*tests?\b|->\s*tests?\b/;
352
+ const defs = [];
353
+ secLines.forEach((l, i) => { const m = DEF.exec(l.trim()); if (m) defs.push({ i, id: m[1] }); });
354
+ for (let k = 0; k < defs.length; k++) {
355
+ const to = k + 1 < defs.length ? defs[k + 1].i : secLines.length;
356
+ const block = secLines.slice(defs[k].i, to).join('\n');
357
+ const hasTest = MARK.test(block);
358
+ const superseded = /superseded by AM-(?:CP-)?\d+/i.test(block);
359
+ if (!hasTest && !superseded) failures.push(`C6: ${defs[k].id} carries neither \`\u2192 test <name>\` nor \`superseded by AM-N\` — an amendment without a confirmation is a wish, and a retracted one must say its successor`);
360
+ }
361
+ }
362
+ }
363
+
364
+ // ── C7 ADR↔plan command-name drift (seam д) — WARN, deliberately never FAIL ─────────────────────
365
+ // The measured incident: the ADR said `dz policy-sync`, the plan said `dz agents-sync` (and even
366
+ // carried a test that the OTHER alias must not exist) — whichever file the coder opened first won.
367
+ // Deterministically provable is only the SET DIFFERENCE, not which side is right, so this warns
368
+ // with both sides named and never blocks.
369
+ {
370
+ const adrAll = adrFiles.map((f) => { try { return readFileSync(join(adrDir, f), 'utf-8'); } catch { return ''; } }).join('\n');
371
+ const cmds = (t) => new Set([...t.matchAll(/`dz ([a-z][a-z0-9-]+)`/g)].map((m) => m[1]));
372
+ const inAdr = cmds(adrAll); const inPlan = cmds(plan);
373
+ const onlyAdr = [...inAdr].filter((c) => !inPlan.has(c));
374
+ const onlyPlan = [...inPlan].filter((c) => !inAdr.has(c));
375
+ if (adrAll !== '' && onlyAdr.length > 0 && onlyPlan.length > 0) {
376
+ warnings.push(`C7: ADR and plan cite DIFFERENT dz commands — ADR-only: ${onlyAdr.join(', ')}; plan-only: ${onlyPlan.join(', ')} — if these name the SAME thing, one of the two files is lying to the coder (seam д)`);
377
+ }
378
+ }
379
+
295
380
  // C5 — Inputs read line
296
381
  if (!/Inputs read:/i.test(plan)) warnings.push('C5: no "Inputs read:" line (wave-2 seam, WARN only)');
297
382
  else for (const need of ['03_adr','05_architecture']) if (!plan.includes(need)) warnings.push(`C5: Inputs read line missing ${need}`);