Skip to content

Re-verify the feature ledger and close its findings - #1616

Merged
xiaolai merged 4 commits into
mainfrom
docs/feature-ledger-reverify
Oct 30, 2026
Merged

xiaolai merged 4 commits into
mainfrom
docs/feature-ledger-reverify

Conversation

@xiaolai

@xiaolai xiaolai commented Oct 30, 2026

Copy link
Copy Markdown
Owner

Summary

Re-verifies the feature ledger (.claude/feature-ledger.md) against current main across all 15 areas, then closes the findings that pass turned up: in code, tests, gates, feature-map ownership and the user guide.

CHANGE-SIZE-ACK: 582 files (+9,777/−5,566), intended. The ledger re-verification touches every area, and each finding is fixed in the area where it was found. The work is split into four commits by kind (ledger, code fixes, guide in 10 languages, header comments). Most of the file count comes from the guide's 9 locale copies.

Policy Gates (Required)

  • This PR is single-focus (one issue, one problem, one objective). It has one objective (bring the ledger and the product back into agreement), but several kinds of fix. They are split into four commits for review.
  • This PR includes 100% test coverage for changed behavior and changed code paths. Every behaviour change has a test, and the coverage floors pass in check:all. I have not measured per-line coverage of this diff.
  • If this is a bug fix, the linked issue contains detailed reproduction context. There is no linked issue; each finding's context is in the ledger and the commit messages.

Linked Issue

None. The findings come from the ledger re-verification in ce4066bf5.

Type of Change

  • Bug fix
  • Docs
  • Refactor
  • Feature
  • Test-only
  • Other

What Changed

Security (each tightened to the stricter behaviour)

  • PDF, Pandoc and Slidev exports write only to a path the user picked in a native save panel shown by Rust. The choice is recorded per webview and works once; a request naming any other path cancels it.
  • The secure store is opened by the backend, and the webview only looks it up. The webview is no longer granted store:allow-load, which accepted absolute paths outside app data.
  • The automation bridge's capability moves out of capabilities/ and is added at runtime, only in debug builds where the bridge started.
  • open_workspace binds its one-time approval to the connection that asked for it.
  • A second launch resolves relative arguments against its own working directory, and drops them when that is unknown.
  • All three approval prompts (browser, workflow step, workspace folder) show invisible characters as escapes: category Cf, Default_Ignorable_Code_Point and U+2800. They go through one shared helper, src/utils/revealInvisibleChars.ts. The browser prompt's eval/style script used to be shown raw, so a bidi override could disguise it.

Dead code removed (each has a Retired row in the ledger): the coherence accept path, the operators and merge audit, resolveTerminalCwd, a cjkFormatter re-export, and the unused @xterm/addon-serialize.

Ownership and gates

  • Feature-map owners now match the files' real features, and new modules are registered.
  • single_instance.rs is split at its argv seam so it stays under the file-size limit.
  • Baselines only shrink: the stale file-size and mock-boundary entries are removed.
  • The locale-structure join now also compares the number of rows in each table. That is how it caught the Japanese multi-cursor page missing a shortcut, which is restored here.

Size budgets re-measured, each with its mechanism

  • Eager entry: 130 → 144 kB, because lintEngine moved into it from the documentStore chunk. The eager total is unchanged at 3.14 MB.
  • ShortcutsSettings: 8.7 → 9.4 kB, for the new Remove and Reassign controls.

Guide: 20 pages corrected, and every change carried into all 9 locales.

Visible changes:

  • "Hide" is now "Hide VMark", and the .md toggle label changed.
  • The sidebar panel was renamed.
  • PDF CJK letter spacing now defaults to off; it was 0.05em.

Stale tests and comments:

  • The useGenieShortcuts lifecycle test now mocks load_genies.
  • DelegationsSection uses a fake clock.
  • Six module headers are corrected.

Validation

  • I ran pnpm check:all locally. Exit 0: app tier 2,327 files / 49,533 tests, the other tiers green, every size limit within budget.
  • I added or updated tests to fully cover behavior changes. Each security change got a test that failed before the fix.
  • I manually verified critical flows. Not done: the native save panel, Windows (trusted HTML, tray, single-instance), Linux fcitx5, and the e2e journeys.

Rust: cargo test --lib passed 5,197 tests with 0 failures; cargo clippy --all-targets -- -D warnings and cargo fmt --check pass; scripts/check-cross-target.sh passes.

pnpm check:predelta passes all 49 gates. The branch adds no skip, only, eslint-disable, #[allow] or #[ignore].

UI Evidence (if applicable)

None attached. The visible changes are a menu label, a toggle label, a sidebar panel name, and escape sequences in approval prompts.

PR Checklist

  • The PR avoids unrelated refactors or cleanup. The work is cleanup by design; each change traces to a ledger finding.
  • The issue context is clear (linked issue or explanation above).
  • Docs/changelog were updated if behavior or usage changed.
  • I am ready to address review feedback.

