star-chart-search-enhancer/docs/superpowers/plans/2026-04-15-star-chart-market-visible-page-columns-implementation.md

16 KiB

Star Chart Market Visible Page Columns Implementation Plan

For agentic workers: REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (- [ ]) syntax for tracking.

Goal: Add two after-search-rate columns to the Xingtu creator market list page, auto-load them for the current visible result page, and support cache-backed retryable row rendering without regressing the existing detail-page experiment.

Architecture: Keep the existing detail-page hook flow intact, split the content entry into route-aware controllers, and implement the market-page feature entirely inside src/content/market/. Market-page data loading uses a dedicated same-origin API client plus a list-sequence-aware controller so DOM sync, cache reuse, retry, and stale-result suppression stay deterministic and testable.

Tech Stack: TypeScript, Vitest, jsdom, tsup, Chrome Extension Manifest V3


Implementation Notes

  • Current workspace already contains working detail-page code, build scripts, and tests. This plan assumes incremental change, not greenfield scaffolding.
  • Current workspace is still not a git repository, so each “commit” step is replaced with a verification note.
  • This plan only covers stage 1: current visible result page enhancement.
  • Follow TDD strictly: failing test first, then minimal code.
  • Do not route the market-page feature through src/page/hook.ts unless runtime evidence proves content-script requests are blocked.
  • Market async flows must not cache raw HTMLElement references across request boundaries. Cache/request layers may store only row metadata such as authorId, listSeq, and list signature.
  • The market API client should expose deterministic error reasons: timeout for AbortError, request-failed for network/non-2xx/parse failures, and bad-response for structurally valid responses missing either target field.
  • Every async writeback must re-check current DOM markers (data-sces-author-id, data-sces-list-seq) before rendering, instead of trusting a stale row reference captured earlier.

Planned File Map

  • Modify: src/manifest.json
    • Add market-page match coverage while preserving detail-page coverage.
  • Modify: src/content/index.ts
    • Reduce to route bootstrap and controller selection.
  • Create: src/content/detail/index.ts
    • Hold the existing detail-page controller logic currently living in src/content/index.ts.
  • Create: src/content/market/index.ts
    • Orchestrate market-page DOM sync, list sessions, loading, cache reuse, and retry.
  • Create: src/content/market/api-client.ts
    • Build request URLs, issue same-origin fetches with timeout, and map the known API response into normalized rates.
  • Create: src/content/market/batch-loader.ts
    • Coordinate concurrency-limited loading, stale-result suppression, and row-level retry.
  • Create: src/content/market/cache-store.ts
    • Store success cache and in-flight request dedupe entries by authorId.
  • Create: src/content/market/dom-sync.ts
    • Find the target table, insert headers/cells, and bind row metadata markers.
  • Create: src/content/market/id-extractor.ts
    • Extract authorId from row links and fallback attributes.
  • Create: src/content/market/list-signature.ts
    • Produce deterministic list/session signatures from current rows and URL state.
  • Create: src/content/market/row-render.ts
    • Render loading, success, and error states into the two injected cells.
  • Create: src/content/market/row-state.ts
    • Define row-status types and transition helpers.
  • Create: src/shared/normalize-rate-value.ts
    • Normalize known rate shapes such as <0.02% and 0.02 - 0.1%.
  • Modify: src/shared/extract-after-search-rates.ts
    • Reuse the extracted shared normalizer so detail-page behavior stays consistent.
  • Modify: tests/build-layout.test.ts
    • Extend manifest/build assertions for the market route.
  • Modify: tests/content-bridge.test.ts
    • Point detail-page tests at the extracted detail controller module.
  • Create: tests/content-entry.test.ts
    • Cover route bootstrap behavior for detail, market, and unsupported URLs.
  • Create: tests/market-api-client.test.ts
    • Cover request URL generation, timeout handling, and response mapping.
  • Create: tests/market-id-extractor.test.ts
    • Cover author-id extraction from row fixtures.
  • Create: tests/market-dom-sync.test.ts
    • Cover header/cell insertion and duplicate protection.
  • Create: tests/market-row-render.test.ts
    • Cover row rendering transitions and retry affordance.
  • Create: tests/market-batch-loader.test.ts
    • Cover cache reuse, in-flight dedupe, concurrency, and retry behavior.
  • Create: tests/market-controller.test.ts
    • Cover list changes, stale-result suppression, and cache-backed rehydration.
  • Modify: tests/readme.test.ts
    • Require README coverage for the market-page feature.
  • Modify: README.md
    • Document market-page support and manual verification.

Task 1: Split the Content Entry Into a Route Bootstrap and a Detail Controller

Files:

  • Modify: src/content/index.ts

  • Create: src/content/detail/index.ts

  • Modify: tests/content-bridge.test.ts

  • Create: tests/content-entry.test.ts

  • Step 1: Write the failing route-bootstrap tests

