feat(stagecraft): the studio's Ticket tab on the work-item page, and the nav shows where you are (swamp-club #2969) #444

Merged
seth merged 2 commits from cue/2969-stagecraft-studio-ticket into main 2026-10-02 18:49:17 +00:00
Owner

swamp-club #2969: a Ticket tab on the studio's work-item page, and the nav shows where you are.

Ticket tab

The work-item page's Tracker tab is now Ticket, and it's the default tab when the work item has a ticket. It shows the bound ticket's:

  • title, status, labels or type, assignees, and created and updated times
  • markdown description, drawn safely
  • comments and lifecycle entries, oldest first, with stagecraft's own marked
  • relations, each linking to the work item on the other ticket in any factory
  • link out, for an external ticket

Data. A new read-only route, GET /api/work-items/<key>/ticket (studio_ticket.ts), reads what the tracker instance stored:

  • the issue-<id> snapshot that fetch_issue, claim or create wrote;
  • for the built-in tracker, the ticket and its comment- and entry- records.

The studio still calls no tracker and resolves no credential. Seth chose this over a live fetch to keep "The seam" and the no-method rule. The tab says when its copy was recorded, and fetch_issue refreshes it.

Adapters. fetchIssue now reads description, labels, assignees, createdAt, updatedAt and activity for every tracker:

  • Linear: description, labels and up to 250 comments.
  • Lab: ripples and lifecycleEntries, parsed defensively against the live reply's shape.
  • Built-in: its own records, through queryData when the method has it. Without it, activity is absent and claim is unaffected.

The conformance suite checks that a comment and an entry come back under the id the write returned. That id is what the delivery ledger records, and it's how the tab marks stagecraft's posts.

Safe markdown. studio/src/markdown.tsx parses markdown into Preact elements and never builds an HTML string:

  • raw HTML stays text;
  • links are http(s) only;
  • images become links.

A test walks the element tree of a description containing a script tag, an onerror image, an iframe, and javascript: and data: links, and checks that all of them render inert.

Navigation

  • Design, Simulate and Board are links. The current one carries aria-current="page", and on a work item, Board carries aria-current="true".
  • The work-item page has a "Board › key" breadcrumb.
  • Every route sets the browser tab title, for example "blog-12 · Board · blog · Stagecraft Studio".

Testing

  • Unit: conformance for all three adapters, the ticket read, the route, the markdown renderer, nav and title for every route, the tab default, and loading.
  • End to end on real swamp (integration/extension/studio_ticket_test.ts):
    • Built-in: a ticket with a description and two comments, one of them marked as stagecraft's, plus an item with no ticket.
    • Linear: against linear_fake; the ticket reads as missing until fetch_issue runs, and the studio never contacts Linear.
    • Lab: against swamp_club_fake.
  • By hand in headless Chromium on real swamp:
    • every route marks its place;
    • the hostile description renders as text;
    • keyboard order runs nav, breadcrumb, item tabs, ticket links, then Refresh;
    • the new text has a contrast ratio of 8.4 or better.
  • Verification: verify-build and verify-reviews passed on dcb6aaa29. Attestation 6fd04aea-03d3-4e9e-a78a-7722dc422d71.

Notes

  • The tracker models' versions are bumped: builtin and swamp_club to 2026.10.02.2, linear to 2026.10.02.3.
  • The studio bundle's app module is now 774 KB, against the test's 800,000-byte budget.
  • docs/studio.png was not retaken, because headless capture of Design mode hangs.
  • Moving the remaining CLI data get uses off is filed separately as #2974.

🤖 Generated with Claude Code

