Skip to content

Release v1.16.0 - #3767

Merged
nighca merged 158 commits into
mainfrom
dev
Nov 13, 2026
Merged

nighca merged 158 commits into
mainfrom
dev

Conversation

@nighca

@nighca nighca commented Nov 12, 2026 •

Copy link
Copy Markdown
Collaborator

[skip review]

Deployment Notes

#3650 — Progressive Course video playback

Keep the existing COEP/COOP headers. Content endpoints must allow anonymous CORS, including Range responses, and retain byte-range support. Production/CN CDN configuration was not verified by the child PR.

#3722 — Tutorial v2 backend coordination

Ensure the target backend includes goplus/builder-backend#418 and exposes the Tutorial v2 Course/Series APIs before enabling learning and authoring flows. Collaboration previews and local development now use standard staging defaults.

#3728 — Frontend directory rename

Coordinate the Vercel xgo-team/builder Root Directory change from spx-gui to gui, then retry deployment. This project-wide setting also affects older branches. Update repository ruleset 324471's required check from spx-gui-lint to gui-lint. The child PR did not change these external settings; verify their current state before rollout.

#3706 — Feedback replies

Deploy goplus/builder-backend#416 before enabling feedback replies. The notification panel also depends on the existing endpoints from goplus/builder-backend#355.

#3690 — Account API compatibility

Deploy the matching Account admin console together with the backend cutover in goplus/builder-backend#426. Pause Account writes and stop all old backend instances before migration 023_account_oauth_clients runs; old backends cannot use the migrated schema. Follow the backend release PR for migration order and recovery constraints. App registration no longer accepts OAuth client settings; clients and secrets use the app's oauth-clients resources, and administrator-issued user tokens require oauthClientID.

nighca and others added 30 commits August 14, 2026 09:32
* docs: add playground course tech design

* docs: remove tutorial v2 design

* docs: refine playground course tech design

* docs: simplify playground course interfaces

* docs: refine playground course component contracts

* docs: refine tutorial assets and copilot APIs

* docs: derive tutorial JSON schemas from structs

* docs: update playground course module diagram

* docs: name course playground entry

* docs: correct playground module ownership

* docs: rename tutorial v2 tech design

* docs: align tutorial v2 module boundaries

* docs: correct course storage indexes

* docs: refine tutorial v2 contracts
showPrelude(preludeMessage) displays the Course opening guide, mirroring
the existing course-prelude concept from the current course system. It
blocks until the learner dismisses it, like showMessage; how the host
renders the opening guide is up to the Tutorial implementation. The
example course now opens with showPrelude instead of showMessage.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
docs: amend Tutorial v2 presentation and Spotlight contracts
- Capitalize SpotlightOptions fields (XGo auto-lowercasing applies to
  functions only, not struct fields)
- Replace persist with duration: the auto-conceal delay in seconds,
  where 0 keeps the spotlight until the learner clicks anywhere
- Unify the options type name across the Go and TS contracts
- Drop the pointer-events behavior assertion; interaction details
  follow the UI design
- Note in the host contract that reveal's defaults are materialized by
  createTutorialFramework before spotlight_reveal is invoked
