redweb 0.11.0 → 0.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +163 -0
- package/README.md +176 -508
- package/bin/redweb.js +11 -0
- package/client.d.ts +7 -2
- package/config/tsconfig.json +14 -0
- package/contract.d.ts +45 -0
- package/contract.js +5 -0
- package/docs/ACTION_INPUT_VERIFICATION.md +96 -0
- package/docs/ADMISSION_TIMEOUT_VERIFICATION.md +69 -0
- package/docs/AGENT_ACCESS.md +35 -0
- package/docs/AGENT_EVALUATION.md +58 -0
- package/docs/AGENT_READY_ACCEPTANCE.md +763 -0
- package/docs/APPLICATION_RECORDER_VERIFICATION.md +50 -0
- package/docs/BENCHMARK_VERIFICATION.md +307 -0
- package/docs/BROWSER_OWNER_VERIFICATION.md +191 -0
- package/docs/CLI.md +116 -0
- package/docs/CLIENT_DEVELOPMENT.md +152 -0
- package/docs/CLIENT_POLISH_VERIFICATION.md +282 -0
- package/docs/COVERAGE_COUNTER_VALIDATION.md +109 -0
- package/docs/COVERAGE_SCOPE_AUDIT.md +1183 -0
- package/docs/DEVELOPMENT.md +79 -0
- package/docs/DIAGNOSTIC_COMPATIBILITY.md +76 -0
- package/docs/DOCUMENTATION.md +37 -0
- package/docs/FEEDBACK_COMMAND_VERIFICATION.md +228 -0
- package/docs/GETTING_STARTED.md +58 -0
- package/docs/JSX_PERFORMANCE_VERIFICATION.md +59 -0
- package/docs/LIVE_HTML.md +169 -8
- package/docs/LIVE_HTML_LOAD_VERIFICATION.md +98 -0
- package/docs/MIGRATION.md +28 -0
- package/docs/MULTIPLAYER_OPERATIONS.md +26 -4
- package/docs/ORIGINAL_RECOVERY_VERIFICATION.md +100 -0
- package/docs/PACKAGED_EXAMPLE_VERIFICATION.md +126 -0
- package/docs/POLISH_RELEASE_CHECKPOINT.md +91 -0
- package/docs/PROCESS_CLEANUP_OBSERVATION.md +61 -0
- package/docs/PROCESS_REAPING_VERIFICATION.md +30 -0
- package/docs/PRODUCTION_READINESS.md +11 -2
- package/docs/RECOVERY_CLIENT_HEAP.md +201 -0
- package/docs/RECOVERY_CODE_ATTRIBUTION.md +174 -0
- package/docs/RECOVERY_CODE_CENSUS.md +158 -0
- package/docs/RECOVERY_COMPARISON.md +103 -0
- package/docs/RECOVERY_DEOPTIMIZATION.md +169 -0
- package/docs/RECOVERY_FOLLOWUP_SPIKE.md +147 -0
- package/docs/RECOVERY_INVESTIGATION.md +229 -0
- package/docs/RECOVERY_RUNTIME_CONTROLS.md +181 -0
- package/docs/RELEASE_TRUST.md +58 -0
- package/docs/ROOM_AUTHORIZATION.md +49 -0
- package/docs/RUNTIME_DIAGNOSTICS.md +78 -0
- package/docs/SERVER_RECOVERY_CANDIDATE.md +185 -0
- package/docs/SOAK_ROTATION_OBSERVATION.md +160 -0
- package/docs/SOAK_VERIFICATION.md +154 -0
- package/docs/SOCKET_CONTRACTS.md +39 -0
- package/docs/SPLIT_RECOVERY_COVERAGE.md +83 -0
- package/docs/SPLIT_RECOVERY_ERROR_HANDLING.md +67 -0
- package/docs/STARTER_COORDINATOR_VERIFICATION.md +112 -0
- package/docs/STARTER_LIFECYCLE_VERIFICATION.md +75 -0
- package/docs/STARTER_REPORT_RETENTION.md +73 -0
- package/docs/VERIFICATION_EVIDENCE.md +2 -0
- package/docs/generated.json +2154 -0
- package/docs/guides/chatroom.md +27 -0
- package/docs/guides/http-websocket.md +28 -0
- package/docs/guides/jsx-without-react.md +26 -0
- package/docs/guides/realtime-dashboard.md +29 -0
- package/docs/guides/typed-websockets.md +26 -0
- package/docs/reference.json +1207 -0
- package/docs/snippets/room-access.tsx +51 -0
- package/docs/topics.json +21 -0
- package/examples/live-html/chatroom.js +207 -268
- package/examples/live-html/chatroom.tsx +167 -0
- package/examples/live-html/jsx-page.js +1 -1
- package/examples/live-html/jsx-page.tsx +1 -1
- package/examples/live-html/tsconfig.json +3 -8
- package/index.d.ts +170 -45
- package/index.js +2 -0
- package/jsx-dev-runtime.js +2 -2
- package/jsx-runtime.d.ts +7 -2
- package/package.json +94 -7
- package/recipes/add/artifact.test.cjs +57 -0
- package/recipes/add/live.tsx +18 -0
- package/recipes/add/socket-route.ts +24 -0
- package/recipes/chat/README.md +22 -0
- package/recipes/chat/app.test.cjs +105 -0
- package/recipes/chat/app.tsx +9 -0
- package/recipes/dashboard/README.md +43 -0
- package/recipes/dashboard/admin.ts +21 -0
- package/recipes/dashboard/app.css +16 -0
- package/recipes/dashboard/app.test.cjs +450 -0
- package/recipes/dashboard/app.tsx +86 -0
- package/recipes/dashboard/auth.ts +80 -0
- package/recipes/dashboard/cards.tsx +102 -0
- package/recipes/dashboard/rate-window.test.cjs +17 -0
- package/recipes/dashboard/store.ts +120 -0
- package/recipes/http-ws/README.md +11 -0
- package/recipes/http-ws/app.test.cjs +92 -0
- package/recipes/http-ws/app.tsx +36 -0
- package/recipes/realtime/README.md +8 -0
- package/recipes/realtime/app.test.cjs +15 -0
- package/recipes/realtime/app.tsx +28 -0
- package/recipes/shared/README.md +40 -0
- package/recipes/shared/app.css +8 -0
- package/recipes/shared/copy-assets.cjs +8 -0
- package/recipes/shared/network.cjs +59 -0
- package/recipes/shared/run-app.test.cjs +158 -0
- package/recipes/shared/run-app.ts +50 -0
- package/recipes/site/README.md +4 -0
- package/recipes/site/app.test.cjs +19 -0
- package/recipes/site/app.tsx +25 -0
- package/recipes/socket/README.md +39 -0
- package/recipes/socket/app.test.cjs +85 -0
- package/recipes/socket/app.tsx +30 -0
- package/recipes/socket/contract.ts +12 -0
- package/recipes/socket/handlers.ts +40 -0
- package/src/OwnedServerLifecycle.js +66 -0
- package/src/access/AccessPolicy.js +37 -0
- package/src/access/AuthenticationFailure.js +13 -0
- package/src/access/RequestFailure.js +33 -0
- package/src/access/failure-codes.json +25 -0
- package/src/async/BoundedOperation.js +62 -0
- package/src/cli/ActionReferences.js +193 -0
- package/src/cli/AdditionLayout.js +140 -0
- package/src/cli/FilePlan.js +94 -0
- package/src/cli/ProjectAddition.js +60 -0
- package/src/cli/ProjectConfig.js +26 -0
- package/src/cli/ProjectDoctor.js +112 -0
- package/src/cli/ProjectInitializer.js +20 -0
- package/src/cli/SourceInspector.js +207 -0
- package/src/cli/StaticSource.js +192 -0
- package/src/cli/arguments.js +62 -0
- package/src/cli/formatCommand.js +10 -0
- package/src/cli/run.js +57 -0
- package/src/cli/templates.js +86 -0
- package/src/context/RequestSnapshot.js +41 -0
- package/src/dataProperty.js +11 -0
- package/src/development/DevelopmentPageManager.js +48 -0
- package/src/development/Inspection.js +104 -0
- package/src/development/ObservedRenderer.js +42 -0
- package/src/development/description.js +35 -0
- package/src/development/loopbackRequest.js +27 -0
- package/src/development/refreshBrowser.js +96 -0
- package/src/development/refreshStyles.js +9 -0
- package/src/development/settings.js +17 -0
- package/src/docs/Documentation.js +182 -0
- package/src/htmx/ActionDefinition.js +44 -0
- package/src/htmx/Jsx.js +24 -8
- package/src/htmx/LiveHtmlServer.js +41 -19
- package/src/htmx/LivePage.js +63 -13
- package/src/htmx/PageIdentity.js +32 -0
- package/src/htmx/PageLifetime.js +37 -0
- package/src/htmx/PageManager.js +203 -74
- package/src/htmx/ReactiveRenderer.js +241 -0
- package/src/htmx/StaticExporter.js +1 -1
- package/src/htmx/TemplateRenderer.js +13 -7
- package/src/htmx/browserRuntime.js +2 -93
- package/src/htmx/metadata.js +19 -7
- package/src/validation/ActionInputError.js +12 -0
- package/src/validation/SchemaValidator.js +38 -0
- package/src/ws/AdmissionPolicy.js +24 -23
- package/src/ws/BaseSocketServer.js +53 -38
- package/src/ws/ContractValidationError.js +12 -0
- package/src/ws/HeartbeatMonitor.js +19 -7
- package/src/ws/ProtocolPolicy.js +1 -1
- package/src/ws/RoomAccess.js +82 -0
- package/src/ws/RoomRegistry.js +56 -6
- package/src/ws/RouteRuntime.js +56 -10
- package/src/ws/SocketContract.js +112 -0
- package/src/ws/SocketRoute.js +18 -0
- package/src/ws/protocol-schema.json +6 -1
- package/examples/live-html/chatroom.ts +0 -217
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
# Deferred runtime-recovery investigation
|
|
2
|
+
|
|
3
|
+
Status: deferred research, not a resolved defect or a recovery waiver.
|
|
4
|
+
|
|
5
|
+
The maintainer subsequently authorized development, review and adoption of the
|
|
6
|
+
server-focused check documented in `docs/SERVER_RECOVERY_CANDIDATE.md`. It now
|
|
7
|
+
blocks CI; the original command remains unchanged as a visible non-blocking
|
|
8
|
+
diagnostic. This changes the acceptance contract, not the historical results or
|
|
9
|
+
the unresolved runtime explanation. No historical bounded comparison is repeated.
|
|
10
|
+
|
|
11
|
+
The one-original/one-split Ubuntu comparison is now complete. See
|
|
12
|
+
[its results and contrary ordinary-CI evidence](RECOVERY_COMPARISON.md).
|
|
13
|
+
The stopping rule remains in effect: no repeat research measurement is needed.
|
|
14
|
+
|
|
15
|
+
The maintainer prioritized finishing Redweb's release work over further open-ended
|
|
16
|
+
runtime investigation. Exact V8 code-lifetime attribution is therefore a separate
|
|
17
|
+
follow-up spike. It is no longer a prerequisite to finish the implementation.
|
|
18
|
+
This does not by itself authorize shipping with a failed acceptance check.
|
|
19
|
+
|
|
20
|
+
## What is parked
|
|
21
|
+
|
|
22
|
+
- Explaining whether the attached Code objects in the private client snapshots
|
|
23
|
+
remain executable or are marked for invalidation.
|
|
24
|
+
- Accounting for every hidden/runtime byte and the remaining unclassified parser.
|
|
25
|
+
- Matching invalidated versions from the separate code-log run to snapshot objects.
|
|
26
|
+
- Producing a minimal upstream V8/ws reproduction if the evidence warrants one.
|
|
27
|
+
|
|
28
|
+
No more heap captures, compiler tracing, GC experiments or new diagnostic tooling
|
|
29
|
+
are planned on the release path solely to answer these questions. Do not repeat
|
|
30
|
+
the existing research or treat its partial explanations as a production fix.
|
|
31
|
+
|
|
32
|
+
## Evidence already available
|
|
33
|
+
|
|
34
|
+
[Offline attribution](RECOVERY_CODE_ATTRIBUTION.md) found 261 final
|
|
35
|
+
deoptimization-bearing Code objects attached to preexisting functions/closures,
|
|
36
|
+
one unchanged double-version group, and three unchanged standard-stream/prototype
|
|
37
|
+
Socket objects. The [JIT control](RECOVERY_RUNTIME_CONTROLS.md) strongly supports
|
|
38
|
+
a compilation-dependent contribution in the separate load-generator process.
|
|
39
|
+
|
|
40
|
+
These findings do not establish the entire cause of the original shared-process
|
|
41
|
+
Ubuntu/Node 22.23.2 failure. Its fourth storm reached 110.218742% against the 110%
|
|
42
|
+
limit. One separately traced server also reached 110.080951%; server isolation is
|
|
43
|
+
not assumed to guarantee a pass. Original failures and private evidence remain
|
|
44
|
+
preserved. The snapshots must not be uploaded or embedded in a public issue.
|
|
45
|
+
|
|
46
|
+
## Bounded release decision
|
|
47
|
+
|
|
48
|
+
The next recovery-specific release step is a predeclared comparison using the
|
|
49
|
+
existing original and split-process tools on Ubuntu/Node 22.23.2, with the matching
|
|
50
|
+
client dependency identified. Record exact revisions, environments and every
|
|
51
|
+
phase; keep connection counts, fixed warm baseline, delivery/cleanup checks and
|
|
52
|
+
the 110% bound. No snapshots, tracing, JIT disabling, coverage instrumentation or
|
|
53
|
+
other tests may run inside or alongside the measured processes.
|
|
54
|
+
|
|
55
|
+
Use one original run and one baseline split run, sequentially, not retries until
|
|
56
|
+
green. A failed setup is not a workload result. This is a bounded decision input,
|
|
57
|
+
not enough by itself to establish repeatability or replace cross-runtime release
|
|
58
|
+
checks. Separate processes change scheduling/GC and are not equivalent to the
|
|
59
|
+
original shared-process measurement.
|
|
60
|
+
|
|
61
|
+
Before execution, pin Node 22.23.2, record the Ubuntu 24.04 image/patch/kernel and
|
|
62
|
+
any differences from the historical runner, and record source/lockfile/client
|
|
63
|
+
hashes. Clear inherited diagnostic, coverage and workload overrides. Commands,
|
|
64
|
+
in this order, with the second result collected even if the first fails, but only
|
|
65
|
+
after confirming that the first process and all its children have terminated.
|
|
66
|
+
If cleanup is uncertain, record the second run as blocked; do not launch it beside
|
|
67
|
+
potential residual load:
|
|
68
|
+
|
|
69
|
+
```text
|
|
70
|
+
node --expose-gc scripts/verify-recovery.js
|
|
71
|
+
node scripts/diagnostics/recovery-split.cjs baseline
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
After these two runs, stop, record both outcomes, and request the acceptance-contract
|
|
75
|
+
decision. Do not automatically launch follow-up tracing or repeat either run.
|
|
76
|
+
|
|
77
|
+
- If the isolated server satisfies its own budget and delivery/cleanup checks,
|
|
78
|
+
review whether an explicitly versioned server-focused acceptance protocol is
|
|
79
|
+
appropriate. Track client-generator health separately. Adoption is a separate
|
|
80
|
+
reviewed decision, not automatic promotion of this diagnostic or erasure of
|
|
81
|
+
historical failures.
|
|
82
|
+
- If the server fails its budget, delivery, registry cleanup or process shutdown,
|
|
83
|
+
report the concrete failure and the required release decision. Do not start
|
|
84
|
+
another unbounded runtime-research cycle automatically.
|
|
85
|
+
- A failed diagnostic, incomplete output or uncertain cleanup is not a pass.
|
|
86
|
+
The diagnostic's successful exit proves its stated delivery/cleanup conditions,
|
|
87
|
+
not that its reported heap ratios satisfy a release budget.
|
|
88
|
+
|
|
89
|
+
Existing CI remains unchanged until a replacement protocol is explicitly approved.
|
|
90
|
+
No threshold increase, selective rerun, code-byte subtraction or blanket
|
|
91
|
+
`continue-on-error` follows from this deferral.
|
|
92
|
+
|
|
93
|
+
### Temporary collection host
|
|
94
|
+
|
|
95
|
+
The local Windows machine has no running Docker Linux engine or Ubuntu WSL
|
|
96
|
+
distribution. A temporary, push-only `recovery-comparison.yml` workflow therefore
|
|
97
|
+
collects the declared pair on a separate Ubuntu 24.04 hosted VM, pinned to Node
|
|
98
|
+
22.23.2. It only triggers when that workflow file changes on `codex/agent-ready`,
|
|
99
|
+
rejects repeated run attempts, and is removed after collection. It does not replace
|
|
100
|
+
or modify `ci.yml`, and its completion does not adopt a new acceptance protocol.
|
|
101
|
+
|
|
102
|
+
The historical failed runner reported Ubuntu 24.04.4, image `20260823.283.1`
|
|
103
|
+
and runner agent 2.336.0 (run `33322376349`, job `99286494853`). The new run records
|
|
104
|
+
its actual OS/image/kernel and Node/V8, revision, source/lockfile and client hashes.
|
|
105
|
+
The historical log did not independently record its kernel. Matching the image
|
|
106
|
+
label is not a claim of identical hardware or kernel.
|
|
107
|
+
|
|
108
|
+
Each measured command runs in a transient systemd service with a minimal
|
|
109
|
+
environment and `ExitType=cgroup`, so detached diagnostic worker groups remain
|
|
110
|
+
owned. The 180-second outer cap and five-second termination bound do not change
|
|
111
|
+
the scripts' existing internal deadlines. No resource quota or memory subtraction
|
|
112
|
+
is added. Before either workload, two trivial real Node services exit 0 and 7
|
|
113
|
+
through the same wrapper to verify status propagation and cleanup; these are setup
|
|
114
|
+
probes, not recovery measurements. A failed command remains failed; an empty/removed cgroup must establish
|
|
115
|
+
descendant termination before the split run starts. Systemd containment and clean
|
|
116
|
+
environment differ from the historical direct-shell execution and are disclosed
|
|
117
|
+
in the evidence. Other CI jobs use separate VMs, not necessarily exclusive physical
|
|
118
|
+
hardware. Only explicit safe logs/reports/hashes are retained, never snapshots.
|
|
119
|
+
|
|
120
|
+
The orchestration follows [systemd's transient-service semantics](https://raw.githubusercontent.com/systemd/systemd/v255/man/systemd-run.xml)
|
|
121
|
+
and the kernel's [recursive cgroup population definition](https://docs.kernel.org/admin-guide/cgroup-v2.html#un-populated-notification).
|
|
122
|
+
Its syntax/review and actual hosted execution are verification evidence, not a
|
|
123
|
+
claim of unit coverage for shell orchestration. Both outcomes and the split server's
|
|
124
|
+
actual warm/storm ratios still require review before the acceptance decision.
|
|
125
|
+
|
|
126
|
+
## What remains release-critical
|
|
127
|
+
|
|
128
|
+
- Actual message delivery, reconnect behavior, bounded queues and empty owned
|
|
129
|
+
registries after cleanup.
|
|
130
|
+
- Successful shutdown checks; a reproduced timeout must be resolved or explicitly
|
|
131
|
+
dispositioned, not hidden by a longer deadline. The historical timeout remains
|
|
132
|
+
unexplained even when current regression tests pass.
|
|
133
|
+
- Matching packed Redweb/client compatibility, required coverage and ordinary
|
|
134
|
+
test/load/memory/package checks. Existing gaps are not waived by this spike.
|
|
135
|
+
- Honest documentation of the tested runtime, limits and remaining uncertainty.
|
|
136
|
+
|
|
137
|
+
The full acceptance checklist remains in [AGENT_READY_ACCEPTANCE.md](AGENT_READY_ACCEPTANCE.md).
|
|
138
|
+
This spike adds no new release feature, performance guarantee or certification.
|
|
139
|
+
|
|
140
|
+
## Reopening the spike
|
|
141
|
+
|
|
142
|
+
Resume only as deliberately scheduled work, or when a server-specific regression,
|
|
143
|
+
continued growth under an approved protocol, or a real deployment incident makes
|
|
144
|
+
these questions actionable. Start from the existing evidence and a single
|
|
145
|
+
falsifiable question. Set the experiment count and stopping rule before executing;
|
|
146
|
+
end with a reproducible cause/fix or a documented evidence boundary, not an
|
|
147
|
+
indefinite sequence of deeper snapshots.
|
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
# Recovery investigation — 2026-08-30
|
|
2
|
+
|
|
3
|
+
Status: unresolved. This investigation does not waive the fixed recovery gate.
|
|
4
|
+
|
|
5
|
+
## Question and controls
|
|
6
|
+
|
|
7
|
+
The existing five-cycle `steady-v2` gate intermittently exceeds its 110% retained
|
|
8
|
+
heap limit despite empty connection, room and session registries. The retained
|
|
9
|
+
earlier snapshots showed a temporary compiled-code increase, but did not prove a
|
|
10
|
+
complete attribution or establish an application-owned leak.
|
|
11
|
+
|
|
12
|
+
This investigation used Windows and Node 22.21.0, starting at Redweb `2410e60`.
|
|
13
|
+
The workload remained 1,200 preconditioning connections, 200 warm connections,
|
|
14
|
+
five rounds of 1,200 connections, batches of 50, and the existing 400 ms settling
|
|
15
|
+
period and two explicit collections. No warm-up, threshold, dependency, V8
|
|
16
|
+
acceptance flag or workload change was made. The local npm links were preserved.
|
|
17
|
+
|
|
18
|
+
## Observations
|
|
19
|
+
|
|
20
|
+
One separate `--trace-opt --trace-deopt` run showed repeated weak-object
|
|
21
|
+
invalidation of compiled code in Node transport functions and Redweb's
|
|
22
|
+
`requestSnapshot`, `decorate`, `prepareContext`, `ensureContext`, `handleConnection`
|
|
23
|
+
and session paths. The captured console output was truncated, so it cannot support
|
|
24
|
+
complete event counts or attribution. This trace is diagnostic only, even though
|
|
25
|
+
the verifier's `diagnosticOnly` field does not detect Node trace flags. No raw heap
|
|
26
|
+
snapshots were created. It does not prove that socket-property transitions caused
|
|
27
|
+
the peak, nor that application retention is absent.
|
|
28
|
+
|
|
29
|
+
Source review found avoidable per-connection allocations: a finite-capacity route
|
|
30
|
+
without authentication or protocol policy still allocated an admission abort
|
|
31
|
+
controller, pending-map record and promise chain. A capacity-only synchronous
|
|
32
|
+
path was tested using the existing reservation and rejection logic without that extra
|
|
33
|
+
admission lifecycle. Custom authorization and native `verifyClient` hooks remain
|
|
34
|
+
on the existing asynchronous path. The route's connection-lifetime controller,
|
|
35
|
+
when needed, was unchanged. No connection or exemplar object was kept alive to
|
|
36
|
+
inflate the baseline or preserve V8 shapes.
|
|
37
|
+
|
|
38
|
+
**That candidate was discarded.** Its eligibility check accessed an overridable
|
|
39
|
+
authorization getter outside the protected promise path. It could also mistake a
|
|
40
|
+
replacement on `SocketRoute.prototype` for the default implementation. Two added
|
|
41
|
+
regressions failed on the candidate: the first threw synchronously instead of
|
|
42
|
+
rejecting safely; the second bypassed a denial. Both pass on the restored original
|
|
43
|
+
runtime. The initial reviewer approval was explicitly withdrawn after these
|
|
44
|
+
findings. With no demonstrated recovery or throughput benefit, additional
|
|
45
|
+
compatibility machinery would not justify keeping this optimization.
|
|
46
|
+
|
|
47
|
+
## Unchanged acceptance measurements
|
|
48
|
+
|
|
49
|
+
One ordinary run was taken before the change and one after it. These are individual
|
|
50
|
+
measurements, not a repeated statistical comparison or a throughput claim.
|
|
51
|
+
|
|
52
|
+
| Phase | Before: heap bytes | After: heap bytes |
|
|
53
|
+
| --- | ---: | ---: |
|
|
54
|
+
| Warm | 10,583,768 | 10,575,480 |
|
|
55
|
+
| Storm 1 | 11,043,608 | 11,004,912 |
|
|
56
|
+
| Storm 2 | 11,512,000 | 11,498,392 |
|
|
57
|
+
| Storm 3 | 11,577,120 | 11,560,912 |
|
|
58
|
+
| Storm 4 | 11,583,512 | 11,668,656 |
|
|
59
|
+
| Storm 5 | 10,544,464 | 10,448,840 |
|
|
60
|
+
|
|
61
|
+
The before run passed at a maximum 109.44601204410375%. The after run **failed**
|
|
62
|
+
at 110.33689250984354%. All measured registries were zero in both runs. Final
|
|
63
|
+
decline to 98.80251298286224% after the change does not waive the intermediate
|
|
64
|
+
failure. No retry was used to replace that result. The allocation reduction is
|
|
65
|
+
therefore **not a recovery fix**, and the previous CI failure remains relevant.
|
|
66
|
+
|
|
67
|
+
## Functional verification
|
|
68
|
+
|
|
69
|
+
The new real-listener regression failed before the change: a capacity-only
|
|
70
|
+
connection still had a pending admission record. Afterward, the same regression
|
|
71
|
+
verifies an active capacity reservation during connection, no asynchronous
|
|
72
|
+
admission record, rejection at capacity, release on disconnect and successful
|
|
73
|
+
reconnection. Separate real connections exercise custom authorization denial and
|
|
74
|
+
asynchronous native verification. Unit cases exercise drain, destroyed transports,
|
|
75
|
+
upgrade exceptions and reservation cleanup. These tests do not inject mocked
|
|
76
|
+
transports into the integration cases.
|
|
77
|
+
|
|
78
|
+
Before these extra compatibility cases were added, the discarded candidate
|
|
79
|
+
passed 759 tests in 74 suites and all four instrumented-library coverage metrics
|
|
80
|
+
at 100% (392.665 seconds), plus pretest/types. That broad pass did not detect the
|
|
81
|
+
two subsequently demonstrated compatibility defects, and is not final-tree
|
|
82
|
+
verification. The restored runtime with the two retained regression cases passes
|
|
83
|
+
143 unit/real-network tests in ten suites, with all-four 100% coverage over
|
|
84
|
+
`src/ws/BaseSocketServer.js`. Earlier narrower selections lacked unrelated
|
|
85
|
+
constructor/inspection coverage and correctly failed their 100% coverage checks;
|
|
86
|
+
their behavior tests passed. No threshold was changed.
|
|
87
|
+
|
|
88
|
+
## Native WebSocket control
|
|
89
|
+
|
|
90
|
+
After the full suite completed, one separate native-`ws` control acknowledged all
|
|
91
|
+
7,400 messages using the same connection counts, batch size, settling delay and
|
|
92
|
+
collection sequence. It loaded no Redweb server/runtime, but reused the existing
|
|
93
|
+
native client open/close helpers. It omitted Redweb's rooms, sessions, authorization
|
|
94
|
+
and application dispatch, so it is not a feature-equivalent benchmark or acceptance
|
|
95
|
+
substitute. Its wire-response assertions and helper waits also differ from the
|
|
96
|
+
acceptance driver. It measured zero native server clients after every phase.
|
|
97
|
+
|
|
98
|
+
Warm heap was 6,919,096 bytes. Successive cycle heaps were 7,279,776 / 7,672,840 /
|
|
99
|
+
7,755,872 / 7,819,640 / 7,829,720 bytes, ending at **113.16102565999951%** of warm.
|
|
100
|
+
The control's exit 0 means its delivery/cleanup assertions passed, not that it
|
|
101
|
+
passed a 110% memory gate; it deliberately reports measurements without enforcing
|
|
102
|
+
Redweb's acceptance threshold. Its local source is retained at
|
|
103
|
+
`coverage/recovery-native-control.cjs` (SHA-256
|
|
104
|
+
`70484c74a59071fc8b9c73691c4e01dc6240abe65e15ea1a9e15536da03772e1`).
|
|
105
|
+
|
|
106
|
+
This demonstrates that exceeding a 10% total-heap ratio is possible in this host's
|
|
107
|
+
underlying network workload without Redweb. Together with the trace, it supports
|
|
108
|
+
further investigation of runtime/compiled-code lifetime. It does **not** establish
|
|
109
|
+
complete attribution of Redweb's failure or prove the absence of a Redweb leak.
|
|
110
|
+
|
|
111
|
+
## Remaining investigation boundary
|
|
112
|
+
|
|
113
|
+
The next recovery investigation must distinguish normal compiled-code lifetime
|
|
114
|
+
from a concrete application retainer using a narrowly targeted observation. Do
|
|
115
|
+
not subtract code bytes, retain artificial baseline objects, weaken the 110%
|
|
116
|
+
limit, increase warm-up, or treat a later isolated pass as resolution. Publication,
|
|
117
|
+
full original-client/application coverage and final cross-platform checks remain
|
|
118
|
+
separate requirements.
|
|
119
|
+
|
|
120
|
+
## Split-process milestone
|
|
121
|
+
|
|
122
|
+
The original verifier measures Redweb, native client sockets and its load driver
|
|
123
|
+
inside one Node heap. To distinguish those owners, the separate diagnostic
|
|
124
|
+
`node scripts/diagnostics/recovery-split.cjs` starts a server worker and a native
|
|
125
|
+
client worker. Only the coordinator retains earlier measurements. The acceptance
|
|
126
|
+
verifier is unchanged; this diagnostic cannot pass or waive its heap gate.
|
|
127
|
+
|
|
128
|
+
Both workers use Node's existing `--expose-gc` flag, without inherited Node options
|
|
129
|
+
or coverage instrumentation. The server retains the original route, handler,
|
|
130
|
+
room/session limits and timing. Work remains 1,200 preconditioning connections,
|
|
131
|
+
200 warm connections, five 1,200-connection storms and batches of 50. Each batch
|
|
132
|
+
waits for server connection cleanup. Each phase waits 400 ms, collects twice with
|
|
133
|
+
one intervening immediate, and requires all measured registries to be empty.
|
|
134
|
+
|
|
135
|
+
Differences are deliberate and material: there are separate runtimes, IPC and a
|
|
136
|
+
coordinator between batches; replies are parsed and checked against their exact
|
|
137
|
+
IDs; client operations use settled-result arrays and explicit ownership through
|
|
138
|
+
failure cleanup. V8 statistics are read after the phase's heap measurement. These
|
|
139
|
+
extra allocations and the changed scheduling mean ratios cannot be substituted
|
|
140
|
+
for, added to, or directly compared as equivalents of the original shared heap.
|
|
141
|
+
V8 spaces, code statistics, external memory and array buffers are overlapping views,
|
|
142
|
+
not additive explanations of heap growth. No code-byte subtraction is allowed.
|
|
143
|
+
|
|
144
|
+
Evidence is written to a new exclusive directory under `coverage/recovery-split-*`:
|
|
145
|
+
complete per-phase JSON lines, a final JSON report, source fingerprints, versions,
|
|
146
|
+
process identities, actual delivery counts, registry sizes and all memory views.
|
|
147
|
+
Source fingerprints are checked again after completion. Output beyond 1 MiB is
|
|
148
|
+
explicitly marked truncated. Each request and process cleanup is bounded; failed
|
|
149
|
+
channels cannot be reused, and uncertain cleanup retains the PID and nested
|
|
150
|
+
failures rather than claiming success. No raw heap snapshots are taken.
|
|
151
|
+
|
|
152
|
+
### Single split run: observations
|
|
153
|
+
|
|
154
|
+
Run once after the full suite finished, from 19:05:35.658 to 19:05:48.448 UTC on
|
|
155
|
+
2026-08-30, Windows/Node 22.21.0, V8 `12.4.254.21-node.33`, native `ws` 8.21.3.
|
|
156
|
+
The server PID was 22040; the load-generator PID was 34932. Both workers exited.
|
|
157
|
+
All 7,400 request IDs were acknowledged exactly, and every phase had zero server
|
|
158
|
+
connections/rooms/sessions and zero tracked client connections. Fingerprints were
|
|
159
|
+
unchanged at completion. Neither worker emitted output; no output was truncated.
|
|
160
|
+
|
|
161
|
+
| Phase | Server heap bytes | Client heap bytes |
|
|
162
|
+
| --- | ---: | ---: |
|
|
163
|
+
| Preconditioning | 10,181,120 | 6,579,816 |
|
|
164
|
+
| Warm | 10,187,232 | 6,540,872 |
|
|
165
|
+
| Storm 1 | 10,466,240 | 6,782,104 |
|
|
166
|
+
| Storm 2 | 10,874,320 | 7,205,968 |
|
|
167
|
+
| Storm 3 | 10,989,184 | 7,312,720 |
|
|
168
|
+
| Storm 4 | 11,037,936 | 7,374,504 |
|
|
169
|
+
| Storm 5 | 9,718,488 | 7,410,304 |
|
|
170
|
+
|
|
171
|
+
The server peaked at **108.35068839111547%** of its own warm heap and ended at
|
|
172
|
+
**95.39871085688438%**. The client crossed 110% at storm 2 and ended at
|
|
173
|
+
**113.29229497229116%**, its highest measured value. This attributes the sustained
|
|
174
|
+
above-110% ratio **in this split diagnostic** to the native load-generator process,
|
|
175
|
+
which does not load Redweb's runtime or `redweb-client`. It does not establish the
|
|
176
|
+
cause or relative contributions inside the original shared-process CI failure.
|
|
177
|
+
|
|
178
|
+
The client's warm-to-final heap increase was 869,432 bytes. Its code-and-metadata
|
|
179
|
+
statistic increased 521,972 bytes, while bytecode-and-metadata stayed at 755,952.
|
|
180
|
+
Its old/code/trusted spaces increased 394,608 / 321,216 / 152,360 bytes respectively;
|
|
181
|
+
external memory and array buffers remained unchanged after warm-up. These are
|
|
182
|
+
overlapping views sampled sequentially, not an exact object-retention accounting.
|
|
183
|
+
The data supports investigating client/runtime code and metadata lifetime, but
|
|
184
|
+
does not establish that all growth is compiled code or exclude retained objects.
|
|
185
|
+
|
|
186
|
+
On the server, bytecode-and-metadata fell from 908,240 bytes at storm 4 to 204,960
|
|
187
|
+
at storm 5 while heap fell by 1,319,448 bytes. This is a correlated observation,
|
|
188
|
+
not proof of a particular garbage-collector or bytecode-flushing cause. Server
|
|
189
|
+
code-and-metadata remained 416,038 bytes above warm at the final measurement.
|
|
190
|
+
|
|
191
|
+
Complete local evidence: `coverage/recovery-split-RQytod/report.json`, SHA-256
|
|
192
|
+
`fa8b0a070dfb833a8449e4c658190a64778f9e425fed42c93251dda57ed35db7`, alongside
|
|
193
|
+
`samples.ndjson`. The report includes all source fingerprints and memory views;
|
|
194
|
+
the table above preserves every phase's heap measurement in version control.
|
|
195
|
+
|
|
196
|
+
### Verification and next boundary
|
|
197
|
+
|
|
198
|
+
The full suite passed **770 tests / 76 suites**, pretest/type checks, and all-four
|
|
199
|
+
100% instrumented-library coverage in 427.392 seconds. Sixteen focused tests cover
|
|
200
|
+
the diagnostic's fixed phase plan, fingerprints, nested errors, real HTTP-upgrade
|
|
201
|
+
and WebSocket delivery, malformed replies, refused connections, timeout/exit,
|
|
202
|
+
graceful and forced cleanup, and command validation. OS-cleanup uncertainty is
|
|
203
|
+
tested separately with mocked units, not presented as real-process integration.
|
|
204
|
+
|
|
205
|
+
The diagnostic scripts are **not at 100% coverage**. Native child-aware coverage
|
|
206
|
+
reports 74.83% statements/lines, 95.12% branches and 80% functions across both
|
|
207
|
+
scripts. Worker statements/lines are 97.36%; orchestration/CLI and failure paths
|
|
208
|
+
remain uncovered. The earlier Jest-only report did not instrument child code and
|
|
209
|
+
reported 36.72% statements; that was not a behavioral failure. Both coverage gates
|
|
210
|
+
correctly exited nonzero without weakened thresholds; all sixteen behavior tests
|
|
211
|
+
passed. Coverage instrumentation is explicit in behavioral tests and disabled in
|
|
212
|
+
the actual measured workers. Library coverage does not certify diagnostic coverage.
|
|
213
|
+
|
|
214
|
+
Final pretest/type/generated-documentation checks and 20 focused documentation/
|
|
215
|
+
diagnostic tests also passed after the evidence update. The senior critic approved
|
|
216
|
+
the milestone after independently checking report/source hashes, phase counts,
|
|
217
|
+
registries and calculations; earlier cleanup/evidence findings were addressed.
|
|
218
|
+
The next causal step is client-only retaining-path/code-lifetime
|
|
219
|
+
inspection at warm and late storms, with complete bounded evidence, followed by a
|
|
220
|
+
one-variable control. A speculative Redweb runtime optimization is not justified
|
|
221
|
+
by this result. The original recovery failure, client/application coverage gaps
|
|
222
|
+
and release requirements remain open. No original acceptance gate was rerun or
|
|
223
|
+
waived, and no production code, dependency, threshold, publication or deployment
|
|
224
|
+
changed in this milestone.
|
|
225
|
+
|
|
226
|
+
Research-led follow-up: [runtime/JIT controls](RECOVERY_RUNTIME_CONTROLS.md) records
|
|
227
|
+
the subsequent same-source baseline, complete trace and client-only JIT-disabled
|
|
228
|
+
control. It narrows the client growth to a JIT-dependent effect without waiving
|
|
229
|
+
the original recovery failure.
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
# Recovery runtime controls — 2026-08-30
|
|
2
|
+
|
|
3
|
+
Status: a strong JIT-dependent effect was identified in the split load generator.
|
|
4
|
+
The original shared-process recovery failure is **not resolved or waived**.
|
|
5
|
+
This continues [the split-process investigation](RECOVERY_INVESTIGATION.md).
|
|
6
|
+
|
|
7
|
+
## Research and predeclared tests
|
|
8
|
+
|
|
9
|
+
The V8 source bundled with Node 22.21.0 enables bytecode flushing with an aging
|
|
10
|
+
threshold of six eligible collections. Forced and heap-profiler collections keep
|
|
11
|
+
ages unchanged; the exposed `gc()` function requests a forced collection. Thus two
|
|
12
|
+
explicit collections do not guarantee that unused code has aged enough to flush.
|
|
13
|
+
These are implementation details of this exact runtime, not portable API promises.
|
|
14
|
+
Sources: [flags](https://github.com/nodejs/node/blob/v22.21.0/deps/v8/src/flags/flag-definitions.h),
|
|
15
|
+
[age handling](https://github.com/nodejs/node/blob/v22.21.0/deps/v8/src/heap/heap.h),
|
|
16
|
+
[GC extension](https://github.com/nodejs/node/blob/v22.21.0/deps/v8/src/extensions/gc-extension.cc),
|
|
17
|
+
[V8 bytecode-flushing explanation](https://v8.dev/blog/v8-lite).
|
|
18
|
+
|
|
19
|
+
Three runs were declared before measurement, executed once each, sequentially:
|
|
20
|
+
|
|
21
|
+
1. `node scripts/diagnostics/recovery-split.cjs baseline` — a fresh same-source control.
|
|
22
|
+
2. `node scripts/diagnostics/recovery-split.cjs trace` — both workers use
|
|
23
|
+
`--trace-gc --trace-flush-code`, with additional sample markers.
|
|
24
|
+
3. `node scripts/diagnostics/recovery-split.cjs client-jitless` — only the load
|
|
25
|
+
generator additionally uses `--jitless`; the server retains normal compilation.
|
|
26
|
+
|
|
27
|
+
All use `--expose-gc`. No inherited Node options or coverage instrumentation enter
|
|
28
|
+
the measured workers. Windows, Node 22.21.0, V8 12.4.254.21-node.33 and ws 8.21.3
|
|
29
|
+
are unchanged. All three reports contain identical source fingerprints, also
|
|
30
|
+
checked at each run's completion. No test suite ran alongside the measurements.
|
|
31
|
+
The diagnostic changes no original acceptance script, workload, warm-up or budget.
|
|
32
|
+
|
|
33
|
+
The fixed workload remains 1,200 preconditioning connections, 200 warm connections,
|
|
34
|
+
five rounds of 1,200, batches of 50, connection-cleanup barriers and 400 ms settling
|
|
35
|
+
with two explicit collections. Every run verified all 7,400 exact reply IDs and
|
|
36
|
+
empty measured registries at every phase. Both workers exited in every run.
|
|
37
|
+
|
|
38
|
+
## Measurements
|
|
39
|
+
|
|
40
|
+
Heap bytes, captured before allocating each sample's subsequent V8 statistics:
|
|
41
|
+
|
|
42
|
+
| Phase | Baseline server | Baseline client | Traced server | Traced client | JIT-control server | JIT-disabled client |
|
|
43
|
+
| --- | ---: | ---: | ---: | ---: | ---: | ---: |
|
|
44
|
+
| Preconditioning | 10,171,000 | 6,568,792 | 10,174,984 | 6,571,376 | 10,186,408 | 5,566,904 |
|
|
45
|
+
| Warm | 10,190,632 | 6,539,864 | 10,182,928 | 6,504,752 | 10,190,344 | 5,570,608 |
|
|
46
|
+
| Storm 1 | 10,472,704 | 6,767,512 | 10,453,688 | 6,773,968 | 10,455,296 | 5,573,200 |
|
|
47
|
+
| Storm 2 | 10,866,832 | 7,235,712 | 10,777,240 | 7,198,296 | 10,774,848 | 5,573,320 |
|
|
48
|
+
| Storm 3 | 10,888,784 | 7,339,704 | 11,079,576 | 7,321,224 | 11,000,000 | 5,575,240 |
|
|
49
|
+
| Storm 4 | 11,067,616 | 7,365,128 | 10,882,944 | 7,362,680 | 11,112,632 | 5,575,752 |
|
|
50
|
+
| Storm 5 | 9,911,296 | 7,388,792 | 11,209,464 | 7,343,488 | 11,109,832 | 5,575,752 |
|
|
51
|
+
|
|
52
|
+
The like-for-like comparison is baseline versus client-JIT control, **not** trace
|
|
53
|
+
versus JIT control. Baseline client growth after warm-up was **848,928 bytes**
|
|
54
|
+
(112.98082039626512% of warm); the JIT-disabled client grew **5,144 bytes**
|
|
55
|
+
(100.09234180541873%). Baseline client code-and-metadata grew 504,608 bytes;
|
|
56
|
+
the JIT-disabled client's corresponding value stayed exactly 2,058,560 bytes.
|
|
57
|
+
Client bytecode-and-metadata, external memory and array buffers remained unchanged
|
|
58
|
+
after warm-up in both runs.
|
|
59
|
+
|
|
60
|
+
This is strong evidence of **JIT-dependent growth in this split workload**. It is
|
|
61
|
+
not exact accounting of every retained byte: code/space statistics overlap, and
|
|
62
|
+
disabling JIT also changes execution speed, allocation and collection behavior.
|
|
63
|
+
The control additionally reports `Warning: disabling flag --expose_wasm due to
|
|
64
|
+
conflicting flags`; that warning is preserved, not suppressed. The workload does
|
|
65
|
+
not exercise WebAssembly. This is neither a throughput result nor a recommendation
|
|
66
|
+
to disable JIT in production. See [V8's description of JIT-less execution](https://v8.dev/blog/jitless).
|
|
67
|
+
|
|
68
|
+
The baseline server peaked at 108.60578617695154% and finished at
|
|
69
|
+
97.25889424718703% of its warm heap. Its bytecode-and-metadata again fell late,
|
|
70
|
+
from 908,584 to 205,248 bytes. That event **did not recur in the traced run**:
|
|
71
|
+
server bytecode remained 908,584 and final heap reached 110.08095117632178%.
|
|
72
|
+
The normal-JIT server paired with the JIT-disabled client peaked at
|
|
73
|
+
109.05060712376344% and finished at 109.0231301318189%, also without the late
|
|
74
|
+
bytecode drop. Retain all three observations; do not select the smallest result.
|
|
75
|
+
|
|
76
|
+
## Complete trace and its framing limitation
|
|
77
|
+
|
|
78
|
+
The traced server's stdout contains 12,979 bytes and the client's 12,257 bytes;
|
|
79
|
+
both stderr files are empty. All file lengths and SHA-256 values were independently
|
|
80
|
+
rechecked. Natural successful shutdown now drains output before exit; abrupt
|
|
81
|
+
coordinator loss retains orphan protection and the coordinator retains bounded
|
|
82
|
+
forced cleanup. Output is limited to 16 MiB per stream: overflow or a write failure
|
|
83
|
+
invalidates the run instead of silently truncating successful evidence.
|
|
84
|
+
|
|
85
|
+
V8's buffered native output and JavaScript sample markers interleave, occasionally
|
|
86
|
+
inside a native line. **Raw marker adjacency is not a trustworthy timeline.**
|
|
87
|
+
The original byte logs are preserved unchanged. For the counts below, remove only
|
|
88
|
+
the fourteen exact `[rw-phase ...]` marker records (including their line endings)
|
|
89
|
+
per worker from an in-memory copy. The reconstructed native records all have the
|
|
90
|
+
expected process prefix and monotonically increasing V8 millisecond timestamps.
|
|
91
|
+
No original bytes/files are overwritten, and no marker-based phase timing claim
|
|
92
|
+
is made.
|
|
93
|
+
|
|
94
|
+
| Reconstructed native records | Server | Client |
|
|
95
|
+
| --- | ---: | ---: |
|
|
96
|
+
| Scavenges | 37 | 41 |
|
|
97
|
+
| Mark-Compacts | 19 | 16 |
|
|
98
|
+
| Mark-Compacts labeled `testing` | 14 | 14 |
|
|
99
|
+
| Mark-Compacts labeled `finalize incremental marking via task` | 5 | 2 |
|
|
100
|
+
| Flushing summary records | 19 | 16 |
|
|
101
|
+
| Total flushed SharedFunctionInfos reported | 0 | 0 |
|
|
102
|
+
|
|
103
|
+
Server natural-major timestamps: 454 / 6,299 / 8,275 / 10,259 / 12,244 ms.
|
|
104
|
+
Client natural-major timestamps: 1,323 / 4,201 ms. The fourteen testing collections
|
|
105
|
+
per worker agree with two explicit calls for each of seven phases. The zero
|
|
106
|
+
flushing totals and stable bytecode measurements are consistent with the V8 aging
|
|
107
|
+
mechanism, but do not prove what caused the earlier untraced bytecode drop.
|
|
108
|
+
No retry was made to obtain the desired flushing event.
|
|
109
|
+
|
|
110
|
+
## Evidence locations
|
|
111
|
+
|
|
112
|
+
Each directory contains `report.json`, `samples.ndjson`, and separate server/client
|
|
113
|
+
stdout/stderr logs. Reports include flags, versions, identities, source hashes,
|
|
114
|
+
per-phase memory views, delivery counts and output-file hashes. Times are UTC.
|
|
115
|
+
|
|
116
|
+
| Mode | Local directory under `coverage/` | Start–end on 2026-08-30 |
|
|
117
|
+
| --- | --- | --- |
|
|
118
|
+
| Baseline | `recovery-split-RqlKQM` | 19:20:24.892–19:20:37.704 |
|
|
119
|
+
| Trace | `recovery-split-bg0hV9` | 19:20:42.205–19:20:54.990 |
|
|
120
|
+
| Client JIT-disabled | `recovery-split-z9JA5J` | 19:20:59.831–19:21:13.483 |
|
|
121
|
+
|
|
122
|
+
Report SHA-256 values, respectively:
|
|
123
|
+
|
|
124
|
+
- `212f24669b0240eff1680cb9aa91cef4690465f3203b6b81e6f8da50981d9a08`
|
|
125
|
+
- `88fa6323feded06fea25f78169c88f79d7f4dcead997730d078203f8ee132f02`
|
|
126
|
+
- `21b6c73bac8789c4f234363416df9fd740c0c7208b977e821f83c9377ccd7521`
|
|
127
|
+
|
|
128
|
+
Trace stdout SHA-256 values:
|
|
129
|
+
|
|
130
|
+
- Server: `29be4f852458b55af3ce6b77a9fd4b9b8213430c38e7c827c66231f2ae67d38c`
|
|
131
|
+
- Client: `e006731ada264a63220e4dcafa6da080c049699e59c3f7caaabd2572cf14b4a2`
|
|
132
|
+
|
|
133
|
+
## Verification and remaining work
|
|
134
|
+
|
|
135
|
+
Twenty-four focused tests pass, combining unit tests with real child processes
|
|
136
|
+
and real HTTP-upgrade/WebSocket traffic. New cases verify exact mode flags,
|
|
137
|
+
complete output/hashes, cap failures, exclusive evidence creation and an 8 MiB
|
|
138
|
+
queued-output shutdown fixture. That last test also passed before the drain fix
|
|
139
|
+
on Windows; it must not be described as a reproduced POSIX truncation bug.
|
|
140
|
+
|
|
141
|
+
Native child-aware diagnostic coverage remains below its unchanged 100% gate:
|
|
142
|
+
76.03% statements/lines, 95.57% branches and 91.66% functions. The worker is at
|
|
143
|
+
100% statements/lines/functions and 97.82% branches; its connection-barrier timeout
|
|
144
|
+
branch remains uncovered. Coordinator/CLI and failure paths also remain uncovered.
|
|
145
|
+
All behavior tests pass; the separate coverage command correctly exits nonzero.
|
|
146
|
+
No exclusions or relaxed thresholds were introduced.
|
|
147
|
+
|
|
148
|
+
Full-suite verification failed: **777 tests passed and one failed** across
|
|
149
|
+
76 suites (75 passed, one failed), in 415.09 seconds. The failing case is
|
|
150
|
+
`owned-http-shutdown.integration.test.js`: successful page cleanup with `live=true`
|
|
151
|
+
timed out waiting 500 ms for the client's WebSocket close event, after application
|
|
152
|
+
shutdown and incomplete-HTTP-peer closure had completed. Its cause remains
|
|
153
|
+
unestablished; it is not dismissed as a timing flake or attributed to these
|
|
154
|
+
diagnostics. No retry was used to replace this result. Pretest/generated-document
|
|
155
|
+
and TypeScript gates passed. Instrumented-library coverage was 100% for statements,
|
|
156
|
+
branches, functions and lines, but that does not override the behavioral failure
|
|
157
|
+
or the separate diagnostic-tool coverage gaps above.
|
|
158
|
+
|
|
159
|
+
Read-only critic inspection confirmed that the client close listener was installed
|
|
160
|
+
before connection readiness, so no obvious missed-listener race explains the
|
|
161
|
+
failure. Server shutdown bounds termination attempts but does not await the remote
|
|
162
|
+
client's close notification. Endpoint state and error timing were not captured at
|
|
163
|
+
the deadline; those observations are needed before attributing this failure.
|
|
164
|
+
Final documentation generation/TypeScript checks passed, followed by 28 focused
|
|
165
|
+
documentation and diagnostic tests across three suites. That scoped pass does not
|
|
166
|
+
replace the failed full-suite result.
|
|
167
|
+
|
|
168
|
+
The senior critic independently checked mode isolation, cleanup, report/log hashes,
|
|
169
|
+
delivery/registry counts, reconstructed trace counts and the inference boundaries.
|
|
170
|
+
There was no actionable evidence-integrity finding after the drain fix.
|
|
171
|
+
|
|
172
|
+
The next causal investigation, if continued, should identify which compiled
|
|
173
|
+
functions, feedback structures and retaining paths account for the client growth
|
|
174
|
+
under normal JIT. The paired result does not establish an exact object-level cause
|
|
175
|
+
or resolve the original shared-process CI failure. No further repeated benchmark
|
|
176
|
+
is justified merely to obtain a smaller number or a flushing event. Original
|
|
177
|
+
acceptance limits, runtime/library sources, dependencies, npm links, publication
|
|
178
|
+
and deployment remain unchanged. No raw heap snapshots were taken.
|
|
179
|
+
|
|
180
|
+
Follow-up: [client code-creation census](RECOVERY_CODE_CENSUS.md) identifies
|
|
181
|
+
concrete normal-JIT compilation candidates without claiming retained-size proof.
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# Choose and verify a Redweb release
|
|
2
|
+
|
|
3
|
+
Redweb is a Node.js HTTP/WebSocket library with server-rendered TSX, not a hosted service. Evaluate the exact package, runtime, application and deployment you intend to use. A passing test suite, a registry signature and a provenance statement answer different questions; none certifies an application as secure.
|
|
4
|
+
|
|
5
|
+
## Runtime and compiler compatibility
|
|
6
|
+
|
|
7
|
+
| Area | Contract and verification boundary |
|
|
8
|
+
| --- | --- |
|
|
9
|
+
| Core runtime | The package declares Node `>=18`. This is an installation/compatibility floor, not a recommendation to deploy an end-of-life runtime. |
|
|
10
|
+
| Production Node | Use a currently maintained LTS release with current security patches. As checked on 2026-08-30, Node 22 and 24 are LTS; Node 18 and 20 are end-of-life. Recheck the official schedule when deploying. |
|
|
11
|
+
| CI coverage | The repository matrix targets Node 18, 20, 22 and 24 on Linux. The 18/20 jobs are legacy-compatibility checks, not security-support claims. A configured job is not a passing result; inspect checks for your exact commit. |
|
|
12
|
+
| TypeScript/TSX | The starter uses the package's tested TypeScript dependency and `redweb/tsconfig.json`. Standard decorators and legacy `experimentalDecorators` consumers have separate compile tests. Node's native TypeScript execution is not a replacement for compiling TSX/decorators with this configuration. |
|
|
13
|
+
| Persistent dashboard | This application recipe requires Node 22.13+ and native `node:sqlite`; it is not part of the core runtime requirement. Its database and account/session design are single-process. |
|
|
14
|
+
| Browser | The real-browser gates exercise Chromium. They are not a Firefox/Safari compatibility certification. Test the browsers you support, including reconnect and forms, before release. |
|
|
15
|
+
| Runtime platforms | This branch has local Windows evidence and Linux CI configuration. Neither proves every OS, architecture, proxy, container platform or serverless host works. Live pages require a long-lived Node listener with WebSocket upgrades. Static export is a separate deployment mode. |
|
|
16
|
+
|
|
17
|
+
Use the [official Node release schedule](https://nodejs.org/en/about/previous-releases) for maintained releases, the [TypeScript decorator documentation](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-5-0.html#decorators) for the distinction between decorator modes, and [Node's TypeScript limitations](https://nodejs.org/api/typescript.html) for native execution constraints. Current per-commit test evidence and uncompleted checks are recorded in the [release checklist](AGENT_READY_ACCEPTANCE.md), not inferred from this table.
|
|
18
|
+
|
|
19
|
+
## Pin the package and the documentation together
|
|
20
|
+
|
|
21
|
+
For a published application, select an exact release, commit its lockfile, and use `npm ci` in CI/deployment. The following is an intentionally pinned example, not an instruction to treat `0.12.0` as permanently current:
|
|
22
|
+
|
|
23
|
+
```sh
|
|
24
|
+
npm view redweb@0.12.0 version engines dist.integrity dist.signatures dist.attestations gitHead --json
|
|
25
|
+
npm install --save-exact redweb@0.12.0
|
|
26
|
+
npm audit signatures
|
|
27
|
+
npm audit --omit=dev
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
The signature command must run in the installed application directory. Keep TLS verification enabled and use a current npm CLI; a certificate/trust-store failure is not a reason to disable verification. A lockfile's integrity value detects changed package bytes; registry signatures authenticate registry metadata; provenance, when present and verified, links an artifact to a build/source identity. Vulnerability audit is a separate check against known advisories, not an application penetration test.
|
|
31
|
+
|
|
32
|
+
For this branch's **unreleased** features, follow the matching tarball instructions in the [complete starter recipes](GETTING_STARTED.md#start-with-a-complete-recipe). The checkout has package metadata `0.13.0`, reserved for this unreleased candidate; the published `redweb@0.12.0` does not contain these changes. Installing `latest` does not install the unmerged branch. Do not mix a local-candidate guide with an older registry release and assume the APIs exist. Changing the package version does not publish it or satisfy outstanding release checks.
|
|
33
|
+
|
|
34
|
+
Redweb is pre-1.0. Consult the changelog and versioned guide before upgrading, run your own real HTTP/WebSocket/browser tests, and keep a rollback artifact. Patch/minor numbers and a compatible TypeScript build alone do not prove wire compatibility, preserved sessions, database compatibility or application authorization. HTTP-created live-page sessions are process-owned; a restart or rolling replacement does not migrate them automatically. Raw socket protocol versions are negotiated only when the route opts in, and application payload compatibility remains your contract.
|
|
35
|
+
|
|
36
|
+
## What was verified for the published package
|
|
37
|
+
|
|
38
|
+
Read-only registry inspection on **2026-08-30** reported `latest: 0.12.0`, with:
|
|
39
|
+
|
|
40
|
+
- `gitHead`: `6c95093c5e3b357772841f40c5371359dab0bf03`.
|
|
41
|
+
- SHA-512 integrity: `sha512-74AOoEmREkoPElYB9nalsN8nLfiPzw1Ap3WYEwxERJqoSGcfYAQhyfpAK2dOyLQtc+A+sAl9fFv0HMuIXWDjEg==`.
|
|
42
|
+
- Registry signatures present; **no `dist.attestations` field was returned**. Build provenance is therefore not claimed for this release.
|
|
43
|
+
|
|
44
|
+
An independently created temporary application installed that exact package with lifecycle scripts disabled and ran `npm audit signatures --json` using Node 22.21.0/npm 11.6.2 and the Windows system trust store. It exited successfully with `invalid: []` and `missing: []`. That checks the installed registry dependency tree's signatures/available attestations; an empty failure list does **not** mean every package has build provenance. This historical observation is not a verification of a future release or of the current unreleased source.
|
|
45
|
+
|
|
46
|
+
The commands above let you repeat the check. See npm's [signature and attestation verification](https://docs.npmjs.com/cli/v11/commands/npm-audit/) and [viewing provenance](https://docs.npmjs.com/viewing-package-provenance/) documentation for current verification behavior.
|
|
47
|
+
|
|
48
|
+
## Publishing provenance is a maintainer action
|
|
49
|
+
|
|
50
|
+
No publishing workflow or npm account setting is enabled by this guide. To add provenance to a future release, the maintainer must choose an authorized supported build/publish workflow, configure the correct repository identity and npm permissions, publish the exact tested artifact, and verify the resulting registry attestation afterward. A local `npm pack`, `gitHead`, checksum, badge or successful CI run is not a substitute for a verified attestation. Do not label older releases retroactively as provenance-verified.
|
|
51
|
+
|
|
52
|
+
npm describes the supported providers and identity requirements in [generating provenance](https://docs.npmjs.com/generating-provenance-statements/) and [trusted publishing](https://docs.npmjs.com/trusted-publishers/). Provenance provides origin/build evidence, not proof that source code is safe.
|
|
53
|
+
|
|
54
|
+
## Support and reporting boundaries
|
|
55
|
+
|
|
56
|
+
For ordinary bugs, provide a minimal reproducible project, exact Redweb/Node/npm/TypeScript versions, operating system, decorator mode, sanitized logs, and the failing HTTP/WebSocket sequence in the [issue tracker](https://github.com/lakam99/redweb/issues). Never include tokens, cookies, passwords, private database contents or customer traffic.
|
|
57
|
+
|
|
58
|
+
There is no paid support contract, response-time SLA or long-term backport policy established by these files. No private vulnerability contact is invented here. The repository inspection on 2026-08-30 reported no published security policy; the maintainer still needs to establish a private reporting channel and its handling policy before the project claims one. Do not disclose a suspected vulnerability or working exploit in a public bug report merely because that is the only linked tracker.
|