@dzhechkov/skills-bto 1.1.0 → 1.2.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/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@dzhechkov/skills-bto",
3
- "version": "1.1.0",
4
- "description": "Build-Test-Optimize skill pack for Claude Code — structured BTO pipeline with quality gates, testing strategies, and optimization workflows",
3
+ "version": "1.2.0",
4
+ "description": "Build-Test-Optimize skill pack for Claude Code — structured BTO pipeline with quality gates, witness chain verification, judge attestation, and optimization workflows",
5
5
  "main": "src/cli.js",
6
6
  "bin": {
7
7
  "skills-bto": "./bin/cli.js"
@@ -39,5 +39,13 @@
39
39
  "homepage": "https://github.com/dzhechko/product-keysarium-2026#readme",
40
40
  "bugs": {
41
41
  "url": "https://github.com/dzhechko/product-keysarium-2026/issues"
42
+ },
43
+ "peerDependencies": {
44
+ "@dzhechkov/keysarium-core": "^1.0.0"
45
+ },
46
+ "peerDependenciesMeta": {
47
+ "@dzhechkov/keysarium-core": {
48
+ "optional": true
49
+ }
42
50
  }
43
51
  }
package/src/utils.js CHANGED
@@ -320,6 +320,12 @@ const COMPONENTS = {
320
320
  group: 'core',
321
321
  filter: 'bto',
322
322
  },
323
+ shards: {
324
+ src: '.claude/shards',
325
+ label: 'BTO Context Shards (1)',
326
+ group: 'core',
327
+ filter: 'bto',
328
+ },
323
329
  };
324
330
 
325
331
  // ===========================================================================
