test(e2e): transfers through a gateway keep their promises
I maintainer di solito rispondono entro 1 giorno
@V3RON ci sta già lavorando.
Dal 14/10/2026.
Valutazione
Questa issue non è ancora stata valutata.
Descrizione
Part of #552.
Scope
After this PR, #552's measured promises are proven against a real gateway
and worker over the real WebSocket: bytes on the uplink, the 1 s bound
for small calls with uploads and downloads running, a slow reader slowing
only itself, memory per transfer in both directions, 2 GiB both ways with
the download inside agent-device's 90 s, and, on the slow lane, the 1.5×
upload time.
A promise that fails is fixed in this PR, in the module that breaks it.
A fix that would change a value ADR 0028 or #552's Shared values table
sets (credit, unsent mark, message size, channel limit, waits) is not
made: the implementer stops and reports, since those values are the
maintainer's.
The values are in #552's Shared values table.
In short
flowchart LR
T["test"] -->|relay| G["gateway"]
G --- P["counting TCP proxy (test)"] --- W["worker"]
W --> F["fake relay target / real agent-device"]
The tests put a TCP proxy between the worker and the gateway to count
the bytes on the uplink. The timing tests run in their own test project,
alone, so other test files do not compete for the CPU. If this goes
wrong, a promise #552 makes to users is false and nothing shows it.
Technical spec
Facts
| # | Fact | Source |
|---|---|---|
| F1 | startFleet starts a real gateway and worker over the real WebSocket on 127.0.0.1 with a fake relay target; it is local to the file's describe and points the worker's gateway.url straight at the gateway's port |
src/daemon/relay-gateway.e2e.test.ts:124-145, :178, :210 |
| F2 | patternStream and patternDigest make and check large bodies; the pattern is generated byte by byte |
src/daemon/test-relay-support.ts:88-93, :102-110 |
| F3 | The model for timing a small call while a relay runs, with a check that the relay had not finished first | src/daemon/relay-gateway.e2e.test.ts:294-328 |
| F4 | The worker dials gateway.url; the uplink endpoint is derived from it |
src/ports/uplink.ts:52 (resolveUplinkUrl) |
| F5 | The test projects: unit takes src/**/*.test.ts, e2e takes e2e/**/*.test.ts; CI runs pnpm run test:unit |
vitest.config.ts:14-27; package.json:47; .github/workflows/ci.yml:69 |
| F6 | The slow-lane gateway suite starts a gateway and one real-driver worker with one device; its lease tests each open their own lease through the gateway | e2e/slow-agent-device-gateway.test.ts:124-153, :181-200 |
| F7 | A worker answers agent-device calls made with its own agent tokens on its own front | docs/HTTP-API.md:1497-1499 |
| F8 | simlock's upload routes: preflight, direct upload, finalize, each naming the lease in x-agent-device-lease-id |
src/agent-device/shared/routes.ts:20-35; docs/HTTP-API.md:1507-1511 |
| F10 | CI's jobs: unit has a 10-minute limit; quality gates merges and needs static, unit and e2e; pnpm check runs pnpm test, and CI runs what it runs |
.github/workflows/ci.yml:49-54, :105-107; package.json:46, :62; docs/internal/agent-rules/toolchain.md:35 |
| F11 | The command guard lists the scripts agents never run, and toolchain.md's "Checks agents never run" table must match it |
.agents/scripts/tool-guard.mjs:17-28; docs/internal/agent-rules/toolchain.md:18-21 |
| F12 | The mutation config includes every src/**/*.test.ts, and Stryker reruns tests per mutant |
vitest.mutate.config.ts:8; stryker.config.mjs:4-6 |
| F13 | A test pins the lane filters in package.json |
src/test-lanes.test.ts |
| F9 | agent-device's preflight body: sha256, uploadAttemptId, fileName, sizeBytes, artifactType, optional platform and contentType; finalize takes { uploadId } and checks size and hash |
agent-device src/daemon/upload-http.ts:246-256, :197-205; src/daemon/resumable-upload.ts:104-117, at the commit vendor/README.md names |
Modules touched
src/daemon/test-relay-support.ts:startFleetmoves here from
src/daemon/relay-gateway.e2e.test.tswith agatewayUrloption (F1);
a counting TCP proxy helper that pipes each direction with backpressure
and holds no buffer of its own; the pattern helpers derive each byte
from its own offset (a hash in counter mode), so no stretch of the
pattern equals any other, and build it fast enough for 2 GiB (F2).src/daemon/relay-gateway.e2e.test.ts: uses the movedstartFleet.src/daemon/relay-promises.timing.test.ts(new): the tests below.vitest.config.ts,vitest.mutate.config.ts,package.json,
.github/workflows/ci.yml,docs/internal/agent-rules/toolchain.md,
.agents/scripts/tool-guard.mjs,src/test-lanes.test.ts: atiming
project that takessrc/**/*.timing.test.ts, which theunitproject
and the mutation config leave out (F12), runs its files one at a time
with nothing else in parallel, and gives each test 300 s; atest:timingscript that
pnpm test(and sopnpm check) runs (F10); atimingCI job with a
30-minute limit thatqualityneeds; the script intoolchain.md's
"Checks agents never run" table and in the command guard's list (F11),
and a "Tests agents run" row for one timing file:
pnpm vitest run --project timing <file>.e2e/slow-agent-device-gateway.test.ts: the slow-lane test.- A failing promise adds the module that fixes it (Scope).
Contract and event changes
None.
Other code on the same state
None: tests and test tooling. A fix this PR makes names the code it
changes in the PR body.
Rules in play
testing.md: rule 2, every test can fail for the right reason: a
timing test checks its load was still running when it measured.toolchain.md: the new script goes in "Checks agents never run" and
the command guard's list; the slow lane runs through
scripts/slow-e2e.sh.
Tests
Seam: startFleet (F1) with gatewayUrl pointed at the counting TCP
proxy in front of the gateway's port (F4). The proxy counts the bytes it
carries in both directions from a transfer's start to its end. The two
ratio tests (the 1 s bound and the 1.5× slow reader) take the median of 5
runs against a baseline measured the same way in the same test; every
other test is one run. Tests moving 1 GiB or more set a 180 s timeout
and compare by digest while streaming. Model: F3.
- a 100 MiB upload through the gateway puts at most 105 MiB on the uplink
- a 1 GiB upload through the gateway puts at most 1.05 GiB on the uplink, and so does a 1 GiB download, each measured on its own
- while 10 relays each upload 64 MiB and 10 each download 64 MiB to one worker, a forwarded
lease.renewand a relayed request whose target answers at once each answer at most 1 s later than with nothing running, and each of the 20 relays carried at least 1 MiB in the second before and the second after each answer came back - while one relay's caller reads none of its 1 GiB response, another relay's 256 MiB upload to the same worker takes at most 1.5 times as long as with nothing else running
- while the gateway's caller reads none of a 2 GiB response, the target has handed over at most 8 MiB after 5 s; reading it then gets every byte, in order
- while the target reads none of a 2 GiB upload, the gateway has read at most 8 MiB of the caller's body after 5 s; once the target reads, every byte arrives, in order
- a 2 GiB upload through the gateway arrives byte for byte
- a 2 GiB download through the gateway arrives byte for byte and finishes within 90 s
- swapping two chunks of different random sizes (1 byte to 64 KiB) at random offsets of a 2 GiB pattern changes its digest, in each of 100 trials
- the
unitproject and the mutation config leave out*.timing.test.ts, thetimingproject takes them and runs files one at a time,pnpm testrunstest:timing, and CI'squalityjob needs thetimingjob (insrc/test-lanes.test.ts)
Slow lane (F6–F9): in the iOS suite, a test opens a device through the
worker's own front with an agent token minted on the worker, and times a
1 GiB upload with that lease from the preflight to the finalize answer
(F9), three times, then closes it. It then opens a device through the
gateway and times the same upload the same way. The ratio compares the
medians. Both legs run on the same machine, one after the other.
Done when
- Every Tests line passes, and CI runs the
timingproject. - On a Mac with an iOS runtime and the agent-device checks of
toolchain.md: "a 1 GiB upload takes at most 1.5 times as long through the gateway as straight to the worker" passes ine2e/slow-agent-device-gateway.test.ts.
Out of scope
- Any behaviour #558 or #557 owns, except a fix a failing promise needs.
Depends on
- #558
Written by an agent.
- Lingua principale
- TypeScript
- Stelle
- 19
- Fork
- 1
- Merge medio
- 6h 31m
- PR unite (30g)
- 194
Preparare l'ambiente
Questo progetto non fornisce container di sviluppo, Dockerfile né guida per i contributori, quindi l'ambiente è a tuo carico: parti dal suo README e consulta la nostra guida al primo contributo per i passaggi generali.
Come iniziare
- Leggi tutta la issue e poi la guida ai contributi del progetto.
- Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
- Fai un fork del repository e lavora su un branch.
- Apri una pull request che faccia riferimento al numero della issue.
Altre issue di callstackincubator/simlock
-
Lint does not enforce index.ts boundaries for cleanup/, routing/, warm-pool/ and contract/ helpersApertabug:new
Difficoltà 2/5 1-3 ore Idoneità per principianti 70/100
callstackincubator/simlock#445 ·
I maintainer di solito rispondono entro 1 giorno
-
bug:new
Difficoltà 2/5 1-3 ore Idoneità per principianti 78/100
callstackincubator/simlock#424 ·
I maintainer di solito rispondono entro 1 giorno
-
daemon-lifecycle e2e: the it.fails status test passes for the wrong reasonForse già presa @V3RON l’ha presa 5 giorni fa. Apertabug:triage
Difficoltà 2/5 1-3 ore Idoneità per principianti 84/100
callstackincubator/simlock#422 · 1 commento · 1 assegnatario ·
I maintainer di solito rispondono entro 1 giorno
-
task:draft
Difficoltà 4/5 3-5 giorni Idoneità per principianti 15/100
callstackincubator/simlock#569 ·
I maintainer di solito rispondono entro 1 giorno
-
feat(gateway): relayed bodies travel on byte channelsForse già presa @V3RON l’ha presa oggi. Apertatask:ready
callstackincubator/simlock#558 · 1 assegnatario ·
I maintainer di solito rispondono entro 1 giorno
Tutte le issue di callstackincubator/simlock
Issue simili
-
Create/import wallet form shows raw "password must be at least 1 characters" instead of the translated messageForse già presa @CapThunder19 l’ha presa oggi. Apertabug
Difficoltà 2/5 1-3 ore Idoneità per principianti 82/100
joinmarket-webui/jam#1538 ·
I maintainer di solito rispondono entro 1 giorno
-
t0ggles
Difficoltà 2/5 1-3 ore Idoneità per principianti 70/100
nolimits4web/swiper#8240 · 1 commento ·
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 82/100
I maintainer di solito rispondono entro 1 giorno
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 72/100
modelcontextprotocol/inspector#2723 ·
I maintainer di solito rispondono entro 1 giorno
-
status:approved type:bug
Difficoltà 1/5 Meno di un'ora Idoneità per principianti 70/100
egdev6/quorb#109 · 1 commento ·
I maintainer di solito rispondono entro 1 giorno