Skip to content

Conversation

@FadhlanR
Copy link
Contributor

@FadhlanR FadhlanR commented Jan 15, 2026

Purpose

This PR introduces a guard to prevent large amounts of data from being stored in cards.

Background

Card data can currently be inserted or updated through several pathways:

  • Editing card data from the stack item edit view in Interact submode
  • Editing card data in the code editor in Code submode
  • Patching a card via AI commands
  • Calling the realm endpoint directly

Without a guard, these paths can allow large payloads to enter the system.

Implementation

To address this, I implemented validateWriteSize function in both the host and the realm:

  • Host-level guard:
    Implemented to fail early for scenarios that originate in the host.

  • Realm-level guard:
    Added as a second line of defense to ensure protection even when requests reach the realm directly.

Error Handling by Scenario

  • Interact submode and Code submode:
    Errors are thrown directly and surfaced to the user immediately.

  • AI-based patching:
    I extended the check correctness command to retrieve the card limit error from cardService, so we can handle errors originating from:

    • patch-code command
    • patch-card-instance command

I’m open to alternative approaches here if there’s a better way to handle validation or error propagation for AI-driven updates.

Interact Submode:

Screenshot 2026-01-19 at 15 45 39

Code Submode:

Screenshot 2026-01-19 at 15 44 25

@github-actions
Copy link

Preview deployments

@github-actions
Copy link

github-actions bot commented Jan 15, 2026

Host Test Results

    1 files  ± 0      1 suites  ±0   1h 46m 35s ⏱️ + 7m 11s
1 902 tests +15  1 885 ✅ +13  17 💤 +2  0 ❌ ±0 
1 917 runs  +15  1 900 ✅ +13  17 💤 +2  0 ❌ ±0 

Results for commit 31d2f38. ± Comparison against base commit 10d957c.

This pull request removes 5 and adds 20 tests. Note that renamed tests count towards both.
Chrome ‑ Unit | card-menu-items: ai-assistant context contains Copy to Workspace when editable
Chrome ‑ Unit | card-menu-items: ai-assistant context omits Copy to Workspace when not editable
Chrome ‑ Unit | card-menu-items: code-mode-playground includes sample-data tagged items and Open in Code Mode
Chrome ‑ Unit | card-menu-items: code-mode-preview includes Copy Card URL and Open in Interact Mode
Chrome ‑ Unit | card-menu-items: interact context includes Copy Card URL and (when editable) New Card of This Type and Delete
Chrome ‑ Acceptance | Spec preview: shows cannot create spec message for subclasses of spec 
Chrome ‑ Acceptance | code submode tests > single realm: code editor shows size limit error when json save exceeds limit
Chrome ‑ Acceptance | code submode | file def navigation: clicking embedded file in preview opens markdown file in code mode
Chrome ‑ Acceptance | code submode | head format preview: head format preview updates when editing card json
Chrome ‑ Acceptance | code-submode | card playground > single realm: playground does not auto-create spec for subclasses of specs
Chrome ‑ Acceptance | interact submode tests > size limit errors: edit view shows size limit error when save exceeds limit
Chrome ‑ Acceptance | markdown file def: extracts title and excerpt from markdown
Chrome ‑ Acceptance | markdown file def: falls back when markdown def is used for non-markdown files
Chrome ‑ Acceptance | markdown file def: indexing stores markdown search data and file meta uses it
Chrome ‑ Integration | Command | create-specs: throws error when creating a spec from another spec
…
This pull request skips 2 tests.
Chrome ‑ Integration | ai-assistant-panel | commands: command that returns a CardForAttachmentCard result is specially handled to attach the card
Chrome ‑ Integration | ai-assistant-panel | commands: command that returns a FileForAttachmentCard result is specially handled to attach the file

♻️ This comment has been updated with latest results.

@FadhlanR FadhlanR marked this pull request as ready for review January 19, 2026 12:00
@FadhlanR FadhlanR requested a review from a team January 19, 2026 12:00
@FadhlanR
Copy link
Contributor Author

