@dzhechkov/p-replicator 1.5.14 → 1.5.16

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
@@ -21,7 +21,7 @@
21
21
  },
22
22
  {
23
23
  "path": "README.md",
24
- "sha256": "2200c141323c375e968bdc053a866bb0be31ff2c1d4c06206729698a4dd57103"
24
+ "sha256": "0093c41c841f82d8fa7ab39c501c7a523656e6a50a0484cdc5f2743dbfc494cc"
25
25
  },
26
26
  {
27
27
  "path": "README/eng/01_quickstart.md",
@@ -109,7 +109,7 @@
109
109
  },
110
110
  {
111
111
  "path": "package.json",
112
- "sha256": "1ac0141d8c9d46838bde096e45af3ad8e514195ae16daa64db87511d1b7a0f2e"
112
+ "sha256": "011685bd583211cceafdd0bdf8687191fc07f1c04fe61383b80199a0b021d60c"
113
113
  },
114
114
  {
115
115
  "path": "scripts/sync-templates.js",
@@ -405,7 +405,7 @@
405
405
  },
406
406
  {
407
407
  "path": "templates/.claude/skills/explore/SKILL.md",
408
- "sha256": "c755a7bcdfe97fb7cb0bcd7bf3b1fd8a2d238ef082967fbf87740fc808302542"
408
+ "sha256": "2473e7961845db0d64566cd42627b374d1830664b9e302058a1b1aa466bc7361"
409
409
  },
410
410
  {
411
411
  "path": "templates/.claude/skills/explore/references/questioning-techniques.md",
@@ -417,7 +417,7 @@
417
417
  },
418
418
  {
419
419
  "path": "templates/.claude/skills/goap-research-ed25519/SKILL.md",
420
- "sha256": "e23770a81922103571eb2645fb82509f7046bc7dd407a33b06f67ad2e709b9b4"
420
+ "sha256": "95459a1566b2f88b6fb0c1d2f096f7631d698b95fa156afa26444a7c06e76451"
421
421
  },
422
422
  {
423
423
  "path": "templates/.claude/skills/goap-research-ed25519/references/ed25519-verification.md",
@@ -431,18 +431,42 @@
431
431
  "path": "templates/.claude/skills/goap-research-ed25519/references/source-evaluation.md",
432
432
  "sha256": "d6a19abb6be64dc9e1f539903080029125d2d899da4de3063e75e1afb7e4906f"
433
433
  },
434
+ {
435
+ "path": "templates/.claude/skills/goap-research-ed25519/scripts/check_report_evidence.py",
436
+ "sha256": "81dfdb14a868c7d0d72a640cfdf8ae3b2b5a453a17fcc1a3396587f3b488a919"
437
+ },
434
438
  {
435
439
  "path": "templates/.claude/skills/goap-research-ed25519/scripts/ed25519_verifier.py",
436
- "sha256": "dc9edc4d7907d13b28dfa74cc86b30a27a41de707ce72f39aca0ae08f07b5703"
440
+ "sha256": "9d0e74bab811a15b5032ec605e66a58081b52129aac873e7402e30b4dc4a2f10"
441
+ },
442
+ {
443
+ "path": "templates/.claude/skills/goap-research-ed25519/scripts/evidence_fetch.py",
444
+ "sha256": "5f4d7cb5d6fb3106d64130b6606582eb55a4f633ef969cf7890b1de1c179345b"
445
+ },
446
+ {
447
+ "path": "templates/.claude/skills/goap-research-ed25519/scripts/fixture_legacy_v1_fact.json",
448
+ "sha256": "e613de4737145cbfb5f349fbf9f1122801ce3508b62c3a18e2e0cba26b9da5b0"
437
449
  },
438
450
  {
439
451
  "path": "templates/.claude/skills/goap-research-ed25519/scripts/goap_planner.py",
440
452
  "sha256": "2ec359e1ddc52ca3118144532ed483dcc609e856a04b29bb191b875c60ff4260"
441
453
  },