@@ -0,0 +1,168 @@
1
+ # /verify-chain — Witness Chain and Judge Attestation Verification
2
+
3
+ > Verify the integrity of SHA-256 witness chains and BTO judge attestation chains.
4
+
5
+ ## Usage
6
+
7
+ ```
8
+ /verify-chain [path] — Verify a specific research directory
9
+ /verify-chain all — Verify all research directories
10
+ ```
11
+
12
+ ## Arguments
13
+
14
+ - `path`: Path to a research directory (e.g., `researches/bank_kc_automation/`) or `"all"` to scan all directories under `researches/`.
15
+
16
+ $ARGUMENTS
17
+
18
+ ## Protocol
19
+
20
+ ### Step 1: Parse Arguments and Discover Targets
21
+
22
+ Determine which directories to verify:
23
+
24
+ ```bash
25
+ TARGET="$ARGUMENTS"
26
+
27
+ if [ "${TARGET}" = "all" ]; then
28
+ # Find all research directories
29
+ DIRS=$(find researches/ -mindepth 1 -maxdepth 1 -type d 2>/dev/null)
30
+ if [ -z "${DIRS}" ]; then
31
+ echo "No research directories found under researches/"
32
+ exit 0
33
+ fi
34
+ else
35
+ # Single directory
36
+ DIRS="${TARGET}"
37
+ if [ ! -d "${TARGET}" ]; then
38
+ echo "ERROR: Directory '${TARGET}' not found"
39
+ exit 1
40
+ fi
41
+ fi
42
+ ```
43
+
44
+ ### Step 2: Load Protocols
45
+
46
+ Read the witness chain and judge attestation protocols for reference:
47
+
48
+ ```
49
+ Read: lib/witness-chain.md
50
+ Read: lib/judge-attestation.md
51
+ ```
52
+
53
+ ### Step 3: Verify Each Directory
54
+
55
+ For each target directory, perform two verification passes:
56
+
57
+ #### Pass A: Witness Chain Verification
58
+
59
+ 1. Check if `.witness-chain.json` exists in the directory
60
+ 2. If not found: report `NOT_FOUND` for this directory (not an error — chain may not have been enabled)
61
+ 3. If found:
62
+ a. Parse the JSON file
63
+ b. Detect platform SHA-256 command (`sha256sum` or `shasum -a 256`)
64
+ c. For each record in the chain:
65
+ - Read the artifact file
66
+ - If file missing: record FAIL with "artifact file not found"
67
+ - Compute the chained hash: `SHA-256(file_content + previous_hash)`
68
+ - For sequence 0: previous_hash = NULL_HASH (64 zeros)
69
+ - For sequence N: previous_hash = chain[N-1].hash (without "sha256:" prefix)
70
+ - Compare computed hash with stored hash
71
+ - If match: record PASS
72
+ - If mismatch: record FAIL with expected vs actual hash
73
+ d. Verify sequence numbers are contiguous (0, 1, 2, ...)
74
+ e. Verify timestamps are chronologically ordered
75
+
76
+ #### Pass B: Judge Attestation Verification
77
+
78
+ 1. Check if `.judge-attestations.json` exists in the directory
79
+ 2. If not found: skip (attestations are optional — only present if BTO was run)
80
+ 3. If found:
81
+ a. Parse the JSON file
82
+ b. For each evaluation round:
83
+ - Verify `artifact_hash` by recomputing SHA-256 of the artifact file (if file path available)
84
+ - For each attestation:
85
+ - Reconstruct evaluation_hash from: `judge_id|artifact_hash|score|rationale_summary`
86
+ - Compare reconstructed hash with stored `evaluation_hash`
87
+ - Verify `previous_attestation_hash` matches the preceding attestation's `evaluation_hash`
88
+ - Verify timestamp is after the preceding attestation's timestamp
89
+ - Report isolation status (all hashes valid = isolation confirmed)
90
+
91
+ ### Step 4: Produce Verification Report
92
+
93
+ Display a formatted report for each directory:
94
+
95
+ ```
96
+ ===============================================================
97
+ WITNESS CHAIN VERIFICATION REPORT
98
+ ===============================================================
99
+
100
+ Directory: researches/bank_kc_automation/
101
+
102
+ --- Artifact Chain ---
103
+ [PASS] #0 phase-0 00_product_discovery.md
104
+ [PASS] #1 phase-1 01_case_brief.md
105
+ [PASS] #2 phase-2 02_research_findings.md
106
+ [FAIL] #3 phase-2.5 02.5_trend_brief.md
107
+ Expected: sha256:abc123...
108
+ Actual: sha256:def456...
109
+ >> Artifact may have been modified after checkpoint
110
+ [SKIP] #4 phase-3 03_solution_strategy.md (upstream chain broken)
111
+
112
+ Chain Status: BROKEN at record #3
113
+ Verified: 3/5 records
114
+
115
+ --- Judge Attestations ---
116
+ Evaluation: bto-eval-2026-03-01T12:00:00Z
117
+ [PASS] domain-expert score=8.2 hash verified
118
+ [PASS] critic score=7.5 hash verified, chain link valid
119
+ [PASS] completeness-auditor score=8.0 hash verified, chain link valid
120
+
121
+ Isolation Status: CONFIRMED
122
+ All 3 judges evaluated independently.
123
+
124
+ ===============================================================
125
+ SUMMARY
126
+ ===============================================================
127
+
128
+ Directories verified: 1
129
+ PASS: 0
130
+ FAIL: 1 (broken chain in bank_kc_automation)
131
+ NOT_FOUND: 0
132
+
133
+ Attestation sets verified: 1
134
+ Isolation confirmed: 1
135
+ Isolation violated: 0
136
+
137
+ ===============================================================
138
+ ```
139
+
140
+ ### Step 5: Handle Edge Cases
141
+
142
+ | Scenario | Behavior |
143
+ |----------|----------|
144
+ | No `.witness-chain.json` in directory | Report NOT_FOUND, do not treat as error |
145
+ | Empty chain (no records) | Report WARNING: "Chain exists but contains no records" |
146
+ | Artifact file deleted | Report FAIL: "Artifact file not found" |
147
+ | Invalid JSON | Report FAIL: "Chain file corrupted — invalid JSON" |
148
+ | `sha256sum` not available | Try `shasum -a 256`, if also missing report ERROR |
149
+ | Directory does not exist | Report ERROR: "Directory not found" |
150
+ | Chain has gaps in sequence numbers | Report WARNING: "Non-contiguous sequence numbers" |
151
+ | Timestamps not monotonic | Report WARNING: "Timestamps not in chronological order" |
152
+
153
+ ### Step 6: Summary and Recommendations
154
+
155
+ After all directories are verified, provide actionable recommendations:
156
+
157
+ - If a chain is broken: "Run the pipeline phase again to re-hash from the modified artifact forward"
158
+ - If attestation isolation is violated: "Review the BTO evaluation process — judges may have shared context"
159
+ - If no chains found: "Witness chains are created automatically during the /casarium pipeline when witness-chain rules are active"
160
+
161
+ ## Quality Gates
162
+
163
+ - [ ] All target directories scanned
164
+ - [ ] Each record verified with hash recomputation (not just format check)
165
+ - [ ] Broken links reported with specific artifact name and hash values
166
+ - [ ] Judge attestation isolation checked (if attestations present)
167
+ - [ ] Clear summary with pass/fail counts
168
+ - [ ] Actionable recommendations provided for failures
@@ -0,0 +1,153 @@
1
+ # Witness Chain Integration Rules
2
+
3
+ ## Purpose
4
+
5
+ These rules define when and how SHA-256 witness records and BTO judge attestations are created during the Keysarium pipeline. They integrate with the existing checkpoint protocol and BTO quality gates.
6
+
7
+ ## Rule 1: Witness Record at Every Phase Checkpoint
8
+
9
+ **WHEN:** A phase checkpoint is reached and the phase artifact has been created.
10
+ **THEN:** Create a witness record before displaying the checkpoint banner.
11
+
12
+ ### Procedure
13
+
14
+ 1. After creating the phase artifact file, compute its witness record
15
+ 2. If this is Phase 0 (first phase): create genesis record in `.witness-chain.json`
16
+ 3. If this is Phase 1+: append record to existing `.witness-chain.json`
17
+ 4. Include the witness hash in the checkpoint banner
18
+
19
+ ### Integration with Checkpoint Format
20
+
21
+ The checkpoint banner gains a witness hash line:
22
+
23
+ ```
24
+ =============================================================
25
+ CHECKPOINT N: [Phase Name] Complete
26
+ <promise>[PROMISE_TAG]</promise>
27
+ Witness: sha256:<hash> (chain link #N)
28
+
29
+ [2-3 line summary of what was done]
30
+ Files created: [list]
31
+
32
+ * "ok" -- next phase
33
+ * "углуби [section]" -- elaborate
34
+ * "[specific feedback]" -- adjust
35
+ =============================================================
36
+ ```
37
+
38
+ ## Rule 2: Chain Structure Per Research
39
+
40
+ Each research directory (`researches/<slug>/`) has its own independent witness chain stored in `researches/<slug>/.witness-chain.json`.
41
+
42
+ ### Chain initialization
43
+
44
+ - Created at Phase 0 (Discovery) with the genesis record
45
+ - Uses NULL_HASH (64 zeros) as the previous_hash for the first record
46
+
47
+ ### Standard chain sequence
48
+
49
+ | Sequence | Phase | Artifact | Promise Tag |
50
+ |----------|-------|----------|-------------|
51
+ | 0 | phase-0 | 00_product_discovery.md | DISCOVERY_COMPLETE |
52
+ | 1 | phase-1 | 01_case_brief.md | CASE_EXPLORED |
53
+ | 2 | phase-2 | 02_research_findings.md | RESEARCH_PARANOID_PASSED |
54
+ | 3 | phase-2.5 | 02.5_trend_brief.md | CJM_VALIDATED |
55
+ | 4 | phase-3 | 03_solution_strategy.md | SOLUTION_DESIGNED |
56
+ | 5 | phase-4 | 04_architecture.md | ARCHITECTURE_DEFINED |
57
+ | 6 | phase-5 | 05_presentation_content.md | PRESENTATION_READY |
58
+
59
+ Additional artifacts (06_speaker_script.md, 07_qa_preparation.md, 08_executive_summary.md) may be added as additional chain records after sequence 6 if desired.
60
+
61
+ ## Rule 3: Required Fields Per Witness Record
62
+
63
+ Every witness record MUST contain ALL of the following fields:
64
+
65
+ | Field | Type | Description |
66
+ |-------|------|-------------|
67
+ | `sequence` | integer | 0-based position, monotonically increasing |
68
+ | `phase` | string | Phase identifier (phase-0 through phase-5) |
69
+ | `artifact` | string | Filename relative to research directory |
70
+ | `hash` | string | `sha256:` prefix + 64 hex chars |
71
+ | `previous_hash` | string | `sha256:` prefix + 64 hex chars (or null hash for genesis) |
72
+ | `timestamp` | string | ISO-8601 UTC timestamp |
73
+ | `promise_tag` | string | The semantic promise tag for this phase |
74
+
75
+ No field may be empty, null, or omitted.
76
+
77
+ ## Rule 4: BTO Judge Attestation Integration
78
+
79
+ **WHEN:** A BTO Layer 2 judge panel completes evaluation.
80
+ **THEN:** Create judge attestations in `.judge-attestations.json`.
81
+
82
+ ### Procedure
83
+
84
+ 1. Before the panel starts: compute the artifact_hash of the evaluated artifact
85
+ 2. After each judge submits its score and rationale:
86
+ a. Compute evaluation_hash = SHA-256(judge_id|artifact_hash|score|rationale_summary)
87
+ b. Link to previous attestation hash (or NULL_HASH for first judge)
88
+ c. Record timestamp
89
+ 3. After all judges complete: write `.judge-attestations.json` alongside the evaluation files
90
+ 4. If meta-judge is invoked (disagreement > 3 points): append meta-judge attestation
91
+
92
+ ### Attestation placement
93
+
94
+ The `.judge-attestations.json` file is stored in the same directory as the BTO evaluation output. If the BTO evaluation is for a skill, this could be:
95
+ - `researches/<slug>/` if BTO was run on a research artifact
96
+ - `.claude/skills/<name>/` if BTO was run on a skill
97
+ - The current working directory if path was specified explicitly
98
+
99
+ ## Rule 5: Chain Repair After Legitimate Edits
100
+
101
+ If a user provides feedback at a checkpoint and the artifact is modified:
102
+
103
+ 1. Re-hash the modified artifact using the same previous_hash
104
+ 2. Update the record's hash in `.witness-chain.json`
105
+ 3. If subsequent records exist: re-hash ALL downstream records (cascade)
106
+ 4. Update `last_updated` timestamp
107
+ 5. Log the repair in a `chain_repairs` array at the top level of the JSON:
108
+
109
+ ```json
110
+ {
111
+ "chain_repairs": [
112
+ {
113
+ "repaired_at": "2026-03-01T11:30:00Z",
114
+ "sequence": 2,
115
+ "artifact": "02_research_findings.md",
116
+ "reason": "User requested additional research depth",
117
+ "records_rehashed": 3
118
+ }
119
+ ]
120
+ }
121
+ ```
122
+
123
+ This is expected behavior, not an error. The repair log provides audit context.
124
+
125
+ ## Rule 6: Verification Recommendation
126
+
127
+ After completing a full pipeline (all phases through packaging):
128
+ - Recommend running `/verify-chain researches/<slug>/` as a final integrity check
129
+ - Include verification in the Phase 6 (Packaging) checklist
130
+
131
+ After completing a BTO evaluation:
132
+ - Recommend running `/verify-chain` on the evaluation directory to confirm judge isolation
133
+
134
+ ## Rule 7: Graceful Degradation
135
+
136
+ If witness chain creation fails for any reason (sha256sum not available, file permission error, JSON write failure):
137
+ - Log a WARNING but do NOT block the pipeline
138
+ - The witness chain is an integrity enhancement, not a pipeline gate
139
+ - The pipeline must complete even without witness records
140
+
141
+ Exception: In banking domain (detected by Phase 0 domain detection), witness chain failure should be escalated to the user as a WARNING at the checkpoint, since audit trail is especially important for ФЗ-152 compliance.
142
+
143
+ ## Rule 8: No Witness Chain for Feature ADR Pipeline
144
+
145
+ The `/feature-adr` pipeline does NOT require witness chains. Witness chains are designed for the Keysarium research pipeline (`/casarium`) and BTO evaluation pipeline (`/bto-test`).
146
+
147
+ If a user explicitly requests witness chain verification for a feature directory, `/verify-chain` should handle it gracefully (scan for `.witness-chain.json`, report NOT_FOUND if absent).
148
+
149
+ ## Rule 9: Chain Files in .gitignore
150
+
151
+ The `.witness-chain.json` and `.judge-attestations.json` files SHOULD be committed to git alongside research artifacts. They are part of the audit trail and should be version-controlled.
152
+
153
+ Do NOT add these files to `.gitignore`.
@@ -0,0 +1,322 @@
1
+ # Judge Attestation Protocol
2
+
3
+ > Cryptographic proof of BTO judge isolation via SHA-256 hash chain attestations.
4
+
5
+ ## Purpose
6
+
7
+ This protocol defines how BTO judges (Domain Expert, Critic, Completeness Auditor) create cryptographic attestations proving their evaluations were performed independently. Each judge records a hash of its evaluation before seeing other judges' scores. The attestations are chained to provide ordering proof.
8
+
9
+ ## Constants
10
+
11
+ ```
12
+ NULL_HASH = "0000000000000000000000000000000000000000000000000000000000000000"
13
+ ATTESTATION_FILE = ".judge-attestations.json"
14
+ HASH_PREFIX = "sha256:"
15
+ STANDARD_PANEL_SIZE = 3
16
+ HIGH_STAKES_PANEL_SIZE = 5
17
+ ```
18
+
19
+ ## Section 1: Attestation Creation
20
+
21
+ ### Hash Input Construction
22
+
23
+ Each judge's evaluation hash is computed from a deterministic concatenation of:
24
+
25
+ ```
26
+ evaluation_hash = SHA-256(judge_id + "|" + artifact_hash + "|" + score + "|" + rationale_summary)
27
+ ```
28
+
29
+ The pipe character `|` serves as a delimiter to prevent ambiguity in concatenation.
30
+
31
+ **Fields:**
32
+ - `judge_id`: One of `"domain-expert"`, `"critic"`, `"completeness-auditor"` (or `"meta-judge"` for escalation)
33
+ - `artifact_hash`: SHA-256 hash of the artifact being evaluated (computed before evaluation starts)
34
+ - `score`: The numeric score as a string with one decimal place (e.g., `"8.2"`)
35
+ - `rationale_summary`: First 500 characters of the judge's rationale text, trimmed of leading/trailing whitespace
36
+
37
+ ### Computing the Artifact Hash
38
+
39
+ Before any judge starts evaluation, compute the artifact hash:
40
+
41
+ ```bash
42
+ ARTIFACT_HASH=$(${SHA_CMD} "path/to/artifact.md" | awk '{print $1}')
43
+ ```
44
+
45
+ This hash is shared with all judges and recorded in each attestation. It proves all judges evaluated the same artifact.
46
+
47
+ ### Computing the Evaluation Hash
48
+
49
+ After a judge completes its evaluation:
50
+
51
+ ```bash
52
+ JUDGE_ID="domain-expert"
53
+ ARTIFACT_HASH="<computed above>"
54
+ SCORE="8.2"
55
+ RATIONALE_SUMMARY="<first 500 chars of rationale>"
56
+
57
+ EVAL_HASH=$(printf '%s' "${JUDGE_ID}|${ARTIFACT_HASH}|${SCORE}|${RATIONALE_SUMMARY}" | ${SHA_CMD} | awk '{print $1}')
58
+ ```
59
+
60
+ **Important:** The rationale_summary must be trimmed to exactly 500 characters (or fewer if the rationale is shorter) to ensure deterministic reproduction during verification.
61
+
62
+ ## Section 2: Chain Linking
63
+
64
+ ### Attestation Order
65
+
66
+ Judges are recorded in a fixed order within each evaluation round:
67
+
68
+ 1. Domain Expert (first, previous = NULL_HASH)
69
+ 2. Critic (second, previous = Domain Expert's evaluation_hash)
70
+ 3. Completeness Auditor (third, previous = Critic's evaluation_hash)
71
+
72
+ For a 5-judge high-stakes panel:
73
+ 4. Additional Expert (fourth, previous = Auditor's evaluation_hash)
74
+ 5. Tiebreaker (fifth, previous = Additional Expert's evaluation_hash)
75
+
76
+ ### Chain Link Protocol
77
+
78
+ ```bash
79
+ # Judge 1 (Domain Expert)
80
+ PREV_ATTESTATION_HASH="${NULL_HASH}"
81
+ # ... compute evaluation_hash_1 ...
82
+ # Record attestation with previous = NULL_HASH
83
+
84
+ # Judge 2 (Critic)
85
+ PREV_ATTESTATION_HASH="${EVAL_HASH_1}"
86
+ # ... compute evaluation_hash_2 ...
87
+ # Record attestation with previous = evaluation_hash_1
88
+
89
+ # Judge 3 (Completeness Auditor)
90
+ PREV_ATTESTATION_HASH="${EVAL_HASH_2}"
91
+ # ... compute evaluation_hash_3 ...
92
+ # Record attestation with previous = evaluation_hash_2
93
+ ```
94
+
95
+ ### Ordering Note
96
+
97
+ The chain records the ORDER in which attestations were finalized, not the order in which judges started evaluating. Since judges evaluate in parallel but record sequentially, the chain proves:
98
+ - Each attestation was recorded after the previous one
99
+ - The evaluation_hash was computed from the judge's OWN data only
100
+ - The previous_attestation_hash links to the preceding record (not to the preceding judge's score)
101
+
102
+ ## Section 3: Isolation Verification
103
+
104
+ ### Verification Algorithm
105
+
106
+ ```
107
+ 1. Load .judge-attestations.json
108
+ 2. For each evaluation round:
109
+ a. Verify artifact_hash matches across all attestations
110
+ b. For each attestation (index i):
111
+ i. Reconstruct evaluation_hash from (judge_id, artifact_hash, score, rationale_summary)
112
+ ii. Compare reconstructed hash with stored evaluation_hash
113
+ iii. If i == 0: verify previous_attestation_hash == NULL_HASH
114
+ iv. If i > 0: verify previous_attestation_hash == attestations[i-1].evaluation_hash
115
+ v. Verify timestamp > attestations[i-1].timestamp (if i > 0)
116
+ 3. Produce verification report
117
+ ```
118
+
119
+ ### Isolation Proof Logic
120
+
121
+ The isolation proof works as follows:
122
+
123
+ 1. **Hash Independence:** Each evaluation_hash is computed from `judge_id|artifact_hash|score|rationale`. If a judge had seen another judge's score, it would not affect its own hash computation -- but it would be detectable if the rationale text references specific scores from other judges.
124
+
125
+ 2. **Chain Integrity:** The previous_attestation_hash links attestations in order but does NOT include other judges' scores in the hash input. This means the chain proves ORDER but the evaluation content is provably independent.
126
+
127
+ 3. **Timestamp Monotonicity:** Timestamps must be strictly increasing. If Judge B's timestamp is BEFORE Judge A's, but Judge B's previous_attestation_hash points to Judge A, then something is wrong.
128
+
129
+ ### Verification Script
130
+
131
+ ```bash
132
+ python3 << 'VERIFY_ATTESTATION'
133
+ import json, subprocess, sys
134
+
135
+ NULL_HASH = "0" * 64
136
+
137
+ def sha256(content):
138
+ result = subprocess.run(
139
+ ["sha256sum"],
140
+ input=content.encode(),
141
+ capture_output=True
142
+ )
143
+ if result.returncode != 0:
144
+ result = subprocess.run(
145
+ ["shasum", "-a", "256"],
146
+ input=content.encode(),
147
+ capture_output=True
148
+ )
149
+ return result.stdout.decode().split()[0]
150
+
151
+ DIR = sys.argv[1] if len(sys.argv) > 1 else "."
152
+
153
+ with open(f"{DIR}/.judge-attestations.json") as f:
154
+ data = json.load(f)
155
+
156
+ for eval_round in data.get("evaluations", [data]):
157
+ attestations = eval_round.get("attestations", [])
158
+ artifact_hash = eval_round.get("artifact_hash", "")
159
+ violations = []
160
+
161
+ for i, att in enumerate(attestations):
162
+ # Reconstruct evaluation hash
163
+ hash_input = f"{att['judge_id']}|{artifact_hash}|{att['score']}|{att.get('rationale_summary', '')}"
164
+ expected = sha256(hash_input)
165
+ actual = att["evaluation_hash"].replace("sha256:", "")
166
+
167
+ if expected != actual:
168
+ violations.append(f"Judge {att['judge_id']}: evaluation_hash mismatch")
169
+
170
+ # Verify chain link
171
+ if i == 0:
172
+ expected_prev = NULL_HASH
173
+ else:
174
+ expected_prev = attestations[i-1]["evaluation_hash"].replace("sha256:", "")
175
+
176
+ actual_prev = att["previous_attestation_hash"].replace("sha256:", "")
177
+ if expected_prev != actual_prev:
178
+ violations.append(f"Judge {att['judge_id']}: chain link broken")
179
+
180
+ if not violations:
181
+ print(f"PASS: All {len(attestations)} judge attestations verified. Isolation confirmed.")
182
+ else:
183
+ print(f"FAIL: {len(violations)} violations detected:")
184
+ for v in violations:
185
+ print(f" - {v}")
186
+
187
+ VERIFY_ATTESTATION
188
+ ```
189
+
190
+ ## Section 4: File Format
191
+
192
+ ### .judge-attestations.json Schema
193
+
194
+ ```json
195
+ {
196
+ "evaluations": [
197
+ {
198
+ "evaluation_id": "string — unique ID for this evaluation round",
199
+ "artifact_path": "string — path to the evaluated artifact",
200
+ "artifact_hash": "string — sha256:<hex> of the artifact content",
201
+ "panel_size": "integer — 3 (standard) or 5 (high-stakes)",
202
+ "started_at": "ISO-8601 — when evaluation round began",
203
+ "completed_at": "ISO-8601 — when last attestation recorded",
204
+ "attestations": [
205
+ {
206
+ "judge_id": "string — domain-expert|critic|completeness-auditor",
207
+ "score": "float — 0.0-10.0",
208
+ "rationale_summary": "string — first 500 chars of rationale",
209
+ "evaluation_hash": "string — sha256:<hex>",
210
+ "timestamp": "ISO-8601 — when attestation was recorded",
211
+ "previous_attestation_hash": "string — sha256:<hex> or null hash"
212
+ }
213
+ ],
214
+ "final_score": "float — weighted average",
215
+ "weights": {
216
+ "domain-expert": 0.4,
217
+ "critic": 0.3,
218
+ "completeness-auditor": 0.3
219
+ }
220
+ }
221
+ ]
222
+ }
223
+ ```
224
+
225
+ ### Example Attestation File
226
+
227
+ ```json
228
+ {
229
+ "evaluations": [
230
+ {
231
+ "evaluation_id": "bto-eval-2026-03-01T12:00:00Z",
232
+ "artifact_path": ".claude/skills/explore/SKILL.md",
233
+ "artifact_hash": "sha256:abc123def456789012345678901234567890123456789012345678901234fedc",
234
+ "panel_size": 3,
235
+ "started_at": "2026-03-01T12:00:00Z",
236
+ "completed_at": "2026-03-01T12:01:45Z",
237
+ "attestations": [
238
+ {
239
+ "judge_id": "domain-expert",
240
+ "score": 8.2,
241
+ "rationale_summary": "Strong SKILL.md with clear protocol steps. References directory provides good examples...",
242
+ "evaluation_hash": "sha256:111222333444555666777888999000aaabbbcccdddeeefff000111222333444555",
243
+ "timestamp": "2026-03-01T12:00:30Z",
244
+ "previous_attestation_hash": "sha256:0000000000000000000000000000000000000000000000000000000000000000"
245
+ },
246
+ {
247
+ "judge_id": "critic",
248
+ "score": 7.5,
249
+ "rationale_summary": "Missing edge case handling for multi-language inputs. Error recovery protocol unclear...",
250
+ "evaluation_hash": "sha256:222333444555666777888999000aaabbbcccdddeeefff000111222333444555666",
251
+ "timestamp": "2026-03-01T12:01:00Z",
252
+ "previous_attestation_hash": "sha256:111222333444555666777888999000aaabbbcccdddeeefff000111222333444555"
253
+ },
254
+ {
255
+ "judge_id": "completeness-auditor",
256
+ "score": 8.0,
257
+ "rationale_summary": "All required sections present. References directory has 3 examples. Missing: performance benchmarks...",
258
+ "evaluation_hash": "sha256:333444555666777888999000aaabbbcccdddeeefff000111222333444555666777",
259
+ "timestamp": "2026-03-01T12:01:30Z",
260
+ "previous_attestation_hash": "sha256:222333444555666777888999000aaabbbcccdddeeefff000111222333444555666"
261
+ }
262
+ ],
263
+ "final_score": 7.94,
264
+ "weights": {
265
+ "domain-expert": 0.4,
266
+ "critic": 0.3,
267
+ "completeness-auditor": 0.3
268
+ }
269
+ }
270
+ ]
271
+ }
272
+ ```
273
+
274
+ ## Section 5: Integration with BTO Pipeline
275
+
276
+ ### When to Create Attestations
277
+
278
+ Attestations are created during **BTO Layer 2 evaluation** (the judge panel stage):
279
+
280
+ 1. **Before panel starts:** Compute `artifact_hash` of the artifact being evaluated
281
+ 2. **After each judge completes:** Create attestation record with evaluation_hash
282
+ 3. **After all judges complete:** Write `.judge-attestations.json`
283
+ 4. **If meta-judge is invoked:** Add a 4th attestation with `judge_id: "meta-judge"`
284
+
285
+ ### Integration Points
286
+
287
+ | BTO Stage | Attestation Action |
288
+ |-----------|-------------------|
289
+ | Layer 0 (structural) | No attestation needed (deterministic checks) |
290
+ | Layer 1 (semantic) | No attestation needed (single haiku agent) |
291
+ | Layer 2 (judge panel) | Create attestation set with 3 attestations |
292
+ | Meta-judge (escalation) | Append meta-judge attestation to the set |
293
+ | Optimization rounds | Create new attestation set per round's final evaluation |
294
+
295
+ ### Disagreement Detection Enhancement
296
+
297
+ With attestations, disagreement detection gains cryptographic backing:
298
+
299
+ ```
300
+ If max_score - min_score > 3.0:
301
+ 1. Verify all attestations are valid (no tampering)
302
+ 2. Verify isolation (no judge influenced another)
303
+ 3. If isolation verified: escalate to meta-judge (genuine disagreement)
304
+ 4. If isolation violated: flag conformity collapse warning
305
+ ```
306
+
307
+ ## Section 6: Meta-Judge Attestation
308
+
309
+ When the meta-judge is invoked (disagreement > 3 points), it creates its own attestation:
310
+
311
+ ```json
312
+ {
313
+ "judge_id": "meta-judge",
314
+ "score": 7.8,
315
+ "rationale_summary": "Disagreement between domain-expert (8.5) and critic (5.2) on dimension 'completeness'...",
316
+ "evaluation_hash": "sha256:...",
317
+ "timestamp": "2026-03-01T12:02:00Z",
318
+ "previous_attestation_hash": "sha256:<last judge's eval hash>"
319
+ }
320
+ ```
321
+
322
+ The meta-judge's rationale MAY reference other judges' scores (it has access to them for arbitration). This is expected and does not violate isolation -- the meta-judge is explicitly a synthesizer, not an independent evaluator.
@@ -0,0 +1,372 @@
1
+ # Witness Chain Protocol
2
+
3
+ > SHA-256 hash-chain for tamper-evident artifact integrity verification.
4
+
5
+ ## Purpose
6
+
7
+ This protocol defines how to compute SHA-256 hashes of pipeline artifacts and link them into a chain. Each artifact's hash includes the previous artifact's hash, making the chain tamper-evident: modifying any artifact breaks all downstream hashes.
8
+
9
+ ## Constants
10
+
11
+ ```
12
+ NULL_HASH = "0000000000000000000000000000000000000000000000000000000000000000"
13
+ CHAIN_FILE = ".witness-chain.json"
14
+ HASH_PREFIX = "sha256:"
15
+ ```
16
+
17
+ ## Section 1: Hash Computation
18
+
19
+ ### Platform Detection
20
+
21
+ Detect the available SHA-256 command:
22
+
23
+ ```bash
24
+ # Try sha256sum first (Linux), then shasum (macOS)
25
+ if command -v sha256sum &>/dev/null; then
26
+ SHA_CMD="sha256sum"
27
+ elif command -v shasum &>/dev/null; then
28
+ SHA_CMD="shasum -a 256"
29
+ else
30
+ echo "ERROR: No SHA-256 command found. Install coreutils."
31
+ exit 1
32
+ fi
33
+ ```
34
+
35
+ ### Computing a File Hash
36
+
37
+ Hash a single file's content:
38
+
39
+ ```bash
40
+ HASH=$(${SHA_CMD} "path/to/file.md" | awk '{print $1}')
41
+ ```
42
+
43
+ ### Computing a Chained Hash
44
+
45
+ Hash file content concatenated with the previous hash to create a chain link:
46
+
47
+ ```bash
48
+ # Read file content and previous hash
49
+ FILE_CONTENT=$(cat "path/to/file.md")
50
+ PREV_HASH="<previous hash value>"
51
+
52
+ # Compute chained hash
53
+ CHAINED_HASH=$(printf '%s%s' "${FILE_CONTENT}" "${PREV_HASH}" | ${SHA_CMD} | awk '{print $1}')
54
+ ```
55
+
56
+ **Important:** Use `printf '%s%s'` (not `echo`) to avoid trailing newline issues. The content is the raw file bytes followed immediately by the 64-character hex hash string.
57
+
58
+ ### Content Normalization
59
+
60
+ Before hashing, the content should be the raw file content as stored on disk. Do NOT:
61
+ - Trim whitespace
62
+ - Normalize line endings
63
+ - Strip BOM markers
64
+
65
+ The hash must match the exact bytes in the file so that verification produces the same result.
66
+
67
+ ## Section 2: Chain Operations
68
+
69
+ ### Operation: Create Genesis Record
70
+
71
+ Called at Phase 0 (Discovery) to initialize the chain for a new research.
72
+
73
+ **Preconditions:**
74
+ - Research directory `researches/<slug>/` exists
75
+ - Phase 0 artifact `00_product_discovery.md` has been created
76
+ - No `.witness-chain.json` exists yet
77
+
78
+ **Procedure:**
79
+
80
+ ```bash
81
+ SLUG="<research-slug>"
82
+ DIR="researches/${SLUG}"
83
+ ARTIFACT="00_product_discovery.md"
84
+ PREV_HASH="${NULL_HASH}"
85
+
86
+ # Compute genesis hash
87
+ FILE_CONTENT=$(cat "${DIR}/${ARTIFACT}")
88
+ HASH=$(printf '%s%s' "${FILE_CONTENT}" "${PREV_HASH}" | ${SHA_CMD} | awk '{print $1}')
89
+ TIMESTAMP=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
90
+
91
+ # Create .witness-chain.json
92
+ cat > "${DIR}/.witness-chain.json" << ENDOFCHAIN
93
+ {
94
+ "research_slug": "${SLUG}",
95
+ "created_at": "${TIMESTAMP}",
96
+ "last_updated": "${TIMESTAMP}",
97
+ "chain": [
98
+ {
99
+ "sequence": 0,
100
+ "phase": "phase-0",
101
+ "artifact": "${ARTIFACT}",
102
+ "hash": "${HASH_PREFIX}${HASH}",
103
+ "previous_hash": "${HASH_PREFIX}${PREV_HASH}",
104
+ "timestamp": "${TIMESTAMP}",
105
+ "promise_tag": "DISCOVERY_COMPLETE"
106
+ }
107
+ ]
108
+ }
109
+ ENDOFCHAIN
110
+ ```
111
+
112
+ ### Operation: Append Record
113
+
114
+ Called at each subsequent phase checkpoint to add a new record to the chain.
115
+
116
+ **Preconditions:**
117
+ - `.witness-chain.json` exists in the research directory
118
+ - The new artifact file has been created
119
+ - The previous phase's record exists in the chain
120
+
121
+ **Procedure:**
122
+
123
+ 1. Read `.witness-chain.json` and extract the last record's hash
124
+ 2. Compute the new chained hash: `SHA-256(new_content + last_hash)`
125
+ 3. Append the new record to the chain array
126
+ 4. Update `last_updated` timestamp
127
+
128
+ ```bash
129
+ SLUG="<research-slug>"
130
+ DIR="researches/${SLUG}"
131
+ ARTIFACT="<artifact-filename>"
132
+ PHASE="<phase-id>"
133
+ PROMISE="<promise-tag>"
134
+
135
+ # Get the latest hash from the chain
136
+ PREV_HASH=$(cat "${DIR}/.witness-chain.json" | python3 -c "
137
+ import json, sys
138
+ chain = json.load(sys.stdin)
139
+ last = chain['chain'][-1]
140
+ print(last['hash'].replace('sha256:', ''))
141
+ ")
142
+
143
+ # Compute new hash
144
+ FILE_CONTENT=$(cat "${DIR}/${ARTIFACT}")
145
+ HASH=$(printf '%s%s' "${FILE_CONTENT}" "${PREV_HASH}" | ${SHA_CMD} | awk '{print $1}')
146
+ TIMESTAMP=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
147
+ SEQUENCE=$(cat "${DIR}/.witness-chain.json" | python3 -c "
148
+ import json, sys
149
+ chain = json.load(sys.stdin)
150
+ print(len(chain['chain']))
151
+ ")
152
+
153
+ # Append to chain (using python3 for safe JSON manipulation)
154
+ python3 -c "
155
+ import json, sys
156
+ with open('${DIR}/.witness-chain.json', 'r') as f:
157
+ chain = json.load(f)
158
+ chain['chain'].append({
159
+ 'sequence': ${SEQUENCE},
160
+ 'phase': '${PHASE}',
161
+ 'artifact': '${ARTIFACT}',
162
+ 'hash': 'sha256:${HASH}',
163
+ 'previous_hash': 'sha256:${PREV_HASH}',
164
+ 'timestamp': '${TIMESTAMP}',
165
+ 'promise_tag': '${PROMISE}'
166
+ })
167
+ chain['last_updated'] = '${TIMESTAMP}'
168
+ with open('${DIR}/.witness-chain.json', 'w') as f:
169
+ json.dump(chain, f, indent=2)
170
+ "
171
+ ```
172
+
173
+ ### Operation: Get Latest Hash
174
+
175
+ Retrieve the most recent hash from the chain (needed as input for the next append).
176
+
177
+ ```bash
178
+ LATEST_HASH=$(python3 -c "
179
+ import json
180
+ with open('${DIR}/.witness-chain.json') as f:
181
+ chain = json.load(f)
182
+ print(chain['chain'][-1]['hash'].replace('sha256:', ''))
183
+ ")
184
+ ```
185
+
186
+ ## Section 3: Verification
187
+
188
+ ### Operation: Verify Chain
189
+
190
+ Walk the entire chain and verify each hash matches the current file content.
191
+
192
+ **Algorithm:**
193
+
194
+ ```
195
+ 1. Load .witness-chain.json
196
+ 2. For each record in chain (index i):
197
+ a. Read the artifact file
198
+ b. Get previous_hash:
199
+ - If i == 0: previous_hash = NULL_HASH
200
+ - Else: previous_hash = chain[i-1].hash (without prefix)
201
+ c. Compute expected = SHA-256(file_content + previous_hash)
202
+ d. Compare expected with record.hash (without prefix)
203
+ e. If mismatch: record broken link
204
+ 3. Produce verification report
205
+ ```
206
+
207
+ **Bash implementation:**
208
+
209
+ ```bash
210
+ DIR="researches/<slug>"
211
+
212
+ python3 << 'VERIFY_SCRIPT'
213
+ import json, subprocess, sys
214
+
215
+ NULL_HASH = "0" * 64
216
+ DIR = sys.argv[1] if len(sys.argv) > 1 else "."
217
+
218
+ def sha256(content):
219
+ """Compute SHA-256 of a string."""
220
+ result = subprocess.run(
221
+ ["sha256sum"],
222
+ input=content.encode(),
223
+ capture_output=True
224
+ )
225
+ if result.returncode != 0:
226
+ # Fallback to shasum
227
+ result = subprocess.run(
228
+ ["shasum", "-a", "256"],
229
+ input=content.encode(),
230
+ capture_output=True
231
+ )
232
+ return result.stdout.decode().split()[0]
233
+
234
+ # Load chain
235
+ with open(f"{DIR}/.witness-chain.json") as f:
236
+ chain_data = json.load(f)
237
+
238
+ records = chain_data["chain"]
239
+ broken = []
240
+ verified = 0
241
+
242
+ for i, record in enumerate(records):
243
+ artifact_path = f"{DIR}/{record['artifact']}"
244
+ try:
245
+ with open(artifact_path) as f:
246
+ content = f.read()
247
+ except FileNotFoundError:
248
+ broken.append({
249
+ "sequence": i,
250
+ "artifact": record["artifact"],
251
+ "reason": "File not found"
252
+ })
253
+ continue
254
+
255
+ if i == 0:
256
+ prev_hash = NULL_HASH
257
+ else:
258
+ prev_hash = records[i-1]["hash"].replace("sha256:", "")
259
+
260
+ expected = sha256(content + prev_hash)
261
+ actual = record["hash"].replace("sha256:", "")
262
+
263
+ if expected == actual:
264
+ verified += 1
265
+ else:
266
+ broken.append({
267
+ "sequence": i,
268
+ "artifact": record["artifact"],
269
+ "expected_hash": f"sha256:{expected}",
270
+ "actual_hash": record["hash"],
271
+ "reason": "Hash mismatch - artifact may have been modified"
272
+ })
273
+
274
+ # Report
275
+ total = len(records)
276
+ if not broken:
277
+ print(f"PASS: All {total} records verified successfully")
278
+ else:
279
+ print(f"FAIL: {len(broken)} broken links out of {total} records")
280
+ for b in broken:
281
+ print(f" - Record {b['sequence']} ({b['artifact']}): {b['reason']}")
282
+
283
+ VERIFY_SCRIPT
284
+ ```
285
+
286
+ ## Section 4: File Format
287
+
288
+ ### .witness-chain.json Schema
289
+
290
+ ```json
291
+ {
292
+ "research_slug": "string — research directory name",
293
+ "created_at": "ISO-8601 — when chain was initialized",
294
+ "last_updated": "ISO-8601 — when last record was added",
295
+ "chain": [
296
+ {
297
+ "sequence": "integer — 0-based position in chain",
298
+ "phase": "string — phase-0, phase-1, ..., phase-5",
299
+ "artifact": "string — filename relative to research dir",
300
+ "hash": "string — sha256:<64 hex chars>",
301
+ "previous_hash": "string — sha256:<64 hex chars> or sha256:<null hash>",
302
+ "timestamp": "ISO-8601 — when record was created",
303
+ "promise_tag": "string — semantic completion promise"
304
+ }
305
+ ]
306
+ }
307
+ ```
308
+
309
+ ### Standard Phase-to-Artifact Mapping
310
+
311
+ | Phase | Artifact | Promise Tag |
312
+ |-------|----------|-------------|
313
+ | phase-0 | 00_product_discovery.md | DISCOVERY_COMPLETE |
314
+ | phase-1 | 01_case_brief.md | CASE_EXPLORED |
315
+ | phase-2 | 02_research_findings.md | RESEARCH_PARANOID_PASSED |
316
+ | phase-2.5 | 02.5_trend_brief.md | CJM_VALIDATED |
317
+ | phase-3 | 03_solution_strategy.md | SOLUTION_DESIGNED |
318
+ | phase-4 | 04_architecture.md | ARCHITECTURE_DEFINED |
319
+ | phase-5 | 05_presentation_content.md | PRESENTATION_READY |
320
+
321
+ ### Example Complete Chain
322
+
323
+ ```json
324
+ {
325
+ "research_slug": "bank_kc_automation",
326
+ "created_at": "2026-03-01T10:00:00Z",
327
+ "last_updated": "2026-03-01T14:30:00Z",
328
+ "chain": [
329
+ {
330
+ "sequence": 0,
331
+ "phase": "phase-0",
332
+ "artifact": "00_product_discovery.md",
333
+ "hash": "sha256:a1b2c3d4e5f6789012345678901234567890123456789012345678901234abcd",
334
+ "previous_hash": "sha256:0000000000000000000000000000000000000000000000000000000000000000",
335
+ "timestamp": "2026-03-01T10:00:00Z",
336
+ "promise_tag": "DISCOVERY_COMPLETE"
337
+ },
338
+ {
339
+ "sequence": 1,
340
+ "phase": "phase-1",
341
+ "artifact": "01_case_brief.md",
342
+ "hash": "sha256:b2c3d4e5f67890123456789012345678901234567890123456789012345bef01",
343
+ "previous_hash": "sha256:a1b2c3d4e5f6789012345678901234567890123456789012345678901234abcd",
344
+ "timestamp": "2026-03-01T10:30:00Z",
345
+ "promise_tag": "CASE_EXPLORED"
346
+ }
347
+ ]
348
+ }
349
+ ```
350
+
351
+ ## Section 5: Chain Repair
352
+
353
+ If an artifact is legitimately modified (e.g., user requested changes during checkpoint review), the chain must be repaired:
354
+
355
+ 1. Re-hash the modified artifact using the previous record's hash
356
+ 2. Update the modified record's hash in `.witness-chain.json`
357
+ 3. Re-hash ALL subsequent records (cascade update)
358
+ 4. Update `last_updated` timestamp
359
+
360
+ This is expected and normal. The witness chain protects against *undetected* modifications, not against all modifications.
361
+
362
+ ## Section 6: Platform Compatibility
363
+
364
+ | Platform | Command | Notes |
365
+ |----------|---------|-------|
366
+ | Linux (Ubuntu, Debian, etc.) | `sha256sum` | Available by default in coreutils |
367
+ | macOS | `shasum -a 256` | Available by default |
368
+ | Windows (WSL) | `sha256sum` | Available in WSL |
369
+ | Windows (Git Bash) | `sha256sum` | Available in Git for Windows |
370
+ | Alpine Linux | `sha256sum` | Available in coreutils |
371
+
372
+ The protocol should attempt `sha256sum` first, then fall back to `shasum -a 256`.