mirror of
https://github.com/Permissionless-Software-Foundation/psf-memo.git
synced 2026-09-21 16:52:01 -07:00
Review topic-recency-pagination: harden mutation coverage
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.
This commit is contained in:
@@ -1,3 +1,8 @@
|
||||
# mutation-stamp: sha256=62b1088abcd456b0067ce18fd78f32c715254e912046c44d8d67fdd54417147f
|
||||
# acceptance-mutation-manifest-begin
|
||||
# {"version":1,"tested_at":"2026-09-17T17:23:44.068113041Z","feature_name":"Backfill topic indexes","feature_path":"/home/trout/work/psf-memo/.worktrees/architect/psf-memo-db/specs/backfill-topic-indexes.feature","background_hash":"386b39215fd2ac58af1a095ce21b3e5a94c26a052be33ebb653986f56d1cdaf5","implementation_hash":"unknown","scenarios":[{"index":0,"name":"Backfill topic indexes - 1 backfill summarizes every room","scenario_hash":"98e2a49f35bf2c57825af892d343b091df3b8ea9938d88877112a244195e2b6a","mutation_count":9,"result":{"Total":9,"Killed":9,"Survived":0,"Errors":0},"tested_at":"2026-09-17T17:23:44.068113041Z"},{"index":1,"name":"Backfill topic indexes - 2 backfill builds the recency index","scenario_hash":"6210a596d0011bd42ab984430a01e639932e19bb99dd05e6b79c0e3d8e50ccdc","mutation_count":6,"result":{"Total":6,"Killed":6,"Survived":0,"Errors":0},"tested_at":"2026-09-17T17:23:44.068113041Z"},{"index":2,"name":"Backfill topic indexes - 3 backfill is idempotent","scenario_hash":"93b5d81880c0f9bf768aa363353607761c7cebd4d6b1c6cef52eae0f40fd3cc0","mutation_count":6,"result":{"Total":6,"Killed":6,"Survived":0,"Errors":0},"tested_at":"2026-09-17T17:23:44.068113041Z"}]}
|
||||
# acceptance-mutation-manifest-end
|
||||
|
||||
# Scenarios: Backfill topic indexes - 1, Backfill topic indexes - 2, Backfill topic indexes - 3
|
||||
#
|
||||
# The topic backfill utility builds topicSummaries and topicRecency from the
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
# acceptance-mutation-manifest-begin
|
||||
# {"version":1,"tested_at":"2026-09-17T17:22:41.386110241Z","feature_name":"Topic Pagination","feature_path":"/home/trout/work/psf-memo/.worktrees/architect/psf-memo-db/specs/topic-pagination.feature","background_hash":"4a01ae658dda9a91b7f19edbeb3e657bef1d666b5355b8dd30496013bed35d7e","implementation_hash":"unknown","scenarios":[]}
|
||||
# acceptance-mutation-manifest-end
|
||||
|
||||
# Scenarios: Topic Pagination - 1, Topic Pagination - 2, Topic Pagination - 3
|
||||
#
|
||||
# GET /topics returns a page of topics ordered by their most recent post's
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# acceptance-mutation-manifest-begin
|
||||
# {"version":1,"tested_at":"2026-09-04T14:07:09.030166090Z","feature_name":"Topic Read","feature_path":"/home/trout/work/psf-memo/.worktrees/architect/psf-memo-db/specs/topic-read.feature","background_hash":"922fd45b8606f723073833f0aaca0e6d92b03a263a6b54c60490843e0ac41cc0","implementation_hash":"unknown","scenarios":[{"index":4,"name":"Topic Read - 5 GET /topics orders topics by most recent post","scenario_hash":"fcb48583a39be06c616d4d1636d06ac7e985a16fa7d9f66d9c9c43e95639812c","mutation_count":1,"result":{"Total":1,"Killed":1,"Survived":0,"Errors":0},"tested_at":"2026-09-04T14:07:09.030166090Z"},{"index":0,"name":"Topic Read - 1 GET /topics lists distinct topics with their post counts","scenario_hash":"a425a0cbf18c7e7fcb7d01c3571556d4c184b013ad7990e724d95d8d100eebb9","mutation_count":8,"result":{"Total":8,"Killed":8,"Survived":0,"Errors":0},"tested_at":"2026-08-28T15:39:33.364455310Z"},{"index":1,"name":"Topic Read - 2 GET /topics/:room/posts returns the posts for a topic sorted by block height descending","scenario_hash":"cffb702052b0df29aa87510e0c45dd01b83c4607e7ce915bc0e660d601f79cce","mutation_count":4,"result":{"Total":4,"Killed":4,"Survived":0,"Errors":0},"tested_at":"2026-08-28T15:39:33.364455310Z"}]}
|
||||
# {"version":1,"tested_at":"2026-09-17T17:24:59.147244904Z","feature_name":"Topic Read","feature_path":"/home/trout/work/psf-memo/.worktrees/architect/psf-memo-db/specs/topic-read.feature","background_hash":"1a085ee8fae67e6f4b1217ee65d86b03af1088ca1a468da8a9edef83683332b3","implementation_hash":"unknown","scenarios":[{"index":0,"name":"Topic Read - 1 GET /topics lists distinct topics with their post counts","scenario_hash":"a425a0cbf18c7e7fcb7d01c3571556d4c184b013ad7990e724d95d8d100eebb9","mutation_count":8,"result":{"Total":8,"Killed":8,"Survived":0,"Errors":0},"tested_at":"2026-09-17T17:24:59.147244904Z"},{"index":1,"name":"Topic Read - 2 GET /topics/:room/posts returns the posts for a topic sorted by block height descending","scenario_hash":"cffb702052b0df29aa87510e0c45dd01b83c4607e7ce915bc0e660d601f79cce","mutation_count":4,"result":{"Total":4,"Killed":4,"Survived":0,"Errors":0},"tested_at":"2026-09-17T17:24:59.147244904Z"},{"index":4,"name":"Topic Read - 5 GET /topics orders topics by most recent post","scenario_hash":"fcb48583a39be06c616d4d1636d06ac7e985a16fa7d9f66d9c9c43e95639812c","mutation_count":1,"result":{"Total":1,"Killed":1,"Survived":0,"Errors":0},"tested_at":"2026-09-17T17:24:59.147244904Z"}]}
|
||||
# acceptance-mutation-manifest-end
|
||||
|
||||
# Scenarios: Topic Read - 1, Topic Read - 2, Topic Read - 3, Topic Read - 4, Topic Read - 5
|
||||
|
||||
@@ -170,5 +170,5 @@ class TopicQuery {
|
||||
export default TopicQuery
|
||||
|
||||
// mutate4javascript-manifest-begin
|
||||
// {"version":1,"tested_at":"2026-09-04T20:12:29.631Z","module_hash":"c839533977040f56c6f45a1aa1e64ee422567570556c6beac19fe72d0c5970f0","functions":[{"id":"func/TopicQuery.constructor","name":"TopicQuery.constructor","line":16,"end_line":35,"hash":"56e5538d08449cf5870754c0e1e440b7d7e6a90ae5320b678fee77b18abcb81a"},{"id":"func/TopicQuery.roomFromKey","name":"TopicQuery.roomFromKey","line":37,"end_line":40,"hash":"4175916ac2bb8f9f102c70750f336ed980db2a30a1f8f35645534303408aaece"},{"id":"func/TopicQuery.txidFromKey","name":"TopicQuery.txidFromKey","line":42,"end_line":45,"hash":"4f5f5c456f1e74a60acff54d1d5e2d982be53886c2a77c6eff3293133efa9c87"},{"id":"func/TopicQuery.listTopics","name":"TopicQuery.listTopics","line":47,"end_line":76,"hash":"b96bd821ff6eb1e14abe4418004f74418d3276666ca185c544c90d2095b08474"},{"id":"func/TopicQuery.getTopicPostTxids","name":"TopicQuery.getTopicPostTxids","line":78,"end_line":98,"hash":"943729090c4532333410ee001c75ecdd45a562dfffd6f1f6d5e9313489f1b76a"},{"id":"func/TopicQuery.isFollowingRoom","name":"TopicQuery.isFollowingRoom","line":101,"end_line":110,"hash":"a0cf48cc6f4842adf65830b41d536cd6a078c7adf6b837e57259491157e2e97d"},{"id":"func/TopicQuery.listRoomFollowers","name":"TopicQuery.listRoomFollowers","line":113,"end_line":124,"hash":"351d71881e8b0953366056f223a6f06326e8ecd946277abc372ae5771c0b0f08"},{"id":"func/TopicQuery.followAddrFromValue","name":"TopicQuery.followAddrFromValue","line":126,"end_line":130,"hash":"2ce68c35f539e1fd7694774059b4b2afd096014c99a87c7538f3cbb70e26c3c7"}]}
|
||||
// {"version":1,"tested_at":"2026-09-17T17:27:18.416Z","module_hash":"a31f16e3a18a841a71910ab28019ded60ef8800bc08dcd5460dfb21a84194903","functions":[{"id":"func/TopicQuery.constructor","name":"TopicQuery.constructor","line":24,"end_line":52,"hash":"51f22d20b4d0bb817f3b005e12f1635a3669a77bd741c3f0b386bc71fa28c08e"},{"id":"func/TopicQuery.roomFromKey","name":"TopicQuery.roomFromKey","line":54,"end_line":57,"hash":"4175916ac2bb8f9f102c70750f336ed980db2a30a1f8f35645534303408aaece"},{"id":"func/TopicQuery.txidFromKey","name":"TopicQuery.txidFromKey","line":59,"end_line":62,"hash":"4f5f5c456f1e74a60acff54d1d5e2d982be53886c2a77c6eff3293133efa9c87"},{"id":"func/TopicQuery.roomRange","name":"TopicQuery.roomRange","line":67,"end_line":69,"hash":"ceb99a638ee22ce625c9962d90786bd779de8d946b501640db9b76276c8bd7ea"},{"id":"func/TopicQuery.summaryRoom","name":"TopicQuery.summaryRoom","line":73,"end_line":76,"hash":"8ca2c04ae70839ca8e2deebe6f0661883dacbf3a06731dd9c134f326bf921b7c"},{"id":"func/TopicQuery.recencyRoom","name":"TopicQuery.recencyRoom","line":80,"end_line":84,"hash":"677abdcb0687362d170da432571cb0912bc43d4bd6e7022e3d785714f8bd9402"},{"id":"func/TopicQuery.listTopics","name":"TopicQuery.listTopics","line":90,"end_line":117,"hash":"75cb4c5ee90a44a156119f08226d0d3a8a75c136568676cdbd484c3f1e55a943"},{"id":"func/TopicQuery.getTopicPostTxids","name":"TopicQuery.getTopicPostTxids","line":119,"end_line":137,"hash":"c18e8ca08fa3695cc2d49bbc0a83eb5488831bf14ddfdb9c421afefd4b91d521"},{"id":"func/TopicQuery.isFollowingRoom","name":"TopicQuery.isFollowingRoom","line":140,"end_line":149,"hash":"a0cf48cc6f4842adf65830b41d536cd6a078c7adf6b837e57259491157e2e97d"},{"id":"func/TopicQuery.listRoomFollowers","name":"TopicQuery.listRoomFollowers","line":152,"end_line":161,"hash":"40dc014f433895e930bfec5de78d73ca2f75a023cecb174ddc57f7ec150dd300"},{"id":"func/TopicQuery.followAddrFromValue","name":"TopicQuery.followAddrFromValue","line":163,"end_line":167,"hash":"2ce68c35f539e1fd7694774059b4b2afd096014c99a87c7538f3cbb70e26c3c7"}]}
|
||||
// mutate4javascript-manifest-end
|
||||
|
||||
@@ -150,5 +150,5 @@ class TopicsRESTControllerLib {
|
||||
export default TopicsRESTControllerLib
|
||||
|
||||
// mutate4javascript-manifest-begin
|
||||
// {"version":1,"tested_at":"2026-08-28T19:53:31.127Z","module_hash":"4c3f3e9152899ed272cb583e558c4522c0f54c37a0ae728f3ec6bc40248a3fdc","functions":[{"id":"func/TopicsRESTControllerLib.constructor","name":"TopicsRESTControllerLib.constructor","line":8,"end_line":23,"hash":"bacd230f3777dda39ec134a69a9a7c1801cb3cd09c0cc86659df324540053028"},{"id":"func/TopicsRESTControllerLib.handleError","name":"TopicsRESTControllerLib.handleError","line":25,"end_line":32,"hash":"b9ba0c7b9752ac2fda3cf058a983a8b6708715e2e4dc882903ab5ef369956e03"},{"id":"func/TopicsRESTControllerLib.getTopics","name":"TopicsRESTControllerLib.getTopics","line":49,"end_line":55,"hash":"b89a696bcd1d601ef86754974dbf181baf2ece7d592674ba4fd87887725d6fa8"},{"id":"func/TopicsRESTControllerLib.getTopicPosts","name":"TopicsRESTControllerLib.getTopicPosts","line":82,"end_line":90,"hash":"8ad5f9b1749968c3fbfea95683bb388a5d99eda0b8fe7a4dce3447d6d47e6dba"},{"id":"func/TopicsRESTControllerLib.getTopicFollowState","name":"TopicsRESTControllerLib.getTopicFollowState","line":110,"end_line":118,"hash":"6d72fecc2bf46276cd00d39cc1c19ed6647beed1f2f3ba187a2c085ed4308611"},{"id":"func/TopicsRESTControllerLib.getTopicFollowers","name":"TopicsRESTControllerLib.getTopicFollowers","line":136,"end_line":143,"hash":"2bcd22520d962c008a3255f5cf6cf536fdeb738d036d3c6b6d61d5d5cf040615"}]}
|
||||
// {"version":1,"tested_at":"2026-09-17T16:42:30.815Z","module_hash":"50c5f72fa562d8c8f2c0ce8bed281a727b7effd3effbf92f8c4d573003b7b689","functions":[{"id":"func/TopicsRESTControllerLib.constructor","name":"TopicsRESTControllerLib.constructor","line":8,"end_line":23,"hash":"bacd230f3777dda39ec134a69a9a7c1801cb3cd09c0cc86659df324540053028"},{"id":"func/TopicsRESTControllerLib.handleError","name":"TopicsRESTControllerLib.handleError","line":25,"end_line":27,"hash":"801609a06e8f034702fb7293f5c7b0d316a54dfac1921d934e248a3b0a11f58c"},{"id":"func/TopicsRESTControllerLib.getTopics","name":"TopicsRESTControllerLib.getTopics","line":49,"end_line":56,"hash":"e2cf9b957874c42489d8c50b1d371f8191ce94d1002bca4a5ee7d6333d278d11"},{"id":"func/TopicsRESTControllerLib.getTopicPosts","name":"TopicsRESTControllerLib.getTopicPosts","line":84,"end_line":94,"hash":"bc18f51006b1c1079a0584b75d6666bec0b299febdcd565aab071679a2f1fe00"},{"id":"func/TopicsRESTControllerLib.getTopicFollowState","name":"TopicsRESTControllerLib.getTopicFollowState","line":114,"end_line":122,"hash":"6d72fecc2bf46276cd00d39cc1c19ed6647beed1f2f3ba187a2c085ed4308611"},{"id":"func/TopicsRESTControllerLib.getTopicFollowers","name":"TopicsRESTControllerLib.getTopicFollowers","line":140,"end_line":147,"hash":"2bcd22520d962c008a3255f5cf6cf536fdeb738d036d3c6b6d61d5d5cf040615"}]}
|
||||
// mutate4javascript-manifest-end
|
||||
|
||||
@@ -85,3 +85,7 @@ export async function backfillTopicIndexes ({ roomsDb, topicSummariesDb, topicRe
|
||||
|
||||
return { rooms: summaries.size }
|
||||
}
|
||||
|
||||
// mutate4javascript-manifest-begin
|
||||
// {"version":1,"tested_at":"2026-09-17T16:40:51.620Z","module_hash":"7a67d2c6ca7ea2494b1ff3a6dcc703c47a0dfd341fe2d593750b82b810f36da1","functions":[{"id":"func/topicRecencyKey","name":"topicRecencyKey","line":26,"end_line":29,"hash":"a034a6023f72d08e40d28bb51e41e370c1a42d5682315b162a7c2a81f7f31310"},{"id":"func/roomFromEntry","name":"roomFromEntry","line":33,"end_line":36,"hash":"5bf2a8338a623f65191729bc2433a87869b085b29547fbb5e42ebaa67d6473c1"},{"id":"func/applyPost","name":"applyPost","line":39,"end_line":43,"hash":"4edf9dd98a5889c62fd60f4107563427f0a55dc0250c27f6ac0af49b6b934c42"},{"id":"func/collectSummaries","name":"collectSummaries","line":45,"end_line":60,"hash":"73a07286477939379fb82ceace71991aa0cd830f041897dbe4cb5748c091a93f"},{"id":"func/removeStale","name":"removeStale","line":63,"end_line":69,"hash":"09cc44be72b9f955722f17c117d8ca18fe953dcf2cbd6efab110798dce4d0417"},{"id":"func/backfillTopicIndexes","name":"backfillTopicIndexes","line":71,"end_line":87,"hash":"7a6c1207032b16c5e7fc90fe9f7e2543b22d126fc0924296573c911dbf21d8c4"}]}
|
||||
// mutate4javascript-manifest-end
|
||||
|
||||
@@ -20,5 +20,5 @@ class ListTopics extends ListUseCase {
|
||||
export default ListTopics
|
||||
|
||||
// mutate4javascript-manifest-begin
|
||||
// {"version":1,"tested_at":"2026-08-28T15:09:18.069Z","module_hash":"4d7755c0ac3ab79ea014862e6c728fde8af6e76c65046c9691f81ecd00993734","functions":[{"id":"func/ListTopics.constructor","name":"ListTopics.constructor","line":8,"end_line":10,"hash":"0e6872a32236c0cb076d7a728a37d8a40f2aca9bada0395d502cd3dba466c273"},{"id":"func/ListTopics.execute","name":"ListTopics.execute","line":12,"end_line":15,"hash":"c41d34757567d55659cc3a8ba77730a34478dfff9a95af00868aa8c5b2db159a"}]}
|
||||
// {"version":1,"tested_at":"2026-09-17T16:41:57.476Z","module_hash":"07fb13faa0cead7ef6f073eab4f16dd74ece5eb290c37b306827735fa154320d","functions":[{"id":"func/ListTopics.constructor","name":"ListTopics.constructor","line":9,"end_line":11,"hash":"0e6872a32236c0cb076d7a728a37d8a40f2aca9bada0395d502cd3dba466c273"},{"id":"func/ListTopics.execute","name":"ListTopics.execute","line":13,"end_line":17,"hash":"b54242b912b2b499a9e0023a2428c193c0a2c9989e4b3187d61ad76c8e31ec47"}]}
|
||||
// mutate4javascript-manifest-end
|
||||
|
||||
Reference in New Issue
Block a user