@dzhechkov/p-replicator 1.10.4 → 1.13.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.
Files changed (136) hide show
  1. package/.dz-manifest.json +312 -76
  2. package/CHANGELOG.md +232 -0
  3. package/MULTIPLATFORM_ROADMAP.md +1 -1
  4. package/README/eng/01_quickstart.md +3 -3
  5. package/README/eng/02_user_guide.md +1 -1
  6. package/README/eng/03_admin_guide.md +2 -2
  7. package/README/eng/04_api_reference.md +11 -5
  8. package/README/eng/05_architecture.md +1 -1
  9. package/README/eng/README.md +2 -1
  10. package/README/ru/01_quickstart.md +3 -3
  11. package/README/ru/02_user_guide.md +1 -1
  12. package/README/ru/03_admin_guide.md +2 -2
  13. package/README/ru/04_api_reference.md +11 -5
  14. package/README/ru/05_architecture.md +1 -1
  15. package/README/ru/README.md +2 -1
  16. package/README/ru/html/index.html +9 -9
  17. package/README.md +278 -39
  18. package/package.json +5 -4
  19. package/sbom.json +665 -75
  20. package/scripts/check-pipeline-gaps.sh +413 -0
  21. package/src/commands/doctor.js +94 -4
  22. package/src/commands/init.js +1 -1
  23. package/src/rule-components.json +15 -0
  24. package/src/utils.js +35 -11
  25. package/templates/.claude/agents/harvest-coordinator.md +10 -1
  26. package/templates/.claude/agents/product-discoverer.md +38 -0
  27. package/templates/.claude/agents/replicate-coordinator.md +11 -1
  28. package/templates/.claude/commands/feature.md +81 -9
  29. package/templates/.claude/commands/go.md +9 -0
  30. package/templates/.claude/commands/harvest.md +39 -3
  31. package/templates/.claude/commands/myinsights.md +21 -26
  32. package/templates/.claude/commands/replicate.md +171 -37
  33. package/templates/.claude/commands/start.md +29 -0
  34. package/templates/.claude/hooks/capture-source-path.cjs +795 -0
  35. package/templates/.claude/hooks/check-canon.cjs +493 -0
  36. package/templates/.claude/hooks/check-embed-contract.cjs +374 -0
  37. package/templates/.claude/hooks/check-external-deps.cjs +288 -0
  38. package/templates/.claude/hooks/check-file-ownership.cjs +424 -0
  39. package/templates/.claude/hooks/check-handoff-manifest.cjs +367 -0
  40. package/templates/.claude/hooks/check-job-contract.cjs +501 -0
  41. package/templates/.claude/hooks/check-look-origin.cjs +240 -0
  42. package/templates/.claude/hooks/check-look-trace.cjs +385 -0
  43. package/templates/.claude/hooks/check-metric-source.cjs +296 -0
  44. package/templates/.claude/hooks/check-model-cost.cjs +470 -0
  45. package/templates/.claude/hooks/check-ports.cjs +434 -24
  46. package/templates/.claude/hooks/check-source-version.cjs +312 -0
  47. package/templates/.claude/hooks/check-swarm-receipts.cjs +197 -0
  48. package/templates/.claude/hooks/check-webhook-contract.cjs +535 -0
  49. package/templates/.claude/hooks/session-insights.cjs +158 -25
  50. package/templates/.claude/hooks/statusline.cjs +2 -2
  51. package/templates/.claude/hooks/write-insight.cjs +253 -0
  52. package/templates/.claude/rules/cost-of-detection-ladder.md +96 -0
  53. package/templates/.claude/rules/docker-ports.md +41 -19
  54. package/templates/.claude/rules/embeddable-widget.md +73 -0
  55. package/templates/.claude/rules/feature-lifecycle.md +13 -3
  56. package/templates/.claude/rules/honest-configuration.md +54 -0
  57. package/templates/.claude/rules/incoming-webhooks.md +99 -0
  58. package/templates/.claude/rules/insights-capture.md +10 -5
  59. package/templates/.claude/rules/long-running-job.md +73 -0
  60. package/templates/.claude/rules/model-call-cost.md +85 -0
  61. package/templates/.claude/rules/replicate-pipeline.md +123 -52
  62. package/templates/.claude/rules/skill-interface-protocol.md +1 -0
  63. package/templates/.claude/rules/swarm-file-evidence.md +46 -0
  64. package/templates/.claude/settings.json +13 -1
  65. package/templates/.claude/skills/brutal-honesty-review/SKILL.md +9 -0
  66. package/templates/.claude/skills/cc-toolkit-generator-enhanced/SKILL.md +4 -0
  67. package/templates/.claude/skills/cc-toolkit-generator-enhanced/modules/03-generate-p0.md +46 -1
  68. package/templates/.claude/skills/cc-toolkit-generator-enhanced/modules/04-generate-p1.md +7 -1
  69. package/templates/.claude/skills/cc-toolkit-generator-enhanced/modules/06-package-deliver.md +20 -2
  70. package/templates/.claude/skills/cc-toolkit-generator-enhanced/references/claude-md-strategy.md +7 -0
  71. package/templates/.claude/skills/cc-toolkit-generator-enhanced/references/templates/automation-commands.md +17 -0
  72. package/templates/.claude/skills/cc-toolkit-generator-enhanced/references/templates/feature-lifecycle-ent.md +43 -5
  73. package/templates/.claude/skills/cc-toolkit-generator-enhanced/references/templates/feature-lifecycle.md +43 -7
  74. package/templates/.claude/skills/cc-toolkit-generator-enhanced/references/templates/start-command.md +19 -1
  75. package/templates/.claude/skills/cc-toolkit-generator-enhanced/references/templates/swarm-file-evidence.md +151 -0
  76. package/templates/.claude/skills/goap-research-ed25519/SKILL.md +37 -22
  77. package/templates/.claude/skills/goap-research-ed25519/references/negative-results.md +94 -0
  78. package/templates/.claude/skills/goap-research-ed25519/scripts/check_report_evidence.py +368 -4
  79. package/templates/.claude/skills/goap-research-ed25519/scripts/ed25519_verifier.py +122 -5
  80. package/templates/.claude/skills/goap-research-ed25519/scripts/evidence_fetch.py +33 -16
  81. package/templates/.claude/skills/goap-research-ed25519/scripts/quote_provenance.py +342 -0
  82. package/templates/.claude/skills/goap-research-ed25519/scripts/test_ed25519_verifier.py +60 -0
  83. package/templates/.claude/skills/goap-research-ed25519/scripts/test_evidence_provenance.py +139 -6
  84. package/templates/.claude/skills/goap-research-ed25519/scripts/test_quote_provenance.py +274 -0
  85. package/templates/.claude/skills/goap-research-ed25519/scripts/test_suite_completeness.py +2 -1
  86. package/templates/.claude/skills/knowledge-extractor/SKILL.md +4 -0
  87. package/templates/.claude/skills/knowledge-extractor/modules/01-agent-review.md +16 -5
  88. package/templates/.claude/skills/pipeline-forge/SKILL.md +18 -23
  89. package/templates/.claude/skills/pipeline-forge/examples/replicate-analysis.md +7 -2
  90. package/templates/.claude/skills/pipeline-forge/references/patterns-catalog.md +19 -1
  91. package/templates/.claude/skills/pipeline-forge/references/self-extracted-patterns.md +17 -6
  92. package/templates/.claude/skills/pipeline-forge/references/skill-anatomy.md +0 -1
  93. package/templates/.claude/skills/reverse-engineering-unicorn/modules/025-cjm-prototype.md +21 -1
  94. package/templates/.claude/skills/sparc-prd-mini/SKILL.md +234 -716
  95. package/tests/e2e/lifecycle.test.js +55 -9
  96. package/tests/e2e/packed-insights-writer.test.js +308 -0
  97. package/tests/fixtures/prep-traceability-fixture/docs/features/order-refund/01_specification.md +29 -0
  98. package/tests/fixtures/prep-traceability-fixture/docs/features/order-refund/02_pseudocode.md +57 -0
  99. package/tests/snapshot/baseline.json +72 -46
  100. package/tests/snapshot/templates.test.js +47 -0
  101. package/tests/unit/absence-is-not-emptiness.test.js +15 -1
  102. package/tests/unit/capture-source-path.test.js +492 -0
  103. package/tests/unit/check-canon.test.js +403 -0
  104. package/tests/unit/check-embed-contract.test.js +422 -0
  105. package/tests/unit/check-external-deps.test.js +363 -0
  106. package/tests/unit/check-file-ownership.test.js +388 -0
  107. package/tests/unit/check-handoff-manifest.test.js +410 -0
  108. package/tests/unit/check-job-contract.test.js +514 -0
  109. package/tests/unit/check-look-origin.test.js +180 -0
  110. package/tests/unit/check-look-trace.test.js +420 -0
  111. package/tests/unit/check-metric-source.test.js +325 -0
  112. package/tests/unit/check-model-cost.test.js +425 -0
  113. package/tests/unit/check-pipeline-gaps.test.js +94 -0
  114. package/tests/unit/check-ports.test.js +773 -2
  115. package/tests/unit/check-source-version.test.js +344 -0
  116. package/tests/unit/check-swarm-receipts.test.js +231 -0
  117. package/tests/unit/check-webhook-contract.test.js +536 -0
  118. package/tests/unit/db-port-rule.test.js +43 -6
  119. package/tests/unit/detection-ladder-contract.test.js +302 -0
  120. package/tests/unit/detection-ladder-registry.test.js +52 -0
  121. package/tests/unit/doctor-insight-flow.test.js +315 -0
  122. package/tests/unit/external-dependency-check.test.js +19 -19
  123. package/tests/unit/generator-swarm-contract.test.js +287 -0
  124. package/tests/unit/guard-honest-input-meta.test.js +64 -0
  125. package/tests/unit/honest-failure-rules.test.js +574 -0
  126. package/tests/unit/hooks-project-anchored.test.js +67 -3
  127. package/tests/unit/insights-docs-tell-the-truth.test.js +52 -31
  128. package/tests/unit/insights-dz-delegation.test.js +197 -0
  129. package/tests/unit/insights-writer.test.js +285 -0
  130. package/tests/unit/look-phase-contract.test.js +231 -0
  131. package/tests/unit/negative-conclusion-gate.test.js +300 -0
  132. package/tests/unit/quote-provenance.test.js +122 -0
  133. package/tests/unit/shipped-suite-context.test.js +3 -1
  134. package/tests/unit/traceability-machine-ids.test.js +413 -0
  135. package/tests/unit/traceability-negative-fixture.test.js +322 -0
  136. package/tests/unit/utils.test.js +40 -2
