4.2 KiB
Architect Review — binary-payload-broadcast
Reviewed commits
62e0479Specify binary hash160 broadcast payload for follow/mute (specifier)5e1f473Broadcast follow/mute/unfollow/unmute hash160 payloads as Uint8Array (coder)53f6b90/8d40f2bDeduplicate Memo follow/mute onto shared MemoStateAction base (refactorer)
Task: Follow/unfollow and mute/unmute must broadcast the target's raw
20-byte hash160 (not its display-form cash address text) as the OP_RETURN
payload, and must not depend on the Node-only Buffer global. The refactorer
also consolidated the previously near-identical MemoFollow/MemoMute action
classes onto a shared MemoStateAction base.
Architectural findings
UI/Core separation — good. The follow/mute services remain pure logic over
injected wallet/profiles adapters. No UI, framework, or IO leaked into the
core; everything network/UI-specific stays behind the small wallet/profile
adapter boundaries. The modules remain fully testable without launching a UI or
network.
Dependency rule — good. MemoFollow/MemoMute → MemoStateAction →
MemoAction → hex/utf8. High-level action semantics depend on low-level
byte/hex helpers through a stable base; the direction is inward. The base
subclasses (MemoFollow, MemoMute) are thin facades exposing only
follow/unfollow and mute/unmute.
Information hiding / encapsulation — good. MemoStateAction encapsulates
the shared validate → toHash160 → hexToBytes → sendOpReturn → reflect
transition. Subclasses expose only config (followConfig/muteConfig) and
their two public methods; static exports and the public API are preserved. The
20-byte length lives on the base as PK_HASH_LENGTH, surfaced on both
subclasses.
Local code quality. The refactor is a clean DRY extraction (~150 duplicate lines removed). Two minor, pre-existing notes (not requiring change):
- Each config carries a
prefixkey that is unused (state actions pass the prefix explicitly to_setState); harmless dead config carried over from the priorMemoActioncontract. MemoStateAction.validatethrows a typed error whereas the baseMemoAction.validatereturns{ok:false}; contract difference is intended and documented in the module header.
No architectural changes were required. The merged work confirms and preserves
the earlier binary Uint8Array broadcast behavior (hexToBytes) and the
Buffer-free production source.
Verification
All per-component verification for psf-memo-client (the only touched
component) passed.
- Unit tests: 280/280 pass
- Property tests: 40/40 pass (run separately, as required)
- Lint: clean (
standard) - Acceptance: all 23 generated feature suites pass, including the new
binary-payload-broadcast.feature - Language mutation (
mutate4javascript --mutate-all --max-workers 8):memo-follow.js: 2 killed, 0 survived, 0 uncoveredmemo-mute.js: 2 killed, 0 survived, 0 uncoveredmemo-state-action.js(new base): 5 killed, 0 survived, 0 uncoveredhex.js/memo-action.jsunchanged and unaffected.
- DRY (
dry4javascript) onmemo-state-action.js/memo-follow.js/memo-mute.js: no duplicate candidates.
Soft Gherkin acceptance mutation (survivors)
gherkin-mutator --level soft over binary-payload-broadcast.feature:
4 mutations run, 4 survived, 0 killed, 0 errors. All four are single-character
case mutations of the shared example cash address (q→Q, x→X,
c→C, k→K). Each mutated example is applied consistently on both the
broadcast setup side and the assertion side of its scenario, so the scenario
still passes under the mutation (both sides derive from the same mutated
value). These are genuine intrinsic equivalents, not implementation gaps,
and match the documented read-only-payload survivor pattern. Documented here;
no chase performed.
Handoffs
No functional handoffs sent. The work was a review of an already-functional
refactorer merge; my branch adds only the durable review summary plus the
tool-refreshed manifests (mutation tested_at timestamps and the new
acceptance-mutation manifest) from the verification runs. Function and module
hashes in the mutation manifests are unchanged, confirming no code drift.