Skip to content

fix: publish playground source with its Published switch - #696

Merged
davidmckayv merged 4 commits into
CopilotKit:mainfrom
Harbor404:fix/693-playground-publish-source
Oct 2, 2026
Merged

davidmckayv merged 4 commits into
CopilotKit:mainfrom
Harbor404:fix/693-playground-publish-source

Conversation

@Harbor404

Copy link
Copy Markdown
Contributor

What this changes

Fixes #693.

The generic Published switch used to call ComponentStore.publish for every component kind. For a sandboxed component that promoted only the governance row, so Bots were offered a component whose published_html was still null.

This change makes the generic component store refuse to write a sandboxed publication itself. The publication route catches that signal and delegates to sandboxedStore, which now publishes or withdraws the source row, published description, argument schema, revision, and governance row in one PostgreSQL transaction. Missing playground source, empty HTML, or an empty description is answered with 409 and changes nothing. Re-publishing an unchanged draft is idempotent and records one audit event; unpublish withdraws both rows together.

Where it runs

  • New state that outlives a request? No new state or process-local cache. The existing sandboxed_components and components rows remain the state.
  • What happens on the second replica? Both replicas use the same PostgreSQL rows; publication is not held in a process.
  • Anything serialised? sandboxed_components.publish and unpublish run the two writes inside database.transaction, locking both rows with SELECT ... FOR UPDATE. The unchanged-publish branch is a no-op. No check-then-write outside a transaction is introduced.
  • Anything fanned out to a browser? No new fan-out. The existing published-source query observes the committed state.
  • New listener, port, or schedule? None.

Boundary and audit

  • The endpoint remains behind requireAdmin; no client-supplied source or actor is trusted.
  • Successful publish/unpublish is audited exactly once through the sandboxed store. Invalid or incomplete drafts are refused before any write and do not create a publication event.
  • The route no longer emits a second generic audit row when it delegates to the source-aware store.

Changelog

Added an Unreleased entry because playground publication behavior changes.

Proof

  • TEST_DATABASE_URL=... bun test server/tests/component-publication.test.ts server/tests/sandboxed-routes.test.ts server/tests/sandboxed-save-fields.test.ts server/tests/sandboxed-components.integration.test.ts server/tests/component-store.integration.test.ts server/tests/sandboxed-publication.integration.test.ts
    • 83 pass, 0 fail (213 expectations).
  • The new Postgres integration file proves: source and governance publish together; missing source and empty HTML/description return 409 without state; repeated publish keeps revision 1 and one audit event; a forced failure on the governance update rolls back the source write; unpublish clears both rows and removes the component from /api/sandboxed/published.
  • bun run typecheck — server, app, and worker pass.
  • bun run lint — 983 files, no fixes.
  • bun run format:check — 968 files, no fixes.
  • A full local bun test was also run. Component/publication tests passed; the remaining local-only failures were in separate bot fixtures that require their own CI-installed dependencies (Mastra/LangGraph were rechecked after installation and pass), plus agent-computer/tests/identity.test.ts, whose child process fails on this workspace's percent-encoded Chinese path rather than on the change.

@davidmckayv
davidmckayv merged commit 764a8fb into CopilotKit:main Oct 2, 2026
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.

The Published switch on a playground component publishes it without its source

2 participants