@@ -0,0 +1,274 @@
1
+ #!/usr/bin/env python3
2
+ """Quote-provenance tests, including the ADR-001 red-first A1 fixture."""
3
+
4
+ import sys
5
+
6
+ sys.dont_write_bytecode = True
7
+
8
+ import hashlib
9
+ import io
10
+ import json
11
+ import os
12
+ import tempfile
13
+ import unittest
14
+ from contextlib import redirect_stdout
15
+
16
+ import check_report_evidence as gate
17
+ import evidence_fetch as evidence_fetch
18
+ import quote_provenance as quote_provenance
19
+
20
+
21
+ def _record(body, content_type="text/plain; charset=utf-8"):
22
+ return evidence_fetch.FetchRecord(
23
+ url="https://example.test/source",
24
+ final_url="https://example.test/source",
25
+ status=200,
26
+ sha256_body=hashlib.sha256(body).hexdigest(),
27
+ bytes_len=len(body),
28
+ fetched_at="2026-09-02T00:00:00Z",
29
+ content_type=content_type,
30
+ witness=evidence_fetch._FETCH_WITNESS,
31
+ )
32
+
33
+
34
+ def _fact(quote, body_hash, acquisition="raw-fetch", excerpt_id="excerpt.json"):
35
+ return {
36
+ "claim": quote,
37
+ "source_url": "https://example.test/source",
38
+ "evidence_class": "FETCH_VERIFIED",
39
+ "schema_version": 4,
40
+ "quote": quote,
41
+ "acquisition": acquisition,
42
+ "sha256_body": body_hash,
43
+ "locator": "paragraph 1",
44
+ "excerpt_id": excerpt_id,
45
+ }
46
+
47
+
48
+ def _excerpt(text, body_hash, content_type="text/plain; charset=utf-8"):
49
+ return {
50
+ "sha256_body": body_hash,
51
+ "fetched_at": "2026-09-02T00:00:00Z",
52
+ "source_url": "https://example.test/source",
53
+ "excerpt": text,
54
+ "excerpt_offset": 0,
55
+ "radius_chars": 500,
56
+ "encoding": "utf-8",
57
+ "content_type": content_type,
58
+ "sha256_excerpt": hashlib.sha256(text.encode("utf-8")).hexdigest(),
59
+ }
60
+
61
+
62
+ class QuoteGateRedFirstTests(unittest.TestCase):
63
+ def test_report_quote_absent_from_source_body_is_named_violation(self):
64
+ body = b"The preserved source discusses iron status and recovery."
65
+ excerpt = body.decode("utf-8")
66
+ body_hash = hashlib.sha256(body).hexdigest()
67
+ excerpt_id = "a1.json"
68
+ quote = "The source explicitly recommends immediate supplementation"
69
+ fact = _fact(quote, body_hash, excerpt_id=excerpt_id)
70
+ report = (
71
+ 'The source states "The source explicitly recommends immediate '
72
+ 'supplementation" in its recommendation.'
73
+ )
74
+
75
+ with tempfile.TemporaryDirectory() as tmp:
76
+ with open(os.path.join(tmp, excerpt_id), "w", encoding="utf-8") as handle:
77
+ json.dump(
78
+ _excerpt(excerpt, body_hash),
79
+ handle,
80
+ )
81
+ findings, _ = gate.evaluate_quotes(report, [fact], tmp)
82
+
83
+ report_path = os.path.join(tmp, "report.md")
84
+ facts_path = os.path.join(tmp, "facts.json")
85
+ with open(report_path, "w", encoding="utf-8") as handle:
86
+ handle.write(report)
87
+ with open(facts_path, "w", encoding="utf-8") as handle:
88
+ json.dump([fact], handle)
89
+ output = io.StringIO()
90
+ with redirect_stdout(output):
91
+ exit_code = gate.main([
92
+ "--report", report_path,
93
+ "--facts", facts_path,
94
+ "--excerpts", tmp,
95
+ "--json",
96
+ ])
97
+
98
+ self.assertEqual([finding.kind for finding in findings], ["QUOTE_NOT_IN_SOURCE"])
99
+ self.assertIn(fact["quote"], findings[0].detail)
100
+ self.assertEqual(exit_code, 1)
101
+ payload = json.loads(output.getvalue())
102
+ self.assertIn("QUOTE_NOT_IN_SOURCE", [finding["kind"] for finding in payload["findings"]])
103
+ self.assertEqual(payload["counts"]["quote-not-in-excerpt"], 1)
104
+
105
+ def test_present_control_and_tool_summary_ceiling(self):
106
+ quote = "The source explicitly recommends gradual refeeding"
107
+ body = quote.encode("utf-8")
108
+ body_hash = hashlib.sha256(body).hexdigest()
109
+ excerpt = _excerpt(quote, body_hash)
110
+ with tempfile.TemporaryDirectory() as tmp:
111
+ for excerpt_id in ("present.json", "summary.json"):
112
+ with open(os.path.join(tmp, excerpt_id), "w", encoding="utf-8") as handle:
113
+ json.dump(excerpt, handle)
114
+ present_findings, present_counts = gate.evaluate_quotes(
115
+ f'The report says "{quote}".',
116
+ [_fact(quote, body_hash, excerpt_id="present.json")],
117
+ tmp,
118
+ )
119
+ summary_findings, _ = gate.evaluate_quotes(
120
+ f'The report says "{quote}".',
121
+ [_fact(quote, body_hash, acquisition="tool-summary", excerpt_id="summary.json")],
122
+ tmp,
123
+ )
124
+ self.assertEqual(present_findings, [])
125
+ self.assertEqual(present_counts["quote-verbatim-confirmed"], 1)
126
+ self.assertEqual([finding.kind for finding in summary_findings], ["QUOTE_METHOD_INELIGIBLE"])
127
+ self.assertIn("tool-summary", summary_findings[0].detail)
128
+
129
+
130
+ class QuoteRecordTests(unittest.TestCase):
131
+ def test_closed_acquisition_vocabulary_and_no_writable_verdict(self):
132
+ fields = quote_provenance.QuoteRecord.__dataclass_fields__
133
+ self.assertNotIn("verbatim_status", fields)
134
+ with self.assertRaisesRegex(ValueError, "closed set"):
135
+ quote_provenance.QuoteRecord("valid quote", "Raw-Download", "u", "a" * 64)
136
+ with self.assertRaisesRegex(ValueError, "closed set"):
137
+ quote_provenance.QuoteRecord("valid quote", "webfetch", "u", "a" * 64)
138
+ with self.assertRaisesRegex(ValueError, "non-blank"):
139
+ quote_provenance.QuoteRecord(" ", "raw-fetch", "u", "a" * 64)
140
+
141
+ def test_unknown_or_absent_method_is_honest_fifth_read_state(self):
142
+ for value in (None, "Raw-Fetch", "webfetch", ""):
143
+ with self.subTest(value=value):
144
+ self.assertEqual(quote_provenance.read_acquisition(value), "method-unknown")
145
+
146
+ def test_legacy_quote_is_denied_without_regrading_other_trust_fields(self):
147
+ quote = "A legacy quoted phrase long enough for the gate"
148
+ legacy = {
149
+ "claim": quote,
150
+ "source_url": "https://example.test/legacy",
151
+ "evidence_class": "FETCH_VERIFIED",
152
+ "trust_class": "SELF_ATTESTED",
153
+ "confidence": 0.4,
154
+ "schema_version": 3,
155
+ "quote": quote,
156
+ }
157
+ trust_before = {key: legacy[key] for key in ("evidence_class", "trust_class", "confidence")}
158
+ findings, counts = gate.evaluate_quotes(f'The report says "{quote}".', [legacy], "unused")
159
+ self.assertEqual([finding.kind for finding in findings], ["QUOTE_NO_EXCERPT"])
160
+ self.assertIn("unverified", findings[0].detail)
161
+ self.assertEqual(counts["quote-method-unknown"], 1)
162
+ self.assertEqual(
163
+ {key: legacy[key] for key in ("evidence_class", "trust_class", "confidence")},
164
+ trust_before,
165
+ )
166
+
167
+
168
+ class VerbatimPolicyTests(unittest.TestCase):
169
+ def setUp(self):
170
+ self.text = 'The source says “iron\u00a0status & recovery” — exactly.'
171
+ self.body_hash = hashlib.sha256(self.text.encode("utf-8")).hexdigest()
172
+ self.excerpt = _excerpt(self.text, self.body_hash, "text/html; charset=utf-8")
173
+
174
+ def fact(self, **overrides):
175
+ fact = _fact('iron status & recovery" - exactly', self.body_hash, excerpt_id="x.json")
176
+ fact.update(overrides)
177
+ return fact
178
+
179
+ def test_closed_verdict_set_and_normalized_exact_match(self):
180
+ self.assertEqual(
181
+ quote_provenance.VERBATIM_VERDICTS,
182
+ ("verbatim-confirmed", "not-in-excerpt", "no-excerpt", "method-ineligible",
183
+ "hash-mismatch", "method-unknown"),
184
+ )
185
+ verdict = quote_provenance.verify_verbatim(
186
+ 'iron status & recovery" - exactly', self.excerpt, self.fact()
187
+ )
188
+ self.assertEqual(verdict, "verbatim-confirmed")
189
+
190
+ def test_overlap_paraphrase_does_not_count_as_verbatim(self):
191
+ verdict = quote_provenance.verify_verbatim(
192
+ "iron status recovery was described exactly", self.excerpt, self.fact()
193
+ )
194
+ self.assertEqual(verdict, "not-in-excerpt")
195
+
196
+ def test_search_listing_and_manual_need_the_same_reconciliation(self):
197
+ span = 'iron status & recovery" - exactly'
198
+ for acquisition in ("search-listing", "manual"):
199
+ with self.subTest(acquisition=acquisition):
200
+ self.assertEqual(
201
+ quote_provenance.verify_verbatim(
202
+ span, self.excerpt, self.fact(acquisition=acquisition)
203
+ ),
204
+ "verbatim-confirmed",
205
+ )
206
+ self.assertEqual(
207
+ quote_provenance.verify_verbatim(span, None, self.fact(acquisition=acquisition)),
208
+ "no-excerpt",
209
+ )
210
+
211
+ def test_every_refusal_verdict_is_reachable(self):
212
+ cases = (
213
+ (None, self.fact(), "no-excerpt"),
214
+ (self.excerpt, self.fact(acquisition="tool-summary"), "method-ineligible"),
215
+ (dict(self.excerpt, sha256_excerpt="0" * 64), self.fact(), "hash-mismatch"),
216
+ (self.excerpt, self.fact(acquisition=None), "method-unknown"),
217
+ )
218
+ for excerpt, fact, expected in cases:
219
+ with self.subTest(expected=expected):
220
+ self.assertEqual(quote_provenance.verify_verbatim("anything at all", excerpt, fact), expected)
221
+
222
+ def test_quote_found_only_across_join_of_two_excerpts_is_rejected(self):
223
+ leaves = [
224
+ _excerpt("boundary phrase begins", self.body_hash),
225
+ _excerpt(" and ends here", self.body_hash),
226
+ ]
227
+ verdict = quote_provenance.verify_verbatim(
228
+ "phrase begins and ends", leaves, self.fact()
229
+ )
230
+ self.assertEqual(verdict, "not-in-excerpt", "a JOIN of excerpt leaves is never searched")
231
+
232
+
233
+ class CaptureTests(unittest.TestCase):
234
+ def test_capture_round_trip_is_bounded_and_self_ignoring(self):
235
+ quote = "bounded phrase copied exactly from source bytes"
236
+ body = (("prefix " * 500) + quote + (" suffix" * 500)).encode("utf-8")
237
+ record = _record(body)
238
+ captured = quote_provenance.capture_excerpt(body, quote, record)
239
+ self.assertLessEqual(len(captured["excerpt"]), quote_provenance.EXCERPT_MAX_CHARS)
240
+ self.assertNotEqual(captured["excerpt"].encode("utf-8"), body)
241
+ fact = _fact(quote, record.sha256_body, excerpt_id=captured["excerpt_id"])
242
+ with tempfile.TemporaryDirectory() as tmp:
243
+ path = quote_provenance.write_excerpt(tmp, captured)
244
+ loaded = quote_provenance.load_excerpt(tmp, captured["excerpt_id"])
245
+ self.assertTrue(os.path.exists(os.path.join(tmp, ".gitignore")))
246
+ with open(os.path.join(tmp, ".gitignore"), encoding="utf-8") as handle:
247
+ self.assertEqual(handle.read(), "*\n")
248
+ self.assertEqual(path, os.path.join(tmp, captured["excerpt_id"]))
249
+ self.assertEqual(quote_provenance.verify_verbatim(quote, loaded, fact), "verbatim-confirmed")
250
+
251
+ def test_forged_excerpt_and_wrong_source_body_are_refused(self):
252
+ quote = "captured phrase"
253
+ body = quote.encode("utf-8")
254
+ record = _record(body)
255
+ with self.assertRaisesRegex(quote_provenance.ExcerptCaptureRefused, "hash-mismatch"):
256
+ quote_provenance.capture_excerpt(body + b" forged", quote, record)
257
+ captured = quote_provenance.capture_excerpt(body, quote, record)
258
+ captured["excerpt"] = "author supplied captured phrase"
259
+ fact = _fact(quote, record.sha256_body, excerpt_id=captured["excerpt_id"])
260
+ self.assertEqual(quote_provenance.verify_verbatim(quote, captured, fact), "hash-mismatch")
261
+
262
+ def test_non_text_and_undecodable_bodies_refuse_by_name(self):
263
+ pdf = b"%PDF-1.7 quoted phrase"
264
+ with self.assertRaisesRegex(quote_provenance.ExcerptCaptureRefused, "non-text"):
265
+ quote_provenance.capture_excerpt(pdf, "quoted phrase", _record(pdf, "application/pdf"))
266
+ invalid = b"quoted phrase \xff"
267
+ with self.assertRaisesRegex(quote_provenance.ExcerptCaptureRefused, "undecodable"):
268
+ quote_provenance.capture_excerpt(
269
+ invalid, "quoted phrase", _record(invalid, "text/plain; charset=ascii")
270
+ )
271
+
272
+
273
+ if __name__ == "__main__":
274
+ unittest.main()
@@ -58,7 +58,8 @@ class SuiteCompletenessTests(unittest.TestCase):
58
58
  """The specific omission AM-14 caught, pinned by name so it cannot recur."""
