Commit Graph
66 Commits
Author SHA1 Message Date
Chris Troutner ec753a9c88 Add property tests for the topics table view model
- Add client property tests for buildTopicsTable: one row per topic in input
  order, four-cell alignment with the header order, link percent-encoding
  round trips, and post/follower count conservation over random topic lists
  that also omit count/last-seen fields.
- No production change: the coder's view model already scans at CRAP 1.0
  with zero dry4javascript candidates and only 2 mutation sites. The JSX
  Topics component stays a thin, tool-excluded shell over the testable model.

Verification: client 447 unit / 94 property / 34 acceptance + lint + build;
indexer 113 unit / 12 property / 7 acceptance + lint; db 392 unit / 57
property / 16 acceptance + lint.

By refactorer.
2026-09-18 07:42:52 -07:00
Chris Troutner ac4d9ea7f7 Render topics page as a table
Replace the topics page flex list with a react-bootstrap Table driven by a
testable topics-table view model: a labeled header row, aligned cells for
name, relative time, post count, and follower count, feed links on each row,
and a horizontal-scroll wrapper for narrow screens.

By coder.
2026-09-18 07:36:16 -07:00
Chris Troutner dd11964174 Refactor topic metadata: cut CRAP, share test doubles, harden property tests
- Replace the ternary follower delta in recordTopicFollow with
  Number(isActive) - Number(wasActive), dropping its cyclomatic complexity
  from 8 to 6 (CRAP 8.0 -> 6.0). No behavior change.
