Add the architect review summary and the machine-readable client verification
record (git_sha 07ff61392b) for task post-options-menu.
By architect.
6.1 KiB
post-options-menu — Architect Review
Task: post-options-menu
Component: psf-memo-client
Base: 5e62d1e (last merged architect review); inbound refactorer commit d0882bb
What was reviewed
Inbound refactorer batch (priority 10), merged onto swarmforge-architect by
fast-forwarding to d0882bb. The linear chain reviewed:
091272d— specifier: Record feed-total-cap completion in backlog and briefing.bc964fa— specifier: Specify post options menu for all post cards. Addspsf-memo-client/specs/post-options-menu.feature(9 scenario outlines across the recent/following/topic/thread/profile surfaces) and the backlog entry.20e67da— coder: Implement post options menu on every post card. Adds the puresrc/services/post-options.js, thesrc/components/post-feed/post-options-menu.jsshared React component, the acceptance render adapter, the post-options acceptance handlers, and unit tests; wires the menu intopost-feed-item.jsandprofile/index.js.d0882bb— refactorer: Refactor post options menu and add property tests. Moves the key-command mapping intopostOptionsKeyCommandin the pure service so the component is a thin adapter, DRYs the duplicated acceptance step bodies behindtogglePostOptionsMenu/transitionActivePostOptionsMenu, and addstest/property/post-options.property.test.js.
Architect review commit: 07ff61392b — the two mutate4javascript manifest
footers, the soft gherkin-mutator acceptance-mutation manifest stamp on
post-options-menu.feature, and the hardening changes described below. The
summary and verification record are committed on top, so
git diff 07ff61392b HEAD touches only docs/. The record's git_sha is
07ff61392b, the commit that contains the verified source state.
Architectural findings and fixes applied
The refactorer's structure is sound: a framework-free core service, a React adapter, and a separate acceptance render adapter. Two testability gaps found by language mutation were fixed with a behavior-preserving extraction.
- UI/Core separation.
src/services/post-options.jsis plain CommonJS with no React, DOM, or IO; it owns URL construction and the open/close/focus transitions. The React component consumes it throughrequireand only maps state to markup. The acceptance pipeline reaches the same service throughacceptance/lib/render-post-options.js, which server-renders the actual component. Core behavior is exercised with no browser. - Dependency rule. The service depends on nothing; the component and the acceptance adapter depend inward on the service. No framework or persistence structure leaks across the boundary.
- Uncovered mutation / testable boundary. The outside-click decision was an
inline
containerRef.current && !containerRef.current.contains(event.target)insideuseEffect, which the unit (node --test) harness never executes, so the&& -> ||mutation was uncovered. Extracted it to the pureisOutsidePostOptions(container, target)in the service; the effect is now a thin adapter and the decision is unit tested. This follows the role rule to maximize testable modules and minimize the environmentally unsuitable shell. - Mutation survivors. Two
-1default-focus literals survived because no unit test rendered an open menu with the default (unfocused) state: theinitialFocusedIndex = -1default and thetabIndex ... : -1else branch. Added a unit test asserting the default open menu makes no item tabbable, killing both. (Property tests are a separate suite and are intentionally not part of the language-mutation test command.) - Duplication. The refactorer's acceptance-step DRY is local and clear; the
new service helper adds no duplication.
dry4javascriptreported 96 duplicate blocks, all pre-existingacceptance/lib/handlers.jsstep-handler boilerplate; none involves the post-options modules. - Test/helper separation.
render-post-options.js(acceptance helper) and the property-test generators live in their helper libraries, separate from the unit and property test files.
Verification results
Language mutation (mutate4javascript, differential, --max-workers 8)
Initial component run before the fix: 3 killed, 2 survived, 1 uncovered. After the extraction and unit tests:
src/services/post-options.js: 10 covered sites. Differential selected 1 of 10 after the new function;mutate-file.shauto-reran--mutate-all: 10 killed, 0 survived, 0 uncovered.src/components/post-feed/post-options-menu.js: 5 killed, 0 survived, 0 uncovered.
DRY (dry4javascript)
Changed source/tests/handlers plus acceptance/lib/handlers.js:
no duplicate candidate involves the new code. 96 reported blocks are
pre-existing handler step-handler boilerplate, consistent with prior reviews.
CRAP / cyclomatic complexity (crap4javascript)
All changed functions below the 8.0 threshold:
PostOptionsMenu (CC 3, 81.8% covered, CRAP 3.1 — the uncovered remainder is the
DOM useEffect shell), postOptionsKeyCommand (CC 3, CRAP 3.0),
isOutsidePostOptions (CC 2, 100%, CRAP 2.0), and the remaining service
accessors (CC 1–2, 100%).
Soft Gherkin acceptance mutation (gherkin-mutator --level soft)
post-options-menu.feature: 20 executed, 20 killed, 0 survived, 0 errors. All nine scenario outlines killed every soft mutation, so the tool wrote a full-feature acceptance-mutation manifest stamp (no survivors to document).
Suite status
swarmforge/scripts/verify.sh client --record docs/reviews/post-options-menu-verification.json --task post-options-menu
-> pass (5/5):
unit 364 passing, property 68 passing, acceptance all 28 suites
passing, lint pass, build pass. Record git_sha = 07ff61392b.
Handoffs sent
- End-of-chain
git_handoffto the specifier (taskpost-options-menu) with the review commit so it can mergeswarmforge-architectintomaster. - No coder/refactorer handoff: the review is test hardening plus a behavior-preserving extraction with no follow-up work for them.
By architect.