59
59
  collected = _collected()
60
60
  for required in ("test_ed25519_verifier", "test_evidence_provenance", "test_goap_planner",
61
- "test_signature_v3", "test_population_match", "test_risk_absolute"):
61
+ "test_signature_v3", "test_population_match", "test_quote_provenance",
62
+ "test_risk_absolute"):
62
63
  self.assertIn(required, collected)
63
64
 
64
65
  def test_no_enumerated_run_command_is_reintroduced(self):
@@ -138,6 +138,10 @@ Read module: `modules/01-agent-review.md`
138
138
 
139
139
  **Goal:** Find all extractable knowledge in the project using parallel agents.
140
140
 
141
+ Each extractor delivers a FILE at its own absolute `TRACE_PATH` (terminal `Status:` line last),
142
+ never a reply — see `.claude/rules/swarm-file-evidence.md` and the assignment table in
143
+ `modules/01-agent-review.md`. A dead extractor and a working one are both silent.
144
+
141
145
  **Swarm Strategy — 5 parallel extraction agents:**
142
146
 
143
147
  | Agent | Scope | What It Looks For |
@@ -18,6 +18,16 @@ snippets, skills, and hooks that could be reused in other projects.
18
18
  Launch 5 parallel agents via Task tool. Each agent independently scans the codebase
