Skip to content

feat(console): chat surface + Paper sidebar on block contract - #99

Merged
Travis-Gilbert merged 2 commits into
mainfrom
cursor/chat-sidebar-dockview-reconcile
Jul 23, 2026
Merged

feat(console): chat surface + Paper sidebar on block contract#99
Travis-Gilbert merged 2 commits into
mainfrom
cursor/chat-sidebar-dockview-reconcile

Conversation

@Travis-Gilbert

@Travis-Gilbert Travis-Gilbert commented Jul 23, 2026

Copy link
Copy Markdown
Owner

Summary

  • Reconciles chat surface (ShaderSurface composer, multibuffer thread excerpts) and Paper sidebar anatomy onto the one-block contract tip from fix: PR #94 one-block review/merge (tracking) #98.
  • Pins dockview and records FOLLOWUP-DOCKVIEW-GROUND.md as the ground canvas upstream (replacing react-grid-layout); nested kanban stays on dnd-kit.
  • Adds material register docs/tokens and radius gate.

Test plan

Depends on / pairs with #98.

Summary by CodeRabbit

  • New Features
    • Added expandable chat and tool excerpts with timestamps, summaries, object links, and full-density jump navigation.
    • Introduced clearer empty and unavailable states with causes and optional actions.
    • Added material-based visuals, including shader-powered Composer edges, canvas backgrounds, and color-coded block icons.
    • Improved sidebar shortcuts, landmark controls, and responsive thread navigation.
  • Bug Fixes
    • Preserved local layout edits during initialization and improved document targeting.
    • Improved todo interactions and handling of unloaded content.
  • Tests
    • Improved end-to-end synchronization, deterministic resets, accessibility states, visual checks, contrast validation, and radius validation.

Copilot AI review requested due to automatic review settings July 23, 2026 18:48
@ecc-tools

ecc-tools Bot commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

ECC bundle files are already tracked in this repository. Skipping generation of another bundle PR.

@coderabbitai

coderabbitai Bot commented Jul 23, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@Travis-Gilbert, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 44 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 7a27fc4c-7191-458f-aa1d-403e86359791

📥 Commits

Reviewing files that changed from the base of the PR and between 7871d72 and 699ebcd.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (43)
  • .harness/checklists/console-chat-surface--plan-local.json
  • apps/console/AGENTS.md
  • apps/console/CLAUDE.md
  • apps/console/docs/plans/console-block-system/FOLLOWUP-DOCKVIEW-GROUND.md
  • apps/console/e2e/console-ia.spec.ts
  • apps/console/e2e/signatures.spec.ts
  • apps/console/package.json
  • apps/console/scripts/check-contrast.mjs
  • apps/console/scripts/check-radius-lint.mjs
  • apps/console/src/components/blocks/BlockCanvas.tsx
  • apps/console/src/components/blocks/kind-glyph.tsx
  • apps/console/src/components/composer/Composer.tsx
  • apps/console/src/components/composer/ComposerSheenCanvas.tsx
  • apps/console/src/components/material/EmptyRegion.tsx
  • apps/console/src/components/material/ShaderSurface.tsx
  • apps/console/src/components/shell/Sidebar.tsx
  • apps/console/src/lib/goal-stack-contract.test.ts
  • apps/console/src/lib/material/kind-hues.test.ts
  • apps/console/src/lib/material/kind-hues.ts
  • apps/console/src/lib/material/materials.ts
  • apps/console/src/lib/plan-program-shape.test.ts
  • apps/console/src/motion/motion-tokens.ts
  • apps/console/src/styles/app.css
  • apps/console/src/styles/int-ui-register-light.css
  • apps/console/src/styles/int-ui-register.css
  • apps/console/src/styles/register-bridge.css
  • apps/console/src/styles/token-manifest.json
  • apps/console/src/views/CardView.tsx
  • apps/console/src/views/CodeFileView.tsx
  • apps/console/src/views/ThreadView.tsx
  • apps/console/src/views/ViewStates.test.tsx
  • apps/console/src/views/ViewStates.tsx
  • apps/console/src/views/canvas/CanvasPaperGround.tsx
  • apps/console/src/views/thread/ObjectExcerpt.tsx
  • apps/console/src/views/thread/ThreadExcerpt.test.tsx
  • apps/console/src/views/thread/ThreadExcerpt.tsx
  • docs/plans/console-chat-surface/FOLLOWUP-FORME-DISCHARGE-TEXTURE.md
  • docs/plans/console-chat-surface/README.md
  • docs/plans/console-chat-surface/implementation-plan.md
  • docs/plans/material-register/SPEC-MATERIAL-REGISTER-1.0.md
  • docs/plans/material-register/implementation-plan.md
  • docs/plans/material-register/report.md
  • packages/theorem-acp/src/plan-program.ts
📝 Walkthrough

Walkthrough

The PR adds the console chat surface and material-register implementation, including ShaderSurface rendering, thread excerpts, empty-state causes, tier and hue tokens, contrast and radius gates, shell synchronization, deterministic E2E fixtures, and canonical plan shape identifiers.

Changes

Console chat and material system

