Skip to content

feat: Claude auto-update, spec workflow overhaul, share URL shortener#144

Merged
maxritter merged 2 commits into
mainfrom
dev
May 13, 2026
Merged

feat: Claude auto-update, spec workflow overhaul, share URL shortener#144
maxritter merged 2 commits into
mainfrom
dev

Conversation

@maxritter

@maxritter maxritter commented May 13, 2026

Copy link
Copy Markdown
Owner

Five user-facing features verified via /spec on the dev branch. All non-breaking.

pilot update updates Claude Code too

pilot update (alias pilot upgrade) now updates Claude Code alongside Pilot Shell via the npm registry. Run it once, get both up-to-date.

Branch toggle + Settings UI overhaul

[Plan: docs/plans/2026-05-13-branch-toggle-and-settings-ui.md]

  • worktreeSupport renamed to branchIsolation (covers both new-branch and worktree creation)
  • Dispatcher skips the branch question entirely when the toggle is off (defaults to current branch)
  • Settings page restructured into a left-vertical-tab sidebar with extracted section components

Spec skills step consolidation

[Plan: docs/plans/2026-05-13-spec-skills-step-consolidation.md]

  • Step count cut 60 → 42 (-30%) across the five spec-driven skills
  • Eliminates the user-reported "Step 1 → Step 4 phantom gap" pattern
  • Behavior preserved; spec/ dispatcher and fix/ skill untouched (already lean)

/spec process improvements (ported from claude-goal)

[Plan: docs/plans/2026-05-13-spec-process-improvements-from-claude-goal.md]

  • Stop-guard re-injects the plan's objective and verification truths on every block message, keeping goal top-of-mind across long verify→implement loops
  • Blocking, evidence-mapped completion-audit checklist that every feature and bugfix plan must pass before reaching Status: VERIFIED

Spec share URL shortener

[Plan: docs/plans/2026-05-13-spec-share-url-shortener.md]