19
19
  from its perspective.
20
20
 
21
+ ### Positive file receipt contract
22
+
23
+ Before dispatch, allocate one `RUN_ID` and give every extraction perspective a unique `WORK_UNIT_ID`
24
+ and absolute `TRACE_PATH`. Each agent must write a substantive raw-findings body ending in
25
+ `Status: completed` or `Status: failed` to `TRACE_PATH` before its one-line pointer. Before the
26
+ Merging Strategy, verify each path is a regular non-symlink file, non-whitespace, post-launch, and
27
+ terminal. Narrative output or silence is not a receipt. Name missing, stale, partial, unreadable,
28
+ duplicate, failed, dead-PID, or probe-error perspectives and refuse synthesis/completion unless every
29
+ required receipt is valid and completed. See `.claude/rules/swarm-file-evidence.md`.
30
+
21
31
  ### Agent: extractor-patterns
22
32
 
23
33
  **Scope:** Architecture and code patterns
@@ -166,11 +176,12 @@ from its perspective.
166
176
 
167
177
  After all 5 agents complete:
168
178
 
169
- 1. **Deduplicate** — same finding reported by multiple agents keep richest description
170
- 2. **Cross-reference** — if a pattern is also a template, note both categories
171
- 3. **Sort by confidence** — HIGH reusability first
172
- 4. **Count** — total findings, per-category breakdown
173
- 5. **Include TOOLKIT_HARVEST.md markers** — merge manual markers with auto-discovered
179
+ 1. **Validate traces** — read findings only from five valid completed `TRACE_PATH` receipts
180
+ 2. **Deduplicate** — same finding reported by multiple agents keep richest description
181
+ 3. **Cross-reference** — if a pattern is also a template, note both categories
182
+ 4. **Sort by confidence** — HIGH reusability first
183
+ 5. **Count** — total findings, per-category breakdown
184
+ 6. **Include TOOLKIT_HARVEST.md markers** — merge manual markers with auto-discovered
174
185
 