@codex review

Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: a3ddefa247

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +81 to +85
let sizeLimitError = this.cardService.getSizeLimitError(input.targetRef);
if (sizeLimitError) {
return new CorrectnessResultCard({
correct: false,
errors: [sizeLimitError.message],

Choose a reason for hiding this comment

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

P2 Badge Ensure size-limit errors are available before correctness

This early return relies on cardService.getSizeLimitError() being populated, but that map is only set when validateSizeLimit runs during the async persist flow. For AI patch commands that call store.patch with doNotWaitForPersist (e.g., PatchCardInstanceCommand/PatchCodeCommand), CheckCorrectnessCommand can run before the save reaches validation, so it will report correct: true even though the write later fails with a 413. Consider validating size synchronously before returning from the patch commands or ensuring correctness checks wait for the persist attempt to complete so the size-limit error is guaranteed to be recorded.

Useful? React with 👍 / 👎.

Copy link
Contributor

@lukemelia lukemelia left a comment

Choose a reason for hiding this comment

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

LGTM. I'd like to make sure @habdelra reviews this and weighs in on what a suitable limit value is.

cardRenderTimeout: Number(
process.env.RENDER_TIMEOUT_MS ?? DEFAULT_CARD_RENDER_TIMEOUT_MS,
),
cardSizeLimit: Number(process.env.CARD_SIZE_LIMIT ?? 64 * 1024),
Copy link
Contributor

Choose a reason for hiding this comment

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

Adjust name or add comment indicating units (bytes, I assume?)

Copy link
Contributor

Choose a reason for hiding this comment

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

why do we hard code 64 *1024 twice? once here and once in runtime-common. let's just have a single place for this constant

fromScratchIndexPriority?: number;
}

const DEFAULT_CARD_SIZE_LIMIT = 64 * 1024;
Copy link
Contributor

Choose a reason for hiding this comment

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

i think this is 64KB (please add units to this env var name). if so, i think that is a perfectly fine limit.

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR introduces safeguards to prevent large payloads from being stored in cards by implementing size validation at both the host and realm levels.

Changes:

  • Added a shared validateWriteSize function to validate content size against a configurable limit
  • Implemented host-level validation in card-service to fail early for client-originated requests
  • Implemented realm-level validation as a second line of defense for direct realm endpoint calls
  • Extended the check-correctness command to retrieve and report size limit errors from AI-based patching operations

Reviewed changes

Copilot reviewed 19 out of 20 changed files in this pull request and generated 7 comments.

Show a summary per file
File Description
packages/runtime-common/write-size-validation.ts New shared utility function for validating content size against byte limits
packages/runtime-common/realm.ts Added realm-level size validation with CardError responses and configurable size limit
packages/runtime-common/index.ts Exported validateWriteSize function for use in other packages
packages/realm-server/tests/helpers/index.ts Added cardSizeLimit parameter to test helper functions
packages/realm-server/tests/card-source-endpoints-test.ts Added test coverage for 413 errors when source file payloads exceed size limit
packages/realm-server/tests/card-endpoints-test.ts Added test coverage for 413 errors when card payloads exceed size limit
packages/realm-server/server.ts Added cardSizeLimit property and passed it to realm instances
packages/realm-server/main.ts Passed cardSizeLimit configuration when creating realm instances
packages/host/tests/integration/commands/check-correctness-test.gts Added tests for size limit error reporting in file and card writes via commands
packages/host/tests/helpers/index.gts Passed cardSizeLimit configuration when setting up test realm
packages/host/tests/acceptance/interact-submode-test.gts Added test for size limit error display in interact submode edit view
packages/host/tests/acceptance/code-submode-test.ts Added test for size limit error display in code submode editor
packages/host/config/environment.js Added cardSizeLimit configuration with default value of 64KB
packages/host/app/services/environment-service.ts Added cardSizeLimit property to environment service
packages/host/app/services/card-service.ts Implemented host-level size validation with error tracking for check-correctness command
packages/host/app/config/environment.d.ts Added cardSizeLimit type definition to config
packages/host/app/components/operator-mode/code-submode/editor-indicator.gts Added error message display styling and logic to editor indicator
packages/host/app/components/operator-mode/code-submode.gts Added writeError state tracking and onWriteError handler
packages/host/app/components/operator-mode/code-editor.gts Added error handling for write operations with error message propagation
packages/host/app/commands/check-correctness.ts Added size limit error retrieval from cardService for AI-based patching scenarios

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

#definitionLookup: DefinitionLookup;
#copiedFromRealm: URL | undefined;
#sourceCache = new AliasCache<SourceCacheEntry>();
#moduleCache = new AliasCache<ModuleCacheEntry>();
Copy link

Copilot AI Jan 19, 2026

Choose a reason for hiding this comment

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

The private field #cardSizeLimit is used to validate both card and file sizes, but the name only refers to cards. Consider renaming to something more generic like #writeSizeLimit or #maxPayloadSize to better reflect its dual purpose, or document that despite the name, it applies to both cards and files.

Suggested change
#moduleCache = new AliasCache<ModuleCacheEntry>();
#moduleCache = new AliasCache<ModuleCacheEntry>();
// Used to validate the size of both cards and files written to this realm.

Copilot uses AI. Check for mistakes.
cardRenderTimeout: Number(
process.env.RENDER_TIMEOUT_MS ?? DEFAULT_CARD_RENDER_TIMEOUT_MS,
),
cardSizeLimit: Number(process.env.CARD_SIZE_LIMIT ?? 64 * 1024),
Copy link

Copilot AI Jan 19, 2026

Choose a reason for hiding this comment

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

The configuration variable cardSizeLimit is used to validate both card and file sizes, but the name only refers to cards. This is consistent with the naming throughout the codebase, but it may be misleading. Consider renaming to something more generic like writeSizeLimit or maxPayloadSize in a future refactor to better reflect that it applies to both cards and files.

Copilot uses AI. Check for mistakes.
Comment on lines +1 to +5
export function validateWriteSize(
content: string,
maxSizeBytes: number,
type: 'card' | 'file',
): void {
Copy link

Copilot AI Jan 19, 2026

Choose a reason for hiding this comment

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

The function lacks documentation explaining its purpose, parameters, and when/how it should be used. Consider adding JSDoc comments to document the validation logic, especially since this is a shared utility that's used in multiple contexts (host and realm).

Copilot uses AI. Check for mistakes.
FadhlanR and others added 4 commits January 22, 2026 16:23
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
@FadhlanR FadhlanR merged commit e976e43 into main Jan 23, 2026
96 of 97 checks passed
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.

4 participants