swamp-club #2969: a Ticket tab on the studio's work-item page, and the nav shows where you are. ## Ticket tab The work-item page's Tracker tab is now **Ticket**, and it's the default tab when the work item has a ticket. It shows the bound ticket's: - title, status, labels or type, assignees, and created and updated times - markdown description, drawn safely - comments and lifecycle entries, oldest first, with stagecraft's own marked - relations, each linking to the work item on the other ticket in any factory - link out, for an external ticket **Data.** A new read-only route, `GET /api/work-items/<key>/ticket` (`studio_ticket.ts`), reads what the tracker instance stored: - the `issue-<id>` snapshot that `fetch_issue`, `claim` or `create` wrote; - for the built-in tracker, the ticket and its `comment-` and `entry-` records. The studio still calls no tracker and resolves no credential. Seth chose this over a live fetch to keep "The seam" and the no-method rule. The tab says when its copy was recorded, and `fetch_issue` refreshes it. **Adapters.** `fetchIssue` now reads `description`, `labels`, `assignees`, `createdAt`, `updatedAt` and `activity` for every tracker: - **Linear:** description, labels and up to 250 comments. - **Lab:** ripples and `lifecycleEntries`, parsed defensively against the live reply's shape. - **Built-in:** its own records, through `queryData` when the method has it. Without it, `activity` is absent and `claim` is unaffected. The conformance suite checks that a comment and an entry come back under the id the write returned. That id is what the delivery ledger records, and it's how the tab marks stagecraft's posts. **Safe markdown.** `studio/src/markdown.tsx` parses markdown into Preact elements and never builds an HTML string: - raw HTML stays text; - links are http(s) only; - images become links. A test walks the element tree of a description containing a script tag, an `onerror` image, an iframe, and `javascript:` and `data:` links, and checks that all of them render inert. ## Navigation - Design, Simulate and Board are links. The current one carries `aria-current="page"`, and on a work item, Board carries `aria-current="true"`. - The work-item page has a "Board › key" breadcrumb. - Every route sets the browser tab title, for example "blog-12 · Board · blog · Stagecraft Studio". ## Testing - **Unit:** conformance for all three adapters, the ticket read, the route, the markdown renderer, nav and title for every route, the tab default, and loading. - **End to end on real swamp** (`integration/extension/studio_ticket_test.ts`): - **Built-in:** a ticket with a description and two comments, one of them marked as stagecraft's, plus an item with no ticket. - **Linear:** against `linear_fake`; the ticket reads as missing until `fetch_issue` runs, and the studio never contacts Linear. - **Lab:** against `swamp_club_fake`. - **By hand in headless Chromium on real swamp:** - every route marks its place; - the hostile description renders as text; - keyboard order runs nav, breadcrumb, item tabs, ticket links, then Refresh; - the new text has a contrast ratio of 8.4 or better. - **Verification:** `verify-build` and `verify-reviews` passed on `dcb6aaa29`. Attestation `6fd04aea-03d3-4e9e-a78a-7722dc422d71`. ## Notes - The tracker models' versions are bumped: `builtin` and `swamp_club` to `2026.10.02.2`, `linear` to `2026.10.02.3`. - The studio bundle's app module is now 774 KB, against the test's 800,000-byte budget. - `docs/studio.png` was not retaken, because headless capture of Design mode hangs. - Moving the remaining CLI `data get` uses off is filed separately as #2974. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
The work-item page's Tracker tab becomes Ticket: the bound ticket's title,
status, labels or type, assignees, times, its markdown description drawn
safely as elements, and its comments and lifecycle entries oldest first,
with stagecraft's marked by the tracker's delivery ledger. Relations link to
the work item on the other ticket, in any factory, and an external ticket
links out to Linear or the Lab. A new route,
GET /api/work-items/<key>/ticket, reads what the tracker instance stored; the
studio still calls no tracker and resolves no credential.

Every adapter's fetchIssue reads that content (Linear's description, labels
and comments; the Lab's ripples and lifecycle entries; the built-in ticket's
comment and entry records through the data query), and the conformance suite
checks a comment and an entry come back under the id the write returned.

The bar's views are links with aria-current, the work-item page has a
"Board › key" breadcrumb, and every route titles the browser tab.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
fix(stagecraft): REFERENCE names the Ticket tab's link out without the Lab (swamp-club #2969)
All checks were successful
CI / Review Integrity (pull_request) Successful in 1m10s
CI / Validate Attestation (pull_request) Successful in 1m6s
dcb6aaa29c
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
seth merged commit 6725d925ef into main 2026-10-02 18:49:17 +00:00
seth deleted branch cue/2969-stagecraft-studio-ticket 2026-10-02 18:49:18 +00:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
swamp-club/swamp-extensions!444
No description provided.