175
186
  ## Output: Raw Findings List
176
187
 
@@ -351,17 +351,10 @@ Context flow: [summary]
351
351
  - Use `templates/pipeline-template.md` for the orchestrator
352
352
  - Substitute `{{PLACEHOLDERS}}` with domain-specific content
353
353
 
354
- **Master Validation Checklist:**
355
- - [ ] Every skill has `SKILL.md` with name, description, triggers
356
- - [ ] Every skill has explicit input/output format
357
- - [ ] Every skill has anti-pattern warnings
358
- - [ ] Orchestrator references all skills by correct path
359
- - [ ] Quality gates have scoring systems and verdicts
360
- - [ ] Checkpoints have user commands documented
361
- - [ ] Context flow matches phase ordering
362
- - [ ] Git commits defined for each major phase
363
- - [ ] No circular dependencies in skill graph
364
- - [ ] All templates substituted (no `{{PLACEHOLDER}}` remaining)
354
+ **Master Validation Checklist:** every skill has `SKILL.md` (name/description/triggers), explicit
355
+ input/output format and anti-pattern warnings; orchestrator references correct paths; quality gates
356
+ carry scoring + verdicts; checkpoints document user commands; context flow matches phase order;
357
+ git commits per major phase; no circular dependencies; no `{{PLACEHOLDER}}` left unsubstituted.
365
358
 