Layer / File(s) Summary
Planning and implementation contracts
.harness/checklists/*, docs/plans/*, apps/console/AGENTS.md, apps/console/CLAUDE.md
Adds executable plans, material-register specifications, follow-up records, source ledgers, and checklist metadata for the console chat and material changes.
Material register, tokens, and gates
apps/console/src/lib/material/*, apps/console/src/styles/*, apps/console/scripts/*, apps/console/package.json, apps/console/src/components/blocks/kind-glyph.tsx
Adds material descriptors, kind-hue mapping, elevation and radius tokens, sidebar metrics, contrast validation, radius linting, and related dependencies and gate wiring.
Composer, thread, canvas, and empty states
apps/console/src/components/composer/*, apps/console/src/components/material/*, apps/console/src/views/*, apps/console/src/motion/motion-tokens.ts
Replaces the composer canvas sheen with ShaderSurface, introduces collapsible thread excerpts and object loading, updates canvas synchronization and paper ground rendering, and standardizes empty-state causes and actions.
Shell, rail, and layout state
apps/console/src/components/shell/*, apps/console/src/lib/console-host.ts
Adds mounted shell readiness markers, revises sidebar activation and styling, handles marker queries, and preserves local layout state during remote seed adoption.
E2E synchronization and fixture validation
apps/console/e2e/*
Replaces fixed waits with layout-readiness checks, adds fixture reset endpoints, updates composer and shell selectors, and revises interaction and screenshot assertions.
Canonical plan shape identifiers
packages/theorem-acp/src/plan-program.ts, apps/console/src/lib/*shape*.test.ts
Introduces canonical theorem:plan-task@1.0.0 references, parsing validation, and graph-port shape tests.

Estimated code review effort: 5 (Critical) | ~120 minutes

Possibly related PRs

Suggested reviewers: copilot

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 14.75% 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 accurately reflects the main changes to the console chat surface and Paper sidebar under the block contract.
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.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch cursor/chat-sidebar-dockview-reconcile

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.

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 7871d7294c

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +59 to +64
<ThreadExcerpt
kind="object"
excerptId={excerptId}
speaker={`object · ${kind}`}
summary={title}
defaultCollapsed

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Load object excerpts when users expand them

Every object excerpt is initially collapsed, so ThreadExcerpt does not mount this child until after its toggle is used. The only paths that set expandedOnce are the unmounted child's ref and focus handler, while the header toggle never updates it; therefore the query effect never runs and expanding any referenced object leaves it permanently at “Loading through the object seam…”.

AGENTS.md reference: apps/console/AGENTS.md:L109-L109

Useful? React with 👍 / 👎.

Comment on lines +398 to +402
const localViewOverrides = new Map(
[...this.layout.values()]
.filter((node) => node.type === 'view-instance')
.map((node) => [node.id, {
title: node.properties.title,

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Preserve only edits made while the remote layout is loading

This snapshots title and query from every local view instance after the fetch, including the ordinary seed layout or an old browser cache, and later applies every difference over the fetched remote layout. On a new device or after clearing local storage, a server-persisted reader target/title is consequently replaced by the seed values on each startup rather than being adopted; track mutations made during the request instead of treating all pre-adoption values as overrides.

AGENTS.md reference: apps/console/AGENTS.md:L132-L137

Useful? React with 👍 / 👎.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR advances the Console’s one-block contract tip by (1) reconciling the /chat surface into a multibuffer excerpt model (composer + thread excerpts + object pull-ins), and (2) landing the Material Register system (tiers, keylines, radii, kind hues, shader seam, empty-state primitives) with new/extended gates and updated fixtures.

Changes:

  • Introduces Material Register primitives and enforcement: elevation tiers, radius scale, contrast gate extensions, kind hue ramp, ShaderSurface (pinned Paper shaders), and EmptyRegion with named causes.
  • Rebuilds the chat surface to the excerpt model: ThreadExcerpt/ObjectExcerpt, jump strip, tokenized chip/composer metrics, and replaces the composer sheen canvas with a ShaderSurface “lit edge”.
  • Hardens layout/view wiring and tests: seed-layout adopt preservation, doc navigation stability, and refreshed Playwright expectations/fixture reset utilities.

Reviewed changes

Copilot reviewed 57 out of 81 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
pnpm-lock.yaml Adds pinned shader deps and dockview resolution updates.
packages/theorem-acp/src/plan-program.ts Canonicalizes plan-task ShapeId and adds a ShapeId::parse-compatible parser.
docs/plans/material-register/SPEC-MATERIAL-REGISTER-1.0.md Introduces the Material Register spec and measurable acceptance criteria.
docs/plans/material-register/report.md Status report for which Material Register deliverables shipped vs deferred.
docs/plans/material-register/implementation-plan.md Implementation checklist and verify-first findings for the material work.
docs/plans/console-chat-surface/README.md Links chat surface plan to handoff/spec inputs.
docs/plans/console-chat-surface/implementation-plan.md Detailed executable plan for chat composer + multibuffer thread implementation.
docs/plans/console-chat-surface/FOLLOWUP-FORME-DISCHARGE-TEXTURE.md Documents the deferral of non-Deterministic receipt textures until backend support.
apps/console/src/views/ViewStates.tsx Switches empty/unavailable rendering to EmptyRegion with named causes/actions.
apps/console/src/views/ViewStates.test.tsx Updates tests for new empty/unavailable semantics and action labels.
apps/console/src/views/ThreadView.tsx Replaces bubbles with excerpt primitives, adds tool/object excerpts, and jump strip.
apps/console/src/views/thread/ThreadExcerpt.tsx New collapsible, sticky-header excerpt container component.
apps/console/src/views/thread/ThreadExcerpt.test.tsx Adds unit tests for excerpt collapse/expand behavior.
apps/console/src/views/thread/ObjectExcerpt.tsx Adds object pull-in excerpt via BlockHost seam with “Open” action.
apps/console/src/views/GalleyDocView.tsx Reworks todo decoration to survive re-rendering via observer + event delegation.
apps/console/src/views/DocListView.tsx Prefers docs editor region to avoid active-surface race during navigation.
apps/console/src/views/CodeFileView.tsx Uses emptyCause="not-loaded" for unloaded files.
apps/console/src/views/CardView.tsx Uses emptyCause="not-loaded" for missing full-card object.
apps/console/src/views/canvas/CanvasView.tsx Replaces useSyncExternalStore store with effect subscription and improves empty state.
apps/console/src/views/canvas/CanvasPaperGround.tsx Re-expresses canvas ground through ShaderSurface (removes shaders-react DotGrid).
apps/console/src/styles/token-manifest.json Extends/updates manifest for new material/chat/sidebar tokens and tier mapping notes.
apps/console/src/styles/register-bridge.css Adds tier + radius + kind hue + sidebar + chat/composer/excerpt tokens and elevation styling.
apps/console/src/styles/int-ui-register.css Introduces tier tokens, maps structural surfaces onto tiers, adds radius scale + keyline tokens.
apps/console/src/styles/int-ui-register-light.css Light-theme tier + keyline token mapping updates.
apps/console/src/styles/app.css Adds responsive visibility rule for the thread jump strip.
apps/console/src/motion/motion-tokens.ts Updates motion inventory and declared paint surfaces for ShaderSurface.
apps/console/src/lib/plan-program-shape.test.ts Adds tests ensuring emitted ShapeIds are parseable and canonical.
apps/console/src/lib/material/materials.ts Introduces material vocabulary/map and reachability rules.
apps/console/src/lib/material/kind-hues.ts Adds kind hue var accessors + hue ramp constants.
apps/console/src/lib/material/kind-hues.test.ts Verifies register contains every kind hue token and matches the fixed L/C ramp.
apps/console/src/lib/goal-stack-contract.test.ts Ensures graph ports emit the canonical plan-task ShapeId.
apps/console/src/lib/console-host.ts Preserves local view-instance overrides and local-only nodes across seed-layout adoption.
apps/console/src/lib/console-host.test.ts Adds test for preserving in-flight doc navigation during seed adopt.
apps/console/src/components/shell/ViewInstanceHost.tsx Prevents “empty” state for marker panes and avoids dependency on unstable instance identity.
apps/console/src/components/shell/Sidebar.tsx Updates rail anatomy, shortcut glyphs, and activation/routing semantics.
apps/console/src/components/shell/MainToolbar.tsx Clarifies surface switching behavior (activate without routing).
apps/console/src/components/shell/IntuiShell.tsx Keeps data-shell mounted while resolving layout to stabilize activation/e2e oracles.
apps/console/src/components/material/ShaderSurface.tsx Adds repo-owned Paper shader mount with context budget, reduced-motion, and token-derived colors.
apps/console/src/components/material/EmptyRegion.tsx Adds a canonical empty-state primitive with named causes and optional resolving action.
apps/console/src/components/composer/ComposerSheenCanvas.tsx Removes legacy 2D sheen canvas implementation.
apps/console/src/components/composer/Composer.tsx Rebuilds composer chrome, metrics, and status handling; adds ShaderSurface lit edge and interrupt state.
apps/console/src/components/blocks/kind-glyph.tsx Applies kind hue to glyphs and introduces edge-marker styling.
apps/console/src/components/blocks/BlockCanvas.tsx Documents dockview follow-up for ground geometry while retaining dnd-kit for nested kanban.
apps/console/scripts/check-radius-lint.mjs Adds radius scale lint gate to block raw px radius usage outside allowed folders.
apps/console/scripts/check-contrast.mjs Extends contrast gate with rail pairs, selection two-of-four rule, and decorative keyline registry.
apps/console/package.json Pins shaders(-react) versions, adds dockview, and adds gate:radius into gates.
apps/console/e2e/stub-data-api.mjs Makes mention-candidate fixtures resettable and adds reset-domain endpoint.
apps/console/e2e/signatures.spec.ts Updates composer assertions for ShaderSurface lit edge and revised screenshot flow.
apps/console/e2e/search-field.spec.ts Adds stub reset and waits on data-layout-ready instead of fixed delays.
apps/console/e2e/filing-index.spec.ts Waits for layout readiness before navigating surfaces.
apps/console/e2e/console-ia.spec.ts Updates composer assertions for lit edge and new metric constraints.
apps/console/e2e/cards.spec.ts Adds stub reset helpers, injected-surface activation path, and more robust assertions/screenshot tolerances.
apps/console/e2e/appearance.spec.ts Adds stub reset + readiness waits and relaxes divider expectation under new one-block paint behavior.
apps/console/e2e/account.spec.ts Increases timeout robustness for GitHub login disabled text assertion.
apps/console/docs/plans/console-block-system/FOLLOWUP-DOCKVIEW-GROUND.md Records dockview adoption decision and constraints for the ground canvas follow-up.
apps/console/CLAUDE.md Updates console component map to replace sheen canvas with ShaderSurface lit edge.
apps/console/AGENTS.md Updates console component map to replace sheen canvas with ShaderSurface lit edge.
.harness/checklists/console-chat-surface--plan-local.json Adds an executable checklist projection for chat surface work when harness plan minting is unavailable.
Files not reviewed (1)
  • pnpm-lock.yaml: Generated file

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 71 to +82
const PAIRS = [
{ name: 'ink on chrome', foreground: '--ij-ink', background: '--ij-chrome', target: 4.5 },
{ name: 'info on chrome', foreground: '--ij-ink-info', background: '--ij-chrome', target: 3 },
{ name: 'gold on chrome', foreground: '--ij-gold', background: '--ij-chrome', target: 4.5 },
{ name: 'accent on chrome', foreground: '--ij-accent', background: '--ij-chrome', target: 3 },
{ name: 'ink on editor', foreground: '--ij-ink', background: '--ij-editor', target: 4.5 },
{ name: 'bright ink on accent', foreground: '--ij-ink-bright', background: '--ij-accent', target: 3 },
{ name: 'keyline on chrome', foreground: '--ij-keyline', background: '--ij-chrome', target: 1.2 },
/* HANDOFF-CONSOLE-BLOCK-SYSTEM choice 8: island surfaces vs frame floor. */
{ name: 'chrome island on frame', foreground: '--ij-chrome', background: '--ij-frame', target: 1.22 },
{ name: 'editor island on frame', foreground: '--ij-editor', background: '--ij-frame', target: 1.22 },
/* Editor is sunken (material register D1): floor is the sunken-vs-ground step, not island-on-frame. */
{ name: 'editor sunken on frame', foreground: '--ij-editor', background: '--ij-frame', target: 1.08 },
Comment on lines +287 to +303
useEffect(() => {
const read = () => {
const roots = [...document.querySelectorAll<HTMLElement>('[data-thread-excerpt]')];
setHeaders(
roots
.filter((node) => node.id)
.map((node) => ({
id: node.id,
label: node.querySelector('[data-excerpt-speaker]')?.textContent?.trim() || node.dataset.threadExcerpt || 'excerpt',
})),
);
};
read();
const observer = new MutationObserver(read);
observer.observe(document.body, { childList: true, subtree: true });
return () => observer.disconnect();
}, []);
Comment on lines +72 to +75
if (LIVE_MOUNTS.size >= SHADER_CONTEXT_BUDGET) {
setFallback(true);
return;
}
@ecc-tools

ecc-tools Bot commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

ECC bundle files are already tracked in this repository. Skipping generation of another bundle PR.

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 12073362b9

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +115 to +117
const [interruptedFlag, setInterrupted] = useState(false);
// While a run is live, interrupt state is cleared without an effect.
const interrupted = isRunning ? false : interruptedFlag;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Reset interrupted state for each new run

After a user presses Stop, interruptedFlag is never cleared. A subsequent request temporarily renders as composing only while isRunning is true, then returns to the interrupted Presence mark when that request completes, so the sole agent activity indicator falsely reports the prior cancellation for the rest of the mounted composer session. Clear this flag when a new submission starts or when the next run begins.

AGENTS.md reference: apps/console/AGENTS.md:L104-L104

Useful? React with 👍 / 👎.

u_colorStroke: nextFill,
});
});
observer.observe(document.documentElement, { attributes: true, attributeFilter: ['data-theme', 'class'] });

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Observe every appearance mutation for shader colors

Switching between IntelliJ and GitHub while staying in the same light or dark mode changes data-theme-preset, and the Navy preset also updates inline custom properties, but neither mutation is observed here. The mounted composer edge and canvas ground therefore retain the previous theme's WebGL uniforms until they are remounted, producing mismatched material after an in-app appearance change. Observe data-theme-preset and style changes, or subscribe directly to the appearance store.