- Align the product docs with the persist-by-default behavior (dismissed
  by the learner's click; no delay-based auto-conceal in the default path)

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
* feat: add browser XGo executor

* refactor: reorganize XGo executor modules

* refactor: flatten XGo executor frontend files

* docs: document frontend XGo executor

* refactor: move Tutorial binding into executor bundle

* docs: add Tutorial XGo project config

* refactor: flatten Tutorial framework package

* fix: harden XGo executor lifecycle

* refactor: rename frontend XGo executor module

* fix: use current XGo package marker

* feat: add XGo executor debug page

* feat: validate Tutorial capabilities and events

* chore: mark XGo debug page as temporary

* refactor: simplify Tutorial event handling

* fix: avoid deadlock in Tutorial events
* docs(tutorial): define video resources by name

* docs(tutorial): address video resource review

* docs(tutorial): clarify video name contract

* docs(tutorial): keep module overview focused
* docs: formalize Tutorial events and remaining contract semantics

- Add the TutorialEvent contract: editor.runtime.start / editor.runtime.exit
  / editor.runtime.log / copilot.roundFinish, dispatched by Tutorial, with
  per-entry, in-order, log-kind-only semantics for runtime logs
- Specify Course completion semantics: complete/completeWith end the program
  after the current callback returns; later presentation calls are ignored
  and repeated completions are idempotent; document how executor exit
  reasons map to Course outcomes
- Activate editor.project with session-project-model reading:
  getCode(file) and listCodeFiles(), mirrored as editor_project_* host
  capabilities; document codeEditor.getCode's attached-UI semantics
- Annotate resolve timing for Promise-returning host capabilities
  (completion accepted, formatting finished, spotlight shown)
- Publish the initial stable spotlight target ID list (append-only,
  owned by the SPX Project Editor)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* docs: apply #3439 review feedback

- Mirror the spotlight target-ID list into the author-facing Go contract
- Reword course_completeWith to avoid contradicting course_complete's
  "without feedback" phrasing
- Align the runtime-log channel wording with the Go contract instead of
  the undefined "judging channel" term
- Confine editor_project_getCode resolution to the listCodeFiles set and
  reject path traversal and absolute paths
- Document the runtime-log adaptation against the real Runtime: diff by
  the per-entry monotonic id (outputs is a bounded ring buffer whose
  indices shift once full) and fan out batched didChangeOutput
  notifications in order; add the missing id field to RuntimeOutput

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* docs: define the API identifier vocabulary and spotlight target grammar

- Pin filterAPIs entries to the editor's definition-identifier scheme:
  author shorthand "name" / "name#overloadId" resolved in the Course
  project's API context, or a full "xgo:<package>?<name>#<overloadId>"
  string; an identifier without "#overloadId" addresses all overloads
- Extend spotlight targets with a parameterized family:
  "apiReference.<apiId>" addresses API Reference entries using the same
  identifiers as filterAPIs; a bare name highlights the whole overload
  group together
- Specify failure semantics: unknown IDs (name outside the vocabulary,
  nonexistent overload, unpublished static ID) fail the capability call
  so mistakes surface during Preview; known IDs that cannot currently be
  resolved (filtered out, not mounted yet) retry briefly, then skip the
  highlight with a warning

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* docs: apply #3439 review feedback on scope and contract shape

- Drop the RuntimeOutput id field again: retrieval by output id has no
  concrete requirement yet, and may belong to the runtime module rather
  than being collected through Tutorial
- Keep index.md at module positioning: remove the didChangeOutput
  adaptation detail and replace the interface enumeration with a
  responsibility-level description; the executor exit-reason mapping
  moves to the Tutorial module contract, which owns that interpretation
- Use full definition identifiers for API identification: a shorthand
  would need mapping logic that cannot safely assume the package or
  receiver; overload selection by index stays
- Give codeEditor.getCode a file path and add getCurrentActiveDocument,
  which fails when no editor is attached, so "nothing is open" is never
  confused with "the open file is empty"; editor.project.getCode is
  therefore dropped, while listCodeFiles stays for Courses whose goal is
  for the learner to create a sprite
- Address spotlight targets with Radar selectors instead of a separate
  stable-ID registry; a selector matching several elements reveals them
  as one group, and failure is split into malformed (fails) versus
  currently unmatched (retries, then skips with a warning)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* docs: align the contract with the merged executor and review feedback

- Capitalize the author-facing namespace fields (Course.Editor, .Copilot,
  .Spotlight and Editor.Project, .Runtime, .CodeEditor, .Ruler) to match
  the framework package merged in #3424: XGo auto-capitalizes method
  calls but not struct field access. Method names stay lowercase, and
  the example Course is updated accordingly
- Replace getCurrentActiveDocument with getActiveDocuments, returning a
  list: one Code Editor may have several UIs attached, each with at most
  one active document, so an empty list expresses "nothing is open"
  without introducing an error

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* docs: read Course code through editor.project

Provide editor.project.getCode(file) alongside listCodeFiles, and defer
"the code the learner is currently editing" until the Code Editor's
attached UIs and their active documents are settled. Reading project
content and controlling the editor UI stay in separate namespaces, and
no capability carries the ambiguous "current" semantics for now.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* docs: address the project by sprite name

SpxProject models its contents as business concepts identified by name,
so the Course-facing project capabilities follow suit: listSprites
returns sprite names and getCode takes one, instead of enumerating and
addressing code files by path.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* docs: describe project.getCode as reading the project

The project reads the sprite's code from the session project, not from a
Code Editor UI buffer, so "unsaved edits" described neither of the two
things it could mean: edits still held by the editor are not visible
here, and Course changes are never saved to a server in the first place.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
feat(tutorial): add project domain models
nighca and others added 21 commits November 6, 2026 12:05
* chore: restore standard staging API endpoints

* chore: remove temporary Tutorial course debug runner

* docs: remove stale Tutorial debug runner instructions

* fix: use stable Radar names for admin and preprocessing

* fix: keep Radar selector identities independent of locale

* fix: preserve localized accessible labels in Radar metadata
* chore(deps): bump spx to 4.0.1

* chore(deps): pin xgolsw spx list alias fix

* chore(deps): sync xgolsw review follow-up

* chore(deps): use merged upstream xgolsw fix
Separate stable first-party app identities from OAuth client
configurations so shared services can use consistent app references.

Define product boundaries for delegated user access, app-only access
with app-level scope approval, directory queries, and user profiles.

Specify persistence, API and frontend changes, transaction and audit
boundaries, token revocation, and an atomic migration that removes legacy
OAuth storage while preserving existing client IDs, credentials, tokens,
and sessions.

Signed-off-by: Aofei Sheng <aofei@aofeisheng.com>
* refactor: rename spx-gui directory to gui

* refactor: align GUI naming across CI and documentation
* fix(copilot): isolate global and docked panel expansion

* refactor(copilot): restore preview state after docked UI unmounts

* docs(copilot): explain docked panel reset on mount
Separate app registration from OAuth client configuration in the Account
admin console. Approve app-only scopes per app, manage client credentials,
and bind administrator-issued user tokens to the selected client.

Extend the OpenAPI contract for app directory and user profile queries,
and preserve public client identifiers throughout hosted sign-in.

BREAKING CHANGE: app registration no longer accepts OAuth client
settings. Manage clients and their secrets under the app's `oauth-clients`
resources. Administrator token creation requires `oauthClientID`.

Updates #3651

Signed-off-by: Aofei Sheng <aofei@aofeisheng.com>
#3727)

* Polish read-only feedback and prevent blocked completion requests

* Match API reference item corners to the design reference

* Simplify read-only completion handling and align feedback with caret

* Match latest read-only bubble shape and caret offset

* Suppress API reference hover effects while read-only

* Skip API reference pressed feedback while disabled

* Prevent text selection in API reference items
* fix(editor): capture Simple Mode thumbnails without a transformer

* fix(code-editor): hide completed empty API references

* fix(editor): remove API Reference changes from thumbnail PR
* feat(spx-gui): add feedback replies and the notification panel

* fix(spx-gui): follow Radar naming conventions for feedback replies and notifications

* docs(product): name the feedback action "Mark as no reply needed"

* refactor(spx-gui): let UITab and NotificationLink style the notification panel

* fix(spx-gui): render reply images with useRenderableImageUrl

* docs(spx-gui): document and test useInfiniteQueryWithCache

* docs(openapi): require reply attachments in the upload bucket

* docs(product): simplify the handled status description

* fix(gui): keep full notification text and reply drafts

- Render notification bodies and previews as complete Markdown, so the
  text after `<` is no longer dropped
- Reload the feedback only after a reply is sent or conflicts, so a
  failed send keeps the draft
- Preview only images in Kodo, and keep native clicks with modifier keys
- Share unread counts from the notification store, accept a `null` page
  token, require the notification time, and rename the Radar name of
  the no-reply-needed button

* fix(gui): always upload reply images to Kodo

The backend accepts only Kodo URLs for reply attachments. Pass
inlineable: false to saveFile, instead of relying on its current rule
that only text files become data URLs.

Tested by the admin feedback page test, which now checks the saveFile
options.

* refactor(gui): compose feedback replies as Markdown

Use one Markdown content field for replies and notifications instead of
maintaining separate attachment state, validation and rendering. Keep the
normal textarea and insert uploaded images at the selection.

Reuse sanitized notification rendering, preserve native linked-image
behavior, and scope draft/detail state to the feedback and signed-in user.

Validated with 1713 tests, type-check, changed-file ESLint and Prettier,
OpenAPI references, Chromium upload/submit/preview, and scoped complexity,
duplication and mutation checks.

* refactor(gui): drop optional notification link changes

Restore the previous modifier-click handling and remove the added Radar
metadata and corresponding assertions at the user's request.

Keep Markdown replies, inline image handling, and feedback/account state
isolation. Validated with 1713 tests, type-check, ESLint and Prettier.

* fix(gui): open notification links and preview images by element

Whether a click previews an image now depends on what is clicked, not
on the URL: text links always open their targets, even image URLs, and
images open the preview wherever they are stored, unless they are inside
a link.

`custom` is meant for custom elements, so MarkdownView gets `link` and
`image` entries beside `codeBlock` instead of notifications overriding
native `a` and `img`. Kodo URLs are kept only for the matching entry.
URLs other than Kodo URLs, such as `mailto:` and relative URLs, are kept
as they are.

Validated with 1713 tests, type-check, ESLint and Prettier. Targeted
mutations of the new branches are all caught by the tests.

* test(gui): cover MarkdownView code blocks

No test reached the `codeBlock` branch of MarkdownView. Pin the current
behavior: the language comes from the `language-*` class, is empty
without it, and the code is passed as children.

Disabling the entry, keeping the class prefix, dropping the language or
dropping the code now fails the test. Validated with 1714 tests, ESLint
and Prettier.

* refactor(gui): let MarkdownView callers allow custom URL protocols
…ry click (#3738)

* fix(ui): preserve dialogs after cross-boundary text selection

* refactor(ui): share dialog mask component and clarify content element

* docs(ui): explain dialog mask gesture semantics

* fix(ui): preserve dropdowns after cross-boundary text selection
* Hide API Reference after filtering leaves no APIs

* Clarify API Reference configuration and visibility names

* Cover API item shadows with sticky headings and clarify loading comments
…e height (#3742)

* feat(course-editor): expand the Copilot context field to the available height

The field fills the space left in the course settings document instead of a
fixed 10 rows. Six rows remain as its minimum height; below that the page
scrolls.

Fixes #3735

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(course-editor): keep the Copilot context field between 10 and 30 rows

Restore the previous 10-row height as the minimum, and stop the field at 30
rows on tall viewports so the button and any content after it stay next to
the field instead of being pushed to the bottom of the card.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* fix: upgrade xgolsw to prevent sprite completion panic

* test: remove upstream-covered completion regression
* Save management editing state and live course panel follow-up

* Keep Tutorial course data consistent across management and learning

Refs #3720

* Simplify Tutorial snapshots and course return navigation

* Unify query modes and keep series course views consistent

* test: cover nested composed queries

* fix: share course page size and validate stored tutorial IDs

* docs: document infinite query options
* fix(tutorial): put next course first in completion dialogs

* docs: revert completion action ordering note

* fix(tutorial): align guided completion button metadata and style
* fix: retain runtime call sites across source files

* chore: sync ixgo execution stack dependency

* chore: use upstream ixgo stack tracking version

* refactor: clarify execution location variable names
* feat(tutorial): show course series title in navigation panel

* docs(tutorial): record series heading decision

* test(tutorial): cover course series heading updates

* docs(tutorial): remove design note from issue scope
* fix(code-editor): focus input helpers after popup positioning

* fix(ui): coordinate input autofocus with popup visibility

* fix(ui): wait for popup readiness before autofocus

* docs(ui): explain autofocus timing trade-off

* test(ui): remove redundant input helper focus case
@codecov

codecov Bot commented Nov 12, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 69.85242% with 429 lines in your changes missing coverage. Please review.
✅ Project coverage is 59.95%. Comparing base (f8187bb) to head (fce3f1a).

Files with missing lines Patch % Lines
...s/xbuilder/pages/course-management/series-list.vue 0.00% 99 Missing ⚠️
...c/apps/xbuilder/pages/course-management/series.vue 68.03% 60 Missing and 18 partials ⚠️
...c/apps/xbuilder/pages/docs/ui-design/spotlight.vue 0.00% 66 Missing ⚠️
gui/src/apps/xbuilder/pages/admin/oauth-client.vue 80.00% 8 Missing and 14 partials ⚠️
gui/src/apps/xbuilder/pages/admin/OAuthClients.vue 77.41% 6 Missing and 8 partials ⚠️
...ui/src/apps/xbuilder/pages/course-editor/index.vue 73.07% 7 Missing and 7 partials ⚠️
...pps/xbuilder/pages/tutorials/course-playground.vue 78.94% 6 Missing and 6 partials ⚠️
gui/src/apps/xbuilder/router.ts 42.85% 12 Missing ⚠️
gui/src/apis/admin/account.ts 41.17% 10 Missing ⚠️
gui/src/apps/xbuilder/pages/admin/app.vue 90.21% 0 Missing and 9 partials ⚠️
... and 28 more
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #3767      +/-   ##
==========================================
+ Coverage   51.24%   59.95%   +8.70%     
==========================================
  Files         666      772     +106     
  Lines       23070    27728    +4658     
  Branches     4122     5231    +1109     
==========================================
+ Hits        11823    16625    +4802     
+ Misses      10192     9590     -602     
- Partials     1055     1513     +458     
Flag Coverage Δ
gui 59.42% <69.85%> (?)
spx-gui ?
tools-ai 79.61% <ø> (-0.09%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
gui/src/apis/account/common.ts 100.00% <ø> (ø)
gui/src/apis/account/index.ts 23.80% <ø> (ø)
gui/src/apis/account/oauth.ts 50.00% <ø> (ø)
gui/src/apis/admin/audit.ts 0.00% <ø> (ø)
gui/src/apis/admin/authorization.ts 0.00% <ø> (ø)
gui/src/apis/aigc.ts 75.00% <ø> (ø)
gui/src/apis/asset.ts 45.45% <ø> (ø)
gui/src/apis/common/client.ts 57.25% <ø> (ø)
gui/src/apis/common/exception.ts 96.42% <ø> (ø)
gui/src/apis/common/index.ts 97.22% <ø> (ø)
... and 101 more

... and 1227 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

* fix: exit snippet interaction after insertion in Simple Mode

* docs: explain disabling snippet stops in Simple Mode

* docs: clarify snippet cancellation selection behavior
…3766)

* fix(tutorial): report a run's start before the project's code runs

The editor emitted didStart only after the runner's run() resolved, that
is after startGame and file hashing, while the project's top-level code
already runs and prints inside startGame. Courses therefore received
editor.runtime.start after the first logs of the same run.

ProjectRunner now emits start right before calling startGame, and the
editor preview forwards it as didStart. Logs are still forwarded as they
are printed.

Fixes #3744

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* test(tutorial): check that the runner emits start before starting the game

ProjectRunner had no tests, and the editor preview's tests use a stubbed
runner, so nothing guarded where start is emitted. The new test runs the
runner against a fake runner page whose startGame prints a line, and
expects start, then startGame, then that line.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(tutorial): say that a run stopped after its start keeps it

The didStart documentation now states both sides: a run that fails or is
stopped before the project's code starts emits no start, and one that
fails or is stopped after it keeps the start it emitted. The comment on
emit('start') now reads as a full sentence.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Use the latest language-server fixes and register server disposal for
in-process Worker tests so completed tests release project data and host
callbacks.

Verify that disposed instances reject subsequent messages.

Signed-off-by: Aofei Sheng <aofei@aofeisheng.com>
@nighca
nighca marked this pull request as ready for review November 13, 2026 03:42
@nighca
nighca merged commit cc80cb7 into main Nov 13, 2026
16 of 17 checks passed

This branch was successfully deployed

1 active deployment
Preview – builder — fce3f1aa Deployed Nov 13, 2026 by vercel[bot]
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.

7 participants