Skip to content

fix(contracts): reject project script ids that cannot form keybinding commands - #7947

Closed
IzonIcy wants to merge 2 commits into
pingdotgg:mainfrom
IzonIcy:fix/project-script-id-keybinding-crash
Closed

fix(contracts): reject project script ids that cannot form keybinding commands#7947
IzonIcy wants to merge 2 commits into
pingdotgg:mainfrom
IzonIcy:fix/project-script-id-keybinding-crash

Conversation

@IzonIcy

@IzonIcy IzonIcy commented Aug 23, 2026

Copy link
Copy Markdown

What changed

packages/contracts: the identifier portion of SCRIPT_RUN_COMMAND_PATTERN is extracted into an exported ProjectScriptId schema (single source of truth), and ProjectScript.id now uses it instead of TrimmedNonEmptyString. Behavior change is exactly one: commands carrying script ids that cannot form a valid script.<id>.run keybinding command are rejected with a schema error at the dispatch boundary instead of being persisted.

Two new tests in orchestration.test.ts: the UUID id from #7851's repro now fails to decode; a conforming id still passes.

Why

Fixes #7851, using its first suggested direction. The web client calls commandForProjectScript(script.id) (SCRIPT_RUN_COMMAND_PATTERN.make("script." + id + ".run")) while rendering thread views and Settings → Projects. The server accepted any trimmed non-empty id, so one dispatched UUID poisoned every read model of that project and both surfaces threw inside the React error boundary with no in-app way to repair — the persisted data re-threw on every render.

Client-side tolerance was the alternative direction, but it would add null-handling through ~10 keybinding call sites to accommodate input the system never intended to accept. Rejecting at the schema keeps orchestration pure and the client dumb. UI-created ids already conform via normalizeScriptId, so nothing changes for normal flows. Note this prevents new poison but does not migrate already-poisoned projects — happy to look at a cleanup path if maintainers want one.

Verification

  • Failing-test-first: with the old schema stashed, the UUID test fails (server accepts the poison), passes after
  • contracts suite 268/268 · server orchestration suite 273/273 · web projectScripts suites 13/13
  • Scoped typecheck clean

--
Worked by ox-alpha via opencode (x-preview-f-free).


Note

Medium Risk
Tightens decode of project scripts and related events/commands. Existing payloads with UUID or otherwise non-conforming ids will now fail schema decode rather than persist or render.

Overview
Stops persisting project script ids that cannot form a valid script.<id>.run keybinding. The web client rebuilds that command while rendering, so a UUID (or other non-conforming id) previously poisoned the project and crashed thread/settings views.

Exports a shared ProjectScriptId schema (lowercase alphanumerics/hyphens, max length) and uses it for both SCRIPT_RUN_COMMAND_PATTERN and ProjectScript.id. Tests cover rejecting a UUID and accepting a conforming id.

Does not migrate already-poisoned projects; it only blocks new ones. UI-created ids already go through normalizeScriptId / nextProjectScriptId.

Reviewed by Cursor Bugbot for commit f5999a9. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Reject project script IDs that cannot form keybinding commands

Adds a ProjectScriptId schema that enforces lowercase alphanumerics and hyphens (starting alphanumeric, within MAX_SCRIPT_ID_LENGTH). Changes ProjectScript.id from TrimmedNonEmptyString to this schema so payloads with non-conforming IDs fail decoding. The SCRIPT_RUN_COMMAND_PATTERN now reuses ProjectScriptId for the script-id portion.

  • Risk: ProjectScript.id decoding now rejects IDs like UUIDs or strings with uppercase/underscores; existing payloads with such IDs will fail to decode.

Macroscope summarized f5999a9.

… commands

ProjectScript.id validated as TrimmedNonEmptyString, but the web client
rebuilds `script.<id>.run` keybinding commands while rendering thread
views and project settings. An id outside that pattern's constraint
(e.g. a UUID) persisted fine via project.meta.update, then threw inside
the React error boundary on every thread view of the project — with no
way to repair it from Settings.

Tighten ProjectScript.id to the same constraint as the identifier
portion of SCRIPT_RUN_COMMAND_PATTERN by extracting it as ProjectScriptId
(single source of truth), so the server rejects such commands with a
schema error instead of poisoning read models. Conforming ids decode
unchanged; UI-created ids already satisfy the pattern via
normalizeScriptId.

Covers pingdotgg#7851 (option 1).
Copilot AI lite review requested due to automatic review settings August 23, 2026 00:33

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@github-actions github-actions Bot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:S 10-29 changed lines (additions + deletions). labels Aug 23, 2026
@coderabbitai

coderabbitai Bot commented Aug 23, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 8db2d871-a0d1-4fe8-a4eb-69690e346477

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@macroscopeapp

macroscopeapp Bot commented Aug 23, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Skipped

Macroscope did not run approvability analysis for this PR. Macroscope could not determine whether this PR modifies its approvability configuration, so the PR was not approved automatically. A PR that may change the rules that govern approval is never approved automatically.

@t3dotgg

t3dotgg commented Aug 27, 2026

Copy link
Copy Markdown
Member

Note

🤖 GPT-5.6 Sol responding on behalf of Theo

We're closing this PR as we clean up the T3 Code backlog. Thank you for taking the time to put this together.

Closing this alternative in favor of #7961. Tightening ProjectScript.id also changes decoding of scripts that may already be stored. The retained approach accepts existing IDs when building keybinding commands instead of rejecting their saved data. Please preserve the failing command case in that compatible fix. #7961 is still open.

If you believe we closed this in error, please reopen the PR and leave a comment explaining what we missed. If GitHub does not let you reopen it, leave a comment here and we'll take another look.

@t3dotgg t3dotgg closed this Aug 27, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:S 10-29 changed lines (additions + deletions). vouch:unvouched PR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Server accepts project script ids that the client keybinding schema rejects, every thread view of the project crashes

3 participants