{
  "updated": "2026-10-07",
  "commit": "38d342f50e549374cffc04494bf443a30931bd73",
  "unfiled": [
    {
      "id": "docker-errors",
      "finding": 2,
      "priority": "P1",
      "kind": "Fix",
      "name": "Distinguish Docker failures from missing resources",
      "description": "Some inspect failures are treated as absence or as a stopped container.",
      "why": "A daemon, permission, or executable failure can trigger the wrong startup action or conceal incomplete cleanup.",
      "change": "Classify only verified not-found results as absence; propagate other errors with stderr and exit status.",
      "impact": "Lifecycle decisions become trustworthy, and failed cleanup retains useful metadata rather than pretending resources disappeared.",
      "consider": "Test not-found, unavailable daemon, permission denial, malformed output, and missing executable. Recheck merged ownership code before changing adjacent paths.",
      "paths": [
        "crates/ths-cli/src/runtime.rs"
      ],
      "deferred": false
    },
    {
      "id": "bounded-probes",
      "finding": 3,
      "priority": "P1",
      "kind": "Fix",
      "name": "Make startup deadlines bound each probe",
      "description": "HTTP and Docker subprocess waits can outlive the outer readiness deadline. Port overflow is separately tracked in #166.",
      "why": "One stalled command can prevent timeout handling and delay interruption and cleanup.",
      "change": "Use existing blocking reqwest for bounded HTTP probes, cap each wait by remaining time, and bound/reap subprocesses with standard-library mechanisms.",
      "impact": "Startup deadlines cover real work rather than only time between probes; cleanup can proceed after a stall.",
      "consider": "Exercise stalled connections, bodies and commands, cancellation, and child reaping. Preserve readiness-specific validation and instance ownership.",
      "paths": [
        "crates/ths-cli/src/runtime.rs"
      ],
      "deferred": false
    },
    {
      "id": "reorg-activity",
      "finding": 4,
      "priority": "P1",
      "kind": "Fix",
      "name": "Reconcile confirmed activity after a chain reorganization",
      "description": "Wallet scanning can rewind while confirmed application activity remains terminal and replay returns it unchanged.",
      "why": "A payment can be reported confirmed in an orphaned block even when the authoritative wallet has rewound.",
      "change": "Revalidate affected confirmations on detected rewinds and update the existing journal from canonical-chain observations.",
      "impact": "Activity, replay, and wallet state agree after a fork without rebuilding a payment simply because a lookup failed.",
      "consider": "Cover same-height/lower-tip forks, mempool return, disappearance, re-inclusion, and node failure. Preserve operation identity and uncertain submission.",
      "paths": [
        "crates/ths-server/src/api.rs",
        "crates/ths-server/src/db.rs",
        "crates/ths-server/src/reconcile.rs"
      ],
      "deferred": false
    },
    {
      "id": "external-discovery",
      "finding": 5,
      "priority": "P1",
      "kind": "Fix",
      "name": "Process external transaction and spend discovery",
      "description": "Current-UTXO refresh inserts received outputs, but does not fully process transactions spending those outputs outside this app or all SDK enhancement obligations.",
      "why": "An externally spent output can remain in wallet storage; transparent-only activity and full payload details can be incomplete.",
      "change": "Integrate the pinned SDK discovery, address-range completion, enhancement, and status work with existing local transports.",
      "impact": "The SDK has the transactions needed to maintain spentness and complete wallet records, instead of relying on a parallel app ledger.",
      "consider": "Test external receives/spends, empty completed ranges, failed lookups retained for retry, shielded enhancement, and spend reorgs. Keep treasury discovery demand-driven.",
      "paths": [
        "crates/ths-server/src/reconcile.rs",
        "crates/ths-server/src/wallet.rs"
      ],
      "deferred": false
    },
    {
      "id": "send-outcomes",
      "finding": 6,
      "priority": "P1",
      "kind": "Fix",
      "name": "Preserve send identity and report pending outcomes",
      "description": "Send callers can treat HTTP success as confirmation. The CLI creates a fresh operation key on each invocation. Faucet callers were addressed separately by merged #149.",
      "why": "If submission is accepted but its response is lost, retrying the CLI command with a new key can pay again. A pending HTTP response also does not prove confirmation.",
      "change": "Define durable send intent/retry semantics and branch messages and key cleanup on the returned activity outcome.",
      "impact": "Retries can reconcile the same operation, while users can intentionally make a new identical payment after completion.",
      "consider": "Follow dashboard and CLI callers, including shield/unshield. Cover response loss, process restart, concurrency, pending-to-confirmed transition, and a new identical intent. Do not retain all fingerprints forever.",
      "paths": [
        "crates/ths-cli/src/runtime.rs",
        "web/src/hooks/mutations.ts",
        "web/src/features/wallet/SendDialog.tsx",
        "crates/ths-server/src/api.rs"
      ],
      "deferred": false
    },
    {
      "id": "sdk-identity",
      "finding": 10,
      "priority": "P2",
      "kind": "Fix",
      "name": "Use SDK derivation identity and stored viewing keys",
      "description": "Application account IDs are associated with SDK accounts through sorted display names and positional mapping; key material is rederived on reads.",
      "why": "Renaming, importing, or reordering accounts can break a fragile mapping invariant. Default untouched names are not proof of an existing live mismatch.",
      "change": "Resolve derived SDK accounts by ZIP-32 identity and associate them explicitly with public IDs; read stored UFVKs.",
      "impact": "Account identity has one reliable owner and metadata reads avoid unnecessary spending-key derivation.",
      "consider": "Preserve deterministic addresses, key encoding, existing account migration, and treasury isolation. Test renamed/reordered/missing/imported accounts.",
      "paths": [
        "crates/ths-server/src/db.rs",
        "crates/ths-server/src/wallet.rs"
      ],
      "deferred": false
    },
    {
      "id": "snapshot-balances",
      "finding": 11,
      "priority": "P2",
      "kind": "Fix",
      "name": "Separate account metadata from authoritative wallet balances",
      "description": "App DB balance columns are legacy placeholders while SDK summaries supply real balances; initialization can suppress metadata-read errors.",
      "why": "A plausible stale value or empty snapshot can conceal a failed initialization or missing summary.",
      "change": "Keep metadata reads free of operational balance projections, make initialization errors explicit, and define missing-summary behavior.",
      "impact": "Published snapshots remain the single authoritative balance source; legacy columns need not be removed without a migration.",
      "consider": "Preserve last-good snapshots and legacy compatibility. Test initialization errors and absent summaries without reconstructing balances from activity.",
      "paths": [
        "crates/ths-server/src/db.rs",
        "crates/ths-server/src/wallet.rs",
        "crates/ths-server/src/api.rs"
      ],
      "deferred": false
    },
    {
      "id": "publication-health",
      "finding": 12,
      "priority": "P2",
      "kind": "Fix",
      "name": "Bound publication work and define server health",
      "description": "Wallet publication and pending-activity reconciliation extend beyond the synchronization deadline; health can rely on a past successful sync.",
      "why": "Many slow transaction lookups can hold the sync lock, while health may appear good after a later sync failure.",
      "change": "Bound canonical snapshot publication and activity reconciliation separately; define whether health means alive, initialized, or currently synchronized.",
      "impact": "Timeout and readiness behavior become explicit while preserving coherent last-good data.",
      "consider": "Merged PR #143 fixes a different concurrent-block publication problem. Test many pending rows, stalled RPC, current sync errors after prior success, and coherent publication.",
      "paths": [
        "crates/ths-server/src/api.rs"
      ],
      "deferred": false
    },
    {
      "id": "browser-freshness",
      "finding": 13,
      "priority": "P2",
      "kind": "Fix",
      "name": "Repair query freshness after SSE reconnects",
      "description": "Mutation and event invalidation maps differ, and reconnecting can leave active queries stale after changes during disconnection.",
      "why": "With focus refetch disabled, users may keep seeing old wallet or explorer data until another event happens.",
      "change": "Share a small invalidation map and refresh relevant active queries when EventSource opens or reconnects.",
      "impact": "The browser repairs missed changes without a durable event bus or a second client ledger.",
      "consider": "Recheck PR #92 lag-resync work separately. Cover reconnect without a later mutation, missed events, disabled SSE, and avoiding needless unrelated detail refetches.",
      "paths": [
        "web/src/hooks/mutations.ts",
        "web/src/hooks/useServerEvents.ts",
        "web/src/app/providers.tsx"
      ],
      "deferred": false
    },
    {
      "id": "client-limits",
      "finding": 14,
      "priority": "P2",
      "kind": "Fix",
      "name": "Reject oversized send amounts before submission",
      "description": "The send form parses exact bigint amounts but lacks the protocol upper limit before JSON-number conversion. Max formatting is separately filed as #162.",
      "why": "Invalid amounts travel farther than necessary and can lose exactness when extremely large values are converted for transport.",
      "change": "Validate parsed send amounts against MAX_MONEY before conversion; preserve the general decimal parser and stricter faucet ceiling.",
      "impact": "Users receive an inline amount error without a send request; server validation remains authoritative.",
      "consider": "Accept the protocol limit, reject one zatoshi above it and very large input, and assert no submission. Balance and fee checks remain separate.",
      "paths": [
        "web/src/features/wallet/schemas.ts",
        "web/src/lib/money.ts",
        "web/src/lib/api/endpoints.ts"
      ],
      "deferred": true
    },
    {
      "id": "cli-http",
      "finding": 15,
      "priority": "P2",
      "kind": "Cleanup",
      "name": "Share repeated CLI HTTP setup",
      "description": "Mining, address faucet, account faucet, and send repeat running-instance checks, endpoint lookup, and 300-second client setup.",
      "why": "Transport maintenance requires editing multiple commands, with inconsistent operation context in response errors.",
      "change": "Start with one private setup helper; share status/JSON decoding only if the signature stays readable and command-specific context survives.",
      "impact": "Less repeated plumbing, while commands retain request bodies, outputs, journal handling, and completion decisions.",
      "consider": "Keep one client across account batches, per-request timeouts, sequential aggregation, locks and key retention. Add no automatic retries. Docker error classification and send retry gaps are separate fixes.",
      "paths": [
        "crates/ths-cli/src/runtime.rs",
        "crates/ths-cli/src/main.rs"
      ],
      "deferred": true
    },
    {
      "id": "bootstrap-atomicity",
      "finding": 16,
      "priority": "P2",
      "kind": "Fix",
      "name": "Make wallet bootstrap persist atomically",
      "description": "Seed, mnemonic, and account initialization can cross separate app-database commit boundaries. Mechanical claim/SQL reuse is tracked in #153.",
      "why": "Interruption can leave only part of the bootstrap state durable.",
      "change": "Persist related bootstrap state within a deliberate transaction and define recovery for existing partial state.",
      "impact": "Restart either finds a complete coherent bootstrap or a safely recoverable incomplete state.",
      "consider": "Inject failure at each persistence boundary. Preserve deterministic credentials and account/treasury identity; do not mix this with a cosmetic SQL refactor.",
      "paths": [
        "crates/ths-server/src/db.rs"
      ],
      "deferred": false
    },
    {
      "id": "database-constraints",
      "finding": 16,
      "priority": "P2",
      "kind": "Fix",
      "name": "Add targeted database constraints with migration support",
      "description": "Several persisted app invariants are enforced by code rather than schema constraints.",
      "why": "Unexpected or legacy invalid rows can violate journal relationships and state assumptions.",
      "change": "Design explicit migrations and only necessary constraints for valid statuses, pools, amounts, and journal references.",
      "impact": "Storage enforces chosen invariants consistently across writers without introducing an ORM.",
      "consider": "Audit legacy data and rollback/recovery behavior. Enabling foreign keys alone does not create constraints. Preserve claim fingerprint and memo distinctions.",
      "paths": [
        "crates/ths-server/src/db.rs"
      ],
      "deferred": false
    },
    {
      "id": "journal-ownership",
      "finding": 17,
      "priority": "P2",
      "kind": "Cleanup",
      "name": "Decide ownership before consolidating prepared journals",
      "description": "Raw bytes and expiry are stored in both SDK/wallet extension state and the app journal.",
      "why": "Duplication adds ownership decisions, but the wallet extension also preserves the atomic activity-to-transaction link across a crash.",
      "change": "Specify ownership and recoverable projections, then consolidate only after proving migration and crash-recovery equivalence.",
      "impact": "Potentially fewer payload copies and clearer recovery responsibilities without losing constructed transactions.",
      "consider": "This is conditional, not immediate deletion. Test crash before/after each DB commit, lost accepted-broadcast response, old rows missing bytes, and expired replacement.",
      "paths": [
        "crates/ths-server/src/wallet.rs",
        "crates/ths-server/src/db.rs",
        "crates/ths-server/src/api.rs"
      ],
      "deferred": false
    },
    {
      "id": "explorer-work",
      "finding": 18,
      "priority": "P2",
      "kind": "Cleanup",
      "name": "Fetch only the explorer data that is consumed",
      "description": "Block lists retrieve full transactions; prevout fetches deduplicate linearly and run sequentially; hash search can return data discarded before refetch.",
      "why": "Requests perform avoidable local RPC work, while unresolved prevouts need clear error semantics.",
      "change": "Validate lower block verbosity on the pinned node, use request-local deduplication, and simplify search results where compatible. Measure before adding bounded concurrency.",
      "impact": "Potentially smaller responses and less repeated retrieval; no latency improvement has yet been measured.",
      "consider": "Preserve detail endpoints, ordering, pagination, genesis/tip behavior, reorg handling, and distinguish unresolved inputs from zero. No global transaction cache.",
      "paths": [
        "crates/ths-server/src/api.rs",
        "crates/ths-server/src/rpc.rs",
        "web/src/features/explorer"
      ],
      "deferred": false
    },
    {
      "id": "boundary-contracts",
      "finding": 19,
      "priority": "P2",
      "kind": "Fix",
      "name": "Reject malformed API and explorer values",
      "description": "Unknown activity kinds become send, public account IDs are loosely bounded, statuses are arbitrary strings, and some monetary/nested RPC fields are weakly validated.",
      "why": "Invalid or evolving data can be silently misclassified or fail later during rendering or bigint conversion.",
      "change": "Validate the app enums and public-account range, safe integer money with correct signedness, and only nested detail fields the UI consumes.",
      "impact": "Contract errors appear at the request boundary rather than as plausible wrong data or deep rendering failures.",
      "consider": "Separate app contracts from RPC schemas. Inspect external-address activity semantics before restricting all destination IDs. Preserve intentional older-server optionals. Row keys and pool reuse are already #164/#165.",
      "paths": [
        "web/src/lib/api/schemas.ts",
        "web/src/features/explorer"
      ],
      "deferred": true
    },
    {
      "id": "pczt-feature",
      "finding": 23,
      "priority": "P3",
      "kind": "Cleanup",
      "name": "Review the unused direct pczt declaration",
      "description": "The server declares direct pczt/signing features without an identified production source reference.",
      "why": "A declaration may be redundant, but it can still activate features used transitively.",
      "change": "Inspect the locked feature graph and remove the direct declaration only if it is unnecessary.",
      "impact": "A simpler manifest; not necessarily one fewer resolved package or a smaller binary.",
      "consider": "Run all-target/all-feature clippy, Rust tests, and the server build. Do not change pinned crypto versions.",
      "paths": [
        "crates/ths-server/Cargo.toml",
        "Cargo.lock"
      ],
      "deferred": false
    },
    {
      "id": "cors-feature",
      "finding": 23,
      "priority": "P3",
      "kind": "Cleanup",
      "name": "Remove unused CORS feature activation",
      "description": "tower-http enables CORS while the server router uses filesystem and trace capabilities.",
      "why": "Unused feature activation makes the manifest less accurate and can pull unnecessary feature code into builds.",
      "change": "Verify production/test consumers and feature closure, then remove cors if unused.",
      "impact": "Manifest capabilities more closely match actual use; build-size savings remain unmeasured.",
      "consider": "Keep serving and tracing behavior, dependencies, and host binding unchanged. Run the required Rust checks.",
      "paths": [
        "crates/ths-server/Cargo.toml",
        "crates/ths-server/src/main.rs"
      ],
      "deferred": false
    },
    {
      "id": "tokio-features",
      "finding": 23,
      "priority": "P3",
      "kind": "Cleanup",
      "name": "Evaluate narrowing Tokio full features",
      "description": "Tokio full is activated across the workspace.",
      "why": "Broad activation obscures the runtime capabilities actually needed, but narrowing may add maintenance complexity.",
      "change": "Inspect the workspace and all-target feature closure; narrow only if the result remains straightforward.",
      "impact": "A more explicit manifest with any build savings determined by measurement.",
      "consider": "Include tests and binary targets; keep worker, signal, time, process, and I/O needs intact. Do not replace runtime architecture.",
      "paths": [
        "Cargo.toml",
        "crates/ths-cli/Cargo.toml",
        "crates/ths-server/Cargo.toml"
      ],
      "deferred": false
    },
    {
      "id": "stale-comments",
      "finding": 24,
      "priority": "P3",
      "kind": "Cleanup",
      "name": "Correct stale synchronization comments",
      "description": "Some dashboard comments still say GET /accounts performs wallet synchronization, though the route now reads the server snapshot.",
      "why": "Outdated explanations can lead maintainers to make wrong freshness or ownership assumptions.",
      "change": "Update references in FetchProgress and AccountCardSkeleton, plus directly related stale descriptions found by caller inspection.",
      "impact": "Documentation in source describes the current snapshot contract.",
      "consider": "Retain comments explaining invariants and compatibility; avoid unrelated comment churn. No behavior change is intended.",
      "paths": [
        "web/src/components/ui/FetchProgress.tsx",
        "web/src/features/wallet/AccountCardSkeleton.tsx"
      ],
      "deferred": false
    },
    {
      "id": "release-gates",
      "finding": 25,
      "priority": "P3",
      "kind": "Decision",
      "name": "Decide release-candidate verification parity",
      "description": "The audit found release-candidate gates different from main CI, with web build alone and selected live recovery cases.",
      "why": "A release can have a different validation envelope than ordinary changes unless that difference is intentional.",
      "change": "Explicitly choose web gate parity and which additional live recovery scenarios justify their runtime before changing workflows.",
      "impact": "Release evidence becomes deliberate and documented rather than inferred from the existence of tests.",
      "consider": "Recheck current workflows first. Preserve native ARM builds, digests, release feature gating, archive checks and atomic replacement. This is release-sensitive policy work.",
      "paths": [
        ".github/workflows/ci.yml",
        ".github/workflows/release.yml"
      ],
      "deferred": false
    }
  ],
  "filed": [
    {
      "number": 153,
      "name": "Reduce duplication in db.rs: the activity projection and the transfer/faucet bodies",
      "state": "OPEN",
      "priority": "P2",
      "url": "https://github.com/zcashlabs/thus-spoke-zakura/issues/153",
      "finding": [
        16
      ],
      "related": false
    },
    {
      "number": 154,
      "name": "Reduce duplication in wallet.rs: the build-and-broadcast path and the nested subtree-root match",
      "state": "OPEN",
      "priority": "P3",
      "url": "https://github.com/zcashlabs/thus-spoke-zakura/issues/154",
      "finding": [
        22
      ],
      "related": false
    },
    {
      "number": 155,
      "name": "Remove dead code and a duplicate network constructor from the server and launcher",
      "state": "OPEN",
      "priority": "P3",
      "url": "https://github.com/zcashlabs/thus-spoke-zakura/issues/155",
      "finding": [
        20
      ],
      "related": false
    },
    {
      "number": 157,
      "name": "refactor(server): share the send and account-faucet lifecycle",
      "state": "OPEN",
      "priority": "P2",
      "url": "https://github.com/zcashlabs/thus-spoke-zakura/issues/157",
      "finding": [
        8
      ],
      "related": false
    },
    {
      "number": 158,
      "name": "fix(wallet): run blocking wallet operations through with_db",
      "state": "OPEN",
      "priority": "P1",
      "url": "https://github.com/zcashlabs/thus-spoke-zakura/issues/158",
      "finding": [
        7
      ],
      "related": false
    },
    {
      "number": 162,
      "name": "fix(web): make Send Max amounts valid at 1,000 ZEC and above",
      "state": "OPEN",
      "priority": "P2",
      "url": "https://github.com/zcashlabs/thus-spoke-zakura/issues/162",
      "finding": [
        14
      ],
      "related": false
    },
    {
      "number": 163,
      "name": "refactor(web): remove unused dashboard adapters",
      "state": "OPEN",
      "priority": "P3",
      "url": "https://github.com/zcashlabs/thus-spoke-zakura/issues/163",
      "finding": [
        20
      ],
      "related": false
    },
    {
      "number": 164,
      "name": "fix(web): use unique keys for transaction input rows",
      "state": "OPEN",
      "priority": "P3",
      "url": "https://github.com/zcashlabs/thus-spoke-zakura/issues/164",
      "finding": [
        19
      ],
      "related": false
    },
    {
      "number": 165,
      "name": "refactor(web): reuse shared pool validation and activity error messages",
      "state": "OPEN",
      "priority": "P3",
      "url": "https://github.com/zcashlabs/thus-spoke-zakura/issues/165",
      "finding": [
        19,
        24
      ],
      "related": false
    },
    {
      "number": 166,
      "name": "fix(cli): reject invalid port offsets before deleting an instance",
      "state": "OPEN",
      "priority": "P1",
      "url": "https://github.com/zcashlabs/thus-spoke-zakura/issues/166",
      "finding": [
        3
      ],
      "related": false
    },
    {
      "number": 167,
      "name": "fix(web): preserve theme selection when localStorage is blocked",
      "state": "OPEN",
      "priority": "P3",
      "url": "https://github.com/zcashlabs/thus-spoke-zakura/issues/167",
      "finding": [
        24
      ],
      "related": false
    },
    {
      "number": 168,
      "name": "fix(web): distinguish node connectivity from wallet readiness",
      "state": "OPEN",
      "priority": "P3",
      "url": "https://github.com/zcashlabs/thus-spoke-zakura/issues/168",
      "finding": [
        24
      ],
      "related": false
    },
    {
      "number": 169,
      "name": "refactor(tests): share valid installer fixture packaging",
      "state": "OPEN",
      "priority": "P3",
      "url": "https://github.com/zcashlabs/thus-spoke-zakura/issues/169",
      "finding": [
        25
      ],
      "related": false
    },
    {
      "number": 170,
      "name": "refactor(web): define dark theme tokens once",
      "state": "OPEN",
      "priority": "P3",
      "url": "https://github.com/zcashlabs/thus-spoke-zakura/issues/170",
      "finding": [
        21
      ],
      "related": false
    },
    {
      "number": 128,
      "name": "fix(web): correct Explorer search and address feedback",
      "state": "OPEN",
      "priority": "P3",
      "url": "https://github.com/zcashlabs/thus-spoke-zakura/issues/128",
      "finding": [
        24
      ],
      "related": false
    },
    {
      "number": 144,
      "name": "ths faucet can pay twice when an interrupted request is retried",
      "state": "OPEN",
      "priority": "P1",
      "url": "https://github.com/zcashlabs/thus-spoke-zakura/issues/144",
      "finding": [
        9
      ],
      "related": false
    },
    {
      "number": 159,
      "name": "fix(server): log the full error chain for 500 responses and failed operations",
      "state": "OPEN",
      "priority": "P2",
      "url": "https://github.com/zcashlabs/thus-spoke-zakura/issues/159",
      "finding": [],
      "related": true
    },
    {
      "number": 161,
      "name": "Retrying a payment right after a client hangs up during broadcast returns 500 \"already queued for download\"",
      "state": "OPEN",
      "priority": "P1",
      "url": "https://github.com/zcashlabs/thus-spoke-zakura/issues/161",
      "finding": [],
      "related": true
    },
    {
      "number": 131,
      "name": "Check Docker ownership before instance cleanup",
      "state": "CLOSED",
      "priority": "P1",
      "url": "https://github.com/zcashlabs/thus-spoke-zakura/issues/131",
      "finding": [
        1
      ],
      "related": false
    },
    {
      "number": 149,
      "name": "Make faucet retries safe across address API, CLI, and dashboard",
      "state": "CLOSED",
      "priority": "P1",
      "url": "https://github.com/zcashlabs/thus-spoke-zakura/issues/149",
      "finding": [
        6,
        9
      ],
      "related": false
    },
    {
      "number": 135,
      "name": "fix(faucet): show CLI faucet transfers in dashboard activity",
      "state": "CLOSED",
      "priority": "P2",
      "url": "https://github.com/zcashlabs/thus-spoke-zakura/issues/135",
      "finding": [
        9
      ],
      "related": false
    }
  ]
}