454
+ {
455
+ "path": "templates/.claude/skills/goap-research-ed25519/scripts/learning_bridge.py",
456
+ "sha256": "6980dd654d77e296f1ab20a9b7a7c43741fd4125ee44727183c63587421d5503"
457
+ },
458
+ {
459
+ "path": "templates/.claude/skills/goap-research-ed25519/scripts/source_tiers.py",
460
+ "sha256": "e1aae76fad01693ab35b51466fc4369c04a5ac64230fd307e7b798dc5beeff7a"
461
+ },
442
462
  {
443
463
  "path": "templates/.claude/skills/goap-research-ed25519/scripts/test_ed25519_verifier.py",
444
464
  "sha256": "ea6d888ac53bac3a0fe236c101f90a984edbac044d787d73c8414f1c4fc540d3"
445
465
  },
466
+ {
467
+ "path": "templates/.claude/skills/goap-research-ed25519/scripts/test_evidence_provenance.py",
468
+ "sha256": "6825da92d859a299b86bd9bf9910088a95665e0716346e55f0f117d991d25c9b"
469
+ },
446
470
  {
447
471
  "path": "templates/.claude/skills/knowledge-extractor/SKILL.md",
448
472
  "sha256": "ccfd23ead51b710c5197372e82522d17706a1a4e71143bc6f03d80f913bc0a67"
@@ -533,7 +557,7 @@
533
557
  },
534
558
  {
535
559
  "path": "templates/.claude/skills/problem-solver-enhanced/SKILL.md",
536
- "sha256": "530623c986dee931d47314c22195ea9de50a75f2a0daecfc469fb015c3dd3415"
560
+ "sha256": "031378aa2e10c98928e35de07d454135e73550cd0c49f0cd886d53e4208d6b9f"
537
561
  },
538
562
  {
539
563
  "path": "templates/.claude/skills/requirements-validator/SKILL.md",
@@ -561,7 +585,7 @@
561
585
  },
562
586
  {
563
587
  "path": "templates/.claude/skills/reverse-engineering-unicorn/SKILL.md",
564
- "sha256": "ad667aa11254dcd0612689efc3bccd95db537720f5e5846583efe21c631a9375"
588
+ "sha256": "20d6b667971f9749d091c1d47e2f75df957f259647cbb861ac54174280096c71"
565
589
  },
566
590
  {
567
591
  "path": "templates/.claude/skills/reverse-engineering-unicorn/examples/noom-cjm-example.md",
@@ -649,5 +673,5 @@
649
673
  }
650
674
  ]
651
675
  },
652
- "signature": "iMkku8fvUga4J4vXdx0onJvSWAGvEMW5GSOgQ1XSVKeCfgeF3rPfhSRo/mpk4frWQlJLtIhGB2hKDfaPJWavBw=="
676
+ "signature": "ZBgsOmd9A9FQN59phyNUyYikXnGhY+Lnd9eP8/htEuY8VStEwpWjOVlcaXhtZBAsgpQYmCiATKukSoCKT292DQ=="
653
677
  }
package/README.md CHANGED
@@ -25,6 +25,15 @@
25
25
 
26
26
  ---
27
27
 
28
+
29
+ > **`goap-research-ed25519` — self-learning (optional, since this release).** When
30
+ > [`@dzhechkov/harness-cli`](https://www.npmjs.com/package/@dzhechkov/harness-cli) is on PATH, the
31
+ > bundled research skill recalls prior METHOD lessons at the start of an investigation and records new
32
+ > ones at four named moments. Without it the skill behaves exactly as before and says so once — it is
33
+ > detected, never required. A guard refuses to record anything shaped like personal data: a method
34
+ > lesson is written in lower case, carries no digits, and holds no identifier. See
35
+ > `skills/goap-research-ed25519/SKILL.md`.
36
+
28
37
  ## 📚 Documentation in your language
29
38
 
30
39
  | Language | Format | Description |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dzhechkov/p-replicator",
3
- "version": "1.5.14",
3
+ "version": "1.5.16",
4
4
  "description": "P-Replicator — Claude Code toolkit for AI-assisted product development (Vibe Coding). Full /replicate pipeline, 10 modular skills (880K+ chars), /harvest knowledge extraction, swarm agents, quality gates, security patterns, cross-project learning.",
5
5
  "main": "src/cli.js",
6
6
  "bin": {
package/sbom.json CHANGED
@@ -55,7 +55,7 @@
55
55
  "hashes": [
56
56
  {
57
57
  "alg": "SHA-256",
58
- "content": "2200c141323c375e968bdc053a866bb0be31ff2c1d4c06206729698a4dd57103"
58
+ "content": "0093c41c841f82d8fa7ab39c501c7a523656e6a50a0484cdc5f2743dbfc494cc"
59
59
  }
60
60
  ]
61
61
  },
@@ -275,7 +275,7 @@
275
275
  "hashes": [
276
276
  {
277
277
  "alg": "SHA-256",
278
- "content": "1ac0141d8c9d46838bde096e45af3ad8e514195ae16daa64db87511d1b7a0f2e"
278
+ "content": "011685bd583211cceafdd0bdf8687191fc07f1c04fe61383b80199a0b021d60c"
279
279
  }
280
280
  ]
281
281
  },
