# txid-wire-encoding — Architect Review Task: `txid-wire-encoding` Components: `psf-memo-client`, `psf-memo-db` Base: `bf7edd5` (last merged architect review); inbound refactorer commit `a76fcee` ## What was reviewed Inbound refactorer batch (priority 10), merged onto `swarmforge-architect` by fast-forwarding to `a76fcee`. The linear chain reviewed: - **`bb0c9ab`** — specifier: *Spec txid wire encoding and database repair*. Adds `psf-memo-client/specs/txid-wire-encoding.feature` (4 scenario outlines pinning the like, reply, poll-option, and poll-vote wire order) and `psf-memo-db/specs/repair-txid-encoding.feature` (6 scenario outlines for the byte-reversed-reference repair utility). - **`dedb7a1`** — coder: *Fix txid wire encoding and add txid repair utility*. Adds `txidToWireBytes` and reverses the txid in `buildTxidTextPayload`, so likes, replies, poll options, and poll votes now embed the referenced txid little-endian; adds the `repair-txid-encoding` library (`correctReference`, `repairTxidEncoding`), the `util/txid` CLI wrapper, unit tests, the DB acceptance fixture/handlers, and decodes the wire txid in the client acceptance handlers. - **`a76fcee`** — refactorer: *Refactor txid wire encoding and repair library*. Generalizes the four near-identical repair loops into `repairStore` plus a `txidIndex` key/value adapter, replaces the reply-only `buildReplyPayload` with the shared `buildTxidTextPayload(txid, text, label)`, and adds client and DB property tests (round trip, involution, idempotence, conservation, resolution, index rebuild). **Architect review commit: `a2229f7dd4`** — the `mutate4javascript` footer manifests (client `hex.js`, `memo-like.js`, `memo-reply.js`; DB `src/lib/repair-txid-encoding.js`), the soft `gherkin-mutator` acceptance-mutation manifests on both touched feature files, the hardening tests below, and the extracted shared test double. The summary and verification records are committed on top, so `git diff a2229f7dd4 HEAD` touches only `docs/`. The records' `git_sha` is `a2229f7dd4`, the commit that contains the verified source state. ## Architectural findings and fixes applied The refactorer's structure is sound and required no further boundary change. The hardening work was mutation- and duplication-driven. 1. **UI/Core separation.** `src/services/hex.js` is a pure leaf (byte decode, reverse, payload assembly) with no React, DOM, wallet, or IO. `memo-like.js` and `memo-reply.js` are core services that receive the wallet/feed/thread behind injected adapter doubles. `src/lib/repair-txid-encoding.js` is a pure async core that receives the LevelDB handles; only `util/txid/repair-txid-encoding.js` opens real stores. Every piece of core behavior is exercised without a browser, network, or database file. 2. **Dependency rule.** The client services depend inward on `hex.js`; the DB CLI wrapper depends inward on `src/lib`. Nothing in the pure modules reaches out to React, the router, LevelDB, or the file system. 3. **Information hiding.** The little-endian wire order now has exactly one definition (`txidToWireBytes`), and the txid+text payload shape has one definition (`buildTxidTextPayload`). The refactorer's `repairStore` + `txidIndex` hide the per-store field/key/value differences behind a small adapter, and `correctReference` hides the "keep / reverse / leave" decision. No persistence structure leaks into callers. 4. **Minor coupling, accepted.** `buildTxidTextPayload` defaults its label to `'Poll txid'`, a residue of its poll-only origin. It is now generic and the reply caller passes `'Parent txid'` explicitly; the poll callers rely on the default. A fully neutral default was not worth churning the poll call sites. 5. **Test boundaries.** The task-local `FakeDb`/`makeLevel` double was duplicated verbatim across the new unit and property tests, so it was extracted to `psf-memo-db/test/support/level-double.js` (a test helper, kept out of `test/unit/**` and `test/property/*.test.js`). The util CLI wrapper is an environmentally unsuitable adapter shell and is deliberately excluded from the tools that run tests/coverage/mutation. 6. **Mutation hardening (see below).** Six pre-existing boundary survivors in `memo-like.js` and one in `memo-reply.js` were killed with focused boundary assertions rather than design changes. ## Verification results ### Language mutation (`mutate4javascript`, `--mutate-all` where the wrapper detected differential under-selection, `--max-workers 8`) | File | Sites | Killed | Survived | Uncovered | |------|------:|-------:|---------:|----------:| | `psf-memo-client/src/services/hex.js` | 7 | 7 | 0 | 0 | | `psf-memo-client/src/services/memo-like.js` | 34 | 34 | 0 | 0 | | `psf-memo-client/src/services/memo-reply.js` | 2 | 2 | 0 | 0 | | `psf-memo-db/src/lib/repair-txid-encoding.js` | 6 | 6 | 0 | 0 | The first `memo-like.js` run left 9 survivors (`true -> false` on the `validate`/`validateTip` return values, the `validateTip` `tipSats > spendableSats` boundary, the `_validateTipAmount` max-tip boundary, the `getSpendableSats` `?? 0` default, the `_requireTipAddress` `<= 0` and `.length > 0` boundaries, the `_buildTipOutput` `tipSats > 0` boundary, and the `_incrementPostCount` `|| 0` default). `memo-reply.js` left the `isTooLong` `> MAX_REPLY_BYTES` boundary. Each was a missing boundary/default assertion, not a design fault; focused unit assertions were added and the re-runs report 34/0 and 2/0. `hex.js` and the DB repair library were clean on the first full run. `psf-memo-db/util/txid/repair-txid-encoding.js` is not mutated: it is the file-system adapter shell (opens real LevelDB stores, no unit coverage by design), and the tool that runs tests is scoped to the testable core. ### DRY (`dry4javascript`) Scoped runs over the changed production files, tests, and adapters. - **DB.** The verbatim `FakeDb`/`makeLevel` duplication across the two new test files was extracted to `test/support/level-double.js`; the scoped report dropped from 72 to 70 duplicate blocks. Every remaining block is pre-existing `acceptance/lib/handlers.js` step-handler boilerplate, except one structurally identical but semantically distinct pair in the unit test (like/postLikes vs reply/postChildren index-rebuild assertions), left as deliberate test boilerplate. - **Client.** The task-local candidates are two `makeWallet` doubles (`test/property/poll-services.property.test.js` vs `test/unit/memo-reply.test.js`) and one structurally identical pair of like-rejection tests in `memo-like.test.js`. `makeWallet` appears in 28 client test files as an established per-suite fixture convention, so extracting it would be a broad cross-suite refactor beyond this task; both are recorded as documented pattern-boilerplate. The remaining blocks are pre-existing `acceptance/lib/handlers.js` boilerplate. ### CRAP / cyclomatic complexity (`crap4javascript`) - **Client:** every changed function at or below CRAP 6.0 with ~100% coverage — `MemoLike._validateTipAmount` (CC 6, 100%, 6.0), `hexToBytes` (CC 5, 5.0), `MemoLike._incrementPostCount` (CC 5, 5.0), `MemoLike.getSpendableSats` (CC 4, 4.0), the rest CC ≤ 3. `MemoReply.reply` is 90% covered but CRAP 2.0. - **DB:** `repairStore` (CC 5, 100%, 5.0), `correctReference` (CC 4, 4.0), `hasRecord` (CC 4, 4.0), `reverseTxid` (CC 3, 3.0), `repairTxidEncoding`/ `txidIndex` (CC 1). All below the 8.0 threshold. ### Soft Gherkin acceptance mutation (`gherkin-mutator --level soft`) - **`txid-wire-encoding.feature`** (client): **14 executed, 8 killed, 6 survived, 0 errors**. All six survivors are single-character case mutations of values that are never asserted: reply `message` (`hello memo`, `a second one`), poll `option` (`yes`, `no`), and poll-vote `comment` (`yes`, `I choose this`). Each scenario asserts the Memo prefix and the referenced txid, not the carried text, so the mutated text is an intrinsic equivalent / weak example-to-assertion link. The wire-order txid mutations (the point of the feature) were killed. - **`repair-txid-encoding.feature`** (DB): **21 executed, 18 killed, 3 survived, 0 errors**. All three survivors mutate the `reversedPostTxid` example value in scenarios 0, 1, and 5, which use it only in the negative assertion "the postLikes store contains 0 entry whose key starts with ``". Since the key is absent by construction, any mutated value still yields 0 entries — a genuine negative-assertion equivalent. All positive repair and index assertions killed their mutations. These survivors are specifier-side feature-quality items (weak text assertions), not implementation gaps; no implementation change is warranted. ### Suite status Canonical records, both against review commit `a2229f7dd4523e6397418e2bb8ac43800940b902`: - `swarmforge/scripts/verify.sh client --record docs/reviews/txid-wire-encoding-verification.json --task txid-wire-encoding` -> **pass (5/5)**: unit **417 pass / 0 fail**, property **80 pass / 0 fail**, acceptance **all 30 suites passed**, lint **ok**, build **ok**. - `swarmforge/scripts/verify.sh db --record docs/reviews/txid-wire-encoding-db-verification.json --task txid-wire-encoding` -> **pass (4/4)**: unit **371 passing**, property **54 pass / 0 fail**, acceptance **all 13 suites passed**, lint **ok**. This is the first recent task to touch two components, so the client record uses the canonical `-verification.json` name and the DB record uses `-db-verification.json`; both carry the same review `git_sha`. ## Handoffs sent - End-of-chain `git_handoff` to the specifier (task `txid-wire-encoding`) with the review commit `a2229f7dd4` so it can merge `swarmforge-architect` into `master`. - No coder/refactorer handoff: the review is mutation hardening plus a test-double extraction with no follow-up work for those roles. By architect.