AGENTS.md reference: apps/console/AGENTS.md:L36-L43

Useful? React with 👍 / 👎.

Comment on lines 412 to +415
this.replaceLayout(remote.objects);
for (const node of localOnly) {
this.layout.set(node.id, node);
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Reattach local-only nodes to their restored parents

When a view instance is created and moved into an existing editor while the layout query is in flight, that editor exists in remote.objects but the new child does not. This restores the child object only; replaceLayout has already replaced the editor's children with the stale remote relation, so the new tab is detached and disappears from the UI despite being retained in the cache. Merge local parent-child relations for local-only nodes, or replay the pending move actions after adoption.

AGENTS.md reference: apps/console/AGENTS.md:L134-L136

Useful? React with 👍 / 👎.

Comment on lines +287 to +301
useEffect(() => {
const read = () => {
const roots = [...document.querySelectorAll<HTMLElement>('[data-thread-excerpt]')];
setHeaders(
roots
.filter((node) => node.id)
.map((node) => ({
id: node.id,
label: node.querySelector('[data-excerpt-speaker]')?.textContent?.trim() || node.dataset.threadExcerpt || 'excerpt',
})),
);
};
read();
const observer = new MutationObserver(read);
observer.observe(document.body, { childList: true, subtree: true });

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Scope jump-strip discovery to its own thread surface

This collects excerpts from the entire document rather than this ThreadView. If the Chat surface's Thread companion is opened, both the full and compact views render the shared messages, so the strip receives duplicate entries and duplicate DOM ids; its duplicate React keys and fragment links then point at the first matching excerpt instead of the intended one. Query within a ref for this surface and give each view's excerpts distinct ids.

Useful? React with 👍 / 👎.

Travis-Gilbert and others added 2 commits July 23, 2026 14:59
…ract

Land chat composer ShaderSurface, multibuffer thread excerpts, and Paper
sidebar anatomy on the one-block tip. Pin dockview for the ground canvas
follow-up and keep nested kanban on dnd-kit.

Co-authored-by: Cursor <cursoragent@cursor.com>
Derive interrupt state from isRunning, defer ShaderSurface fallback updates,
and restore the canvas external-store subscription from the block-contract tip.

Co-authored-by: Cursor <cursoragent@cursor.com>
@Travis-Gilbert
Travis-Gilbert force-pushed the cursor/chat-sidebar-dockview-reconcile branch from 1207336 to 699ebcd Compare July 23, 2026 18:59
@ecc-tools

ecc-tools Bot commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

ECC bundle files are already tracked in this repository. Skipping generation of another bundle PR.

@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: 12

🧹 Nitpick comments (3)
apps/console/src/views/GalleyDocView.tsx (1)

15-15: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Alias name collides with the library's real markdownLanguage export.

markdown is aliased to markdownLanguage here, but @codemirror/lang-markdown also exports an actual markdownLanguage (a plain Language, not callable). Calling it as markdownLanguage() at Line 62 is correct today because it's really the aliased markdown() factory, but the name will mislead anyone who checks the library docs and could tempt a future edit to drop the () call.

♻️ Suggested rename
-import { markdown as markdownLanguage } from '`@codemirror/lang-markdown`';
+import { markdown as markdownExtension } from '`@codemirror/lang-markdown`';
-          markdownLanguage(),
+          markdownExtension(),

Also applies to: 62-62

🤖 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 `@apps/console/src/views/GalleyDocView.tsx` at line 15, Rename the aliased
import from `@codemirror/lang-markdown` to a name that reflects the callable
markdown factory, and update its invocation at the corresponding editor setup
call site. Preserve the existing factory call behavior and avoid using the
library’s exported markdownLanguage name for this alias.
apps/console/e2e/stub-data-api.mjs (1)

175-182: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Shallow-cloned relations could leak mutations back into the seed.

cloneMentionCandidates spreads entry.relations, which only copies the top-level keys; any array values inside are still shared with MENTION_CANDIDATES_SEED. No current handler mutates a relations array in place (delete/update reassign or only touch properties), so this isn't an active bug, but it's a trap for a future in-place mutation (e.g. .push()) silently corrupting the reset seed across test runs.

♻️ Suggested deep clone
-function cloneMentionCandidates() {
-  return MENTION_CANDIDATES_SEED.map((entry) => ({
-    ...entry,
-    properties: { ...entry.properties },
-    relations: { ...entry.relations },
-  }));
-}
+function cloneMentionCandidates() {
+  return MENTION_CANDIDATES_SEED.map((entry) => structuredClone(entry));
+}
🤖 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 `@apps/console/e2e/stub-data-api.mjs` around lines 175 - 182, Update
cloneMentionCandidates to deep-clone nested values within entry.relations,
including array values, so cloned candidates never share mutable relation data
with MENTION_CANDIDATES_SEED. Preserve the existing cloning of entry and
properties and keep the function’s returned candidate shape unchanged.
apps/console/src/components/composer/Composer.tsx (1)

132-142: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Reorder markState to drop the reset effect (and the eslint error).

Because interrupted is checked before isRunning, starting a new run while interrupted is still true renders 'interrupted' for one frame until the effect flips it, a brief wrong glyph. ESLint also flags the synchronous setState in this effect (react-hooks/set-state-in-effect). Prioritizing isRunning in the derivation and clearing interrupted on submit removes the effect and the flash.

Proposed change
-  useEffect(() => {
-    if (isRunning) setInterrupted(false);
-  }, [isRunning]);
-
   const mention = useObjectMentionAdapter(mentions, tenant);

-  const markState: MarkState = interrupted
-    ? 'interrupted'
-    : isRunning
-      ? 'composing'
-      : 'idle';
+  const markState: MarkState = isRunning
+    ? 'composing'
+    : interrupted
+      ? 'interrupted'
+      : 'idle';

Then clear on submit (Line 256):

-          onSubmit={() => setCharacterCount(0)}
+          onSubmit={() => { setCharacterCount(0); setInterrupted(false); }}
🤖 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 `@apps/console/src/components/composer/Composer.tsx` around lines 132 - 142,
Remove the useEffect that calls setInterrupted when isRunning changes, and
reorder the markState derivation so isRunning takes precedence over interrupted,
producing 'composing' during active runs. In the submit flow around the existing
submit handler, clear interrupted explicitly when a new run is submitted.

Source: Linters/SAST tools

🤖 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 @.harness/checklists/console-chat-surface--plan-local.json:
- Around line 10-16: Update the status_lead_not_done checklist to remove entries
whose corresponding work is marked done, including CH0, CH1a, CH1b, CH2, and
CH6, or explicitly label the list as historical baseline status if those entries
must remain.

In `@apps/console/package.json`:
- Around line 73-75: Update the dockview dependency entry in package.json from a
caret range to an exact pinned version, preserving the current 4.10.0 version so
it matches the repository’s pinned dependency style and ensures reproducible
builds.

In `@apps/console/scripts/check-contrast.mjs`:
- Around line 227-230: Replace the tautological DECORATIVE_KEYLINES membership
check with a lookup against the register declarations, resolving
--ij-keyline-decorative through the same declaration-based mechanism used by the
PAIRS and RAIL_PAIRS loops. Keep the existing error message and exit behavior
when the token is absent, and avoid using the locally defined
DECORATIVE_KEYLINES set for this validation.

In `@apps/console/scripts/check-radius-lint.mjs`:
- Around line 29-30: Update RAW_RADIUS in check-radius-lint to match React
camelCase borderRadius declarations and Tailwind arbitrary rounded-[Npx]
classes, while preserving detection of existing CSS and Tailwind forms. Ensure
SCALE_TOKEN exemptions remain unchanged.

In `@apps/console/src/components/shell/Sidebar.tsx`:
- Around line 557-578: Update the landmark controls wrapper in the landmark
rendering flow of Sidebar so its opacity becomes visible when either the parent
group is hovered or the Pin/Remove buttons receive keyboard focus. Preserve the
existing collapsed-state condition and hover transition behavior while adding an
appropriate focus-within visibility utility.

In `@apps/console/src/styles/app.css`:
- Around line 247-255: Restore the base html, body height rule in app.css before
the existing .thread-jump-strip styles, setting both elements to 100% height.
Leave the thread-jump-strip responsive display rules unchanged.

In `@apps/console/src/styles/int-ui-register-light.css`:
- Around line 47-53: Correct the lightness annotation in the tier comment above
--ij-tier-sunken and --ij-tier-ground so it reflects the existing hex values:
sunken is darker than ground, with sunken approximately ~88 and ground
approximately ~92. Leave the tier variable values and their ordering unchanged.

In `@apps/console/src/styles/int-ui-register.css`:
- Around line 47-53: Update the seam and keyline token definitions in the CSS
variable block: derive --ij-seam and --ij-seam-raised from darker tier values so
each is darker than its corresponding frame, editor, raised, and floating
surfaces. Keep --ij-keyline aligned with the corrected raised seam and preserve
the existing focus and decorative keyline behavior.

In `@apps/console/src/styles/register-bridge.css`:
- Around line 170-190: Update the semantic elevation selectors in the register
bridge so every host—ground, raised, floating, sunken, and scrim—receives its
corresponding tier fill via background. Preserve the existing border, radius,
corner-shape, and shadow declarations while adding the missing fills for ground,
raised, and floating using the established tier-fill variables.

In `@apps/console/src/views/canvas/CanvasView.tsx`:
- Around line 26-47: Update queryCanvas and the CanvasView initialization/effect
flow to resolve Promise results from host.query before storing or rendering the
ObjectSet, rather than permanently using the empty snapshot. Preserve
synchronous query handling and ensure async results update state when resolved;
avoid re-querying in createCanvasStore.subscribe because the live subscription
already manages updates.

In `@apps/console/src/views/GalleyDocView.tsx`:
- Around line 89-185: Update the useEffect dependency array in GalleyDocView so
it includes the document title value used to compute docTitle, such as
doc?.properties.title, alongside mode, text, and doc?.id. Preserve the existing
openFor behavior while ensuring title changes recreate the closure and refresh
the hand-off chip label.

In `@apps/console/src/views/ThreadView.tsx`:
- Line 9: Replace the direct theoremUri import and usage in ThreadView with the
designated console address API, reusing the existing address parser to derive
the needed theorem address. Remove the block-view addressing import while
preserving the current behavior at the call site.

---

Nitpick comments:
In `@apps/console/e2e/stub-data-api.mjs`:
- Around line 175-182: Update cloneMentionCandidates to deep-clone nested values
within entry.relations, including array values, so cloned candidates never share
mutable relation data with MENTION_CANDIDATES_SEED. Preserve the existing
cloning of entry and properties and keep the function’s returned candidate shape
unchanged.

In `@apps/console/src/components/composer/Composer.tsx`:
- Around line 132-142: Remove the useEffect that calls setInterrupted when
isRunning changes, and reorder the markState derivation so isRunning takes
precedence over interrupted, producing 'composing' during active runs. In the
submit flow around the existing submit handler, clear interrupted explicitly
when a new run is submitted.

In `@apps/console/src/views/GalleyDocView.tsx`:
- Line 15: Rename the aliased import from `@codemirror/lang-markdown` to a name
that reflects the callable markdown factory, and update its invocation at the
corresponding editor setup call site. Preserve the existing factory call
behavior and avoid using the library’s exported markdownLanguage name for this
alias.
🪄 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: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 1043ca8b-bde0-4c0f-afcc-2669ab829d38

📥 Commits

Reviewing files that changed from the base of the PR and between 581d115 and 7871d72.

⛔ Files ignored due to path filters (24)
  • apps/console/e2e/appearance.spec.ts-snapshots/workspace-1280-light-linux.png is excluded by !**/*.png
  • apps/console/e2e/appearance.spec.ts-snapshots/workspace-1440-light-linux.png is excluded by !**/*.png
  • apps/console/e2e/cards.spec.ts-snapshots/action-sheet-linux.png is excluded by !**/*.png
  • apps/console/e2e/cards.spec.ts-snapshots/card-compact-inspector-linux.png is excluded by !**/*.png
  • apps/console/e2e/cards.spec.ts-snapshots/cards-grid-linux.png is excluded by !**/*.png
  • apps/console/e2e/console-ia.spec.ts-snapshots/chat-empty-linux.png is excluded by !**/*.png
  • apps/console/e2e/console-ia.spec.ts-snapshots/chat-plan-linux.png is excluded by !**/*.png
  • apps/console/e2e/console-ia.spec.ts-snapshots/chat-streaming-linux.png is excluded by !**/*.png
  • apps/console/e2e/console-ia.spec.ts-snapshots/context-graph-linux.png is excluded by !**/*.png
  • apps/console/e2e/console-ia.spec.ts-snapshots/files-projection-linux.png is excluded by !**/*.png
  • apps/console/e2e/console-ia.spec.ts-snapshots/stripe-groups-linux.png is excluded by !**/*.png
  • apps/console/e2e/hunk-review.spec.ts-snapshots/hunk-review-1440-dark-linux.png is excluded by !**/*.png
  • apps/console/e2e/proactivity.spec.ts-snapshots/proactivity-cards-1440-dark-linux.png is excluded by !**/*.png
  • apps/console/e2e/proactivity.spec.ts-snapshots/proactivity-graph-1440-dark-linux.png is excluded by !**/*.png
  • apps/console/e2e/search-field.spec.ts-snapshots/search-panel-expanded-linux.png is excluded by !**/*.png
  • apps/console/e2e/signatures.spec.ts-snapshots/composer-sheen-idle-dark-linux.png is excluded by !**/*.png
  • apps/console/e2e/signatures.spec.ts-snapshots/composer-sheen-idle-light-linux.png is excluded by !**/*.png
  • apps/console/e2e/signatures.spec.ts-snapshots/composer-sheen-streaming-dark-linux.png is excluded by !**/*.png
  • apps/console/e2e/signatures.spec.ts-snapshots/composer-sheen-streaming-light-linux.png is excluded by !**/*.png
  • apps/console/e2e/signatures.spec.ts-snapshots/workspace-1280-dark-linux.png is excluded by !**/*.png
  • apps/console/e2e/signatures.spec.ts-snapshots/workspace-1440-dark-linux.png is excluded by !**/*.png
  • apps/console/e2e/workspace-goal-stack.spec.ts-snapshots/goal-stack-v2-1440-dark-linux.png is excluded by !**/*.png
  • apps/console/e2e/workspace-goal-stack.spec.ts-snapshots/workspace-substrate-v2-1440-dark-linux.png is excluded by !**/*.png
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (57)
  • .harness/checklists/console-chat-surface--plan-local.json
  • apps/console/AGENTS.md
  • apps/console/CLAUDE.md
  • apps/console/docs/plans/console-block-system/FOLLOWUP-DOCKVIEW-GROUND.md
  • apps/console/e2e/account.spec.ts
  • apps/console/e2e/appearance.spec.ts
  • apps/console/e2e/cards.spec.ts
  • apps/console/e2e/console-ia.spec.ts
  • apps/console/e2e/filing-index.spec.ts
  • apps/console/e2e/search-field.spec.ts
  • apps/console/e2e/signatures.spec.ts
  • apps/console/e2e/stub-data-api.mjs
  • apps/console/package.json
  • apps/console/scripts/check-contrast.mjs
  • apps/console/scripts/check-radius-lint.mjs
  • apps/console/src/components/blocks/BlockCanvas.tsx
  • apps/console/src/components/blocks/kind-glyph.tsx
  • apps/console/src/components/composer/Composer.tsx
  • apps/console/src/components/composer/ComposerSheenCanvas.tsx
  • apps/console/src/components/material/EmptyRegion.tsx
  • apps/console/src/components/material/ShaderSurface.tsx
  • apps/console/src/components/shell/IntuiShell.tsx
  • apps/console/src/components/shell/MainToolbar.tsx
  • apps/console/src/components/shell/Sidebar.tsx
  • apps/console/src/components/shell/ViewInstanceHost.tsx
  • apps/console/src/lib/console-host.test.ts
  • apps/console/src/lib/console-host.ts
  • apps/console/src/lib/goal-stack-contract.test.ts
  • apps/console/src/lib/material/kind-hues.test.ts
  • apps/console/src/lib/material/kind-hues.ts
  • apps/console/src/lib/material/materials.ts
  • apps/console/src/lib/plan-program-shape.test.ts
  • apps/console/src/motion/motion-tokens.ts
  • apps/console/src/styles/app.css
  • apps/console/src/styles/int-ui-register-light.css
  • apps/console/src/styles/int-ui-register.css
  • apps/console/src/styles/register-bridge.css
  • apps/console/src/styles/token-manifest.json
  • apps/console/src/views/CardView.tsx
  • apps/console/src/views/CodeFileView.tsx
  • apps/console/src/views/DocListView.tsx
  • apps/console/src/views/GalleyDocView.tsx
  • apps/console/src/views/ThreadView.tsx
  • apps/console/src/views/ViewStates.test.tsx
  • apps/console/src/views/ViewStates.tsx
  • apps/console/src/views/canvas/CanvasPaperGround.tsx
  • apps/console/src/views/canvas/CanvasView.tsx
  • apps/console/src/views/thread/ObjectExcerpt.tsx
  • apps/console/src/views/thread/ThreadExcerpt.test.tsx
  • apps/console/src/views/thread/ThreadExcerpt.tsx
  • docs/plans/console-chat-surface/FOLLOWUP-FORME-DISCHARGE-TEXTURE.md
  • docs/plans/console-chat-surface/README.md
  • docs/plans/console-chat-surface/implementation-plan.md
  • docs/plans/material-register/SPEC-MATERIAL-REGISTER-1.0.md
  • docs/plans/material-register/implementation-plan.md
  • docs/plans/material-register/report.md
  • packages/theorem-acp/src/plan-program.ts
💤 Files with no reviewable changes (1)
  • apps/console/src/components/composer/ComposerSheenCanvas.tsx

@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.

Caution

Inline review comments failed to post. This is likely due to GitHub's internal server error or limits when posting large numbers of comments. If you are seeing this consistently it is likely a permissions issue. Please check "Moderation" -> "Code review limits" under your organization settings.

Actionable comments posted: 12

🧹 Nitpick comments (3)
apps/console/src/views/GalleyDocView.tsx (1)

15-15: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Alias name collides with the library's real markdownLanguage export.

markdown is aliased to markdownLanguage here, but @codemirror/lang-markdown also exports an actual markdownLanguage (a plain Language, not callable). Calling it as markdownLanguage() at Line 62 is correct today because it's really the aliased markdown() factory, but the name will mislead anyone who checks the library docs and could tempt a future edit to drop the () call.

♻️ Suggested rename
-import { markdown as markdownLanguage } from '`@codemirror/lang-markdown`';
+import { markdown as markdownExtension } from '`@codemirror/lang-markdown`';
-          markdownLanguage(),
+          markdownExtension(),

Also applies to: 62-62

🤖 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 `@apps/console/src/views/GalleyDocView.tsx` at line 15, Rename the aliased
import from `@codemirror/lang-markdown` to a name that reflects the callable
markdown factory, and update its invocation at the corresponding editor setup
call site. Preserve the existing factory call behavior and avoid using the
library’s exported markdownLanguage name for this alias.
apps/console/e2e/stub-data-api.mjs (1)

175-182: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Shallow-cloned relations could leak mutations back into the seed.

cloneMentionCandidates spreads entry.relations, which only copies the top-level keys; any array values inside are still shared with MENTION_CANDIDATES_SEED. No current handler mutates a relations array in place (delete/update reassign or only touch properties), so this isn't an active bug, but it's a trap for a future in-place mutation (e.g. .push()) silently corrupting the reset seed across test runs.

♻️ Suggested deep clone
-function cloneMentionCandidates() {
-  return MENTION_CANDIDATES_SEED.map((entry) => ({
-    ...entry,
-    properties: { ...entry.properties },
-    relations: { ...entry.relations },
-  }));
-}
+function cloneMentionCandidates() {
+  return MENTION_CANDIDATES_SEED.map((entry) => structuredClone(entry));
+}
🤖 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 `@apps/console/e2e/stub-data-api.mjs` around lines 175 - 182, Update
cloneMentionCandidates to deep-clone nested values within entry.relations,
including array values, so cloned candidates never share mutable relation data
with MENTION_CANDIDATES_SEED. Preserve the existing cloning of entry and
properties and keep the function’s returned candidate shape unchanged.
apps/console/src/components/composer/Composer.tsx (1)

132-142: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Reorder markState to drop the reset effect (and the eslint error).

Because interrupted is checked before isRunning, starting a new run while interrupted is still true renders 'interrupted' for one frame until the effect flips it, a brief wrong glyph. ESLint also flags the synchronous setState in this effect (react-hooks/set-state-in-effect). Prioritizing isRunning in the derivation and clearing interrupted on submit removes the effect and the flash.

Proposed change
-  useEffect(() => {
-    if (isRunning) setInterrupted(false);
-  }, [isRunning]);
-
   const mention = useObjectMentionAdapter(mentions, tenant);

-  const markState: MarkState = interrupted
-    ? 'interrupted'
-    : isRunning
-      ? 'composing'
-      : 'idle';
+  const markState: MarkState = isRunning
+    ? 'composing'
+    : interrupted
+      ? 'interrupted'
+      : 'idle';

Then clear on submit (Line 256):

-          onSubmit={() => setCharacterCount(0)}
+          onSubmit={() => { setCharacterCount(0); setInterrupted(false); }}
🤖 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 `@apps/console/src/components/composer/Composer.tsx` around lines 132 - 142,
Remove the useEffect that calls setInterrupted when isRunning changes, and
reorder the markState derivation so isRunning takes precedence over interrupted,
producing 'composing' during active runs. In the submit flow around the existing
submit handler, clear interrupted explicitly when a new run is submitted.

Source: Linters/SAST tools

🤖 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 @.harness/checklists/console-chat-surface--plan-local.json:
- Around line 10-16: Update the status_lead_not_done checklist to remove entries
whose corresponding work is marked done, including CH0, CH1a, CH1b, CH2, and
CH6, or explicitly label the list as historical baseline status if those entries
must remain.

In `@apps/console/package.json`:
- Around line 73-75: Update the dockview dependency entry in package.json from a
caret range to an exact pinned version, preserving the current 4.10.0 version so
it matches the repository’s pinned dependency style and ensures reproducible
builds.

In `@apps/console/scripts/check-contrast.mjs`:
- Around line 227-230: Replace the tautological DECORATIVE_KEYLINES membership
check with a lookup against the register declarations, resolving
--ij-keyline-decorative through the same declaration-based mechanism used by the
PAIRS and RAIL_PAIRS loops. Keep the existing error message and exit behavior
when the token is absent, and avoid using the locally defined
DECORATIVE_KEYLINES set for this validation.

In `@apps/console/scripts/check-radius-lint.mjs`:
- Around line 29-30: Update RAW_RADIUS in check-radius-lint to match React
camelCase borderRadius declarations and Tailwind arbitrary rounded-[Npx]
classes, while preserving detection of existing CSS and Tailwind forms. Ensure
SCALE_TOKEN exemptions remain unchanged.

In `@apps/console/src/components/shell/Sidebar.tsx`:
- Around line 557-578: Update the landmark controls wrapper in the landmark
rendering flow of Sidebar so its opacity becomes visible when either the parent
group is hovered or the Pin/Remove buttons receive keyboard focus. Preserve the
existing collapsed-state condition and hover transition behavior while adding an
appropriate focus-within visibility utility.

In `@apps/console/src/styles/app.css`:
- Around line 247-255: Restore the base html, body height rule in app.css before
the existing .thread-jump-strip styles, setting both elements to 100% height.
Leave the thread-jump-strip responsive display rules unchanged.

In `@apps/console/src/styles/int-ui-register-light.css`:
- Around line 47-53: Correct the lightness annotation in the tier comment above
--ij-tier-sunken and --ij-tier-ground so it reflects the existing hex values:
sunken is darker than ground, with sunken approximately ~88 and ground
approximately ~92. Leave the tier variable values and their ordering unchanged.

In `@apps/console/src/styles/int-ui-register.css`:
- Around line 47-53: Update the seam and keyline token definitions in the CSS
variable block: derive --ij-seam and --ij-seam-raised from darker tier values so
each is darker than its corresponding frame, editor, raised, and floating
surfaces. Keep --ij-keyline aligned with the corrected raised seam and preserve
the existing focus and decorative keyline behavior.

In `@apps/console/src/styles/register-bridge.css`:
- Around line 170-190: Update the semantic elevation selectors in the register
bridge so every host—ground, raised, floating, sunken, and scrim—receives its
corresponding tier fill via background. Preserve the existing border, radius,
corner-shape, and shadow declarations while adding the missing fills for ground,
raised, and floating using the established tier-fill variables.

In `@apps/console/src/views/canvas/CanvasView.tsx`:
- Around line 26-47: Update queryCanvas and the CanvasView initialization/effect
flow to resolve Promise results from host.query before storing or rendering the
ObjectSet, rather than permanently using the empty snapshot. Preserve
synchronous query handling and ensure async results update state when resolved;
avoid re-querying in createCanvasStore.subscribe because the live subscription
already manages updates.

In `@apps/console/src/views/GalleyDocView.tsx`:
- Around line 89-185: Update the useEffect dependency array in GalleyDocView so
it includes the document title value used to compute docTitle, such as
doc?.properties.title, alongside mode, text, and doc?.id. Preserve the existing
openFor behavior while ensuring title changes recreate the closure and refresh
the hand-off chip label.

In `@apps/console/src/views/ThreadView.tsx`:
- Line 9: Replace the direct theoremUri import and usage in ThreadView with the
designated console address API, reusing the existing address parser to derive
the needed theorem address. Remove the block-view addressing import while
preserving the current behavior at the call site.

---

Nitpick comments:
In `@apps/console/e2e/stub-data-api.mjs`:
- Around line 175-182: Update cloneMentionCandidates to deep-clone nested values
within entry.relations, including array values, so cloned candidates never share
mutable relation data with MENTION_CANDIDATES_SEED. Preserve the existing
cloning of entry and properties and keep the function’s returned candidate shape
unchanged.

In `@apps/console/src/components/composer/Composer.tsx`:
- Around line 132-142: Remove the useEffect that calls setInterrupted when
isRunning changes, and reorder the markState derivation so isRunning takes
precedence over interrupted, producing 'composing' during active runs. In the
submit flow around the existing submit handler, clear interrupted explicitly
when a new run is submitted.

In `@apps/console/src/views/GalleyDocView.tsx`:
- Line 15: Rename the aliased import from `@codemirror/lang-markdown` to a name
that reflects the callable markdown factory, and update its invocation at the
corresponding editor setup call site. Preserve the existing factory call
behavior and avoid using the library’s exported markdownLanguage name for this
alias.
🪄 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: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 1043ca8b-bde0-4c0f-afcc-2669ab829d38

📥 Commits

Reviewing files that changed from the base of the PR and between 581d115 and 7871d72.

⛔ Files ignored due to path filters (24)
  • apps/console/e2e/appearance.spec.ts-snapshots/workspace-1280-light-linux.png is excluded by !**/*.png
  • apps/console/e2e/appearance.spec.ts-snapshots/workspace-1440-light-linux.png is excluded by !**/*.png
  • apps/console/e2e/cards.spec.ts-snapshots/action-sheet-linux.png is excluded by !**/*.png
  • apps/console/e2e/cards.spec.ts-snapshots/card-compact-inspector-linux.png is excluded by !**/*.png
  • apps/console/e2e/cards.spec.ts-snapshots/cards-grid-linux.png is excluded by !**/*.png
  • apps/console/e2e/console-ia.spec.ts-snapshots/chat-empty-linux.png is excluded by !**/*.png
  • apps/console/e2e/console-ia.spec.ts-snapshots/chat-plan-linux.png is excluded by !**/*.png
  • apps/console/e2e/console-ia.spec.ts-snapshots/chat-streaming-linux.png is excluded by !**/*.png
  • apps/console/e2e/console-ia.spec.ts-snapshots/context-graph-linux.png is excluded by !**/*.png
  • apps/console/e2e/console-ia.spec.ts-snapshots/files-projection-linux.png is excluded by !**/*.png
  • apps/console/e2e/console-ia.spec.ts-snapshots/stripe-groups-linux.png is excluded by !**/*.png
  • apps/console/e2e/hunk-review.spec.ts-snapshots/hunk-review-1440-dark-linux.png is excluded by !**/*.png
  • apps/console/e2e/proactivity.spec.ts-snapshots/proactivity-cards-1440-dark-linux.png is excluded by !**/*.png
  • apps/console/e2e/proactivity.spec.ts-snapshots/proactivity-graph-1440-dark-linux.png is excluded by !**/*.png
  • apps/console/e2e/search-field.spec.ts-snapshots/search-panel-expanded-linux.png is excluded by !**/*.png
  • apps/console/e2e/signatures.spec.ts-snapshots/composer-sheen-idle-dark-linux.png is excluded by !**/*.png
  • apps/console/e2e/signatures.spec.ts-snapshots/composer-sheen-idle-light-linux.png is excluded by !**/*.png
  • apps/console/e2e/signatures.spec.ts-snapshots/composer-sheen-streaming-dark-linux.png is excluded by !**/*.png
  • apps/console/e2e/signatures.spec.ts-snapshots/composer-sheen-streaming-light-linux.png is excluded by !**/*.png
  • apps/console/e2e/signatures.spec.ts-snapshots/workspace-1280-dark-linux.png is excluded by !**/*.png
  • apps/console/e2e/signatures.spec.ts-snapshots/workspace-1440-dark-linux.png is excluded by !**/*.png
  • apps/console/e2e/workspace-goal-stack.spec.ts-snapshots/goal-stack-v2-1440-dark-linux.png is excluded by !**/*.png
  • apps/console/e2e/workspace-goal-stack.spec.ts-snapshots/workspace-substrate-v2-1440-dark-linux.png is excluded by !**/*.png
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (57)
  • .harness/checklists/console-chat-surface--plan-local.json
  • apps/console/AGENTS.md
  • apps/console/CLAUDE.md
  • apps/console/docs/plans/console-block-system/FOLLOWUP-DOCKVIEW-GROUND.md
  • apps/console/e2e/account.spec.ts
  • apps/console/e2e/appearance.spec.ts
  • apps/console/e2e/cards.spec.ts
  • apps/console/e2e/console-ia.spec.ts
  • apps/console/e2e/filing-index.spec.ts
  • apps/console/e2e/search-field.spec.ts
  • apps/console/e2e/signatures.spec.ts
  • apps/console/e2e/stub-data-api.mjs
  • apps/console/package.json
  • apps/console/scripts/check-contrast.mjs
  • apps/console/scripts/check-radius-lint.mjs
  • apps/console/src/components/blocks/BlockCanvas.tsx
  • apps/console/src/components/blocks/kind-glyph.tsx
  • apps/console/src/components/composer/Composer.tsx
  • apps/console/src/components/composer/ComposerSheenCanvas.tsx
  • apps/console/src/components/material/EmptyRegion.tsx
  • apps/console/src/components/material/ShaderSurface.tsx
  • apps/console/src/components/shell/IntuiShell.tsx
  • apps/console/src/components/shell/MainToolbar.tsx
  • apps/console/src/components/shell/Sidebar.tsx
  • apps/console/src/components/shell/ViewInstanceHost.tsx
  • apps/console/src/lib/console-host.test.ts
  • apps/console/src/lib/console-host.ts
  • apps/console/src/lib/goal-stack-contract.test.ts
  • apps/console/src/lib/material/kind-hues.test.ts
  • apps/console/src/lib/material/kind-hues.ts
  • apps/console/src/lib/material/materials.ts
  • apps/console/src/lib/plan-program-shape.test.ts
  • apps/console/src/motion/motion-tokens.ts
  • apps/console/src/styles/app.css
  • apps/console/src/styles/int-ui-register-light.css
  • apps/console/src/styles/int-ui-register.css
  • apps/console/src/styles/register-bridge.css
  • apps/console/src/styles/token-manifest.json
  • apps/console/src/views/CardView.tsx
  • apps/console/src/views/CodeFileView.tsx
  • apps/console/src/views/DocListView.tsx
  • apps/console/src/views/GalleyDocView.tsx
  • apps/console/src/views/ThreadView.tsx
  • apps/console/src/views/ViewStates.test.tsx
  • apps/console/src/views/ViewStates.tsx
  • apps/console/src/views/canvas/CanvasPaperGround.tsx
  • apps/console/src/views/canvas/CanvasView.tsx
  • apps/console/src/views/thread/ObjectExcerpt.tsx
  • apps/console/src/views/thread/ThreadExcerpt.test.tsx
  • apps/console/src/views/thread/ThreadExcerpt.tsx
  • docs/plans/console-chat-surface/FOLLOWUP-FORME-DISCHARGE-TEXTURE.md
  • docs/plans/console-chat-surface/README.md
  • docs/plans/console-chat-surface/implementation-plan.md
  • docs/plans/material-register/SPEC-MATERIAL-REGISTER-1.0.md
  • docs/plans/material-register/implementation-plan.md
  • docs/plans/material-register/report.md
  • packages/theorem-acp/src/plan-program.ts
💤 Files with no reviewable changes (1)
  • apps/console/src/components/composer/ComposerSheenCanvas.tsx
🛑 Comments failed to post (12)
.harness/checklists/console-chat-surface--plan-local.json (1)

10-16: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Keep the checklist status fields consistent.

status_lead_not_done still lists CH0, CH1a, CH1b, CH2, and CH6 work even though their corresponding items are marked done. Remove completed entries or label this as historical baseline status.

🤖 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 @.harness/checklists/console-chat-surface--plan-local.json around lines 10 -
16, Update the status_lead_not_done checklist to remove entries whose
corresponding work is marked done, including CH0, CH1a, CH1b, CH2, and CH6, or
explicitly label the list as historical baseline status if those entries must
remain.
apps/console/package.json (1)

73-75: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

dockview uses a caret range while the PR claims it is pinned.

Sibling deps here are exact-pinned (zustand 5.0.14, @paper-design/shaders 0.0.77), and the PR objective says it "pins dockview". ^4.10.0 still allows minor/patch drift. Pin it to a single version for reproducible builds.

Proposed pin
-    "dockview": "^4.10.0"
+    "dockview": "4.10.0"
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

    "zustand": "5.0.14",
    "`@paper-design/shaders`": "0.0.77",
    "dockview": "4.10.0"
🤖 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 `@apps/console/package.json` around lines 73 - 75, Update the dockview
dependency entry in package.json from a caret range to an exact pinned version,
preserving the current 4.10.0 version so it matches the repository’s pinned
dependency style and ensures reproducible builds.
apps/console/scripts/check-contrast.mjs (1)

227-230: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Decorative-keyline gate is tautological.

DECORATIVE_KEYLINES is a local constant defined with '--ij-keyline-decorative' (Lines 99-101), so DECORATIVE_KEYLINES.has('--ij-keyline-decorative') is always true and can never catch a register that fails to define the token. To make this a real registry check, resolve the token from the register declarations (as the PAIRS/RAIL_PAIRS loops do) instead of probing an in-file set.

🤖 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 `@apps/console/scripts/check-contrast.mjs` around lines 227 - 230, Replace the
tautological DECORATIVE_KEYLINES membership check with a lookup against the
register declarations, resolving --ij-keyline-decorative through the same
declaration-based mechanism used by the PAIRS and RAIL_PAIRS loops. Keep the
existing error message and exit behavior when the token is absent, and avoid
using the locally defined DECORATIVE_KEYLINES set for this validation.
apps/console/scripts/check-radius-lint.mjs (1)

29-30: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Find inline camelCase borderRadius with raw px in components (would evade current RAW_RADIUS).
rg -nP --type=ts --type=tsx -g '!apps/console/src/styles/**' -g '!apps/console/src/motion/**' \
  "borderRadius\s*:\s*['\"]?\d+(\.\d+)?px" apps/console/src || echo "none found"
# Find Tailwind arbitrary radius classes.
rg -nP --type=ts --type=tsx "rounded-\[\d+(\.\d+)?px\]" apps/console/src || echo "none found"

Repository: Travis-Gilbert/CommonPlace

Length of output: 242


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== file excerpt =="
sed -n '1,120p' apps/console/scripts/check-radius-lint.mjs

echo
echo "== repository files mentioning check-radius-lint =="
rg -n "check-radius-lint|radius|border-radius|borderRadius|rounded-" apps/console -g '!node_modules' -g '!dist' -g '!build' | head -200 || true

Repository: Travis-Gilbert/CommonPlace

Length of output: 44552


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== pattern coverage probe =="
node - <<'JS'
const p = /(?:border-radius|rounded(?:-[a-z]+)?)\s*[:=]\s*[^;\n]*\b\d+(?:\.\d+)?px\b/;
const testCases = [
  'border-radius: 99px;',
  'borderRadius: 8px;',
  "borderRadius: '8px'",
  'borderRadius: 4.5px;',
  'rounded-[12px]',
  'rounded-[8px] bg-red',
  'rounded-ij-arc',
  'var(--ij-radius-md)',
  'var(--ij-radius-xs) px',
  'border-radius: var(--ij-radius-md);',
];
for (const s of testCases) {
  console.log(`${p.test(s) ? 'MATCH   ' : 'MISS    '}${s}`);
}
JS

echo
echo "== all non-exempt raw radius px candidates in apps/console/src =="
python3 - <<'PY'
import os, re
IGNORE = {'src/styles', 'src/motion'}
root = 'apps/console/src'
re_plain = re.compile(r'\bborder-radius\s*:\s*[^;\n]*\b\d+(?:\.\d+)?px\b')
re_camel = re.compile(r'borderRadius\s*:\s*[^;\n]*\b\d+(?:\.\d+)?px\b')
re_arb = re.compile(r'rounded-\[\d+(?:\.\d+)?px\]')
re_rounded = re.compile(r'\b(?:border-radius|rounded(?:-[a-z]+)?)\s*[:=]\s*[^;\n]*\b\d+(?:\.\d+)?px\b')
for name in ['plain/css', 'camel/jsx', 'arbitrary/class']:
    print(f'\n-- {name} --')
    hits = []
    if name == 'plain/css':
        pat = re_plain
    elif name == 'camel/jsx':
        pat = re_camel
    else:
        pat = re_arb
    for fn in sorted(os.listdir(root)):
        dirpath = os.path.join(root, fn)
        if os.path.isdir(dirpath):
            if fn in IGNORE:
                continue
        for rel in sorted(os.listdir(dirpath) if os.path.isdir(dirpath) else [fn]):
            path = os.path.join(root, fn, rel) if os.path.isdir(dirpath) else os.path.join(root, fn)
            if os.path.isdir(path):
                continue
            try:
                text = open(path, encoding='utf-8', errors='ignore').read()
            except Exception:
                continue
            if rel.endswith(('.ts','.tsx','js','.jsx','.mjs','.cjs')):
                for i,line in enumerate(text.splitlines(),1):
                    if pat.search(line):
                        hits.append(f'{path}:{i}: {line.strip()[:120]}')
            elif rel.endswith('.css'):
                for i,line in enumerate(text.splitlines(),1):
                    if path.startswith('src/styles') or path.startswith('src/motion'):
                        continue
                    if pat.search(line):
                        hits.append(f'{path}:{i}: {line.strip()[:120]}')
    if hits:
        print('\n'.join(hits))
    else:
        print('none')
print('\n-- old lint pattern hits --')
hits=[]
for fn in sorted(os.listdir(root)):
    dirpath = os.path.join(root, fn)
    if os.path.isdir(dirpath) and fn in IGNORE:
        continue
    for rel in sorted(os.listdir(dirpath) if os.path.isdir(dirpath) else [fn]):
        path = os.path.join(root, fn, rel) if os.path.isdir(dirpath) else os.path.join(root, fn)
        if os.path.isdir(path):
            continue
        try:
            text = open(path, encoding='utf-8', errors='ignore').read()
        except Exception:
            continue
        if rel.endswith(('.ts','.tsx','js','.jsx','.mjs','.cjs')):
            for i,line in enumerate(text.splitlines(),1):
                if re_rounded.search(line):
                    hits.append(f'{path}:{i}: {line.strip()[:120]}')
        else:
            for i,line in enumerate(text.splitlines(),1):
                if path.startswith('src/styles') or path.startswith('src/motion'):
                    continue
                if re_rounded.search(line):
                    hits.append(f'{path}:{i}: {line.strip()[:120]}')
if hits:
    print('\n'.join(hits))
else:
    print('none')
PY

Repository: Travis-Gilbert/CommonPlace

Length of output: 657


Cover inline and Tailwind raw radius in the lint.

RAW_RADIUS misses common .tsx forms: React inline styles use camelCase borderRadius: '8px', and Tailwind arbitrary classes use rounded-[12px] without [:=]. Add those cases to catch component-level raw-radius violations or confirm another merge gate covers them.

🤖 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 `@apps/console/scripts/check-radius-lint.mjs` around lines 29 - 30, Update
RAW_RADIUS in check-radius-lint to match React camelCase borderRadius
declarations and Tailwind arbitrary rounded-[Npx] classes, while preserving
detection of existing CSS and Tailwind forms. Ensure SCALE_TOKEN exemptions
remain unchanged.
apps/console/src/components/shell/Sidebar.tsx (1)

557-578: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Hover-only landmark controls are invisible on keyboard focus.

The Pin/Remove buttons are focusable, but their wrapper is opacity-0 and only revealed via group-hover:opacity-100. A keyboard user who tabs onto Pin/Remove sees no visible control, which fails focus visibility. Reveal the controls on focus as well.

♿ Reveal controls on keyboard focus
-                  <span className="flex shrink-0 items-center gap-1 opacity-0 transition-opacity group-hover:opacity-100">
+                  <span className="flex shrink-0 items-center gap-1 opacity-0 transition-opacity group-hover:opacity-100 group-focus-within:opacity-100">
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

                {!visuallyCollapsed ? (
                  <span className="flex shrink-0 items-center gap-1 opacity-0 transition-opacity group-hover:opacity-100 group-focus-within:opacity-100">
                    <button
                      type="button"
                      className="text-ij-ink-info hover:text-ij-ink"
                      onClick={() => pinLandmark(landmark)}
                      aria-label={`${landmark.properties.pinned === true ? 'Unpin' : 'Pin'} ${label}`}
                    >
                      {landmark.properties.pinned === true ? 'Unpin' : 'Pin'}
                    </button>
                    {removable ? (
                      <button
                        type="button"
                        className="text-ij-ink-info hover:text-ij-ink"
                        onClick={() => removeLandmark(landmark)}
                        aria-label={`Remove ${label}`}
                      >
                        Remove
                      </button>
                    ) : null}
                  </span>
                ) : null}
🤖 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 `@apps/console/src/components/shell/Sidebar.tsx` around lines 557 - 578, Update
the landmark controls wrapper in the landmark rendering flow of Sidebar so its
opacity becomes visible when either the parent group is hovered or the
Pin/Remove buttons receive keyboard focus. Preserve the existing collapsed-state
condition and hover transition behavior while adding an appropriate focus-within
visibility utility.
apps/console/src/styles/app.css (1)

247-255: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
rg -n 'html,\s*body|height:\s*100%' apps/console/src/styles/app.css

Repository: Travis-Gilbert/CommonPlace

Length of output: 164


🏁 Script executed:

#!/bin/bash
set -euo pipefail
printf 'Tracked file count:\n'
git ls-files 'apps/console/src/styles/app.css'
printf '\nRelevant searches:\n'
rg -n '^(html,|body|\.thread-jump-strip)|height:\s*100%|100vh|min-height:\s*100%' apps/console/src/styles/app.css || true
printf '\nApp.css line count:\n'
wc -l apps/console/src/styles/app.css
printf '\nLine 220-270:\n'
sed -n '220,270p' apps/console/src/styles/app.css

Repository: Travis-Gilbert/CommonPlace

Length of output: 1689


Restore the viewport-height root rule.

apps/console/src/styles/app.css no longer sets html, body { height: 100%; }; it only has .thread-jump-strip before a body rule without height. Add that base rule back to keep h-full, min-h-0 flex-1, and viewport-height layouts from collapsing.

🤖 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 `@apps/console/src/styles/app.css` around lines 247 - 255, Restore the base
html, body height rule in app.css before the existing .thread-jump-strip styles,
setting both elements to 100% height. Leave the thread-jump-strip responsive
display rules unchanged.
apps/console/src/styles/int-ui-register-light.css (1)

47-53: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Tier lightness comment inverts sunken vs ground.

The annotation says "After: sunken ~92, ground ~88", i.e. sunken lighter than ground. But --ij-tier-sunken: #D2CEC5 is darker than `--ij-tier-ground: `#D9D6CF (lower RGB → lower L*), which is also what the "editor sunken on frame" contrast pair assumes. The hex ordering is correct; the comment L% values are reversed and could mislead when the dark register or future tuning is derived from them. Please correct the annotated values.

🤖 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 `@apps/console/src/styles/int-ui-register-light.css` around lines 47 - 53,
Correct the lightness annotation in the tier comment above --ij-tier-sunken and
--ij-tier-ground so it reflects the existing hex values: sunken is darker than
ground, with sunken approximately ~88 and ground approximately ~92. Leave the
tier variable values and their ordering unchanged.
apps/console/src/styles/int-ui-register.css (1)

47-53: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Do not make seam and keyline tokens lighter than their surfaces.

--ij-seam is lighter than --ij-frame and --ij-editor; --ij-seam-raised is also lighter than the raised and floating tiers. Since --ij-keyline aliases that value, this reintroduces light hairlines across elevated surfaces. Derive these seams from darker tier values instead.

As per coding guidelines, seams must be darker than surfaces, with no light hairlines.

🤖 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 `@apps/console/src/styles/int-ui-register.css` around lines 47 - 53, Update the
seam and keyline token definitions in the CSS variable block: derive --ij-seam
and --ij-seam-raised from darker tier values so each is darker than its
corresponding frame, editor, raised, and floating surfaces. Keep --ij-keyline
aligned with the corrected raised seam and preserve the existing focus and
decorative keyline behavior.

Source: Coding guidelines

apps/console/src/styles/register-bridge.css (1)

170-190: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Apply tier fills for every semantic elevation host.

Only sunken and scrim receive a background. ground, raised, and floating hosts retain their parent fill when consumers rely on data-elevation, so their declared elevation is visually lost.

Proposed fix
+[data-register="intui"] [data-elevation="ground"] {
+  background: var(--ij-tier-ground);
+}
+
 [data-register="intui"] [data-elevation="raised"],
 [data-register="intui"] [data-elevation="floating"] {
+  background: var(--ij-tier-raised);
   border: 1px solid var(--ij-keyline);
   border-radius: var(--ij-radius-md);
   corner-shape: var(--ij-corner-raised);
 }
 
 [data-register="intui"] [data-elevation="floating"] {
+  background: var(--ij-tier-floating);
   border-radius: var(--ij-radius-lg);
   box-shadow: var(--ij-floating-shadow);
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

/* Raised and above: keyline + continuous-curvature corner (Chromium). WebKit
   degrades to border-radius alone (named choice 3). */
[data-register="intui"] [data-elevation="ground"] {
  background: var(--ij-tier-ground);
}

[data-register="intui"] [data-elevation="raised"],
[data-register="intui"] [data-elevation="floating"] {
  background: var(--ij-tier-raised);
  border: 1px solid var(--ij-keyline);
  border-radius: var(--ij-radius-md);
  corner-shape: var(--ij-corner-raised);
}

[data-register="intui"] [data-elevation="floating"] {
  background: var(--ij-tier-floating);
  border-radius: var(--ij-radius-lg);
  box-shadow: var(--ij-floating-shadow);
}

[data-register="intui"] [data-elevation="sunken"] {
  background: var(--ij-tier-sunken);
  border-radius: var(--ij-radius-sm);
}

[data-register="intui"] [data-elevation="scrim"] {
  background: var(--ij-scrim-fill);
🤖 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 `@apps/console/src/styles/register-bridge.css` around lines 170 - 190, Update
the semantic elevation selectors in the register bridge so every host—ground,
raised, floating, sunken, and scrim—receives its corresponding tier fill via
background. Preserve the existing border, radius, corner-shape, and shadow
declarations while adding the missing fills for ground, raised, and floating
using the established tier-fill variables.
apps/console/src/views/canvas/CanvasView.tsx (1)

26-47: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Determine whether BlockHost.query can return a Promise in this codebase.
rg -nP -C3 "\bquery\s*\(" packages/block-view/src/types.ts
rg -nP -C2 "Promise<ObjectSet>|ObjectSet\s*\|\s*Promise" packages/block-view/src

Repository: Travis-Gilbert/CommonPlace

Length of output: 1235


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== CanvasView =="
cat -n apps/console/src/views/canvas/CanvasView.tsx

echo
echo "== HttpBlockHost query context =="
sed -n '1,180p' packages/block-view/src/host/HttpBlockHost.ts | cat -n

echo
echo "== MaybePromise definition and object set subscribe usages =="
rg -n -C3 "type MaybePromise|interface MaybePromise|Promise<ObjectSet>|ObjectSet \| Promise|subscribe\\(" packages/block-view apps/console/src/views/canvas -g '*.ts' -g '*.tsx'

echo
echo "== Similar MaybePromise query handling =="
rg -n -C4 "Promise\.resolve\\(host\.(query|get)?|await host\s*\?\.?\.query|query\\(" apps/console/src packages -g '*.ts' -g '*.tsx' | head -n 220

Repository: Travis-Gilbert/CommonPlace

Length of output: 43341


Handle async host.query in the canvas store.

BlockHost.query is MaybePromise<ObjectSet>, and both HttpBlockHost and the live domain path return promises. queryCanvas returns only an empty snapshot when the query is a Promise, so the canvas can render stuck. Await the promise before returning/consuming the result. Minor: createCanvasStore.subscribe also re-runs queryCanvas, but the live subscribe path already handles that by construction.

🧰 Tools
🪛 ESLint

[error] 45-45: Error: Calling setState synchronously within an effect can trigger cascading renders

Effects are intended to synchronize state between React and external systems such as manually updating the DOM, state management libraries, or other platform APIs. In general, the body of an effect should do one or both of the following:

  • Update external systems with the latest state from React.
  • Subscribe for updates from some external system, calling setState in a callback function when external state changes.

Calling setState synchronously within an effect body causes cascading renders that can hurt performance, and is not recommended. (https://react.dev/learn/you-might-not-need-an-effect).

/home/jailuser/git/apps/console/src/views/canvas/CanvasView.tsx:45:5
43 | useEffect(() => {
44 | const current = queryCanvas(host);

45 | setSet(current);
| ^^^^^^ Avoid calling setState() directly within an effect
46 | return current.subscribe(setSet);
47 | }, [host]);
48 |

(react-hooks/set-state-in-effect)

🤖 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 `@apps/console/src/views/canvas/CanvasView.tsx` around lines 26 - 47, Update
queryCanvas and the CanvasView initialization/effect flow to resolve Promise
results from host.query before storing or rendering the ObjectSet, rather than
permanently using the empty snapshot. Preserve synchronous query handling and
ensure async results update state when resolved; avoid re-querying in
createCanvasStore.subscribe because the live subscription already manages
updates.

Source: Linters/SAST tools

apps/console/src/views/GalleyDocView.tsx (1)

89-185: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Stale docTitle closure: missing effect dependency.

openFor closes over docTitle, but the effect's dependency array ([mode, text, doc?.id]) omits doc?.properties.title. If the title changes while text/doc.id stay the same, the hand-off chip label will use the stale title until something else re-triggers the effect. Confirmed by the ESLint react-hooks/exhaustive-deps warning on Line 185.

🐛 Suggested fix
-  }, [mode, text, doc?.id]);
+  }, [mode, text, doc?.id, doc?.properties.title]);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

  useEffect(() => {
    if (mode !== 'read') return;
    const root = scrollRef.current;
    const docId = doc?.id;
    const docTitle = typeof doc?.properties.title === 'string' ? doc.properties.title : docId;
    if (!root || !docId) return;

    const openFor = (todoText: string) => {
      useShellStore.getState().openActionSheet({
        chips: [
          objectChip(docId, 'doc', docTitle ?? docId),
          {
            id: `chip-selection-${docId}-${todoText.slice(0, 24)}`,
            kind: 'selection',
            label: todoText,
            text: todoText,
            source: 'origin',
          },
        ],
      });
    };

    const decorate = () => {
      const items = [
        ...root.querySelectorAll<HTMLElement>('li.task-list-item'),
        ...[...root.querySelectorAll<HTMLElement>('.galley li:not(.task-list-item)')].filter((li) =>
          /^\[( |x)\]\s/.test((li.textContent ?? '').trimStart()),
        ),
      ];
      for (const item of items) {
        if (item.querySelector('[data-todo-action]')) continue;
        const todoText = (item.textContent ?? '').trim();
        const button = document.createElement('button');
        button.type = 'button';
        button.dataset.todoAction = '';
        button.dataset.todoText = todoText;
        button.setAttribute('aria-label', 'Hand this todo to the agent');
        button.textContent = '→';
        button.className =
          'ml-2 h-5 rounded-ij-arc px-1 text-ij-ink-info hover:bg-ij-hover-surface hover:text-ij-ink focus:outline-2 focus:outline-ij-accent';
        item.tabIndex = 0;
        item.dataset.todoItem = '';
        item.dataset.todoText = todoText;
        item.appendChild(button);
      }
    };

    const onClick = (event: MouseEvent) => {
      const target = event.target as HTMLElement | null;
      const button = target?.closest<HTMLElement>('[data-todo-action]');
      if (!button || !root.contains(button)) return;
      event.preventDefault();
      openFor(button.dataset.todoText ?? '');
    };
    const onKey = (event: KeyboardEvent) => {
      if (!(event.altKey && event.key === 'Enter')) return;
      const target = event.target as HTMLElement | null;
      const item = target?.closest<HTMLElement>('[data-todo-item]');
      if (!item || !root.contains(item)) return;
      event.preventDefault();
      event.stopPropagation();
      openFor(item.dataset.todoText ?? (item.textContent ?? '').trim());
    };

    let timer: ReturnType<typeof setTimeout> | null = null;
    let observer: MutationObserver;
    const scheduleDecorate = () => {
      if (timer) clearTimeout(timer);
      timer = setTimeout(() => {
        timer = null;
        observer.disconnect();
        try {
          decorate();
        } finally {
          observer.observe(root, { childList: true, subtree: true });
        }
      }, 0);
    };

    decorate();
    observer = new MutationObserver(() => scheduleDecorate());
    observer.observe(root, { childList: true, subtree: true });
    root.addEventListener('click', onClick);
    root.addEventListener('keydown', onKey);
    return () => {
      if (timer) clearTimeout(timer);
      observer.disconnect();
      root.removeEventListener('click', onClick);
      root.removeEventListener('keydown', onKey);
      root.querySelectorAll('[data-todo-action]').forEach((node) => node.remove());
      root.querySelectorAll<HTMLElement>('[data-todo-item]').forEach((item) => {
        item.removeAttribute('tabindex');
        delete item.dataset.todoItem;
        delete item.dataset.todoText;
      });
    };
  }, [mode, text, doc?.id, doc?.properties.title]);
🧰 Tools
🪛 GitHub Check: Gates, unit tests, build

[warning] 185-185:
React Hook useEffect has a missing dependency: 'doc.properties.title'. Either include it or remove the dependency array

🤖 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 `@apps/console/src/views/GalleyDocView.tsx` around lines 89 - 185, Update the
useEffect dependency array in GalleyDocView so it includes the document title
value used to compute docTitle, such as doc?.properties.title, alongside mode,
text, and doc?.id. Preserve the existing openFor behavior while ensuring title
changes recreate the closure and refresh the hand-off chip label.

Source: Linters/SAST tools

apps/console/src/views/ThreadView.tsx (1)

9-9: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
fd object-address.ts apps/console/src/lib --exec cat {}
rg -n 'theoremUri|extractTheoremAddress' apps/console/src

Repository: Travis-Gilbert/CommonPlace

Length of output: 2998


🏁 Script executed:

#!/bin/bash
set -euo pipefail
sed -n '1,115p' apps/console/src/views/ThreadView.tsx
printf '\n--- objectAddress usages ---\n'
rg -n 'objectAddress\(|AddressableObject|extractTheoremAddress\(' apps/console/src/views/ThreadView.tsx apps/console/src/lib apps/console/src

Repository: Travis-Gilbert/CommonPlace

Length of output: 5980


Direct theoremUri calls still bypass the console address helper.

apps/console/src/views/ThreadView.tsx:71 calls theoremUri(address) directly; use the designated console address API, such as the existing address parser, instead of importing @commonplace/block-view/addressing.

🤖 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 `@apps/console/src/views/ThreadView.tsx` at line 9, Replace the direct
theoremUri import and usage in ThreadView with the designated console address
API, reusing the existing address parser to derive the needed theorem address.
Remove the block-view addressing import while preserving the current behavior at
the call site.

Source: Coding guidelines

@Travis-Gilbert
Travis-Gilbert merged commit a43d45f into main Jul 23, 2026
3 of 4 checks passed
@Travis-Gilbert
Travis-Gilbert deleted the cursor/chat-sidebar-dockview-reconcile branch July 23, 2026 19:18
cursor Bot pushed a commit that referenced this pull request Jul 23, 2026
Post-#99: island gutter is 6px, Hide loses data-island-hide, companion chips
sit on chrome not selection wash. Refresh linux snapshots from CI actuals
and force companion/Files clicks so soft-nav races cannot hang the worker.

Co-authored-by: Travis Gilbert <Travis-Gilbert@users.noreply.github.com>
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.

2 participants