@@ -1015,7 +1015,7 @@
1015
1015
  "hashes": [
1016
1016
  {
1017
1017
  "alg": "SHA-256",
1018
- "content": "c755a7bcdfe97fb7cb0bcd7bf3b1fd8a2d238ef082967fbf87740fc808302542"
1018
+ "content": "2473e7961845db0d64566cd42627b374d1830664b9e302058a1b1aa466bc7361"
1019
1019
  }
1020
1020
  ]
1021
1021
  },
@@ -1045,7 +1045,7 @@
1045
1045
  "hashes": [
1046
1046
  {
1047
1047
  "alg": "SHA-256",
1048
- "content": "e23770a81922103571eb2645fb82509f7046bc7dd407a33b06f67ad2e709b9b4"
1048
+ "content": "95459a1566b2f88b6fb0c1d2f096f7631d698b95fa156afa26444a7c06e76451"
1049
1049
  }
1050
1050
  ]
1051
1051
  },
@@ -1079,13 +1079,43 @@
1079
1079
  }
1080
1080
  ]
1081
1081
  },
1082
+ {
1083
+ "type": "file",
1084
+ "name": "templates/.claude/skills/goap-research-ed25519/scripts/check_report_evidence.py",
1085
+ "hashes": [
1086
+ {
1087
+ "alg": "SHA-256",
1088
+ "content": "81dfdb14a868c7d0d72a640cfdf8ae3b2b5a453a17fcc1a3396587f3b488a919"
1089
+ }
1090
+ ]
1091
+ },
1082
1092
  {
1083
1093
  "type": "file",
1084
1094
  "name": "templates/.claude/skills/goap-research-ed25519/scripts/ed25519_verifier.py",
1085
1095
  "hashes": [
1086
1096
  {
1087
1097
  "alg": "SHA-256",
1088
- "content": "dc9edc4d7907d13b28dfa74cc86b30a27a41de707ce72f39aca0ae08f07b5703"
1098
+ "content": "9d0e74bab811a15b5032ec605e66a58081b52129aac873e7402e30b4dc4a2f10"
1099
+ }
1100
+ ]
1101
+ },
1102
+ {
1103
+ "type": "file",
1104
+ "name": "templates/.claude/skills/goap-research-ed25519/scripts/evidence_fetch.py",
1105
+ "hashes": [
1106
+ {
1107
+ "alg": "SHA-256",
1108
+ "content": "5f4d7cb5d6fb3106d64130b6606582eb55a4f633ef969cf7890b1de1c179345b"
1109
+ }
1110
+ ]
1111
+ },
1112
+ {
1113
+ "type": "file",
1114
+ "name": "templates/.claude/skills/goap-research-ed25519/scripts/fixture_legacy_v1_fact.json",
1115
+ "hashes": [
1116
+ {
1117
+ "alg": "SHA-256",
1118
+ "content": "e613de4737145cbfb5f349fbf9f1122801ce3508b62c3a18e2e0cba26b9da5b0"
1089
1119
  }
1090
1120
  ]
1091
1121
  },
@@ -1099,6 +1129,26 @@
1099
1129
  }
1100
1130
  ]
1101
1131
  },
