Conversation
Introduce an isolated <data-dir>/index/index.db cache owned by the host. The store namespaces roots by a hash of the canonicalized path, enforces file-count, per-file, and total-byte budgets, records a fresh/partial/ skipped_over_limit/failed state machine, honors .gitignore and .pi-desktopignore when scanning, and quarantines a corrupt database for rebuild without touching pi.sqlite. P2-A scope: lifecycle only — Grep does not read this cache yet.
Expose index.status, index.rebuild, and index.clear over the host RPC. All three accept an optional rootPath that must match the active workspace (INDEX_ROOT_OUTSIDE_WORKSPACE otherwise), clone the store out of the state lock, and run the blocking scan off the async runtime. index.status returns metadata only and never file contents.
Drive the real host binary over stdio JSON-RPC in a temp data dir: empty status, rebuild to fresh, workspace-boundary rejection, and scoped clear. Registered as pnpm test:e2e:index for scenario E2E-INDEX-status-rebuild-clear.
Add the index.db storage boundary (rebuildable cache, excluded from backup/export, content inventory) to 03-runtime data storage, the three lifecycle RPCs to the host protocol doc, and the E2E scenario plus traceability rows for E2E-INDEX-status-rebuild-clear, in English and Chinese pairs. Include the P2-0 rg baseline script and the 2026-09-13 measurement report for later fast-path calibration.
Add pi-desktop/index/{status,rebuild,clear} channels with
WorkspaceIndexRoot types on the shared contract, forward them to the
host RPCs from Electron main, and wrap them in the renderer api client.
Ipc surface stays read/rebuild-only; no settings keys are added.
The Index destination shows host-owned index health (status, file count, indexed size, unreadable files, last update) and offers Rebuild and Clear through the lifecycle RPCs. Empty and load-failure states are handled explicitly, and the copy states the index is a rebuildable local cache rather than something Grep reads. Adds the lucide Database glyph, token-based styles, and the settings.nav.index plus index.* keys for all eight locales.
Assert the nav entry, page wiring, the three IPC channels, and locale keys as source contracts, and keep the nav order plus Database glyph in the settings-general nav test.
Add the Index destination to the settings IA and the three IPC channels to the IPC protocol in English and Chinese pairs, and record the UI health-card scenario with traceability rows in the E2E plan.
Promote 数据与统计/Data & Statistics to a fifth titled settings cluster placed before System, and move the workspace index entry out of the workspace group into it. Adds settings.groupData for all eight locales and updates the nav contracts, settings IA, and its Chinese pair.
Rename the destination title to 索引库/Index library across locales and specs, and rebuild the health card as metric tiles aligned with the accepted mockup language: tinted icon chips, large tabular values, a status badge, a warning badge for unreadable files, and a primary rebuild action. Styles stay on design tokens for dark and light themes.
… index Select Grep candidate files from a fresh workspace index (FTS5 trigram phrase query) and verify each candidate against the filesystem before serving. The fast path only narrows the candidate file list; the shared line scanner still decides every hit, so the result shape is unchanged. The path stays opt-in (`indexGrepBoost`, default off): the index visible set is not yet proven equal to Grep's, so enabling it now would silently change Grep results. Enabling requires the visible-set parity diff test first. Spec and E2E coverage remain pending.
The P2-B fast path may only narrow the candidate file list, which is safe only if the index covers every file Grep can reach. Two mechanisms now hold that, and both are covered by tests: 1. `tools/ignore_rules` becomes the single definition of the visible set. The index crawler and Grep's candidate walk both derive from it, so agreement is structural instead of coincidental. A diff property test (`grep_candidates_match_the_index_visible_set`) asserts the two sets are exactly equal across hidden files, `.pi-desktopignore`, `.gitignore`, `.ignore`, vendor directories and plain content. 2. The index no longer equates "visible" with "ingested". Binary extensions, over-size text and unreadable files used to be dropped silently, so a fast path over such an index would report fewer hits than the fallback — a false negative no drift check can detect. `files` now stores the whole visible set with a `content_indexed` flag, and the fast path appends every unindexed row to its candidate list, handing those files to the same line scanner the fallback uses. Schema version bumps to 2; the index is a rebuildable cache, so `open` re-crawls a v1 database. `file_count` keeps its meaning (ingested files only), so the health card is unchanged. The fast path remains opt-in and unreachable from the production call site; the settings gate, spec and E2E coverage still stand between this commit and shipping it.
Complete the opt-in chain for the P2-B fast path: AppSettings gains indexGrepBoost (shared type + host-side boolean validation rejecting malformed patches), the RPC dispatch consults it for Grep only and hands the index store to execute_tool_with_index, and the index library page renders the toggle with copy that promises speed, never changed results. RPC-boundary tests drive a literal Grep through the real dispatch with the switch both off and on; the settings contract test pins the toggle wiring; settings-IA and the E2E plan document the opt-in semantics in English and Chinese pairs.
Complete the two-switch contract: indexNewFolders (shared AppSettings key, boolean-only host validation, toggle on the index library page) makes workspace.set trigger ensure_index for a changed workspace and run the rebuild on the blocking pool, so the RPC returns immediately while index.status reports building. The health card polls status once a second while building, pausing when the window is hidden. With both switches off, switching workspaces never touches the index. RPC-boundary tests cover the off/on matrix; settings-IA, host-rpc protocol, and the E2E plan document the behavior in English and Chinese pairs.
Complete P1 of the Data & Statistics series (ADR 0181 amends D335 / ADR 0173): a host stats module aggregates completed turns into a summary (cards, insights, daily/per-model series, model and project shares, 365-day heatmap) plus top sessions, TTL-cached per range, project, timezone, metric version, and last turn end. The Usage destination renders range switching, heatmap, trend, donut, insights, top sessions, CSV/JSON export, and a local-computation provenance note. i18n covers all eight locales; specs (settings IA, host RPC protocol, E2E plan) are updated in English and Chinese pairs; the amended no-usage contract now asserts the destination exists.
stats.summary used '?' on an anyhow result inside the JsonRpcError handler, which broke the plain bin build and left the packaged app without a host binary. Route the error through rpc_err instead.
Both destinations now share one MetricTile component (tinted icon chip, muted label, large tabular value, optional badge/caption) instead of the usage page drawing a chip-less variant. Adds the design-spec badges (Highest / Record / On track), fixes the heatmap to a weekly column grid with month axis labels and a Low/High legend, and keeps the labels in all eight locales.
The usage page had drifted from the approved design on several axes at once, so this closes the whole gap in one pass rather than patching symptoms. Root cause of two defects: `--ds-text` is not a real token (only `--ds-text-primary/secondary/muted/faint` exist). Both the heatmap empty-cell fill and the trend gridline stroke resolved to nothing, so empty heat cells rendered pure black and every gridline vanished. Both now use `--ds-text-primary`. Layout now follows the mockup order: heatmap beside the donut, trend beside diagnostics, and the high-token session list on its own full-width row. The trend chart gained a real Y axis (nice-ceiled 0/50K/100K/…) and X date labels, and plots a Total series plus per-model lines instead of one summed polyline. Also fixed: - `.idx-badge` had no fill and `.idx-badge-ok` was undefined, so the 纪录 and 进行中 badges rendered as bare text; all three badges are now tinted pills. - Chart panels were padding-free inside an `overflow: hidden` tile, which put labels on the border and clipped the 22% value at the rounded corner. - The heatmap gained its Mon–Sun row axis and a left gutter so the first month label is no longer cut by the tile edge. - The donut legend is now two-line so long model ids stop truncating. - Added the project filter (sourced from the project registry, not from the already-narrowed summary, so options do not collapse) and the page subtitle. Verified: host-core 325, desktop 1210, shared 410, i18n 22, typecheck, style-lint, and build all pass. Two-page pixel conformance audit: CONFORMS.
Four defects in the usage statistics and index surfaces were producing wrong numbers or missing data, plus the layout and accessibility work the design spec asks for. Verified against an independently seeded fixture. Correctness: - `stats::summary` accumulated every in-range day into one map twice, so `dailyTotals`, `heatmap` and the peak-day figure were ~2x for in-range days and the daily totals did not sum to the headline total. Split into `daily_range` (range-scoped) and `daily_full` (365-day heatmap window). - `stats::top_sessions` collected session titles and then dropped them, and hardcoded `lastActiveMs: 0`. Both now carry real values; the row falls back to a short session id when the title is the schema's empty-string default. - Cache leverage used `cacheRead / (input + output + cacheRead)`, which reads low against the spec's `cacheRead / (input + cacheRead)` and disagreed with the renderer's own context-usage panel. Aligned to the spec. - The heatmap keyed cells by UTC date while the host buckets by local date, so every cell was off by a day for part of each day. Keys are now local dates. Metering and robustness: - `stats.summary` accepts `force` so the refresh button actually invalidates the TTL cache instead of re-serving it; illegal `rangeDays` now errors rather than silently becoming 30, and `topSessions.limit` is clamped. - `index.rebuild`/`index.clear` are audited; stats and index handlers emit tracing with duration and error markers. - `index.status` reports `progress` while building and in-memory fast-path metrics (served/fallback counts, candidate ratio, p50/p95). - `cards.peakDayDate` carries the peak day so the card can label it. Renderer: - New `stats/dataset.ts` is the single semantic shape feeding the charts, the screen-reader tables and the export, replacing per-component traversal. - Heatmap and trend gain `sr-only` data tables and numeric aria summaries. - Top sessions are buttons that open the session; rows show turn count and relative last-active time. CSV export is sectioned with a metadata header. - Spacing tokens `--space-1..6` now exist, so the thirteen `var(--space-N, X)` sites stop depending on their fallbacks. Card surface/radius unified across both pages, the 42px block gap collapsed to the page rhythm, and the toolbar wraps instead of overflowing at narrow widths. Verified: host-core 336, desktop 1233, shared 410, i18n 22, typecheck, style-lint and build all pass. UI conformance re-audited.
The tile fill sits only ~1.09:1 over the page plate, so the hairline is what reads as the card edge. At 5% alpha it was weaker than the mockup's border; 8% restores a comparable edge without turning the cards into outlined boxes.
…tegrate # Conflicts: # apps/desktop/electron/main/index.ts # apps/desktop/src/pages/SettingsPage.tsx # apps/desktop/src/styles/settings.css # crates/host-core/src/db.rs # crates/host-core/src/rpc/mod.rs # crates/host-core/src/tools/ignore_rules.rs # crates/host-core/src/tools/mod.rs # docs/spec/06-delivery/04-e2e-test-plan.md # docs/zh-CN/spec/06-delivery/04-e2e-test-plan.md # packages/i18n/src/locales/de/index.ts # packages/i18n/src/locales/es/index.ts # packages/i18n/src/locales/fr/index.ts # packages/shared/src/types.ts
The post-merge conformance audit returned CONFORMS with a short list of residuals; this closes all of them. - The stats and index IPC forwarders threw a bare "host unavailable" error, which the renderer's invoke envelope delivered without an error code, so the dedicated host-down copy on the usage page was a dead branch. The five guards now attach HOST_UNAVAILABLE (same pattern as the existing permission guard in register.ts). - The data-provenance footnote reused `.idx-error-line`, painting an informational note in error red; it now has its own muted style. - Metric tile labels wrap instead of truncating when a badge squeezes the head row (en "Current streak" at narrow widths). - The loading state renders the four metric cards with `--` placeholders per spec §2.2 instead of a bare status line. - Two stray `>` characters from the settings.css union merge are gone; one of them had disabled overflow clipping on plugin extension diagnostics. - `.stats-sr-table` gains display:block so the visually-hidden sizing applies to tables too. - English plurals: stats.days / stats.longestStreak use the _one/_other pair across all eight catalogs, fixing "1 days". Verified: desktop 1935/1935, i18n 24, typecheck, style-lint, build.
Interactions the reference product shows and the usage page lacked:
- Heatmap cells now carry a styled hover bubble with the localized date,
token total and completed-turn count. The host heatmap payload gains the
per-day turn count (HeatDay {date, tokens, turns}); dailyTotals is left
untouched to keep the change surface small.
- Token activity gains a 每日/每周/累计 switch: daily keeps the weekly-cell
grid, weekly renders ~53 ISO-week bars, cumulative renders the running
total as an area with the final value annotated. All three derive in the
dataset layer from the same daily series.
- The trend card gets its own 近7日/近30日 switch (independent of the
toolbar range; follows it when that changes), its legend moves above the
plot, and hovering snaps a crosshair to the nearest day with a bubble
listing the total and every model's value.
- Shared .stats-tooltip bubble (dark surface, pointer-events none) used by
both charts; the chart panels opt out of tile clipping so bubbles can
escape the card edge.
Verified: host-core 446, desktop 1952, i18n 24, typecheck, style-lint,
build. Live-checked on the real data dir: heat tooltip "2026年9月15日 |
7.5K Token · 1 轮", trend crosshair with per-model values, 53 weekly bars,
cumulative area, trend range switch.
…and hover Both non-daily charts were unreadable. The weekly view drew one bar among 53 empty weeks with no y axis, and the cumulative view had no ticks or dates at all; the stray caret above the baseline was a "0" label drawn 4px past a 126px viewBox and clipped into an arc. Share one 664x126 canvas across all three granularities so the card height no longer jumps with the switch, and add a reusable axis grid whose tick step derives from the axis top (four equal steps printed "0,0,1,1,1" at small magnitudes). Month labels thin out to a 34-unit minimum gap and skip a partial first month, which otherwise drops October entirely from a 365-day window. Weekly buckets carry turn counts, and both charts reveal a crosshair and a bubble on hover. Verified: typecheck, biome, style tokens, 1956 desktop tests, 24 i18n tests, and real-app screenshots of all three granularities.
Two switches claimed the same index and disagreed about who owned it. `indexNewFolders` only fed the auto-index trigger in `workspace.set`, so turning on `indexGrepBoost` alone already indexed every newly opened workspace and left the other switch redundant; turning on `indexNewFolders` alone built an index that nothing read, because Grep is the index's only consumer. Keep one switch. `indexGrepBoost` now owns both sides of the index: it triggers the background scan when the workspace changes and gates the Grep literal fast path. The card's lifecycle rows (status, rebuild, clear) are untouched. - shared/settings.ts: drop the field; the comment now states why one switch is enough. - IndexPage.tsx: delete the second toggle block, leaving one role="switch". - rpc/mod.rs: drop the `indexNewFolders` validation and the `auto_on` disjunct in `workspace.set`; rename the auto-index test to match. - i18n (8 locales): remove the newFolders keys and merge the auto-index sentence into grepBoostDesc, so the surviving copy names both effects. - docs (EN + zh-CN, 5 pairs): the settings IA, host RPC, storage, IPC and e2e plan all still described the two-switch trigger. - desktop test: assert exactly one role="switch" and no newFolders key. Verified: host-core 446, desktop 1956, i18n 24, typecheck, biome, style tokens, plus a real-app check of the settings page (one switch, merged copy, no newFolders in the DOM).
Integrates 146 commits of upstream work (quote/annotation/side-chat removal, capability-level transfer, plugin websocket transport, plugin display locale) with the workspace-index and usage-statistics work on this branch. Conflict resolution: - crates/host-core/src/rpc/mod.rs: unioned the import list and the test module so the index lifecycle/auto-index tests and upstream's plugin-label and capability-target tests all survive. - docs/spec/06-delivery/04-e2e-test-plan.md and its zh-CN mirror: kept upstream's real-time-capability rows, collapsed the duplicated `M6+` acceptance row into one (our E2E-INDEX ids plus upstream's list), and dropped the stale re-sorted copy of the traceability table that had duplicated 10 rows (en) / 6 rows (zh) and broken the EN/zh table-shape parity. Follow-ups folded in so the Docs check passes on the merged tree: - Renumbered our ADR 0181 to 0270: upstream already owns 0181 for main-owned picker capabilities. Indexed it in docs/adr/README.md and the Chinese index, and repointed the two settings-IA citations. - Listed 06-delivery/rg-baseline-2026-09-13.md in both NAV.md trees. - Gave the Chinese rg-baseline page the standard [英文源规格] notice that check-locales requires. - rustfmt on rpc/mod.rs, tools/mod.rs and stats.rs, and dropped an unused PROJECT_TOP_N constant.
StatsPage.tsx had grown to 1350 lines, over the repository's 800-line budget for a new TypeScript source file. The page keeps the toolbar, metric cards, insights and the session table; each chart moves to its own module under settings/stats/: types.ts, format.ts, export.ts, geometry.ts AxisGrid.tsx, Heatmap.tsx, WeeklyActivity.tsx, CumulativeActivity.tsx, Trend.tsx, Donut.tsx No behaviour change: the code is moved verbatim and the new modules read the existing stats/dataset.ts, which stays the single data source for the charts, the sr-only tables and the export. The two activity views still own their crosshair, marker and tooltip inside their own plot wrapper. The source-contract tests read the page as text, so they now read the whole surface through a new readStatsSource() helper (facade + stats/ modules), the same pattern readSettingsSource() already uses. The two tests that depended on the order the code happened to be written in read their module directly instead of slicing a concatenation.
chat-error-message.test.mjs never closed the test above it, so the network-errno case was parsed as a nested subtest: the parent body resolved first and node cancelled the child, surfacing a failure that had nothing to do with the assertions. Closing the test where it ends makes all three cases top-level; they pass unchanged.
…rate # Conflicts: # crates/host-core/src/agent_capabilities.rs # crates/host-core/src/mcp_servers.rs # crates/host-core/src/user_skills.rs # docs/adr/README.md # docs/zh-CN/adr/index.md
…st order Appending the unindexed tail after the FTS hits let a head-limited Grep read an older indexed hit before a newer unindexed file, so the boosted answer could differ from rg's — exactly what the byte-for-byte contract forbids. Re-sort the merged set by (mtime desc, rel_path) and pin the order with a diff test.
visible_walker never applied parents(false) for scoped walks, so without a system rg an explicitly named directory under an ignored parent came back empty while rg searched it. Set the flag in the shared walker, drop the dead locally-configured walker the candidate loop never iterated, and pin the contract with a walker-level test.
…esidue builds Three reliability gaps closed: a 'building' row left by a crashed host process answered InProgress forever and was never retried; an unchanged workspace was never re-crawled, so in-place edits stayed invisible to the fast path until a different workspace was opened; and an unopenable index store blocked host startup. Builds now register in-process so residue is recognizable, workspace.set refreshes an unchanged root at most once per AUTO_REFRESH_MIN_INTERVAL, and an unopenable store degrades to a disabled one.
… a plugin Per the maintainer's call on vastsa#478, the cross-session usage dashboard belongs to the plugin ecosystem — pi.token-insights already covers it, and a plugin cannot import app internals, so keeping the unrouted page had no path back to a route. Delete the page, its chart modules, the dataset layer, the component tests, the self-skipping e2e script, the stats CSS blocks, and the per-locale stats.* keys (the two nudge keys move to index.*, still used by the index page). What deliberately stays on the Core surface: the stats.* RPCs, their shared types, and the host unit tests — the data layer a plugin calls. The D335 guard test now pins the boundary in both directions: no usage destination may creep back into Settings, and the stats RPCs may not be swept away as dead code. The interim ADR is renumbered to 0273 (upstream took 0271 for the provider-transport rebuild) and rewritten to record this end state; the E2E-STATS cases are marked Parked; the zh error-code table, the stale ipc-protocol index row, and the en/zh settings-ia copy are re-synced.
Keeps index.rs under the Rust file budget without an exemption: the refresh interval, its store methods, and their tests move to index/refresh.rs. No behaviour change.
…tries honest Three polish points from the re-review: the ensure/refresh calls run on the index store's own connection, so the app state lock is dropped before them instead of being held across the store I/O; the refresh interval now starts only when the re-walk actually triggered (a failed request_refresh retries on the next workspace.set instead of waiting out the interval, and a changed-path rebuild marks the interval too so it is not immediately refreshed again); and request_refresh registers the build in-process before the row flips, so a concurrent ensure_index in the spawn window reads a live build rather than crash residue. The candidate sort comparator is destructured for readability. No behaviour change beyond the retry and window semantics.
…rate Upstream minted ADR 0273-0275, colliding with the branch's withdrawn usage ADR a second time. The withdrawn ADR is dropped outright instead of re-numbered: it never shipped upstream, its Superseded substance is carried by ADR 0173, the vastsa#478 thread, and the guard test, and chasing a free number in a repo minting ADRs daily cannot converge.
The ten-minute same-path refresh used to flip the root to building and re-crawl unconditionally. It now walks the visible set stat-only (same walker the crawler uses, minus the content read, ~0.5s at the file budget) and skips the crawl entirely when every stored row still matches disk — the ninja no-op-build pattern. Any disagreement (edited, added, vanished, over budget) falls through to the full crawl. The probe runs on the blocking pool and consumes the interval either way, and the spec copy now states the freshness model honestly (en/zh).
…rate # Conflicts: # docs/spec/06-delivery/04-e2e-test-plan.md
The cascade also carries a .chat-surface[data-chat-resizing=true] .home-stack-inner rule whose suffix satisfies the unanchored pattern first, so the probe read a block with no gap and failed on main independently of this branch. Anchoring at the line start selects the standalone gap block the test was written for.
|
整体方向我认可,Workspace Index 放到 Workspace 设置下、默认 opt-in、索引失败不影响 Host 启动、FTS 只做 candidate narrowing 而最终仍由原 Grep scanner 判定,这些设计都比较合理。 不过当前实现我建议先不要直接合并,还有几个 correctness / lifecycle 问题需要收一下:
另外,开启 Stats 这一块我个人也更倾向后续单独拆 PR。当前这个 PR 已经同时包含 Index、Grep fast path、Settings、Stats RPC 和大量 spec,scope 比较大,后续 review / regression / rollback 都会更困难。 整体不是要推翻方案,FTS5 + trigram + fallback 这个方向我觉得可以继续。把 freshness、内存和并发这几个基础问题闭环后,我会更放心让它进入主线。 |
Review follow-ups on the freshness lifecycle: - building_roots now maps each root to its own BuildProgress, so two roots building concurrently no longer share one card's done/total; index.status reads the building root's own counters. - A rebuild that enters a root already registered in this process adopts the existing registration instead of interleaving a second crawl's totals into the health card; the auto-refresh probe and the rebuild it spawns are the same logical re-walk. - ensure_index registers (with the denominator seeded from the previous visible set) before the row flips, so the card never shows 0/0 and a concurrent caller answers InProgress from the in-process entry. - Turning indexGrepBoost on arms the index for the workspace the user is looking at: settings.set ensures and rebuilds the current workspace's index, so the switch's lifetime is not disjoint from its only consumer.
scan_root pushed every ingested body into a Vec<IndexedFile> before any row reached SQLite — at the 2GB indexed-bytes budget that is 2GB of heap on a desktop app. The crawler now hands each file to a RootWriter as it is read: statements prepared from the connection, one open transaction per rebuild, commit at the end. Same rows, same state machine, same tests; the memory ceiling moves from the indexed-bytes budget to SQLite's page cache.
Review follow-up (the correctness half of the freshness ask): with the refresh limited to workspace.set, content the agent itself writes stayed invisible to the fast path for up to the refresh interval — FTS could serve a candidate set that predates the write, which is exactly the silent-miss the index must never cause. A successful Write/Edit/Bash call now marks the workspace's root stale. Grep's fast path answers StateGate for a stale root and falls back to the full walk, so the index can only cost speed, never correctness; the rebuild stays opportunistic on the next workspace.set. A filesystem watcher (for edits made outside the host) is the remaining half and is tracked separately.
The other half of the freshness ask: edits made outside the host (an editor, git checkout, a build script) were invisible until the next workspace.set. A new optional workspace-watch feature adds a notify-based watcher that does exactly one thing — mark the affected root stale — so Grep's fast path falls back instead of serving a candidate set that predates the change. It never parses paths, patches the index incrementally, or rebuilds on its own: events are hints, and the stat-only probe plus a rebuild stay the authority, which also means a burst of events needs no debouncing (a second mark is a no-op). Wired at workspace.set and index.rebuild (a manually built root is served by the fast path and must be watched too) and unwired at workspace.clear. Off by default; CI builds with --all-features, and both watcher tests run there, including an end-to-end external-write-lands-as-stale case.
index.rs crossed the 1000-line budget as the rebuild and watcher work landed. The SQLite layer — schema, connection opener, pragmas — is a self-contained unit and moves to index/fts.rs rather than earning an allowlist exemption. No behaviour change.
|
感谢细致的 review,三条都成立,已全部处理并推送(分支 tip 1. freshness 不能保证 Grep 正确性 —— 已修,拆成两半覆盖 您指出的窗口确实存在:refresh 只挂在
2. rebuild 不把正文全放内存 —— 已改为流式(
3. 同一 root 的 rebuild 需要统一协调 —— 已做 per-root 状态(
关于 boost 开关生命周期:同意,已接上——开启 关于拆 PR:同意,这个 PR 确实过宽。计划这样拆:
如果您认可这个拆法,我把 stats 部分摘出去后重推本 PR 的分支范围;摘之前想先确认一下,避免您 review 到一半分支变动。另外顺手报一个与本 PR 无关的发现: |
|
docs 撞号没事哒,这个是开发规范有问题,一直没空处理,感谢时间,我有空看看 |
|
不客气~两个 PR 的三条 correctness/lifecycle 修复都已推上分支了(watcher/流式 rebuild/per-root 协调/boost-on ensure + listTurns 契约),您方便时过目即可 🙏 |
…rate # Conflicts: # apps/desktop/test/interaction-polish.test.mjs # crates/host-core/src/state.rs
…rate # Conflicts: # docs/spec/06-delivery/04-e2e-test-plan.md # docs/zh-CN/spec/06-delivery/04-e2e-test-plan.md
|
感谢这一轮跟进,流式 rebuild、per-root 构建协调、打开 boost 时对当前 workspace ensure/rebuild,这几处我都看到了,方向还是认可的。Index 放 Workspace、默认 opt-in、FTS 只缩候选、失败不挡 Host 启动,这些都没变。 不过 boost 打开时 Grep 正确性还没真正闭环,建议先不要合,再收一小轮就行。不是推翻方案。 1.
|
Review follow-up: with the dashboard UI gone, the stats RPC surface has no consumer inside this change and no coupling to the index — it ships on its own branch instead. Removes stats.rs, the summary/topSessions RPC cases and param helpers, the shared types and protocol constants, the api/session-ipc forwarding, the reconcile script, and the guard assertions that pinned the RPCs to this PR; the D335 guard now asserts their absence here. getTokenUsageHistory (main's own sessions-domain surface) is untouched, and the index status types move to types/workspace-index.ts — they describe the index, not usage stats.
The stats split renamed the shared types home for the index surface; the test's source-read path follows it.
…rate # Conflicts: # docs/spec/06-delivery/04-e2e-test-plan.md # package.json
|
三条全部收到并已修复,分支 tip 1. 2. 发版二进制没有 watcher —— 已修(选了您的第一项)。 3. 空候选自信漏 —— 正确性闭环的完整描述:现在失效有三道闸,任何一道触发,fast path 即回退 rg(StateGate):① 宿主写入立即标 stale;② watcher 事件立即标 stale(默认开启,事件延迟为毫秒级);③ 构建期间到达的事件不再丢弃—— 4. stats 拆分 —— 已拆。 5. rebase:已在 门禁:host 552/0(含 workspace-watch)、desktop 2071/0、typecheck / lint / i18n 键集全等、架构预算(无豁免, |
PR: feat(settings): fold the workspace index into the Workspace group
Summary
Implements the split the maintainer called for on #478:
no new "Data & Statistics" group. One opt-in switch (
indexGrepBoost)owns both sides: the status/rebuild/clear page and the Grep fast path.
the Core surface is the host-owned aggregation —
stats.summary/stats.topSessionsRPCs, their shared types, and their host tests — asthe data layer plugins build on (ADR 0273 supersedes the interim ADR;
pi.token-insightsowns the cross-session dashboard).What's in the box
index.rs— FTS5 content store for the workspace visible set(single source shared with Grep via
tools/ignore_rules), three-axisbudgets (files/bytes/indexed-bytes), a six-state root status machine,
corruption quarantine, in-process build registry with crash-residue
recovery.
index/fast_path.rs— trigram admission gate, per-candidatestat verification with a drift fuse, candidate sets provably equal to the
rg visible set (diff-tested), merged into the fallback's global
newest-first order so a head-limited Grep answers identically with or
without the boost.
index.status/index.rebuild/index.clearandstats.summary/stats.topSessions, error codes registered, specen/zh paired.
hit-rate/latency metrics, one-time nudge) under the Workspace group;
a freshness interval (
AUTO_REFRESH_MIN_INTERVAL) bounds how longin-place edits stay invisible to the fast path; an unopenable index
store degrades to disabled instead of blocking host startup.
test:e2e:indexautomated;the stats board cases are marked Parked (plugin territory).
Review-round fixes baked in
reorder head-limited results vs rg)
--no-ignore-parent(was: explicitly named dirs could come up emptywithout a system rg)
buildingcrash residue is re-armed instead of answered InProgressforever
workspace.set, rate-limitedGates
docs:check(78 en/zh spec pairs): cleanRust limit by splitting the refresh into
index/refresh.rs, no exemptionof the real
~/.pi-desktopdatabase; the Settings IA was verified live overCDP (Index under the Workspace group, single opt-in switch, no usage
destination anywhere)
same architecture published for GitHub Blackbird / Zoekt / livegrep; the
bounded-staleness interval and drift fuse mirror standard practice
Follow-up (separate stacked PR, not in this one)
A minimal
pi.usageplugin API (summary/topSessions+ a read-onlyusage.readpermission) wrapping the same host functions, sopi.token-insightscan adopt the formal contract instead of reading thehost database directly.