@dzhechkov/keysarium 1.1.2 → 1.3.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.
Files changed (62) hide show
  1. package/README.md +7 -2
  2. package/package.json +10 -2
  3. package/templates/.claude/commands/brain-export.md +97 -20
  4. package/templates/.claude/commands/brain-import.md +75 -4
  5. package/templates/.claude/commands/dream.md +101 -0
  6. package/templates/.claude/commands/feature-adr.md +92 -0
  7. package/templates/.claude/commands/init-platform.md +161 -0
  8. package/templates/.claude/commands/learning-stats.md +130 -0
  9. package/templates/.claude/commands/workers.md +140 -0
  10. package/templates/.claude/rules/background-workers.md +72 -0
  11. package/templates/.claude/rules/dream-cycles.md +90 -0
  12. package/templates/.claude/rules/feature-adr-conventions.md +82 -0
  13. package/templates/.claude/rules/reward-learning.md +124 -0
  14. package/templates/.claude/shards/feature-adr.shard.md +98 -0
  15. package/templates/.claude/skills/feature-adr/SKILL.md +252 -0
  16. package/templates/.claude/skills/feature-adr/examples/sample-feature-output.md +257 -0
  17. package/templates/.claude/skills/feature-adr/modules/00-complexity-router.md +114 -0
  18. package/templates/.claude/skills/feature-adr/modules/01-requirements.md +113 -0
  19. package/templates/.claude/skills/feature-adr/modules/02-research.md +92 -0
  20. package/templates/.claude/skills/feature-adr/modules/03-adr.md +135 -0
  21. package/templates/.claude/skills/feature-adr/modules/04-ddd.md +114 -0
  22. package/templates/.claude/skills/feature-adr/modules/05-architecture.md +149 -0
  23. package/templates/.claude/skills/feature-adr/modules/06-implementation-plan.md +129 -0
  24. package/templates/.claude/skills/feature-adr/modules/07-code.md +126 -0
  25. package/templates/.claude/skills/feature-adr/modules/08-qe.md +167 -0
  26. package/templates/.claude/skills/feature-adr/references/adr-template.md +102 -0
  27. package/templates/.claude/skills/feature-adr/references/c4-template.md +120 -0
  28. package/templates/.claude/skills/feature-adr/references/complexity-matrix.md +139 -0
  29. package/templates/.claude/skills/feature-adr/references/qe-checklist.md +86 -0
  30. package/templates/CLAUDE.md +135 -8
  31. package/templates/docs/feature-adr/01-architecture.md +750 -0
  32. package/templates/docs/feature-adr/02-functionality.md +712 -0
  33. package/templates/docs/feature-adr/03-deployment-guide.md +614 -0
  34. package/templates/docs/feature-adr/04-admin-guide.md +564 -0
  35. package/templates/docs/feature-adr/05-user-guide.md +508 -0
  36. package/templates/docs/feature-adr/06-user-flows.md +1101 -0
  37. package/templates/docs/improvement-directions.md +16 -16
  38. package/templates/docs/keysarium/01-deployment-guide.md +21 -12
  39. package/templates/docs/keysarium/02-admin-guide.md +204 -3
  40. package/templates/docs/keysarium/03-user-guide.md +224 -0
  41. package/templates/docs/keysarium/05-architecture.md +181 -0
  42. package/templates/docs/keysarium/06-user-flows.md +235 -0
  43. package/templates/docs/keysarium-core/01-architecture.md +559 -0
  44. package/templates/docs/keysarium-core/02-functionality.md +953 -0
  45. package/templates/docs/keysarium-core/03-deployment-guide.md +625 -0
  46. package/templates/docs/keysarium-core/04-admin-guide.md +529 -0
  47. package/templates/docs/keysarium-core/05-user-guide.md +599 -0
  48. package/templates/docs/keysarium-core/06-user-flows.md +804 -0
  49. package/templates/lib/background-workers.md +278 -0
  50. package/templates/lib/dream-engine.md +460 -0
  51. package/templates/lib/judge-attestation.md +322 -0
  52. package/templates/lib/memory-protocol.md +344 -0
  53. package/templates/lib/platform-adapters.md +100 -0
  54. package/templates/lib/platform-templates/copilot.md +134 -0
  55. package/templates/lib/platform-templates/cursor.md +95 -0
  56. package/templates/lib/platform-templates/opencode.md +155 -0
  57. package/templates/lib/reward-tracker.md +256 -0
  58. package/templates/lib/witness-chain.md +372 -0
  59. package/templates/lib/worker-templates/brain-export.md +187 -0
  60. package/templates/lib/worker-templates/consolidate.md +180 -0
  61. package/templates/lib/worker-templates/dream-cycle.md +154 -0
  62. package/templates/lib/worker-templates/health-check.md +255 -0
