Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
486665a
refactor: rename the declared-screenshot feature to "captures"
lukemelia Sep 24, 2026
80a51a8
Merge remote-tracking branch 'origin/main' into cs-13193-rename-captures
lukemelia Sep 25, 2026
7a2e0c6
Keep the renamed wire paths answering, and fail the renamed author su…
lukemelia Sep 25, 2026
4ac9e5a
Merge remote-tracking branch 'origin/main' into cs-13193-rename-captures
lukemelia Sep 28, 2026
fb11b7f
Keep old-revision capture manifests across the column drop, and resol…
lukemelia Sep 28, 2026
009d075
Revert the manifest re-copy and the legacy capture tool shim
lukemelia Sep 28, 2026
e16b1c4
State the accepted manifest loss in the screenshots drop migration
lukemelia Sep 28, 2026
f5b0cee
Merge remote-tracking branch 'origin/main' into cs-13193-rename-captures
lukemelia Sep 28, 2026
e22a8cf
Merge remote-tracking branch 'origin/main' into cs-13193-rename-captures
lukemelia Sep 28, 2026
95e4763
Sort capture-card into place in the job-registration expectation
lukemelia Sep 28, 2026
452129d
Merge remote-tracking branch 'origin/main' into cs-13193-rename-captures
lukemelia Sep 29, 2026
a6e5ee2
Merge remote-tracking branch 'origin/main' into cs-13193-rename-captures
lukemelia Sep 29, 2026
31de8d8
Merge remote-tracking branch 'origin/main' into cs-13193-rename-captures
lukemelia Sep 30, 2026
f4fe060
Merge remote-tracking branch 'origin/main' into cs-13193-rename-captures
lukemelia Sep 30, 2026
7bcd4f2
Merge remote-tracking branch 'origin/main' into cs-13193-rename-captures
lukemelia Sep 30, 2026
c0dd491
Claim screenshot-card jobs with the capture-card task
Sep 30, 2026
447ed58
Recognize legacy _screenshot/ URLs in the signer, shell negotiation, …
Sep 30, 2026
e9cde5e
Honor allowArbitraryScreenshots as a legacy spelling of the capture gate
Sep 30, 2026
074bbc3
Move declared-capture retry state to its current diagnostics keys pos…
Sep 30, 2026
bd4aec6
Fail capture slots signalling under either legacy attribute name
Sep 30, 2026
4c0832e
Rename the capture-perf-diagnosis skill directory and fix its dashboa…
Sep 30, 2026
024fb63
Post software-factory render-gate captures to /_capture-card
Sep 30, 2026
042fc67
List /_capture-card among the realm-server endpoints in the factory's…
Sep 30, 2026
e64478f
Merge remote-tracking branch 'origin/main' into cs-13193-rename-captures
Sep 30, 2026
cb30358
Name the capture prefix in the local media-cache env comment
Sep 30, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .claude/skills/ai-assistant-evals/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -309,7 +309,7 @@ Check these before blaming the model. Status as of 2026-09-08.

## What the runner cannot tell you

- Whether the card looks right. Look at the screenshot.
- Whether the card looks right. Look at the capture.
- Why the host froze, when it did. That needs the tab's console; the runner
keeps the room and the trace.
- Whether the card still works after the run. The snapshot holds the code and
Expand Down

Large diffs are not rendered by default.

44 changes: 22 additions & 22 deletions .claude/skills/indexing-diagnostics/SKILL.md

Large diffs are not rendered by default.

10 changes: 5 additions & 5 deletions .claude/skills/pr-privacy/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ Treat any of the following as user data that must be redacted before it touches
- **User-authored content.** Card titles, descriptions, body text, field values quoted from a card document.
- **Matrix handles, room IDs that map to user DMs, and email addresses.**
- **Account IDs that map to a specific person**, including Matrix user IDs (`@handle:matrix.boxel.ai`).
- **Screenshots that incidentally show any of the above** in the address bar, breadcrumbs, sidebar, or card body.
- **Captures that incidentally show any of the above** in the address bar, breadcrumbs, sidebar, or card body.

## What is OK to keep verbatim

Expand All @@ -31,11 +31,11 @@ Treat any of the following as user data that must be redacted before it touches

