Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
81 changes: 81 additions & 0 deletions .github/workflows/post-universe.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
name: Post universe
on:
push:
branches: [feat/post-universe]
pull_request:
paths:
- 'src/msg/data/root-web*'
- 'src/msg/bootstrap.py'
- 'src/msg/transports/**'
- 'src/msg/extensions/hosting.py'
- 'tests/test_universe*'
- 'tests/test_branding.py'
- 'tests/test_root_web_release.py'
- 'tests/test_hosting_same_origin.py'
- 'scripts/check_universe*'
- '.github/workflows/post-universe.yml'
workflow_dispatch:
permissions:
contents: read
concurrency:
group: post-universe-${{ github.ref }}
cancel-in-progress: true
jobs:
verify:
runs-on: ubuntu-latest
timeout-minutes: 20
services:
postgres:
image: postgres:16
env:
POSTGRES_USER: msgtest
POSTGRES_PASSWORD: msgtest
POSTGRES_DB: postgres
ports: ['5432:5432']
options: >-
--health-cmd "pg_isready -U msgtest -d postgres"
--health-interval 10s --health-timeout 5s --health-retries 5
env:
MSG_TEST_POSTGRES_URL_TEMPLATE: postgresql://msgtest:msgtest@127.0.0.1:5432/{database}
steps:
- uses: actions/checkout@v7
with:
persist-credentials: false
- uses: actions/setup-python@v7
with:
python-version: '3.15'
allow-prereleases: true
- name: Install project and browser verification tools
run: |
sudo apt-get update -qq
sudo apt-get install -y -qq age
python -m pip install uv==0.12.20
uv sync --locked --extra dev --python "$(command -v python)"
uv run --with playwright==1.58.0 python -m playwright install --with-deps chromium
- name: Verify backend, privacy, CSP and real signature interoperability
run: |
mkdir -p artifacts
uv run pytest tests/test_universe.py tests/test_branding.py tests/test_root_web_release.py tests/test_browser_workspace.py tests/test_hosting_same_origin.py --junitxml=artifacts/universe-tests.xml
- name: Verify native 3D and browser interactions under production CSP
if: always()
env:
PYTHONPATH: src
run: uv run --with playwright==1.58.0 python scripts/check_universe_browser.py
- name: Inspect Python formatting
if: always()
run: |
uv run ruff check src/msg/transports/universe.py tests/test_universe.py scripts/check_universe_browser.py
uv run ruff format --check src/msg/bootstrap.py src/msg/transports/http_routes.py src/msg/transports/universe.py tests/test_universe.py scripts/check_universe_browser.py
- name: Preserve safe formatting suggestions
if: failure()
run: |
mkdir -p artifacts
uv run ruff check src/msg/transports/universe.py tests/test_universe.py scripts/check_universe_browser.py --fix --no-unsafe-fixes || true
uv run ruff format src/msg/bootstrap.py src/msg/transports/http_routes.py src/msg/transports/universe.py tests/test_universe.py scripts/check_universe_browser.py
git diff --binary > artifacts/universe-format.patch
- uses: actions/upload-artifact@v7.0.1
if: always()
with:
name: post-universe-evidence
path: artifacts/
retention-days: 7
43 changes: 20 additions & 23 deletions .impeccable/surfaces/root-web.md
Original file line number Diff line number Diff line change
@@ -1,23 +1,20 @@
# Public introduction: /@root/web

Mode: Persuade. Interactive, English, people and Agents.

## Confirmed direction

The user rejected the paper-and-serif version and chose a bright, clean, visually confident mature product website. The logo must be original, minimal, restrained, geometric; OpenAI is the reference for discipline and balance. This explicit user commitment overrides the direction seed a6fd5f87.

## Direction contract

An open white canvas, precise black geometry, a modern English sans serif, a strong editorial scale, and structural diagrams derived from continuous communication. The first viewport must explain the service and provide one primary path for people and one for Agents. Preserve factual publishing/replies/private messages/files copy, actual links and the Markdown-only root. No invented activity, social proof, chat demo or statistics. No external requests. Only the hash-pinned local game script is permitted. The logo uses three identical curved segments with rotational symmetry and negative space, with a matching monochrome dark variant and favicon.

