Skip to content

cloudApi v3.1: dial metadata + decide, aiPresets + mesh-job status line (1.15.1) - #231

Merged
AlexZ005 merged 3 commits into
release/nextfrom
feat/1.15.1
Sep 20, 2026
Merged

AlexZ005 merged 3 commits into
release/nextfrom
feat/1.15.1

Conversation

@AlexZ005

Copy link
Copy Markdown
Collaborator

Roadmap 29 round 2 — the two core seams the cloud lanes could not land themselves, released as 1.15.1 (patch: additive cloudApi members, no hooks-version bump, no format change). The 29-core-seams lane stalled at zero commits, so the integrator carried it.

Seam 1 — rooms access control (8e9fb5d)

cloudApi.connectToPeer(peerId, cloudMeta) rides plain JSON (≤ 1 KB) on the join dial's PeerJS metadata, remembered per peer for restore re-dials; authProvider.decide(peerId, cloudMeta) replaces authorize when present — 'admit' / 'deny' (no card; a jr joiner hears denied) / {label} (the card carries it); cloudApi.dialMeta is the probe. The rooms-access lane's proven patch, plus the JSDoc it lacked. pendingApprovals typed → five baseline errors gone.

Seam 2 — hosted AI (311e184)

api.aiPresets.userHas(tag) / seed(tag, {ai, mesh, activate, enable}): one plugin-managed provider preset per domain (managedBy on the config, absent = the user's own), two activation guards (the trap: the stores auto-activate a first provider, so a seed without permission restores the pointer), enable only when we became active. setMeshJobStatus(fn) + cloudHooks.meshJobStatus = the queue line under a running mesh-job card.

Gates

gate result
svelte-check 336 / 47 (base 341/47, zero new messages; baseline ratcheted)
vitest 178
build (server down) green
dial-metadata (new) 44 — stubbed peer for every verdict branch, then two real peers over signaling
ai-presets (new) 45 — both guards with counterfactuals, the status line
held: net-handshake 9 · approval-timeout 17 · join-result 41 · open-core-m1 16/1 · sdk-game-seams 78 · invite-link-live 21/1 green; the two reds are pre-existing (open-core-m1 A/B'd identical on pristine 1.14.0; invite-link-live's public-cloud dial)
cloud smoke against this core 139 / 0 — rooms access admits on a real room code through decide; G3 seeds through api.aiPresets

Also in the docs commit: the stale plans-core/ paths in CLAUDE.md, and a gotcha for the finding on the way — jsDelivr parses scenes@v2 as a semver version and never re-resolves a retag (core #230).

🤖 Generated with Claude Code

AlexZ005 and others added 3 commits September 20, 2026 03:48
…vider.decide answers it

Roadmap 29, rooms access control (seam 1). A gated cloud room needs the host to see a
knock's name or a room-code proof BEFORE the conn opens - an unapproved conn is closed at
once, so the dial's PeerJS metadata is the only channel that arrives first.

- `cloudApi.connectToPeer(peerId, cloudMeta)` -> `requestConnect(peerId, cloudMeta)`: the
  join dial's metadata gains `cloud: <plain JSON <= 1 KB>` (bounded in `boundCloudMeta`;
  oversized or unserialisable data is dropped, not truncated), remembered per peer on the
  PeerConnection (`dialCloud`) so a restore re-dial knocks with the same hand, forgotten by
  the next plain dial. Absent = the dial is byte-identical (`{jr: 1}`).
- `authProvider.decide(peerId, cloudMeta)` REPLACES `authorize` when present: 'admit' (the
  auto-approve path), 'deny' (refused with NO card; a joiner that advertised `jr` hears
  `denied` through the 25-F refusal dial, an older one is closed silently), `{label}` (the
  normal card carrying the label, capped at 120 chars, refreshed by a re-dial). Undefined
  defers to `authorize`; a provider with only `authorize` is byte-unchanged; a throwing
  `decide` falls back to the manual card and admits nobody.
- `Toasts.svelte` and the Connect drawer's Toasts tab render `approval.label`.
- `cloudApi.dialMeta = true` is the probe an older engine lacks (the cloud plugin fails
  closed to the plain approval card without it). No CLOUD_HOOKS_VERSION bump: additive.
- `pendingApprovals` is typed `Writable<any[]>` (it inferred never[]), which removes five
  pre-existing svelte-check errors; the patch's own JSDoc gaps (dialOptions/dial params,
  the `dialCloud` field) are filled so the check adds nothing.

