801 lines
18 KiB
Markdown
801 lines
18 KiB
Markdown
# Star Chart Market After-Search Rate 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:** Build a new Chrome MV3 extension that adds two after-search-rate columns to the Xingtu creator market page, then supports plugin-owned filtering, sorting, full-scan export, and CSV download.
|
|
|
|
**Architecture:** Start from a minimal MV3 content-script extension and keep the implementation split into small modules: value normalization, API mapping, result storage, DOM sync, full-scan orchestration, filter/sort control, and CSV export. Follow TDD for every production behavior module; only project bootstrap and config files may be created directly as setup.
|
|
|
|
**Tech Stack:** TypeScript, Chrome Manifest V3, Vitest, jsdom, tsup, Node.js
|
|
|
|
---
|
|
|
|
## File Structure
|
|
|
|
Planned initial structure:
|
|
|
|
```text
|
|
package.json
|
|
package-lock.json
|
|
tsconfig.json
|
|
vitest.config.ts
|
|
scripts/
|
|
build.mjs
|
|
src/
|
|
manifest.json
|
|
content/
|
|
index.ts
|
|
market/
|
|
index.ts
|
|
types.ts
|
|
dom-sync.ts
|
|
api-client.ts
|
|
result-store.ts
|
|
filter-sort-controller.ts
|
|
full-scan-controller.ts
|
|
csv-exporter.ts
|
|
plugin-toolbar.ts
|
|
shared/
|
|
rate-normalizer.ts
|
|
csv.ts
|
|
tests/
|
|
rate-normalizer.test.ts
|
|
market-api-client.test.ts
|
|
result-store.test.ts
|
|
filter-sort-controller.test.ts
|
|
market-dom-sync.test.ts
|
|
full-scan-controller.test.ts
|
|
csv-exporter.test.ts
|
|
market-content-entry.test.ts
|
|
```
|
|
|
|
Responsibilities:
|
|
|
|
- `src/shared/rate-normalizer.ts`: parse and normalize display values and comparable lower-bound values
|
|
- `src/content/market/api-client.ts`: fetch and map `/gw/api/aggregator/get_author_ase_info`
|
|
- `src/content/market/result-store.ts`: hold per-author status and merged market records
|
|
- `src/content/market/filter-sort-controller.ts`: apply threshold filters and lower-bound sorting
|
|
- `src/content/market/dom-sync.ts`: locate market rows, inject two columns, and update row visibility/order
|
|
- `src/content/market/full-scan-controller.ts`: paginate through filtered result pages and hydrate the result store
|
|
- `src/content/market/csv-exporter.ts`: generate CSV rows and blob/download metadata
|
|
- `src/content/market/plugin-toolbar.ts`: render the plugin controls for threshold filter, sorting, and export
|
|
- `src/content/market/index.ts`: compose all market modules for the live page
|
|
- `src/content/index.ts`: route-match and boot the market controller
|
|
|
|
## Task 1: Initialize the Empty Project
|
|
|
|
**Files:**
|
|
- Create: `package.json`
|
|
- Create: `tsconfig.json`
|
|
- Create: `vitest.config.ts`
|
|
- Create: `scripts/build.mjs`
|
|
- Create: `src/manifest.json`
|
|
- Create: `src/content/index.ts`
|
|
|
|
- [ ] **Step 1: Initialize the repository and npm package**
|
|
|
|
Run:
|
|
|
|
```bash
|
|
git init
|
|
npm init -y
|
|
```
|
|
|
|
Expected: a new `.git/` directory and baseline `package.json`.
|
|
|
|
- [ ] **Step 2: Add build and test dependencies**
|
|
|
|
Run:
|
|
|
|
```bash
|
|
npm install -D typescript vitest jsdom tsup
|
|
```
|
|
|
|
Expected: `package-lock.json` created and dev dependencies added.
|
|
|
|
- [ ] **Step 3: Write the minimal config and manifest files**
|
|
|
|
Create direct setup files:
|
|
|
|
- `package.json` scripts: `build`, `test`, `test:watch`
|
|
- `tsconfig.json`
|
|
- `vitest.config.ts`
|
|
- `scripts/build.mjs`
|
|
- `src/manifest.json`
|
|
- `src/content/index.ts`
|
|
|
|
The initial manifest should only match the Xingtu market page and load one content entry bundle.
|
|
|
|
- [ ] **Step 4: Run the test command to verify the toolchain is wired**
|
|
|
|
Run:
|
|
|
|
```bash
|
|
npm test
|
|
```
|
|
|
|
Expected: Vitest runs with zero or pending test files, without config errors.
|
|
|
|
- [ ] **Step 5: Run the build command to verify the extension bundle layout**
|
|
|
|
Run:
|
|
|
|
```bash
|
|
npm run build
|
|
```
|
|
|
|
Expected: build succeeds and writes a minimal `dist/` layout containing the manifest and content bundle.
|
|
|
|
- [ ] **Step 6: Commit the bootstrap**
|
|
|
|
Run:
|
|
|
|
```bash
|
|
git add package.json package-lock.json tsconfig.json vitest.config.ts scripts/build.mjs src/manifest.json src/content/index.ts
|
|
git commit -m "chore: bootstrap mv3 extension project"
|
|
```
|
|
|
|
## Task 2: Implement Rate Normalization
|
|
|
|
**Files:**
|
|
- Create: `src/shared/rate-normalizer.ts`
|
|
- Test: `tests/rate-normalizer.test.ts`
|
|
|
|
- [ ] **Step 1: Write the failing tests for normalization and comparable lower bounds**
|
|
|
|
Add tests covering:
|
|
|
|
```ts
|
|
import { describe, expect, test } from "vitest";
|
|
import {
|
|
compareRateValues,
|
|
normalizeRateDisplay,
|
|
parseRateLowerBound
|
|
} from "../src/shared/rate-normalizer";
|
|
|
|
describe("rate-normalizer", () => {
|
|
test("normalizes compact ranges", () => {
|
|
expect(normalizeRateDisplay("0.5%-1%")).toBe("0.5% - 1%");
|
|
});
|
|
|
|
test("parses the lower bound of a range", () => {
|
|
expect(parseRateLowerBound("0.02% - 0.1%")).toBe(0.02);
|
|
});
|
|
|
|
test("treats less-than values as smaller than the boundary range", () => {
|
|
expect(compareRateValues("<0.02%", "0.02% - 0.1%")).toBeLessThan(0);
|
|
});
|
|
});
|
|
```
|
|
|
|
- [ ] **Step 2: Run the rate normalizer test file and verify RED**
|
|
|
|
Run:
|
|
|
|
```bash
|
|
npm test -- tests/rate-normalizer.test.ts
|
|
```
|
|
|
|
Expected: FAIL because the module does not exist yet.
|
|
|
|
- [ ] **Step 3: Write the minimal implementation**
|
|
|
|
Implement only:
|
|
|
|
- display normalization for compact range strings
|
|
- lower-bound parsing
|
|
- comparison helper that orders invalid or missing values last
|
|
|
|
- [ ] **Step 4: Run the test file and verify GREEN**
|
|
|
|
Run:
|
|
|
|
```bash
|
|
npm test -- tests/rate-normalizer.test.ts
|
|
```
|
|
|
|
Expected: PASS.
|
|
|
|
- [ ] **Step 5: Refactor for one parsing pipeline**
|
|
|
|
Keep parsing logic in one shared path so filtering, sorting, and export do not interpret values differently.
|
|
|
|
- [ ] **Step 6: Re-run the test file after refactor**
|
|
|
|
Run:
|
|
|
|
```bash
|
|
npm test -- tests/rate-normalizer.test.ts
|
|
```
|
|
|
|
Expected: PASS.
|
|
|
|
- [ ] **Step 7: Commit**
|
|
|
|
Run:
|
|
|
|
```bash
|
|
git add src/shared/rate-normalizer.ts tests/rate-normalizer.test.ts
|
|
git commit -m "feat: add rate normalization helpers"
|
|
```
|
|
|
|
## Task 3: Implement the ASE API Client
|
|
|
|
**Files:**
|
|
- Create: `src/content/market/api-client.ts`
|
|
- Create: `src/content/market/types.ts`
|
|
- Test: `tests/market-api-client.test.ts`
|
|
|
|
- [ ] **Step 1: Write the failing tests for response mapping and failure states**
|
|
|
|
Cover:
|
|
|
|
- successful mapping from `avg_search_after_view_rate`
|
|
- successful mapping from `personal_avg_search_after_view_rate`
|
|
- `missing` or `failed` behavior when fields are absent
|
|
- timeout or non-OK response failure mapping
|
|
|
|
Example test seed:
|
|
|
|
```ts
|
|
test("maps a valid ASE payload into normalized rates", async () => {
|
|
const client = createMarketApiClient({
|
|
fetchImpl: async () => ({
|
|
ok: true,
|
|
json: async () => ({
|
|
data: {
|
|
avg_search_after_view_rate: "<0.02%",
|
|
personal_avg_search_after_view_rate: "0.02 - 0.1%"
|
|
}
|
|
})
|
|
})
|
|
});
|
|
|
|
await expect(client.loadAuthorAseInfo("123")).resolves.toMatchObject({
|
|
success: true,
|
|
rates: {
|
|
singleVideoAfterSearchRate: "<0.02%",
|
|
personalVideoAfterSearchRate: "0.02% - 0.1%"
|
|
}
|
|
});
|
|
});
|
|
```
|
|
|
|
- [ ] **Step 2: Run the API client test file and verify RED**
|
|
|
|
Run:
|
|
|
|
```bash
|
|
npm test -- tests/market-api-client.test.ts
|
|
```
|
|
|
|
Expected: FAIL because the client module does not exist yet.
|
|
|
|
- [ ] **Step 3: Write the minimal implementation**
|
|
|
|
Implement:
|
|
|
|
- request builder for `/gw/api/aggregator/get_author_ase_info`
|
|
- response mapping
|
|
- timeout handling
|
|
- normalized success result and stable failure reasons
|
|
|
|
- [ ] **Step 4: Run the API client tests and verify GREEN**
|
|
|
|
Run:
|
|
|
|
```bash
|
|
npm test -- tests/market-api-client.test.ts
|
|
```
|
|
|
|
Expected: PASS.
|
|
|
|
- [ ] **Step 5: Refactor shared types**
|
|
|
|
Move reusable market result types into `src/content/market/types.ts`.
|
|
|
|
- [ ] **Step 6: Re-run the API client tests**
|
|
|
|
Run:
|
|
|
|
```bash
|
|
npm test -- tests/market-api-client.test.ts
|
|
```
|
|
|
|
Expected: PASS.
|
|
|
|
- [ ] **Step 7: Commit**
|
|
|
|
Run:
|
|
|
|
```bash
|
|
git add src/content/market/api-client.ts src/content/market/types.ts tests/market-api-client.test.ts
|
|
git commit -m "feat: add ase api client"
|
|
```
|
|
|
|
## Task 4: Implement the Result Store
|
|
|
|
**Files:**
|
|
- Create: `src/content/market/result-store.ts`
|
|
- Modify: `src/content/market/types.ts`
|
|
- Test: `tests/result-store.test.ts`
|
|
|
|
- [ ] **Step 1: Write the failing tests for merged record lifecycle**
|
|
|
|
Cover:
|
|
|
|
- create loading records from current-page rows
|
|
- update one author to success
|
|
- preserve failed authors instead of dropping them
|
|
- dedupe the same author across pages
|
|
- keep stable major fields after repeated writes
|
|
|
|
- [ ] **Step 2: Run the result store test file and verify RED**
|
|
|
|
Run:
|
|
|
|
```bash
|
|
npm test -- tests/result-store.test.ts
|
|
```
|
|
|
|
Expected: FAIL because the store module does not exist yet.
|
|
|
|
- [ ] **Step 3: Write the minimal implementation**
|
|
|
|
Implement:
|
|
|
|
- `upsertMarketRow`
|
|
- `setAuthorLoading`
|
|
- `setAuthorSuccess`
|
|
- `setAuthorFailed`
|
|
- `listRecords`
|
|
- `getRecord`
|
|
|
|
- [ ] **Step 4: Run the result store tests and verify GREEN**
|
|
|
|
Run:
|
|
|
|
```bash
|
|
npm test -- tests/result-store.test.ts
|
|
```
|
|
|
|
Expected: PASS.
|
|
|
|
- [ ] **Step 5: Refactor state transitions into one reducer-style path**
|
|
|
|
Keep state transitions explicit so later full-scan orchestration does not spread status logic across files.
|
|
|
|
- [ ] **Step 6: Re-run the result store tests**
|
|
|
|
Run:
|
|
|
|
```bash
|
|
npm test -- tests/result-store.test.ts
|
|
```
|
|
|
|
Expected: PASS.
|
|
|
|
- [ ] **Step 7: Commit**
|
|
|
|
Run:
|
|
|
|
```bash
|
|
git add src/content/market/result-store.ts src/content/market/types.ts tests/result-store.test.ts
|
|
git commit -m "feat: add market result store"
|
|
```
|
|
|
|
## Task 5: Implement Filter and Sort Control
|
|
|
|
**Files:**
|
|
- Create: `src/content/market/filter-sort-controller.ts`
|
|
- Modify: `src/content/market/types.ts`
|
|
- Test: `tests/filter-sort-controller.test.ts`
|
|
|
|
- [ ] **Step 1: Write the failing tests for threshold filtering and lower-bound sorting**
|
|
|
|
Cover:
|
|
|
|
- pass only when lower bound is greater than or equal to the threshold
|
|
- sort single-rate descending
|
|
- sort personal-rate ascending
|
|
- keep failed or missing rows at the end
|
|
|
|
- [ ] **Step 2: Run the filter/sort tests and verify RED**
|
|
|
|
Run:
|
|
|
|
```bash
|
|
npm test -- tests/filter-sort-controller.test.ts
|
|
```
|
|
|
|
Expected: FAIL because the controller module does not exist yet.
|
|
|
|
- [ ] **Step 3: Write the minimal implementation**
|
|
|
|
Implement:
|
|
|
|
- filter state type
|
|
- sort state type
|
|
- record predicate
|
|
- comparator
|
|
- application helper returning ordered visible record IDs
|
|
|
|
- [ ] **Step 4: Run the filter/sort tests and verify GREEN**
|
|
|
|
Run:
|
|
|
|
```bash
|
|
npm test -- tests/filter-sort-controller.test.ts
|
|
```
|
|
|
|
Expected: PASS.
|
|
|
|
- [ ] **Step 5: Refactor duplicated comparison branches**
|
|
|
|
Keep one comparison path per metric and one final fallback ordering rule.
|
|
|
|
- [ ] **Step 6: Re-run the filter/sort tests**
|
|
|
|
Run:
|
|
|
|
```bash
|
|
npm test -- tests/filter-sort-controller.test.ts
|
|
```
|
|
|
|
Expected: PASS.
|
|
|
|
- [ ] **Step 7: Commit**
|
|
|
|
Run:
|
|
|
|
```bash
|
|
git add src/content/market/filter-sort-controller.ts src/content/market/types.ts tests/filter-sort-controller.test.ts
|
|
git commit -m "feat: add filter and sort controller"
|
|
```
|
|
|
|
## Task 6: Implement CSV Export
|
|
|
|
**Files:**
|
|
- Create: `src/shared/csv.ts`
|
|
- Create: `src/content/market/csv-exporter.ts`
|
|
- Test: `tests/csv-exporter.test.ts`
|
|
|
|
- [ ] **Step 1: Write the failing tests for CSV serialization**
|
|
|
|
Cover:
|
|
|
|
- header order
|
|
- escaped commas and quotes
|
|
- failed rows emitting empty rate fields plus status
|
|
- export rows using normalized display values
|
|
|
|
- [ ] **Step 2: Run the CSV exporter tests and verify RED**
|
|
|
|
Run:
|
|
|
|
```bash
|
|
npm test -- tests/csv-exporter.test.ts
|
|
```
|
|
|
|
Expected: FAIL because the exporter module does not exist yet.
|
|
|
|
- [ ] **Step 3: Write the minimal implementation**
|
|
|
|
Implement:
|
|
|
|
- CSV escaping helper
|
|
- column definition list
|
|
- row-to-CSV conversion
|
|
- blob-ready text generation function
|
|
|
|
- [ ] **Step 4: Run the CSV exporter tests and verify GREEN**
|
|
|
|
Run:
|
|
|
|
```bash
|
|
npm test -- tests/csv-exporter.test.ts
|
|
```
|
|
|
|
Expected: PASS.
|
|
|
|
- [ ] **Step 5: Refactor field mapping into one declarative schema**
|
|
|
|
Keep export field order and labels in one place.
|
|
|
|
- [ ] **Step 6: Re-run the CSV exporter tests**
|
|
|
|
Run:
|
|
|
|
```bash
|
|
npm test -- tests/csv-exporter.test.ts
|
|
```
|
|
|
|
Expected: PASS.
|
|
|
|
- [ ] **Step 7: Commit**
|
|
|
|
Run:
|
|
|
|
```bash
|
|
git add src/shared/csv.ts src/content/market/csv-exporter.ts tests/csv-exporter.test.ts
|
|
git commit -m "feat: add csv exporter"
|
|
```
|
|
|
|
## Task 7: Implement Current-Page DOM Sync
|
|
|
|
**Files:**
|
|
- Create: `src/content/market/dom-sync.ts`
|
|
- Test: `tests/market-dom-sync.test.ts`
|
|
|
|
- [ ] **Step 1: Write the failing DOM tests for current-page enhancement**
|
|
|
|
Use jsdom fixtures that mimic the Xingtu market grid and cover:
|
|
|
|
- injecting the two header cells
|
|
- injecting one pair of per-row cells
|
|
- rendering loading, success, and failed states
|
|
- hiding filtered rows
|
|
- reordering rows based on an ordered ID list
|
|
|
|
- [ ] **Step 2: Run the DOM sync tests and verify RED**
|
|
|
|
Run:
|
|
|
|
```bash
|
|
npm test -- tests/market-dom-sync.test.ts
|
|
```
|
|
|
|
Expected: FAIL because the module does not exist yet.
|
|
|
|
- [ ] **Step 3: Write the minimal implementation**
|
|
|
|
Implement:
|
|
|
|
- page structure discovery
|
|
- row extraction with major field snapshots
|
|
- inserted-cell rendering
|
|
- row hide/show
|
|
- row order application
|
|
|
|
- [ ] **Step 4: Run the DOM sync tests and verify GREEN**
|
|
|
|
Run:
|
|
|
|
```bash
|
|
npm test -- tests/market-dom-sync.test.ts
|
|
```
|
|
|
|
Expected: PASS.
|
|
|
|
- [ ] **Step 5: Refactor DOM selectors into one locator object**
|
|
|
|
This keeps future layout changes isolated.
|
|
|
|
- [ ] **Step 6: Re-run the DOM sync tests**
|
|
|
|
Run:
|
|
|
|
```bash
|
|
npm test -- tests/market-dom-sync.test.ts
|
|
```
|
|
|
|
Expected: PASS.
|
|
|
|
- [ ] **Step 7: Commit**
|
|
|
|
Run:
|
|
|
|
```bash
|
|
git add src/content/market/dom-sync.ts tests/market-dom-sync.test.ts
|
|
git commit -m "feat: add market dom sync"
|
|
```
|
|
|
|
## Task 8: Implement Full-Scan Pagination Control
|
|
|
|
**Files:**
|
|
- Create: `src/content/market/full-scan-controller.ts`
|
|
- Modify: `src/content/market/types.ts`
|
|
- Test: `tests/full-scan-controller.test.ts`
|
|
|
|
- [ ] **Step 1: Write the failing tests for on-demand full scans**
|
|
|
|
Cover:
|
|
|
|
- initial page load does not start full scan
|
|
- filter action starts full scan
|
|
- sort action starts full scan
|
|
- export action starts full scan
|
|
- repeated actions do not restart a completed scan unnecessarily
|
|
- failed author fetches are recorded but do not abort the whole scan
|
|
|
|
- [ ] **Step 2: Run the full-scan tests and verify RED**
|
|
|
|
Run:
|
|
|
|
```bash
|
|
npm test -- tests/full-scan-controller.test.ts
|
|
```
|
|
|
|
Expected: FAIL because the controller module does not exist yet.
|
|
|
|
- [ ] **Step 3: Write the minimal implementation**
|
|
|
|
Implement the controller around injected dependencies:
|
|
|
|
- current-page row reader
|
|
- paginator
|
|
- author metrics loader
|
|
- result store writer
|
|
|
|
The controller should expose one explicit method per trigger source, such as:
|
|
|
|
- `ensureScanForFilter()`
|
|
- `ensureScanForSort()`
|
|
- `ensureScanForExport()`
|
|
|
|
- [ ] **Step 4: Run the full-scan tests and verify GREEN**
|
|
|
|
Run:
|
|
|
|
```bash
|
|
npm test -- tests/full-scan-controller.test.ts
|
|
```
|
|
|
|
Expected: PASS.
|
|
|
|
- [ ] **Step 5: Refactor to a single idempotent scan path**
|
|
|
|
All trigger entry points should delegate to the same internal scan routine.
|
|
|
|
- [ ] **Step 6: Re-run the full-scan tests**
|
|
|
|
Run:
|
|
|
|
```bash
|
|
npm test -- tests/full-scan-controller.test.ts
|
|
```
|
|
|
|
Expected: PASS.
|
|
|
|
- [ ] **Step 7: Commit**
|
|
|
|
Run:
|
|
|
|
```bash
|
|
git add src/content/market/full-scan-controller.ts src/content/market/types.ts tests/full-scan-controller.test.ts
|
|
git commit -m "feat: add full scan controller"
|
|
```
|
|
|
|
## Task 9: Implement the Plugin Toolbar and Market Composition
|
|
|
|
**Files:**
|
|
- Create: `src/content/market/plugin-toolbar.ts`
|
|
- Create: `src/content/market/index.ts`
|
|
- Modify: `src/content/index.ts`
|
|
- Test: `tests/market-content-entry.test.ts`
|
|
|
|
- [ ] **Step 1: Write the failing integration tests for the page entry flow**
|
|
|
|
Cover:
|
|
|
|
- market controller boots on the Xingtu market URL
|
|
- current page rows are hydrated on start
|
|
- applying plugin filters triggers full scan and hides non-matching rows
|
|
- applying plugin sorting triggers full scan and reorders rows
|
|
- export triggers full scan and hands the ordered visible records to the CSV exporter
|
|
|
|
- [ ] **Step 2: Run the market entry tests and verify RED**
|
|
|
|
Run:
|
|
|
|
```bash
|
|
npm test -- tests/market-content-entry.test.ts
|
|
```
|
|
|
|
Expected: FAIL because the market controller composition does not exist yet.
|
|
|
|
- [ ] **Step 3: Write the minimal implementation**
|
|
|
|
Implement:
|
|
|
|
- toolbar controls for threshold inputs, sort selector, and export button
|
|
- event wiring from toolbar to full scan, filter/sort controller, and exporter
|
|
- market page bootstrap in `src/content/index.ts`
|
|
|
|
- [ ] **Step 4: Run the market entry tests and verify GREEN**
|
|
|
|
Run:
|
|
|
|
```bash
|
|
npm test -- tests/market-content-entry.test.ts
|
|
```
|
|
|
|
Expected: PASS.
|
|
|
|
- [ ] **Step 5: Run the whole test suite**
|
|
|
|
Run:
|
|
|
|
```bash
|
|
npm test
|
|
```
|
|
|
|
Expected: all test files PASS.
|
|
|
|
- [ ] **Step 6: Run the production build**
|
|
|
|
Run:
|
|
|
|
```bash
|
|
npm run build
|
|
```
|
|
|
|
Expected: extension build succeeds with all planned bundles and manifest output.
|
|
|
|
- [ ] **Step 7: Commit**
|
|
|
|
Run:
|
|
|
|
```bash
|
|
git add src/content/index.ts src/content/market/index.ts src/content/market/plugin-toolbar.ts tests/market-content-entry.test.ts
|
|
git commit -m "feat: wire market plugin controls"
|
|
```
|
|
|
|
## Task 10: Manual Verification and Documentation
|
|
|
|
**Files:**
|
|
- Modify: `externaldocs/2026-04-20-star-chart-market-after-search-rate-plugin-spec.md` (only if actual implementation forces scope adjustments)
|
|
- Create: `README.md`
|
|
|
|
- [ ] **Step 1: Write a minimal README**
|
|
|
|
Document:
|
|
|
|
- install
|
|
- test
|
|
- build
|
|
- load unpacked extension
|
|
- manual verification checklist
|
|
|
|
- [ ] **Step 2: Run manual verification on the live page**
|
|
|
|
Verify:
|
|
|
|
- current page gets two new columns
|
|
- loading, success, failed states render correctly
|
|
- filter triggers scan and hides unmatched rows
|
|
- sort triggers scan and reorders rows
|
|
- export produces a CSV with plugin status fields
|
|
|
|
- [ ] **Step 3: Update the spec if implementation realities changed any promised behavior**
|
|
|
|
Only adjust documented scope if the live page proves a requirement impossible or unstable.
|
|
|
|
- [ ] **Step 4: Run the full test suite again**
|
|
|
|
Run:
|
|
|
|
```bash
|
|
npm test
|
|
npm run build
|
|
```
|
|
|
|
Expected: both commands succeed.
|
|
|
|
- [ ] **Step 5: Commit**
|
|
|
|
Run:
|
|
|
|
```bash
|
|
git add README.md externaldocs/2026-04-20-star-chart-market-after-search-rate-plugin-spec.md
|
|
git commit -m "docs: add usage and verification notes"
|
|
```
|
|
|
|
## Notes for Execution
|
|
|
|
- Do not write production behavior before the corresponding failing test exists.
|
|
- Keep DOM selectors isolated; the Xingtu page is likely to shift.
|
|
- Reuse the old project's verified API field names, but do not copy large modules blindly; re-derive them under tests.
|
|
- For full-scan logic, dependency-inject pagination and row reading so the orchestration stays testable.
|
|
- If a task reveals a missing boundary in the spec, pause and update the spec before continuing.
|