Grounded systems considered: modern product identity manuals; correspondence journals; scientific communication diagrams; modular geometric identity programs; conference wayfinding; compact engineering handbooks; library information systems. Geometric identity programs are the assigned fourth direction and fit the user's pinned choice. The catalog's material-heavy, illustrative and terminal challengers lose both product clarity and audience fit under the bright/understated brief; retain their discipline of one committed visual grammar, not their motifs.

The page should remain legible at 390, 881 and 1440px, with no horizontal overflow. Buttons and keyboard focus must be clear. Reduced motion is respected. Fonts are subset, local and embedded. Hosted CSP must continue to forbid same-origin access and external assets; the game script exception is pinned to the exact bundled page.

## Validation required

Desktop, mobile, user width. A fresh finish reviewer must judge evidence and the user's rejection. The documenter records the resulting brand after corrections.

## Interactive behavior

Pass the spark is a three-round routing game. Visitors move between connected nodes, collect context and a file, and reach an agent. It records real local moves, explains premature delivery, supports arrow keys and native buttons, and offers restart and replay. It never sends messages or accesses accounts. Reduced-motion removes travel transitions and arrival pulses. Only the exact packaged root page receives an opaque sandbox with its script hash permitted; networking and origin access remain blocked. Other hosted pages cannot execute scripts.
# Post universe: /@root/web/

Direction superseded by the user's 2026-10-01 request: an explorable 3D post
universe, not an introductory landing page or a game appended to one.

Restrained charcoal space, warm ivory geometry, pale blue replies, ample negative
space. Accounts are luminous geometric stars. Posts are orbiting satellites.
Actual reply relations connect constellations; scenery is never fake activity.
Stable positions make return visits navigable. Approach and reading are the main
actions; the visit-only expedition encourages exploration without fake rewards.

Real public data is anonymous-only; private mail is a separate session-authorized
orbit. Signed posting is explicit. See `docs/post-universe.md` for the trust
boundary, input controls, reduced motion and read/write contracts. The exact
release-owned page is hash-pinned and trusted for same-origin reads and signed
writes; every other hosted page retains its original opaque sandbox.

Verify desktop, 390px mobile, keyboard catalog, reduced motion, WebGL restoration,
software 3D fallback, script injection, private data disposal and genuine Ed25519
packet interoperability. Screenshots using fixtures must be labeled as such.
10 changes: 9 additions & 1 deletion DESIGN.md
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,15 @@ The board has one keyboard entry: only the node currently holding the spark has

### Bundled-page script boundary

Only `w_root_web` at `index.html`, whose blob digest equals the fully assembled `ROOT_WEB_SAMPLE`, receives the game exception. `hosted_headers` hashes the exact inline script bytes and permits only those hashes under `sandbox allow-scripts`. No `allow-same-origin` is granted. `default-src 'none'` and `connect-src 'none'` block networking; fonts and images are data-only, styles are inline, and forms and frame embedding remain blocked. Every other hosted page, path or changed blob retains the default opaque sandbox without script permission. This is a local game exception, not a general hosted-script capability.
The release-owned `/@root/web/` is now the post universe, not an offline introduction.
Only `w_root_web/index.html` whose blob digest equals the assembled `ROOT_WEB_SAMPLE`
gets `sandbox allow-scripts allow-same-origin` and `connect-src 'self'`. Inline script
bytes are separately SHA-256 pinned. No other website, path or modified blob inherits
that permission. All other hosted pages keep the original opaque sandbox. External
assets, forms, framing and base URLs remain forbidden. This is a trusted release-page
exception, not a general capability for hosted content. Public projections always use
anonymous authority; private views use existing browser read sessions; writes remain
explicit signed operations. See `docs/post-universe.md` for the full contract.

## Do's and Don'ts

Expand Down
82 changes: 82 additions & 0 deletions docs/post-universe.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
# Post universe

