- before every attempt the picked file is read into memory (ArrayBuffer) and that copy is what
the SDK uploads; a file the browser cannot read fails there as "file unreadable before upload"
- while an attempt runs, XMLHttpRequest open/send are wrapped (reference-counted with the abort
probe, restored in finally, no behaviour change) so the failure line carries each upload XHR's
method, path (query dropped), readyState, status, the events it fired with timings, and our
signal.aborted
- the abort-call stacks stay as a minor extra
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
For each upload attempt, XMLHttpRequest.prototype.abort and AbortController.prototype.abort are
wrapped (reference-counted across overlapping attempts, restored in finally) and every call is
recorded with a six-frame file:line:col stack; "abort calls: none" says the page called neither.
The upload hook also counts renders after attach (and those within 300ms) and any unmount.
The in-memory copy and the once-only retry are unchanged.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
An AbortError within 3s of starting, with no progress event and no user cancel, is retried once;
the failed attempt discards its connection, so the retry cannot reuse it. The final failure text
says "retried" with attempt 1's timing. Never retried after progress, a user cancel, a
different error, or a slow abort. The cause (a reused dead keep-alive socket) is unproven.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Adds connectivity (onLine, effectiveType, rtt, downlink, saveData), tab visibility, ms since
last user activity, time to first progress and bytes loaded, and ms to failure. Nothing patches
XMLHttpRequest; the progress handler and window input events are the only sources.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
The catch in uploadContent set errcode from e.message and dropped an empty
message, so the SDK's status-0 AbortError (DOMException with empty message)
surfaced as "MatrixError: Unknown message". uploadFailure now uses e.name for
errcode, keeps the original as cause, and puts size, type and whether the
file can still be read into the message the upload card shows.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Signed in, the shell is clear over the ridge scene (html[data-scene]): Background and Surface
container tokens are redefined on #root only, so menus, dialogs and tooltips in #portalContainer
keep their fills. Bubbles and the composer are the filled surfaces: their colour at 50% over a
12px blur. Avatar initials read the surface colour through a variable captured above the override.
On phones the message content (a flex column) formed its own block formatting context and sat
beside the floated portrait for the bubble's whole height, so text stayed as narrow as the gap
beside the portrait. It is a plain block there now: lines wrap around the silhouette and then
run the bubble's full width.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
The demo pose thumbnails were 160px wide palette PNGs, about 4 KB, shown at up to 210 CSS px
on phones: 195 CSS px x DPR 3 = 585 device px from 160, a 3.6x upscale. They are now 480px
wide (about 2.5x the phone portrait at DPR 3, still 25-70 KB each), generated from
/opt/commons/cast-art/poses by scripts/make-pose-thumbs.mjs, and cover every pose the
catalogue lists for the three demo Minds.
The Ratatoskr demo room gains three long Mind posts with paragraphs, lists and code,
sent with formatted_body like the real Minds' Markdown.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Found driving Chrome: the pose setting was seeded after settings.ts had already read defaults;
the Connecting bar stayed until the first 15 s long poll returned.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
The host CSP sandbox lacks allow-forms; Chrome drops native submission before the submit
event fires, so the login button did nothing in a real browser (found driving Chrome).
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
src/preview-demo answers a demo.invalid homeserver from fixtures through a guarded fetch;
own-origin requests pass, every other origin is refused (fetch, WebSocket, XHR, beacon).
Built in only with VITE_PREVIEW_DEMO=1 and switched on by previewDemo in config.json
(scripts/preview-config.js --demo, run by the dev workflow). Login prefills 'demo'.
Pose art: 24 downscaled thumbnails in preview-demo/poses, copied into dist by the workflow.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Run 170: CreateArtifact got an nginx 404 page; /twirp 404s at the host root and answers
(401 without a token) at /forge/twirp. Try the results URL with the subpath.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
actions/upload-artifact v4+ throws GHESNotSupportedError on this forge (run 169);
Forgejo's fork is the supported uploader.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Push to dev builds with base /void/rat-dev/, tier low, heap 3072 MB, and uploads dist.
No secrets. Consumed by gamecult-ops install-rat-dev-preview.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Under html[data-scene] the card is a blurred 85% pane in the sky bubble colour
(--sky-bubble, fallback #0d1a26), message-bubble radius, no visible border, and
shorter padding/gaps so more scene shows on a phone. Tier off is unchanged.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
BackgroundScene hosts the scene behind the app (fixed, z-index -1, tier off
renders nothing); mountBackgroundScene owns the async start/dispose race and
calls login() when a session already exists. Signed-out screens go transparent
while a scene runs. build:preview sets backgroundScene.tier low in dist.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Remove cla, pr-title, deploy-pull-request, netlify-dev and prod-deploy;
drop the deleted prod-deploy path from docker-pr's trigger filter.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Heimdall's ruling: type org.gamecult.notice, state_key '', content {version, scope}.
version is a positive integer, scope exactly show, study or train; absent or
malformed means no train line. ROOM_NOTICE_CONTENT_KEY becomes
ROOM_NOTICE_EVENT_TYPE; RoomTrainingLine reads the state event through useStateEvent.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
The collector reads the notice version from the room's pinned notice and takes
the member's first reply as the acceptance (Heimdall answer-collector-consent.md),
so a localStorage record at registration was a second, unread copy. Deleted it
and its unused re-ask helpers. RoomTrainingLine now reads the room's own pinned
notice and shows the train sentence only where that notice declares train; no
notice, no line (DMs included). The pinned event's encoding is not fixed by the
doc; the key is provisional and isolated in trainingNotice.ts.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Two themes replace the navy GameCult theme. Every colour is a bark, leaf, soil
or pigment albedo times the irradiance sun.js gives for a fixed moment (equinox
noon and midnight, 45N). scripts/bake-sky.mjs writes src/sky/baked.ts: the
terrain-free sky gradient used as the fallback background, folds tokens for
panels and buttons, chat bubble colours, link and name colours.
skyTokens.test.ts holds every text pairing to WCAG AA and fails if baked.ts is
stale.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Per-layer Beer-Lambert transmittance exp(-k d) mixes each layer toward the haze colour, with
desaturation, 0-2 px edge softening (2D canvas filter, where supported) and an optional faint
warm sun-side in-scatter growing with distance. All at bake time; no per-frame work. Sky colours
still come only from skyColours() (gains optional sunAzimuth).
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Login no longer shows the notice. Registration shows the ruled sentence with a
plain tick, and records {noticeVersion, acceptedAt} on submit (newcomers only;
a changed TRAINING_NOTICE_VERSION is a fresh acceptance). Each room carries one
line above the composer. The Discord sentence and "on this server" are gone.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Four ridge layers generated once on the CPU from CultMath value-noise fbm, each painted
once to an integer-size 2D canvas over a baked sky; CSS translate3d drift only. Pauses
hidden / reduced motion; falls back to a still image if rAF p95 > 33 ms over 2 s;
?probe=1 shows median/p95. Same createScene contract, tier flag still defaults off.
Ray-march scene stays behind backgroundScene.style = 'raymarch'.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Dependency-free ES module: light({time,lat,lon,cloud_cover,precipitation})
-> {elevation, direct, diffuse, wetness}, linear RGB. Constants that were
tuned by eye are labelled EYEBALLED. Fixed-moment tests in
sun.node-test.js (plain node, not collected by vitest).
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
One TrainingNotice component above the submit button on both screens. Login
shows the notice only; registration adds a ticked checkbox that gates the
Register button.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>