- Add DB unit tests covering a summary missing postCount, a post missing
blockHeight in listTopics/getTopicPostTxids ordering, listTopics' default
limit/offset, and topicRecencyKey's missing-height fallback. These kill the
remaining language-mutation survivors in the changed DB sources.
- Refresh the mutate4javascript manifests for the changed sources and commit
the gherkin-mutator manifests/stamps written into the three topic-metadata
features.
- No production behavior changes; the review adds tests and tool-written
metadata only.
By architect.
- 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.
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.
Define four-column topics page behavior across client, indexer, and DB:
topic name, time since most recent post, post count, and follower count.
By specifier.
A historical rooms record with an empty room name made the backfill call
put('') and abort with "key cannot be an empty String". Skip records with no
room name so the one-time backfill can complete; such rooms have no listing
entry to write.
By specifier.
Architectural review of the topic recency indexes and pagination:
- Indexer topic index maintenance lives in its own topic-indexing.js,
separate from the action handlers; the backfill library takes injected
LevelDB handles so its logic stays testable.
- DB listTopics reads counts from topicSummaries and paginates the
topicRecency index without iterating the rooms store; the client reuses
PaginatedPage.
- Kill four topic-indexing mutation survivors with focused unit tests
covering the height fallbacks, plus exact-key/isNotFound and max-size
boundary tests.
- One topic-message survivor is an intrinsic equivalent: handlePost reads
the text at push index 1 and ignores push index 0.
Includes tool-written mutate4javascript and acceptance-mutation manifests.
By architect.
The DB soft Gherkin mutation re-ran the whole feature for every mutant;
with a fresh LevelDB world per example, a 48-mutation feature exceeded
900s. The runner-worker now diffs the mutated IR against the base feature
at <work>/base/feature.json (derived from the mutation path, since
job.work_dir may be mutation-specific) and runs only the changed
scenario/example. Safe because each scenario uses an isolated world.
The same feature now completes in ~74s.
By architect.
Run the 15 generated DB acceptance files with bounded concurrency
(default min(4, files), ACCEPTANCE_CONCURRENCY to override) instead of
strictly sequentially. Generation still runs first and sequentially.
Each generated file uses its own tmp/acceptance/level-* world, so the
pool is isolated. Full DB acceptance drops from ~430-790s to ~96s.
Also record the orphaned-mocha mutation-hang finding and remediation in
the architect process notes.
By architect.
- 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.
- 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.
Add Gherkin for efficient GET /topics ordering by most recent post, the
topicSummaries and topicRecency index stores, an idempotent backfill, and
client topics-page pagination.
By specifier.
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.
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.
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.
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.
Add client Gherkin pinning little-endian wire order for every action that
embeds a parent txid (like, reply, poll option, poll vote), and a
psf-memo-db Gherkin for a utility that repairs existing byte-reversed
references and rebuilds the affected indexes.
By specifier.
Architectural review of the raised recent-feed total scan cap (10 -> 500)
and the refactorer's property tests. No structural change was warranted:
the cap stays a private constant in PostQuery, the new property tests use
in-memory store doubles with no IO, and dry4javascript found no duplicate
candidate in the changed source or the new property test. Mutation killed
all 37 sites in post-query.js.
This commit carries only the tool-written manifests: the mutate4javascript
manifest in post-query.js and the gherkin-mutator acceptance stamps in the
two touched feature files.
By architect.
Cover the total-scan cap and bounded raw scan of
PostQuery.scanRecentPostTxidsAndCount over seeded random corpora: capped
total, newest-first pagination conservation, the raw-scan bound, the 500
default cap, and reply exclusion.
By refactorer.
GET /posts/recent now caps its total scan at 500 eligible top-level posts
instead of 10, so corpora smaller than the cap report an exact total while
larger corpora stay bounded. Added unit coverage for the exact-total-under-cap
and default-cap cases, plus the many-top-level-posts acceptance fixture.
By coder.
Every acceptance run re-parsed and regenerated all features even when only
one changed. Record feature_hash and aps_commit in the per-feature metadata
and skip parse/generate when both match, and drop generated tests for
features that no longer exist.
By specifier.
There were up to four APS copies (tmp/aps, tmp/aps-spec, tmp/aps-fresh, and a
component-local client copy) and the briefing, wrappers, and runners disagreed
on which to use. Add ensure-aps.sh (ensure/update/reclone) as the one canonical
tmp/aps checkout, point the gherkin-parser wrapper, architect startup, and all
three acceptance runners at it, and update the architect cheat-sheet.
By specifier.
Each psf-memo-db acceptance scenario opened an isolated LevelDB directory
but close() only closed the handles, so tmp/acceptance grew without bound
(found at 961 dirs / 293 MB). Delete the scenario dir in close() and sweep
tmp/acceptance at the start of the acceptance run.
By specifier.
Encapsulate the postChildren prefix scan in PostQuery.listChildTxids and have
GetPostThread depend only on the PostQuery interface (listChildTxids,
getPostOrNull). countRepliesForTxids now reuses listChildTxids. Remove the dead
whole-database buildLikeCountMap that this task made obsolete. Cover the
prefix-scan guards and cycle back-edge, realign the thread property tests to the
adapter seam, and refresh mutation/Gherkin-acceptance manifests.
By architect.
Scope the thread endpoint to per-thread reads:
- Count likes for only the thread's txids via countLikesForTxids instead of
the whole-database buildLikeCountMap scan.
- Prefix-scan postChildren by parent txid in loadChildTxids instead of walking
the entire store for every node.
- Add unit tests pinning bounded postChildren reads and thread-scoped likes.
By coder.
Bound /posts/:txid/thread to per-thread reads: prefix-scan postChildren
by parent txid and scope like counts to the thread's txids instead of
the global postLikes scan. Record both implementation parts in the
feature backlog.
By specifier.
Extract reply/mute eligibility check into PostQuery.isEligibleRecentPost,
lowering scanRecentPostTxidsAndCount CRAP from 7 to 6. Refresh mutation
manifest.
By refactorer.
- Replace full-postHeights and full-postChildren scans in ListRecentPosts with
a single capped scan and per-page reply counting.
- Add PostQuery.scanRecentPostTxidsAndCount with TOTAL_SCAN_CAP=10.
- Update acceptance handlers and fixture for the new feed-query-performance
spec, and add entry-count wrappers for bounded-read assertions.
By coder.
Fix Adapters.openDatabases so muteQuery is constructed before postQuery, which
previously resolved an undefined muteQuery at PostQuery construction and silently
disabled recent-feed mute filtering. Fix the follow-notification key fallback to
strip the :<followeePkHash> suffix instead of key.split(':')[0] (which yielded
only the "bitcoincash" network prefix). Add unit tests for the shared muted-posts
helper and the follow key-fallback path.
By architect.
Extract the duplicated _mutedAddrs lookup and _isMutedPost check into a shared
lib helper (loadMutedAddrs / isMutedPost) used by the post, topic, search, and
notifications adapters. Extract follow/like notification predicates in
NotificationsQuery to bring CRAP down to 6. Add a mute-filtering conservation,
exclusion, and pagination property test for topic queries.
By refactorer.
- Add tests for profile/level handleError to raise coverage
- Extract DbBackup pure helpers into testable db-backup-util module
- Add tests for DbBackup zip/unzip and the pure helpers
- Extract shared handleControllerError helper across 7 REST controllers
By refactorer.
Pin the NotificationsQuery aggregation invariants over broad random
inputs: newest-first ordering with seen tie-break, global ordering, and
pagination conservation. Coverage, CRAP (max 6.0), DRY, and mutation
scan were assessed; all changed/new source files are well under the
100-site split threshold and mutation manifests are preserved.
By refactorer.
Extract the post-lookup-with-null helper into a shared module used by both
the notifications and post query adapters, removing duplication. Add a
dedicated NotificationsQuery unit suite (26 tests) and hardening tests that
kill the sort-comparator and followee-guard mutations. Refresh mutation
manifests via the approved tool. Document 5 intrinsic mutation equivalents
and 16 soft-Gherkin equivalents in the review summary.
By architect.
Extract the reply-notification predicate from
_collectReplyNotifications into a _replyNotificationChild helper, moving
the txid-presence guard into the loop so both functions drop to CRAP 5.
Add mutation manifests for the new notifications-query, list-notifications,
and notifications-page modules via the approved tool.
By refactorer.
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.
Extract the reply/viewer/membership predicate from
scanFollowingFeedTxidsAndCount into an isFolloweePost helper, reducing
the scan's cyclomatic complexity from 7 to 5 (CRAP 7.0 to 5.0) while
preserving behavior. Refresh the mutation manifest via the approved tool.
By refactorer.
- 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.
- 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.
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.