mirror of
https://github.com/Permissionless-Software-Foundation/psf-memo.git
synced 2026-09-21 16:52:01 -07:00
Add the architect review summary and the machine-readable client verification
record (unit, property, acceptance, lint, build) pinned to review commit
a7d9ca6299.
By architect.
8.2 KiB
8.2 KiB
Mute Broadcast Result — Architect Review
By architect.
Task and commits reviewed
- Task:
mute-broadcast-result(refactorer handoffmerge_and_process refactorer 722c486ef6). - Merged
swarmforge-refactorer(fast-forward froma1e4a4f). Commits:c0e18d8Add mute broadcast result specification (specifier)24d7f0fImplement mute broadcast result (coder)722c486Refactor mute broadcast result: share result handlers, add property tests (refactorer)
- Architect review commit:
a7d9ca6299(dead-store removal + error-getter test hardening + tool-written mutation/acceptance manifests). - Verification record
git_sha:a7d9ca6299(client). - Records/summary commit: this commit.
The feature shows a broadcast result modal on the profile page after a
mute/unmute (Memor 0x6d16/0x6d17): on success the success message, the mute
txid, and a link to that transaction on the block explorer (new tab); on failure
the broadcast error message. A successful mute flips the button to Unmute and a
successful unmute flips it back to Mute; a failed broadcast leaves the button in
its previous state. The modal stays open until dismissed and dismissing closes
it without navigating. Client-only, mirrors the like/tip and New Post result
modals. Touches psf-memo-client only.
Architectural findings
- UI/Core separation (good). The mute result state machine lives in the pure
controller
src/services/profile-page.js(_broadcastMute,getMuteBroadcastMessage,getMuteResultError,dismissMuteResult) with thememoDb/memoFollow/memoMute/viewer-address dependencies injected by the React page.src/components/app-body/profile/mute-result.jsand the extractedsrc/components/explorer-tx-link.jsare presentational plainReact.createElementcomponents shared by the browser JSX build and the Node acceptance adapter (acceptance/lib/render-mute-result.js). The whole feature is testable without a DOM or network. - Dependency rule (good).
profile-page.jsdepends only on the pureblock-explorerutil.MemoMute/MemoDb(IO) and the wallet are constructed in the React adapter shell (profile/index.js) and injected inward. No core module imports a component, service, or IO module; dependency direction runs from the adapter shell inward to the controller. - Information hiding (good, one simplification).
_broadcastMuterecords the outcome inlastMuteResultand exposes only getters; the reflected button state is updated inside_setStateafter the injected handler succeeds, so a failed broadcast cannot change the button. The reset ofshowMuteResultModalat the start of_broadcastMutewas a dead store — the flag is set true unconditionally after the awaited broadcast, so no observer can read the reset value. Removed (see Fixes). - DRY / acceptance structure (good). The refactorer generalized the
like/tip and mute broadcast-result acceptance assertions behind
BROADCAST_RESULTS+renderBroadcastResult, the follow/unfollow/mute/unmute broadcast checks behindassertMemoBroadcastPrefix, and extracted the sharedExplorerTxLinkused by bothLikeResultandMuteResult. Behavior is unchanged; the broad DRY run now reports only the pre-existinghandlers.jsstep-handler boilerplate (untouched lines), and the changed production/test set reports no duplicate candidates. - Mutation surface.
explorer-tx-link.js,mute-result.js, andlike-result.jseach scan as 0 mutation sites (structural, likeblock-explorer.js): they are built from!/ternary/template-literal markup with no arithmetic, comparison, or boolean operators the tool targets. Their behavior is pinned by unit and property tests instead. The only mutated module with sites isprofile-page.js. - Observation, not changed — merge included two earlier master commits.
The fast-forward from
a1e4a4fto722c486also brought inea67979(remove redundant author name from posts) and8eab46d(notifications CSS + entry tweaks), both committed tomasterbefore the mute spec and outside the refactorer handoff. They were not the subject of this review; the full client suite (unit/property/acceptance/lint/build) passes with them. - Observation, not changed —
render-like-result/render-mute-resultadapters are near-identical. They render different components and DRY reports no candidate at its thresholds, so they are left as separate test helpers (test helpers stay separate from the modules under test).
Fixes applied
- Removed the dead
showMuteResultModalreset.ProfilePage._broadcastMuteset the modal hidden, then set it visible unconditionally after the awaited broadcast. The reset was unobservable and left a surviving equivalent mutant (false -> true); deleting it removes the site and the dead state write. - Pinned
getMuteResultError's empty-string contract. Added two unit tests: no result (constructor defaultnull) and a failure result with no message. These kill both|| -> &&mutants in the getter (the null case exercises the short-circuit guard, the no-message case exercises the trailing|| ''). - No further production changes were needed. Module structure, dependency direction, and information hiding were accepted.
Verification results
Record (pinned to the review commit a7d9ca6299):
| File | Component |
|---|---|
docs/reviews/mute-broadcast-result-verification.json |
psf-memo-client |
- Language mutation (
mutate4javascript,--max-workers 8,--mutate-all; wrapper confirmed all sites selected):src/services/profile-page.js: 31 killed, 0 survived, 0 uncovered. First differential run selected all 32 sites (30 killed / 2 survived: the dead modal reset and thegetMuteResultErrorguard) → after the fixes, 31 sites, all killed.src/components/explorer-tx-link.js,src/components/app-body/profile/mute-result.js,src/components/post-feed/like-result.js: 0 mutation sites (structural).- Total: 31 killed, 0 survived, 0 uncovered.
src/services/memo-db.jswas not mutated: the client HTTP adapter is a standing mutation exclusion (ESM +../configdirectory import).
- DRY (
dry4javascript, scoped to the changed production files, the acceptance adapters, and the new/changed tests): No duplicate candidates found. The broad run overacceptance/lib/handlers.jsreports only pre-existing step-handler boilerplate on lines untouched by this task. - Cyclomatic complexity / CRAP (
crap4javascript): max CRAP 4.0 (ProfilePage._broadcastMuteCC 4,getMuteBroadcastMessageCC 4,getMuteResultErrorCC 4, all 100% covered);ExplorerTxLinkandMuteResultCC 2,LikeResultCC 1, every other changed function CC ≤ 3 at 100%. All functions are below the 8.0 threshold; no refactor was warranted. - Soft Gherkin acceptance mutation (
gherkin-mutator --level soft --workers 8),psf-memo-client/specs/mute-broadcast-result.feature: 5 total, 0 killed, 5 survived, 0 errors. All 5 are single-character case mutations of example values (addrin scenarios 1–4,broadcast_errorin scenario 4) used consistently on both the Given setup and the Then assertion side, so the mutated value still matches — the documented intrinsic-equivalent class. None is an implementation gap and none was chased.gherkin-mutatorwrote a manifest with"scenarios":[]because every scenario has an intrinsic survivor; committed as tool-written.
Suite status
verify.sh client result: pass at git_sha a7d9ca6299:
- unit: 484 pass / 0 fail
- property: 111 pass / 0 fail
- acceptance: all 36 generated suites passed (including all 4 mute-broadcast-result scenarios)
- lint: ok
- build: ok
Handoffs
- End-of-chain
git_handofftospecifier(priority 50) to mergeswarmforge-architectintomaster, using this records/summary commit. git_handofftocoderandrefactorer(priority 00) with the review commita7d9ca6299for follow-up review: the only production change is the removal of the deadshowMuteResultModalreset inProfilePage._broadcastMute; the rest is two edge-case unit tests and tool-written manifests.