Suite `dial-metadata` (43): the joiner's dial (identical without metadata, carried on the
dial and its restore, bounded), every verdict branch against a stubbed peer, and two real
peers over signaling (label, deny, admit). The patch itself was written and proven by the
`29-rooms-access` lane; this lands it.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
… seam)

Roadmap 29, G-3 hosted AI (seam 2). A signed-in cloud user should get the assistant with
no key, URL or model to type. The plugin cannot write core's aiProviders / meshProviders
itself - they are Svelte stores loaded from localStorage at module init, so a key written
after boot changes nothing until a reload - so core owns ONE plugin-managed preset per
domain and the plugin describes it.

- `api.aiPresets.userHas(tag)` -> `{ai, mesh}`: does the user have a provider of their
  OWN (the tagged entry excluded).
- `api.aiPresets.seed(tag, {ai, mesh, activate, enable})`: create / update / remove the
  managed entry in both lists (`null` removes). `tag` is `managedBy` on the config, so a
  user-created provider - which carries no tag - is untouchable by construction; a config
  cannot smuggle an `id` or a tag. ACTIVATION takes two guards, both required: the
  caller's `activate.<domain>` AND the slot being empty or already ours. The trap the lane
  brief named: `addAiProvider`/`addMeshProvider` activate a first provider on their own,
  so a seed without permission restores the previous pointer, or guard 1 leaks through
  the add (the suite's counterfactual). `enable` flips the master toggle only when our
  entry became the active one.
- `providers.js` / `meshProviders.js`: optional `managedBy` on the config typedef (absent
  = the user's own, no migration) and the add whitelists keep it.
- `api.setMeshJobStatus(fn)` + `cloudHooks.meshJobStatus`: one line under each RUNNING
  mesh-job card ("You are #3 in queue"); `fn()` -> string | null, re-read on every set
  (a function is never equal to itself in svelte's store check, so a set is the poke) and
  on every job-list change; a throwing fn renders nothing and breaks nothing.
- `makeCloudApi` is exported so the debug hook can hand a suite the real api.
- No CLOUD_HOOKS_VERSION bump: every member is additive and typeof-probed (the plugin
  stays compatibleHooks = 3; hostedAi.js already calls exactly this shape).

Suite `ai-presets` (45): the probe, create/update/remove, both activation guards with
their counterfactuals, enable-only-when-active, managedBy across the store and a reload,
and the status line's render/re-read/remove/throw.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…d entries, baseline 336/47

- CHANGELOG: the 1.15.1 section (gated rooms end to end, the hosted-AI preset + queue line,
  cloudApi v3.1 for plugin authors).
- CLAUDE.md: the cloudApi v3.1 architecture entry (both seams and their guards), the jsDelivr
  semver-tag gotcha (core #230), the round-2 status entry, and the stale `plans-core/` plan
  paths rewritten to `cloud/plans/core/` (51 mentions incl. the two prose lines the brief named).
- e2e skill: the dial-metadata + ai-presets suites.
- check-baseline.json ratcheted 341 -> 336 (typing `pendingApprovals` removed five errors).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@AlexZ005
AlexZ005 merged commit 0e74782 into release/next Sep 20, 2026
4 checks passed
@AlexZ005
AlexZ005 deleted the feat/1.15.1 branch September 20, 2026 01:22
@AlexZ005 AlexZ005 mentioned this pull request Sep 20, 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.

1 participant