@@ -0,0 +1,256 @@
1
+ # Reward Tracker -- Analytics & Pattern Detection
2
+
3
+ Computes aggregate statistics and detects domain patterns from accumulated reward records. Used by `/learning-stats` and by `memory_query()` for pattern enrichment.
4
+
5
+ ## Overview
6
+
7
+ The Reward Tracker operates on the data stored by the Memory Protocol (`lib/memory-protocol.md`). It reads all RewardRecord JSON files from `.keysarium/memory/` and produces two output artifacts:
8
+
9
+ 1. **reward-summary.json** -- aggregate statistics per phase, domain, and skill
10
+ 2. **domain-patterns.json** -- detected patterns with confidence scores
11
+
12
+ ## Computation Protocol
13
+
14
+ ### Step 1: Load All Records
15
+
16
+ 1. Scan `.keysarium/memory/` recursively for all `*.json` files (excluding config.json, domain-patterns.json, reward-summary.json).
17
+ 2. Parse each JSON file as a RewardRecord.
18
+ 3. Exclude records where `expires_at < current_date`.
19
+ 4. Collect into a list sorted by `timestamp` DESC.
20
+
21
+ ### Step 2: Per-Phase Reward Averages
22
+
23
+ Group records by `phase` and compute:
24
+
25
+ ```json
26
+ {
27
+ "phase-0": {
28
+ "avg_reward": 0.85,
29
+ "total_runs": 12,
30
+ "distribution": {
31
+ "excellent": 8,
32
+ "good": 3,
33
+ "needs_work": 1,
34
+ "failed": 0
35
+ },
36
+ "trend": "stable",
37
+ "best_case": "retail_personalization",
38
+ "worst_case": "bank_kc_automation"
39
+ }
40
+ }
41
+ ```
42
+
43
+ **Trend Detection Algorithm:**
44
+ 1. Split records for each phase into two halves by timestamp (older half, newer half).
45
+ 2. Compute average reward for each half.
46
+ 3. If newer_avg - older_avg > 0.15 -> "improving"
47
+ 4. If older_avg - newer_avg > 0.15 -> "degrading"
48
+ 5. Otherwise -> "stable"
49
+ 6. Minimum 4 records required for trend detection; otherwise "insufficient_data".
50
+
51
+ ### Step 3: Per-Domain Reward Averages
52
+
53
+ Group records by `domain` and compute:
54
+
55
+ ```json
56
+ {
57
+ "banking": {
58
+ "avg_reward": 0.72,
59
+ "total_runs": 18,
60
+ "phase_breakdown": {
61
+ "phase-0": 0.85,
62
+ "phase-1": 0.90,
63
+ "phase-2": 0.55,
64
+ "phase-2.5": 0.70,
65
+ "phase-3": 0.65,
66
+ "phase-4": 0.80,
67
+ "phase-5": 0.72
68
+ },
69
+ "bottleneck_phase": "phase-2",
70
+ "strongest_phase": "phase-1"
71
+ }
72
+ }
73
+ ```
74
+
75
+ **Bottleneck Detection:**
76
+ - Phase with the lowest average reward in a domain is flagged as `bottleneck_phase`.
77
+ - Phase with the highest average reward is flagged as `strongest_phase`.
78
+ - Only computed if domain has 3+ records.
79
+
80
+ ### Step 4: Per-Skill Effectiveness
81
+
82
+ Group records by `skill_used` and cross-reference with domain:
83
+
84
+ ```json
85
+ {
86
+ "goap-research-ed25519": {
87
+ "overall_avg": 0.74,
88
+ "total_runs": 15,
89
+ "by_domain": {
90
+ "banking": { "avg": 0.65, "runs": 8 },
91
+ "retail": { "avg": 0.85, "runs": 7 }
92
+ },
93
+ "best_domain": "retail",
94
+ "worst_domain": "banking"
95
+ }
96
+ }
97
+ ```
98
+
99
+ ### Step 5: Domain Pattern Detection
100
+
101
+ Analyze accumulated data to detect actionable patterns. Each pattern has a confidence score based on evidence count.
102
+
103
+ **Pattern Detection Rules:**
104
+
105
+ | Rule | Condition | Pattern Template |
106
+ |------|-----------|-----------------|
107
+ | Phase Bottleneck | Phase avg < 0.5 in domain, 3+ records | "{domain} cases struggle in {phase} (avg reward: {avg})" |
108
+ | Phase Excellence | Phase avg > 0.9 in domain, 3+ records | "{domain} cases excel in {phase} (avg reward: {avg})" |
109
+ | Skill-Domain Mismatch | Skill avg < 0.5 in domain but > 0.7 in another | "{skill} underperforms in {domain} vs {other_domain}" |
110
+ | Improving Trend | Trend = "improving" for phase in domain | "{phase} quality is improving in {domain} domain" |
111
+ | Degrading Trend | Trend = "degrading" for phase in domain | "{phase} quality is degrading in {domain} -- investigate" |
112
+ | Time Overhead | Phase avg iterations > 2.0 in domain | "{domain} cases require more iterations in {phase}" |
113
+
114
+ **Confidence Calculation:**
115
+ ```
116
+ confidence = min(1.0, evidence_count / 10)
117
+ ```
118
+ Where `evidence_count` is the number of records supporting the pattern. Confidence reaches 1.0 at 10+ supporting records.
119
+
120
+ ### Step 6: Write Outputs
121
+
122
+ #### reward-summary.json
123
+
124
+ Write to `.keysarium/memory/_stats/reward-summary.json`:
125
+
126
+ ```json
127
+ {
128
+ "version": "1.0",
129
+ "generated_at": "2026-03-01T14:00:00Z",
130
+ "total_records": 42,
131
+ "total_domains": 3,
132
+ "total_cases": 8,
133
+ "phase_averages": { ... },
134
+ "domain_averages": { ... },
135
+ "skill_effectiveness": { ... },
136
+ "overall_average": 0.76,
137
+ "overall_trend": "improving"
138
+ }
139
+ ```
140
+
141
+ #### domain-patterns.json
142
+
143
+ Write to `.keysarium/memory/_patterns/domain-patterns.json`:
144
+
145
+ ```json
146
+ {
147
+ "version": "1.0",
148
+ "generated_at": "2026-03-01T14:00:00Z",
149
+ "patterns": [
150
+ {
151
+ "pattern_id": "banking-phase2-bottleneck",
152
+ "domain": "banking",
153
+ "description": "Banking cases struggle in Phase 2 (Research) with average reward 0.55",
154
+ "category": "phase_bottleneck",
155
+ "confidence": 0.80,
156
+ "evidence_count": 8,
157
+ "detected_at": "2026-03-01T14:00:00Z",
158
+ "examples": ["bank_kc_automation", "bank_loan_approval"],
159
+ "actionable_advice": "Allocate 20% extra time for Phase 2 in banking cases. Consider pre-loading regulatory templates."
160
+ },
161
+ {
162
+ "pattern_id": "retail-triz-effective",
163
+ "domain": "retail",
164
+ "description": "TRIZ methodology produces better results than Game Theory for retail problem-solving",
165
+ "category": "skill_effectiveness",
166
+ "confidence": 0.60,
167
+ "evidence_count": 6,
168
+ "detected_at": "2026-03-01T14:00:00Z",
169
+ "examples": ["ecom_personalization", "retail_inventory"],
170
+ "actionable_advice": "Prefer TRIZ framework over Game Theory for retail domain cases in Phase 3."
171
+ }
172
+ ]
173
+ }
174
+ ```
175
+
176
+ ## Display Format for /learning-stats
177
+
178
+ ### Phase Averages Table
179
+
180
+ ```
181
+ Phase Reward Averages (42 records, 8 cases)
182
+ ───────────────────────────────────────────
183
+ Phase | Avg | Runs | Trend |
184
+ ────────────|────────|──────|─────────────|
185
+ Phase 0 | 0.85 | 8 | stable |
186
+ Phase 1 | 0.92 | 8 | improving |
187
+ Phase 2 | 0.65 | 7 | stable |
188
+ Phase 2.5 | 0.78 | 6 | improving |
189
+ Phase 3 | 0.71 | 5 | stable |
190
+ Phase 4 | 0.89 | 4 | stable |
191
+ Phase 5 | 0.74 | 4 | stable |
192
+ ────────────|────────|──────|─────────────|
193
+ Overall | 0.76 | 42 | improving |
194
+ ```
195
+
196
+ ### Domain Breakdown Table
197
+
198
+ ```
199
+ Domain Breakdown
200
+ ───────────────────────────────────────
201
+ Domain | Avg | Cases | Bottleneck |
202
+ ────────────|────────|───────|─────────────|
203
+ Banking | 0.72 | 3 | Phase 2 |
204
+ Retail | 0.82 | 3 | Phase 5 |
205
+ Enterprise | 0.69 | 2 | Phase 3 |
206
+ ```
207
+
208
+ ### Detected Patterns
209
+
210
+ ```
211
+ Detected Patterns (confidence > 0.5)
212
+ ──────────────────────────────────────────────────────
213
+ 1. [0.80] Banking cases struggle in Phase 2 (Research)
214
+ Advice: Allocate 20% extra time for Phase 2 in banking cases
215
+
216
+ 2. [0.60] TRIZ outperforms Game Theory for retail problem-solving
217
+ Advice: Prefer TRIZ framework for retail domain in Phase 3
218
+
219
+ 3. [0.55] Phase 1 quality is improving across all domains
220
+ Advice: Current exploration approach is working well
221
+ ```
222
+
223
+ ### Skill Effectiveness Table
224
+
225
+ ```
226
+ Skill Effectiveness
227
+ ────────────────────────────────────────────────────
228
+ Skill | Avg | Best Domain |
229
+ ───────────────────────────────|──────|─────────────|
230
+ explore | 0.92 | retail |
231
+ goap-research-ed25519 | 0.74 | retail |
232
+ problem-solver-enhanced | 0.71 | enterprise |
233
+ reverse-engineering-unicorn | 0.85 | banking |
234
+ presentation-storyteller | 0.74 | retail |
235
+ ```
236
+
237
+ ## Empty State
238
+
239
+ When no records exist yet:
240
+
241
+ ```
242
+ Learning Stats
243
+ ──────────────
244
+ No reward data found in .keysarium/memory/
245
+
246
+ To start collecting data:
247
+ 1. Run a case with /casarium
248
+ 2. Respond at each checkpoint
249
+ 3. Rewards are automatically tracked
250
+
251
+ Memory directory: .keysarium/memory/ (will be created on first run)
252
+ ```
253
+
254
+ ## Modular Reuse
255
+
256
+ This tracker is domain-agnostic. It works with any RewardRecord JSON that conforms to the schema defined in `lib/memory-protocol.md`. The pattern detection rules can be extended by adding entries to the Pattern Detection Rules table.
@@ -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`.