Add tests asserting:

  • detail URLs bootstrap the detail controller

  • non-detail, non-market URLs no-op cleanly

  • the detail controller still injects the page hook exactly once

  • Step 2: Run the tests to verify they fail

Run: npm test -- tests/content-entry.test.ts tests/content-bridge.test.ts Expected: FAIL because route bootstrap and extracted detail controller do not exist yet

  • Step 3: Implement the minimal route bootstrap split

Implement:

  • createDetailContentController in src/content/detail/index.ts

  • route matching in src/content/index.ts

  • no-op behavior on unsupported URLs

  • updated imports in the existing detail tests

  • Step 4: Run the tests to verify they pass

Run: npm test -- tests/content-entry.test.ts tests/content-bridge.test.ts Expected: PASS

  • Step 5: Record the verification note

Record which tests passed and that detail-page behavior remained intact

Task 2: Extend Manifest Coverage to the Market Page

Files:

  • Modify: src/manifest.json

  • Modify: tests/build-layout.test.ts

  • Step 1: Write the failing manifest assertions

Extend the build-layout test to assert:

  • the content script matches both detail and market URLs

  • the emitted JS asset list is unchanged

  • web_accessible_resources for the detail hook still stay present

  • Step 2: Run the test to verify it fails

Run: npm test -- tests/build-layout.test.ts Expected: FAIL because the manifest only targets the detail page

  • Step 3: Implement the minimal manifest update

Implement:

  • add https://*.xingtu.cn/ad/creator/market* to content_scripts.matches

  • keep existing detail-page matches and page-hook asset coverage

  • Step 4: Run the test to verify it passes

Run: npm test -- tests/build-layout.test.ts Expected: PASS

  • Step 5: Verify the build still works

Run: npm run build Expected: PASS and dist/manifest.json includes the market match

  • Step 6: Record the verification note

Record the passing build-layout test and build output

Task 3: Add the Shared Rate Normalizer and the Market API Client

Files:

  • Create: src/shared/normalize-rate-value.ts

  • Modify: src/shared/extract-after-search-rates.ts

  • Create: src/content/market/api-client.ts

  • Create: tests/market-api-client.test.ts

  • Modify: tests/extract-after-search-rates.test.ts

  • Step 1: Write the failing API-client and normalization tests

Cover:

  • normalizing <0.02% without changing it

  • normalizing 0.02 - 0.1% into 0.02% - 0.1%

  • mapping the known API fields into the two display fields

  • returning bad-response when either field is missing

  • returning timeout for aborted requests and request-failed for non-OK/network failures

  • issuing fetch with credentials: "include" and a timeout signal

  • Step 2: Run the tests to verify they fail

Run: npm test -- tests/market-api-client.test.ts tests/extract-after-search-rates.test.ts Expected: FAIL because the shared normalizer and market API client do not exist yet

  • Step 3: Implement the minimal shared normalizer and API client

Implement:

  • normalizeRateValue

  • market request URL builder for get_author_ase_info

  • response mapper for avg_search_after_view_rate and personal_avg_search_after_view_rate

  • explicit error classification for timeout vs request-failed vs bad-response

  • reuse the shared normalizer from the detail extractor

  • Step 4: Run the tests to verify they pass

Run: npm test -- tests/market-api-client.test.ts tests/extract-after-search-rates.test.ts Expected: PASS

  • Step 5: Record the verification note

Record that both the new market mapper tests and the existing detail extractor tests passed

Task 4: Add Author-ID Extraction and List-Signature Utilities

Files:

  • Create: src/content/market/id-extractor.ts

  • Create: src/content/market/list-signature.ts

  • Create: tests/market-id-extractor.test.ts

  • Step 1: Write the failing extractor tests

Cover:

  • extracting authorId from a row detail link

  • extracting from fallback row attributes when available

  • returning an explicit missing-id result when no stable source exists

  • producing a deterministic list signature from author IDs plus relevant URL state

  • Step 2: Run the test to verify it fails

Run: npm test -- tests/market-id-extractor.test.ts Expected: FAIL because the market row extraction utilities do not exist yet

  • Step 3: Implement the minimal extractor utilities

Implement:

  • detail-link parsing via getStarIdFromUrl

  • fallback attribute parsing

  • explicit missing-author-id results

  • deterministic list-signature generation

  • Step 4: Run the test to verify it passes

Run: npm test -- tests/market-id-extractor.test.ts tests/get-star-id.test.ts Expected: PASS

  • Step 5: Record the verification note

Record the passing extractor and shared ID tests

Task 5: Insert the Two Columns and Render Row States

Files:

  • Create: src/content/market/dom-sync.ts

  • Create: src/content/market/row-render.ts

  • Create: src/content/market/row-state.ts

  • Create: tests/market-dom-sync.test.ts

  • Create: tests/market-row-render.test.ts

  • Step 1: Write the failing DOM and rendering tests