## How to redact

Preserve the *shape* of the data so the reviewer can still reason about it, drop the identifying parts:
Preserve the _shape_ of the data so the reviewer can still reason about it, drop the identifying parts:

- Replace path segments with placeholders that describe the role: `<username>/<realm>/<card-type>/<card>.json`.
- Replace lists of concrete examples with a count plus opaque IDs: instead of three full URLs, write "3 affected cards across 3 user realms (job IDs 209668, 209743, 209962)".
- Crop or blur screenshots before attaching them. Check the browser address bar, breadcrumb trail, sidebar realm list, and any visible card titles.
- Crop or blur captures before attaching them. Check the browser address bar, breadcrumb trail, sidebar realm list, and any visible card titles.
- For log excerpts, replace user realm URLs with `<user-realm>` and keep the structural fields (timestamps, request IDs, status codes, durations).

If a reviewer genuinely needs the concrete identifiers to reproduce a bug, write "see <Linear-ticket-id> for affected realm slugs" in the PR and put the unredacted list in the Linear ticket. Linear is staff-only and is the right place for that detail.
Expand Down Expand Up @@ -74,12 +74,12 @@ Apply this check at **two** moments — not just when calling a GitHub tool:
In both cases, ask:

1. Does this contain a path of the form `<word>/<word>/...` where the first word could be a real username?
2. Does this quote a log line, DB row, card document, or screenshot taken from staging or prod?
2. Does this quote a log line, DB row, card document, or capture taken from staging or prod?
3. Is this a hardcoded test value, fixture, or comment derived from something a real user actually has in their realm?
4. Would a search engine indexing this give someone outside Cardstack information about a specific user's data?

If yes to any: redact to the placeholder form above, or move the concrete detail to a linked Linear ticket and reference it by ID.

## Why this skill exists

PR comments are indexed by search engines, archived by third parties, and remain public forever. Pasting CloudWatch output, DB query results, or screenshots that include real user realm slugs into a PR comment ships that information out of Cardstack permanently — even if the comment is later edited or the PR is closed.
PR comments are indexed by search engines, archived by third parties, and remain public forever. Pasting CloudWatch output, DB query results, or captures that include real user realm slugs into a PR comment ships that information out of Cardstack permanently — even if the comment is later edited or the PR is closed.
2 changes: 1 addition & 1 deletion .claude/skills/pr-review/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ Expect most of the work to stay invisible. A review that traced six paths and fo
Load these companion skills before writing a single comment; each applies in **both directions** — to the diff under review and to the review's own output:

- **pr-comment-attribution** — every comment the review posts — inline comments, thread replies, and the review body — begins with the `[Claude Code 🤖]` prefix.
- **pr-privacy** — scan the diff for user data the author is about to publish (fixtures, code comments, screenshots, PR text), and scan the review's own comments before posting: quoting a log line or DB row into a review comment publishes it.
- **pr-privacy** — scan the diff for user data the author is about to publish (fixtures, code comments, captures, PR text), and scan the review's own comments before posting: quoting a log line or DB row into a review comment publishes it.
- **evergreen-comments** — the review's own prose is evergreen (no ticket IDs, no PR numbers, no journey narration), and the diff's new or edited comments, docs, and skill files are checked for temporal wording, tracker references, and journey narration as a standing review dimension.

