docs(comments): no WebSocket and no CI in the present tense
The chat cut removed the only WebSocket and CI went before it, but comments still leaned on both: `?account=` was justified by the socket, job polling by an in-process WS registry, the e2e flows as "proxy-safe (none use the WebSocket)", and pyrightconfig named a CI container the engine contract test never checked. Each now says what holds today (the wallet gate, no push channel, the two contract test halves, the image build's `npm ci`, the gate).
This commit is contained in:
@@ -889,8 +889,8 @@ class DownloadJob(Base, TimestampMixin, UpdatedAtMixin):
|
|||||||
"""A user's request to download one source — the per-user layer over `MediaAsset`.
|
"""A user's request to download one source — the per-user layer over `MediaAsset`.
|
||||||
|
|
||||||
The worker claims `queued` jobs with ``FOR UPDATE SKIP LOCKED`` and writes live
|
The worker claims `queued` jobs with ``FOR UPDATE SKIP LOCKED`` and writes live
|
||||||
`progress`/`speed_bps`/`eta_s`/`phase` here (the frontend polls via useLiveQuery — the
|
`progress`/`speed_bps`/`eta_s`/`phase` here (the frontend polls via useLiveQuery: there is
|
||||||
worker is a separate process and can't reach the in-process WS registry). `profile_snapshot`
|
no server push channel, and the worker is a separate process anyway). `profile_snapshot`
|
||||||
freezes the spec at enqueue so later edits/deletion of the profile don't change this job.
|
freezes the spec at enqueue so later edits/deletion of the profile don't change this job.
|
||||||
`display_name` is the user's own name for the file (display + the Content-Disposition on
|
`display_name` is the user's own name for the file (display + the Content-Disposition on
|
||||||
local download); the on-disk asset is never renamed. `asset_id` links to the shared file
|
local download); the on-disk asset is never renamed. `asset_id` links to the shared file
|
||||||
|
|||||||
@@ -13,8 +13,8 @@
|
|||||||
// image installs — so the lane's version IS the pin, with no host-vs-pin check to drift.
|
// image installs — so the lane's version IS the pin, with no host-vs-pin check to drift.
|
||||||
//
|
//
|
||||||
// `pythonVersion` is not free-standing: `/.python-version` is the single source of truth and
|
// `pythonVersion` is not free-standing: `/.python-version` is the single source of truth and
|
||||||
// `tests/test_python_engine_contract.py` fails this gate if this file, the two Dockerfiles, the CI
|
// `tests/test_python_engine_contract.py` (with its host half, pythonEngine.contract.test.ts) fails
|
||||||
// container or ruff's target-version disagree with it.
|
// this gate if this file, the two Dockerfiles or ruff's target-version disagree with it.
|
||||||
//
|
//
|
||||||
// `include` covers `alembic` for the same reason the ruff lane was widened to it: migrations run on
|
// `include` covers `alembic` for the same reason the ruff lane was widened to it: migrations run on
|
||||||
// every container start, so one that raises there crash-loops prod, and "it is generated code" is
|
// every container start, so one that raises there crash-loops prod, and "it is generated code" is
|
||||||
|
|||||||
@@ -331,7 +331,7 @@ class TestWantHw:
|
|||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _opencl(monkeypatch, present):
|
def _opencl(monkeypatch, present):
|
||||||
# Pin the OpenCL-runtime probe so the routing doesn't depend on the CI box's /etc/OpenCL.
|
# Pin the OpenCL-runtime probe so the routing doesn't depend on the test machine's /etc/OpenCL.
|
||||||
monkeypatch.setattr(stream, "_opencl_present", lambda: present)
|
monkeypatch.setattr(stream, "_opencl_present", lambda: present)
|
||||||
|
|
||||||
def test_no_hw_when_not_transcoding(self, monkeypatch):
|
def test_no_hw_when_not_transcoding(self, monkeypatch):
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ login-free `/watch/<token>` share link).
|
|||||||
- **`:8080`** (baked SPA) is authoritative and same-origin. After a **frontend change you must
|
- **`:8080`** (baked SPA) is authoritative and same-origin. After a **frontend change you must
|
||||||
`siftlode dev` (rebuild)** for its baked SPA to carry the latest test hooks.
|
`siftlode dev` (rebuild)** for its baked SPA to carry the latest test hooks.
|
||||||
- **`:5173`** (Vite dev) serves source live — the fast refactor loop; it proxies `/api` to `:8080`,
|
- **`:5173`** (Vite dev) serves source live — the fast refactor loop; it proxies `/api` to `:8080`,
|
||||||
so the stack must still be up. All five flows are proxy-safe (none use the WebSocket):
|
so the stack must still be up. All five flows are proxy-safe:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
PW_BASE_URL=http://localhost:5173 siftlode e2e
|
PW_BASE_URL=http://localhost:5173 siftlode e2e
|
||||||
|
|||||||
@@ -4,8 +4,8 @@ import { defineConfig, devices } from "@playwright/test";
|
|||||||
* E2E characterization (golden-master) net for the Platform refactor.
|
* E2E characterization (golden-master) net for the Platform refactor.
|
||||||
*
|
*
|
||||||
* Target (PW_BASE_URL): defaults to the baked localdev stack on :8080 (production-faithful,
|
* Target (PW_BASE_URL): defaults to the baked localdev stack on :8080 (production-faithful,
|
||||||
* same-origin, no HMR/WS gaps). Point it at http://localhost:5173 for the fast Vite loop — all
|
* same-origin, no HMR gaps). Point it at http://localhost:5173 for the fast Vite loop — all
|
||||||
* five characterization flows are proxy-safe (none use the WebSocket).
|
* five characterization flows are proxy-safe.
|
||||||
*
|
*
|
||||||
* The stack must already be UP (owned by `siftlode dev`); there is deliberately no `webServer`.
|
* The stack must already be UP (owned by `siftlode dev`); there is deliberately no `webServer`.
|
||||||
* `e2e/global.setup.ts` seeds the dedicated test account and logs in once, sharing the resulting
|
* `e2e/global.setup.ts` seeds the dedicated test account and logs in once, sharing the resulting
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ describe("ItemCount", () => {
|
|||||||
it("pluralises and thousands-separates a normal count", () => {
|
it("pluralises and thousands-separates a normal count", () => {
|
||||||
render(<ItemCount count={192045} />);
|
render(<ItemCount count={192045} />);
|
||||||
// Separators come from the shared formatNumber — compare against it, not a fixed en-US string,
|
// Separators come from the shared formatNumber — compare against it, not a fixed en-US string,
|
||||||
// so the test asserts ItemCount's formatting path rather than the CI locale.
|
// so the test asserts ItemCount's formatting path rather than the runner's locale.
|
||||||
expect(text()).toBe(`${formatNumber(192045, "en")} items`);
|
expect(text()).toBe(`${formatNumber(192045, "en")} items`);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -200,7 +200,7 @@ export const downloadsApi = {
|
|||||||
// The body IS the file, and the two names ride as headers. Not a style choice: a multipart part is
|
// The body IS the file, and the two names ride as headers. Not a style choice: a multipart part is
|
||||||
// a DECLARED body, which FastAPI reads and spools BEFORE the route's `current_user` dependency
|
// a DECLARED body, which FastAPI reads and spools BEFORE the route's `current_user` dependency
|
||||||
// runs — so with the old shape an unauthenticated caller could make the server write the whole
|
// runs — so with the old shape an unauthenticated caller could make the server write the whole
|
||||||
// per-file allowance to temp (P1). Headers are latin-1 on the wire, hence `encodeURIComponent`;
|
// per-file allowance to temp. Headers are latin-1 on the wire, hence `encodeURIComponent`;
|
||||||
// the server percent-decodes both. Content-Type is left to the browser (the File's own type).
|
// the server percent-decodes both. Content-Type is left to the browser (the File's own type).
|
||||||
uploadDownload: (
|
uploadDownload: (
|
||||||
file: File,
|
file: File,
|
||||||
@@ -274,8 +274,9 @@ export const downloadsApi = {
|
|||||||
revokeDownloadLink: (linkId: number): Promise<{ deleted: number }> =>
|
revokeDownloadLink: (linkId: number): Promise<{ deleted: number }> =>
|
||||||
req(`/api/downloads/links/${linkId}`, { method: "DELETE" }),
|
req(`/api/downloads/links/${linkId}`, { method: "DELETE" }),
|
||||||
// A plain <a> navigation can't send the X-Siftlode-Account header, so pass the active
|
// A plain <a> navigation can't send the X-Siftlode-Account header, so pass the active
|
||||||
// account via ?account= (same wallet-gated selection the WebSocket uses) — otherwise the
|
// account via ?account= (the server honours it only for an account in this browser's wallet) —
|
||||||
// download resolves to the session-default account and 404s for a per-tab account's file.
|
// otherwise the download resolves to the session-default account and 404s for a per-tab
|
||||||
|
// account's file.
|
||||||
downloadFileUrl: (id: number): string => {
|
downloadFileUrl: (id: number): string => {
|
||||||
const a = getActiveAccount();
|
const a = getActiveAccount();
|
||||||
return a != null ? `/api/downloads/${id}/file?account=${a}` : `/api/downloads/${id}/file`;
|
return a != null ? `/api/downloads/${id}/file?account=${a}` : `/api/downloads/${id}/file`;
|
||||||
|
|||||||
@@ -3,7 +3,8 @@ import { describe, it, expect, beforeAll } from "vitest";
|
|||||||
// The façade guard: lib/api.ts is a spread-only façade over per-domain slice modules. These tests
|
// The façade guard: lib/api.ts is a spread-only façade over per-domain slice modules. These tests
|
||||||
// mechanise the two invariants that make that structure safe — so a future edit that reintroduces
|
// mechanise the two invariants that make that structure safe — so a future edit that reintroduces
|
||||||
// the interleave (a method dropped into two slices → a silent last-wins spread override) or bloats
|
// the interleave (a method dropped into two slices → a silent last-wins spread override) or bloats
|
||||||
// the barrel (a method defined inline instead of in a domain module) fails CI instead of shipping.
|
// the barrel (a method defined inline instead of in a domain module) fails the gate instead of
|
||||||
|
// shipping.
|
||||||
//
|
//
|
||||||
// Scope, on purpose: this covers RUNTIME method-key collisions — the only *silent* failure mode,
|
// Scope, on purpose: this covers RUNTIME method-key collisions — the only *silent* failure mode,
|
||||||
// since tsc does not flag overlapping spread keys. It deliberately does NOT cover exported-TYPE-name
|
// since tsc does not flag overlapping spread keys. It deliberately does NOT cover exported-TYPE-name
|
||||||
|
|||||||
@@ -133,7 +133,7 @@ describe("relativeFromMs", () => {
|
|||||||
// printed "1 234 567" (and a Hungarian UI in an English browser "1,234,567"). The case below asserts
|
// printed "1 234 567" (and a Hungarian UI in an English browser "1,234,567"). The case below asserts
|
||||||
// BOTH languages and that the two differ, rather than comparing against the runtime's own default:
|
// BOTH languages and that the two differ, rather than comparing against the runtime's own default:
|
||||||
// the default is whatever locale the machine running the suite has (Hungarian on the dev box, English
|
// the default is whatever locale the machine running the suite has (Hungarian on the dev box, English
|
||||||
// on a CI image), so a one-language assertion passes under the old bug on half the machines.
|
// in the test image), so a one-language assertion passes under the old bug on half the machines.
|
||||||
describe("formatNumber", () => {
|
describe("formatNumber", () => {
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
i18nStub.language = "en";
|
i18nStub.language = "en";
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import { useSyncExternalStore } from "react";
|
import { useSyncExternalStore } from "react";
|
||||||
|
|
||||||
// A minimal observable value shared across React components AND non-React code (the api
|
// A minimal observable value shared across React components AND non-React code (the api
|
||||||
// layer, websocket handlers, etc.). Replaces the hand-rolled `listeners`/`subscribe`/`emit`
|
// layer, the debug recorder, the error dialog, etc.). Replaces the hand-rolled
|
||||||
// triad that several modules each re-implemented slightly differently.
|
// `listeners`/`subscribe`/`emit` triad that several modules each re-implemented slightly differently.
|
||||||
export interface Store<T> {
|
export interface Store<T> {
|
||||||
get(): T;
|
get(): T;
|
||||||
set(next: T | ((prev: T) => T)): void;
|
set(next: T | ((prev: T) => T)): void;
|
||||||
|
|||||||
@@ -4,8 +4,8 @@
|
|||||||
// The local gate's frontend lanes run against the HOST's node_modules, and nothing tied that tree to
|
// The local gate's frontend lanes run against the HOST's node_modules, and nothing tied that tree to
|
||||||
// the lock: a `git pull` that bumped a dependency, or an `npm install` that was never committed, left
|
// the lock: a `git pull` that bumped a dependency, or an `npm install` that was never committed, left
|
||||||
// tsc/eslint/vitest judging the code against packages the build image (`npm ci`) does not use — a
|
// tsc/eslint/vitest judging the code against packages the build image (`npm ci`) does not use — a
|
||||||
// green that proves nothing about what ships, in either direction. CI is immune (it runs `npm ci`);
|
// green that proves nothing about what ships, in either direction. The image build is immune (it
|
||||||
// this makes the local lanes say so instead of quietly differing.
|
// runs `npm ci`); this makes the local lanes say so instead of quietly differing.
|
||||||
//
|
//
|
||||||
// Checks every package the lock places under node_modules/: present, at the pinned version. A package
|
// Checks every package the lock places under node_modules/: present, at the pinned version. A package
|
||||||
// marked `optional` may be absent (a platform binary for another OS). Exit 1 with the list and the
|
// marked `optional` may be absent (a platform binary for another OS). Exit 1 with the list and the
|
||||||
|
|||||||
Reference in New Issue
Block a user