Skip to content

FE-534: Walking skeleton SDK to SSE to React#10

Merged
lunelson merged 5 commits into
mainfrom
ln/fe-534-walking-skeleton
Apr 2, 2026
Merged

FE-534: Walking skeleton SDK to SSE to React#10
lunelson merged 5 commits into
mainfrom
ln/fe-534-walking-skeleton

Conversation

@lunelson
Copy link
Copy Markdown
Contributor

  • Add memory/SPEC.md with full v2 product spec
  • Add memory/ROADMAP.md with 12 sliced issues (FE-534–FE-545)
  • Update AGENTS.md with git/linear/graphite conventions
  • Move REFACTORS.md, REMODEL.md to docs/design/
  • Move TEST_PROBLEMS.md to docs/test-scenarios/

- Add memory/SPEC.md with full v2 product spec
- Add memory/ROADMAP.md with 12 sliced issues (FE-534–FE-545)
- Update AGENTS.md with git/linear/graphite conventions
- Move REFACTORS.md, REMODEL.md to docs/design/
- Move TEST_PROBLEMS.md to docs/test-scenarios/
@linear
Copy link
Copy Markdown

linear Bot commented Mar 30, 2026

FE-534 Walking skeleton: SDK → SSE → React

Prove the integration seam end-to-end. New Express route, pipeSDKStream adapter (Design A), React + Vite + useChat. Thinking, text, tool-use events visible in browser. No DB, no domain logic.

Copy link
Copy Markdown
Contributor Author

lunelson commented Mar 30, 2026

This stack of pull requests is managed by Graphite. Learn more about stacking.

lunelson and others added 4 commits March 31, 2026 13:23
…ation

- Define canonical section schemas for SPEC.md (concept, constraints, requirements,
  assumptions, decisions, lexicon, verification design, acceptance criteria) and
  PLAN.md (phases with slices/spikes, cross-referencing SPEC.md)
- Extract templates to resources/ subdirs (ln-spec, ln-plan), matching ln-handoff pattern
- Add traceability hygiene to ln-spec, ln-plan, ln-build, ln-spike, ln-scope
- Expand routing tables across all execution skills to include ln-spec/ln-plan escalation
- Add lexicon alignment survey to ln-review (feeds into ln-refactor)
- Add routing table to ln-sync
- Make ln-spec and ln-plan re-runnable (read-first, update semantics)
- Migrate memory/SPEC.md to new schema: surface 10 implicit assumptions, build
  19-term lexicon, consolidate acceptance criteria, fold Q&A into decision rationale
- Rename memory/ROADMAP.md → PLAN.md: organize 12 slices into 4 phases + horizon,
  add requirement/assumption cross-references to every slice
- Update templates bidirectionally: add issue IDs, branches, acceptance, dependencies
  sections from existing docs back into plan-template
- Add HTML comments throughout templates and docs as section-level guidance
- Update AGENTS.md with protocol docs (two-document system, skill flow, symlinks)
- Add .claude/skills → .agents/skills symlink for Claude Code compatibility

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- ln-grill: add anti-pattern naming and lexicon sharpening behaviors
- ln-plan: add epistemic horizon and spike economics concepts
- AGENTS.md: tie git/Linear/planning into one workflow (PLAN.md → Linear issue → Graphite stacked branch)
- Delete docs/design/REFACTORS.md (absorbed into REMODEL.md and SPEC.md)
- Add cli-graphite, cli-linear skill references

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Prove the integration seam: Claude Agent SDK query() streams through
an Express SSE adapter emitting AI SDK UI Message Stream protocol
events, consumed by @ai-sdk/react useChat hook rendering thinking
and text in a React UI.

- SSE adapter (pure function): translates SDK stream events to
  AI SDK protocol (text-start/delta/end, reasoning-start/delta/end,
  start, finish-step, finish, [DONE])
- Express POST /api/chat handler with SDK integration
- React + Vite client with useChat, thinking/text rendering
- 17 tests (10 unit, 5 integration, 2 format)
- TypeScript throughout, strict mode
- Replaced Preact with React, removed v1 deps (mysql2, dnd-kit, etc.)