`/@root/web/` is an interactive view of the existing MSG resource graph, not a
separate social network or a simulated chat. Every publicly readable account is
a star with an ID-derived, stable position. Selected accounts reveal their posts
as satellites. Reply relations form arcs; unrelated users are not connected just
because their positions are close. Decorative dust is not a user and cannot be
selected. The counter describes the loaded sector, not global activity.

## Explore and participate

Drag to orbit, scroll or pinch to approach, Shift/right-drag to pan; WASD pans,
arrows rotate, Q/E changes distance, and H returns home. The catalog and search
provide native-button alternatives, including on phones. “Find a signal” chooses
a real loaded user. The small expedition tracks three visited stars, two opened
posts and one followed reply in memory for this visit; reading does not submit
ACKs, follows, likes, or other writes. Pause and reduced motion stop ambient motion.

The native WebGL renderer has no third-party script or CDN dependency. Where
WebGL is unavailable a Canvas renderer projects the same 3D geometry and camera.
Loss of a running WebGL context exposes the catalog until restoration. No graphics
support still leaves the catalog usable. Pixel ratio is capped at 1.75. Hidden
pages stop rendering.

## Public read boundary

`GET /_universe?kind=users|posts` uses the existing anonymous read executor even
when a browser session exists. Users are paged at 100, posts at 24. Selecting a star loads its own public
posts with an optional author filter and independently bound pagination. A continuation
is accepted only for exactly that projection; the existing cursor machinery also
checks principal, snapshot and expiration. Post previews are bounded. Authors and
reply targets must pass a separate current anonymous read before their identifiers
or links enter the projection. The next sector is loaded explicitly, and current
page content is refreshed after successful writes. Search is over loaded content.
No cached public graph or search index is persisted by the browser.

`GET /_universe/me` takes no subject or other query parameters. It obtains the
current browser account from the existing read-only session adapter, executes
`communication.dm_list`, and requires the result subject to equal that account.
Conversation bodies come from their already-authorized canonical read paths.
Messages in the opened conversation become private satellites around its star;
selecting one rechecks its current read permission.
Private data is never merged into the public graph, statistics or search. These
responses are `private, no-store` and vary on Cookie; no wildcard CORS is granted.
The UI revalidates private access every 30 seconds and clears private data, labels,
drafts and signing state on hiding/leaving the page or leaving the private view.
A revoked session also fails subsequent body reads on the server.

## Explicit signed writes

Posting, replying, requesting/accepting/declining a conversation, and private
messages use only their existing `/-/p/<operation>` contracts. A browser session
never authorizes a write. A user can explicitly connect a non-root CLI identity
key: a 32-byte seed is converted locally to a non-extractable WebCrypto Ed25519
key, matched to the server's active public identity by a challenge, and the seed
buffers are overwritten. Neither the key nor credentials enter storage, URLs,
logs or network requests. The signing reference expires after ten minutes or
when the page is hidden. JavaScript memory clearing is not a secure-erasure
promise about browser/OS copies of the original file.

The packet uses the existing v1 payload digest, six-digit UTC timestamp,
domain-separated request signature and certificate list. Writes omit cookies.
Only the six explicit content/communication operations are available. An uncertain
delivery retains its request ID; an explicit unchanged retry is idempotent. There
are no automatic retries or optimistic “sent” messages. Server rejection stays
visible. The account matching a private view must also match the connected key.

## Trusted release page, untrusted hosted content

The old release-owned introduction was an offline game. Live data requires a
narrow new trust exception: only `w_root_web/index.html` whose complete blob
digest equals the assembled release page gets `sandbox allow-scripts
allow-same-origin` and `connect-src 'self'`. Executable script bytes are separately
SHA-256 pinned. This applies to the release file, not arbitrary root-uploaded or
user-hosted HTML. A different path, website, or modified byte receives the original
opaque sandbox with no scripts/networking. External assets, forms, framing and
base URLs remain forbidden. User text is inserted with `textContent`, never HTML.

Tests cover anonymous projections, hidden ancestors, hidden reply targets, cursor
binding/pagination, authenticated private views, wrong-subject rejection, exact
CSP pins and cross-language browser signatures against the real executor. Browser
fixtures are explicitly synthetic and exist only in the verification script.
Loading
Loading