If the diff touches an area with a dedicated domain skill (index-query-engine, search, gts-component-conventions, ember-best-practices, …), load it — those files carry the invariants the change must preserve, which is exactly what a review checks.
Expand Down
6 changes: 3 additions & 3 deletions .claude/skills/search-shape-diagnosis/SKILL.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
---
name: search-shape-diagnosis
description: Read the per-request query-shape telemetry the federated search emits — one JSON log line per `_federated-search` request on the `boxel:search-shape` channel (the same `| json` convention as `boxel:client-perf` and `boxel:screenshot-perf`), carrying the query's *shape* with every caller-supplied value elided, plus which cache answered, the result counts, and the wall-clock. Use it to answer what a search load was actually made of, which the request rate alone cannot show: (1) what a burst of searches asked for — the filter trees, type anchors, page sizes and fieldsets behind a spike, and how many distinct shapes (`shapeHash`) it decomposes into; (2) which shapes dominate a window by volume, by latency, or by rows returned; (3) how much of a load the caches absorbed — `miss`/`join`/`hit` on the live-search cache and `job-miss`/`job-hit`/`not-modified` on the indexer's job-scoped cache — and therefore how much of it reached the index at all; (4) separating prerender search load from live browser load via `linkMode`, since a prerender skips the `loadLinks` relationship-assembly pass and so costs a different amount for the same query; (5) attributing live search load to a person or a tab session, by joining `correlationId` to the `server-request` event on `boxel:client-perf`; (6) attributing in-render search load to the indexing job that caused it via `jobId` and `consumingRealm`; and (7) authoring a replay that exercises the same index paths a real load did; and (8) auditing the link-shape policy, which picks how much of each result's link graph a live read carries from the load the process is under and may overrule a caller — answering "was this page served a degraded shape, and why" from `requestedLinkMode` / `linkModeDowngraded` / `linkShapeLoad` / `linkShapeLevel` beside the served `linkMode`, and "is the policy engaging more than it should" from the per-realm transition records and sampled no-change records on the `boxel:link-shape-policy` channel, whose `dwellMs` is the flapping signal. Carries the traps that make naive aggregates silently wrong: a cache hit reports no counts, an incomplete merge reports no total, `correlationId` is minted per search so nothing on the line groups one render (`jobId` is a whole index pass), `linkMode` is what was *served* rather than what was asked for, `linkShapeLoad` is a sustained mean that will not match a health line's instantaneous `inFlightSearch`, and a search the admission gate sheds emits no line at all — so under saturation this counts admitted searches rather than arriving ones. Joins to `realm:requests` and the `realm:search-timing` stage breakdown on `correlationId`. For staging/prod this layers on `aws-access` (the AWS session and Loki auth) and `tail-logs` (the Loki wrapper); hand off to `indexing-diagnostics` when the cost is inside the indexer rather than in what was asked for, and to the `search` skill when the task is authoring a query rather than reading one. Use when someone asks what a search spike was made of, which queries a realm is issuing, why search load is high, what a representative query looks like, or wants to replay a real load.
description: Read the per-request query-shape telemetry the federated search emits — one JSON log line per `_federated-search` request on the `boxel:search-shape` channel (the same `| json` convention as `boxel:client-perf` and `boxel:capture-perf`), carrying the query's *shape* with every caller-supplied value elided, plus which cache answered, the result counts, and the wall-clock. Use it to answer what a search load was actually made of, which the request rate alone cannot show: (1) what a burst of searches asked for — the filter trees, type anchors, page sizes and fieldsets behind a spike, and how many distinct shapes (`shapeHash`) it decomposes into; (2) which shapes dominate a window by volume, by latency, or by rows returned; (3) how much of a load the caches absorbed — `miss`/`join`/`hit` on the live-search cache and `job-miss`/`job-hit`/`not-modified` on the indexer's job-scoped cache — and therefore how much of it reached the index at all; (4) separating prerender search load from live browser load via `linkMode`, since a prerender skips the `loadLinks` relationship-assembly pass and so costs a different amount for the same query; (5) attributing live search load to a person or a tab session, by joining `correlationId` to the `server-request` event on `boxel:client-perf`; (6) attributing in-render search load to the indexing job that caused it via `jobId` and `consumingRealm`; and (7) authoring a replay that exercises the same index paths a real load did; and (8) auditing the link-shape policy, which picks how much of each result's link graph a live read carries from the load the process is under and may overrule a caller — answering "was this page served a degraded shape, and why" from `requestedLinkMode` / `linkModeDowngraded` / `linkShapeLoad` / `linkShapeLevel` beside the served `linkMode`, and "is the policy engaging more than it should" from the per-realm transition records and sampled no-change records on the `boxel:link-shape-policy` channel, whose `dwellMs` is the flapping signal. Carries the traps that make naive aggregates silently wrong: a cache hit reports no counts, an incomplete merge reports no total, `correlationId` is minted per search so nothing on the line groups one render (`jobId` is a whole index pass), `linkMode` is what was *served* rather than what was asked for, `linkShapeLoad` is a sustained mean that will not match a health line's instantaneous `inFlightSearch`, and a search the admission gate sheds emits no line at all — so under saturation this counts admitted searches rather than arriving ones. Joins to `realm:requests` and the `realm:search-timing` stage breakdown on `correlationId`. For staging/prod this layers on `aws-access` (the AWS session and Loki auth) and `tail-logs` (the Loki wrapper); hand off to `indexing-diagnostics` when the cost is inside the indexer rather than in what was asked for, and to the `search` skill when the task is authoring a query rather than reading one. Use when someone asks what a search spike was made of, which queries a realm is issuing, why search load is high, what a representative query looks like, or wants to replay a real load.
allowed-tools: Read, Grep, Glob, Bash
---