Validates assumptions A1, A2, A8, A10.
Establishes invariants I1-I4 (SSE conformance, stream lifecycle,
thinking/text separation, Vite proxy routing).

Also: refine ln-* skills (scope-before-build routing, mandatory
traceability, invariants as first-class ledger in spec template).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@lunelson lunelson changed the title chore: scaffold v2 planning docs and project structure FE-534: Walking skeleton SDK to SSE to React Apr 1, 2026
@lunelson lunelson marked this pull request as ready for review April 1, 2026 11:29
Copy link
Copy Markdown

@augmentcode augmentcode Bot left a comment

Choose a reason for hiding this comment

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

Review completed. 5 suggestions posted.

Fix All in Augment

Comment augment review to trigger a new review at any time.

Comment thread src/server/sse-adapter.ts
type SDKMessage = SDKStreamEvent | SDKOtherMessage;

// Track content block types by index
const thinkingBlocks = new Set<number>();
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

src/server/sse-adapter.ts:39-41 — thinkingBlocks/textBlocks are module-level mutable state, so concurrent /api/chat requests can interfere with each other. In particular, one request’s resetAdapter() can clear another request’s in-flight block tracking and cause incorrect *-end events or missing events.

Severity: high

Fix This in Augment

🤖 Was this useful? React with 👍 or 👎, or 🚀 if it prevented an incident/outage.

Comment thread src/server/sse-adapter.ts

switch (event.type) {
case 'message_start':
return [{ type: 'start', messageId: event.message!.id }];
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

src/server/sse-adapter.ts:61-87 — Several non-null assertions (event.message!, event.content_block!, event.delta!, event.index!, delta.text!/delta.thinking!) will throw if the SDK ever emits an unexpected/partial shape. That would terminate the SSE stream and can also generate protocol ids like reasoning-undefined / text-undefined if index is absent.

Severity: medium

Fix This in Augment

🤖 Was this useful? React with 👍 or 👎, or 🚀 if it prevented an incident/outage.

Comment thread src/server/app.ts
},
});

for await (const sdkMessage of stream) {
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

src/server/app.ts:36-43 — If the client disconnects mid-stream, the for await loop will likely keep consuming from query() and attempting res.write(...) on a closed response. This can waste tokens/compute and may surface as noisy errors unless the stream is cancelled on req/res close.

Severity: medium

Fix This in Augment

🤖 Was this useful? React with 👍 or 👎, or 🚀 if it prevented an incident/outage.

Comment thread src/server/app.ts
?? lastMessage?.parts?.filter((p: { type: string }) => p.type === 'text')
.map((p: { text: string }) => p.text).join('') ?? '';

console.log('POST /api/chat — prompt:', JSON.stringify(prompt).substring(0, 100));
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

src/server/app.ts:17 — Logging the user prompt (even truncated) can unintentionally persist sensitive user input/PII into server logs. If this endpoint is used beyond local dev, it’s worth ensuring the logging policy matches your privacy/security requirements.

Severity: low

Fix This in Augment

🤖 Was this useful? React with 👍 or 👎, or 🚀 if it prevented an incident/outage.

});
});

describe('translateEvent', () => {
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

src/server/sse-adapter.test.ts:16 — translateEvent depends on module-level adapter state (thinkingBlocks/textBlocks), but these tests don’t reset that state between cases. This can make the suite order-dependent or flaky if tests are run concurrently or re-ordered.

Severity: medium

Fix This in Augment

🤖 Was this useful? React with 👍 or 👎, or 🚀 if it prevented an incident/outage.

Copy link
Copy Markdown
Contributor Author

lunelson commented Apr 2, 2026

Merge activity

  • Apr 2, 6:20 AM UTC: A user started a stack merge that includes this pull request via Graphite.
  • Apr 2, 6:20 AM UTC: @lunelson merged this pull request with Graphite.

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.

1 participant