366
359
  **Checkpoint:**
367
360
  ```
@@ -403,11 +396,18 @@ When designing pipelines, identify parallelism opportunities and use swarm agent
403
396
  **Swarm Design Pattern:**
404
397
  ```
405
398
  1. DECOMPOSE: Break task into independent subtasks
406
- 2. SPAWN: Launch parallel agents via Task tool
407
- 3. AGGREGATE: Collect results, merge, resolve conflicts
408
- 4. VALIDATE: Cross-check aggregate for consistency
399
+ 2. ASSIGN: One WORK_UNIT_ID + one absolute TRACE_PATH per subtask; record the launch instant
400
+ 3. SPAWN: Launch parallel agents via Task tool, each carrying its assignment
401
+ 4. RECEIPT: node .claude/hooks/check-swarm-receipts.cjs <manifest> (0 ok / 1 undelivered / 2 not run)
402
+ 5. AGGREGATE: Collect results FROM THE FILES, merge, resolve conflicts
403
+ 6. VALIDATE: Cross-check aggregate for consistency
409
404
  ```
410
405
 
406
+ A forged pipeline that skips steps 2 and 4 cannot tell a dead agent from a working one — both are
407
+ silent — so it will report a stage as running when nothing is. See
408
+ `.claude/rules/swarm-file-evidence.md`; the full seam text to paste into the forged pipeline lives
409
+ in `cc-toolkit-generator-enhanced/references/templates/swarm-file-evidence.md` (Section 2).
410
+
411
411
  **Swarm Agent Template:**
412
412
  ```markdown