1132
+ {
1133
+ "type": "file",
1134
+ "name": "templates/.claude/skills/goap-research-ed25519/scripts/learning_bridge.py",
1135
+ "hashes": [
1136
+ {
1137
+ "alg": "SHA-256",
1138
+ "content": "6980dd654d77e296f1ab20a9b7a7c43741fd4125ee44727183c63587421d5503"
1139
+ }
1140
+ ]
1141
+ },
1142
+ {
1143
+ "type": "file",
1144
+ "name": "templates/.claude/skills/goap-research-ed25519/scripts/source_tiers.py",
1145
+ "hashes": [
1146
+ {
1147
+ "alg": "SHA-256",
1148
+ "content": "e1aae76fad01693ab35b51466fc4369c04a5ac64230fd307e7b798dc5beeff7a"
1149
+ }
1150
+ ]
1151
+ },
1102
1152
  {
1103
1153
  "type": "file",
1104
1154
  "name": "templates/.claude/skills/goap-research-ed25519/scripts/test_ed25519_verifier.py",
@@ -1109,6 +1159,16 @@
1109
1159
  }
1110
1160
  ]
1111
1161
  },
1162
+ {
1163
+ "type": "file",
1164
+ "name": "templates/.claude/skills/goap-research-ed25519/scripts/test_evidence_provenance.py",
1165
+ "hashes": [
1166
+ {
1167
+ "alg": "SHA-256",
1168
+ "content": "6825da92d859a299b86bd9bf9910088a95665e0716346e55f0f117d991d25c9b"
1169
+ }
1170
+ ]
1171
+ },
1112
1172
  {
1113
1173
  "type": "file",
1114
1174
  "name": "templates/.claude/skills/knowledge-extractor/SKILL.md",
@@ -1335,7 +1395,7 @@
1335
1395
  "hashes": [
1336
1396
  {
1337
1397
  "alg": "SHA-256",
1338
- "content": "530623c986dee931d47314c22195ea9de50a75f2a0daecfc469fb015c3dd3415"
1398
+ "content": "031378aa2e10c98928e35de07d454135e73550cd0c49f0cd886d53e4208d6b9f"
1339
1399
  }
1340
1400
  ]
1341
1401
  },
@@ -1405,7 +1465,7 @@
1405
1465
  "hashes": [
1406
1466
  {
1407
1467
  "alg": "SHA-256",
1408
- "content": "ad667aa11254dcd0612689efc3bccd95db537720f5e5846583efe21c631a9375"
1468
+ "content": "20d6b667971f9749d091c1d47e2f75df957f259647cbb861ac54174280096c71"
1409
1469
  }
1410
1470
  ]
1411
1471
  },
@@ -10,7 +10,7 @@ description: >
10
10
  provide solutions until task is fully explored.
11
11
  trust_tier: 1
12
12
  trust_tier_label: "Structured"
13
- trust_tier_path: "Run /bto-test to promote to Tier 2"
13
+ trust_tier_path: "Run a BTO evaluation (see the skills-bto package) to promote to Tier 2"
14
14
  ---
15
15
 
16
16
  # Explore: Adaptive Task Clarification
@@ -3,7 +3,7 @@ name: goap-research-ed25519
3
3
  description: GOAP research system with Ed25519 provenance and tamper-evidence under pinned trusted-issuer keys. Use for high-stakes research that needs cited sources, explicit confidence, signed audit trails, or cryptographic proof of who signed a fact. Ed25519 does not prove truthfulness or prevent hallucination.
4
4
  trust_tier: 1
5
5
  trust_tier_label: "Structured"
6
- trust_tier_path: "Run /bto-test to promote to Tier 2"
6
+ trust_tier_path: "Run a BTO evaluation (see the skills-bto package) to promote to Tier 2"
7
7
  ---
8
8
 
9
9
  # GOAP Research with Ed25519 Provenance
@@ -28,6 +28,107 @@ Ed25519 provides cryptographic provenance and tamper-evidence under pinned trust
28
28
  | `SELF_ATTESTED` | Researcher signature verifies against the embedded researcher key | The research record was not altered after self-signing | up to `0.60` |