- Extend the indexer topic property test to conserve lastSeen (newest post
  time) and followerCount (each address's final active follow state)
  alongside postCount/lastHeight, with varying post seen times.
- Extend the DB backfill and topic-query property tests to conserve lastSeen
  and followerCount; generated follows now include unfollows.
- Add a client topic-metadata property test covering relativeTime bucket
  classification, pluralization, monotonicity, and getLastSeenLabel
  consistency, and cover ensureTopicRoom's existing-summary path plus
  recordTopicFollow's legacy-follower-count fallback.
- Share one in-memory DB double per component (indexer test/support/
  memory-db.js, DB test/support/level-double.js) and table-drive the
  parallel topic-follow/topic-message/topic-query cases, clearing every
  dry4javascript candidate in the changed files.

Verification: indexer 113 unit / 12 property / 7 acceptance; db 387 unit /
57 property / 16 acceptance; client 441 unit / 90 property / 33 acceptance
+ build; lint clean. CRAP max 6.0; mutation scans under 100 sites/file.

By refactorer.
2026-09-18 06:02:13 -07:00
Chris Troutner 8da0f09f46 Implement topic metadata columns
Add lastSeen and followerCount to topicSummaries across the indexer, DB,
and client. The indexer now tracks the newest post seen time, updates
follower counts idempotently on follow/unfollow, and preserves post
metadata. The DB exposes lastSeen and followerCount from GET /topics and
rebuilds both from the rooms store in the backfill. The client renders the
four-column topics page with relative-time labels.

By coder.
2026-09-18 05:46:58 -07:00
Chris Troutner 92ce290873 Refactor topic recency indexing: cut CRAP, harden property coverage
- Extract roomFromEntry/applyPost from backfill collectSummaries so its
  cyclomatic complexity drops from 7 to 4 (CRAP 7.0 -> 4.0), and extract
  the shared roomRange key bounds from getTopicPostTxids/listRoomFollowers.
- Add indexer property tests over arbitrary post/follow/unfollow
  interleavings: postCount conservation, newest-height recency shape,
  replay idempotence, and inverted-key ordering.
- Add DB property tests for the topic index backfill: conservation,
  recency shape, stale-record removal, and inverted-key ordering.
- Cover the topic action error paths (invalid push counts, oversized
  topic message), the topic-query room fallbacks, and the client
  openTopic/topicFeedPath navigation.

By refactorer.
2026-09-17 08:07:24 -07:00
Chris Troutner e02bea5460 Implement topic recency ordering and pagination
- Indexer maintains topicSummaries and topicRecency for topic messages and
  follows, idempotently, moving each room's recency record to its newest post.
- DB adds the two index stores and serves GET /topics from them with
  limit/offset pagination, without iterating the rooms store. Adds
  util/room/backfill-topic-indexes.js to build the indexes idempotently.
- Client topics page loads 50 per page with Previous/Next.

By coder.
2026-09-17 07:24:45 -07:00
Chris Troutner fac01730c4 Review multi-push encoding: fix browser Buffer and harden coverage
Import the browser-safe buffer module in the multi-push adapter so the
CRA production bundle no longer reads the Node global Buffer, add
regression tests for the falsy-wallet and idempotent-attach paths, share
the script-encoding test helper, and de-duplicate the UTF-8 push
acceptance assertions. Refresh the language mutation manifests and the
soft acceptance-mutation manifest.

By architect.
2026-09-16 21:31:23 -07:00
Chris Troutner 8310b6a1d8 Refactor multi-push helpers and add adapter property tests
Share a single UTF-8 encoding helper across hex, poll-create, and
topic-post instead of repeating new TextEncoder().encode(), drop the
redundant Uint8Array branch in the push normalizer, rename the
txid-action push builder parameter from buildPayload to buildPushes to
match what it returns, and factor the db repair unit-test setup into a
repairedFixture helper.

Add property tests for the multi-push adapter covering prefix/ordering,
field-byte conservation, buffer round trips, array expansion, single
field delegation, and idempotent attach, plus a unit test for the
unsupported-wallet guard.

By refactorer.
2026-09-16 20:56:42 -07:00
Chris Troutner 2e2db86263 Implement multi-push encoding for Memo multi-field actions
Reply, topic message, add-poll-option, poll-vote, and create-poll now
broadcast each protocol field as its own OP_RETURN script push instead of
combining them into one push. The indexer requires three pushes for reply,
topic message, and poll children, and accepts four for create-poll; the
combined form was rejected or misparsed.

hex.js builds the txid and text as separate pushes, and a new
memo-multipush adapter teaches minimal-slp-wallet's single-push sendOpReturn
to expand an array of fields into separate pushes. Acceptance step handlers
assert the individual pushes, and unit/property tests cover the new shape.

By coder.
2026-09-16 20:37:59 -07:00
Chris Troutner a2229f7dd4 Review txid wire encoding: harden mutation coverage and DRY test doubles
Refresh the mutate4javascript and Gherkin acceptance-mutation manifests,
kill the memo-like/memo-reply boundary survivors, and extract the shared
FakeDb/makeLevel double used by the txid repair unit and property tests.

By architect.
2026-09-16 15:25:23 -07:00
Chris Troutner a76fceee73 Refactor txid wire encoding and repair library
Share the txid-and-text payload builder between hex and reply, extract the
repair store loop from repairTxidEncoding to cut CRAP from 13 to 5, correct
the poll-services property test to the little-endian wire order, and add
property tests for wire round trips and repair idempotence/conservation.

By refactorer.
2026-09-16 14:59:00 -07:00
Chris Troutner dedb7a1343 Fix txid wire encoding and add txid repair utility
Client likes, replies, poll options, and poll votes now embed the
referenced txid in little-endian wire order, matching the indexer's
byte reversal. Add a psf-memo-db repair library and CLI that rewrites
byte-reversed references in likes, postParents, pollOptions, and
pollVotes and rebuilds the postLikes and postChildren indexes, leaving
correct and unknown references untouched and staying idempotent.

By coder.
2026-09-16 14:40:13 -07:00
Chris Troutner e071881ea0 Harden like result modal: kill mutation survivors and DRY test setup
Add unit coverage for the LikeTipPage initial state, deps seeding, the
dust-limit boundary, and empty/null tip parsing, and assert exact
validation/broadcast error messages. Add the NewPostPage initial
result-modal state assertion. Refresh the mutate4javascript footer
manifests for the touched services and the soft Gherkin
acceptance-mutation manifest for the like-result feature.

By architect.
2026-09-16 12:29:53 -07:00
Chris Troutner e978516a0f Refactor like result modal and share the block explorer link
Deduplicate the new like-result acceptance steps behind one render helper,
and extract the bch.loping.net transaction link shared by the New Post result
modal, the post options menu, and the like/tip result into a block-explorer
service. Cover the LikeTipPage open/parse/handler failure branches and add
property tests for the explorer URL, the LikeResult markup, and the result
modal state machine.

CRAP is at or below 5 with full coverage on the changed services; every
changed/new plain source file scans at 21 or fewer mutation sites. The
existing mutation manifests are left for the mutation tool to refresh.

By refactorer.
2026-09-16 12:03:41 -07:00
Chris Troutner a0040f98c1 Implement like broadcast result modal
Keep the like/tip modal open after a successful like and show a broadcast
result instead of closing: the success message, the like transaction id, and
a link to that transaction on bch.loping.net that opens in a new tab. The
like count and filled heart update immediately, and dismissing the result
closes the modal. The result state lives on the testable LikeTipPage
controller; a server-renderable LikeResult component backs the modal and the
acceptance adapter, with acceptance step handlers for the new wording.

By coder.
2026-09-16 11:41:49 -07:00
Chris Troutner 07ff61392b Harden post-options menu: testable outside-click, kill mutation survivors
Move the outside-click decision into the pure post-options service so the
effect stays a thin adapter and the previously uncovered `&&` mutation is
unit testable. Add unit tests for the outside-click predicate and for the
default no-focus open menu, killing the two surviving `-1` default-focus
mutations.

Stamp the mutate4javascript manifests for both modules and the soft
acceptance-mutation manifest for post-options-menu.

By architect.
2026-09-16 10:02:29 -07:00
Chris Troutner d0882bbd82 Refactor post options menu and add property tests
Move the keyboard shortcut mapping into the pure post-options service so the
React component is a thin adapter and the Escape/ArrowDown decisions are unit
and property testable. DRY the duplicated post-options acceptance steps behind
two helpers, and add property tests for the explorer URL, menu-item shape,
state transitions, key command, and rendered markup.

The createElement post-options component and service stay scannable by
mutate4javascript; the JSX call sites (post-feed-item, profile) are unchanged
except for rendering the shared menu.

By refactorer.
2026-09-16 09:48:36 -07:00
Chris Troutner 20e67da216 Implement post options menu on every post card
Add a shared PostOptionsMenu component, used by the feed/thread post card and
the profile post card, with a pure post-options service for the block explorer
link and the open/close/focus state. Its first item links to the post
transaction on bch.loping.net in a new tab; the menu opens on the button and
closes on the button again, an outside click, or Escape, with ArrowDown moving
focus to the first item.

By coder.
2026-09-16 09:42:15 -07:00
Chris Troutner 19e57be1ec Review post-image-rendering: cover isImageUrl guard, stamp manifests
Merged the refactorer handoff (e77e174). The architecture holds: the image
helpers isImageUrl/imageAltText are pure post-links functions, failed-images
is a pure state transition, and PostImage/PostContent stay presentational
with no IO. Added a unit test for isImageUrl non-string input to kill the
last surviving language mutant; mutation and acceptance manifests are
tool-written.

By architect.
2026-09-16 07:34:13 -07:00
Chris Troutner e77e174c92 Refactor post image rendering and cover image helpers
Extract the pure failed-image set transition into a testable service,
DRY the acceptance no-link/no-image assertions, and add property tests
for image URL detection, alt text, and image rendering.

By refactorer.
2026-09-16 07:20:40 -07:00
Chris Troutner 3971e0736f Render image URLs inline in posts
Recognize common image file extensions in post URLs (query string and
fragment ignored), render them as inline images inside new-tab anchors
with the filename as alt text, and fall back to a plain link when the
image fails to load. Non-image URLs keep the existing plain-link
behavior.

By coder.
2026-09-16 07:07:40 -07:00
Chris Troutner b63792fb7b Review post-link-formatting: kill link-parser boundary mutants
Harden the post link parser after the refactorer handoff:
- add start-of-text and leading-token boundary unit tests and drop a
  redundant range guard, killing the isBareDomainBoundary survivors
- replace the mutable React key counter with React.Children.toArray and
  assert the embedded iframe is fullscreen, killing both PostContent
  mutation survivors
- record the client verification pass and the review summary

By architect.
2026-09-15 19:33:46 -07:00
Chris Troutner e17c515065 Add property tests for post link parsing
Cover parsePostLinks invariants over broad seeded random inputs: round
trip reconstruction, link/text segment shape, trailing-punctuation
handling, input ordering, email exclusion, and determinism.

By refactorer.
2026-09-15 19:20:48 -07:00
Chris Troutner 6c7952f469 Format post URLs and bare domains as links
Render http(s) URLs and bare domains in post text as anchors that open in a
new tab. Explicit URLs keep their scheme; bare domains get an https href while
their visible text stays as written. Embeddable YouTube links keep their
embedded-player behavior.

By coder.
2026-09-15 19:08:49 -07:00
Chris Troutner 8244e11ec4 New posts display TXID after broadcast 2026-09-13 06:42:14 -07:00
Chris Troutner 8088d73fc3 Add property tests for account page avatar display logic
By refactorer.
2026-09-05 13:09:09 -07:00
Chris Troutner afd4585374 Implement account avatar image display on the account page
By coder.
2026-09-05 13:04:24 -07:00
Chris Troutner 448bddc31f Implement mute feed filtering across recent, topic, search, and notifications feeds
By coder.
2026-09-04 12:23:00 -07:00
Chris Troutner 5e1f4739e3 Broadcast follow/mute/unfollow/unmute hash160 payloads as Uint8Array
Replaces the Node-only Buffer global in memo-follow and memo-mute with
the existing hexToBytes helper, which returns a Uint8Array. Updates unit
and property tests to assert bytes without requiring Buffer in the
production source, and adds an acceptance handler for the new binary
payload wording so the Binary Payload Broadcast regression spec passes.

By coder.
2026-09-04 11:13:15 -07:00
Chris Troutner a4cd814931 Review page-size-50: harden pagination null edge, document equivalents
By architect.
2026-09-04 10:45:35 -07:00
Chris Troutner a9488d9ae2 Refactor paginated pages onto shared base, add property coverage
Extract PaginatedPage base for the recent feed and recent profiles page
controllers to remove the duplicated load/canLoadMore pattern introduced
with the 50-item page size. Refresh mutation manifests via the tool. Add
property tests for the base pagination invariants (canLoadMore mirrors
hasMore, load forwards limit/offset, item lookup).

By refactorer.
2026-09-04 10:06:27 -07:00
Chris Troutner 38f7a42b90 Merge commit '59cce4426d' into swarmforge-refactorer 2026-09-04 10:00:44 -07:00
Chris Troutner 59cce4426d Reduce paginated client page size to 50
By coder.
2026-09-04 10:00:19 -07:00
Chris Troutner 9ec8760b59 Add property tests for youtube-embed parser invariants
Cover round-trip reconstruction, segment shape, non-YouTube URLs staying
text, and video-id round trips over broad random inputs.

By refactorer.
2026-09-04 09:43:51 -07:00
Chris Troutner b63019c31f Review youtube-embed: harden parser edge cases, document equivalents
Add unit tests for invalid video id and non-/watch youtube.com URL to
kill mutation survivors; document the match[1]/match[0] equivalent and
the soft-Gherkin example-value equivalents.

By architect.
2026-09-04 09:28:13 -07:00
Chris Troutner 8e606aecb1 Implement YouTube embed rendering in recent posts feed
By coder.
2026-09-04 08:50:28 -07:00
Chris Troutner 5c6bffd6de Add getViewerAddress property tests for reactive precedence
Pin the profile wallet-address selector invariants over broad input
space: reactive-state precedence, wallet fallback, and null-on-absent.
CRAP (3.0), DRY, and mutation scan assessed; no split needed and no
manifests discarded.

By refactorer.
2026-09-03 16:13:15 -07:00
Chris Troutner c294617782 Fix profile page wallet address wiring so Follow button appears for other profiles
Use the reactive bchWalletState.cashAddress as the viewer address source
and include it in the profile load effect dependencies. Extract a small
wallet-address selector so the behavior is unit-testable.

By coder.
2026-09-03 16:07:48 -07:00
Chris Troutner 8ee07fc35f Implement Notifications read-only feature
Add psf-memo-db notifications query, use case, route, and tests.
Add psf-memo-client NotificationsPage service, React page, nav link,
route, and tests. Wire acceptance handlers for notifications.

By coder.
2026-09-02 12:53:02 -07:00
Chris Troutner 4bf99e7db0 Review and harden following feed: kill survivors, DRY parseRequiredString
- Extract parseRequiredString into pagination.js, shared by the three list
  use cases, removing duplicated required-field guards.
- Add client hardening tests (emptyBecauseNoFollows init, canLoadMore null
  guard) and a DB composition-root test for UseCases.start.
- Refresh mutation manifests and Gherkin acceptance-mutation stamp.

By architect.
2026-09-02 12:20:37 -07:00
Chris Troutner d606ee6608 Refactor following feed: reduce CRAP/DRY, add property coverage
- Extract shared runUseCase and listPostsForAddr in the posts controller to
  remove the duplicated try/catch error wrapper (CRAP 14.7 -> 4.0) and DRY
  the addr-scoped handlers.
- Add error-path unit tests for the posts controller covering both branches
  of handleError.
- Consolidate ListFollowingFeed onto the shared ListUseCase constructor to
  remove constructor duplication across list use cases.
- Add property tests for scanFollowingFeedTxidsAndCount (ordering, reply/
  viewer/membership exclusion, pagination conservation) and for the client
  FollowingFeedPage.load state invariants.

By refactorer.
2026-08-29 10:44:28 -07:00
Chris Troutner 6d1bd148e9 Implement Following feed
Add psf-memo-db endpoint GET /posts/following/:addr that returns top-level
posts from followed profiles, excluding replies and the viewer's own posts,
newest first and paginated. Add PostQuery.scanFollowingFeedTxidsAndCount,
ListFollowingFeed use case, and REST controller/router wiring.

Add psf-memo-client Following feed page, route /posts/following, nav link,
MemoDb.getFollowingFeed, and FollowingFeedPage service. Update acceptance
handlers for the new following-feed.feature.

By coder.
2026-08-29 10:30:54 -07:00
Chris Troutner e8bf42a1f3 Review and harden search: kill mutation survivors, refresh manifests
Add hardening tests to kill mutation survivors in SearchQuery guards and
profileMatches defaults, SearchAll pagination/empty-query guards, the search
REST controller 500-error path, and the client SearchPage constructor/getPost/
getProfile. Refresh mutation manifests and the Gherkin acceptance-mutation
stamp.

By architect.
2026-08-29 08:51:42 -07:00
Chris Troutner 8508fdaff0 Implement Search feature (P6.4)
- Add psf-memo-db /search endpoint with SearchQuery adapter, SearchAll use case,
  and REST controller/router.
- Add psf-memo-client SearchPage service, Search component, route, and nav link.
- Wire search support into the acceptance handler fake MemoDb.
- Add unit tests for the new adapter, use case, controller, and page service.

By coder.
2026-08-29 07:18:39 -07:00
Chris Troutner ac468072df Review and harden mute-user: kill mutation survivors, refresh manifests
Add hardening tests to kill mutation survivors in MemoMute.validate,
ProfilePage constructor/_loadState/canMute, MuteQuery._nextString,
MuteState validation guards, and the mute REST controller statused-error
path. Refresh mutation manifests and Gherkin acceptance-mutation stamps.

By architect.
2026-08-28 21:08:50 -07:00
Chris Troutner d8ab5bc79c Refactor mute-user: reduce DRY, add property coverage
Extract shared _getState/_getList helpers in the client MemoDb, a shared
_loadState/_setState base in ProfilePage, and a runAction helper for the
profile follow/mute handlers. Add property tests for the MemoMute service,
the DB MuteQuery adapter, and the indexer handleMute action. Preserve
behavior; all unit, acceptance, and property suites pass across client, DB,
and indexer.

By refactorer.
2026-08-28 19:58:39 -07:00
Chris Troutner 4b03210e85 Implement mute/unmute user feature (0x6d16/0x6d17)
- Client: MemoMute service, ProfilePage mute controls, Profile UI Mute/Unmute buttons,
  Profiles mute state, MemoDb mute read APIs, unit/acceptance tests.
- DB: mutes LevelDB store, MuteQuery adapter, /mute REST routes, MuteState and ListMuted use cases, tests.
- Indexer: mute/unmute action codes, handleMute action handler, muteDb adapter, tests.
- Backlog: mark P4.1/P4.2 mute/unmute as shipped.

By coder.
2026-08-28 19:38:42 -07:00
Chris Troutner 06e95150e3 Review and harden poll actions: kill mutation survivors, reduce DRY
- Add hardening tests to kill mutation survivors across client, DB, and
  indexer (hex guards, poll byte-limit boundaries, busy-flag defaults,
  parseTxid empty-string, polls controller handleError, memo-codes
  isMemoPrefix, normalizePollCreateDatas, storePollChildRecord returns).
- Reduce duplication: extract shared reflect/isTooLong into MemoTxidAction
  (client), shared _run into the polls controller and configurable execute
  into PollReadUseCase (DB).
- Refresh mutation manifests and Gherkin acceptance-mutation stamps.

By architect.
2026-08-28 17:51:03 -07:00
Chris Troutner 739b13bfb2 Refactor poll actions: reduce CRAP/DRY, add property coverage
Extract shared txid-action and poll-page bases in the client, a shared
poll-read use-case base and a poll-txid iteration helper in the DB, and a
shared poll-child record helper in the indexer. Reduce normalizePollCreateDatas
complexity (CRAP 7.1 -> 5.0). Add property tests for poll services, handlers,
and query filtering. Preserve behavior; all unit, acceptance, and property
suites pass across client, DB, and indexer.

By refactorer.
2026-08-28 15:23:04 -07:00
Chris Troutner cf05de6630 Implement poll actions (create, option, vote) across client, indexer, and DB
- Client: add MemoPollCreate, MemoPollOption, MemoPollVote services and page controllers.
- Indexer: add create-poll, add-poll-option, and poll-vote handlers with new poll DB adapters.
- DB: add polls/pollOptions/pollVotes stores, PollQuery adapter, GET /polls/:txid endpoints, and use cases.
- Add Gherkin acceptance handlers and focused unit tests for all three components.

By coder.
2026-08-28 14:50:05 -07:00