413
413
  | Agent | Scope | Criteria | Independence |
@@ -467,15 +467,10 @@ Skills written for claude.ai use `/mnt/skills/user/` paths. For Claude Code port
467
467
 
468
468
  ## Anti-Patterns
469
469
 
470
- **Monolithic Skills** — skills with 1000+ lines doing everything
471
- **Implicit Dependencies** skills that assume others exist without declaring
472
- **Skipping Quality Gates** generating toolkit from unvalidated documentation
473
- **Hardcoded Paths** using absolute paths instead of relative/mapped
474
- ❌ **Duplicating Logic** — copying skill content instead of view() references
475
- ❌ **No Checkpoints** — running entire pipeline without user feedback points
476
- ❌ **No Error Recovery** — pipeline that can't resume from a failed phase
477
- ❌ **Over-Engineering** — creating 20 skills when 5 would suffice
478
- ❌ **No Fallbacks** — skills that crash when an optional dependency is missing
470
+ ❌ Monolithic skills (1000+ lines) · implicit undeclared dependencies · skipping quality gates
471
+ (toolkit from unvalidated docs) · hardcoded absolute paths · duplicating logic instead of view() ·
472
+ no checkpoints · no error recovery / resume · over-engineering (20 skills where 5 suffice) ·
473
+ no fallbacks for optional dependencies
479
474
 
480
475
  ## Quality Standards
481
476
 
@@ -140,9 +140,14 @@ Swarm: 5 parallel validators via Task tool
140
140
  ├── validator-pseudocode → Story coverage, implementability
141
141
  └── validator-coherence → Cross-document consistency
142
142
 
143
+ Receipt: per .claude/rules/swarm-file-evidence.md — each validator writes its findings
144
+ to its own absolute TRACE_PATH,
145
+ terminal `Status: completed` / `Status: failed` last, then replies one line.
146
+ Aggregation reads the FILES and refuses to score a validator that delivered none —
147
+ a validator that died is silent exactly like one still working.
143
148
  Scoring: 0-100 per validator
144
- Aggregate: weighted average
145
- Blocking: score <50 = BLOCKED
149
+ Aggregate: weighted average over terminal-completed receipts only
150
+ Blocking: score <50 = BLOCKED; any missing receipt = BLOCKED
146
151
  Iterations: max 3
147
152
 
148
153
  Verdicts:
@@ -199,8 +199,26 @@ UNIFIED RESULT
199
199
  1. **Independence** — swarm agents must not depend on each other (or explicitly declare dependencies)
200
200
  2. **Clear scope** — each agent has a defined scope and criteria
201
201
  3. **Parallel execution** — use Task tool to launch agents concurrently
202
- 4. **Aggregation** — orchestrator merges results, resolves conflicts
202
+ 4. **Aggregation** — orchestrator merges results FROM FILES, resolves conflicts
203
203
  5. **Iterative** — if aggregate fails quality gate, re-run with fixes (max N iterations)
204
+ 6. **Positive file receipt** — every agent's RESULT is a file at a named path, never its reply
205
+
206
+ #### Positive file receipt (required)
207
+
208
+ Before dispatch, allocate one `RUN_ID` and, for every unit, a unique `WORK_UNIT_ID` plus an
209
+ absolute `TRACE_PATH` unique to `(RUN_ID, WORK_UNIT_ID)`; record the launch instant and pass both
210
+ fields to the worker. Each worker must write a substantive body ending in `Status: completed` or
211
+ `Status: failed` to `TRACE_PATH` before it returns its one-line pointer. Before merge, verify every
212
+ path is a regular non-symlink file, non-whitespace, post-launch, and terminal. Narrative output or
213
+ silence is never a receipt. Name missing, stale, partial, unreadable, duplicate, failed, dead-PID,
214
+ or probe-error units and refuse merge, aggregation, or completion until every required receipt is
215
+ valid and completed. Run `node .claude/hooks/check-swarm-receipts.cjs <manifest>` — exit 0 all
216
+ completed, exit 1 undelivered or failed, exit 2 the check did not run. See
217
+ `.claude/rules/swarm-file-evidence.md` for mechanics and the bounded non-atomic-write exception.
218
+
219
+ Why this belongs in the pattern and not in the orchestrator's good intentions: a worker that died
220
+ looks exactly like a worker that is still running, because both are silent. The absence of a
221
+ receipt is indistinguishable from unfinished work and therefore reads as progress.
204
222
 