29
29
  | `UNVERIFIED` | Unknown issuer, missing pin, revoked key, key mismatch, malformed key, or invalid signature | No cryptographic provenance | `0.0` |
30
30
 
31
+ ## Evidence Classes — the second, independent axis
32
+
33
+ Trust classes answer **"was this record altered after signing?"**. They say nothing about whether
34
+ anyone opened the source. That second question caused every content error in real operation, so it
35
+ gets its own axis. A fact can be `ISSUER_SIGNED` **and** `ASSERTED` — a cryptographically perfect
36
+ record of something recited from memory. That combination is legal, expressible, and the dangerous one.
37
+
38
+ | Evidence class | Requirement | What it proves | Ceiling |
39
+ |---|---|---|---|
40
+ | `FETCH_VERIFIED` | `evidence_fetch.fetch_source()` performed the request and got a 2xx body | This script issued an HTTP request and received a body with this byte hash on this date | `1.0` |
41
+ | `LISTING_ONLY` | URL known from a listing, or a body supplied by hand, or the fetch failed | The URL is known; nobody opened it through this tool | `0.50` |
42
+ | `ASSERTED` | Stated from model memory, source never opened | Nothing about the source | `0.0` |
43
+ | *(absent)* | Fact predates this axis | Evidence is **unknown** — neither asserted nor verified | no ceiling of its own |
44
+
45
+ **`FETCH_VERIFIED` cannot be self-declared.** It is minted only by `create_fetched_fact()`, which
46
+ requires a `FetchRecord` — the byte hash, HTTP status and date of a request that actually happened.
47
+ The manual constructors (`create_listing_fact`, `create_asserted_fact`) have no way to produce it.
48
+ The restriction lives in the API shape, not in the author's discipline.
49
+
50
+ **Honest scope of `FETCH_VERIFIED`:** it means the bytes were received. It does **not** mean the
51
+ source is authoritative, that the claim follows from it, or that the reader understood it.
52
+ Provenance, not truth.
53
+
54
+ ### The report gate
55
+
56
+ ```bash
57
+ python3 scripts/check_report_evidence.py --report report.md --facts facts.json
58
+ ```
59
+
60
+ `ASSERTED` claims must not appear in a report at all. `LISTING_ONLY` claims may appear only with a
61
+ visible marker next to the claim. This is an exit code, not advice — exit `1` on violation, exit `2`
62
+ when the inputs cannot be read (a gate that could not evaluate has cleared nothing).
63
+
64
+ ## Self-learning (optional — needs `dz` on PATH)
65
+
66
+ The most valuable signal in research is the moment a conclusion turned out to be
67
+ WRONG. `scripts/learning_bridge.py` records those as METHOD lessons in the shared
68
+ `dz` store and replays them at the start of the next investigation.
69
+
70
+ ```bash
71
+ python3 scripts/learning_bridge.py status # is the loop on at all?
72
+ python3 scripts/learning_bridge.py recall "transferrin saturation" # traps already caught
73
+ python3 scripts/learning_bridge.py teach "total testosterone is uninterpretable without SHBG"
74
+ python3 scripts/learning_bridge.py check "<candidate>" # privacy guard alone
75
+ ```
76
+
77
+ **Recall at the START of an investigation** — before interpreting anything, ask what
78
+ this analyte has already fooled us with. **Teach at four moments**, not at random:
79
+
80
+ | Moment | Why it is the signal |
81
+ |---|---|
82
+ | a conclusion was RETRACTED | the single most valuable lesson available |
83
+ | a population check flipped a conclusion | the effect did not transfer, and now we know the shape |
84
+ | a preanalytical finding explained an alarming value | the value was an artifact; the rule generalises |
85
+ | an open question was closed | the answer, not the waiting |
86
+
87
+ **PRIVACY IS AN INVARIANT, NOT A PREFERENCE.** A lesson describes a METHOD, never a
88
+ person. `teach` REFUSES the wrong shape before any store is touched:
89
+
90
+ ```
91
+ good "a fast lowers total testosterone by roughly a third, LH down, FSH normal"
92
+ bad "testosterone 8.04 nmol/l in this patient turned out to be a fasting artifact"
93
+ bad "John Smith has HIV" — a capitalised word after the first is refused
94
+ ```
95
+
96
+ The accepted form has three properties, all checkable: **no digits** (spelled-out
97
+ values count — `eight point zero four` is a value), **no identifiers**, and **lower
98
+ case** after the first word. The last one replaced an attempt to detect names: a name
99
+ is any word, no list of them exists, and the attempt let `John Smith has HIV` through.
100
+ Lower case costs a keystroke and closes that hole. Acronyms are unaffected — a token
101
+ passes if it is fully upper (`SHBG`, `TSH`) or opens lower (`apoB`, `mmHg`); only Title
102
+ Case is refused, because Title Case is the shape of a name. A token mixing letters with
103
+ a long digit run (`ab1234567`, `NCT04368728`) is an identifier and is refused however it
104
+ is punctuated, while a short lab acronym carrying a digit (`hba1c`) is not.
105
+
106
+ Pass `--allow-numbers` when the number IS the knowledge (a guideline threshold) and
107
+ you take responsibility for it. It never waves through a person beside a number.
108
+
109
+ The refusal is not bureaucracy — the method form is the more useful lesson: a reading
110
+ helps once, a rule helps every time. Honest scope: this is a SHAPE detector, not a
111
+ de-identifier. A lower-case sentence that names nobody and quotes no figure can still
112
+ describe one person, and no regular expression can see that. The shape rule plus the
113
+ four METHOD moments is what keeps the store clean; the guard alone is not a guarantee.
114
+
115
+ Without `dz` installed the package behaves exactly as before and says so once. An
116
+ older `dz` does **not** reject `--domain` — it ignores the flag and exits 0 — so recall
117
+ makes ONE call and detects the older CLI by the ABSENCE of the boost note in the
118
+ output, then states that results may mix other domains. A degraded loop that says so
119
+ beats a silent one. A real failure (non-zero exit) is reported as itself: proceeding
120
+ without prior lessons, never as "your CLI is old".
121
+
122
+ ## Source Tiers
123
+
124
+ `source_tiers.classify_source(url)` assigns a class ceiling: A `0.90` (guideline bodies, WHO,
125
+ registries) · B `0.80` (peer-reviewed literature) · C `0.60` (preprints, trial registries) ·
126
+ D `0.40` (everything else, including unknown domains). A tier is a claim about the CLASS a domain
127
+ belongs to — it is **not** a cryptographic statement and must never be confused with issuer pinning.
128
+
129
+ `source_tiers.is_stale(source_date, kind)` flags sources past their TTL. A **missing** `source_date`
130
+ is flagged too: freshness that cannot be established is not freshness.
131
+
31
132
  ## Signed Message
