Skip to content

Text (Markdown) lens + canvas polish + live-catalog validation + BFF - #8

Merged
aaltshuler merged 4 commits into
mainfrom
dash-books-phase1
Jun 25, 2026
Merged

Text (Markdown) lens + canvas polish + live-catalog validation + BFF#8
aaltshuler merged 4 commits into
mainfrom
dash-books-phase1

Conversation

@aaltshuler

@aaltshuleraaltshuler commented Jun 25, 2026

Copy link
Copy Markdown
Collaborator

Post-merge work on the dash-books canvas (PR #7 → main is already merged; this stacks on top).

Component tier

  • Text lens — a data-driven Markdown card (title_column + text_column), rendering the first result row's prose. Web uses react-markdown (raw HTML off → XSS-safe; links open in a new tab); the TUI degrades to the raw source. Distinct from Card (labeled fields) and Quote (citation feed).

Canvas polish

  • Drag-zoom fix — dragging a card no longer scales/distorts: use CSS.Translate (translate-only) instead of CSS.Transform, which also applied dnd-kit's scaleX/scaleY in our mixed-span grid.
  • Internal vertical scroll — long card content caps (max-h-[28rem]) and scrolls inside the tile with contained overscroll; the card header stays fixed.

Catalog + connection

  • Client.queries() — catalog listing over og.queries.list; validate now resolves cell ref/params against the live catalog, and catalog surfaces server queries.
  • BFF — the browser holds no token for the same-origin /og proxy; the Node proxy owns auth injection.

Docs

  • README / AGENTS / CLAUDE / canon refreshed (lens vocabulary incl. Text, BFF/rawGq notes).

Verified: pnpm -r build && typecheck && test green (core/client/web/tui/cli). Demo notebook (~/exp/concept-graph, separate repo) exercises the Text card bound to /selected.

🤖 Generated with Claude Code

Greptile Summary

This PR adds Markdown Text cards and tightens the server-backed notebook flow. The main changes are:

  • New Text lens schemas and web/TUI renderers.
  • Live catalog lookup for validate and a new Client.queries() API.
  • Browser /og proxy token handling and Vite proxy header cleanup.
  • Canvas drag and internal scroll polish.
  • Documentation updates for catalog queries and BFF usage.

Confidence Score: 4/5

This is close, but the catalog validation issue should be fixed before merging.

  • validate can accept a notebook that omits a nullable catalog parameter.
  • Runtime can then call the stored query without a value the server still expects.
  • The Text lens and proxy-token changes look consistent with the inspected code.

packages/cli/src/commands/validate.ts

Important Files Changed

FilenameOverview
packages/cli/src/commands/validate.tsAdds live catalog ref and param validation, but nullable catalog params can be treated as omitted.
packages/client/src/http.tsAdds the queries() facade and reshapes catalog query metadata.
packages/core/src/catalog/lenses/text.tsDefines the Text lens author and runtime props.
packages/web/src/components/Text.tsxRenders the first result row as Markdown with hardened external links.
packages/web/src/config.tsAvoids browser token reuse for same-origin /og proxy mode.

Fix All in Claude Code

Reviews (4): Last reviewed commit: "Merge remote-tracking branch 'origin/mai..." | Re-trigger Greptile

Greptile also left 1 inline comment on this PR.

Context used:

  • Context used - CLAUDE.md (source)

- Text lens: a data-driven Markdown card (title_column + text_column rendered
via react-markdown; raw HTML off → XSS-safe; links open new-tab). Wired across
core catalog + spec enums + web/Ink renderers; TUI shows raw source.
- Canvas polish: fix the heavy drag-zoom (translate-only, not CSS.Transform's
scaleX/scaleY) in the mixed-span grid; cap long card content with internal
vertical scroll (max-h + overscroll-contain) so tall tiles don't dominate.
- Client.queries() catalog listing (og.queries.list); validate resolves cell
refs/params against the live catalog; catalog command surfaces server queries.
- BFF: the browser holds no token for the same-origin /og proxy (readToken
short-circuits proxy mode); the Node proxy owns auth injection.
- Docs refresh (README / AGENTS / CLAUDE / canon).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Comment threadpackages/cli/src/commands/validate.ts Outdated
Comment threadpackages/cli/src/commands/validate.ts Outdated
Comment threadpackages/core/src/catalog/lenses/text.ts Outdated
Wrap the live-catalog fetch in its own try/catch so a network/server-down
failure reports `catalog_unreachable` ("catalog validation requires a reachable
server: …") rather than a generic `source` error — config/source errors stay
distinct. Cosmetic; behavior unchanged (still exits 1).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Comment threadpackages/web/src/config.ts
Comment threadpackages/cli/src/commands/validate.ts
- Text/Quote `text_column` is now required (z.string().min(1)) — a Text/Quote
cell with rows but no text column was silently rendering the empty fallback
instead of failing validation. (#3)
- validate: warn when a *required* (non-nullable) catalog param is bound to
$state without a default — it resolves at runtime, which validate can't see,
so flag it rather than passing silently. (#2)
- validate: document that the server-bound checks are intentional — structural
parse already runs offline above; the meaningful ref/param validation needs a
resolvable source by design. (#1, accepted-by-design)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Comment on lines +217 to +220
if (isRecord(value) && "$state" in value) {
return "default" in value
? { kind: "literal", value: value.default }
: { kind: "dynamic" };

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1State Params Still Drift

This classifier does not match the runtime resolver for $state params. A required catalog param like { $state: "/missing" } only produces a warning here, so validate can exit successfully even though runtime resolves the missing state path to undefined and invokes the server query without the required value. A malformed value like { $state: true, default: "fallback" } is also accepted as the literal default here, but runtime rejects the non-string $state before reading the default, so it sends undefined instead. The validator should reject malformed $state expressions and fail required dynamic params unless there is a value path that runtime will actually supply.

Fix in Claude Code

@aaltshuler
aaltshuler merged commit 8d3efe8 into mainJun 25, 2026
2 checks passed
}
}

for (const param of descriptors) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1Nullable Params Skipped

This treats nullable catalog params as optional by skipping the missing-param error whenever param.nullable is true. If the catalog uses nullable to mean the parameter may be explicitly null, a notebook can omit that parameter entirely, validate exits successfully, and runtime later invokes the stored query without a value the server still expects. The missing check should distinguish optional params from params that only allow null as a value.

Fix in Claude Code

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@aaltshuler