205
223
  ### Swarm Design Template
206
224
  ```markdown
@@ -206,12 +206,23 @@ OUT: Verdict + score + gap register + iteration count
206
206
  ```
207
207
  IN: Task definition + agent table (scope, criteria, independence, output format)
208
208
  DO: 1. DECOMPOSE into independent subtasks
209
- 2. SPAWN parallel agents via Task tool
210
- 3. Each agent: scoped input -> execute -> structured output
211
- 4. AGGREGATE: collect, deduplicate, resolve conflicts
212
- 5. VALIDATE aggregate for consistency
213
- 6. IF inconsistent: run cross-validation agent (reads all outputs)
214
- OUT: Unified result + conflict resolution notes
209
+ 2. ASSIGN one WORK_UNIT_ID + one absolute TRACE_PATH per subtask; record launch instant
210
+ 3. SPAWN parallel agents via Task tool, each carrying its assignment
211
+ 4. Each agent: scoped input -> execute -> write substantive body + terminal
212
+ `Status: completed` / `Status: failed` to TRACE_PATH -> reply one line
213
+ 5. RECEIPT CHECK before merge: regular, non-symlink, non-whitespace, post-launch, terminal
214
+ (node .claude/hooks/check-swarm-receipts.cjs <manifest>; 0 ok / 1 undelivered / 2 not run)
215
+ 6. AGGREGATE from the files: collect, deduplicate, resolve conflicts
216
+ 7. VALIDATE aggregate for consistency
217
+ 8. IF inconsistent: run cross-validation agent (reads all outputs)
218
+ OUT: Unified result + conflict resolution notes + valid/required receipt ratio
219
+ ```
220
+
221
+ Narrative output and silence are never receipts, and an invalid receipt refuses merge, aggregation
222
+ and completion — a dead agent and a live one are both silent, so only the file separates them. Full
223
+ contract: `.claude/rules/swarm-file-evidence.md`.
224
+
225
+ ```
215
226
  ```
216
227
 
217
228
  **PU Unicorn Example:** `knowledge-extractor` Phase 1 runs 5 agents (extractor-patterns,
@@ -202,7 +202,6 @@ INPUT → PHASE 1 → PHASE 2 → ... → OUTPUT
202
202
  ```markdown
203
203
  ## Anti-Patterns
204
204
 
205
- ❌ [What NOT to do — reason]
206
205
  ❌ [What NOT to do — reason]
207
206
  ```
208
207
 
@@ -144,7 +144,27 @@ const CJM_META = {
144
144
  // Lock result (✅)
145
145
  ```
146
146
 
147
- **Design адаптация под {INDUSTRY}:**
147
+ **Design: откуда берётся облик. Порядок приоритета, и он не симметричен.**
148
+
149
+ Прежде чем открывать таблицу ниже, ответьте на один вопрос: **воспроизводит ли проект НАЗВАННЫЙ
150
+ существующий продукт, и снят ли его облик?**
151
+
152
+ | Состояние источника | Откуда берётся палитра/типографика/тон |
153
+ |---|---|
154
+ | источник назван, облик **СНЯТ** | **из снятого облика источника** — таблица ниже НЕ применяется |
155
+ | источник назван, облик **НЕ ИЗМЕРЕН** (не удалось снять) | таблица ниже — как **ФОЛБЭК**, и он подписывается словом «фолбэк» вместе с причиной, по которой облик не сняли |
156
+ | **источника нет** (продукт не воспроизводится) | таблица ниже — как **ФОЛБЭК** по отрасли, и он тоже подписывается |
157
+
158
+ Почему это не две равноправные ветви. Отраслевая палитра — это догадка о том, как продукт мог бы
159
+ выглядеть. Когда есть живой источник, догадка не «одна из двух опций»: она хуже измерения ровно
160
+ настолько, насколько выдуманное отличается от наблюдённого. Прототип, который тихо подставил
161
+ Emerald, потому что проект про здоровье, читается точно так же, как прототип, у которого Emerald
162
+ измерен у источника — и именно эта неразличимость и есть дефект.
163
+
164
+ Подпись обязательна во всех состояниях, включая «источника нет»: неподписанная палитра и
165
+ подписанная выглядят одинаково для следующего читателя, а значат разное.
166
+
167
+ **Design адаптация под {INDUSTRY} — ФОЛБЭК, применяется только в двух нижних состояниях:**
148
168
 
149
169
  | Industry | Палитра | Иконки | Тон |
150
170
  |----------|---------|--------|-----|