# Federated search query-shape diagnosis

A federated search is a `QUERY` (or `POST`) whose query travels in the request body. Access logs carry method, URL, status and timing and never bodies — so without this channel a search load is legible only as a rate: how many ran and how long each took, with nothing about what any of them asked for.

`boxel:search-shape` closes that. One flat JSON line per `_federated-search` request, emitted from the single call site in `packages/realm-server/handlers/handle-search.ts`, defined in `packages/runtime-common/search-shape.ts`. It is the search sibling of `client-perf-diagnosis` (browser telemetry) and `screenshot-perf-diagnosis` (capture telemetry), and shares their emit convention.
`boxel:search-shape` closes that. One flat JSON line per `_federated-search` request, emitted from the single call site in `packages/realm-server/handlers/handle-search.ts`, defined in `packages/runtime-common/search-shape.ts`. It is the search sibling of `client-perf-diagnosis` (browser telemetry) and `capture-perf-diagnosis` (capture telemetry), and shares their emit convention.

The module header in `search-shape.ts` defines what each member means. This skill is about querying the channel and the ways a reasonable query returns a wrong number; where it touches a field's meaning it does so only far enough to explain the consequence, and points at the header for the rest.

Expand Down Expand Up @@ -363,4 +363,4 @@ Reconstruct the request body from the shape (see the `search` skill for the wire

## Where to run these

`boxel:client-perf`, `boxel:screenshot-perf` and `boxel:actions-queue` each have a dashboard under `packages/observability/grafanactl/resources/dashboards/boxel-status/`; this channel is read from Grafana Explore with the recipes above. The traps are what any panel set has to respect: split by `linkMode`, constrain counts to the miss outcomes, group by `shapeHash` rather than `filter`, and show the `realm:search-admission` shed count beside any request rate.
`boxel:client-perf`, `boxel:capture-perf` and `boxel:actions-queue` each have a dashboard under `packages/observability/grafanactl/resources/dashboards/boxel-status/`; this channel is read from Grafana Explore with the recipes above. The traps are what any panel set has to respect: split by `linkMode`, constrain counts to the miss outcomes, group by `shapeHash` rather than `filter`, and show the `realm:search-admission` shed count beside any request rate.
2 changes: 1 addition & 1 deletion docs/card-def-field-def-relationships.md
Original file line number Diff line number Diff line change
Expand Up @@ -241,7 +241,7 @@ class Person extends CardDef {
}
```

This example builds on to the field and card definitions in the previous item (7). The screenshot below shows the differences in appearance when a `Person` card instance is rendered in `edit` format.
This example builds on to the field and card definitions in the previous item (7). The capture below shows the differences in appearance when a `Person` card instance is rendered in `edit` format.

Note that the `linksTo` and `linksToMany` fields (named `currentLocation` and `previousLocations`) render in `embedded` format provided in the `Country` card definition.

Expand Down
4 changes: 2 additions & 2 deletions mise-tasks/lib/env-vars.sh
Original file line number Diff line number Diff line change
Expand Up @@ -237,9 +237,9 @@ else

fi

# Media cache (declared screenshots: poster/thumb/rendition captures).
# Media cache (declared captures: poster/thumb/rendition).
# Without a store the capture pipeline is disabled and every
# `_screenshot/...?name=` URL 404s forever, so local dev defaults to a disk
# `_capture/...?name=` URL 404s forever, so local dev defaults to a disk
# store under the same ~/.local/share/boxel home the dev certs use.
#
# An object directory must pair one-to-one with a media_cache_ledger: the
Expand Down
Loading
Loading