32
133
 
33
134
  `sign_fact()` and `verify_fact()` use the same deterministic JSON message containing:
@@ -39,6 +140,16 @@ Ed25519 provides cryptographic provenance and tamper-evidence under pinned trust
39
140
  - `timestamp`
40
141
  - optional `research_context` / nonce
41
142
 
143
+ **Schema v2** additionally covers `evidence_class`, `fetch_date` and `source_date`, plus a
144
+ `"schema": "fact-v2"` self-description marker. Version is chosen by the presence of
145
+ `evidence_class`: legacy facts keep verifying against the six-field v1 message forever.
146
+
147
+ Because the three evidence fields are part of the signed text, **both** tamper directions fail:
148
+ stripping `evidence_class` makes the verifier build the v1 text, which no longer matches the signed
149
+ v2 text; adding it to a legacy fact makes it build the v2 text, which does not match the signed v1
150
+ text. (The marker is self-description and the growth point for a future v3 — it is not itself the
151
+ protection; a discrimination run proved that.)
152
+
42
153
  Changing the issuer or moving the source URL after signing invalidates the signature. The code signs the raw canonical message bytes; Ed25519 performs its own internal hashing. Do not pre-hash with SHA-512 before signing.
43
154
 
44
155
  ## Pinned Issuers
@@ -77,25 +188,43 @@ Reordering, substituting, editing, relabeling, or moving a signed fact fails ver
77
188
  ## Confidence Formula
