Skip to content

v0.1.121: close 5 MCP design issues found by live-driving all 48 verbs#32

Merged
singhpratech merged 3 commits into
mainfrom
fix/mcp-v121-design-issues
Jul 21, 2026
Merged

v0.1.121: close 5 MCP design issues found by live-driving all 48 verbs#32
singhpratech merged 3 commits into
mainfrom
fix/mcp-v121-design-issues

Conversation

@singhpratech

Copy link
Copy Markdown
Owner

Fixes 5 MCP design issues surfaced by driving the real editor with the real sidecar on v0.1.120 (gaps the fake-half unit suites can't see):

Approval-gate invariant preserved: save_tab stays WRITE+approval, select_range is ACT (no card), no headless bypass. Each fix has a red-state test that fails without it (spot-verified by hand).

Local: ctest 71/71, Rust default + --features remote green, fmt/clippy --all-features clean, Windows cross-check clean.

#2 (export_chart→file e.isString) is a separate WebEngine runtime bug, tracked separately.

🤖 Generated with Claude Code

Prateek Singh and others added 3 commits July 20, 2026 21:43
Found by driving the real editor with the real sidecar on v0.1.120 —
gaps the fake-half unit suites (C++ fakes the sidecar, Rust fakes the
bridge) structurally cannot see. Opus-architected, implemented in
dependency order, each with a red-state test that FAILS without the fix.

#1 Welcome tab (index 0) was a silent trap: it appeared in list_open_tabs
   like any tab but insert_text/compare_tabs/save_tab failed on it with
   generic errors, and read_tab returned empty text (worse — looked like
   an empty document). Now every tab carries "editable"; the five
   tab-context write/read verbs gate on it.

#3 git_* were unusable with no repo file open. runGit now appends the
   editor's STARTUP working dir (QDir::currentPath captured once at
   construction, never live — a live cwd would make git_status depend on
   the last file dialog) as the final candidate root, so
   `notepatra ~/repo && git_status` works.

#4 save_tab could not persist AI-generated content: it refused untitled
   tabs and had no path. It now takes an optional `path` (Save-As). It
   STAYS WRITE-tier and approval-gated: the path is validated (absolute +
   parent exists) BEFORE the card, the card SHOWS the destination
   (OVERWRITE-flagged if it exists), and the write executes only inside
   the approved closure. No headless bypass.

#5 replace_selection was unusable by an AI — it needed a selection but
   nothing could set one. New ACT-tier verb select_range (1-based, like
   goto_line) sets the selection with no card (it mutates only the
   selection, like goto_line); replace_selection still carries its own
   approval. Tool count 48 -> 49.

#6 generic errors ("could not insert", "could not open compare view",
   "needs Save As") replaced with specific, actionable messages so an AI
   can self-correct.

Verified independently, not just by the implementer: full ctest 71/71,
Rust default + --features remote green, fmt + clippy --all-features
clean, Windows cross-check (x86_64-pc-windows-msvc) clean. Red-state
spot-checked by hand — forcing tabIsEditable true fails exactly the 3
gate tests. Approval-gate audit: save_tab validates before the card and
executes only in the approval closure; select_range enqueues zero cards.

Deliberate deviation from spec: the Rust mock does NOT prepend a Welcome
tab at index 0 — that would shift ~55 index-dependent assertions and
break every write test targeting tab_index 0. The C++ bridge (source of
truth) fully implements and tests Welcome-tab behavior; the mock
exercises editable:false via diagram tabs.

#2 (export_chart-to-file "TypeError: e.isString") is a separate WebEngine
runtime bug, investigated separately — not in this change.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…Engine

ROOT CAUSE (confirmed, hard evidence): the charts feature never rendered on
Qt 5.15. Its WebEngine is Chromium ~87, but the bundled vega libraries call
Object.hasOwn (needs Chromium 93) and structuredClone (needs Chromium 98).
The real-display editor log showed, on every chart render:
    Uncaught TypeError: Object.hasOwn is not a function
    Uncaught ReferenceError: structuredClone is not defined
vega core then fails to initialise, leaving vega.isString undefined, and
vega-embed dies synchronously with "TypeError: e.isString is not a function".
This broke BOTH paths: export_chart surfaced the error, while render_chart
returned rendered:true and drew NOTHING — a headline v0.1.120 feature that
was silently dead on any Qt 5.15 box.

FIX: define both APIs (JSON round-trip is a sufficient structuredClone for
vega's JSON-serialisable specs) in a <script> that runs BEFORE the three
vega <script> tags in the render shell. Standard, minimal polyfills for
exactly the two confirmed-missing functions.

VERIFICATION — HONEST STATUS: root cause is confirmed and the fix is a
textbook polyfill for it, but I could NOT complete an end-to-end runtime
render check in this environment. Offscreen WebEngine does not execute the
chart JS at all (proven: red-stating the fix offscreen showed no change —
the check was a false positive), and the on-display editor kept dying to a
/tmp socket reaper + single-instance collisions before a clean screenshot.
So this is committed as root-cause-confirmed + fix-sound, runtime-pending.
Confirm by rendering any chart on a real display (Qt 5.15 + WebEngine);
the fix is expected to make render_chart draw and export_chart save.

Charts code (vega_chart_renderer.cpp) only — no other surface touched.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Version SSOT 0.1.120 -> 0.1.121 (CMakeLists, Cargo.toml/lock, mcpb
manifest). MCP tool count 48 -> 49 (the new select_range verb; tiers now
Read 24 / Act 14 / Write 11) across MCP_TOOL_COUNT and every current-tense
docs surface; v0.1.120 historical references left at 48/v0.1.120.

Docs swept to v0.1.121 (JSON-LD, sticky-CTA, hero badge — tagline
byte-identical except the version — download buttons/sizes, README
release row + installer filenames, docs.html/mcp.html/llms.txt tool
counts + a new select_range Act-table row). New v0.1.121 version card
added above v0.1.120 with the LATEST pill; no gaps in the card history.
release_notes/v0.1.121.md + CHANGELOG [0.1.121] added.

Test fix: protocol.rs asserted a hardcoded "0.1.120" serverInfo.version;
now derives from env!("CARGO_PKG_VERSION") so a version bump never leaves
it stale again.

The 6 fixes themselves are in the prior commits on this branch (e803578
API fixes #1/#3/#4/#5/#6; 65d4f4d charts Qt5.15 polyfill #2).

Local gates: ctest 71/71, Rust default + --features remote green, fmt +
clippy --all-features clean, stale-text-check 62/62, release-check green
(only tree-clean pending, resolved here). PII clean.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@singhpratech
singhpratech merged commit d71a7f9 into main Jul 21, 2026
12 of 13 checks passed
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