Skip to content

ci: enable GitHub Actions production deployment - #81

Merged
imharrisonking merged 19 commits into
productionfrom
dev
Sep 23, 2026
Merged

imharrisonking merged 19 commits into
productionfrom
dev

Conversation

@imharrisonking

Copy link
Copy Markdown
Contributor

Summary

Promotes the latest dev changes to production, including the GitHub Actions deployment trigger for pushes to production.

After this PR merges, the existing deploy.yml workflow will run the production SST deployment and database migration automatically.

SST Console autodeploy should remain disabled after confirming the GitHub production deployment succeeds.

imharrisonking and others added 19 commits July 31, 2026 19:26
…document-flow (#72)

* docs: resolve chat persistence schema & Electric sync design (iss-016) — four tables, backend-owned writes, terminal-ack run lifecycle

* docs: resolve chat UX design (iss-017) — per-session events hook, single-bubble render, retry semantics; frontier → iss-018

* feat(web): prototype chat UX layouts on assistant-ui ExternalStoreRuntime (iss-017)

Three switchable layout variants (rail / breadcrumb-menu / document-flow)
for the chat sessions chrome, driven by an in-memory mock of the locked
Q1-Q8 events model, hosted at /app/prototype-chat with a ?variant= search
param and a floating switcher.

- add assistant-ui registry components (thread, thread-list, markdown,
  tools, suggestions, attachments); keep Structa primitives; drop the
  composer stop button (Q7) and gate sending while a run is in-flight
- add lib/chat-mock: types, scripts, fold (deriveMessages/convertMessage/
  extractText), engine (immutable session store, retry-as-new-run Q6),
  adapter (ExternalStoreAdapter with inline thread list), use-mock-chat
- add pure-logic unit tests for fold + scripts
- fix repo-level gate breakage blocking preview deploys: restore
  react-dropzone dep (removed with app-example), sync its accept prop to
  v12 typing, re-add SyncEngine source/secret to sst-env.d.ts, bump
  zustand to v5 (assistant-ui useShallow), hoist collapsible keyframes
  out of the @theme block in app.css

* feat(web): move prototype chat sessions into sidebar Recent chats

- AppSidebar adopts the mock chat while /app/prototype-chat is active:
  'New chat' now creates a session, 'Recent chats' lists the mock
  sessions (active highlight, running dot, delete action)
- NavMockChats: mock sessions rendered as a sidebar group wired to the
  mock engine
- NavMain: items can render as buttons (onClick) instead of links
- ChatRail: drop the sessions aside (now in the sidebar); full-width
  thread baseline for the variant comparison
- thread.tsx: message content uses text-base (14px) to match the app
  base size instead of inheriting the 16px browser default

* fix(web): show suggestions in prototype new-chat welcome view

The composer.isEmpty gate never fired with the external-store runtime, so
welcome-state suggestions were dropped on empty threads. Gate on the
new-chat view alone; suggestions stay visible while composing.

* fix(web): render welcome-state suggestions from thread suggestions

ThreadPrimitive.Suggestions subscribes to the s.suggestions scope, which
external-store runtimes never populate (fallback is an empty resource), so
welcome-state suggestion pills never rendered on empty threads. Render them
directly from s.thread.suggestions via ThreadPrimitive.Suggestion, which
takes the prompt and works with our adapter.

* feat(web): add chat previews to prototype sidebar

* feat(web): use chat previews as sidebar labels

* fix(web): use modal chat rename and normalize markdown text

* fix(web): normalize user message paragraph size

* feat(web): enable prototype chat attachments

* feat(web): wire prototype attachment uploads

* fix(web): keep prototype switcher clear of composer
* docs: resolve chat persistence schema & Electric sync design (iss-016) — four tables, backend-owned writes, terminal-ack run lifecycle

* docs: resolve chat UX design (iss-017) — per-session events hook, single-bubble render, retry semantics; frontier → iss-018

* feat(web): prototype chat UX layouts on assistant-ui ExternalStoreRuntime (iss-017)

Three switchable layout variants (rail / breadcrumb-menu / document-flow)
for the chat sessions chrome, driven by an in-memory mock of the locked
Q1-Q8 events model, hosted at /app/prototype-chat with a ?variant= search
param and a floating switcher.

- add assistant-ui registry components (thread, thread-list, markdown,
  tools, suggestions, attachments); keep Structa primitives; drop the
  composer stop button (Q7) and gate sending while a run is in-flight
- add lib/chat-mock: types, scripts, fold (deriveMessages/convertMessage/
  extractText), engine (immutable session store, retry-as-new-run Q6),
  adapter (ExternalStoreAdapter with inline thread list), use-mock-chat
- add pure-logic unit tests for fold + scripts
- fix repo-level gate breakage blocking preview deploys: restore
  react-dropzone dep (removed with app-example), sync its accept prop to
  v12 typing, re-add SyncEngine source/secret to sst-env.d.ts, bump
  zustand to v5 (assistant-ui useShallow), hoist collapsible keyframes
  out of the @theme block in app.css

* feat(web): move prototype chat sessions into sidebar Recent chats

- AppSidebar adopts the mock chat while /app/prototype-chat is active:
  'New chat' now creates a session, 'Recent chats' lists the mock
  sessions (active highlight, running dot, delete action)
- NavMockChats: mock sessions rendered as a sidebar group wired to the
  mock engine
- NavMain: items can render as buttons (onClick) instead of links
- ChatRail: drop the sessions aside (now in the sidebar); full-width
  thread baseline for the variant comparison
- thread.tsx: message content uses text-base (14px) to match the app
  base size instead of inheriting the 16px browser default

* fix(web): show suggestions in prototype new-chat welcome view

The composer.isEmpty gate never fired with the external-store runtime, so
welcome-state suggestions were dropped on empty threads. Gate on the
new-chat view alone; suggestions stay visible while composing.

* fix(web): render welcome-state suggestions from thread suggestions

ThreadPrimitive.Suggestions subscribes to the s.suggestions scope, which
external-store runtimes never populate (fallback is an empty resource), so
welcome-state suggestion pills never rendered on empty threads. Render them
directly from s.thread.suggestions via ThreadPrimitive.Suggestion, which
takes the prompt and works with our adapter.

* feat(web): add chat previews to prototype sidebar

* feat(web): use chat previews as sidebar labels

* fix(web): use modal chat rename and normalize markdown text

* fix(web): normalize user message paragraph size

* feat(web): enable prototype chat attachments

* feat(web): wire prototype attachment uploads

* fix(web): keep prototype switcher clear of composer

* fix(ci): make PR environment cleanup recoverable
* docs: map production chat workspace execution

* feat(chat): add persisted conversation foundation

* feat(chat): add Clerk run contract foundation

* feat(chat): wire Clerk provider run persistence

* fix(ci): allow providerless PR chat previews

* fix(deploy): keep previews providerless and resolve core drizzle

* feat(chat): promote production workspace into app

* feat(chat): persist new conversations on first send

* perf(preview): use generated URLs for PR environments

* fix(chat): include project context in run requests

* docs(ci): clarify generated preview URLs

* fix(ci): publish actual preview resource URLs

* fix(ci): resolve preview URLs from SST resources

* fix(ci): expose actual SST preview endpoints

* fix(ci): use stack Web and Api outputs

* feat(chat): switch Clerk provider to OpenRouter

* feat(ci): allow OpenRouter credentials in preview deploys

* fix(ci): use SST OpenRouter fallback in previews

* fix(infra): rename OpenRouter SST secret

* feat(chat): add durable production conversation runtime

* feat(chat): improve conversation navigation and actions

* chore(dev): add Caddy HTTP2 development proxy

* docs(architecture): map durable automation platform

* style(marketing): normalize navigation typography

* feat(chat): seal Cloudflare env, harden data service materialize

- Remove Cloudflare `environment` block; DB URL, DataServiceToken and
  OpenRouter key now flow only via SST link -> secret_text bindings
  (previously readable as plain_text through the Workers settings API)
- env.ts: parse `SST_RESOURCE_*` link bindings (Database/DataServiceToken/
  OpenRouterApiKey) with per-secret getters and OPENROUTER_MODEL fallback
- materialize: skip gracefully when the chat_sessions row is missing (direct
  Worker calls without a backend-created session must not flip a run to error)
- run materialize after the run-complete broadcast, wrapped in its own
  try/catch so a Neon failure can never change the run outcome
- core package.json: exact exports keys for ./conversation/chat.sql and
  ./conversation/conversation.sql (double-wildcard keys are invalid)
- infra api/web: use dataService.url instead of dataService.properties.url
- fix unused handleWebSocket param (biome)

* test(functions): add data service E2E verification scripts

Repeatable E2E suites for the Cloudflare data service:
- e2e-data-service.mjs: 15 checks — auth, tickets, run lifecycle, WS
  stream, DO SQLite persistence, event replay (service-auth path)
- e2e-materialize.mjs: 8 checks — Neon materialization happy path
  (assistant message, run complete, last_message_at bump, relative
  baseline compare to stay timezone-robust)

Usage: DATA_SERVICE_TOKEN=$TOKEN node scripts/e2e-data-service.mjs [base-url]
       DATA_SERVICE_TOKEN=$TOKEN DATABASE_URL=$URL node scripts/e2e-materialize.mjs [base-url]

* chore(functions): add npm scripts for data service E2E suites
* feat(chat): ship persisted conversation foundation to production (#75)

* ci: add --print-logs to PR Cleanup SST commands for diagnostics

* docs: reorganize docs/ into space-based structure

* docs: remove old docs/ structure (migrated to docs/core/)

* docs: migrate issues to .issues/ with template

* docs: migrate specs to .plan/ and remove dormant artifacts

* docs: update all references to new doc paths

* feat: add GitHub issue sync, agent skills setup, and chat wayfinder map

* docs: resolve chat wayfinder decisions — durable stream architecture (iss-014) and TanStack AI stack (iss-013)

* docs: resolve chat run endpoint & transport decision (iss-015) — web proxy, server-loaded history, gpt-5.6-luna

* feat: Removes app-example package, no longer needed as a reference

* feat: Removes marketing-site-example package, not longer needed as a reference

* feat: Updates app.css and styling of components in components/ui

* feat(web): prototype chat UX layouts (iss-017) — rail / breadcrumb / document-flow (#72)

* docs: resolve chat persistence schema & Electric sync design (iss-016) — four tables, backend-owned writes, terminal-ack run lifecycle

* docs: resolve chat UX design (iss-017) — per-session events hook, single-bubble render, retry semantics; frontier → iss-018

* feat(web): prototype chat UX layouts on assistant-ui ExternalStoreRuntime (iss-017)

Three switchable layout variants (rail / breadcrumb-menu / document-flow)
for the chat sessions chrome, driven by an in-memory mock of the locked
Q1-Q8 events model, hosted at /app/prototype-chat with a ?variant= search
param and a floating switcher.

- add assistant-ui registry components (thread, thread-list, markdown,
  tools, suggestions, attachments); keep Structa primitives; drop the
  composer stop button (Q7) and gate sending while a run is in-flight
- add lib/chat-mock: types, scripts, fold (deriveMessages/convertMessage/
  extractText), engine (immutable session store, retry-as-new-run Q6),
  adapter (ExternalStoreAdapter with inline thread list), use-mock-chat
- add pure-logic unit tests for fold + scripts
- fix repo-level gate breakage blocking preview deploys: restore
  react-dropzone dep (removed with app-example), sync its accept prop to
  v12 typing, re-add SyncEngine source/secret to sst-env.d.ts, bump
  zustand to v5 (assistant-ui useShallow), hoist collapsible keyframes
  out of the @theme block in app.css

* feat(web): move prototype chat sessions into sidebar Recent chats

- AppSidebar adopts the mock chat while /app/prototype-chat is active:
  'New chat' now creates a session, 'Recent chats' lists the mock
  sessions (active highlight, running dot, delete action)
- NavMockChats: mock sessions rendered as a sidebar group wired to the
  mock engine
- NavMain: items can render as buttons (onClick) instead of links
- ChatRail: drop the sessions aside (now in the sidebar); full-width
  thread baseline for the variant comparison
- thread.tsx: message content uses text-base (14px) to match the app
  base size instead of inheriting the 16px browser default

* fix(web): show suggestions in prototype new-chat welcome view

The composer.isEmpty gate never fired with the external-store runtime, so
welcome-state suggestions were dropped on empty threads. Gate on the
new-chat view alone; suggestions stay visible while composing.

* fix(web): render welcome-state suggestions from thread suggestions

ThreadPrimitive.Suggestions subscribes to the s.suggestions scope, which
external-store runtimes never populate (fallback is an empty resource), so
welcome-state suggestion pills never rendered on empty threads. Render them
directly from s.thread.suggestions via ThreadPrimitive.Suggestion, which
takes the prompt and works with our adapter.

* feat(web): add chat previews to prototype sidebar

* feat(web): use chat previews as sidebar labels

* fix(web): use modal chat rename and normalize markdown text

* fix(web): normalize user message paragraph size

* feat(web): enable prototype chat attachments

* feat(web): wire prototype attachment uploads

* fix(web): keep prototype switcher clear of composer

* fix(ci): make PR environment cleanup recoverable (#73)

* docs: resolve chat persistence schema & Electric sync design (iss-016) — four tables, backend-owned writes, terminal-ack run lifecycle

* docs: resolve chat UX design (iss-017) — per-session events hook, single-bubble render, retry semantics; frontier → iss-018

* feat(web): prototype chat UX layouts on assistant-ui ExternalStoreRuntime (iss-017)

Three switchable layout variants (rail / breadcrumb-menu / document-flow)
for the chat sessions chrome, driven by an in-memory mock of the locked
Q1-Q8 events model, hosted at /app/prototype-chat with a ?variant= search
param and a floating switcher.

- add assistant-ui registry components (thread, thread-list, markdown,
  tools, suggestions, attachments); keep Structa primitives; drop the
  composer stop button (Q7) and gate sending while a run is in-flight
- add lib/chat-mock: types, scripts, fold (deriveMessages/convertMessage/
  extractText), engine (immutable session store, retry-as-new-run Q6),
  adapter (ExternalStoreAdapter with inline thread list), use-mock-chat
- add pure-logic unit tests for fold + scripts
- fix repo-level gate breakage blocking preview deploys: restore
  react-dropzone dep (removed with app-example), sync its accept prop to
  v12 typing, re-add SyncEngine source/secret to sst-env.d.ts, bump
  zustand to v5 (assistant-ui useShallow), hoist collapsible keyframes
  out of the @theme block in app.css

* feat(web): move prototype chat sessions into sidebar Recent chats

- AppSidebar adopts the mock chat while /app/prototype-chat is active:
  'New chat' now creates a session, 'Recent chats' lists the mock
  sessions (active highlight, running dot, delete action)
- NavMockChats: mock sessions rendered as a sidebar group wired to the
  mock engine
- NavMain: items can render as buttons (onClick) instead of links
- ChatRail: drop the sessions aside (now in the sidebar); full-width
  thread baseline for the variant comparison
- thread.tsx: message content uses text-base (14px) to match the app
  base size instead of inheriting the 16px browser default

* fix(web): show suggestions in prototype new-chat welcome view

The composer.isEmpty gate never fired with the external-store runtime, so
welcome-state suggestions were dropped on empty threads. Gate on the
new-chat view alone; suggestions stay visible while composing.

* fix(web): render welcome-state suggestions from thread suggestions

ThreadPrimitive.Suggestions subscribes to the s.suggestions scope, which
external-store runtimes never populate (fallback is an empty resource), so
welcome-state suggestion pills never rendered on empty threads. Render them
directly from s.thread.suggestions via ThreadPrimitive.Suggestion, which
takes the prompt and works with our adapter.

* feat(web): add chat previews to prototype sidebar

* feat(web): use chat previews as sidebar labels

* fix(web): use modal chat rename and normalize markdown text

* fix(web): normalize user message paragraph size

* feat(web): enable prototype chat attachments

* feat(web): wire prototype attachment uploads

* fix(web): keep prototype switcher clear of composer

* fix(ci): make PR environment cleanup recoverable

* feat(chat): add persisted conversation foundation (#74)

* docs: map production chat workspace execution

* feat(chat): add persisted conversation foundation

* feat(chat): add Clerk run contract foundation

* feat(chat): wire Clerk provider run persistence

* fix(ci): allow providerless PR chat previews

* fix(deploy): keep previews providerless and resolve core drizzle

* feat(chat): promote production workspace into app

* feat(chat): persist new conversations on first send

* perf(preview): use generated URLs for PR environments

* fix(chat): include project context in run requests

* docs(ci): clarify generated preview URLs

* fix(ci): publish actual preview resource URLs

* fix(ci): resolve preview URLs from SST resources

* fix(ci): expose actual SST preview endpoints

* fix(ci): use stack Web and Api outputs

* feat(chat): switch Clerk provider to OpenRouter

* feat(ci): allow OpenRouter credentials in preview deploys

* fix(ci): use SST OpenRouter fallback in previews

* fix(infra): rename OpenRouter SST secret

* feat(chat): add durable production conversation runtime

* feat(chat): improve conversation navigation and actions

* chore(dev): add Caddy HTTP2 development proxy

* docs(architecture): map durable automation platform

* style(marketing): normalize navigation typography

* feat(chat): seal Cloudflare env, harden data service materialize

- Remove Cloudflare `environment` block; DB URL, DataServiceToken and
  OpenRouter key now flow only via SST link -> secret_text bindings
  (previously readable as plain_text through the Workers settings API)
- env.ts: parse `SST_RESOURCE_*` link bindings (Database/DataServiceToken/
  OpenRouterApiKey) with per-secret getters and OPENROUTER_MODEL fallback
- materialize: skip gracefully when the chat_sessions row is missing (direct
  Worker calls without a backend-created session must not flip a run to error)
- run materialize after the run-complete broadcast, wrapped in its own
  try/catch so a Neon failure can never change the run outcome
- core package.json: exact exports keys for ./conversation/chat.sql and
  ./conversation/conversation.sql (double-wildcard keys are invalid)
- infra api/web: use dataService.url instead of dataService.properties.url
- fix unused handleWebSocket param (biome)

* test(functions): add data service E2E verification scripts

Repeatable E2E suites for the Cloudflare data service:
- e2e-data-service.mjs: 15 checks — auth, tickets, run lifecycle, WS
  stream, DO SQLite persistence, event replay (service-auth path)
- e2e-materialize.mjs: 8 checks — Neon materialization happy path
  (assistant message, run complete, last_message_at bump, relative
  baseline compare to stay timezone-robust)

Usage: DATA_SERVICE_TOKEN=$TOKEN node scripts/e2e-data-service.mjs [base-url]
       DATA_SERVICE_TOKEN=$TOKEN DATABASE_URL=$URL node scripts/e2e-materialize.mjs [base-url]

* chore(functions): add npm scripts for data service E2E suites

* chore: decommission Electric Cloud infrastructure

* fix: normalize user dates before collection sync

* fix: settle user updates in collection state

* fix: make browser Buffer compatible with collection hashing

* fix: let query collection reconcile user updates

* fix: broadcast running chat runs for live streaming

* fix: navigate and refresh new chat sessions

* fix: normalize chat collection timestamps

* fix: keep optimistic user messages in chat order

* fix: preserve user before assistant run order

* chore: remove legacy chat event table
* fix: clean preview stages for closed PRs

* ci: deploy production through GitHub Actions
@github-actions

Copy link
Copy Markdown

Preview Environment

Property Value
Stage pr-81
Web URL https://d1j54d5unsck0k.cloudfront.net
API URL https://d23hj91nh48m8w.cloudfront.net

Quality checks passed
Deployment successful

This environment will be automatically cleaned up when the PR is closed or merged.

@imharrisonking
imharrisonking merged commit 70f03ac into production Sep 23, 2026
11 of 14 checks passed

This branch was successfully deployed

1 active deployment
dev — 951ca235 Deployed Sep 23, 2026 by imharrisonking via Destroy Preview Environment #24
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