78
189
 
79
190
  ```
80
- confidence =
81
- 0.0 if UNVERIFIED
82
- <=0.60 if SELF_ATTESTED
83
- min(0.95, base_by_source_level * recency_factor) if ISSUER_SIGNED
191
+ confidence = min(
192
+ trust_ceiling, # UNVERIFIED 0.0 · SELF_ATTESTED 0.60 · ISSUER_SIGNED 0.95
193
+ evidence_ceiling, # FETCH_VERIFIED 1.0 · LISTING_ONLY 0.50 · ASSERTED 0.0 · absent → no cap
194
+ tier_ceiling, # A 0.90 · B 0.80 · C 0.60 · D 0.40
195
+ )
84
196
  ```
85
197
 
198
+ The **weakest link decides**, never the average. An `ISSUER_SIGNED` fact that nobody read is capped
199
+ at `0.0` by its evidence class — which is the whole point of the second axis.
200
+
86
201
  Invalid signatures are rejected with confidence `0.0`; they are never a recoverable `0.5` penalty.
87
202
 
88
203
  ## Research Workflow
89
204
 
90
205
  1. Define the research goal and required evidence threshold.
91
206
  2. Configure pinned issuer keys when issuer-grade provenance is required.
92
- 3. Search and fetch sources.
207
+ 3. Search and locate candidate sources.
93
208
  4. Extract claims and source URLs.
94
- 5. Hash source content with SHA-256 for `source_hash`.
95
- 6. Create self-attested facts for the research ledger or issuer-signed facts when a pinned issuer key actually signed the message.
209
+ 5. **Fetch each source through the tool, not by hand:**
210
+ ```python
211
+ from evidence_fetch import fetch_source, FetchRecord
212
+ record = fetch_source(url) # real HTTP, stdlib only
213
+ if isinstance(record, FetchRecord):
214
+ fact = verifier.create_fetched_fact(claim, record, issuer, source_date="2024-03-01")
215
+ else: # offline, 404, oversize, refused scheme…
216
+ fact = verifier.create_listing_fact(claim, url, reason=record.reason)
217
+ ```
218
+ A claim you never opened a source for is `verifier.create_asserted_fact(claim)` — record it
219
+ honestly and let the gate refuse it. Never hand-label a class you did not earn.
220
+ 6. Add facts to the research ledger; issuer-signed facts only when a pinned issuer key actually
221
+ signed the message.
96
222
  7. Verify facts and citation chains.
97
223
  8. Cross-check claims through ordinary source evaluation.
98
- 9. Report confidence, unsigned claims, rejected signatures, and limitations explicitly.
224
+ 9. **Run the report gate before delivering:**
225
+ `python3 scripts/check_report_evidence.py --report <report.md> --facts <facts.json>` — exit 0 required.
226
+ 10. Report confidence, evidence-class mix, unsigned claims, rejected signatures, and limitations
227
+ explicitly.
99
228
 
100
229
  ## Output Expectations
101
230
 
@@ -103,10 +232,14 @@ Reports should include:
103
232
 
104
233
  - Research objective and GOAP plan executed.
105
234
  - Findings with source URLs.
106
- - Verification status per claim (`ISSUER_SIGNED`, `SELF_ATTESTED`, or `UNVERIFIED`).
235
+ - Verification status per claim on BOTH axes: trust (`ISSUER_SIGNED` / `SELF_ATTESTED` /
236
+ `UNVERIFIED`) and evidence (`FETCH_VERIFIED` / `LISTING_ONLY` / `ASSERTED` / unknown-legacy).
237
+ - The evidence-class mix as a count — the share of `ASSERTED` should be zero.
238
+ - A visible marker next to every `LISTING_ONLY` claim ("source not opened directly — verify").
107
239
  - Chain integrity result when citation chains are used.
108
240
  - Unsigned and rejected claims.
109
- - Explicit caveat that cryptographic provenance is not truth verification.
241
+ - Explicit caveat that cryptographic provenance is not truth verification, and that
242
+ `FETCH_VERIFIED` means the bytes arrived — not that the source is right.
110
243
 
111
244
  ## Implementation
112
245