Open decisions (not in this PR)

  • Should files outside the built-in folders and workspaces reopen after a restart without asking? A yes needs a persisted list of approved paths.
  • Should the browser/MCP e2e tests run on PRs?
  • Where should a workflow-genie run's step graph, Cancel and Restore appear?
  • On Windows and Linux, should Mod-y mean redo or open Genies?

Every block, finding and retired entry was re-read against the code at
bb94fd3 (v0.9.108). Areas had last been verified about 1,060 commits
earlier. New blocks cover the navigation guard, sidebar style, settled
scroll, third-party notices, terminal transcript, floating prompt and
macOS privacy keys, reading-position restore and the IME write gate.
Open findings go from 151 to 180, with category counts matching the
lines.

The feature map now gives the YAML workflow engine its dispatch and
event-routing files, and Pandoc export its src/export modules; both had
fallen to a broader directory owner.
The re-verification of the feature ledger left findings outside its own
docs-only change. This closes those in code, tests, config and the ledger.

Security, each tightened to the stricter behaviour:
- PDF, Pandoc and Slidev exports write only to a path the user chose in
  a native save panel Rust showed, recorded per webview and spent once;
  a request naming any other path withdraws the choice.
- The secure store is opened by the backend and only looked up by the
  webview, which is no longer granted store:allow-load (an absolute
  path would have reached outside the app data directory). The
  secret_token docs now state the real entropy: 244 bits.
- The automation-bridge capability moves out of capabilities/ and is
  added at runtime only in a debug build whose bridge started, so a
  release build carries no mcp-bridge permission.
- open_workspace binds its one-shot to the connection that asked.
- A second launch resolves relative arguments against its own working
  directory and drops them when that is unknown, instead of opening and
  granting a folder under the running instance's directory.
- Every approval prompt (browser, workflow step, workspace folder) shows
  characters that draw nothing as visible escapes: category Cf plus
  Default_Ignorable_Code_Point plus U+2800, through one shared
  utils/revealInvisibleChars. The browser prompt's eval/style script
  was rendered raw and could be reordered by a bidi override.
- The PDF export window discards its temporary HTML when destroyed, now
  pinned by a source test.

Dead code removed, each with a Retired ledger row: the coherence accept
path, operators and merge audit, resolveTerminalCwd, a cjkFormatter
re-export, and the unused @xterm/addon-serialize with its licence text.

Ownership and gates: feature-map owners moved to the files' real
features; new modules registered. single_instance.rs split at its argv
seam to stay under the file-size limit. Baselines only shrink:
resolveDirtyBatch.test.ts now mocks boundaries only, and stale
file-size and mock-boundary entries are pruned.

Size budgets re-measured, each with its mechanism: the eager entry rises
from 130 to 144 kB because lintEngine moved out of the documentStore
chunk into it, leaving the eager total unchanged at 3.14 MB;
ShortcutsSettings rises from 8.7 to 9.4 kB for the new Remove and
Reassign controls.

Stale tests and comments fixed: useGenieShortcuts lifecycle test now
mocks load_genies, DelegationsSection uses a fake clock, and three
runLint comments name runLintForFormat.
The ledger re-verification found guide statements that no longer match
the app: where the [TOC] marker and Document History settings live, the
Toggle Line Numbers shortcut, the Coherence panel's name, the
workflow-viewer cron sentence, Link Protocols, the MCP tool
composition, the HTML notice in formats, media paths, and the
integrations auto-approve description, plus the behaviour the
previous change closed (media and workflow-genie limits). The English
pages are corrected and every hunk is carried into the nine locales,
with each locale's sidebar label for the renamed panel.

The locale-structure doc join now compares the body-row count of each
table, not only the number of tables. A row English added to an
existing table passed before; it is how the Japanese multi-cursor page
lost its "add cursors to every match in the current block" shortcut,
restored here.
The pre-commit header check warned that 26 files changed without their
leading comment changing. Each was compared with its diff; six headers
had become false or incomplete and are corrected here, the other twenty
still describe their files accurately.

- app_plugins.rs: the Rust-opened secure store and the debug-only
  runtime capability for the automation bridge are now key decisions.
- app_setup.rs: window teardown names window_destroyed, where it moved.
- pdf_smoke/progress_case.rs: the harness calls export_pdf_to_path,
  the command's body, because it has no save panel to choose in.
- files/open.rs and supported_files.rs: a folder passed as a launch
  argument on Windows and Linux is granted like a Finder folder, and
  launch_dirs is the helper that picks it out.
- BrowserApprovalDialog.tsx: payload summaries are uncut and invisible
  characters are shown as escapes.
@xiaolai
xiaolai force-pushed the docs/feature-ledger-reverify branch from 720ef5a to d5a68ac Compare October 30, 2026 23:09
@xiaolai
xiaolai merged commit e28ef78 into main Oct 30, 2026
21 checks passed
@xiaolai
xiaolai deleted the docs/feature-ledger-reverify branch October 30, 2026 23:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant