diff --git a/.github/workflows/REVIEW.md b/.github/workflows/REVIEW.md index b699bf4d25..6e82aeae14 100644 --- a/.github/workflows/REVIEW.md +++ b/.github/workflows/REVIEW.md @@ -10,8 +10,13 @@ such step enforces its rule automatically, with no reviewer involved - `skills/internal/preflight.md` sec."doc.yml - the gates", sec."extended_checks.yml". **A diff that adds or changes a per-PR gate step - a workflow step that runs on -`pull_request` and fails the lane when it finds a defect - makes that step fail on every -defect in what it checks, and on nothing else.** +`pull_request` and fails the lane when it finds a defect - makes the step's failure the +lane's failure: no `continue-on-error`, no trailing `|| true`, no swallowed exit code.** + +**A diff that adds or changes a per-PR gate step states a run of that step's command on the +lane's platform in its PR body or commit message; a green run of that lane on the PR's head +commit is that evidence.** A step that fails for a non-defect turns a green branch red for +everyone. **A diff that adds or changes a step in `pages.yml` that names the deployed games writes that list as a `for g in ; do` loop.** `examples/games/REVIEW.das` (repo root) reads diff --git a/.github/workflows/extended_checks.yml b/.github/workflows/extended_checks.yml index 5b47030bbe..2849bc01e2 100644 --- a/.github/workflows/extended_checks.yml +++ b/.github/workflows/extended_checks.yml @@ -523,6 +523,7 @@ jobs: run: | set -eux python3 utils/watchdog/test_tray_state.py + python3 utils/watchdog/test_consent.py - name: "Test pip wheel repack (python)" if: matrix.target == 'linux' diff --git a/.github/workflows/pages.yml b/.github/workflows/pages.yml index 1d6f69304a..4ac7ca5709 100644 --- a/.github/workflows/pages.yml +++ b/.github/workflows/pages.yml @@ -571,7 +571,8 @@ jobs: cp site-dasllama/robots.txt _site_dasllama/ cp site-dasllama/sitemap.xml _site_dasllama/ cp site-dasllama/feed.xml _site_dasllama/ - cp site-dasllama/files/* _site_dasllama/files/ + # -R: files/ now carries subdirectories (files/fonts/); a bare * would fail on them + cp -R site-dasllama/files/. _site_dasllama/files/ # Shared visual language, staged from the daslang.io tree — single source # in the repo, mirrored by site-dasllama/serve.py for local preview. diff --git a/LICENSE b/LICENSE index 9f90a8ccef..314e897df9 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ BSD 3-Clause License -Copyright (c) 2018-2026, Gaijin Entertainment +Copyright (c) 2018-2026, Gaijin Games Kft. All rights reserved. Redistribution and use in source and binary forms, with or without diff --git a/doc/source/_static/custom.css b/doc/source/_static/custom.css index 878e1f187d..d8b34e6ce9 100644 --- a/doc/source/_static/custom.css +++ b/doc/source/_static/custom.css @@ -8,7 +8,7 @@ /* `@import` must precede all other rules (CSS 2.1 §6.3) — keeping this * at the top of the file so browsers actually fetch the web fonts. A * later `@import` after `:root` would be silently dropped. */ -@import url('https://fonts.googleapis.com/css2?family=Inter+Tight:ital,wght@0,400;0,500;0,600;0,700;1,400;1,600&family=JetBrains+Mono:wght@400;500;600;700&display=swap'); +@import url('fonts/fonts.css'); :root { --bg: #0d0c0a; @@ -433,3 +433,13 @@ footer a { color: var(--fg-dim) !important; } .highlight .n { color: var(--fg); } .highlight .o, .highlight .p { color: var(--fg-dim); } .highlight .err { color: var(--red); background: transparent; border: none; } + +/* LEGAL footer links (layout.html footer block) */ +.forge-legal-links { + margin-top: 8px; + font-size: 90%; + color: var(--fg-faint); +} +.forge-legal-links a { + color: inherit; +} diff --git a/doc/source/_static/fonts/InterTight-italic-cyrillic-ext.woff2 b/doc/source/_static/fonts/InterTight-italic-cyrillic-ext.woff2 new file mode 100644 index 0000000000..83c2eff740 Binary files /dev/null and b/doc/source/_static/fonts/InterTight-italic-cyrillic-ext.woff2 differ diff --git a/doc/source/_static/fonts/InterTight-italic-cyrillic.woff2 b/doc/source/_static/fonts/InterTight-italic-cyrillic.woff2 new file mode 100644 index 0000000000..70552d21a2 Binary files /dev/null and b/doc/source/_static/fonts/InterTight-italic-cyrillic.woff2 differ diff --git a/doc/source/_static/fonts/InterTight-italic-greek-ext.woff2 b/doc/source/_static/fonts/InterTight-italic-greek-ext.woff2 new file mode 100644 index 0000000000..c81a4e55a9 Binary files /dev/null and b/doc/source/_static/fonts/InterTight-italic-greek-ext.woff2 differ diff --git a/doc/source/_static/fonts/InterTight-italic-greek.woff2 b/doc/source/_static/fonts/InterTight-italic-greek.woff2 new file mode 100644 index 0000000000..95d91ab686 Binary files /dev/null and b/doc/source/_static/fonts/InterTight-italic-greek.woff2 differ diff --git a/doc/source/_static/fonts/InterTight-italic-latin-ext.woff2 b/doc/source/_static/fonts/InterTight-italic-latin-ext.woff2 new file mode 100644 index 0000000000..12f8e8f5a5 Binary files /dev/null and b/doc/source/_static/fonts/InterTight-italic-latin-ext.woff2 differ diff --git a/doc/source/_static/fonts/InterTight-italic-latin.woff2 b/doc/source/_static/fonts/InterTight-italic-latin.woff2 new file mode 100644 index 0000000000..870e9b5982 Binary files /dev/null and b/doc/source/_static/fonts/InterTight-italic-latin.woff2 differ diff --git a/doc/source/_static/fonts/InterTight-italic-vietnamese.woff2 b/doc/source/_static/fonts/InterTight-italic-vietnamese.woff2 new file mode 100644 index 0000000000..072774eca7 Binary files /dev/null and b/doc/source/_static/fonts/InterTight-italic-vietnamese.woff2 differ diff --git a/doc/source/_static/fonts/InterTight-normal-cyrillic-ext.woff2 b/doc/source/_static/fonts/InterTight-normal-cyrillic-ext.woff2 new file mode 100644 index 0000000000..23a7b3eede Binary files /dev/null and b/doc/source/_static/fonts/InterTight-normal-cyrillic-ext.woff2 differ diff --git a/doc/source/_static/fonts/InterTight-normal-cyrillic.woff2 b/doc/source/_static/fonts/InterTight-normal-cyrillic.woff2 new file mode 100644 index 0000000000..f0a04608af Binary files /dev/null and b/doc/source/_static/fonts/InterTight-normal-cyrillic.woff2 differ diff --git a/doc/source/_static/fonts/InterTight-normal-greek-ext.woff2 b/doc/source/_static/fonts/InterTight-normal-greek-ext.woff2 new file mode 100644 index 0000000000..68cbfb4227 Binary files /dev/null and b/doc/source/_static/fonts/InterTight-normal-greek-ext.woff2 differ diff --git a/doc/source/_static/fonts/InterTight-normal-greek.woff2 b/doc/source/_static/fonts/InterTight-normal-greek.woff2 new file mode 100644 index 0000000000..0d638f0024 Binary files /dev/null and b/doc/source/_static/fonts/InterTight-normal-greek.woff2 differ diff --git a/doc/source/_static/fonts/InterTight-normal-latin-ext.woff2 b/doc/source/_static/fonts/InterTight-normal-latin-ext.woff2 new file mode 100644 index 0000000000..8df773db33 Binary files /dev/null and b/doc/source/_static/fonts/InterTight-normal-latin-ext.woff2 differ diff --git a/doc/source/_static/fonts/InterTight-normal-latin.woff2 b/doc/source/_static/fonts/InterTight-normal-latin.woff2 new file mode 100644 index 0000000000..228154ffb1 Binary files /dev/null and b/doc/source/_static/fonts/InterTight-normal-latin.woff2 differ diff --git a/doc/source/_static/fonts/InterTight-normal-vietnamese.woff2 b/doc/source/_static/fonts/InterTight-normal-vietnamese.woff2 new file mode 100644 index 0000000000..d08a67efd6 Binary files /dev/null and b/doc/source/_static/fonts/InterTight-normal-vietnamese.woff2 differ diff --git a/doc/source/_static/fonts/JetBrainsMono-normal-cyrillic-ext.woff2 b/doc/source/_static/fonts/JetBrainsMono-normal-cyrillic-ext.woff2 new file mode 100644 index 0000000000..024a1af5eb Binary files /dev/null and b/doc/source/_static/fonts/JetBrainsMono-normal-cyrillic-ext.woff2 differ diff --git a/doc/source/_static/fonts/JetBrainsMono-normal-cyrillic.woff2 b/doc/source/_static/fonts/JetBrainsMono-normal-cyrillic.woff2 new file mode 100644 index 0000000000..1b61cf966c Binary files /dev/null and b/doc/source/_static/fonts/JetBrainsMono-normal-cyrillic.woff2 differ diff --git a/doc/source/_static/fonts/JetBrainsMono-normal-greek.woff2 b/doc/source/_static/fonts/JetBrainsMono-normal-greek.woff2 new file mode 100644 index 0000000000..06f0936048 Binary files /dev/null and b/doc/source/_static/fonts/JetBrainsMono-normal-greek.woff2 differ diff --git a/doc/source/_static/fonts/JetBrainsMono-normal-latin-ext.woff2 b/doc/source/_static/fonts/JetBrainsMono-normal-latin-ext.woff2 new file mode 100644 index 0000000000..310faddfdd Binary files /dev/null and b/doc/source/_static/fonts/JetBrainsMono-normal-latin-ext.woff2 differ diff --git a/doc/source/_static/fonts/JetBrainsMono-normal-latin.woff2 b/doc/source/_static/fonts/JetBrainsMono-normal-latin.woff2 new file mode 100644 index 0000000000..2ca6ac6059 Binary files /dev/null and b/doc/source/_static/fonts/JetBrainsMono-normal-latin.woff2 differ diff --git a/doc/source/_static/fonts/JetBrainsMono-normal-vietnamese.woff2 b/doc/source/_static/fonts/JetBrainsMono-normal-vietnamese.woff2 new file mode 100644 index 0000000000..d37ea35987 Binary files /dev/null and b/doc/source/_static/fonts/JetBrainsMono-normal-vietnamese.woff2 differ diff --git a/doc/source/_static/fonts/fonts.css b/doc/source/_static/fonts/fonts.css new file mode 100644 index 0000000000..1462ddfea1 --- /dev/null +++ b/doc/source/_static/fonts/fonts.css @@ -0,0 +1,180 @@ +/* cyrillic-ext */ +@font-face { + font-family: 'Inter Tight'; + font-style: italic; + font-weight: 400 700; + font-display: swap; + src: url(InterTight-italic-cyrillic-ext.woff2) format('woff2'); + unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; +} +/* cyrillic */ +@font-face { + font-family: 'Inter Tight'; + font-style: italic; + font-weight: 400 700; + font-display: swap; + src: url(InterTight-italic-cyrillic.woff2) format('woff2'); + unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; +} +/* greek-ext */ +@font-face { + font-family: 'Inter Tight'; + font-style: italic; + font-weight: 400 700; + font-display: swap; + src: url(InterTight-italic-greek-ext.woff2) format('woff2'); + unicode-range: U+1F00-1FFF; +} +/* greek */ +@font-face { + font-family: 'Inter Tight'; + font-style: italic; + font-weight: 400 700; + font-display: swap; + src: url(InterTight-italic-greek.woff2) format('woff2'); + unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF; +} +/* vietnamese */ +@font-face { + font-family: 'Inter Tight'; + font-style: italic; + font-weight: 400 700; + font-display: swap; + src: url(InterTight-italic-vietnamese.woff2) format('woff2'); + unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB; +} +/* latin-ext */ +@font-face { + font-family: 'Inter Tight'; + font-style: italic; + font-weight: 400 700; + font-display: swap; + src: url(InterTight-italic-latin-ext.woff2) format('woff2'); + unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; +} +/* latin */ +@font-face { + font-family: 'Inter Tight'; + font-style: italic; + font-weight: 400 700; + font-display: swap; + src: url(InterTight-italic-latin.woff2) format('woff2'); + unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; +} +/* cyrillic-ext */ +@font-face { + font-family: 'Inter Tight'; + font-style: normal; + font-weight: 400 700; + font-display: swap; + src: url(InterTight-normal-cyrillic-ext.woff2) format('woff2'); + unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; +} +/* cyrillic */ +@font-face { + font-family: 'Inter Tight'; + font-style: normal; + font-weight: 400 700; + font-display: swap; + src: url(InterTight-normal-cyrillic.woff2) format('woff2'); + unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; +} +/* greek-ext */ +@font-face { + font-family: 'Inter Tight'; + font-style: normal; + font-weight: 400 700; + font-display: swap; + src: url(InterTight-normal-greek-ext.woff2) format('woff2'); + unicode-range: U+1F00-1FFF; +} +/* greek */ +@font-face { + font-family: 'Inter Tight'; + font-style: normal; + font-weight: 400 700; + font-display: swap; + src: url(InterTight-normal-greek.woff2) format('woff2'); + unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF; +} +/* vietnamese */ +@font-face { + font-family: 'Inter Tight'; + font-style: normal; + font-weight: 400 700; + font-display: swap; + src: url(InterTight-normal-vietnamese.woff2) format('woff2'); + unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB; +} +/* latin-ext */ +@font-face { + font-family: 'Inter Tight'; + font-style: normal; + font-weight: 400 700; + font-display: swap; + src: url(InterTight-normal-latin-ext.woff2) format('woff2'); + unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; +} +/* latin */ +@font-face { + font-family: 'Inter Tight'; + font-style: normal; + font-weight: 400 700; + font-display: swap; + src: url(InterTight-normal-latin.woff2) format('woff2'); + unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; +} +/* cyrillic-ext */ +@font-face { + font-family: 'JetBrains Mono'; + font-style: normal; + font-weight: 400 700; + font-display: swap; + src: url(JetBrainsMono-normal-cyrillic-ext.woff2) format('woff2'); + unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; +} +/* cyrillic */ +@font-face { + font-family: 'JetBrains Mono'; + font-style: normal; + font-weight: 400 700; + font-display: swap; + src: url(JetBrainsMono-normal-cyrillic.woff2) format('woff2'); + unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; +} +/* greek */ +@font-face { + font-family: 'JetBrains Mono'; + font-style: normal; + font-weight: 400 700; + font-display: swap; + src: url(JetBrainsMono-normal-greek.woff2) format('woff2'); + unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF; +} +/* vietnamese */ +@font-face { + font-family: 'JetBrains Mono'; + font-style: normal; + font-weight: 400 700; + font-display: swap; + src: url(JetBrainsMono-normal-vietnamese.woff2) format('woff2'); + unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB; +} +/* latin-ext */ +@font-face { + font-family: 'JetBrains Mono'; + font-style: normal; + font-weight: 400 700; + font-display: swap; + src: url(JetBrainsMono-normal-latin-ext.woff2) format('woff2'); + unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; +} +/* latin */ +@font-face { + font-family: 'JetBrains Mono'; + font-style: normal; + font-weight: 400 700; + font-display: swap; + src: url(JetBrainsMono-normal-latin.woff2) format('woff2'); + unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; +} diff --git a/doc/source/_templates/layout.html b/doc/source/_templates/layout.html index 114e53fc32..1af3c6a248 100644 --- a/doc/source/_templates/layout.html +++ b/doc/source/_templates/layout.html @@ -47,3 +47,14 @@
{%- endblock %} + +{# LEGAL links block — GDPR/EU distributor requirement: Terms, Privacy, license + reachable from every docs page. Rendered under the theme footer. #} +{%- block footer %} + {{ super() }} + +{%- endblock %} diff --git a/doc/source/reference/utils/dasllama_server.rst b/doc/source/reference/utils/dasllama_server.rst index 28aede34e5..b8238ac285 100644 --- a/doc/source/reference/utils/dasllama_server.rst +++ b/doc/source/reference/utils/dasllama_server.rst @@ -189,6 +189,9 @@ Endpoints * - ``POST`` - ``/exchange/retune`` - Arm a local re-tune and restart — the next boot races this box + * - ``POST`` + - ``/exchange/consent`` + - ``{"accept": true|false}`` — record the first-contact choice about contacting the exchange; accept on an untuned box drains and restarts to run the lookup * - ``POST`` - ``/gc`` - Schedule a validated collection at the next lifecycle safe point; concurrent requests coalesce diff --git a/install/README.md b/install/README.md index 53261eefb1..25b4e3fab0 100644 --- a/install/README.md +++ b/install/README.md @@ -160,5 +160,5 @@ Binaries produced by `cmake --install` are ad-hoc code signed automatically, whi ## License -BSD 3-Clause License - Copyright (c) 2019-2026, Gaijin Entertainment. +BSD 3-Clause License - Copyright (c) 2018-2026, Gaijin Games Kft. See `LICENSE` for the full text. diff --git a/modules/dasLLAMA/ARCHITECTURE_ENGINE.md b/modules/dasLLAMA/ARCHITECTURE_ENGINE.md index d5ef22fd07..dac55550bf 100644 --- a/modules/dasLLAMA/ARCHITECTURE_ENGINE.md +++ b/modules/dasLLAMA/ARCHITECTURE_ENGINE.md @@ -190,8 +190,12 @@ file builds an `ArchDesc` (name * `configure` * the `ArchBlocks` fn-ptr quad * ` (record stores + tune sidecars); the dasllama.io ladder service builds on it. - **`dasllama/dasllama_exchange.das`** - the sidecar-exchange client (a sanctioned public entry point): the boot-time lookup/apply (llvm_tune's scope resolver - a verified per-box match downloads instead of a - ~20-minute tune), the privacy-stripped submit rails, and the control-page surface - dasllama-server serves at `/exchange`. + ~12-minute tune), the privacy-stripped submit rails, and the control-page surface + dasllama-server serves at `/exchange`. The first-contact consent gate (GDPR) sits ahead of + every lookup: an explicit `exchange_*` config counts as the expressed choice, otherwise the + `.consent` sidecar-sibling file governs - unset asks on a real terminal, or emits + `@sidecar consent state=needed` for the watchdog dialog / control page, and no request + leaves until a surface records "accepted". - **`benchmarks/asr/mem_census.sh`** - the peak-memory census (`/usr/bin/time -l` around one asr_bench process per cell; macOS only) - the interim footprint instrument until a footprint leg lands in `gen_bench_records`; its numbers live in `PERF_LEDGER.md`, never the stores. diff --git a/modules/dasLLAMA/ARCHITECTURE_MEASUREMENT.md b/modules/dasLLAMA/ARCHITECTURE_MEASUREMENT.md index 3eecddd6e4..7a6ff9fbca 100644 --- a/modules/dasLLAMA/ARCHITECTURE_MEASUREMENT.md +++ b/modules/dasLLAMA/ARCHITECTURE_MEASUREMENT.md @@ -64,3 +64,9 @@ stages, tokenizer build) - the rails do not apply. A clock whose value feeds log flow, not instrumentation; it is marked `// clock: control` so the sweep and any future lint leave it alone. +The override-announce rule (REVIEW.md) draws its boundary here: a knob or setter whose purpose +is timing still counts as an override when it moves computed numerics - two GEMM forms of the +same math differ in float terms - while one that changes only WHEN work happens does not, and +a CLI flag is never an override (it is the run's own command line, visible where the run is +launched). + diff --git a/modules/dasLLAMA/ENVIRONMENT.md b/modules/dasLLAMA/ENVIRONMENT.md index 022757a0c7..00e3945ad6 100644 --- a/modules/dasLLAMA/ENVIRONMENT.md +++ b/modules/dasLLAMA/ENVIRONMENT.md @@ -241,8 +241,8 @@ Overrides for the dasllama.io exchange client. | Variable | Type | Default | Effect | |---|---|---|---| -| `DASLLAMA_EXCHANGE_URL` | text | unset | Sidecar exchange base URL override (tests, mirrors); unset = the baked-in dasllama.io. | -| `DASLLAMA_EXCHANGE_ACCEPT` | text | unset | One-shot exchange accept-policy override: verified | any | off; unset = the app config's exchange_accept. The watchdog arms 'any' on a relaunch when the user adopts an unverified sidecar over finishing a tune. | +| `DASLLAMA_EXCHANGE_URL` | text | unset | Sidecar exchange base URL override (tests, mirrors); unset = the baked-in dasllama.io. Setting it is an expressed choice to use the exchange - the first-contact consent question is skipped (announced at boot). | +| `DASLLAMA_EXCHANGE_ACCEPT` | text | unset | One-shot exchange accept-policy override: verified | any | off; unset = the app config's exchange_accept. The watchdog arms 'any' on a relaunch when the user adopts an unverified sidecar over finishing a tune. Setting it is an expressed choice to use the exchange - the first-contact consent question is skipped (announced at boot). | ## daslang core knobs dasLLAMA honours diff --git a/modules/dasLLAMA/REVIEW.md b/modules/dasLLAMA/REVIEW.md index ad8b7cd1c1..898e0f11c3 100644 --- a/modules/dasLLAMA/REVIEW.md +++ b/modules/dasLLAMA/REVIEW.md @@ -1,9 +1,9 @@ # dasLLAMA Code Review Checklist -**Read `REVIEW_COMMON.md` (repo root) first - its contract binds this checklist.** Architecture doc: -`ARCHITECTURE.md`. Planned work: `followup_general.md`, `followup_vulkan.md`; the perf -backlog is `PERF_LEDGER.md` - a performance followup goes there, everything else in the -two followup ledgers. +**Read `REVIEW_COMMON.md` (repo root) first - its contract binds this checklist.** Architecture +docs: `ARCHITECTURE.md` and the `ARCHITECTURE_*.md` companions it indexes. Planned work: +`followup_general.md`, `followup_vulkan.md`, `PERF_LEDGER.md` (performance goes to the perf +ledger, everything else to the followup ledgers). **A dasLLAMA `[test]` file, wherever the diff puts it, answers to this module's `tests/REVIEW.md`.** @@ -87,8 +87,12 @@ file's sec.1 charter line in `ARCHITECTURE_ENGINE.md`, `ARCHITECTURE_GPU.md`, or **Platform-specific code in an engine file (`dasllama/`) lands only in that platform's backend file.** -**A new engine concern that is not `Model`/`Session`/`Config` state gets its own file, not -more of `dasllama/dasllama_common.das`.** +**A diff that adds a new engine concern that is not `Model`/`Session`/`Config` state to +`dasllama/dasllama_common.das` is a defect - give the concern its own file.** + +**A boot-path prompt (code that runs at startup, before the first request) that reads stdin +without first proving both stdin and stdout are terminals is a defect - emit the question as +a `@sidecar` event instead.** A supervised or piped boot must never block on input. **A NEW clock read paired with a print or log of the elapsed interval is a defect in an engine file (`dasllama/`) outside a cold one-shot load, bake, map, or tokenizer-build progress log** - @@ -124,14 +128,13 @@ template strings any of them look up, records a `tests/test_tokenizer.das` run w EXECUTED, not skipped.** **A diff that adds an override, or gives one a new effect, without the announce is a defect.** -An override is an environment knob or an exported runtime setter that moves a gate, policy, or -threshold off its default and thereby changes what the run writes, reads, mints, or computes - -including a knob or setter whose purpose is timing when it moves computed numerics, since two -GEMM forms of the same math differ in float terms. A knob or setter that changes only WHEN work -happens is not an override, and a CLI flag is never one. The announce is a line the run prints -where the override changes the outcome, naming it by the spelling a user would set - the -environment variable name, the sidecar key, or the setter's function name. Per-site repeats are -fine. A set-but-inert override stays silent. +An override is an environment knob, an exported runtime setter, or an on-disk state file that +moves a gate, policy, or threshold off its default and thereby changes what the run writes, +reads, mints, or computes - a timing knob included when it moves computed numerics. A knob +that changes only WHEN work happens is not one, and a CLI flag is never one. The announce is +a line the run prints where the override changes the outcome, naming it by the spelling a +user would set - the environment variable name, the sidecar or file key, or the setter's +function name. Per-site repeats are fine; a set-but-inert override stays silent. **A change to user-facing API updates every place it is shown: a tutorial source, `.rst` page, docstring, help string, `README.md`, or checked-in document still showing the old call, flag, or @@ -238,7 +241,8 @@ file** - a single-caller helper sanctioned as tower-worthy is ledgered on **A harness that prints output for another tool to compare exits non-zero when its run ends without those comparison lines - wrong flags, failed load.** -**Tool wire text - building or parsing - is produced only in `dasllama/dasllama_tools.das`.** +**Tool wire text (the text of a model's tool/function call, built or parsed) is produced only +in `dasllama/dasllama_tools.das`.** **No engine file (`dasllama/`) other than `dasllama/dasllama_audio_io.das` requires `audio` (the miniaudio decode module).** diff --git a/modules/dasLLAMA/dasllama/dasllama_env.das b/modules/dasLLAMA/dasllama/dasllama_env.das index 11868a0e7e..e6ed7dab00 100644 --- a/modules/dasLLAMA/dasllama/dasllama_env.das +++ b/modules/dasLLAMA/dasllama/dasllama_env.das @@ -653,10 +653,10 @@ struct public ExampleEnv { [EnvConfig(env_prefix = "DASLLAMA")] struct public ExchangeEnv { - @clarg_doc = "Sidecar exchange base URL override (tests, mirrors); unset = the baked-in dasllama.io." + @clarg_doc = "Sidecar exchange base URL override (tests, mirrors); unset = the baked-in dasllama.io. Setting it is an expressed choice to use the exchange - the first-contact consent question is skipped (announced at boot)." exchange_url : string = "" - @clarg_doc = "One-shot exchange accept-policy override: verified | any | off; unset = the app config's exchange_accept. The watchdog arms 'any' on a relaunch when the user adopts an unverified sidecar over finishing a tune." + @clarg_doc = "One-shot exchange accept-policy override: verified | any | off; unset = the app config's exchange_accept. The watchdog arms 'any' on a relaunch when the user adopts an unverified sidecar over finishing a tune. Setting it is an expressed choice to use the exchange - the first-contact consent question is skipped (announced at boot)." exchange_accept : string = "" } diff --git a/modules/dasLLAMA/dasllama/dasllama_exchange.das b/modules/dasLLAMA/dasllama/dasllama_exchange.das index 14bbc4bd99..3a3b93c95d 100644 --- a/modules/dasLLAMA/dasllama/dasllama_exchange.das +++ b/modules/dasLLAMA/dasllama/dasllama_exchange.das @@ -17,10 +17,11 @@ require daslib/sha_256 require daslib/toml require daslib/strings_boost require daslib/fio +require daslib/tty require strings // The dasllama.io exchange client: at an untuned boot, download a matching per-box tune -// sidecar instead of paying ~20 quiet-box minutes; after a local tune, offer/submit it back. +// sidecar instead of paying ~12 quiet-box minutes; after a local tune, offer/submit it back. // Registered as llvm_tune's scope resolver by dasllama-server ([init] — before the guard); // lcpp_bench uses only the submit half. The service contract lives in the repo's // dasllama-ladder README §1.1; validation is dasllama_exchange_schema, shared with the service. @@ -48,8 +49,16 @@ struct ExchangePolicy { url : string = EXCHANGE_URL_DEFAULT accept : string = "verified" // verified | any | off submit : string = "ask" // ask | always | never + configured : bool = false // any exchange_* key came from the config file or env — an explicit choice + configured_via : string = "" // the knob spelling that expressed it, for the waiver announce } +//! The first-contact notice, shown before ANY request leaves for the exchange (GDPR: the +//! lookup transmits the box identity, and the server sees the connection's IP like any web +//! server). PLACEHOLDER wording — Gaijin legal owns the final text; the watchdog dialog +//! (utils/watchdog/watchdog.py CONSENT_*) carries the same wording, keep the two in sync. +let public EXCHANGE_CONSENT_NOTICE = "dasLLAMA can download a ready performance-tuning preset (a \"sidecar\") for this machine from dasllama.io, instead of spending ~12 minutes tuning locally.\nThe request sends only your hardware class - platform, CPU model and OS build. No serial numbers, user names or other personal data; no cookies. Sharing your own tuning results back is always confirmed separately.\nDetails: https://legal.gaijin.net/privacypolicy" + // structured events for the watchdog (same contract as @tune): folded into supervisor STATE def private sc_event(kind : string; kv : string) { print("@sidecar {kind}{empty(kv) ? "" : " "}{kv}\n") @@ -278,17 +287,33 @@ def exchange_policy_from_config(config_path : string) : ExchangePolicy { var terr = "" var root = read_toml(body, terr) if (root != null) { + // an AUTHORITATIVE toml is what the control page saves, and its gatherConfig + // persists the exchange defaults on EVERY save - so its exchange keys are not + // evidence of a choice; only a hand-written config's are (env overrides too) + let hand_written = !(root?["authoritative"] ?? false) let u : string = root?["exchange_url"] ?? "" if (!empty(u)) { p.url = u + if (hand_written) { + p.configured = true + p.configured_via = "exchange_url (config)" + } } let a : string = root?["exchange_accept"] ?? "" if (!empty(a)) { p.accept = a + if (hand_written) { + p.configured = true + p.configured_via = "exchange_accept (config)" + } } let s : string = root?["exchange_submit"] ?? "" if (!empty(s)) { p.submit = s + if (hand_written) { + p.configured = true + p.configured_via = "exchange_submit (config)" + } } unsafe { delete root @@ -298,9 +323,13 @@ def exchange_policy_from_config(config_path : string) : ExchangePolicy { } if (!empty(g_env_exchange.exchange_url)) { p.url = g_env_exchange.exchange_url + p.configured = true + p.configured_via = "DASLLAMA_EXCHANGE_URL (env)" } if (!empty(g_env_exchange.exchange_accept)) { p.accept = g_env_exchange.exchange_accept + p.configured = true + p.configured_via = "DASLLAMA_EXCHANGE_ACCEPT (env)" } if (p.accept != "verified" && p.accept != "any" && p.accept != "off") { print("exchange: unknown exchange_accept '{p.accept}' - using verified (valid: verified | any | off)\n") @@ -313,6 +342,84 @@ def exchange_policy_from_config(config_path : string) : ExchangePolicy { return p } +// ===== consent (GDPR first-contact gate) ===== + +// the sidecar-sibling naming rule: foo.tune.json and foo.tune both yield foo.tune. +def private sidecar_sibling_path(manifest : string; ext : string) : string { + return (ends_with(manifest, ".json") + ? "{slice(manifest, 0, length(manifest) - 5)}.{ext}" + : "{manifest}.{ext}") +} + +// the sidecar-sibling consent file: "accepted" / "declined", one word. An explicit exchange +// config (any exchange_* key, TOML or env) is itself consent, so the file only governs the +// zero-config default path. +def private exchange_consent_path() : string { + return sidecar_sibling_path(tune_manifest_path(), "consent") +} + +//! The recorded first-contact choice: "accepted" | "declined" | "" (never asked). +def exchange_consent_status() : string { + let text = fread(exchange_consent_path()) + let word = strip(text) + return (word == "accepted" || word == "declined") ? word : "" +} + +//! Record the first-contact choice (console prompt, watchdog dialog, control page — every +//! surface lands here). Emits the `@sidecar consent` event so the supervisor state follows. +def exchange_record_consent(accept : bool) : bool { + let word = accept ? "accepted" : "declined" + if (!fwrite(exchange_consent_path(), "{word}\n")) { + return false + } + sc_event("consent", "state={word}") + return true +} + +// The interactive arm: notice + Accept/Decline on the console. Enter defaults to Accept +// (the dialog's default button); anything starting d/D/n/N declines. Only reached on a real +// terminal — a supervised or piped boot must never block on stdin. +def private consent_prompt_console() : bool { + print("\n{EXCHANGE_CONSENT_NOTICE}\n\n") + print("Use the exchange? [Accept]/decline: ") + let line = fgets(fstdin()) + if (empty(line)) { + // EOF (Ctrl+D / closed stdin) is a walkaway, not an answer - record nothing, ask + // again next boot. A bare Enter arrives as "\n", so it never lands here. + print("exchange: no answer - tuning locally; the question returns next boot\n") + return false + } + let word = to_lower(strip(line)) + let accepted = !(word |> starts_with("d") || word |> starts_with("n")) + if (!exchange_record_consent(accepted)) { + print("exchange: could not record the choice at {exchange_consent_path()} - not contacting the exchange\n") + return false + } + print(accepted ? "exchange: enabled - this choice is remembered\n" : "exchange: declined - this box tunes locally; the control page can enable it later\n") + return accepted +} + +// The gate the resolver runs before the first request leaves. True = a request may be made. +// No recorded choice: a real terminal asks inline; anything else stays offline this boot and +// surfaces the question where a human is (watchdog dialog, control page) via the event. +def private exchange_consent_gate() : bool { + let status = exchange_consent_status() + if (status == "accepted") { + print("exchange: consent on record at {exchange_consent_path()} (exchange_record_consent) - proceeding\n") + return true + } + if (status == "declined") { + print("exchange: disabled by the recorded choice - tuning locally (the control page can enable it)\n") + return false + } + if (is_stdin_terminal() && is_stdout_terminal()) { + return consent_prompt_console() + } + sc_event("consent", "state=needed path={url_encode(exchange_consent_path())}") + print("exchange: no recorded choice about contacting dasllama.io - tuning locally; answer the tray dialog or use the control page to enable the exchange\n") + return false +} + // ===== the boot resolver (llvm_tune scope-resolver seam) ===== var private g_resolver_config = "" @@ -327,6 +434,22 @@ def exchange_register_resolver(app_config_name : string) { tune_set_scope_resolver(@@exchange_scope_resolver) } +//! The pre-request decision the boot resolver enforces: nothing leaves for the exchange +//! without an expressed choice. `accept = off` never contacts; an explicit exchange config +//! IS the choice (announced by the knob that expressed it); otherwise the recorded consent +//! file governs - unset asks on a real terminal or emits the `@sidecar consent` event. +def exchange_may_contact(policy : ExchangePolicy) : bool { + if (policy.accept == "off") { + return false + } + if (policy.configured) { + // the override announce: name the knob that expressed the choice and waived the question + print("exchange: consent expressed via {policy.configured_via} - not asking\n") + return true + } + return exchange_consent_gate() +} + def private exchange_scope_resolver(scope_name : string; manifest_path : string; _fnames : string) : bool { // one lookup per process — a second scope re-checks completeness off the same applied file if (g_resolve_attempted) { @@ -341,7 +464,8 @@ def private exchange_scope_resolver(scope_name : string; manifest_path : string; return false } let policy = exchange_policy_from_config(exchange_discover_config(g_resolver_config)) - if (policy.accept == "off") { + // GDPR first-contact gate: nothing leaves for the exchange without an expressed choice + if (!exchange_may_contact(policy)) { return false } let box = tune_box_identity() @@ -388,9 +512,7 @@ def private exchange_scope_resolver(scope_name : string; manifest_path : string; // the sidecar-sibling state file remembering what this box already shared def private exchange_state_path(manifest : string) : string { - return (ends_with(manifest, ".json") - ? "{slice(manifest, 0, length(manifest) - 5)}.exchange.json" - : "{manifest}.exchange.json") + return sidecar_sibling_path(manifest, "exchange.json") } def private state_submitted_for(manifest : string) : string { @@ -519,7 +641,7 @@ def exchange_submit_current(policy : ExchangePolicy) : string { return "" } -//! Arm a local re-tune: the next boot skips the exchange once and races this box (~20 min, +//! Arm a local re-tune: the next boot skips the exchange once and races this box (~12 min, //! quiet machine). The marker is written FIRST and only then is the sidecar removed — a failed //! marker write leaves the sidecar intact and returns the error, so the box is never left with //! no sidecar AND no re-tune armed (which would silently fall back to the exchange). "" on success. @@ -567,7 +689,10 @@ def exchange_status_json(policy : ExchangePolicy) : string { cur_tab |> insert("version_ok", JV(info.dasllama_version == DASLLAMA_VERSION)) } var top <- { - "policy" => JV((url = policy.url, accept = policy.accept, submit = policy.submit)), + "policy" => JV((url = policy.url, accept = policy.accept, submit = policy.submit, + configured = policy.configured)), + "consent" => JV(exchange_consent_status()), + "consent_notice" => JV(EXCHANGE_CONSENT_NOTICE), "engine_version" => JV(int64(DASLLAMA_VERSION)), "box" => JV(tune_box_identity()), "manifest" => JV(manifest), @@ -623,7 +748,9 @@ def exchange_boot_submit_check(policy : ExchangePolicy) { if (state_submitted_for(manifest) == raw_sha) { return } - if (policy.submit == "always") { + // submit=always out of an authoritative toml is not consent either (the page persists it + // on every save) - without a recorded choice the auto-share degrades to the ask offer + if (policy.submit == "always" && (policy.configured || exchange_consent_status() == "accepted")) { let err = exchange_submit_current(policy) if (empty(err)) { print("exchange: shared this box's tune (exchange_submit=always)\n") diff --git a/modules/dasLLAMA/performance/REVIEW.md b/modules/dasLLAMA/performance/REVIEW.md index 1f905fac80..f66082236f 100644 --- a/modules/dasLLAMA/performance/REVIEW.md +++ b/modules/dasLLAMA/performance/REVIEW.md @@ -98,3 +98,20 @@ the box its provenance names, at the current `dasllama_version` - never a hand-e `REVIEW.das` (beside this file) machine-checks the age-independent half (`noise` `ok`, `validation` `ok`, every `race` winner equal to its `kernels` value); weakening that gate is a defect. + +**A diff that changes the exchange consent notice wording updates every checked-in copy in +the same change, and a diff that adds a copy names it here in the same change: +`EXCHANGE_CONSENT_NOTICE` (`../dasllama/dasllama_exchange.das`), `CONSENT_TITLE` / +`CONSENT_TEXT` (`utils/watchdog/watchdog.py`, repo root), and the captured +`utils/dasllama-server/tests/fixtures/exchange.json` (repo root).** The console prompt and the +control page render the served constant, so they are not copies. + +**A diff that adds an outbound exchange request reachable from a tune-boot path +(`exchange_scope_resolver` / `exchange_boot_submit_check`) without routing it through +`exchange_may_contact` (`../dasllama/dasllama_exchange.das`) is a defect.** + +**A diff that adds a tune-boot-path (`exchange_scope_resolver` / +`exchange_boot_submit_check`) consent question with no terminal to ask on also emits that +question as a `@sidecar` event, in the same change** - the watchdog dialog and the control +page are the answer surfaces a supervised boot has. (The stdin-prompt ban itself is +`modules/dasLLAMA/REVIEW.md`'s, which every file under the module applies.) diff --git a/modules/dasLLAMA/tests/_interrupt_probe.das b/modules/dasLLAMA/tests/_interrupt_probe.das new file mode 100644 index 0000000000..5ad1c75ced --- /dev/null +++ b/modules/dasLLAMA/tests/_interrupt_probe.das @@ -0,0 +1,16 @@ +options gen2 +options indenting = 4 +options _dasllama_internal = true + +// dastest fixture, spawned by test_tune_interrupt.das: one interrupt_gate() call between a +// BEFORE and an AFTER print. While DAS_TUNE_CONTROL names an existing file the gate must +// abort (exit 1, nothing past it runs); otherwise it passes through. + +require ../harness/tuner_noise.das + +[export] +def main { + print("PROBE: before gate\n") + interrupt_gate("probe_family") + print("PROBE: gate passed through\n") +} diff --git a/modules/dasLLAMA/tests/run.das b/modules/dasLLAMA/tests/run.das index 9cd8816282..eab0462e32 100644 --- a/modules/dasLLAMA/tests/run.das +++ b/modules/dasLLAMA/tests/run.das @@ -137,6 +137,7 @@ def private suite_files(name : string) : array { // nolint:STYLE038 - "modules/dasLLAMA/tests/test_tok_seed.das", "modules/dasLLAMA/tests/test_tool_formats.das", "modules/dasLLAMA/tests/test_tower_helpers.das", + "modules/dasLLAMA/tests/test_tune_interrupt.das", "modules/dasLLAMA/tests/test_unicode.das", "modules/dasLLAMA/tests/test_vision.das", "modules/dasLLAMA/tests/test_vision_chat.das", diff --git a/modules/dasLLAMA/tests/test_tune_interrupt.das b/modules/dasLLAMA/tests/test_tune_interrupt.das new file mode 100644 index 0000000000..e089aaf00e --- /dev/null +++ b/modules/dasLLAMA/tests/test_tune_interrupt.das @@ -0,0 +1,72 @@ +options gen2 +options indenting = 4 +options persistent_heap + +require dastest/testing_boost public +require daslib/command_line +require daslib/strings_boost +require daslib/fio +require strings + +// The supervisor cancel-minting rail, end to end in a child process: while the file named by +// DAS_TUNE_CONTROL exists, interrupt_gate() aborts between kernel families - the @tune abort +// event fires and nothing past the gate runs (minting is end-gated, so an interrupted run +// writes no sidecar). The env is load-once, so a spawned child is the only honest probe. + +def private run_probe(control_env : string) : string { + let win = get_platform_name() == "windows" + // an empty control_env is spelled as an explicit UNSET - the parent (the watchdog sets + // this very variable) must never leak its own value into the "unset" cell + let envs = (empty(control_env) + ? (win ? "set \"DAS_TUNE_CONTROL=\"&& " : "env -u DAS_TUNE_CONTROL ") + : (win ? "set \"DAS_TUNE_CONTROL={control_env}\"&& " + : "DAS_TUNE_CONTROL=\"{control_env}\" ")) + let cmd = "{envs}\"{get_das_exe()}\" \"modules/dasLLAMA/tests/_interrupt_probe.das\" -dasroot \"{get_das_root()}\" 2>&1" + var out = "" + unsafe { + popen(cmd) $(f) { + if (f != null) { + out = build_string() $(w) { + while (!feof(f)) { + w |> write(fgets(f)) + } + } + } + } + } + return out +} + +[test] +def test_interrupt_aborts_without_minting(t : T?) { + t |> run("a present control file aborts at the gate") @(tt : T?) { + let res = create_temp_file_result("tune_control_", ".stop") + if (res is error) { + tt |> failure("could not create a temp control file") + return + } + let control = res as value + let out = run_probe(control) + tt |> success(out |> find("PROBE: before gate") >= 0, "the probe ran to the gate: {out}") + tt |> success(out |> find("@tune abort reason=interrupted at=probe_family") >= 0, "the abort event fired: {out}") + tt |> success(out |> find("gate passed through") < 0, "nothing past the gate ran - minting is end-gated, so nothing was written: {out}") + remove(control) + } + t |> run("a named-but-absent control file passes through") @(tt : T?) { + let res = create_temp_file_result("tune_control_", ".stop") + if (res is error) { + tt |> failure("could not create a temp control file") + return + } + let control = res as value + remove(control) + let out = run_probe(control) + tt |> success(out |> find("gate passed through") >= 0, "the gate is armed only while the file EXISTS: {out}") + tt |> success(out |> find("@tune abort") < 0, "no abort without the file: {out}") + } + t |> run("no DAS_TUNE_CONTROL passes through") @(tt : T?) { + let out = run_probe("") + tt |> success(out |> find("gate passed through") >= 0, "unset env never interrupts: {out}") + tt |> success(out |> find("@tune abort") < 0, "no abort with the env unset: {out}") + } +} diff --git a/site-dasllama/REVIEW.md b/site-dasllama/REVIEW.md index f30bc0d3d1..82cb57329e 100644 --- a/site-dasllama/REVIEW.md +++ b/site-dasllama/REVIEW.md @@ -10,8 +10,9 @@ implementation that does not exist yet. **A code sample shown on a page that does not compile and run with the current toolchain is a defect.** -**A number shown on a page is a defect unless it is rendered from live data, copied from a -checked-in measurement record, or carries an HTML comment naming it a placeholder.** +**A number shown on a page carries checkable provenance: rendered from live data, copied from +a named checked-in measurement record, or an HTML comment naming the box, date, and what was +measured (or naming it a placeholder). A number with none of these is a defect.** **A claim in words on index.html that one engine beats another ("beats", "Nx faster than", "fastest") is a defect, the generated news region included.** Figures copied from a @@ -21,9 +22,13 @@ reader does is not the page's claim. **Copy or rendering that lets a row with no reference engine's figure imply parity with a reference engine is a defect - an empty ratio cell reads "not raced".** -**A new `dl-*` CSS rule in any file under this directory is a defect** - the `dl-*` -measurement-table styles live only in `site/files/dasllama-table.css`, and site chrome here -uses the `dio-` prefix in `files/dasllama-io.css`. +**A `dl-*` selector that `site/files/dasllama-table.css` (repo root) does not already +define, declared in any file under this directory, is a defect** - site chrome here uses the +`dio-` prefix in `files/dasllama-io.css`, and the `dl-*` measurement-table language is that +shared sheet's. + +**A statement on a page here about what a shipped tool does is a defect unless it matches +the current code.** **A claim in a `_news/*.md` entry that is not true at publish time is a defect, including a claim about what a page here renders - check that one against the page's markup and @@ -40,3 +45,7 @@ quoted-attribute values, `Number(...)` for anything numeric, and `safeApiHref()` **A page that lacks ``, a meta description, OpenGraph tags, or the Atom `<link>` is a defect - a new or renamed page included.** + +**A diff that adds a file under `files/` also verifies the dasllama.io deploy step +(`.github/workflows/pages.yml`, "Stage dasllama.io for deployment") stages it, in the same +change.** Local preview serves the tree directly, so a staging miss is invisible until deploy. diff --git a/site-dasllama/files/dasllama-io.css b/site-dasllama/files/dasllama-io.css index a6d2932dee..103566c2d1 100644 --- a/site-dasllama/files/dasllama-io.css +++ b/site-dasllama/files/dasllama-io.css @@ -167,7 +167,7 @@ /* ── footer ──────────────────────────────────────────────────── */ .dio-footer{padding:52px 0 60px;border-top:1px solid var(--rule);font-family:var(--font-mono);font-size:12.5px;margin-top:40px} -.dio-footer__grid{display:grid;grid-template-columns:1.5fr 1fr 1fr 1fr;gap:32px} +.dio-footer__grid{display:grid;grid-template-columns:1.5fr 1fr 1fr 1fr 1fr;gap:32px} .dio-footer__about{margin-top:14px;color:var(--fg-faint);line-height:1.65;max-width:290px} .dio-footer__head{color:var(--fg-faint);margin-bottom:12px;text-transform:uppercase;letter-spacing:.1em;font-size:10.5px} .dio-footer a.dio-footer__link{color:var(--fg);display:block;margin-bottom:8px} diff --git a/site-dasllama/files/dasllama-io.js b/site-dasllama/files/dasllama-io.js index 412f3cb2ed..1ab5d08bb1 100644 --- a/site-dasllama/files/dasllama-io.js +++ b/site-dasllama/files/dasllama-io.js @@ -661,7 +661,7 @@ }); var head = '<div class="dio-sc__head"><span>status</span><span>box</span><span>engine sha</span><span>date</span><span>noise</span><span></span><span></span></div>'; if (!show.length) { - listBox.innerHTML = head + '<div class="dl-empty">Nothing here yet — tuning your box takes ~20 min of quiet machine and publishes the sidecar that rides along.</div>'; + listBox.innerHTML = head + '<div class="dl-empty">Nothing here yet — tuning your box takes ~12 min of quiet machine and publishes the sidecar that rides along.</div>'; return; } listBox.innerHTML = head + show.map(function (r, i) { diff --git a/site-dasllama/files/fonts/InterTight-italic-cyrillic-ext.woff2 b/site-dasllama/files/fonts/InterTight-italic-cyrillic-ext.woff2 new file mode 100644 index 0000000000..83c2eff740 Binary files /dev/null and b/site-dasllama/files/fonts/InterTight-italic-cyrillic-ext.woff2 differ diff --git a/site-dasllama/files/fonts/InterTight-italic-cyrillic.woff2 b/site-dasllama/files/fonts/InterTight-italic-cyrillic.woff2 new file mode 100644 index 0000000000..70552d21a2 Binary files /dev/null and b/site-dasllama/files/fonts/InterTight-italic-cyrillic.woff2 differ diff --git a/site-dasllama/files/fonts/InterTight-italic-greek-ext.woff2 b/site-dasllama/files/fonts/InterTight-italic-greek-ext.woff2 new file mode 100644 index 0000000000..c81a4e55a9 Binary files /dev/null and b/site-dasllama/files/fonts/InterTight-italic-greek-ext.woff2 differ diff --git a/site-dasllama/files/fonts/InterTight-italic-greek.woff2 b/site-dasllama/files/fonts/InterTight-italic-greek.woff2 new file mode 100644 index 0000000000..95d91ab686 Binary files /dev/null and b/site-dasllama/files/fonts/InterTight-italic-greek.woff2 differ diff --git a/site-dasllama/files/fonts/InterTight-italic-latin-ext.woff2 b/site-dasllama/files/fonts/InterTight-italic-latin-ext.woff2 new file mode 100644 index 0000000000..12f8e8f5a5 Binary files /dev/null and b/site-dasllama/files/fonts/InterTight-italic-latin-ext.woff2 differ diff --git a/site-dasllama/files/fonts/InterTight-italic-latin.woff2 b/site-dasllama/files/fonts/InterTight-italic-latin.woff2 new file mode 100644 index 0000000000..870e9b5982 Binary files /dev/null and b/site-dasllama/files/fonts/InterTight-italic-latin.woff2 differ diff --git a/site-dasllama/files/fonts/InterTight-italic-vietnamese.woff2 b/site-dasllama/files/fonts/InterTight-italic-vietnamese.woff2 new file mode 100644 index 0000000000..072774eca7 Binary files /dev/null and b/site-dasllama/files/fonts/InterTight-italic-vietnamese.woff2 differ diff --git a/site-dasllama/files/fonts/InterTight-normal-cyrillic-ext.woff2 b/site-dasllama/files/fonts/InterTight-normal-cyrillic-ext.woff2 new file mode 100644 index 0000000000..23a7b3eede Binary files /dev/null and b/site-dasllama/files/fonts/InterTight-normal-cyrillic-ext.woff2 differ diff --git a/site-dasllama/files/fonts/InterTight-normal-cyrillic.woff2 b/site-dasllama/files/fonts/InterTight-normal-cyrillic.woff2 new file mode 100644 index 0000000000..f0a04608af Binary files /dev/null and b/site-dasllama/files/fonts/InterTight-normal-cyrillic.woff2 differ diff --git a/site-dasllama/files/fonts/InterTight-normal-greek-ext.woff2 b/site-dasllama/files/fonts/InterTight-normal-greek-ext.woff2 new file mode 100644 index 0000000000..68cbfb4227 Binary files /dev/null and b/site-dasllama/files/fonts/InterTight-normal-greek-ext.woff2 differ diff --git a/site-dasllama/files/fonts/InterTight-normal-greek.woff2 b/site-dasllama/files/fonts/InterTight-normal-greek.woff2 new file mode 100644 index 0000000000..0d638f0024 Binary files /dev/null and b/site-dasllama/files/fonts/InterTight-normal-greek.woff2 differ diff --git a/site-dasllama/files/fonts/InterTight-normal-latin-ext.woff2 b/site-dasllama/files/fonts/InterTight-normal-latin-ext.woff2 new file mode 100644 index 0000000000..8df773db33 Binary files /dev/null and b/site-dasllama/files/fonts/InterTight-normal-latin-ext.woff2 differ diff --git a/site-dasllama/files/fonts/InterTight-normal-latin.woff2 b/site-dasllama/files/fonts/InterTight-normal-latin.woff2 new file mode 100644 index 0000000000..228154ffb1 Binary files /dev/null and b/site-dasllama/files/fonts/InterTight-normal-latin.woff2 differ diff --git a/site-dasllama/files/fonts/InterTight-normal-vietnamese.woff2 b/site-dasllama/files/fonts/InterTight-normal-vietnamese.woff2 new file mode 100644 index 0000000000..d08a67efd6 Binary files /dev/null and b/site-dasllama/files/fonts/InterTight-normal-vietnamese.woff2 differ diff --git a/site-dasllama/files/fonts/JetBrainsMono-normal-cyrillic-ext.woff2 b/site-dasllama/files/fonts/JetBrainsMono-normal-cyrillic-ext.woff2 new file mode 100644 index 0000000000..024a1af5eb Binary files /dev/null and b/site-dasllama/files/fonts/JetBrainsMono-normal-cyrillic-ext.woff2 differ diff --git a/site-dasllama/files/fonts/JetBrainsMono-normal-cyrillic.woff2 b/site-dasllama/files/fonts/JetBrainsMono-normal-cyrillic.woff2 new file mode 100644 index 0000000000..1b61cf966c Binary files /dev/null and b/site-dasllama/files/fonts/JetBrainsMono-normal-cyrillic.woff2 differ diff --git a/site-dasllama/files/fonts/JetBrainsMono-normal-greek.woff2 b/site-dasllama/files/fonts/JetBrainsMono-normal-greek.woff2 new file mode 100644 index 0000000000..06f0936048 Binary files /dev/null and b/site-dasllama/files/fonts/JetBrainsMono-normal-greek.woff2 differ diff --git a/site-dasllama/files/fonts/JetBrainsMono-normal-latin-ext.woff2 b/site-dasllama/files/fonts/JetBrainsMono-normal-latin-ext.woff2 new file mode 100644 index 0000000000..310faddfdd Binary files /dev/null and b/site-dasllama/files/fonts/JetBrainsMono-normal-latin-ext.woff2 differ diff --git a/site-dasllama/files/fonts/JetBrainsMono-normal-latin.woff2 b/site-dasllama/files/fonts/JetBrainsMono-normal-latin.woff2 new file mode 100644 index 0000000000..2ca6ac6059 Binary files /dev/null and b/site-dasllama/files/fonts/JetBrainsMono-normal-latin.woff2 differ diff --git a/site-dasllama/files/fonts/JetBrainsMono-normal-vietnamese.woff2 b/site-dasllama/files/fonts/JetBrainsMono-normal-vietnamese.woff2 new file mode 100644 index 0000000000..d37ea35987 Binary files /dev/null and b/site-dasllama/files/fonts/JetBrainsMono-normal-vietnamese.woff2 differ diff --git a/site-dasllama/files/fonts/fonts.css b/site-dasllama/files/fonts/fonts.css new file mode 100644 index 0000000000..1462ddfea1 --- /dev/null +++ b/site-dasllama/files/fonts/fonts.css @@ -0,0 +1,180 @@ +/* cyrillic-ext */ +@font-face { + font-family: 'Inter Tight'; + font-style: italic; + font-weight: 400 700; + font-display: swap; + src: url(InterTight-italic-cyrillic-ext.woff2) format('woff2'); + unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; +} +/* cyrillic */ +@font-face { + font-family: 'Inter Tight'; + font-style: italic; + font-weight: 400 700; + font-display: swap; + src: url(InterTight-italic-cyrillic.woff2) format('woff2'); + unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; +} +/* greek-ext */ +@font-face { + font-family: 'Inter Tight'; + font-style: italic; + font-weight: 400 700; + font-display: swap; + src: url(InterTight-italic-greek-ext.woff2) format('woff2'); + unicode-range: U+1F00-1FFF; +} +/* greek */ +@font-face { + font-family: 'Inter Tight'; + font-style: italic; + font-weight: 400 700; + font-display: swap; + src: url(InterTight-italic-greek.woff2) format('woff2'); + unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF; +} +/* vietnamese */ +@font-face { + font-family: 'Inter Tight'; + font-style: italic; + font-weight: 400 700; + font-display: swap; + src: url(InterTight-italic-vietnamese.woff2) format('woff2'); + unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB; +} +/* latin-ext */ +@font-face { + font-family: 'Inter Tight'; + font-style: italic; + font-weight: 400 700; + font-display: swap; + src: url(InterTight-italic-latin-ext.woff2) format('woff2'); + unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; +} +/* latin */ +@font-face { + font-family: 'Inter Tight'; + font-style: italic; + font-weight: 400 700; + font-display: swap; + src: url(InterTight-italic-latin.woff2) format('woff2'); + unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; +} +/* cyrillic-ext */ +@font-face { + font-family: 'Inter Tight'; + font-style: normal; + font-weight: 400 700; + font-display: swap; + src: url(InterTight-normal-cyrillic-ext.woff2) format('woff2'); + unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; +} +/* cyrillic */ +@font-face { + font-family: 'Inter Tight'; + font-style: normal; + font-weight: 400 700; + font-display: swap; + src: url(InterTight-normal-cyrillic.woff2) format('woff2'); + unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; +} +/* greek-ext */ +@font-face { + font-family: 'Inter Tight'; + font-style: normal; + font-weight: 400 700; + font-display: swap; + src: url(InterTight-normal-greek-ext.woff2) format('woff2'); + unicode-range: U+1F00-1FFF; +} +/* greek */ +@font-face { + font-family: 'Inter Tight'; + font-style: normal; + font-weight: 400 700; + font-display: swap; + src: url(InterTight-normal-greek.woff2) format('woff2'); + unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF; +} +/* vietnamese */ +@font-face { + font-family: 'Inter Tight'; + font-style: normal; + font-weight: 400 700; + font-display: swap; + src: url(InterTight-normal-vietnamese.woff2) format('woff2'); + unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB; +} +/* latin-ext */ +@font-face { + font-family: 'Inter Tight'; + font-style: normal; + font-weight: 400 700; + font-display: swap; + src: url(InterTight-normal-latin-ext.woff2) format('woff2'); + unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; +} +/* latin */ +@font-face { + font-family: 'Inter Tight'; + font-style: normal; + font-weight: 400 700; + font-display: swap; + src: url(InterTight-normal-latin.woff2) format('woff2'); + unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; +} +/* cyrillic-ext */ +@font-face { + font-family: 'JetBrains Mono'; + font-style: normal; + font-weight: 400 700; + font-display: swap; + src: url(JetBrainsMono-normal-cyrillic-ext.woff2) format('woff2'); + unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; +} +/* cyrillic */ +@font-face { + font-family: 'JetBrains Mono'; + font-style: normal; + font-weight: 400 700; + font-display: swap; + src: url(JetBrainsMono-normal-cyrillic.woff2) format('woff2'); + unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; +} +/* greek */ +@font-face { + font-family: 'JetBrains Mono'; + font-style: normal; + font-weight: 400 700; + font-display: swap; + src: url(JetBrainsMono-normal-greek.woff2) format('woff2'); + unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF; +} +/* vietnamese */ +@font-face { + font-family: 'JetBrains Mono'; + font-style: normal; + font-weight: 400 700; + font-display: swap; + src: url(JetBrainsMono-normal-vietnamese.woff2) format('woff2'); + unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB; +} +/* latin-ext */ +@font-face { + font-family: 'JetBrains Mono'; + font-style: normal; + font-weight: 400 700; + font-display: swap; + src: url(JetBrainsMono-normal-latin-ext.woff2) format('woff2'); + unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; +} +/* latin */ +@font-face { + font-family: 'JetBrains Mono'; + font-style: normal; + font-weight: 400 700; + font-display: swap; + src: url(JetBrainsMono-normal-latin.woff2) format('woff2'); + unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; +} diff --git a/site-dasllama/index.html b/site-dasllama/index.html index 07e8dd720f..0b24f0ab83 100644 --- a/site-dasllama/index.html +++ b/site-dasllama/index.html @@ -10,9 +10,7 @@ <link rel="canonical" href="https://dasllama.io/"/> <link rel="icon" href="files/dasllama-favicon.svg" type="image/svg+xml"/> <link rel="alternate" type="application/atom+xml" href="/feed.xml" title="dasllama.io news"/> -<link rel="preconnect" href="https://fonts.googleapis.com"/> -<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin/> -<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Inter+Tight:ital,wght@0,400;0,500;0,600;0,700;1,400;1,600&family=JetBrains+Mono:wght@400;500;600;700&display=swap"/> +<link rel="stylesheet" href="files/fonts/fonts.css"/> <link rel="stylesheet" href="files/forge.css"/> <link rel="stylesheet" href="files/dasllama-table.css"/> <link rel="stylesheet" href="files/dasllama-io.css"/> @@ -121,6 +119,6 @@ <h2 class="forge-h2">Latest measurements.</h2> <div><div class="dio-footer__head">site</div><a class="dio-footer__link" href="/">news</a><a class="dio-footer__link" href="ladder.html">ladder</a><a class="dio-footer__link" href="sidecars.html">sidecars</a><a class="dio-footer__link" href="/feed.xml">atom feed</a></div> <div><div class="dio-footer__head">daslang</div><a class="dio-footer__link" href="https://daslang.io">daslang.io</a><a class="dio-footer__link" href="https://daslang.io/dasllama.html">scoreboard</a><a class="dio-footer__link" href="https://daslang.io/downloads.html">downloads</a><a class="dio-footer__link" href="https://daslang.io/playground/index.html">playground</a></div> <div><div class="dio-footer__head">method</div><a class="dio-footer__link" href="https://daslang.io/doc/reference/dasllama_methodology.html">methodology</a><a class="dio-footer__link" href="https://github.com/GaijinEntertainment/daScript">github</a><a class="dio-footer__link" href="https://t.me/daScript">telegram</a></div> -</div></div></footer> +<div><div class="dio-footer__head">legal</div><a class="dio-footer__link" href="https://legal.gaijin.net/termsofservice">terms of service</a><a class="dio-footer__link" href="https://legal.gaijin.net/privacypolicy">privacy policy</a><a class="dio-footer__link" href="https://github.com/GaijinEntertainment/daScript/blob/master/LICENSE">bsd 3-clause license</a></div></div></div></footer> </div></body></html> diff --git a/site-dasllama/ladder.html b/site-dasllama/ladder.html index 2465f7460a..cc1b0f07a3 100644 --- a/site-dasllama/ladder.html +++ b/site-dasllama/ladder.html @@ -10,9 +10,7 @@ <link rel="canonical" href="https://dasllama.io/ladder.html"/> <link rel="icon" href="files/dasllama-favicon.svg" type="image/svg+xml"/> <link rel="alternate" type="application/atom+xml" href="/feed.xml" title="dasllama.io news"/> -<link rel="preconnect" href="https://fonts.googleapis.com"/> -<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin/> -<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Inter+Tight:ital,wght@0,400;0,500;0,600;0,700;1,400;1,600&family=JetBrains+Mono:wght@400;500;600;700&display=swap"/> +<link rel="stylesheet" href="files/fonts/fonts.css"/> <link rel="stylesheet" href="files/forge.css"/> <link rel="stylesheet" href="files/dasllama-table.css"/> <link rel="stylesheet" href="files/dasllama-io.css"/> @@ -71,6 +69,6 @@ <div><div class="dio-footer__head">site</div><a class="dio-footer__link" href="/">news</a><a class="dio-footer__link" href="ladder.html">ladder</a><a class="dio-footer__link" href="sidecars.html">sidecars</a><a class="dio-footer__link" href="/feed.xml">atom feed</a></div> <div><div class="dio-footer__head">daslang</div><a class="dio-footer__link" href="https://daslang.io">daslang.io</a><a class="dio-footer__link" href="https://daslang.io/dasllama.html">scoreboard</a><a class="dio-footer__link" href="https://daslang.io/downloads.html">downloads</a></div> <div><div class="dio-footer__head">method</div><a class="dio-footer__link" href="https://daslang.io/doc/reference/dasllama_methodology.html">methodology</a><a class="dio-footer__link" href="https://github.com/GaijinEntertainment/daScript">github</a><a class="dio-footer__link" href="https://t.me/daScript">telegram</a></div> -</div></div></footer> +<div><div class="dio-footer__head">legal</div><a class="dio-footer__link" href="https://legal.gaijin.net/termsofservice">terms of service</a><a class="dio-footer__link" href="https://legal.gaijin.net/privacypolicy">privacy policy</a><a class="dio-footer__link" href="https://github.com/GaijinEntertainment/daScript/blob/master/LICENSE">bsd 3-clause license</a></div></div></div></footer> </div></body></html> diff --git a/site-dasllama/sidecars.html b/site-dasllama/sidecars.html index b42e1089dd..ae73c1d024 100644 --- a/site-dasllama/sidecars.html +++ b/site-dasllama/sidecars.html @@ -2,7 +2,7 @@ <html lang="en"><head><meta charset="utf-8"/> <meta name="viewport" content="width=device-width, initial-scale=1"/> <title>sidecars — dasllama.io - + @@ -10,9 +10,7 @@ - - - + @@ -34,7 +32,8 @@

Somebody may already have tuned your box.

-

A sidecar is dasLLAMA's per-box tune manifest: which JIT kernel variant won in each of ~40 families, 23 tuned runtime scalars, and the provenance to prove where it came from. Producing one costs about 20 minutes of quiet machine. dasllama-server picks a matching sidecar up automatically at startup — this page is the manual browse.

+ +

A sidecar is dasLLAMA's per-box tune manifest: which JIT kernel variant won in each of ~40 families, 23 tuned runtime scalars, and the provenance to prove where it came from. Producing one costs about 12 minutes of quiet machine. dasllama-server picks a matching sidecar up automatically at startup — this page is the manual browse.

@@ -62,18 +61,18 @@

Somebody may already have tuned your box.

-

No questions asked.

-

At startup the server matches your box against the exchange — one code path, no prompts. Manual download is for air-gapped boxes and for people who want to read the manifest before trusting it.

+

One question, once.

+

The first start asks once whether to use the exchange — Accept and every later start matches your box automatically, one code path; Decline and the box tunes itself locally. Setting the exchange policy yourself - exchange_* keys in a hand-written config, or the DASLLAMA_EXCHANGE_* environment - skips the question: it IS the answer. Manual download is for air-gapped boxes and for people who want to read the manifest before trusting it.

01verified match → downloaded, validated, applied
02unverified match → never auto-applied; adopt it from the control page, or from the tray while a tune runs
-
03nothing → the box tunes itself, ~20 min quiet machine, and can share the result back
+
03nothing → the box tunes itself, ~12 min quiet machine, and can share the result back
-
dasllama-serverfirst start, untuned box
+
dasllama-serverfirst start after Accept, untuned box
$ daslang -jit main.das -- --model model.gguf
exchange: scope 'dasllama' is untuned - looking up a sidecar for this box (dasllama version 1)
@@ -96,7 +95,7 @@

No questions asked.

-
+
diff --git a/site/README.md b/site/README.md index 129bc8d9d4..27c0489bd6 100644 --- a/site/README.md +++ b/site/README.md @@ -68,7 +68,7 @@ generated and gitignored - see [`site/.gitignore`](.gitignore). |---|---|---| | **Landing hero** | CodeMirror editor with sample picker, -> run, up playground handoff | Static `
` block, no CM init. Hero buttons + sample tabs hidden via CSS. |
 | **/playground/** | Full multi-file IDE - tabs, splitter, share via `#z=` hash, -> run via WASM | "Open this on a laptop" notice (CSS overlay); the IDE and the runtime still initialize underneath it. |
-| **/blog/** | Full post + Disqus comments at the bottom (shortname `https-borisbat-github-io-dascf-blog`, identifier = slug, Auto theme picks dark via `:root { color-scheme: dark }`) | Same. Disqus is responsive. |
+| **/blog/** | Full post (no comment widget — removed for GDPR: Disqus set cookies) | Same. |
 | **Nav** | Inline links: docs * benchmarks * downloads * blog * community + `v0.6.4`, github up, install | == hamburger toggles a dropdown panel with the same links. `v0.6.4` chip is hidden at <480 px. |
 
 The mobile fallbacks are pure CSS + a tiny synchronous gate script - no UA
diff --git a/site/REVIEW.md b/site/REVIEW.md
index f7193059fb..5511d92965 100644
--- a/site/REVIEW.md
+++ b/site/REVIEW.md
@@ -12,9 +12,9 @@ shows.**
 exact argv `modules/dasLLAMA/performance/gen_bench_records.das` (or the released bench exe it
 spawns) ran is a defect.**
 
-**A row `files/dasllama.js` renders without its run's `cmd` + `date` line is a defect - render
-that line on every row the run produced.** One run's `cmd` + `date` covers several rendered
-rows.
+**A row that `files/dasllama.js` renders without its run's `cmd` + `date` line is a defect -
+render that line on every row the run produced.** One run's `cmd` + `date` covers several
+rendered rows.
 
 **A `cmd` or `date` inside a run's `tests` entry in `files/dasllama/bench_records.json` is a
 defect - the pair belongs on the run object that produced the rows.**
@@ -51,23 +51,22 @@ a defect - link every embedded sample.**
 
 **A daslang sample embedded in a page not written in gen2 is a defect.**
 
-**A diff that changes `playground/` (this folder), `examples/_interp.html` (this folder),
-`web/examples/ui/src/`, or `web/examples/ui/samples/` (both repo root) states a run of the
-WASM-staged Playwright suite (`tests/playground/`, this folder) in its PR body or commit
-message, naming the passes and any failures, in the same change.** The no-WASM lane cannot see
-a broken runtime path, and every sample on the page runs through that path.
+**A diff that changes `playground/` (this folder) or `examples/_interp.html` (this folder)
+states a run of the WASM-staged Playwright suite (`tests/playground/`, this folder) in its PR
+body or commit message, naming the passes and any failures, in the same change.** The no-WASM
+lane cannot see a broken runtime path, and every sample on the page runs through that path.
 
 **A stated Playwright run names every sample the diff changed: for each, the spec that loaded
 it, or - when no spec loads it - that it was opened and run by hand in the playground.**
 
-**A stated Playwright run names the runtime artifacts it used: built from this change when the
-diff touches `src/`, `include/`, `daslib/`, `modules/`, or `web/CMakeLists.txt` (all repo
-root); the deployed ones otherwise.**
+**A stated Playwright run names the runtime artifacts it used: built from this change when
+the diff touches `src/`, `include/`, `daslib/`, `modules/`, `dastest/`, or
+`web/CMakeLists.txt` (all repo root); the deployed ones otherwise.**
 
 **A diff that puts a measurement number - a rate, a duration, a size, a score some run
-produced, never a fixture or run parameter such as an image's dimensions or a token budget - on
-a page without rendering it from live data, copying it from a checked-in measurement record, or
-marking it a placeholder in a source comment is a defect.**
+produced, never a fixture or run parameter - on a page without rendering it from live data,
+copying it from a checked-in measurement record, or marking it a placeholder in a source
+comment is a defect.**
 
 **A placeholder number a page reader could take for a fact is a defect - mark it as a
 placeholder on the page itself.**
diff --git a/site/benchmarks.html b/site/benchmarks.html
index 9eaa4e6f86..8044a2722b 100644
--- a/site/benchmarks.html
+++ b/site/benchmarks.html
@@ -8,9 +8,7 @@
     
     
     
-    
-    
-    
+
     
     
 
@@ -231,6 +229,12 @@ 

The full board.

change list downloads + diff --git a/site/blog/build_blog.py b/site/blog/build_blog.py index 0e9ba1fa4d..20a74a77e4 100644 --- a/site/blog/build_blog.py +++ b/site/blog/build_blog.py @@ -53,14 +53,6 @@ KEY_RE = re.compile(r'^([a-zA-Z_]+):\s*(.*)$') -# Disqus shortname carried over from the legacy borisbat.github.io/dascf-blog -# install — the same account, but new threads under daslang.io URLs (Disqus -# resolves identifier first, then page.url). Old comments stay under the -# original blog URLs in the Disqus admin and can be migrated via the -# Disqus URL Mapper if desired. -DISQUS_SHORTNAME = 'https-borisbat-github-io-dascf-blog' - - @dataclass class Entry: slug: str @@ -296,7 +288,6 @@ def render_post(entry: Entry, prev: Entry | None, next: Entry | None, md, posts_ else: parts.append('') nav_html = f'
{parts[0]}{parts[1]}
' - comments_html = render_comments(entry) return f"""
-{comments_html}""" - - -def render_comments(entry: Entry) -> str: - """Disqus thread, pinned by post slug as identifier so threads survive - URL changes (dev/prod, future renames). The embed script reads - `disqus_config` for the URL + identifier.""" - slug = html.escape(entry.slug, quote=True) - return f"""
-
- -
- - -
-
""" + def render_index(posts: list[Entry], md) -> str: items = [] for p in posts: diff --git a/site/blog/template.html b/site/blog/template.html index d8d206b4de..248cdfb296 100644 --- a/site/blog/template.html +++ b/site/blog/template.html @@ -9,9 +9,7 @@ - - - + @@ -117,6 +115,12 @@ change list downloads + diff --git a/site/dasllama.html b/site/dasllama.html index 966eb62efc..c863fe9120 100644 --- a/site/dasllama.html +++ b/site/dasllama.html @@ -17,9 +17,7 @@ - - - + @@ -479,6 +477,12 @@

The method, stated in full.

change list downloads + diff --git a/site/daspkg.html b/site/daspkg.html index 4790d49c1b..8a72813934 100644 --- a/site/daspkg.html +++ b/site/daspkg.html @@ -11,9 +11,7 @@ - - - + @@ -180,6 +178,12 @@

change list downloads + diff --git a/site/downloads.html b/site/downloads.html index 4cdd7a44da..7e499cb5ed 100644 --- a/site/downloads.html +++ b/site/downloads.html @@ -10,9 +10,7 @@ - - - + @@ -235,6 +233,12 @@

Where to learn more.

github change list + diff --git a/site/examples.html b/site/examples.html index f7da66be53..d6bff6f294 100644 --- a/site/examples.html +++ b/site/examples.html @@ -16,9 +16,7 @@ - - - + @@ -144,6 +142,12 @@

change list downloads + diff --git a/site/files/fonts/InterTight-italic-cyrillic-ext.woff2 b/site/files/fonts/InterTight-italic-cyrillic-ext.woff2 new file mode 100644 index 0000000000..83c2eff740 Binary files /dev/null and b/site/files/fonts/InterTight-italic-cyrillic-ext.woff2 differ diff --git a/site/files/fonts/InterTight-italic-cyrillic.woff2 b/site/files/fonts/InterTight-italic-cyrillic.woff2 new file mode 100644 index 0000000000..70552d21a2 Binary files /dev/null and b/site/files/fonts/InterTight-italic-cyrillic.woff2 differ diff --git a/site/files/fonts/InterTight-italic-greek-ext.woff2 b/site/files/fonts/InterTight-italic-greek-ext.woff2 new file mode 100644 index 0000000000..c81a4e55a9 Binary files /dev/null and b/site/files/fonts/InterTight-italic-greek-ext.woff2 differ diff --git a/site/files/fonts/InterTight-italic-greek.woff2 b/site/files/fonts/InterTight-italic-greek.woff2 new file mode 100644 index 0000000000..95d91ab686 Binary files /dev/null and b/site/files/fonts/InterTight-italic-greek.woff2 differ diff --git a/site/files/fonts/InterTight-italic-latin-ext.woff2 b/site/files/fonts/InterTight-italic-latin-ext.woff2 new file mode 100644 index 0000000000..12f8e8f5a5 Binary files /dev/null and b/site/files/fonts/InterTight-italic-latin-ext.woff2 differ diff --git a/site/files/fonts/InterTight-italic-latin.woff2 b/site/files/fonts/InterTight-italic-latin.woff2 new file mode 100644 index 0000000000..870e9b5982 Binary files /dev/null and b/site/files/fonts/InterTight-italic-latin.woff2 differ diff --git a/site/files/fonts/InterTight-italic-vietnamese.woff2 b/site/files/fonts/InterTight-italic-vietnamese.woff2 new file mode 100644 index 0000000000..072774eca7 Binary files /dev/null and b/site/files/fonts/InterTight-italic-vietnamese.woff2 differ diff --git a/site/files/fonts/InterTight-normal-cyrillic-ext.woff2 b/site/files/fonts/InterTight-normal-cyrillic-ext.woff2 new file mode 100644 index 0000000000..23a7b3eede Binary files /dev/null and b/site/files/fonts/InterTight-normal-cyrillic-ext.woff2 differ diff --git a/site/files/fonts/InterTight-normal-cyrillic.woff2 b/site/files/fonts/InterTight-normal-cyrillic.woff2 new file mode 100644 index 0000000000..f0a04608af Binary files /dev/null and b/site/files/fonts/InterTight-normal-cyrillic.woff2 differ diff --git a/site/files/fonts/InterTight-normal-greek-ext.woff2 b/site/files/fonts/InterTight-normal-greek-ext.woff2 new file mode 100644 index 0000000000..68cbfb4227 Binary files /dev/null and b/site/files/fonts/InterTight-normal-greek-ext.woff2 differ diff --git a/site/files/fonts/InterTight-normal-greek.woff2 b/site/files/fonts/InterTight-normal-greek.woff2 new file mode 100644 index 0000000000..0d638f0024 Binary files /dev/null and b/site/files/fonts/InterTight-normal-greek.woff2 differ diff --git a/site/files/fonts/InterTight-normal-latin-ext.woff2 b/site/files/fonts/InterTight-normal-latin-ext.woff2 new file mode 100644 index 0000000000..8df773db33 Binary files /dev/null and b/site/files/fonts/InterTight-normal-latin-ext.woff2 differ diff --git a/site/files/fonts/InterTight-normal-latin.woff2 b/site/files/fonts/InterTight-normal-latin.woff2 new file mode 100644 index 0000000000..228154ffb1 Binary files /dev/null and b/site/files/fonts/InterTight-normal-latin.woff2 differ diff --git a/site/files/fonts/InterTight-normal-vietnamese.woff2 b/site/files/fonts/InterTight-normal-vietnamese.woff2 new file mode 100644 index 0000000000..d08a67efd6 Binary files /dev/null and b/site/files/fonts/InterTight-normal-vietnamese.woff2 differ diff --git a/site/files/fonts/JetBrainsMono-normal-cyrillic-ext.woff2 b/site/files/fonts/JetBrainsMono-normal-cyrillic-ext.woff2 new file mode 100644 index 0000000000..024a1af5eb Binary files /dev/null and b/site/files/fonts/JetBrainsMono-normal-cyrillic-ext.woff2 differ diff --git a/site/files/fonts/JetBrainsMono-normal-cyrillic.woff2 b/site/files/fonts/JetBrainsMono-normal-cyrillic.woff2 new file mode 100644 index 0000000000..1b61cf966c Binary files /dev/null and b/site/files/fonts/JetBrainsMono-normal-cyrillic.woff2 differ diff --git a/site/files/fonts/JetBrainsMono-normal-greek.woff2 b/site/files/fonts/JetBrainsMono-normal-greek.woff2 new file mode 100644 index 0000000000..06f0936048 Binary files /dev/null and b/site/files/fonts/JetBrainsMono-normal-greek.woff2 differ diff --git a/site/files/fonts/JetBrainsMono-normal-latin-ext.woff2 b/site/files/fonts/JetBrainsMono-normal-latin-ext.woff2 new file mode 100644 index 0000000000..310faddfdd Binary files /dev/null and b/site/files/fonts/JetBrainsMono-normal-latin-ext.woff2 differ diff --git a/site/files/fonts/JetBrainsMono-normal-latin.woff2 b/site/files/fonts/JetBrainsMono-normal-latin.woff2 new file mode 100644 index 0000000000..2ca6ac6059 Binary files /dev/null and b/site/files/fonts/JetBrainsMono-normal-latin.woff2 differ diff --git a/site/files/fonts/JetBrainsMono-normal-vietnamese.woff2 b/site/files/fonts/JetBrainsMono-normal-vietnamese.woff2 new file mode 100644 index 0000000000..d37ea35987 Binary files /dev/null and b/site/files/fonts/JetBrainsMono-normal-vietnamese.woff2 differ diff --git a/site/files/fonts/fonts.css b/site/files/fonts/fonts.css new file mode 100644 index 0000000000..1462ddfea1 --- /dev/null +++ b/site/files/fonts/fonts.css @@ -0,0 +1,180 @@ +/* cyrillic-ext */ +@font-face { + font-family: 'Inter Tight'; + font-style: italic; + font-weight: 400 700; + font-display: swap; + src: url(InterTight-italic-cyrillic-ext.woff2) format('woff2'); + unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; +} +/* cyrillic */ +@font-face { + font-family: 'Inter Tight'; + font-style: italic; + font-weight: 400 700; + font-display: swap; + src: url(InterTight-italic-cyrillic.woff2) format('woff2'); + unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; +} +/* greek-ext */ +@font-face { + font-family: 'Inter Tight'; + font-style: italic; + font-weight: 400 700; + font-display: swap; + src: url(InterTight-italic-greek-ext.woff2) format('woff2'); + unicode-range: U+1F00-1FFF; +} +/* greek */ +@font-face { + font-family: 'Inter Tight'; + font-style: italic; + font-weight: 400 700; + font-display: swap; + src: url(InterTight-italic-greek.woff2) format('woff2'); + unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF; +} +/* vietnamese */ +@font-face { + font-family: 'Inter Tight'; + font-style: italic; + font-weight: 400 700; + font-display: swap; + src: url(InterTight-italic-vietnamese.woff2) format('woff2'); + unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB; +} +/* latin-ext */ +@font-face { + font-family: 'Inter Tight'; + font-style: italic; + font-weight: 400 700; + font-display: swap; + src: url(InterTight-italic-latin-ext.woff2) format('woff2'); + unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; +} +/* latin */ +@font-face { + font-family: 'Inter Tight'; + font-style: italic; + font-weight: 400 700; + font-display: swap; + src: url(InterTight-italic-latin.woff2) format('woff2'); + unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; +} +/* cyrillic-ext */ +@font-face { + font-family: 'Inter Tight'; + font-style: normal; + font-weight: 400 700; + font-display: swap; + src: url(InterTight-normal-cyrillic-ext.woff2) format('woff2'); + unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; +} +/* cyrillic */ +@font-face { + font-family: 'Inter Tight'; + font-style: normal; + font-weight: 400 700; + font-display: swap; + src: url(InterTight-normal-cyrillic.woff2) format('woff2'); + unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; +} +/* greek-ext */ +@font-face { + font-family: 'Inter Tight'; + font-style: normal; + font-weight: 400 700; + font-display: swap; + src: url(InterTight-normal-greek-ext.woff2) format('woff2'); + unicode-range: U+1F00-1FFF; +} +/* greek */ +@font-face { + font-family: 'Inter Tight'; + font-style: normal; + font-weight: 400 700; + font-display: swap; + src: url(InterTight-normal-greek.woff2) format('woff2'); + unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF; +} +/* vietnamese */ +@font-face { + font-family: 'Inter Tight'; + font-style: normal; + font-weight: 400 700; + font-display: swap; + src: url(InterTight-normal-vietnamese.woff2) format('woff2'); + unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB; +} +/* latin-ext */ +@font-face { + font-family: 'Inter Tight'; + font-style: normal; + font-weight: 400 700; + font-display: swap; + src: url(InterTight-normal-latin-ext.woff2) format('woff2'); + unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; +} +/* latin */ +@font-face { + font-family: 'Inter Tight'; + font-style: normal; + font-weight: 400 700; + font-display: swap; + src: url(InterTight-normal-latin.woff2) format('woff2'); + unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; +} +/* cyrillic-ext */ +@font-face { + font-family: 'JetBrains Mono'; + font-style: normal; + font-weight: 400 700; + font-display: swap; + src: url(JetBrainsMono-normal-cyrillic-ext.woff2) format('woff2'); + unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; +} +/* cyrillic */ +@font-face { + font-family: 'JetBrains Mono'; + font-style: normal; + font-weight: 400 700; + font-display: swap; + src: url(JetBrainsMono-normal-cyrillic.woff2) format('woff2'); + unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; +} +/* greek */ +@font-face { + font-family: 'JetBrains Mono'; + font-style: normal; + font-weight: 400 700; + font-display: swap; + src: url(JetBrainsMono-normal-greek.woff2) format('woff2'); + unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF; +} +/* vietnamese */ +@font-face { + font-family: 'JetBrains Mono'; + font-style: normal; + font-weight: 400 700; + font-display: swap; + src: url(JetBrainsMono-normal-vietnamese.woff2) format('woff2'); + unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB; +} +/* latin-ext */ +@font-face { + font-family: 'JetBrains Mono'; + font-style: normal; + font-weight: 400 700; + font-display: swap; + src: url(JetBrainsMono-normal-latin-ext.woff2) format('woff2'); + unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; +} +/* latin */ +@font-face { + font-family: 'JetBrains Mono'; + font-style: normal; + font-weight: 400 700; + font-display: swap; + src: url(JetBrainsMono-normal-latin.woff2) format('woff2'); + unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; +} diff --git a/site/files/forge.css b/site/files/forge.css index 37059c353a..6ebb2cab74 100644 --- a/site/files/forge.css +++ b/site/files/forge.css @@ -30,7 +30,7 @@ --font-sans: "Inter Tight", "Inter", -apple-system, system-ui, sans-serif; --font-mono: "JetBrains Mono", "SF Mono", ui-monospace, Menlo, monospace; - /* Hint embedded widgets (Disqus, GitHub, etc.) to render in dark mode. */ + /* Hint embedded widgets (GitHub, etc.) to render in dark mode. */ color-scheme: dark; } @@ -899,37 +899,6 @@ button { font: inherit; border: 0; background: none; color: inherit; cursor: poi .forge-post-nav a { color: var(--fg-dim); } .forge-post-nav a:hover { color: var(--amber); } -/* ───── Comments (Disqus) ───── */ - -/* Disqus loads in a sandboxed iframe so we can only style the wrapper — - * the comment styling itself comes from the Disqus admin panel - * (Appearance → Color scheme: Auto). The `color-scheme: dark` hint on - * :root makes Auto resolve to dark. */ -.forge-post__comments { - padding: 56px 0 88px; - border-top: 1px solid var(--rule); - background: var(--bg); -} -.forge-post__comments .forge-section-label { margin-bottom: 18px; } -.forge-post__comments #disqus_thread { - margin-top: 20px; - background: var(--bg-2); - border: 1px solid var(--rule); - border-radius: 8px; - padding: 16px 20px; - min-height: 80px; -} -.forge-post__comments noscript { - display: block; - margin-top: 16px; - color: var(--fg-faint); - font-family: var(--font-mono); - font-size: 12.5px; -} -.forge-post__comments noscript a { - color: var(--amber); - border-bottom: 1px solid var(--amber-dim); -} /* Changelist: same layout as blog listing, wider. */ .forge-changelist { margin-top: 24px; } @@ -944,7 +913,7 @@ button { font: inherit; border: 0; background: none; color: inherit; cursor: poi } .forge-footer__grid { display: grid; - grid-template-columns: 1.4fr 1fr 1fr 1fr; + grid-template-columns: 1.4fr 1fr 1fr 1fr 1fr; gap: 32px; } .forge-footer__about { diff --git a/site/index.html b/site/index.html index 87e8cfb34e..edb11f18d1 100644 --- a/site/index.html +++ b/site/index.html @@ -19,9 +19,7 @@ - - - + @@ -472,6 +470,12 @@

Recent activity.

change list downloads + diff --git a/site/performance.html b/site/performance.html index 8c78e29224..c7b2968bd5 100644 --- a/site/performance.html +++ b/site/performance.html @@ -17,9 +17,7 @@ - - - + @@ -353,6 +351,12 @@

How the numbers are made.

change list downloads + diff --git a/site/playground/index.html b/site/playground/index.html index f536a9a88e..b39fe80d45 100644 --- a/site/playground/index.html +++ b/site/playground/index.html @@ -15,9 +15,7 @@ - - - +