hoai2026: levelbuilder update - #75109
Open
breville wants to merge 5 commits into
Open
Conversation
breville
force-pushed
the
hoai2026-levelbuilder-updates
branch
2 times, most recently
from
September 5, 2026 05:17
7bec7fc to
649506b
Compare
Newer lab flags ship before their editing UI: show_world_tab, guide_steps, visible_tabs and friends can only be set by editing .level files on a dev checkout. This injects a collapsed "Additional properties (JSON)" section onto the level edit page for saved Sprite Lab levels with Lab2 enabled. Entirely client-side — everything it needs from the server already exists: values come from the level_properties endpoint the lab itself reads, saves go through the levelbuilder-authorized update_properties endpoint App Lab's starter-code editor already uses, and the module rides the levelbuilder bundle the edit page already loads. The editable set is an explicit allowlist (RAW_EDITABLE_PROPERTIES): the dump enumerates exactly those keys (null = unset) and the box refuses everything else, so every other property keeps its own editor and the list doubles as the burndown of flags still lacking real UI. Replaces earlier exploratory commits on this branch (history rewritten pre-review), including a dashboard-side design whose endpoint hardening is parked for a possible separate PR. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
breville
force-pushed
the
hoai2026-levelbuilder-updates
branch
from
September 5, 2026 05:21
649506b to
9fbfc68
Compare
The dump always shows what the server stored: a successful save refetches level_properties (epoch-guarded against a stale in-flight load) instead of mirroring the submitted values client-side, which also retires the client's copy of the blank-stripping rule. "Saved." annotates itself when the box gained newer edits during the request and when the level is unpublished — an unpublished level's save reaches the database but not its .level file, so the next seed would drop it without a publish. A CodeMirror initialization failure puts the plain textarea back instead of leaving a hidden input. Both requests send Accept: application/json. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
CodeMirror's lint callback is debounced, so a lint pass for pre-save typing can land during the save window; the edited-during-save suffix now compares the box's text against what was sent instead of trusting lint timing. Caught by driving the editor the way a person does — click the heading, type into CodeMirror, click Save. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
"Editor chrome" in plain words. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
breville
marked this pull request as draft
September 6, 2026 23:35
breville
marked this pull request as ready for review
September 7, 2026 01:07
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
[written by Claude]
Newer Sprite Lab in Lab2 flags ship before their editing UI:
show_world_tab,guide_steps,visible_tabs,images_advancedand friends appear nowhere on the level edit page — today they can only be set by editing.levelfiles on a dev checkout. This adds an escape hatch: a collapsed "Additional properties (JSON)" section at the bottom of the level edit page, for saved Sprite Lab levels with Lab2 enabled.Entirely client-side
The PR is one JS module (plus its test and an import line) — not a single server change. Everything the feature needs already exists:
level_propertiesendpoint, the same one the lab itself reads.update_propertiesendpoint, which App Lab's starter-code editor has used for years, and which logs who changed what.An explicit allowlist, not a general property editor
The editable set is a constant — ten flags today. The dump enumerates exactly those keys, set or not (
null= unset), so it reads like a form of the available knobs, and the box refuses any other key with "…isn't in this level's editable list." Every other property keeps its own editor — form fields, the blocks editors, the encrypted values — by construction, and the list doubles as the working list of flags still waiting for real UI: remove an entry when its editor lands, and the section retires with the last one.null— or to any empty or false value — is removed: properties store no blanks, so flags aretrueor absent. The help text says all of this.null) — it is the documented copy-source for nested edits, so it must never show submitted-but-unstored values. The "Saved." status annotates itself when the box holds edits newer than what was saved, and when the level is unpublished — an unpublished level's save reaches the database but not its.levelfile, so it warns to publish before the value can survive a seed. The section sits outside the level form on purpose: it saves through its own endpoint, and sharing the form's submit or dirty-check machinery would discard unsaved edits elsewhere on the page.Screenshot
Testing
level_propertiesserves and saved by the stored snake_case names). Because a save refetches rather than mirroring, the client never needs its own copy of the server's blank-stripping rule.{"show_world_tab": true}into CodeMirror, click Save — and the level itself gains the World tab on next load; typingnulland saving removes it again. The dump shows all ten keys (nullfor unset, real values for set ones), a non-allowlisted key (start_html) is refused with a plain message, and on this unpublished scratch level the save status carried the publish-to-persist warning. On a classic (non-Lab2) Sprite Lab level the section does not render. Lint andyarn run typecheckpass.History note
This branch was rewritten before review: earlier exploratory commits built the same feature server-side (a haml partial, a model allowlist, and
update_propertiesendpoint hardening). The endpoint hardening — refusing encrypted properties and their plaintext twins, 400s with reasons for malformed bodies and values the save hooks reject — is parked as a candidate separate PR, since it protects the endpoint's other callers and is orthogonal to this UI.