Cover:

  • inserting two headers before the 操作 column

  • inserting two cells before the action cell for each row

  • tagging injected cells with stable data-* markers

  • avoiding duplicate insertion on repeated sync

  • rendering 加载中..., success values, and 加载失败

  • exposing retryable error rows without creating per-cell state divergence

  • avoiding any design that requires batch/cache layers to hold row elements after the sync pass ends

  • Step 2: Run the tests to verify they fail

Run: npm test -- tests/market-dom-sync.test.ts tests/market-row-render.test.ts Expected: FAIL because the market DOM modules do not exist yet

  • Step 3: Implement the minimal DOM sync and row rendering

Implement:

  • table/header lookup

  • injected header/cell creation

  • row-state types

  • row rendering with shared row-level status

  • ephemeral DOM references only inside the sync/render step

  • Step 4: Run the tests to verify they pass

Run: npm test -- tests/market-dom-sync.test.ts tests/market-row-render.test.ts Expected: PASS

  • Step 5: Record the verification note

Record the passing DOM and row-render test output

Task 6: Add Cache, In-Flight Dedupe, Concurrency Control, and Row Retry

Files:

  • Create: src/content/market/batch-loader.ts

  • Create: src/content/market/cache-store.ts

  • Create: tests/market-batch-loader.test.ts

  • Modify: src/content/market/api-client.ts

  • Modify: src/content/market/row-state.ts

  • Step 1: Write the failing batch-loader tests

Cover:

  • current page rows auto-enter loading state

  • same authorId reuses success cache

  • same authorId in-flight requests are deduplicated

  • concurrency cap is honored

  • failed rows transition to 加载失败

  • clicking one failed cell retries the whole row

  • loader outputs can be dropped safely when the consumer reports a newer listSeq

  • Step 2: Run the test to verify it fails

Run: npm test -- tests/market-batch-loader.test.ts Expected: FAIL because cache/dedupe/loader behavior does not exist yet

  • Step 3: Implement the minimal cache and loader pipeline

Implement:

  • in-memory cache entries keyed by authorId

  • in-flight request reuse

  • concurrency-limited scheduling

  • row retry behavior

  • timeout and request-failed transitions

  • result delivery based on row metadata and callbacks, not long-lived DOM node ownership

  • Step 4: Run the test to verify it passes

Run: npm test -- tests/market-batch-loader.test.ts tests/market-api-client.test.ts Expected: PASS

  • Step 5: Record the verification note

Record the passing loader and API-client tests

Task 7: Build the Market Controller and Activate It on the Market Route

Files:

  • Create: src/content/market/index.ts

  • Modify: src/content/index.ts

  • Create: tests/market-controller.test.ts

  • Modify: tests/content-entry.test.ts

  • Step 1: Write the failing controller tests

Cover:

  • initial market page auto-load for all current rows

  • pagination/filter/search/sort DOM changes trigger a fresh sync

  • stale async results do not overwrite a newer list

  • cached rows rehydrate immediately when they reappear

  • the content entry now selects the market controller on market URLs

  • writeback only succeeds when fresh DOM markers still match the returning authorId and listSeq

  • Step 2: Run the test to verify it fails

Run: npm test -- tests/market-controller.test.ts tests/content-entry.test.ts Expected: FAIL because the market controller and route activation do not exist yet

  • Step 3: Implement the minimal market controller

Implement:

  • table observation

  • listSeq or equivalent sync-session tracking

  • fresh sync on list changes

  • stale result suppression before DOM writeback

  • re-scan current DOM on each sync instead of holding old row node references

  • market route activation in src/content/index.ts

  • Step 4: Run the test to verify it passes

Run: npm test -- tests/market-controller.test.ts tests/content-entry.test.ts Expected: PASS

  • Step 5: Run the focused market suite

Run: npm test -- tests/market-api-client.test.ts tests/market-id-extractor.test.ts tests/market-dom-sync.test.ts tests/market-row-render.test.ts tests/market-batch-loader.test.ts tests/market-controller.test.ts Expected: PASS

  • Step 6: Record the verification note

Record that the market suite and route-entry tests passed

Task 8: Update README and Run Final Verification

Files:

  • Modify: README.md

  • Modify: tests/readme.test.ts

  • Step 1: Write the failing README expectation

Extend README tests to assert documentation now includes:

  • market page enhancement scope

  • the two inserted column names

  • loading/failure/retry behavior

  • how to manually verify on creator/market

  • the fact that detail-page behavior still exists

  • Step 2: Run the test to verify it fails

Run: npm test -- tests/readme.test.ts Expected: FAIL because README does not document market-page behavior yet

  • Step 3: Update README minimally

Add:

  • market page support notes

  • manual verification steps for both detail and market pages

  • current stage-1 limitations

  • Step 4: Run the test to verify it passes

Run: npm test -- tests/readme.test.ts Expected: PASS

  • Step 5: Run the full verification suite

Run: npm test Expected: all tests PASS

  • Step 6: Run a fresh production build

Run: npm run build Expected: build exits 0 and dist/ contains the updated extension assets

  • Step 7: Record the verification note

Record the passing full test run and build output