@dzhechkov/p-replicator 1.5.17 → 1.6.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.
- package/.dz-manifest.json +173 -65
- package/CHANGELOG.md +135 -0
- package/MULTIPLATFORM_ROADMAP.md +1 -1
- package/README/eng/01_quickstart.md +2 -2
- package/README/eng/02_user_guide.md +1 -1
- package/README/eng/03_admin_guide.md +2 -2
- package/README/eng/05_architecture.md +6 -2
- package/README/eng/README.md +1 -1
- package/README/ru/01_quickstart.md +2 -2
- package/README/ru/02_user_guide.md +1 -1
- package/README/ru/03_admin_guide.md +2 -2
- package/README/ru/05_architecture.md +1 -1
- package/README/ru/README.md +1 -1
- package/README/ru/html/index.html +7 -7
- package/README.md +41 -18
- package/bin/cli.js +0 -0
- package/package.json +11 -10
- package/sbom.json +347 -77
- package/src/utils.js +2 -0
- package/templates/.claude/agents/doc-validator.md +2 -1
- package/templates/.claude/agents/product-discoverer.md +1 -1
- package/templates/.claude/commands/next.md +16 -0
- package/templates/.claude/commands/replicate.md +126 -8
- package/templates/.claude/commands/start.md +19 -1
- package/templates/.claude/hooks/autocommit-insights.cjs +95 -10
- package/templates/.claude/hooks/autocommit-plans.cjs +95 -10
- package/templates/.claude/hooks/autocommit-roadmap.cjs +96 -13
- package/templates/.claude/hooks/check-ports.cjs +232 -0
- package/templates/.claude/hooks/session-insights.cjs +13 -1
- package/templates/.claude/hooks/state-update.cjs +13 -1
- package/templates/.claude/hooks/statusline.cjs +145 -18
- package/templates/.claude/rules/docker-ports.md +123 -0
- package/templates/.claude/rules/replicate-pipeline.md +5 -2
- package/templates/.claude/settings.json +5 -5
- package/templates/.claude/skills/cc-toolkit-generator-enhanced/modules/01-detect-parse.md +57 -14
- package/templates/.claude/skills/cc-toolkit-generator-enhanced/modules/02-analyze-map.md +9 -7
- package/templates/.claude/skills/cc-toolkit-generator-enhanced/references/enhanced-recommendations.md +6 -4
- package/templates/.claude/skills/cc-toolkit-generator-enhanced/references/extended-mapping.md +2 -2
- package/templates/.claude/skills/cc-toolkit-generator-enhanced/references/templates/ddd-agents.md +2 -2
- package/templates/.claude/skills/cc-toolkit-generator-enhanced/references/templates/ddd-skills.md +1 -1
- package/templates/.claude/skills/cc-toolkit-generator-enhanced/references/templates/enhanced-claude-md.md +2 -2
- package/templates/.claude/skills/cc-toolkit-generator-enhanced/references/templates/feature-suggestions.md +11 -2
- package/templates/.claude/skills/cc-toolkit-generator-enhanced/references/templates/start-command.md +1 -1
- package/templates/.claude/skills/goap-research-ed25519/SKILL.md +340 -47
- package/templates/.claude/skills/goap-research-ed25519/scripts/check_report_evidence.py +359 -3
- package/templates/.claude/skills/goap-research-ed25519/scripts/ed25519_verifier.py +386 -13
- package/templates/.claude/skills/goap-research-ed25519/scripts/fixture_legacy_v2_fact.json +23 -0
- package/templates/.claude/skills/goap-research-ed25519/scripts/fixtures_field_cases.json +133 -0
- package/templates/.claude/skills/goap-research-ed25519/scripts/goap_planner.py +314 -44
- package/templates/.claude/skills/goap-research-ed25519/scripts/learning_bridge.py +890 -303
- package/templates/.claude/skills/goap-research-ed25519/scripts/population_match.py +591 -0
- package/templates/.claude/skills/goap-research-ed25519/scripts/risk_statement.py +289 -0
- package/templates/.claude/skills/goap-research-ed25519/scripts/test_ed25519_verifier.py +57 -2
- package/templates/.claude/skills/goap-research-ed25519/scripts/test_evidence_provenance.py +969 -344
- package/templates/.claude/skills/goap-research-ed25519/scripts/test_goap_planner.py +420 -0
- package/templates/.claude/skills/goap-research-ed25519/scripts/test_population_match.py +544 -0
- package/templates/.claude/skills/goap-research-ed25519/scripts/test_risk_absolute.py +239 -0
- package/templates/.claude/skills/goap-research-ed25519/scripts/test_signature_v3.py +554 -0
- package/templates/.claude/skills/goap-research-ed25519/scripts/test_suite_completeness.py +90 -0
- package/templates/.claude/skills/requirements-validator/SKILL.md +7 -0
- package/templates/.claude/skills/requirements-validator/references/scoring-system.md +28 -0
- package/templates/.claude/skills/sparc-prd-mini/SKILL.md +143 -1
- package/tests/e2e/lifecycle.test.js +21 -10
- package/tests/snapshot/baseline.json +51 -34
- package/tests/snapshot/update-baseline.js +2 -1
- package/tests/unit/adr-decision-coverage.test.js +137 -0
- package/tests/unit/adr-scanner-contract.test.js +108 -0
- package/tests/unit/autocommit-deletion.test.js +242 -0
- package/tests/unit/check-ports.test.js +184 -0
- package/tests/unit/db-port-rule.test.js +216 -0
- package/tests/unit/detect-parse-anchor.test.js +109 -0
- package/tests/unit/external-dependency-check.test.js +209 -0
- package/tests/unit/growth-module-b2b-gate.test.js +104 -0
- package/tests/unit/hooks-project-anchored.test.js +223 -0
- package/tests/unit/hooks-report-failures.test.js +207 -0
- package/tests/unit/pipeline-file-ownership.test.js +95 -0
- package/tests/unit/roadmap-one-schema.test.js +179 -0
- package/tests/unit/sparc-reconciliation.test.js +117 -0
- package/tests/unit/spec-pseudocode-traceability.test.js +146 -0
- package/tests/unit/statusline-honest-labels.test.js +178 -0
- package/tests/unit/statusline-two-roots.test.js +237 -0
- package/tests/unit/sync-templates-guard.test.js +209 -0
- package/tests/unit/utils.test.js +2 -2
- package/tests/unit/validation-gate-teeth.test.js +158 -0
- package/LICENSE +0 -21
|
@@ -53,6 +53,34 @@ Total Score = INVEST Score (50%) + SMART Score (30%) + Quality Score (20%)
|
|
|
53
53
|
| 50-69 | Fair | 🔶 REWORK | Significant clarification needed |
|
|
54
54
|
| **0-49** | **Poor** | **🚫 BLOCKED** | **Requires complete rewrite** |
|
|
55
55
|
|
|
56
|
+
### Blocking floor (overrides the total, both directions)
|
|
57
|
+
|
|
58
|
+
**The weakest link decides, never the average.** A requirement is BLOCKED — whatever its total says —
|
|
59
|
+
if either of these is zero:
|
|
60
|
+
|
|
61
|
+
| Criterion | Zero means | Why it vetoes |
|
|
62
|
+
|-----------|-----------|---------------|
|
|
63
|
+
| `Testable` (INVEST, 8) | no acceptance criteria exist | the gate exists to block untestable requirements |
|
|
64
|
+
| `Completeness` (Quality, 10) | "No AC" on the rubric above | nothing states what "done" is |
|
|
65
|
+
|
|
66
|
+
Without this floor the total alone lets an untestable requirement through. Worked case: a story with
|
|
67
|
+
NO acceptance criteria and NO test links loses `Testable` 8, `Completeness` 10 and `Traceability` 10,
|
|
68
|
+
keeps everything else, and totals **72/100** — above the 70 line, filed as "fix minor issues, then
|
|
69
|
+
proceed". The floor blocks it on `Testable = 0` and `Completeness = 0`.
|
|
70
|
+
|
|
71
|
+
**The floor keys on the artifact, not on the number you wrote.** The same agent scores these
|
|
72
|
+
criteria AND is bound by the floor, so a score is not evidence of anything — reporting `Testable = 4`
|
|
73
|
+
("vague AC") on a story with no AC at all evades the veto without lying about the rubric. Therefore:
|
|
74
|
+
|
|
75
|
+
> A non-zero `Testable` or `Completeness` REQUIRES quoting the acceptance criteria being scored —
|
|
76
|
+
> the actual text, with its document and heading. `Testable = 4` means the AC exist and are vague:
|
|
77
|
+
> quote them. **No quote ⇒ the score is 0 ⇒ the floor applies.**
|
|
78
|
+
|
|
79
|
+
**The floor is CLOSED at these two.** `Measurable` and `Traceability` are deliberately NOT on it: a
|
|
80
|
+
requirement with no number is often correct ("the user can export the report as PDF" is specific,
|
|
81
|
+
testable and unmeasurable), so vetoing on `Measurable` would turn a false pass into a false block.
|
|
82
|
+
Widening this list needs the same kind of worked case as the one above.
|
|
83
|
+
|
|
56
84
|
## Quality Gate Rules
|
|
57
85
|
|
|
58
86
|
### BLOCKED (Score < 50)
|
|
@@ -382,16 +382,24 @@ view("/mnt/skills/user/problem-solver-enhanced/SKILL.md")
|
|
|
382
382
|
|
|
383
383
|
**User Story Format:**
|
|
384
384
|
```
|
|
385
|
-
As a [persona],
|
|
385
|
+
US-<nnn>: As a [persona],
|
|
386
386
|
I want to [action],
|
|
387
387
|
So that [benefit].
|
|
388
388
|
|
|
389
389
|
Acceptance Criteria:
|
|
390
|
+
[SC-<story-id>-1]
|
|
390
391
|
Given [context]
|
|
391
392
|
When [action]
|
|
392
393
|
Then [expected result]
|
|
393
394
|
```
|
|
394
395
|
|
|
396
|
+
Every user story carries an ID `US-<nnn>` — three digits, assigned in order, never reused even after
|
|
397
|
+
a story is deleted. Every acceptance scenario under it carries `SC-<US-id>-<n>`, numbered from 1
|
|
398
|
+
within its story: the scenarios of `US-007` are `SC-US-007-1`, `SC-US-007-2`, and so on. Phase 4
|
|
399
|
+
traces algorithms back to these IDs, and there is nothing to trace to if a scenario has no name — nor
|
|
400
|
+
anything reliable to trace to if two scenarios can end up with the same name, which is what the
|
|
401
|
+
never-reused rule prevents.
|
|
402
|
+
|
|
395
403
|
**PRD Generation:**
|
|
396
404
|
```
|
|
397
405
|
view("templates/prd.md")
|
|
@@ -437,6 +445,7 @@ type EntityName = {
|
|
|
437
445
|
## Core Algorithms
|
|
438
446
|
|
|
439
447
|
### Algorithm: [Name]
|
|
448
|
+
REALISES: [SC-… ids this algorithm implements, comma-separated]
|
|
440
449
|
INPUT: [parameters]
|
|
441
450
|
OUTPUT: [result]
|
|
442
451
|
|
|
@@ -471,6 +480,54 @@ Response (4xx/5xx):
|
|
|
471
480
|
[Error categories and responses]
|
|
472
481
|
```
|
|
473
482
|
|
|
483
|
+
**Шаг 4.9 — ПОКРЫТИЕ СЦЕНАРИЕВ (обязательный, до чекпойнта).**
|
|
484
|
+
|
|
485
|
+
Re-read `Specification.md` and collect every `SC-` scenario ID. Collect every algorithm's `REALISES`
|
|
486
|
+
line from `Pseudocode.md`. Write a `## Scenario Coverage` block into `Pseudocode.md` — **in every
|
|
487
|
+
case, including the one where everything is covered**, because an absent block and a block saying
|
|
488
|
+
"all covered" are indistinguishable to the next reader:
|
|
489
|
+
|
|
490
|
+
```
|
|
491
|
+
## Scenario Coverage
|
|
492
|
+
|
|
493
|
+
Scenarios in Specification.md: [N] · claimed by an algorithm: [M]
|
|
494
|
+
|
|
495
|
+
Not claimed by any algorithm:
|
|
496
|
+
| Scenario | Reason |
|
|
497
|
+
|---|---|
|
|
498
|
+
| SC-… | ui-only |
|
|
499
|
+
|
|
500
|
+
Claimed by an algorithm but absent from Specification.md:
|
|
501
|
+
| Algorithm | Claimed ID |
|
|
502
|
+
|---|---|
|
|
503
|
+
| [name] | SC-… |
|
|
504
|
+
```
|
|
505
|
+
|
|
506
|
+
**Both tables are required, and both may be the single word `none`.** A traceability check that runs
|
|
507
|
+
one way only is half a check: without the second table an algorithm can declare `REALISES: SC-US-009-3`
|
|
508
|
+
for a scenario nobody ever wrote, and the dangling reference reads exactly like coverage. `none` is
|
|
509
|
+
written out rather than left blank, because an empty table and a forgotten table look identical.
|
|
510
|
+
|
|
511
|
+
**Reasons are a CLOSED list of five**, and nothing else is accepted:
|
|
512
|
+
|
|
513
|
+
| Reason | Means |
|
|
514
|
+
|---|---|
|
|
515
|
+
| `ui-only` | realised entirely in the interface, no algorithm to write |
|
|
516
|
+
| `external-service` | performed by a third party, see `Architecture.md` → External Dependencies |
|
|
517
|
+
| `out-of-mvp-scope` | deliberately not built yet |
|
|
518
|
+
| `data-only` | satisfied by a schema or constraint, not by a procedure |
|
|
519
|
+
| `config-only` | satisfied by OUR OWN configuration — a server setting, a header, a policy file — with no procedure to write |
|
|
520
|
+
|
|
521
|
+
Free text is NOT a reason, and `N/A` is NOT a reason. A field that accepts anything records nothing:
|
|
522
|
+
the whole value of the list is that an unclaimed scenario has to be one of a small number of
|
|
523
|
+
recognisable things, and if it is none of them, the gap is real and belongs in the algorithms.
|
|
524
|
+
|
|
525
|
+
**What this establishes, and what it does not.** It establishes that a CLAIM exists and that its two
|
|
526
|
+
ends name each other. It does NOT establish that the algorithm's steps actually perform the check the
|
|
527
|
+
scenario describes — no comparison of names can. So this catches *"nobody wrote anything about this
|
|
528
|
+
scenario"*; it does not catch *"someone wrote a line that mentions it"*. Say so here rather than
|
|
529
|
+
letting a later reader assume the stronger thing.
|
|
530
|
+
|
|
474
531
|
**[MANUAL] CP4:**
|
|
475
532
|
```
|
|
476
533
|
═══════════════════════════════════════════════════════════════
|
|
@@ -541,6 +598,51 @@ graph TB
|
|
|
541
598
|
| Queue | | |
|
|
542
599
|
| Infrastructure | | |
|
|
543
600
|
|
|
601
|
+
## External Dependencies
|
|
602
|
+
|
|
603
|
+
Every capability this product needs from someone else's service. One row per capability, not one row
|
|
604
|
+
per vendor: "sends email" and "reports bounces" are two questions, and a provider can do one without
|
|
605
|
+
the other.
|
|
606
|
+
|
|
607
|
+
| Capability needed | Provider / API | Evidence | Verdict | Requirements relying on it |
|
|
608
|
+
|---|---|---|---|---|
|
|
609
|
+
| [what the product needs it to DO] | [service] | [link to the provider's own docs naming this capability] · checked [YYYY-MM-DD] | CONFIRMED | [REQ ids] |
|
|
610
|
+
|
|
611
|
+
**Evidence — what counts, and what does not.** Evidence is a link to the PROVIDER'S OWN documentation
|
|
612
|
+
that names the specific capability, plus the date it was checked, plus **a short verbatim QUOTE from
|
|
613
|
+
that page stating the capability**. These do NOT count, and each is a way this check gets faked: a
|
|
614
|
+
landing page or marketing page; a pricing page; recollection — "the model knows this API supports
|
|
615
|
+
it"; and **a URL nobody opened** — a plausible-looking link is the cheapest possible forgery, which
|
|
616
|
+
is exactly why the quote is required and the link alone is not enough. A capability nobody could cite
|
|
617
|
+
is not confirmed, and saying so is the point of the middle verdict.
|
|
618
|
+
|
|
619
|
+
**Verdicts — exactly three, because two would hide a difference that matters:**
|
|
620
|
+
|
|
621
|
+
| Verdict | Means | Consequence in Phase 2 |
|
|
622
|
+
|---|---|---|
|
|
623
|
+
| CONFIRMED | cited, and the citation names this capability | none |
|
|
624
|
+
| UNCONFIRMED | nobody could produce a citation | the REQUIREMENTS in that row's last column cannot enter Phase 3 — defer, remove or replace them. Unrelated work continues; the run is 🟡 CAVEATS at best and the row is NAMED in the report |
|
|
625
|
+
| CONTRADICTED | the provider's own docs say it cannot | 🔴 NEEDS WORK — the requirement rests on something that is not there |
|
|
626
|
+
|
|
627
|
+
`UNCONFIRMED` is not a failure to be hidden; it is the honest state of a project on a machine with no
|
|
628
|
+
web access. Collapsing it into CONFIRMED overstates what is known; collapsing it into CONTRADICTED
|
|
629
|
+
blocks work that may be perfectly fine — and would push people to write a citation that isn't one,
|
|
630
|
+
which is how a gate becomes theatre.
|
|
631
|
+
|
|
632
|
+
But it does not pass for free either. **The consequence is scoped to the REQUIREMENT, not to the
|
|
633
|
+
run:** the requirements listed in an `UNCONFIRMED` row do not enter Phase 3 until they are deferred,
|
|
634
|
+
removed, or rewritten onto something confirmable. Everything not resting on that capability proceeds.
|
|
635
|
+
Without this scoping an inventory of nothing but `UNCONFIRMED` rows would reach Phase 3 with a
|
|
636
|
+
caveat, and external feasibility would never have to be established at all — the check would be
|
|
637
|
+
optional in practice while looking mandatory on paper.
|
|
638
|
+
|
|
639
|
+
**If this product has no external dependencies**, write exactly that: *"No external dependencies —
|
|
640
|
+
this product calls no third-party service."* An empty section and an absent section are
|
|
641
|
+
indistinguishable, and only one of them means anything.
|
|
642
|
+
|
|
643
|
+
Names in the row above are PLACEHOLDERS. Do not copy a real provider or a real capability from any
|
|
644
|
+
example: what an API can do drifts, and a stale fact recorded as evidence is worse than none.
|
|
645
|
+
|
|
544
646
|
## Data Architecture
|
|
545
647
|
[Data models, relationships, storage strategy]
|
|
546
648
|
|
|
@@ -551,6 +653,46 @@ graph TB
|
|
|
551
653
|
[Horizontal/vertical scaling, bottlenecks]
|
|
552
654
|
```
|
|
553
655
|
|
|
656
|
+
**Шаг 5.9 — СВЕРКА С ПСЕВДОКОДОМ (обязательный, до чекпойнта).**
|
|
657
|
+
|
|
658
|
+
Фаза 4 написала модель данных ДО того, как эта фаза выбрала хранилище и технологии, и до сих пор
|
|
659
|
+
ничто их не сверяло. Именно отсюда берутся расхождения, которые всплывают уже в коде: поле осталось
|
|
660
|
+
булевым, когда схема получила перечисление; алгоритм пользуется полем, которого в схеме нет; у
|
|
661
|
+
статуса три значения в одном документе и пять в другом.
|
|
662
|
+
|
|
663
|
+
Перечитай в `Pseudocode.md` ДВЕ секции — `## Data Structures` и `## Core Algorithms` — и сверь их с
|
|
664
|
+
тем, что выбрано ЗДЕСЬ. Алгоритмы нужны обязательно: расхождение «алгоритм читает поле, которого в
|
|
665
|
+
схеме нет» по одним лишь структурам данных не обнаруживается. Ищи три вида расхождений:
|
|
666
|
+
|
|
667
|
+
- **смена типа** — поле объявлено одним типом, а хранилище требует другого (булево против перечисления);
|
|
668
|
+
- **отсутствующая колонка** — алгоритм читает или пишет поле, которого в схеме нет;
|
|
669
|
+
- **несовпадение набора значений** — у одного и того же поля разное число допустимых значений.
|
|
670
|
+
|
|
671
|
+
Какую сторону править — решается по РОЛИ документа, а не по старшинству. `Pseudocode.md` держит
|
|
672
|
+
ЛОГИЧЕСКУЮ модель (что означает поле), `Architecture.md` — ФИЗИЧЕСКУЮ (где и как оно лежит).
|
|
673
|
+
Поэтому: если эта фаза ввела осознанное физическое ограничение (тип хранилища, индекс, длина) —
|
|
674
|
+
правится `Pseudocode.md`; если выбранная технология НАРУШАЕТ требуемую семантику (теряются значения,
|
|
675
|
+
исчезает состояние, которым пользуется алгоритм) — меняется выбор ЗДЕСЬ, потому что требование
|
|
676
|
+
старше удобства реализации. Секция `## Data Architecture` этого документа остаётся на месте, но
|
|
677
|
+
описывает отображение на хранилище и связи, а НЕ пересказывает список полей: второй экземпляр списка
|
|
678
|
+
становится вторым местом, где начинается расхождение.
|
|
679
|
+
|
|
680
|
+
Результат записывается в `Architecture.md` ВСЕГДА, отдельным блоком:
|
|
681
|
+
|
|
682
|
+
```markdown
|
|
683
|
+
## Reconciliation with Pseudocode
|
|
684
|
+
|
|
685
|
+
| Сущность.поле | Вид расхождения | Что сделано |
|
|
686
|
+
|---|---|---|
|
|
687
|
+
| … | смена типа / отсутствующая колонка / несовпадение набора значений | … |
|
|
688
|
+
```
|
|
689
|
+
|
|
690
|
+
Если сверка не нашла ничего — блок всё равно пишется, и он ОБЯЗАН назвать, что именно
|
|
691
|
+
сверялось: «Расхождений с `Pseudocode.md` не найдено. Сверены сущности: <перечисление>; алгоритмы:
|
|
692
|
+
<перечисление>.» Одна фраза «расхождений нет» без перечня — это церемония, которую модель напишет
|
|
693
|
+
не глядя; перечень делает утверждение проверяемым. Молчание не является результатом сверки: по нему
|
|
694
|
+
нельзя отличить «сверили и чисто» от «не сверяли».
|
|
695
|
+
|
|
554
696
|
**[MANUAL] CP5:**
|
|
555
697
|
```
|
|
556
698
|
═══════════════════════════════════════════════════════════════
|
|
@@ -281,16 +281,24 @@ describe('e2e: unknown command', () => {
|
|
|
281
281
|
// ---------------------------------------------------------------------------
|
|
282
282
|
|
|
283
283
|
describe('e2e: --help shows correct component counts', () => {
|
|
284
|
-
test('
|
|
284
|
+
test('--help agrees with COMPONENTS for every group', () => {
|
|
285
|
+
// DERIVED, not hardcoded. This assertion has now gone stale twice for the same reason — the
|
|
286
|
+
// comment above records "cli.js used to say 1 rule while EXPECTED_RULES had 2 entries", and
|
|
287
|
+
// adding the docker-ports rule broke it again with a literal 5. cli.js:57 already computes the
|
|
288
|
+
// numbers from COMPONENTS; a test that re-types them is a second source of truth, which is the
|
|
289
|
+
// very defect it was written to catch.
|
|
290
|
+
const { COMPONENTS } = require(path.join(PKG_DIR, 'src', 'utils.js'));
|
|
285
291
|
const dir = tmpDir();
|
|
286
292
|
try {
|
|
287
293
|
const r = runCli(['--help'], dir);
|
|
288
294
|
assert.equal(r.exitCode, 0);
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
295
|
+
for (const group of ['skills', 'commands', 'agents', 'rules']) {
|
|
296
|
+
const n = Object.keys(COMPONENTS[group].items).length;
|
|
297
|
+
// singular/plural: cli.js prints "1 rule" but "6 rules"
|
|
298
|
+
const word = n === 1 ? group.replace(/s$/, '') : group;
|
|
299
|
+
assert.match(r.stdout, new RegExp(n + '\\s+' + word, 'i'),
|
|
300
|
+
'--help must say "' + n + ' ' + word + '" to match COMPONENTS.' + group);
|
|
301
|
+
}
|
|
294
302
|
} finally { rmRf(dir); }
|
|
295
303
|
});
|
|
296
304
|
});
|
|
@@ -440,8 +448,10 @@ describe('e2e: v1.4.1 cross-platform hooks', () => {
|
|
|
440
448
|
assert.doesNotMatch(cmd, /\|\|\s*true/,
|
|
441
449
|
`bash-specific || true in: ${cmd}`);
|
|
442
450
|
// Each command should invoke node + a script
|
|
443
|
-
|
|
444
|
-
|
|
451
|
+
// Anchored at the project root, not the drifting cwd (PR-013): still node + the exact
|
|
452
|
+
// script, and now additionally the anchor — strictly stronger than the old assertion.
|
|
453
|
+
assert.match(cmd, /node\s+"\$\{CLAUDE_PROJECT_DIR\}\/\.claude\/hooks\/[A-Za-z0-9._-]+\.cjs"/,
|
|
454
|
+
`expected 'node "\${CLAUDE_PROJECT_DIR}/.claude/hooks/<script>.cjs"', got: ${cmd}`);
|
|
445
455
|
}
|
|
446
456
|
} finally { rmRf(dir); }
|
|
447
457
|
});
|
|
@@ -599,8 +609,9 @@ describe('e2e: v1.5.0 statusline dashboard', () => {
|
|
|
599
609
|
);
|
|
600
610
|
assert.ok(settings.statusLine, 'statusLine field should be present in settings.json');
|
|
601
611
|
assert.equal(settings.statusLine.type, 'command');
|
|
602
|
-
assert.match(settings.statusLine.command,
|
|
603
|
-
|
|
612
|
+
assert.match(settings.statusLine.command,
|
|
613
|
+
/node\s+"\$\{CLAUDE_PROJECT_DIR\}\/\.claude\/hooks\/statusline\.cjs"/,
|
|
614
|
+
'should invoke statusline.cjs via node, anchored at the project root (PR-013)');
|
|
604
615
|
} finally { rmRf(dir); }
|
|
605
616
|
});
|
|
606
617
|
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
|
-
"generatedAt": "2026-
|
|
3
|
-
"totalFiles":
|
|
2
|
+
"generatedAt": "2026-08-27T09:01:34.335Z",
|
|
3
|
+
"totalFiles": 136,
|
|
4
4
|
"files": {
|
|
5
|
-
".claude/agents/doc-validator.md": "
|
|
5
|
+
".claude/agents/doc-validator.md": "e57950758cd4764b2cb54b3f1905567e9dbc1ed20ac6ecd30998614894689f4f",
|
|
6
6
|
".claude/agents/harvest-coordinator.md": "70fa884057669902e18744915305705cf9e45e738a83d7bb5ab011a3b72d683c",
|
|
7
|
-
".claude/agents/product-discoverer.md": "
|
|
7
|
+
".claude/agents/product-discoverer.md": "f74683fe91b4357d6fb4024ed47b4d5a129ea6375ca6b223dee97176d74acf1c",
|
|
8
8
|
".claude/agents/replicate-coordinator.md": "e86060110ab188109cf908878206543f414993e14dad01f8dc19f041ee6497a7",
|
|
9
9
|
".claude/commands/deploy.md": "27f5424ee217163c55e5e6b9322a1f0858159407bd24ebd6d6588d6c22a5f890",
|
|
10
10
|
".claude/commands/docs.md": "be03592cb3f1d61b60dc96d3e26d71281ad4eb2d4626012c080ce609a32c96e4",
|
|
@@ -12,23 +12,25 @@
|
|
|
12
12
|
".claude/commands/go.md": "655dc9cad37b61a9f283cef15e435c492ee7cbc88a6ce59295ac32c975dee858",
|
|
13
13
|
".claude/commands/harvest.md": "c074fe7799f594dda44c5f8166da707f25cee51b12f758dea562a8c1e6ac5dcd",
|
|
14
14
|
".claude/commands/myinsights.md": "2e73e822384f976383d9c3313940888b9853f1781d2c39a2fb89825f221149dc",
|
|
15
|
-
".claude/commands/next.md": "
|
|
15
|
+
".claude/commands/next.md": "1e4984306c3aa80dfc8734dc1c975dfe5fdf2cf6396ddd759e4c7635646107b8",
|
|
16
16
|
".claude/commands/plan.md": "6fef889f51168981bf4a98b8392a0d595e3d199e1cfaa8e08c0a181ec6c440e4",
|
|
17
|
-
".claude/commands/replicate.md": "
|
|
17
|
+
".claude/commands/replicate.md": "13f5e2ebe109f33b63cbcd75e3cf1b94224ab066aba1b0cb10cf34f668144a8a",
|
|
18
18
|
".claude/commands/run.md": "87144dfe8c56c15ba7c117daa544d8a08b84d7205f21dafcc48d27c6c3995059",
|
|
19
|
-
".claude/commands/start.md": "
|
|
20
|
-
".claude/hooks/autocommit-insights.cjs": "
|
|
21
|
-
".claude/hooks/autocommit-plans.cjs": "
|
|
22
|
-
".claude/hooks/autocommit-roadmap.cjs": "
|
|
23
|
-
".claude/hooks/
|
|
24
|
-
".claude/hooks/
|
|
25
|
-
".claude/hooks/
|
|
19
|
+
".claude/commands/start.md": "4aaebc10ca8d607d4b2b43883d82392e9788c2f183878a49fc0d1ed54d07ee95",
|
|
20
|
+
".claude/hooks/autocommit-insights.cjs": "5e7cef87b24d457f25315d79fe15f0dfaf94d9269495d638817f0faee2593c6f",
|
|
21
|
+
".claude/hooks/autocommit-plans.cjs": "9bb404b7f4fda5de03e6c2f16bf8939a79ec1944538767b04bcccc6cf50cc03d",
|
|
22
|
+
".claude/hooks/autocommit-roadmap.cjs": "f4dcc9ffd9a3aed91dd56e011e699fcf8af903cc81594e4ab1ef61e5432a36ad",
|
|
23
|
+
".claude/hooks/check-ports.cjs": "e5f2d2bd8899df27c2dfedf76128467becae1868210eb8525a1bad2869a8c78f",
|
|
24
|
+
".claude/hooks/session-insights.cjs": "46f8357e3886a6d54db1ab4af969b9b8643ae5937ba59038a5651ffbcfd0d30e",
|
|
25
|
+
".claude/hooks/state-update.cjs": "47146a76b768ac2273abe8f2f017856a0e28b45afaf90048148da417dd19604e",
|
|
26
|
+
".claude/hooks/statusline.cjs": "1eca683baf67a17874dc5db6dfe38eb11944f550c66f46330bce0f794732245f",
|
|
27
|
+
".claude/rules/docker-ports.md": "bef41c25c875479341f68783c2d64572800d4710f55401e55519245f03d22efb",
|
|
26
28
|
".claude/rules/feature-lifecycle.md": "f9ddc8c889ab7938a7207b36ae46c36be05e9b870956ef16617bf31b2f78c758",
|
|
27
29
|
".claude/rules/git-workflow.md": "7d8d2ded47fcc0fb95da3dc226efa6cb3c80d6adf7296977588c181dfce20192",
|
|
28
30
|
".claude/rules/insights-capture.md": "488d694caffe7a32915b0ec1beb7a84b223fe602722c5bb91ab8bf2785626387",
|
|
29
|
-
".claude/rules/replicate-pipeline.md": "
|
|
31
|
+
".claude/rules/replicate-pipeline.md": "b65e802d32a1e50bdfcd0cfc79c78e9234eac48a94f0cd1f5647cf4fea6c0162",
|
|
30
32
|
".claude/rules/skill-interface-protocol.md": "fe18fcb9217002572f462f3a7f38de22cdd7ba0dd4e906fdcd0c0e8cfed9f2aa",
|
|
31
|
-
".claude/settings.json": "
|
|
33
|
+
".claude/settings.json": "b1df6cf834ccfa227f3318a70862115c17838ab31253e9d8d89381b7763e61fd",
|
|
32
34
|
".claude/skills/brutal-honesty-review/evals/brutal-honesty-review.yaml": "855c155d55575e12aab23fb3a5fb2fada74d93974ff755dfedac6f2d5bd41f13",
|
|
33
35
|
".claude/skills/brutal-honesty-review/README.md": "2a026b4af50b21456e50424fbfa089cb983fbbaa0c68024c8c17c695bea25a57",
|
|
34
36
|
".claude/skills/brutal-honesty-review/resources/assessment-rubrics.md": "dac09c91c765e2211799cc230738fb72a966f47511edb872306a906e49640cbe",
|
|
@@ -38,8 +40,8 @@
|
|
|
38
40
|
".claude/skills/brutal-honesty-review/scripts/assess-tests.sh": "8c6444bdb5ce97e49223cdaa6b1c58ac8fcec710cd6ee8d56de9bc677379bd88",
|
|
39
41
|
".claude/skills/brutal-honesty-review/scripts/validate-config.json": "7418284839f89735d01f50eefdb488b013e0076f6003a67683062429c14984c6",
|
|
40
42
|
".claude/skills/brutal-honesty-review/SKILL.md": "21e41129dac8e99485b501dcb3767d5f4461ce527782fa7bc71f89dabe5bd2bd",
|
|
41
|
-
".claude/skills/cc-toolkit-generator-enhanced/modules/01-detect-parse.md": "
|
|
42
|
-
".claude/skills/cc-toolkit-generator-enhanced/modules/02-analyze-map.md": "
|
|
43
|
+
".claude/skills/cc-toolkit-generator-enhanced/modules/01-detect-parse.md": "85c72f6daa5af88b4a7ff520a387f47a7c92b81cb1f0757550c8b58100a97be6",
|
|
44
|
+
".claude/skills/cc-toolkit-generator-enhanced/modules/02-analyze-map.md": "5939f3fe6ae542fabb8e665dc373a20410d8de917362fcb3ecac504286f41836",
|
|
43
45
|
".claude/skills/cc-toolkit-generator-enhanced/modules/03-generate-p0.md": "b093a5d66663e2dfd6415afef7c7444409f03379f857001b811685ded410038b",
|
|
44
46
|
".claude/skills/cc-toolkit-generator-enhanced/modules/04-generate-p1.md": "081284d3858c5dd89b45fc8a2b83bbc0477843f864cbceb6d9f8c3629b198a0a",
|
|
45
47
|
".claude/skills/cc-toolkit-generator-enhanced/modules/05-generate-p2p3.md": "9535eaa5fa1be0804369aa4e8ee6f6f580839ea2c3c7b7aa51584e298a928093",
|
|
@@ -49,32 +51,47 @@
|
|
|
49
51
|
".claude/skills/cc-toolkit-generator-enhanced/modules/09-cross-project-learning.md": "c395bc42a40ed14c0b8fe274df516082db0490228c82aba6a56f23b8f41d3d43",
|
|
50
52
|
".claude/skills/cc-toolkit-generator-enhanced/modules/README.md": "9dbcc9c0978d06cbe31caffa909741fdb3a38d3cd1e6e98addf95628ec8394a0",
|
|
51
53
|
".claude/skills/cc-toolkit-generator-enhanced/references/claude-md-strategy.md": "88cdab1687096d58dc4450cdf81d24d00fdb493b2cc4960030b30fd57d1ca2da",
|
|
52
|
-
".claude/skills/cc-toolkit-generator-enhanced/references/enhanced-recommendations.md": "
|
|
53
|
-
".claude/skills/cc-toolkit-generator-enhanced/references/extended-mapping.md": "
|
|
54
|
+
".claude/skills/cc-toolkit-generator-enhanced/references/enhanced-recommendations.md": "657e35db0cb77d3a9d1a4d01215a9b8d50441dd863593bee3a84f62aad8b00bc",
|
|
55
|
+
".claude/skills/cc-toolkit-generator-enhanced/references/extended-mapping.md": "5e87c91956eabc70b4a1084b47b2c9a20ede18bb245735812ead956eafabf3af",
|
|
54
56
|
".claude/skills/cc-toolkit-generator-enhanced/references/maturity-integration.md": "aa4e743bcd0281525336a298d0489c31481f69ff1a534e1ed1d262d888937deb",
|
|
55
57
|
".claude/skills/cc-toolkit-generator-enhanced/references/security-patterns-library.md": "5f1d650c426cbd2c9536b385306605ea62a5a520ee4566d23ca7254409c672a5",
|
|
56
58
|
".claude/skills/cc-toolkit-generator-enhanced/references/templates/automation-commands.md": "23b8204fdc70b5afc5430cbe503af709a04b26716d2d2e07889283a755858fee",
|
|
57
|
-
".claude/skills/cc-toolkit-generator-enhanced/references/templates/ddd-agents.md": "
|
|
59
|
+
".claude/skills/cc-toolkit-generator-enhanced/references/templates/ddd-agents.md": "c91f81da197a072b57378fd0018eea26c35d909a558bdca6f070eb60153c97b3",
|
|
58
60
|
".claude/skills/cc-toolkit-generator-enhanced/references/templates/ddd-hooks-commands.md": "d70a0c4977d322602c35c53bf04880177b5dd8f0de2b339d68a0f55993903745",
|
|
59
|
-
".claude/skills/cc-toolkit-generator-enhanced/references/templates/ddd-skills.md": "
|
|
60
|
-
".claude/skills/cc-toolkit-generator-enhanced/references/templates/enhanced-claude-md.md": "
|
|
61
|
+
".claude/skills/cc-toolkit-generator-enhanced/references/templates/ddd-skills.md": "2f1019d5da7d695983aee79186a47fcefccbfa24db48219c04f9bb9feb757d3a",
|
|
62
|
+
".claude/skills/cc-toolkit-generator-enhanced/references/templates/enhanced-claude-md.md": "db6898b7202b84965cbff9195a6ce780cadd6aeb64adae3fbfd951443a6bc43d",
|
|
61
63
|
".claude/skills/cc-toolkit-generator-enhanced/references/templates/feature-lifecycle-ent.md": "eb9025b687f0408b33280bf5fcc6c8be9b1670a544dd90b510557b89ae6cc123",
|
|
62
64
|
".claude/skills/cc-toolkit-generator-enhanced/references/templates/feature-lifecycle.md": "c537b47e7a4ff2d692767f4aac130e2ae9b1923782106750218696e87f515feb",
|
|
63
|
-
".claude/skills/cc-toolkit-generator-enhanced/references/templates/feature-suggestions.md": "
|
|
65
|
+
".claude/skills/cc-toolkit-generator-enhanced/references/templates/feature-suggestions.md": "3b1c20d2394e180720447416767fbfae99168cf9ca846bf64907f6fe5cd906da",
|
|
64
66
|
".claude/skills/cc-toolkit-generator-enhanced/references/templates/insights-system.md": "244c2ef5f417c5d0097accf5ccfffd9de93d167efbfc6818cb9a8196139e096e",
|
|
65
67
|
".claude/skills/cc-toolkit-generator-enhanced/references/templates/mcp.md": "63d1e6dabf5bb29534e6fa11d9dd531ec55a48cda661f0faf7a29dad6f49296f",
|
|
66
|
-
".claude/skills/cc-toolkit-generator-enhanced/references/templates/start-command.md": "
|
|
68
|
+
".claude/skills/cc-toolkit-generator-enhanced/references/templates/start-command.md": "e037a7e73e65e5216f95f27a255009c4c2b95f0f2d6b7c575d70813efac34438",
|
|
67
69
|
".claude/skills/cc-toolkit-generator-enhanced/SKILL.md": "26fb1a3c0961fbb1f5f7e81ec5134bbe49ba0f99175c394cdf0c6b8a35568be2",
|
|
68
70
|
".claude/skills/explore/references/questioning-techniques.md": "ec0dd00871d3abe950f9cf375216a43043827897166c4165c3fa581839851195",
|
|
69
71
|
".claude/skills/explore/references/task-brief-templates.md": "4e9292479e120afce944b747bb7b4a7226c41e9880708d620de3ea4fa4ef0249",
|
|
70
|
-
".claude/skills/explore/SKILL.md": "
|
|
72
|
+
".claude/skills/explore/SKILL.md": "2473e7961845db0d64566cd42627b374d1830664b9e302058a1b1aa466bc7361",
|
|
71
73
|
".claude/skills/goap-research-ed25519/references/ed25519-verification.md": "2742f14b472bff69c83f24d9bac5bf023bd7f9ecc3e659742ac3152a239dd68f",
|
|
72
74
|
".claude/skills/goap-research-ed25519/references/research-actions.md": "156d2f8ce342f7013bc758fe7c0d3ad3041b4f67f30dbcf8d59e091cb70d9a9c",
|
|
73
75
|
".claude/skills/goap-research-ed25519/references/source-evaluation.md": "d6a19abb6be64dc9e1f539903080029125d2d899da4de3063e75e1afb7e4906f",
|
|
74
|
-
".claude/skills/goap-research-ed25519/scripts/
|
|
75
|
-
".claude/skills/goap-research-ed25519/scripts/
|
|
76
|
-
".claude/skills/goap-research-ed25519/scripts/
|
|
77
|
-
".claude/skills/goap-research-ed25519/
|
|
76
|
+
".claude/skills/goap-research-ed25519/scripts/check_report_evidence.py": "5053e677f11d00b4dd8365a81eafa1d2c961eebd25c33f72b02455573a934a32",
|
|
77
|
+
".claude/skills/goap-research-ed25519/scripts/ed25519_verifier.py": "f4a2ac9e6473201583643fe8abf47560863cec600344dad5c9df06091b4298f5",
|
|
78
|
+
".claude/skills/goap-research-ed25519/scripts/evidence_fetch.py": "5f4d7cb5d6fb3106d64130b6606582eb55a4f633ef969cf7890b1de1c179345b",
|
|
79
|
+
".claude/skills/goap-research-ed25519/scripts/fixture_legacy_v1_fact.json": "e613de4737145cbfb5f349fbf9f1122801ce3508b62c3a18e2e0cba26b9da5b0",
|
|
80
|
+
".claude/skills/goap-research-ed25519/scripts/fixture_legacy_v2_fact.json": "3f552b47c3864e4ff7ae8c72516e98c188592c7f4f7703d09ce88b39f586ad9d",
|
|
81
|
+
".claude/skills/goap-research-ed25519/scripts/fixtures_field_cases.json": "e2ee619732ab4a1b57285e57b4349f96b4158b231a5624e5264fadf69edb8983",
|
|
82
|
+
".claude/skills/goap-research-ed25519/scripts/goap_planner.py": "f5cbf4784106710b363e7f29bfa538b75f488cb25e1c273ae40de9f4c2a6710b",
|
|
83
|
+
".claude/skills/goap-research-ed25519/scripts/learning_bridge.py": "74f8842978ba945ff78c2bd54702415dd87122e61919571e12a19c3cf1e56131",
|
|
84
|
+
".claude/skills/goap-research-ed25519/scripts/population_match.py": "bbd1d3346a6fb75d0e8526cb5d2fc8bc8613bb31ab63ffb0958d436d5e009054",
|
|
85
|
+
".claude/skills/goap-research-ed25519/scripts/risk_statement.py": "320ffece816e875f65624583846f44dc99461f672a0de7cda42be5ddf29d6de5",
|
|
86
|
+
".claude/skills/goap-research-ed25519/scripts/source_tiers.py": "e1aae76fad01693ab35b51466fc4369c04a5ac64230fd307e7b798dc5beeff7a",
|
|
87
|
+
".claude/skills/goap-research-ed25519/scripts/test_ed25519_verifier.py": "dcba1ce538ff946d6928f30a7c5cbcc37fddf712b6181f91f94c76e20c117ac5",
|
|
88
|
+
".claude/skills/goap-research-ed25519/scripts/test_evidence_provenance.py": "292bfcdcc086934905c77f1543d8400ee483166ff3ce26c79bb526c204320dbb",
|
|
89
|
+
".claude/skills/goap-research-ed25519/scripts/test_goap_planner.py": "7942ada069048b7e97bf2b6e920898a58517ccec090069f347399dbf1fc37731",
|
|
90
|
+
".claude/skills/goap-research-ed25519/scripts/test_population_match.py": "f33f72c0ba6305af1644e6b1a7f7635d3f33273344f19c14e7dbd2f819af0e7f",
|
|
91
|
+
".claude/skills/goap-research-ed25519/scripts/test_risk_absolute.py": "ab353db189650551c374cb772ba4a3a6929e3a2618f2f5c112eca4c3f69e46b6",
|
|
92
|
+
".claude/skills/goap-research-ed25519/scripts/test_signature_v3.py": "a04259296df104c9497c7b31d29556cb9a7ad4dd3339cbe3d8d32a4f53950d25",
|
|
93
|
+
".claude/skills/goap-research-ed25519/scripts/test_suite_completeness.py": "727c5d5b0dad215957012276ebc146397178255077e762ed7b88a60d8178d2ab",
|
|
94
|
+
".claude/skills/goap-research-ed25519/SKILL.md": "404cb696d537d29585ec35f97a86173a582cd6fcf8d5f172a4f5bbd75ec971a8",
|
|
78
95
|
".claude/skills/knowledge-extractor/examples/rate-limiting-extraction.md": "fab68772135532aaa7675dfca4ec068cfa68a847f964f872f201f08fb9ee4034",
|
|
79
96
|
".claude/skills/knowledge-extractor/modules/01-agent-review.md": "53883f182c26c710190399a23193cddb4a94b0f35bb42169a353f354aae4083a",
|
|
80
97
|
".claude/skills/knowledge-extractor/modules/02-classify.md": "3b6a59cde451fc89e2e683b7cd35f5535d12cc6072cd40ca35cf7d5f61eb78aa",
|
|
@@ -97,13 +114,13 @@
|
|
|
97
114
|
".claude/skills/pipeline-forge/templates/command-template.md": "b91a4ef084ba542801154c8b1fb2a086a6b404c3f7ee809ceb6ea633e2b55245",
|
|
98
115
|
".claude/skills/pipeline-forge/templates/pipeline-template.md": "952d2e1f050558dacbf86d2b2ad2c9bc671b1ce2809ce430593434998103a27c",
|
|
99
116
|
".claude/skills/pipeline-forge/templates/skill-template.md": "b92775b4d181fc70ae393645999472ddb64f7419392c12d86b4182b49308df65",
|
|
100
|
-
".claude/skills/problem-solver-enhanced/SKILL.md": "
|
|
117
|
+
".claude/skills/problem-solver-enhanced/SKILL.md": "031378aa2e10c98928e35de07d454135e73550cd0c49f0cd886d53e4208d6b9f",
|
|
101
118
|
".claude/skills/requirements-validator/assets/templates/bdd-feature-template.feature": "5b1e47f10447ce574d0eb3917b69e2613b6e3f9c48b30ff5f4cfb57758c99a1d",
|
|
102
119
|
".claude/skills/requirements-validator/references/bdd-patterns.md": "04611a8c52c81f3a6d4fc2f9661ebc56159a125b6fb44a4d18b432e2b82de6e3",
|
|
103
120
|
".claude/skills/requirements-validator/references/invest-criteria.md": "ac6976adf776b9b60c784e1a0f6a0d96dd3332b16f4c12b72d3e59f9325bb626",
|
|
104
|
-
".claude/skills/requirements-validator/references/scoring-system.md": "
|
|
121
|
+
".claude/skills/requirements-validator/references/scoring-system.md": "49afe072f31f5b4f9a33f6b59487244f494b0f5587b6cc10c797c4de59510114",
|
|
105
122
|
".claude/skills/requirements-validator/references/smart-criteria.md": "619a33fdb6bc336872fdf9f1fc91924f8ccd3c2ebef023912124756692b45aef",
|
|
106
|
-
".claude/skills/requirements-validator/SKILL.md": "
|
|
123
|
+
".claude/skills/requirements-validator/SKILL.md": "e50c5269ad181966a81c14ef596946cea67cbf4b8f8f648c90fd66ecad948933",
|
|
107
124
|
".claude/skills/reverse-engineering-unicorn/examples/noom-cjm-example.md": "01d33586e26bf093a57a7a1082bf3bdba3af801bb8348a685c0418f76987a0b0",
|
|
108
125
|
".claude/skills/reverse-engineering-unicorn/examples/noom-module1-example.md": "7009cf2e2624a1254913ad2e1ff554e7ff675358b0b99bc0632f2e12132663a3",
|
|
109
126
|
".claude/skills/reverse-engineering-unicorn/modules/01-intelligence.md": "4af16873637c26baba0d30728748108c79f5b96765de08d54fc65fe1008f4280",
|
|
@@ -116,9 +133,9 @@
|
|
|
116
133
|
".claude/skills/reverse-engineering-unicorn/references/blue-ocean-canvas.md": "9256455b4b0f2c8c5aecb472e69cfbeda38bed8239120b45b46beec27571f8f9",
|
|
117
134
|
".claude/skills/reverse-engineering-unicorn/references/industry-benchmarks.md": "d377f4d9e84b8b65860fb4d20ce67d928f8a8fc8ef333658f88c8c54674eed71",
|
|
118
135
|
".claude/skills/reverse-engineering-unicorn/references/jtbd-canvas.md": "7938e657af631109ca7b4752002c21ac84a7dad3a35cc522be088f814d102773",
|
|
119
|
-
".claude/skills/reverse-engineering-unicorn/SKILL.md": "
|
|
136
|
+
".claude/skills/reverse-engineering-unicorn/SKILL.md": "20d6b667971f9749d091c1d47e2f75df957f259647cbb861ac54174280096c71",
|
|
120
137
|
".claude/skills/sparc-prd-mini/references/sparc-methodology.md": "9c93dafe8149590809ff6b27508d7df52c8efa7f31f8e8f8052b7124a6561fee",
|
|
121
|
-
".claude/skills/sparc-prd-mini/SKILL.md": "
|
|
138
|
+
".claude/skills/sparc-prd-mini/SKILL.md": "50e829635b828b444487e4b04219518a595dbd4b94f91b66fb03ddf4a7b21712",
|
|
122
139
|
".claude/skills/sparc-prd-mini/templates/CLAUDE.md": "9eeb66752cc4dec5c3c3fa5a8f7cfc3dd282f75d245bd36835f690a945b534ed",
|
|
123
140
|
".claude/skills/sparc-prd-mini/templates/prd.md": "7b4497bc76bb421fae7a07ecb46af01e021412180a394a5487a3c3c42dc004b6"
|
|
124
141
|
}
|
|
@@ -44,7 +44,8 @@ function sha256(filePath) {
|
|
|
44
44
|
function main() {
|
|
45
45
|
if (!fs.existsSync(TEMPLATES)) {
|
|
46
46
|
console.error(`[snapshot] templates/ not found at ${TEMPLATES}`);
|
|
47
|
-
console.error('[snapshot]
|
|
47
|
+
console.error('[snapshot] templates/ ships with this package — a missing one means a broken');
|
|
48
|
+
console.error('[snapshot] checkout, not a missing build step. Restore it from git.');
|
|
48
49
|
process.exit(1);
|
|
49
50
|
}
|
|
50
51
|
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// /replicate writes docs/ADR.md in Phase 1 — commands/replicate.md:243, "(if applicable)" — and
|
|
4
|
+
// nothing ever reads it again. A decision could be written down, agreed, and quietly not built.
|
|
5
|
+
//
|
|
6
|
+
// This cannot be a script: MEASURED, `find templates -name '*.mjs' -o -name 'check*.js'` returns
|
|
7
|
+
// nothing — the templates carry no executable gate at all. It is a mandatory prose step held by this
|
|
8
|
+
// test, the shape that shipped for scenario coverage the day before.
|
|
9
|
+
//
|
|
10
|
+
// TWO TRAPS INHERITED VERBATIM from that sibling, both found the expensive way:
|
|
11
|
+
// - PLACEMENT. A step inside the fenced [MANUAL] checkpoint block is skipped by an AUTO run, so a
|
|
12
|
+
// "mandatory" step would run in half of runs. "Precedes the checkpoint text" and "outside the
|
|
13
|
+
// MANUAL-only block" are two different facts and only the second is the property.
|
|
14
|
+
// - BOTH DIRECTIONS. A one-way check lets a reference to a decision nobody wrote read exactly like
|
|
15
|
+
// coverage.
|
|
16
|
+
//
|
|
17
|
+
// WHAT THIS CLAIMS, and the artifact says so itself: a decision is NAMED downstream. NOT that it was
|
|
18
|
+
// implemented — no comparison of identifiers can establish that. The nearest precedent, the K2 gate,
|
|
19
|
+
// records the same limit about its own coverage check in its own source.
|
|
20
|
+
|
|
21
|
+
const { test, describe } = require('node:test');
|
|
22
|
+
const assert = require('node:assert/strict');
|
|
23
|
+
const fs = require('node:fs');
|
|
24
|
+
const path = require('node:path');
|
|
25
|
+
|
|
26
|
+
const REPLICATE = path.join(__dirname, '..', '..', 'templates', '.claude', 'commands',
|
|
27
|
+
'replicate.md');
|
|
28
|
+
const read = () => fs.readFileSync(REPLICATE, 'utf-8');
|
|
29
|
+
|
|
30
|
+
/** Phase 2, from its heading to Phase 3's. */
|
|
31
|
+
function phase2(src) {
|
|
32
|
+
const start = src.indexOf('### Phase 2: VALIDATION');
|
|
33
|
+
const end = src.indexOf('### Phase 3', start + 1);
|
|
34
|
+
assert.ok(start > 0 && end > start, 'replicate.md must have a Phase 2 before Phase 3');
|
|
35
|
+
return { start, end, text: src.slice(start, end) };
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
describe('a recorded decision cannot be quietly left unbuilt (PR-007 G5)', () => {
|
|
39
|
+
test('P1 — the step is INSIDE Phase 2 and OUTSIDE the [MANUAL] checkpoint block', () => {
|
|
40
|
+
const src = read();
|
|
41
|
+
const { text } = phase2(src);
|
|
42
|
+
const step = text.indexOf('**Шаг 2.9 — ПОКРЫТИЕ РЕШЕНИЙ');
|
|
43
|
+
assert.ok(step > 0, 'the coverage step must live inside Phase 2');
|
|
44
|
+
|
|
45
|
+
const checkpoint = text.indexOf('**Checkpoint:**');
|
|
46
|
+
assert.ok(checkpoint > step,
|
|
47
|
+
'and BEFORE the checkpoint, not after it: ' + step + ' vs ' + checkpoint);
|
|
48
|
+
|
|
49
|
+
// The checkpoint's body is a fenced block an AUTO run may skip. The step must not be in it —
|
|
50
|
+
// and this is asserted from the FENCE, not inferred from the ordering above, because those are
|
|
51
|
+
// two different facts and the sibling feature shipped the weaker one first.
|
|
52
|
+
const fenceStart = text.indexOf('```', checkpoint);
|
|
53
|
+
const fenceEnd = text.indexOf('```', fenceStart + 3);
|
|
54
|
+
assert.ok(fenceStart > 0 && fenceEnd > fenceStart, 'the checkpoint must have a fenced body');
|
|
55
|
+
assert.ok(step < fenceStart || step > fenceEnd,
|
|
56
|
+
'the step sits inside the MANUAL-only fenced block, where an AUTO run skips it');
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
test('P2 — the reconciliation runs BOTH ways, and both may say none', () => {
|
|
60
|
+
const { text } = phase2(read());
|
|
61
|
+
assert.match(text, /Recorded but named nowhere:/,
|
|
62
|
+
'decisions nobody mentions must be listed');
|
|
63
|
+
assert.match(text, /Named downstream but absent from docs\/ADR\.md:/,
|
|
64
|
+
'and references matching no decision — without this, a dangling ADR-009 reads as coverage');
|
|
65
|
+
assert.match(text, /Both tables are required, and both may be the single word `none`/,
|
|
66
|
+
'an empty table and a forgotten table look identical');
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
test('P3 — the block is required in EVERY case, including all-covered', () => {
|
|
70
|
+
const { text } = phase2(read());
|
|
71
|
+
assert.match(text, /## Decision Coverage/,
|
|
72
|
+
'the required output block must be named, or "reconcile" is advice');
|
|
73
|
+
assert.match(text, /in every case\*\*, including\s+the one where everything is covered/,
|
|
74
|
+
'an absent block and a block saying "all covered" are indistinguishable to the next reader');
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
test('P4 — three states of the ADR file, each with its own line', () => {
|
|
78
|
+
// Cross-family QE found two defects here. The first version had ONE empty case, so an ADR file
|
|
79
|
+
// that exists but records no ids was unclassified. And its sentence claimed the project "recorded
|
|
80
|
+
// no architectural decisions" — which absence of one FILE cannot establish; decisions may live
|
|
81
|
+
// where this step does not look, and asserting otherwise is a false claim in a generated report.
|
|
82
|
+
const { text } = phase2(read());
|
|
83
|
+
assert.match(text, /Three states of the ADR file/, 'all three must be enumerated');
|
|
84
|
+
assert.match(text, /docs\/ADR\.md is absent, so no decision ids were collected from it/,
|
|
85
|
+
'the absent case must say what is absent — the FILE — and nothing more');
|
|
86
|
+
assert.ok(!/recorded no architectural decisions/.test(text),
|
|
87
|
+
'the step must not claim what it cannot see: decisions may live elsewhere');
|
|
88
|
+
assert.match(text, /exists but records no decision ids/,
|
|
89
|
+
'a present-but-empty ADR is a third state, not the same as an absent file');
|
|
90
|
+
assert.match(text, /In all three states the second table\s*\n?still runs/,
|
|
91
|
+
'a dangling reference is a defect whether or not an ADR file was ever written');
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
test('P7 — the searched files are ENUMERATED, and the two self-defeating ones excluded', () => {
|
|
95
|
+
// The finding that mattered most: "across the SPARC documents" did not exclude docs/ADR.md, whose
|
|
96
|
+
// own headings contain every id — so every decision appeared named and the check passed BY
|
|
97
|
+
// CONSTRUCTION, on any project. And docs/validation-report.md is where this step WRITES, so
|
|
98
|
+
// counting it would let the previous run's output satisfy the next one.
|
|
99
|
+
const { text } = phase2(read());
|
|
100
|
+
assert.match(text, /Where to look, named file by file/,
|
|
101
|
+
'the search set must be enumerated, not described');
|
|
102
|
+
for (const f of ['docs/PRD.md', 'docs/Specification.md', 'docs/Architecture.md']) {
|
|
103
|
+
assert.ok(text.includes(f), 'the search set must name: ' + f);
|
|
104
|
+
}
|
|
105
|
+
assert.match(text, /Two files are EXCLUDED/, 'and the exclusions must be explicit');
|
|
106
|
+
assert.match(text, /the check would pass by construction/,
|
|
107
|
+
'with the reason for excluding the ADR file itself');
|
|
108
|
+
assert.match(text, /the check would start proving itself/,
|
|
109
|
+
'and for excluding the report this step writes');
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
test('P8 — a mention is DEFINED, and a superseded decision has a policy', () => {
|
|
113
|
+
const { text } = phase2(read());
|
|
114
|
+
assert.match(text, /The exact token `ADR-<nnn>`, case-sensitive/,
|
|
115
|
+
'"mention" must be defined, or every reader draws a different line');
|
|
116
|
+
assert.match(text, /Not a title, not a paraphrase/,
|
|
117
|
+
'and what does NOT count must be named too');
|
|
118
|
+
assert.match(text, /A superseded decision needs no current mention/,
|
|
119
|
+
'an id that outlives its decision needs a stated policy, or it reads as a permanent gap');
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
test('P5 — the artifact states its own limit', () => {
|
|
123
|
+
// A coverage block LOOKS like proof of implementation. The backlog item demanded this restraint
|
|
124
|
+
// explicitly, and the limit belongs in the template a reader sees, not only in a feature report.
|
|
125
|
+
const { text } = phase2(read());
|
|
126
|
+
assert.match(text, /It does NOT establish that the decision was implemented/,
|
|
127
|
+
'the limit must be written into the artifact');
|
|
128
|
+
assert.match(text, /the decision was written down and then forgotten/,
|
|
129
|
+
'and the class it DOES catch must be named, so the claim is bounded on both sides');
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
test('P6 — the decision id has a defined form, or there is nothing to trace on', () => {
|
|
133
|
+
const { text } = phase2(read());
|
|
134
|
+
assert.match(text, /`ADR-<nnn>` — three digits, assigned in order, never\s+reused/,
|
|
135
|
+
'an id without a form and a uniqueness rule is an intention, not an identifier');
|
|
136
|
+
});
|
|
137
|
+
});
|