Replace the 30 KB-fragment share URL with a short https://pilot-shell.com/s/<id> link:

  • New Vercel Edge endpoint at docs/site/api/share.ts backed by Upstash Redis (the trial endpoint's existing store; no new infra)
  • 8-char IDs, 3-day TTL, non-spoofable per-IP rate limiting (POST 30/hr, GET 300/hr — protects the daily Upstash command quota from random-ID scan drain)
  • Base64url validation, atomic INCR+EXPIRE pipeline (EXPIRE … NX), NX collision retry
  • pilot-shell.com SPA gains /s/:id route + fetch-by-ID; landing-page paste input recognizes the new format (host-agnostic regex)
  • Local "Has Pilot Shell" target dropped entirely — share and feedback always round-trip through pilot-shell.com
  • Console ShareDialog simplified (no toggle), useShare.ts single POST flow, ImportFeedbackDialog recognizes pilot-shell.com/s/<id> with runtime isFeedbackPayload guard (rejects empty objects, malformed annotations, share-payloads-pasted-as-feedback)
  • Legacy pilot-shell.com/shared#<fragment> URLs still decode (no broken in-flight links)
  • Dead local paste service deleted (ShareRoutes, ShareStore, tests, isPasteServiceId callers across 4 files)
  • New vitest test harness in docs/site with 19 endpoint tests + 5 feedback-flow tests
  • Pre-existing compress.ts Uint8Array typing issue fixed as part of the cleanup

Verification

  • docs/site: 24 vitest tests pass, build clean, typecheck clean
  • console: 1471 bun tests pass / 0 fail / 3 skip, typecheck clean
  • Live E2E verified on Vercel preview: API contract (POST/GET/404/400/413/429/OPTIONS/DELETE), /s/<id> SPA route render, legacy fragment URL back-compat (zero /api/share calls), feedback round-trip with runtime payload guard

Reviewer findings resolved

Two adversarial reviewers (Claude + Codex) flagged 9 issues during /spec verify — all resolved before merge:

  • Rate-limit IP from first x-forwarded-for entry was spoofable → fixed via x-real-ip with last-XFF fallback
  • GET rate-limit gap (random-ID scan could drain quota) → added 300/hr GET limit, 404s count
  • Test harness missing in docs/site → added vitest + 24 tests
  • Trusted arbitrary stored payloads in ImportFeedbackDialog → isFeedbackPayload runtime guard
  • Legacy SharedSpecView still emitted localhost feedback URLs and fell back to deleted route → rewrote to pilot-shell.com flow
  • Stale "Zero data sent" docstring and privacy notices → updated copy across UI
  • Non-atomic INCR+EXPIRE (Edge death = permanent IP cap) → pipelined with EXPIRE NX
  • Landing-page paste input rejected /s/ URLs → host-agnostic regex
  • _lib/cors.ts advertised only POST,OPTIONS on preflight → added GET

Summary by CodeRabbit

  • Documentation

    • Clarified CLI update behavior, added --skip-claude and upgrade alias; updated spec planning guidance and workflow config examples.
  • New Features

    • Short-form shareable spec links with short-lived storage (≤3 days).
    • New URL pattern for accessing shared documents.
    • Collapsible, sectioned spec viewer for improved readability.
  • Bug Fixes

    • Fixed shared-content decompression and enabled GET on share API CORS.
  • Tests

    • Added tests for sharing flows.
  • Chores

    • Config migration to introduce branch isolation setting.

Review Change Stack

* `pilot update` (alias `pilot upgrade`) now updates Claude Code alongside
  Pilot Shell via npm registry lookup
* branch isolation toggle replaces worktreeSupport, dispatcher skips branch
  question when disabled, Settings page restructured into left-vertical-tab
  sidebar with extracted section components
* spec skills step count cut 60→42 (-30%) by merging tiny conditional steps;
  eliminates user-reported phantom Step 1 → Step 4 gaps; behavior preserved
* /spec gains stop-guard objective re-injection and a blocking
  completion-audit gate before reaching VERIFIED (ported from claude-goal)
* spec share URLs replaced with short pilot-shell.com/s/<id> backed by a
  Vercel Edge endpoint on Upstash Redis (non-spoofable per-IP rate limiting,
  base64url validation, atomic INCR+EXPIRE, NX collision retry, runtime
  feedback-payload guard); legacy fragment URLs still decode; dead local
  paste service removed; new vitest harness in docs/site with 24 tests
@vercel

vercel Bot commented May 13, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
pilot-shell Ignored Ignored Preview May 13, 2026 2:07pm

Request Review

@coderabbitai

coderabbitai Bot commented May 13, 2026

Copy link
Copy Markdown

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: fe55828f-692c-4402-952c-a4fab7b62481

📥 Commits

Reviewing files that changed from the base of the PR and between 6270aa9 and 446ad51.

⛔ Files ignored due to path filters (1)
  • console/src/ui/viewer/views/Spec/annotation/SectionedBlockRenderer.tsx is excluded by !console/**
📒 Files selected for processing (3)
  • docs/site/src/components/feedback/SectionedBlockRenderer.tsx
  • docs/site/src/lib/sharing/sharing.ts
  • docs/site/src/pages/Shared.tsx
🚧 Files skipped from review as they are similar to previous changes (3)
  • docs/site/src/lib/sharing/sharing.ts
  • docs/site/src/pages/Shared.tsx
  • docs/site/src/components/feedback/SectionedBlockRenderer.tsx

Walkthrough

This PR adds a config migration (v11) renaming specWorkflow.worktreeSupportspecWorkflow.branchIsolation, and implements server-backed short-share URLs with client routing /s/:id, sharing helpers/tests, a SectionedBlockRenderer, CORS and package/test updates, and related docs/CLI changes.

Changes

Config Schema Migration v11

Layer / File(s) Summary
Config migration version and function
installer/steps/config_migration.py
CURRENT_CONFIG_VERSION bumped to 11; new _migration_v11 renames specWorkflow.worktreeSupport to specWorkflow.branchIsolation, preserving existing branchIsolation and defaulting legacy non-boolean values to False.
Config migration test coverage
installer/tests/unit/steps/test_config_migration.py
Unit tests updated and expanded for v11: v3/v4 assertions now verify branchIsolation and confirm worktreeSupport removal; v10 idempotency fixed; new TestMigrationV11 validates rename, missing keys, non-boolean fallback, "branchIsolation wins", and version bump/skip behavior.
Documentation for config schema and CLI update flow
docs/docusaurus/docs/features/cli.md, docs/docusaurus/docs/features/console.md, docs/docusaurus/docs/workflows/spec.md
CLI docs updated (pilot update/--skip-claude/pilot upgrade alias and update flow); console config example shows branchIsolation; spec workflow guidance condensed to a concise plan format.

Short URL Sharing System

Layer / File(s) Summary
Short-feedback sharing library and exports
docs/site/src/lib/sharing/sharing.ts, docs/site/src/lib/sharing/compress.ts, docs/site/src/lib/sharing/index.ts
Adds generateShortFeedbackUrl and ShortShareResult (10s timeout), documents short server-backed /api/share vs legacy fragment URLs, maps HTTP statuses to structured failure reasons, validates returned id, fixes decompress buffer handling, and updates barrel exports.
Short-feedback sharing test suite
docs/site/src/lib/sharing/sharing.test.ts
New tests mock compress/decompress and fetch to validate success (201), payload-too-large (413), rate-limited (429), network failure, and malformed response id handling.
Routing and shared document page integration
docs/site/src/App.tsx, docs/site/src/pages/Shared.tsx
Adds /s/:id route; Shared.tsx supports path-based /s/:id loading and legacy hash decoding, extracts short-id from pasted URLs, fetches /api/share?id=..., switches to generateShortFeedbackUrl for sending feedback with structured toasts and clipboard fallback, and updates UI/SEO/copy to mention short-lived (≤3 days) storage.
SectionedBlockRenderer for multi-level collapsible spec grouping
docs/site/src/components/feedback/SectionedBlockRenderer.tsx
New component groups blocks by H2 sections, Task N: H3 task grouping, and **Label:** field grouping; provides CollapsibleCard, default-open behavior, and auto-expansion for a selected annotation.
API infrastructure and test setup
docs/site/vercel.json, docs/site/package.json
vercel.json adds GET to CORS Access-Control-Allow-Methods for /api/(.*); docs/site/package.json adds vitest devDependency and a test script.`

Sequence Diagram

sequenceDiagram
  participant User
  participant Browser
  participant App
  participant ShareAPI as /api/share
  participant Redis

  User->>Browser: Paste /s/:id URL
  Browser->>App: Route to /s/:id
  App->>ShareAPI: GET /api/share?id=...
  ShareAPI->>Redis: Retrieve compressed payload
  Redis-->>ShareAPI: Return payload
  ShareAPI-->>App: 200 + payload
  App->>App: Decompress and render
  App-->>Browser: Display shared spec

  User->>Browser: Click Send Feedback
  Browser->>App: Trigger generateShortFeedbackUrl
  App->>App: Compress feedback payload
  App->>ShareAPI: POST /api/share
  ShareAPI->>Redis: Store payload with 3d TTL
  ShareAPI-->>App: 201 + id
  App->>App: Construct https://pilot-shell.com/s/<id>
  App-->>Browser: Copy URL, show success/fallback toast
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Suggested labels

released

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 60.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title directly reflects three major, distinct features in the changeset: Claude auto-update, spec workflow overhaul, and share URL shortener.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch dev

Tip

💬 Introducing Slack Agent: The best way for teams to turn conversations into code.

Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.

  • Generate code and open pull requests
  • Plan features and break down work
  • Investigate incidents and troubleshoot customer tickets together
  • Automate recurring tasks and respond to alerts with triggers
  • Summarize progress and report instantly

Built for teams:

  • Shared memory across your entire org—no repeating context
  • Per-thread sandboxes to safely plan and execute work
  • Governance built-in—scoped access, auditability, and budget controls

One agent for your entire SDLC. Right inside Slack.

👉 Get started


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@claude

claude Bot commented May 13, 2026

Copy link
Copy Markdown

Claude finished @maxritter's task in 2m 49s —— View job


Code Review — PR #144

  • Read repo structure/guidelines
  • Review docs/site changes (sharing, SPA routes, vercel config)
  • Review installer/config migration changes
  • Review pilot/hooks changes (stop guard, tool redirect, util)
  • Review pilot/rules + documentation changes
  • Post final review

Five features, 100 files changed, well-verified before this PR. Reviews below are scoped to non-encrypted paths only (console/**, launcher/**, docs/site/api/** skipped per repo instructions).


docs/site — share URL shortener

docs/site/src/lib/sharing/sharing.ts

generateShortFeedbackUrl is cleanly structured with specific error codes for 413/429 and a catch-all network bucket. One subtle point: the function always builds https://pilot-shell.com/s/${id} regardless of the apiBaseUrl parameter. This is intentional (the canonical share URL must be the prod domain), but it means staging/preview deployments produce links that always point to prod. For a sharing function whose consumer is always pilot-shell.com, this is the right call — just worth being explicit in the docstring.

The ID validation regex ^[A-Za-z0-9]{8}$ on the API response is a good defensive guard against malformed backend responses.

docs/site/src/pages/Shared.tsx

The dual-route handling (path-based /s/:id and hash-based legacy) is correct. One minor type-narrowing observation at line ~170:

const reason = "reason" in result ? result.reason : "network";

Since ShortShareResult is a discriminated union where ok: false always carries reason, this "reason" in result check is redundant — TypeScript already narrows it. The else branch arrived here via result.ok === false, so result.reason is directly accessible. Not a bug, just unnecessary defensive code. Fix this →

docs/site/src/components/feedback/SectionedBlockRenderer.tsx

The CollapsibleCard component has a subtlety: when expanded is passed as true (forced open because a selected annotation lives inside), clicking the toggle sets local open = false. When expanded then becomes undefined (user clicks a different annotation), isOpen = expanded ?? open = false — the section silently collapses. In practice this is an edge case (user must click the heading of a section containing the selected annotation), but it could feel like unexpected behavior. A useEffect resetting open to true when expanded becomes true would prevent the stale-false state.

docs/site/src/lib/sharing/compress.ts

The Uint8Array copy workaround for the TS 5.7+ ArrayBufferLike / SharedArrayBuffer issue is legitimate and the comment explains it well.


installer — config migration v11

installer/steps/config_migration.py_migration_v11

Clean migration. All edge cases are explicitly handled:

  • worktreeSupport absent → no-op (returns False) ✓
  • Both keys present → keep branchIsolation, remove legacy key ✓
  • Non-bool legacy value → safe default False

The docstring clearly explains the "both-keys-present" decision.

Test coverage in test_config_migration.py is thorough — 8 dedicated TestMigrationV11 tests covering the unit function and an end-to-end path. The rewrite of test_v10_idempotent is correct: using CURRENT_CONFIG_VERSION (now 11) as the input sentinel properly tests no-op behavior since a v10-stamped config with no worktreeSupport key would still advance the version sentinel.


pilot/hooks — util, tool_redirect, stop_guard

_lib/util.py — plan-parsing helpers

_extract_section_bullets uses exact heading comparison (==) for both H2 and H3 levels — the PR description calls this out explicitly and it's correctly implemented.

Minor inconsistency: the fallback branch in extract_behavior_contract (for paragraph-form **Key:** value clauses) uses a substring check:

if "Behavior Contract" in line:
    in_section = True

While _extract_section_bullets uses exact match. A section named ## Behavior Contract Notes would trigger the fallback incorrectly. The primary bullet-list path uses _extract_section_bullets (exact match), so this only affects the rare plan that has paragraph-form clauses — low risk in practice, but worth aligning for consistency. Fix this →

tool_redirect.py — context-mode tool coverage

The architecture is clean. _extract_shell_commands correctly dispatches on tool name, and the decision to skip non-shell ctx_execute languages avoids false positives on embedded Python/JS source. The documented gap ("Known gap; revisit if abuse appears") is an appropriate call.

_strip_shell_comment correctly handles single/double quote tracking and backslash escape sequences (i += 2 on \\). The test additions for comment-bypass (git push --force # --dry-run) directly cover the Codex #8 regression.

spec_stop_guard.py

The objective re-injection is a one-liner delegation to build_objective_reinjection — minimal and correct. The safety note "Treat the objective as task context, not as higher-priority instructions" is an important guardrail against prompt-injection via plan files. The test asserting runaway escalation messages must NOT contain <objective> is a good defensive test.


pilot/rules + documentation

  • task-and-workflow.md: ENV var rename PILOT_WORKTREE_ENABLEDPILOT_BRANCH_ISOLATION_ENABLED is consistent with the config key change.
  • cli-tools.md: Correctly removes pilot update from the "Do NOT exist" list and adds the proper entry with --skip-claude flag.
  • testing.md: Path update for the verify step ref (05-automated-checks.md02-automated-checks.md) reflects the step consolidation. This kind of cross-reference maintenance is easy to miss — good catch.
  • docs/docusaurus/: All three doc pages accurately reflect the new behavior.

Summary

No blocking issues. Four minor findings:

# Severity File Finding
1 Low Shared.tsx:~170 Redundant "reason" in result check — direct result.reason is cleaner
2 Low SectionedBlockRenderer.tsx Stale open=false local state when expanded transitions from true to undefined could cause unexpected collapse
3 Low _lib/util.py:extract_behavior_contract Fallback uses substring match where _extract_section_bullets uses exact match
4 Informational sharing.ts apiBaseUrl controls where the payload is POSTed, but the returned short URL always uses pilot-shell.com — intentional, but worth a docstring note

All five features are consistent with their plans, tests are comprehensive (19 endpoint tests + 5 feedback-flow tests in docs/site, 145+ new assertions in hooks tests, 164 lines of new migration tests), and the adversarial review findings from the PR description are all resolved. The implementation is ready to merge.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 7

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
docs/docusaurus/docs/workflows/spec.md (1)

78-78: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Update toggle name to match the renamed config key.

The config key was renamed from worktreeSupport to branchIsolation, but the toggle label still shows "Worktree Support". The description "Worktree and new-branch options" actually confirms the broader scope that "Branch Isolation" captures better.

📝 Proposed fix
-| **Worktree Support** | On      | Worktree and new-branch options are hidden — implementation always runs on the current branch |
+| **Branch Isolation** | On      | Worktree and new-branch options are hidden — implementation always runs on the current branch |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/docusaurus/docs/workflows/spec.md` at line 78, The toggle label
"Worktree Support" should be updated to "Branch Isolation" to match the renamed
config key (from worktreeSupport to branchIsolation); find the table row
containing the string "Worktree Support" and replace that label, and ensure the
adjacent description text ("Worktree and new-branch options are hidden —
implementation always runs on the current branch") still reads correctly or is
adjusted to reflect branchIsolation semantics so the UI label and config key
(branchIsolation) are consistent.
docs/docusaurus/docs/features/console.md (1)

149-149: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Update toggle name to match the renamed config key.

The config key was renamed from worktreeSupport to branchIsolation (line 192), but the toggle label still shows "Worktree Support". Since the PR rationale states the rename covers "new-branch and worktree creation" (broader than just worktrees), the label should be updated for consistency.

📝 Proposed fix
-| **Worktree Support** | On | Asks how to handle branching at `/spec` start | Skips the branch question — changes go on the current branch |
+| **Branch Isolation** | On | Asks how to handle branching at `/spec` start | Skips the branch question — changes go on the current branch |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/docusaurus/docs/features/console.md` at line 149, The docs table still
labels the toggle "Worktree Support" but the config key was renamed from
worktreeSupport to branchIsolation; update the table cell text from "Worktree
Support" to "Branch Isolation" (or similar wording matching branchIsolation) so
the UI label matches the new config key, and ensure any adjacent explanatory
text that references worktreeSupport is updated to branchIsolation as well.
🧹 Nitpick comments (2)
installer/tests/unit/steps/test_config_migration.py (1)

1366-1369: ⚡ Quick win

Rename the test to match the asserted version.

The method name says v10 but Line 1369 asserts 11, which makes failures/debugging misleading after quick scan.

Suggested tweak
-    def test_current_version_is_10(self) -> None:
+    def test_current_version_is_11(self) -> None:
         from installer.steps.config_migration import CURRENT_CONFIG_VERSION

         assert CURRENT_CONFIG_VERSION == 11
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@installer/tests/unit/steps/test_config_migration.py` around lines 1366 -
1369, Rename the test function test_current_version_is_10 to reflect the
asserted value by updating its name to test_current_version_is_11 so it matches
the constant check of CURRENT_CONFIG_VERSION == 11 in
installer/tests/unit/steps/test_config_migration.py; this keeps the test name
and the assertion consistent and avoids confusion when the test fails.
docs/site/src/lib/sharing/sharing.test.ts (1)

30-39: ⚡ Quick win

Assert the outbound fetch contract in the success test.

You validate the result shape, but not the request shape. Adding assertions for URL, method, headers, and body on Line 34 will catch API contract regressions early.

Suggested test addition
   it("returns short URL on 201", async () => {
@@
     const result = await generateShortFeedbackUrl(samplePayload, "");
+    expect(fetchMock).toHaveBeenCalledWith(
+      "/api/share",
+      expect.objectContaining({
+        method: "POST",
+        headers: { "Content-Type": "application/json" },
+        body: JSON.stringify({ data: expect.any(String) }),
+      }),
+    );
     expect(result).toEqual({
       ok: true,
       url: "https://pilot-shell.com/s/ABCDEFGH",
     });
   });
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/site/src/lib/sharing/sharing.test.ts` around lines 30 - 39, The test for
generateShortFeedbackUrl validates the response but not the outbound fetch call;
update the "returns short URL on 201" test to assert fetch was called with the
expected request shape by checking fetchMock was invoked once and that the
request URL, HTTP method, headers (e.g., Content-Type/authorization if
applicable), and JSON body (matching samplePayload) match the contract used by
generateShortFeedbackUrl; use fetchMock.mockResolvedValueOnce as before and
inspect fetchMock.mock.calls[0] (or equivalent helper) to compare the URL
string, method, serialized body, and headers to prevent API contract
regressions.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@docs/site/package.json`:
- Around line 92-93: The package.json lists "vite" ^5.4.19 and "vitest" ^1.6.1
which are incompatible with current Vitest v4; to fix, either leave versions
as-is (no change) or upgrade both together: update the "vite" and "vitest"
entries to matching, compatible ranges (e.g., bump "vite" to a supported major
for Vitest 4 and set "vitest" to a compatible ^4.x range), run your test suite
and update the lockfile (npm/yarn/pnpm) to ensure dependency resolution, and
adjust any breaking-change updates in test configs (references: the "vite" and
"vitest" dependency keys in package.json).

In `@docs/site/src/components/feedback/SectionedBlockRenderer.tsx`:
- Around line 60-75: The H2/H3 grouping helpers remove the heading block from
the group's blocks so annotations anchored to those heading blocks can't render;
update groupByH2 (and the analogous H3 helper at 77-97) so that when you create
a new group for a heading (e.g., in groupByH2 where you set current = { heading:
block.content, headingBlock: block, blocks: [] }), you also include the heading
block in current.blocks (e.g., push or initialize blocks with [block]) so the
heading remains renderable by BlockRenderer; keep the existing heading and
headingBlock fields and adjust the final filter only if necessary to avoid
dropping groups that contain only a heading.
- Around line 77-97: groupByTaskH3 currently ignores any blocks before the first
"### Task N:" heading; collect those initial blocks into a leading TaskGroup
instead of dropping them. Modify groupByTaskH3 to accumulate blocks into a
temporary prelude array until the first heading match, then when you create the
first TaskGroup (in the branch that sets current), if prelude is non-empty push
a TaskGroup (e.g., number: 0 or null, title: '', headingBlock: null) containing
the prelude blocks before pushing the first matched group; ensure TaskGroup
consumers can handle a null/0 headingBlock/title or adjust fields accordingly so
intro paragraphs, notes, or alternate headings are preserved.
- Around line 177-182: The effect that syncs forceOpenBlockId with
selectedAnnotationId never clears the forced block when selection is removed, so
update the useEffect that references selectedAnnotationId, annotations, ann,
setForceOpenBlockId and forceOpenBlockId to explicitly setForceOpenBlockId(null)
when selectedAnnotationId is falsy (or when the matching annotation is not
found); keep the existing behavior of setting the block id when an annotation is
found and ensure both branches (found vs not found / no selection) are handled
in the effect.

In `@docs/site/src/lib/sharing/sharing.ts`:
- Around line 80-89: The POST fetch to `${apiBaseUrl}/api/share` can hang
indefinitely; wrap the request with an AbortController and a timeout: create an
AbortController before calling fetch, pass controller.signal to fetch, schedule
a setTimeout to call controller.abort() after a chosen ms timeout, and clear the
timeout when fetch completes; update the catch block to detect an abort/timeout
(e.g., AbortError or signal.aborted) and return { ok: false, reason: "timeout" }
whereas other errors still return { ok: false, reason: "network" }; apply these
changes around the existing variables and symbols (apiBaseUrl, compressed, res)
and the current try/catch that performs fetch.

In `@docs/site/src/pages/Shared.tsx`:
- Around line 168-195: When generateShortFeedbackUrl(feedbackPayload) returns
ok, don't let navigator.clipboard.writeText rejection be handled by the outer
catch that treats the whole operation as a generation failure; instead, after
confirming result.ok and before writing to clipboard, separate the clipboard
write into its own try/catch so that on clipboard failure you still show the
successful feedback URL (result.url) to the user and a descriptive toast (e.g.,
"URL copied to clipboard failed — tap to copy" or include the URL in the
toast/modal) while logging the clipboard error; ensure the outer catch only
handles failures from generateShortFeedbackUrl and use the existing toast()
function to surface both success-with-manual-copy and true generation errors.
- Around line 36-49: The regex PILOT_SHELL_SHORT_RE used by extractFromPastedUrl
only matches URLs with an explicit http(s) scheme, so scheme-less pastes like
"pilot-shell.com/s/..." fail; update PILOT_SHELL_SHORT_RE to accept an optional
scheme (e.g. change the start to ^(?:https?:\/\/)? so it matches both
"https://host/s/<id>" and "host/s/<id>"), keep the existing host-agnostic and
id-capture group ([A-Za-z0-9]{8}), and keep the rest of extractFromPastedUrl and
parseHashFragment logic unchanged.

---

Outside diff comments:
In `@docs/docusaurus/docs/features/console.md`:
- Line 149: The docs table still labels the toggle "Worktree Support" but the
config key was renamed from worktreeSupport to branchIsolation; update the table
cell text from "Worktree Support" to "Branch Isolation" (or similar wording
matching branchIsolation) so the UI label matches the new config key, and ensure
any adjacent explanatory text that references worktreeSupport is updated to
branchIsolation as well.

In `@docs/docusaurus/docs/workflows/spec.md`:
- Line 78: The toggle label "Worktree Support" should be updated to "Branch
Isolation" to match the renamed config key (from worktreeSupport to
branchIsolation); find the table row containing the string "Worktree Support"
and replace that label, and ensure the adjacent description text ("Worktree and
new-branch options are hidden — implementation always runs on the current
branch") still reads correctly or is adjusted to reflect branchIsolation
semantics so the UI label and config key (branchIsolation) are consistent.

---

Nitpick comments:
In `@docs/site/src/lib/sharing/sharing.test.ts`:
- Around line 30-39: The test for generateShortFeedbackUrl validates the
response but not the outbound fetch call; update the "returns short URL on 201"
test to assert fetch was called with the expected request shape by checking
fetchMock was invoked once and that the request URL, HTTP method, headers (e.g.,
Content-Type/authorization if applicable), and JSON body (matching
samplePayload) match the contract used by generateShortFeedbackUrl; use
fetchMock.mockResolvedValueOnce as before and inspect fetchMock.mock.calls[0]
(or equivalent helper) to compare the URL string, method, serialized body, and
headers to prevent API contract regressions.

In `@installer/tests/unit/steps/test_config_migration.py`:
- Around line 1366-1369: Rename the test function test_current_version_is_10 to
reflect the asserted value by updating its name to test_current_version_is_11 so
it matches the constant check of CURRENT_CONFIG_VERSION == 11 in
installer/tests/unit/steps/test_config_migration.py; this keeps the test name
and the assertion consistent and avoids confusion when the test fails.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: cdafdf4d-e52c-4a7d-8939-d010b0a38254

📥 Commits

Reviewing files that changed from the base of the PR and between 4827103 and 6270aa9.

⛔ Files ignored due to path filters (170)
  • console/src/services/worker-service.ts is excluded by !console/**
  • console/src/services/worker/http/routes/SettingsRoutes.ts is excluded by !console/**
  • console/src/services/worker/http/routes/ShareRoutes.ts is excluded by !console/**
  • console/src/services/worker/http/routes/utils/shareStore.ts is excluded by !console/**
  • console/src/shared/sharing/index.ts is excluded by !console/**
  • console/src/shared/sharing/sharing.ts is excluded by !console/**
  • console/src/ui/viewer/App.tsx is excluded by !console/**
  • console/src/ui/viewer/hooks/useSettings.ts is excluded by !console/**
  • console/src/ui/viewer/hooks/useStats.ts is excluded by !console/**
  • console/src/ui/viewer/views/Requirements/index.tsx is excluded by !console/**
  • console/src/ui/viewer/views/Settings/index.tsx is excluded by !console/**
  • console/src/ui/viewer/views/Settings/sections/ConsoleSection.tsx is excluded by !console/**
  • console/src/ui/viewer/views/Settings/sections/ModelsSection.tsx is excluded by !console/**
  • console/src/ui/viewer/views/Settings/sections/SecuritySection.tsx is excluded by !console/**
  • console/src/ui/viewer/views/Settings/sections/SpecWorkflowSection.tsx is excluded by !console/**
  • console/src/ui/viewer/views/Settings/sections/_shared.tsx is excluded by !console/**
  • console/src/ui/viewer/views/Shared/FeedbackImportView.tsx is excluded by !console/**
  • console/src/ui/viewer/views/Shared/SharedSpecView.tsx is excluded by !console/**
  • console/src/ui/viewer/views/Spec/SpecSection.tsx is excluded by !console/**
  • console/src/ui/viewer/views/Spec/SpecTaskCard.tsx is excluded by !console/**
  • console/src/ui/viewer/views/Spec/annotation/PlanAnnotator.tsx is excluded by !console/**
  • console/src/ui/viewer/views/Spec/annotation/SectionedBlockRenderer.tsx is excluded by !console/**
  • console/src/ui/viewer/views/Spec/index.tsx is excluded by !console/**
  • console/src/ui/viewer/views/Spec/parsePlanContent.ts is excluded by !console/**
  • console/src/ui/viewer/views/Spec/sharing/ImportFeedbackDialog.tsx is excluded by !console/**
  • console/src/ui/viewer/views/Spec/sharing/ShareDialog.tsx is excluded by !console/**
  • console/src/ui/viewer/views/Spec/sharing/useShare.ts is excluded by !console/**
  • console/tests/hooks/useSettings.test.ts is excluded by !console/**
  • console/tests/settings-routes.test.ts is excluded by !console/**
  • console/tests/sharing/shareRoutes.test.ts is excluded by !console/**
  • console/tests/sharing/shareStore.test.ts is excluded by !console/**
  • console/tests/ui/use-stats-sse-coalescing.test.tsx is excluded by !console/**
  • docs/site/api/_lib/cors.ts is excluded by !docs/site/api/**
  • docs/site/api/share.test.ts is excluded by !docs/site/api/**
  • docs/site/api/share.ts is excluded by !docs/site/api/**
  • docs/site/package-lock.json is excluded by !**/package-lock.json
  • launcher/banner.py is excluded by !launcher/**
  • launcher/build.py is excluded by !launcher/**
  • launcher/cli.py is excluded by !launcher/**
  • launcher/config.py is excluded by !launcher/**
  • launcher/model_config.py is excluded by !launcher/**
  • launcher/tests/unit/test_banner.py is excluded by !launcher/**
  • launcher/tests/unit/test_build.py is excluded by !launcher/**
  • launcher/tests/unit/test_cli.py is excluded by !launcher/**
  • launcher/tests/unit/test_model_config.py is excluded by !launcher/**
  • launcher/tests/unit/test_updater.py is excluded by !launcher/**
  • launcher/tests/unit/test_wrapper.py is excluded by !launcher/**
  • launcher/updater.py is excluded by !launcher/**
  • launcher/wrapper.py is excluded by !launcher/**
  • pilot/hooks/_lib/util.py is excluded by !pilot/**
  • pilot/hooks/hooks.json is excluded by !pilot/**
  • pilot/hooks/spec_stop_guard.py is excluded by !pilot/**
  • pilot/hooks/spec_verify_validator.py is excluded by !pilot/**
  • pilot/hooks/tests/test_spec_stop_guard.py is excluded by !pilot/**
  • pilot/hooks/tests/test_spec_validators.py is excluded by !pilot/**
  • pilot/hooks/tests/test_spec_verify_validator.py is excluded by !pilot/**
  • pilot/hooks/tests/test_tool_redirect.py is excluded by !pilot/**
  • pilot/hooks/tests/test_util_plan_parsing.py is excluded by !pilot/**
  • pilot/hooks/tool_redirect.py is excluded by !pilot/**
  • pilot/rules/cli-tools.md is excluded by !pilot/**
  • pilot/rules/task-and-workflow.md is excluded by !pilot/**
  • pilot/rules/testing.md is excluded by !pilot/**
  • pilot/scripts/mcp-server.cjs is excluded by !pilot/**
  • pilot/scripts/worker-service.cjs is excluded by !pilot/**
  • pilot/settings.json is excluded by !pilot/**
  • pilot/skills/create-skill/steps/01-reference.md is excluded by !pilot/**
  • pilot/skills/create-skill/steps/02-understand.md is excluded by !pilot/**
  • pilot/skills/create-skill/steps/03-check.md is excluded by !pilot/**
  • pilot/skills/create-skill/steps/04-create.md is excluded by !pilot/**
  • pilot/skills/create-skill/steps/05-quality.md is excluded by !pilot/**
  • pilot/skills/create-skill/steps/06-test.md is excluded by !pilot/**
  • pilot/skills/create-skill/steps/07-anti-patterns.md is excluded by !pilot/**
  • pilot/skills/create-skill/steps/08-example.md is excluded by !pilot/**
  • pilot/skills/prd/manifest.json is excluded by !pilot/**
  • pilot/skills/prd/steps/01-understand.md is excluded by !pilot/**
  • pilot/skills/prd/steps/02-research.md is excluded by !pilot/**
  • pilot/skills/prd/steps/03-ideate.md is excluded by !pilot/**
  • pilot/skills/prd/steps/04-clarify.md is excluded by !pilot/**
  • pilot/skills/prd/steps/05-propose.md is excluded by !pilot/**
  • pilot/skills/prd/steps/06-converge.md is excluded by !pilot/**
  • pilot/skills/prd/steps/07-write-prd.md is excluded by !pilot/**
  • pilot/skills/prd/steps/08-handoff.md is excluded by !pilot/**
  • pilot/skills/prd/steps/09-anti-patterns.md is excluded by !pilot/**
  • pilot/skills/prd/steps/10-key-principles.md is excluded by !pilot/**
  • pilot/skills/setup-rules/steps/01-reference.md is excluded by !pilot/**
  • pilot/skills/setup-rules/steps/02-read.md is excluded by !pilot/**
  • pilot/skills/spec-bugfix-plan/manifest.json is excluded by !pilot/**
  • pilot/skills/spec-bugfix-plan/orchestrator.md is excluded by !pilot/**
  • pilot/skills/spec-bugfix-plan/steps/00-setup-and-red-flags.md is excluded by !pilot/**
  • pilot/skills/spec-bugfix-plan/steps/00-toggles.md is excluded by !pilot/**
  • pilot/skills/spec-bugfix-plan/steps/01-create-header.md is excluded by !pilot/**
  • pilot/skills/spec-bugfix-plan/steps/02-investigation.md is excluded by !pilot/**
  • pilot/skills/spec-bugfix-plan/steps/03-plan-fix.md is excluded by !pilot/**
  • pilot/skills/spec-bugfix-plan/steps/04-write-plan.md is excluded by !pilot/**
  • pilot/skills/spec-bugfix-plan/steps/05-annotation-check.md is excluded by !pilot/**
  • pilot/skills/spec-bugfix-plan/steps/06-approval.md is excluded by !pilot/**
  • pilot/skills/spec-bugfix-plan/steps/08-continuing.md is excluded by !pilot/**
  • pilot/skills/spec-bugfix-verify/manifest.json is excluded by !pilot/**
  • pilot/skills/spec-bugfix-verify/orchestrator.md is excluded by !pilot/**
  • pilot/skills/spec-bugfix-verify/steps/01-test-suite.md is excluded by !pilot/**
  • pilot/skills/spec-bugfix-verify/steps/01-verify-fix.md is excluded by !pilot/**
  • pilot/skills/spec-bugfix-verify/steps/02-quality-checks.md is excluded by !pilot/**
  • pilot/skills/spec-bugfix-verify/steps/03-verification-scenario.md is excluded by !pilot/**
  • pilot/skills/spec-bugfix-verify/steps/04-final-worktree-sync.md is excluded by !pilot/**
  • pilot/skills/spec-bugfix-verify/steps/05-check-feedback.md is excluded by !pilot/**
  • pilot/skills/spec-bugfix-verify/steps/06-code-review-gate.md is excluded by !pilot/**
  • pilot/skills/spec-bugfix-verify/steps/07-update-status.md is excluded by !pilot/**
  • pilot/skills/spec-implement/manifest.json is excluded by !pilot/**
  • pilot/skills/spec-implement/steps/01-read-plan.md is excluded by !pilot/**
  • pilot/skills/spec-implement/steps/01-setup.md is excluded by !pilot/**
  • pilot/skills/spec-implement/steps/02-detect-worktree.md is excluded by !pilot/**
  • pilot/skills/spec-implement/steps/02-tdd-loop.md is excluded by !pilot/**
  • pilot/skills/spec-implement/steps/03-completion.md is excluded by !pilot/**
  • pilot/skills/spec-implement/steps/03-setup-tasks.md is excluded by !pilot/**
  • pilot/skills/spec-implement/steps/05-update-plan.md is excluded by !pilot/**
  • pilot/skills/spec-implement/steps/06-completion.md is excluded by !pilot/**
  • pilot/skills/spec-implement/steps/07-migration-additions.md is excluded by !pilot/**
  • pilot/skills/spec-plan/manifest.json is excluded by !pilot/**
  • pilot/skills/spec-plan/orchestrator.md is excluded by !pilot/**
  • pilot/skills/spec-plan/steps/00-setup-and-questions.md is excluded by !pilot/**
  • pilot/skills/spec-plan/steps/00-toggles.md is excluded by !pilot/**
  • pilot/skills/spec-plan/steps/01-special-cases.md is excluded by !pilot/**
  • pilot/skills/spec-plan/steps/02-create-header.md is excluded by !pilot/**
  • pilot/skills/spec-plan/steps/02-extending-plans.md is excluded by !pilot/**
  • pilot/skills/spec-plan/steps/03-migration-tasks.md is excluded by !pilot/**
  • pilot/skills/spec-plan/steps/03-workspace-scan.md is excluded by !pilot/**
  • pilot/skills/spec-plan/steps/04-task-understanding.md is excluded by !pilot/**
  • pilot/skills/spec-plan/steps/05-exploration.md is excluded by !pilot/**
  • pilot/skills/spec-plan/steps/06-approach.md is excluded by !pilot/**
  • pilot/skills/spec-plan/steps/07-approach.md is excluded by !pilot/**
  • pilot/skills/spec-plan/steps/07-implementation-planning.md is excluded by !pilot/**
  • pilot/skills/spec-plan/steps/08-e2e-scenarios.md is excluded by !pilot/**
  • pilot/skills/spec-plan/steps/08-implementation-planning.md is excluded by !pilot/**
  • pilot/skills/spec-plan/steps/09-write-plan.md is excluded by !pilot/**
  • pilot/skills/spec-plan/steps/10-plan-verification.md is excluded by !pilot/**
  • pilot/skills/spec-plan/steps/10-write-plan.md is excluded by !pilot/**
  • pilot/skills/spec-plan/steps/11-annotation-check.md is excluded by !pilot/**
  • pilot/skills/spec-plan/steps/12-approval.md is excluded by !pilot/**
  • pilot/skills/spec-verify/manifest.json is excluded by !pilot/**
  • pilot/skills/spec-verify/orchestrator.md is excluded by !pilot/**
  • pilot/skills/spec-verify/steps/00-setup-and-phase-plan.md is excluded by !pilot/**
  • pilot/skills/spec-verify/steps/00-toggles.md is excluded by !pilot/**
  • pilot/skills/spec-verify/steps/01-launch-review.md is excluded by !pilot/**
  • pilot/skills/spec-verify/steps/01-process-overview.md is excluded by !pilot/**
  • pilot/skills/spec-verify/steps/02-automated-checks.md is excluded by !pilot/**
  • pilot/skills/spec-verify/steps/02-classify-runtime.md is excluded by !pilot/**
  • pilot/skills/spec-verify/steps/03-collect-results.md is excluded by !pilot/**
  • pilot/skills/spec-verify/steps/03-phase-a-cleanup-stale.md is excluded by !pilot/**
  • pilot/skills/spec-verify/steps/04-phase-b-build.md is excluded by !pilot/**
  • pilot/skills/spec-verify/steps/05-execution.md is excluded by !pilot/**
  • pilot/skills/spec-verify/steps/06-dod-and-gaps.md is excluded by !pilot/**
  • pilot/skills/spec-verify/steps/06-feature-parity.md is excluded by !pilot/**
  • pilot/skills/spec-verify/steps/07-e2e-and-final-regression.md is excluded by !pilot/**
  • pilot/skills/spec-verify/steps/08-reverify.md is excluded by !pilot/**
  • pilot/skills/spec-verify/steps/08-worktree-sync-and-post-merge.md is excluded by !pilot/**
  • pilot/skills/spec-verify/steps/09-check-feedback.md is excluded by !pilot/**
  • pilot/skills/spec-verify/steps/10-review-gate.md is excluded by !pilot/**
  • pilot/skills/spec-verify/steps/11-dod-audit.md is excluded by !pilot/**
  • pilot/skills/spec-verify/steps/11-update-status.md is excluded by !pilot/**
  • pilot/skills/spec-verify/steps/12-not-verified.md is excluded by !pilot/**
  • pilot/skills/spec-verify/steps/14-final-regression.md is excluded by !pilot/**
  • pilot/skills/spec-verify/steps/16-post-merge.md is excluded by !pilot/**
  • pilot/skills/spec/orchestrator.md is excluded by !pilot/**
  • pilot/skills/spec/steps/00-permission-mode.md is excluded by !pilot/**
  • pilot/skills/spec/steps/01-parse-route.md is excluded by !pilot/**
  • pilot/ui/PlanAnnotator.js is excluded by !pilot/**
  • pilot/ui/index3.js is excluded by !pilot/**
  • pilot/ui/index5.js is excluded by !pilot/**
  • pilot/ui/viewer-bundle.js is excluded by !pilot/**
  • pilot/ui/viewer.css is excluded by !pilot/**
📒 Files selected for processing (14)
  • docs/docusaurus/docs/features/cli.md
  • docs/docusaurus/docs/features/console.md
  • docs/docusaurus/docs/workflows/spec.md
  • docs/site/package.json
  • docs/site/src/App.tsx
  • docs/site/src/components/feedback/SectionedBlockRenderer.tsx
  • docs/site/src/lib/sharing/compress.ts
  • docs/site/src/lib/sharing/index.ts
  • docs/site/src/lib/sharing/sharing.test.ts
  • docs/site/src/lib/sharing/sharing.ts
  • docs/site/src/pages/Shared.tsx
  • docs/site/vercel.json
  • installer/steps/config_migration.py
  • installer/tests/unit/steps/test_config_migration.py

Comment thread docs/site/package.json
Comment thread docs/site/src/components/feedback/SectionedBlockRenderer.tsx
Comment thread docs/site/src/components/feedback/SectionedBlockRenderer.tsx
Comment thread docs/site/src/components/feedback/SectionedBlockRenderer.tsx
Comment thread docs/site/src/lib/sharing/sharing.ts
Comment thread docs/site/src/pages/Shared.tsx Outdated
Comment thread docs/site/src/pages/Shared.tsx
* sharing.ts: add 10s timeout/AbortController to share POST; distinguish timeout from network errors with new ShortShareResult reason

* Shared.tsx: separate clipboard write try/catch so a successful generation isn't lost when clipboard rejects; show URL in toast for manual copy

* Shared.tsx: scheme-less paste regex (`pilot-shell.com/s/<id>` without `https://`) now resolves correctly instead of falling through to parse-error toast

* Shared.tsx: surface new "timeout" failure with a dedicated toast

* SectionedBlockRenderer (both docs/site + console copies): include heading blocks in their groups so annotations anchored to H2/H3 headings still render and selectedAnnotationId auto-expansion can find them

* SectionedBlockRenderer: prelude TaskGroup (number=0, headingBlock=null) preserves content appearing before the first `### Task N:` heading; consumers null-check and render the prelude inline without a card

* SectionedBlockRenderer: clear forceOpenBlockId when selection is removed so old enclosing cards no longer stay permanently open
@claude

claude Bot commented May 13, 2026

Copy link
Copy Markdown

Claude finished @maxritter's task in 3m 2s —— View job


Incremental Code Review — PR #144

  • Read repo guidelines
  • Review changed files in this push (SectionedBlockRenderer.tsx, sharing.ts, Shared.tsx)
  • Post incremental review

✅ Resolved in this push

File Finding
SectionedBlockRenderer.tsx H2 heading blocks now included in section.blocks (line 69: blocks: [block]) so annotations anchored to headings are reachable
SectionedBlockRenderer.tsx Prelude blocks before the first ### Task N: heading are now collected into a leading group instead of being dropped
SectionedBlockRenderer.tsx forceOpenBlockId is now cleared when selectedAnnotationId becomes null (lines 192–194)
sharing.ts fetch now wrapped with AbortController + 10 s timeout; ShortShareResult union extended with "timeout" reason
Shared.tsx Scheme-less paste URLs now accepted (^(?:https?:\/\/)? prefix, line 37)
Shared.tsx Clipboard write failure isolated inside its own try/catch — generated URL is surfaced in toast instead of being silently lost

🆕 New issue introduced in this push

SectionedBlockRenderer.tsx — heading blocks render twice (Medium)

The fix that includes the heading block in section.blocks (and task.blocks) achieves annotation anchoring, but causes every section and task heading to appear twice in the rendered output:

  1. Card title — the CollapsibleCard receives title={section.heading} (a plain string).
  2. Card bodyrenderLeaf(section.blocks) passes all blocks to BlockRenderer, which renders heading blocks as markdown (## <content>, ### Task N: <title>). Confirmed in BlockRenderer.tsx:20: return \${"#".repeat(block.level ?? 2)} ${block.content}``.

For task sections the problem compounds: groupByTaskH3(section.blocks) sees the H2 block first; it doesn't match Task N:, so it lands in the prelude group and renders again inline above the task cards. Each task's H3 is similarly rendered both as the card title and as a block inside renderLeaf(task.blocks).

Minimal fix — strip heading blocks from the rendered lists while keeping them in section.blocks for containsBlock checks:

// In the non-task render path (line ~296):
renderLeaf(section.blocks.filter(b => b !== section.headingBlock))

// In groupByTaskH3 call (line ~240):
groupByTaskH3(section.blocks.filter(b => b !== section.headingBlock))

// In renderLeaf per task (inside CollapsibleCard for tasks):
renderLeaf(task.blocks.filter(b => b !== task.headingBlock))

containsBlock continues to use the full section.blocks / task.blocks arrays, so annotation auto-expand is unaffected. Fix this →


Still open (prior reviews)

  1. Shared.tsx:182const reason = "reason" in result ? result.reason : "network" is redundant; result.ok === false already narrows the union to guarantee result.reason (low)
  2. SectionedBlockRenderer.tsxCollapsibleCard stale open=false when user clicks a heading to collapse it, then selects a different annotation; expanded becomes undefined and the section stays collapsed (low)
  3. installer/tests/unit/steps/test_config_migration.py:1366 — method named test_current_version_is_10 asserts == 11 (nitpick)
  4. docs/docusaurus/docs/features/console.md:149 + docs/workflows/spec.md:78 — toggle label still "Worktree Support" instead of "Branch Isolation" (minor)
  5. docs/site/src/lib/sharing/sharing.test.ts:30-39 — success test validates result shape but not outbound fetch contract (nitpick)

The timeout fix and clipboard isolation are clean. The one blocking concern for this push is the heading duplication — it will visibly double-render every section and task title in the shared spec viewer.

@maxritter

Copy link
Copy Markdown
Owner Author

@coderabbitai resolve

All 6 actionable findings from the previous review are addressed in commit 446ad517:

Verification: docs/site 24/24 vitest pass, build clean, typecheck clean. Console 304/304 sharing+ui tests pass, typecheck clean.

@coderabbitai

coderabbitai Bot commented May 13, 2026

Copy link
Copy Markdown

@maxritter: Thank you for the thorough fix summary and verification results! All seven findings are confirmed addressed — the heading-block inclusion, prelude TaskGroup, forceOpenBlockId clearing, POST timeout with dedicated error path, scheme-less paste regex, and clipboard fallback toast are all solid improvements. Resolving all comments now.


If you found this review helpful, would you consider giving us a shout-out on X?

Thank you for using CodeRabbit!

✅ Actions performed

Comments resolved. Approval is disabled; enable reviews.request_changes_workflow to allow explicit top-level @coderabbitai resolve or @coderabbitai approve commands.

@maxritter maxritter merged commit 2600826 into main May 13, 2026
22 checks passed
@maxritter maxritter deleted the dev branch May 13, 2026 14:20
github-actions Bot pushed a commit that referenced this pull request May 13, 2026
# [8.9.0](v8.8.0...v8.9.0) (2026-05-13)

### Bug Fixes

* add missing UI file ([b43b142](b43b142))

### Features

* spec workflow overhaul, share spec/prd URL shortener, claude auto-update  ([#144](#144)) ([2600826](2600826))
@github-actions

Copy link
Copy Markdown
Contributor

🎉 This PR is included in version 8.9.0 🎉

The release is available on GitHub release

Your semantic-release bot 📦🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant