redweb 0.12.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.
Files changed (167) hide show
  1. package/CHANGELOG.md +166 -9
  2. package/README.md +177 -523
  3. package/bin/redweb.js +11 -20
  4. package/client.d.ts +7 -2
  5. package/config/tsconfig.json +14 -14
  6. package/contract.d.ts +45 -0
  7. package/contract.js +5 -0
  8. package/docs/ACTION_INPUT_VERIFICATION.md +96 -0
  9. package/docs/ADMISSION_TIMEOUT_VERIFICATION.md +69 -0
  10. package/docs/AGENT_ACCESS.md +35 -0
  11. package/docs/AGENT_EVALUATION.md +58 -0
  12. package/docs/AGENT_READY_ACCEPTANCE.md +763 -0
  13. package/docs/APPLICATION_RECORDER_VERIFICATION.md +50 -0
  14. package/docs/BENCHMARK_VERIFICATION.md +307 -0
  15. package/docs/BROWSER_OWNER_VERIFICATION.md +191 -0
  16. package/docs/CLI.md +116 -0
  17. package/docs/CLIENT_DEVELOPMENT.md +152 -0
  18. package/docs/CLIENT_POLISH_VERIFICATION.md +282 -0
  19. package/docs/COVERAGE_COUNTER_VALIDATION.md +109 -0
  20. package/docs/COVERAGE_SCOPE_AUDIT.md +1183 -0
  21. package/docs/DEVELOPMENT.md +79 -0
  22. package/docs/DIAGNOSTIC_COMPATIBILITY.md +76 -0
  23. package/docs/DOCUMENTATION.md +37 -0
  24. package/docs/FEEDBACK_COMMAND_VERIFICATION.md +228 -0
  25. package/docs/GETTING_STARTED.md +58 -0
  26. package/docs/JSX_PERFORMANCE_VERIFICATION.md +59 -0
  27. package/docs/LIVE_HTML.md +169 -21
  28. package/docs/LIVE_HTML_LOAD_VERIFICATION.md +98 -0
  29. package/docs/MIGRATION.md +28 -0
  30. package/docs/MULTIPLAYER_OPERATIONS.md +26 -4
  31. package/docs/ORIGINAL_RECOVERY_VERIFICATION.md +100 -0
  32. package/docs/PACKAGED_EXAMPLE_VERIFICATION.md +126 -0
  33. package/docs/POLISH_RELEASE_CHECKPOINT.md +91 -0
  34. package/docs/PROCESS_CLEANUP_OBSERVATION.md +61 -0
  35. package/docs/PROCESS_REAPING_VERIFICATION.md +30 -0
  36. package/docs/PRODUCTION_READINESS.md +11 -2
  37. package/docs/RECOVERY_CLIENT_HEAP.md +201 -0
  38. package/docs/RECOVERY_CODE_ATTRIBUTION.md +174 -0
  39. package/docs/RECOVERY_CODE_CENSUS.md +158 -0
  40. package/docs/RECOVERY_COMPARISON.md +103 -0
  41. package/docs/RECOVERY_DEOPTIMIZATION.md +169 -0
  42. package/docs/RECOVERY_FOLLOWUP_SPIKE.md +147 -0
  43. package/docs/RECOVERY_INVESTIGATION.md +229 -0
  44. package/docs/RECOVERY_RUNTIME_CONTROLS.md +181 -0
  45. package/docs/RELEASE_TRUST.md +58 -0
  46. package/docs/ROOM_AUTHORIZATION.md +49 -0
  47. package/docs/RUNTIME_DIAGNOSTICS.md +78 -0
  48. package/docs/SERVER_RECOVERY_CANDIDATE.md +185 -0
  49. package/docs/SOAK_ROTATION_OBSERVATION.md +160 -0
  50. package/docs/SOAK_VERIFICATION.md +154 -0
  51. package/docs/SOCKET_CONTRACTS.md +39 -0
  52. package/docs/SPLIT_RECOVERY_COVERAGE.md +83 -0
  53. package/docs/SPLIT_RECOVERY_ERROR_HANDLING.md +67 -0
  54. package/docs/STARTER_COORDINATOR_VERIFICATION.md +112 -0
  55. package/docs/STARTER_LIFECYCLE_VERIFICATION.md +75 -0
  56. package/docs/STARTER_REPORT_RETENTION.md +73 -0
  57. package/docs/VERIFICATION_EVIDENCE.md +2 -0
  58. package/docs/generated.json +2154 -0
  59. package/docs/guides/chatroom.md +27 -0
  60. package/docs/guides/http-websocket.md +28 -0
  61. package/docs/guides/jsx-without-react.md +26 -0
  62. package/docs/guides/realtime-dashboard.md +29 -0
  63. package/docs/guides/typed-websockets.md +26 -0
  64. package/docs/reference.json +1207 -0
  65. package/docs/snippets/room-access.tsx +51 -0
  66. package/docs/topics.json +21 -0
  67. package/examples/live-html/chatroom.js +207 -268
  68. package/examples/live-html/chatroom.tsx +167 -0
  69. package/examples/live-html/jsx-page.js +1 -1
  70. package/examples/live-html/jsx-page.tsx +1 -1
  71. package/examples/live-html/tsconfig.json +8 -7
  72. package/index.d.ts +170 -45
  73. package/index.js +2 -0
  74. package/jsx-dev-runtime.js +2 -2
  75. package/jsx-runtime.d.ts +7 -2
  76. package/package.json +88 -7
  77. package/recipes/add/artifact.test.cjs +57 -0
  78. package/recipes/add/live.tsx +18 -0
  79. package/recipes/add/socket-route.ts +24 -0
  80. package/recipes/chat/README.md +22 -0
  81. package/recipes/chat/app.test.cjs +105 -0
  82. package/recipes/chat/app.tsx +9 -0
  83. package/recipes/dashboard/README.md +43 -0
  84. package/recipes/dashboard/admin.ts +21 -0
  85. package/recipes/dashboard/app.css +16 -0
  86. package/recipes/dashboard/app.test.cjs +450 -0
  87. package/recipes/dashboard/app.tsx +86 -0
  88. package/recipes/dashboard/auth.ts +80 -0
  89. package/recipes/dashboard/cards.tsx +102 -0
  90. package/recipes/dashboard/rate-window.test.cjs +17 -0
  91. package/recipes/dashboard/store.ts +120 -0
  92. package/recipes/http-ws/README.md +11 -0
  93. package/recipes/http-ws/app.test.cjs +92 -0
  94. package/recipes/http-ws/app.tsx +36 -0
  95. package/recipes/realtime/README.md +8 -0
  96. package/recipes/realtime/app.test.cjs +15 -0
  97. package/recipes/realtime/app.tsx +28 -0
  98. package/recipes/shared/README.md +40 -0
  99. package/recipes/shared/app.css +8 -0
  100. package/recipes/shared/copy-assets.cjs +8 -0
  101. package/recipes/shared/network.cjs +59 -0
  102. package/recipes/shared/run-app.test.cjs +158 -0
  103. package/recipes/shared/run-app.ts +50 -0
  104. package/recipes/site/README.md +4 -0
  105. package/recipes/site/app.test.cjs +19 -0
  106. package/recipes/site/app.tsx +25 -0
  107. package/recipes/socket/README.md +39 -0
  108. package/recipes/socket/app.test.cjs +85 -0
  109. package/recipes/socket/app.tsx +30 -0
  110. package/recipes/socket/contract.ts +12 -0
  111. package/recipes/socket/handlers.ts +40 -0
  112. package/src/OwnedServerLifecycle.js +66 -0
  113. package/src/access/AccessPolicy.js +37 -0
  114. package/src/access/AuthenticationFailure.js +13 -0
  115. package/src/access/RequestFailure.js +33 -0
  116. package/src/access/failure-codes.json +25 -0
  117. package/src/async/BoundedOperation.js +62 -0
  118. package/src/cli/ActionReferences.js +193 -0
  119. package/src/cli/AdditionLayout.js +140 -0
  120. package/src/cli/FilePlan.js +94 -0
  121. package/src/cli/ProjectAddition.js +60 -0
  122. package/src/cli/ProjectConfig.js +26 -0
  123. package/src/cli/ProjectDoctor.js +112 -0
  124. package/src/cli/ProjectInitializer.js +20 -30
  125. package/src/cli/SourceInspector.js +207 -0
  126. package/src/cli/StaticSource.js +192 -0
  127. package/src/cli/arguments.js +62 -0
  128. package/src/cli/formatCommand.js +10 -0
  129. package/src/cli/run.js +57 -0
  130. package/src/cli/templates.js +86 -87
  131. package/src/context/RequestSnapshot.js +41 -0
  132. package/src/dataProperty.js +11 -0
  133. package/src/development/DevelopmentPageManager.js +48 -0
  134. package/src/development/Inspection.js +104 -0
  135. package/src/development/ObservedRenderer.js +42 -0
  136. package/src/development/description.js +35 -0
  137. package/src/development/loopbackRequest.js +27 -0
  138. package/src/development/refreshBrowser.js +96 -0
  139. package/src/development/refreshStyles.js +9 -0
  140. package/src/development/settings.js +17 -0
  141. package/src/docs/Documentation.js +182 -0
  142. package/src/htmx/ActionDefinition.js +44 -0
  143. package/src/htmx/Jsx.js +24 -8
  144. package/src/htmx/LiveHtmlServer.js +41 -19
  145. package/src/htmx/LivePage.js +63 -13
  146. package/src/htmx/PageIdentity.js +32 -0
  147. package/src/htmx/PageLifetime.js +37 -0
  148. package/src/htmx/PageManager.js +203 -74
  149. package/src/htmx/ReactiveRenderer.js +241 -0
  150. package/src/htmx/StaticExporter.js +1 -1
  151. package/src/htmx/TemplateRenderer.js +13 -7
  152. package/src/htmx/browserRuntime.js +2 -93
  153. package/src/htmx/metadata.js +19 -7
  154. package/src/validation/ActionInputError.js +12 -0
  155. package/src/validation/SchemaValidator.js +38 -0
  156. package/src/ws/AdmissionPolicy.js +24 -23
  157. package/src/ws/BaseSocketServer.js +53 -38
  158. package/src/ws/ContractValidationError.js +12 -0
  159. package/src/ws/HeartbeatMonitor.js +19 -7
  160. package/src/ws/ProtocolPolicy.js +1 -1
  161. package/src/ws/RoomAccess.js +82 -0
  162. package/src/ws/RoomRegistry.js +56 -6
  163. package/src/ws/RouteRuntime.js +56 -10
  164. package/src/ws/SocketContract.js +112 -0
  165. package/src/ws/SocketRoute.js +18 -0
  166. package/src/ws/protocol-schema.json +6 -1
  167. package/examples/live-html/chatroom.ts +0 -217
@@ -0,0 +1,126 @@
1
+ # Packaged-example verification
2
+
3
+ The installed-example probe now bounds listening, upgrade and action waits,
4
+ owns its socket immediately, and attempts socket closure and application shutdown
5
+ independently. Malformed responses, premature closes, send errors and timeouts
6
+ fail the action with their cause preserved. All action listeners and its timer
7
+ are removed on settlement. Success is printed only after confirmed cleanup.
8
+ The counter's development-route 404 body is consumed as well.
9
+
10
+ This changes verification tooling, not Redweb's public API or application runtime.
11
+ The original acceptance assertions remain: a production-only counter without
12
+ TypeScript or Zod; chat after explicit application Zod installation; actual chat
13
+ join, sanitized inspection, development revision/JS/CSS resources; exact emitted
14
+ client bytes; and generated page/component/socket-route compilation and tests.
15
+
16
+ ## Isolation and ownership
17
+
18
+ The verifier copies the existing realtime harness, error normalizer and frozen
19
+ network helper unchanged, alongside the guarded action helper, into a child
20
+ support directory. Its WebSocket dependency is resolved from the installed
21
+ Redweb package and linked only after checking its real path stays inside this
22
+ consumer. The probe additionally checks transport identity. No repository
23
+ dependency is substituted into the package, and the support directory is not
24
+ an ancestor of the probe: it cannot satisfy the probe's absent-TypeScript/Zod
25
+ checks. Each install refreshes the owned transport link; a replaced regular
26
+ file is rejected, not deleted. Client identity is checked before and after
27
+ the complete consumer flow.
28
+
29
+ Commands reject truncated output. Each probe has a 90-second parent deadline;
30
+ other install/compiler/generated-test commands retain 120 seconds. The existing
31
+ workspace owner supervises processes and removes only its disposable consumer.
32
+
33
+ ## Evidence
34
+
35
+ `npm run verify:package:examples:coverage` passed **40 tests / five suites** in
36
+ 25.259 seconds on Windows / Node 22.21.0. The three-script original-source scope
37
+ is 100%: 178 statements, 44 branches, 20 functions and 150 lines.
38
+
39
+ Explicit unit fault boundaries cover action protocol/timing, coordinator cleanup,
40
+ preflight and installed dependency resolution/link tampering. The copied entrypoint
41
+ is evaluated unchanged with original-source Istanbul instrumentation. Its private
42
+ VM map joins the report only when that file is explicitly selected by the maintained
43
+ coverage command; it does not enlarge the ordinary library denominator.
44
+
45
+ No-mock integration uses actual WebSocket peers for success, unrelated frames,
46
+ malformed data, incorrect results, close and silent timeout. A separate installed
47
+ consumer packs the current source, runs real npm installs, HTTP/WebSockets and
48
+ development resources, then compiles and executes all three generated additions.
49
+ The first local installation timed out after certificate-chain verification failed;
50
+ it cleaned up and was not counted as passing. Using Node's supported
51
+ `--use-system-ca` option succeeded without disabling TLS verification.
52
+
53
+ The senior critic identified two test defects: cleanup could skip server closure,
54
+ and VM coverage could pollute the library denominator. Both were corrected before
55
+ the maintained successful run. CI retains the scoped report for 30 days and
56
+ allows 30 minutes for all bounded install/verification phases.
57
+
58
+ Source SHA-256 identities:
59
+
60
+ - `scripts/lib/example-dependency-probe.cjs`: `3a2b575129544e5497f44fd5e0f0ab574bc4da13ed560219b0f8f1d830b49547`
61
+ - `scripts/lib/performProbeAction.js`: `21dbbe345657b528b62464bb6e4ffef0f4ac8fe7be46a0fa3e7805c5ee67fd98`
62
+ - `scripts/lib/verify-example-dependencies.js`: `fd99d93475fcfbf228564b49bf8fd771e76f9f71bc0faa2f26d2b19d8c6fbbab`
63
+
64
+ Report `coverage/example-dependency-tools/coverage-final.json` SHA-256:
65
+ `51729c6f8604ad0a0b1f4e5c3d71688b75f833d3cb6b78155c7dc769cdc14c17`.
66
+
67
+ This is not whole-repository 100%, a new one-hour soak, a benchmark waiver or a
68
+ release approval. The full package/regression/hosted outcomes are recorded
69
+ separately as they complete. No publication, deployment or merge is implied.
70
+
71
+ The full `verify:live-html:package` gate also passed: isolated registry client
72
+ 0.2.0, actual counter/chat/reconnect/disconnect browser acceptance, all-four 100%
73
+ emitted runtime and refresh browser coverage, every packaged starter, compiled
74
+ documentation/action/room examples, generated additions and static/JSX export.
75
+ The checked archive SHA-256 was
76
+ `739567465bb18a3bf3df9771c84b57f56f503769527ed9c90d96c59a76cd97c1`;
77
+ its retained browser report is
78
+ `coverage/packed-browser/f91d60fd-dffd-4c6e-806f-c8615ecc687c/`.
79
+ That archive preceded this explanatory document; it is runtime/tool behavior
80
+ evidence, not a byte identity claim about a later documentation-bearing tarball.
81
+
82
+ ## Complete increment checkpoint
83
+
84
+ The complete local regression of the source set committed in `449a369` and
85
+ `551a905` passed **1,292 tests / 126 suites** in 690.807 seconds, with two
86
+ POSIX-only skips. Generated documentation, example/protocol snapshots and all
87
+ three TypeScript configurations passed. The ordinary coverage map contains
88
+ exactly the unchanged 91 library files: 5,449 statements, 4,046 branches,
89
+ 978 functions and 4,468 lines, all 100%. Private probe instrumentation did not
90
+ enter that denominator.
91
+
92
+ Full map `coverage/coverage-final.json` SHA-256:
93
+ `c21b602f7d66b6105fa53a7ba0a5eb879d4b75e7ee560c8869beebdbee20f051`.
94
+ Inventory `coverage/example-dependency-full-results.json` SHA-256:
95
+ `8e2612d78a30ee3ce3bf28201e222bbfff9da21d599c1bff2556a904fa304a24`.
96
+
97
+ Sequential clean checks after regression passed on Windows / Node 22.21.0:
98
+
99
+ - Default socket load: 32 clients, 3,200 messages, 6,486.03 messages/second,
100
+ p99 7.2315 ms, slow consumer contained.
101
+ - Memory: 500 connections, three trials, 1,881.744 bytes of measured framework
102
+ metadata per connection against the unchanged 2,048-byte limit.
103
+ - HTML load: 200 expired renders, 110 live clients, 7,501,568-byte heap delta.
104
+ - JSX: 10,000 component rows, 52.5 ms, 0.6 MiB retained.
105
+ - Server-focused recovery: `server-steady-v1`, all 7,400 replies exact,
106
+ all server phases passing (highest 108.4196% of warm). The retained client
107
+ diagnostic exceeded 110% in later phases; this is not a client-memory fix.
108
+ - Thirty-second / 16-client soak: 4,368 sent, 4,363 received, five missing,
109
+ 99.88553114% delivery, seven samples, all eight trends passing, final registries
110
+ zero, final heap 99.909556% of warm, handles 1→2. Not lossless or an hour soak.
111
+ - Production dependency audit: zero reported vulnerabilities, with certificate
112
+ validation retained through the Windows trusted certificate store.
113
+
114
+ Recovery report `coverage/server-recovery-package-final-20260831/report.json`
115
+ SHA-256: `071e98324524586cd8c8c50b35b68d5623f2f179e1e436076da62d7031055465`.
116
+ Soak report `coverage/soak-package-final-20260831.json` SHA-256:
117
+ `4bd8bd5e95054da8c27f1236ca42335663fde6e303c3a850db3e4a684079b371`.
118
+
119
+ The senior critic approved all 18 actual changed remote blobs at `551a905`, with
120
+ no remaining scoped finding. Both [PR CI](https://github.com/lakam99/redweb/actions/runs/33373452034)
121
+ and [push CI](https://github.com/lakam99/redweb/actions/runs/33373448945) passed
122
+ every Node 18/20/22/24 and lifecycle/package/browser job at that head. These are
123
+ implementation-head outcomes, not claims about a later evidence-only commit.
124
+ The npm links and frozen files remain unchanged. The historical room-phase
125
+ failure, unresolved throughput benchmark, remaining private-tool coverage and
126
+ publication/site alignment remain separately recorded release work.
@@ -0,0 +1,91 @@
1
+ # Release-polish checkpoint
2
+
3
+ This document preserves the historical `3166468` checkpoint, including its failed
4
+ CI result. It is not the current release decision: the server-focused recovery
5
+ gate was subsequently adopted, while the original measurement remains a visible
6
+ non-blocking diagnostic. See [the reviewed recovery policy](SERVER_RECOVERY_CANDIDATE.md)
7
+ and [the current acceptance checklist](AGENT_READY_ACCEPTANCE.md) for later work
8
+ and remaining gates. The historical failure below is not relabelled as resolved.
9
+
10
+ These are verified checkpoints, not release approval. Redweb's runtime at
11
+ `3166468` was tested with published `redweb-client@0.2.0` on Windows,
12
+ Node 22.21.0 and Chrome 152.0.7977.64. Later candidate-verifier development changes
13
+ private tooling only; it is not claimed covered by these earlier checks.
14
+
15
+ ## Current package and resources
16
+
17
+ The full clean registry package gate passed: actual counter/chat/dashboard browser
18
+ acceptance, reconnect/disconnect, six starters, executable recipes and source-free
19
+ consumers. It used no client override or consumer link. All 192 original package
20
+ files, 23 harness files and four explicitly external development tools passed
21
+ identity checks.
22
+
23
+ - Redweb archive SHA-256:
24
+ `f9bb0230becb7d1ab29e36a24ab9c35362d70e790bff3a9f3b064f9cb9b49439`.
25
+ - Report: `coverage/packed-browser/a03b7840-905c-4718-8f52-701d5fbd955c/report.json`.
26
+ - Report SHA-256:
27
+ `8c4c051b034998a9ad537c1240600e9b434402a296fd7cdabc69244071a9b0e4`.
28
+ - Frontend run `b71d6f8a-fc4a-4b7f-b61d-207274883b12`: all-four 100% over
29
+ 426 statements, 262 branches, 64 functions and 351 lines.
30
+ - Refresh run `ac9073e4-c2a2-4baa-b6f1-4552a38c526f`: all-four 100% over
31
+ 82 statements, 44 branches, 12 functions and 71 lines; actual bfcache restoration.
32
+
33
+ After package and site tests terminated, the unchanged resource gates ran
34
+ sequentially without inherited workload or instrumentation overrides:
35
+
36
+ | Gate | Observed result |
37
+ | --- | --- |
38
+ | Socket load | 32 clients, 3,200 messages; 6,686.50 messages/s, p99 7.233 ms; slow consumer contained |
39
+ | Metadata overhead | Three 500-client trials; 1,880.752 bytes/connection against 2,048 limit |
40
+ | Live HTML load | 200 expired renders, 110 clients; 8,080,280-byte heap delta |
41
+ | JSX rendering | 10,000 component rows in 49.2 ms; 1.3 MiB retained |
42
+ | Production audit | Zero reported vulnerabilities; TLS verification retained |
43
+
44
+ ## Full 60-minute soak
45
+
46
+ One default run began at 2026-08-31T01:41:14Z. Its original owned terminal session
47
+ completed with exit 0; the resulting file was independently checked against all
48
+ delivery, registry, trend, heap and handle predicates. No competing local
49
+ load/browser/test run was started during the measurement. Runtime source and the
50
+ soak script were unchanged; candidate tooling edits do not enter the soak process.
51
+
52
+ - 3,600 seconds, 64 clients, 720 samples.
53
+ - 2,104,941 messages sent; 2,104,808 received: **99.9936815% delivery** against
54
+ the existing 99% requirement. This is not lossless delivery: 133 replies were
55
+ not received during rotating-connection traffic.
56
+ - Warm heap 11,378,888 bytes; peak 11,918,736; final 11,296,552:
57
+ **99.276414%** of warm, below 110%.
58
+ - All final client/room/session/in-flight registries empty. All eight resource
59
+ trend predicates passed. Handles moved from one to two, within the allowed one.
60
+ - Result: `coverage/polish-soak-3166468-20260831.json`, SHA-256
61
+ `f402a73e26f207fb5e55b53365912169350bba2fad0bb33d4856719db6df49c3`.
62
+ - Script SHA-256:
63
+ `ce30f8abcda0e018b8c586bd53dba775aebdaaaaf5275aa8bdf2b2f8d9b1d22b`.
64
+
65
+ ## Historical CI failure at `3166468`
66
+
67
+ At the same `3166468` revision, the
68
+ [push run](https://github.com/lakam99/redweb/actions/runs/33347952379) passed
69
+ all jobs. The [PR run](https://github.com/lakam99/redweb/actions/runs/33347954450)
70
+ passed Node 18/20/24 and lifecycle checks but failed Node 22 recovery. Its unit and
71
+ integration suites passed first: 83 suites, 858 passing tests and five existing
72
+ platform skips, with all-four 100% instrumented-library coverage.
73
+
74
+ PR storm 3 peaked at **110.111615%**, above the unchanged 110% limit; final heap
75
+ was 98.786034% with empty registries. The push Node 22 peak was 109.607980%.
76
+ Neither final cleanup, the green push run nor the long-soak pass waives this
77
+ failure. No selective rerun occurred. The senior critic independently verified
78
+ the CI and package evidence.
79
+
80
+ The local documentation site imports the same canonical source at commit
81
+ `6b528f1`: 98 pages, 154 assets, real HTTP/link/download and filesystem-rollback
82
+ checks, six documentation tests with 100% line/branch/function coverage across
83
+ its seven declared modules. Catalogue SHA-256:
84
+ `8b4d805a7f845af30175423eebc4da610e579b9a51a74ccd8e6f56a5e0d4fa73`.
85
+ This is not whole-site coverage or a hosting deployment.
86
+
87
+ At this checkpoint, the maintainer had authorized development/review of a
88
+ server-focused candidate, not yet its adoption. Its protocol and results required
89
+ separate assessment.
90
+ Redweb publication, released-site alignment, final requirement audit and merge
91
+ remain pending. The original gate and failed results remain intact.
@@ -0,0 +1,61 @@
1
+ # Starter cleanup: unresolved CI observation
2
+
3
+ The [Node 20 push job for 08348fb](https://github.com/lakam99/redweb/actions/runs/33403291226/job/99524600675)
4
+ failed the immediate descendant-disappearance assertion in
5
+ `tests/integration/starter-verifier.integration.test.js`: signal zero did not
6
+ throw. Ubuntu 24.04.4 / Node 20.20.2 / npm 10.8.2 reported 1,530 passed,
7
+ one failed and six skipped tests. Its other three matrix jobs passed; the
8
+ separate PR workflow passed completely. Neither result waives this failure.
9
+
10
+ Independent inspection found that the frozen process-tree helper signals the
11
+ Linux group but awaits only the direct child's exit. The workspace owner also
12
+ waits for that child's close; the descendant has ignored stdio, so this does not
13
+ establish descendant disappearance. Signal zero checks PID existence, and a
14
+ terminated but unreaped process can still exist. That makes an exit/reaping race
15
+ plausible, not proven for this run. A surviving process or reused PID remains
16
+ possible. See the primary [kill semantics](https://man7.org/linux/man-pages/man2/kill.2.html)
17
+ and [wait/reaping semantics](https://man7.org/linux/man-pages/man2/wait.2.html).
18
+
19
+ The old log lacks process state and start identity. Its fallback sends another
20
+ signal before waiting, so successful fallback is not proof that original cleanup
21
+ alone succeeded. The test now also requires the captured command error to be
22
+ the actual timeout, not merely contain the fixture's output marker.
23
+
24
+ The diagnostic-enabled ordinary Node 20 CI execution retains the existing immediate assertion,
25
+ two-second command limit and five-second fallback limit. The fixture records
26
+ initial process identities. If an assertion fails, it samples descendant and
27
+ group-leader identity **before the fallback signal**, appends the command
28
+ error/cause and observations to the thrown error, and preserves them if fallback
29
+ also fails. No additional acceptance wait or successful-run retry is added.
30
+
31
+ A separate Linux-only negative control deliberately puts its owned descendant
32
+ in a different process group. It requires the unchanged immediate assertion to
33
+ fail, verifies that the diagnostic identifies the live escaped process and its
34
+ unchanged start identity, then confirms that the existing fallback terminated it.
35
+ This is not a reproduction of the original failure or permission to accept escape.
36
+ It must fail specifically at the immediate disappearance assertion and must not
37
+ return an aggregate fallback failure. Independent review caught that accepting
38
+ any error would have allowed a failed fallback to masquerade as a passed control.
39
+ Observation-read errors are recorded separately from the original command error;
40
+ a real malformed-file test verifies that they cannot replace the timeout evidence.
41
+
42
+ The helper retains only PID, state, parent/group/session IDs, process start ticks,
43
+ platform and observation time. It excludes command names, arguments and
44
+ environment. Start ticks remain text, avoiding integer precision loss. Field
45
+ positions follow [proc_pid_stat](https://man7.org/linux/man-pages/man5/proc_pid_stat.5.html).
46
+ Unsupported platforms and failed reads are explicit. A post-assertion snapshot
47
+ is not the process state at the exact failing instant; a later `ENOENT` or a
48
+ passing run is inconclusive. Direct-root exit/signal timestamps are still absent.
49
+
50
+ Local Windows tests exercise parsing and the real npm descendant workflow, but
51
+ cannot reproduce Linux reaping or validate the native `/proc` branch. The local
52
+ Docker Linux engine was unavailable; it was not started or reconfigured.
53
+ The final Windows run passed 21 tests with the one Linux-only negative control
54
+ skipped (7.439 seconds). Both [PR](https://github.com/lakam99/redweb/actions/runs/33406107275)
55
+ and [push](https://github.com/lakam99/redweb/actions/runs/33406101028) workflows
56
+ for `4fe0145` subsequently passed all jobs. The actual Node 20.20.2 push job
57
+ passed 1,573 tests with seven platform skips in 823.853 seconds, including the
58
+ Linux escaped-child negative control and malformed-observation regression.
59
+ This validates the diagnostic on Linux, not the cause of the original failure.
60
+ Frozen helpers/evaluation evidence, runtime code and acceptance thresholds remain
61
+ unchanged. No cause or fix for the original CI failure is claimed yet.
@@ -0,0 +1,30 @@
1
+ # Descendant-reaping test synchronization
2
+
3
+ PR CI at `d24d734`, [run 33353677136, Node 22 job
4
+ 99371666483](https://github.com/lakam99/redweb/actions/runs/33353677136/job/99371666483),
5
+ failed one test: the descendant PID was still addressable immediately after a
6
+ timed-out build returned. The job passed 915 tests, skipped five platform-specific
7
+ cases and failed one; library coverage remained all-four 100%. Its recovery step
8
+ was correctly skipped, not counted as passed. Other matrix and lifecycle jobs passed.
9
+
10
+ The frozen process helper sends a process-group kill on POSIX and awaits the root
11
+ process exit. That event does not notify the test that every descendant has been
12
+ reaped. Linux's [kill(2)](https://man7.org/linux/man-pages/man2/kill.2.html) and
13
+ [wait(2)](https://man7.org/linux/man-pages/man2/waitpid.2.html) documentation explain
14
+ that an exited process can retain a visible PID until reaping. The failed log
15
+ does not establish whether that PID was running, dying, a zombie, or reused; the
16
+ historical failure is not relabelled as proven harmless.
17
+
18
+ The three descendant checks now reuse the existing bounded condition observer.
19
+ They require actual `ESRCH` within five seconds, preserve the final strict
20
+ process-existence assertion, and reject every other error. The observer neither
21
+ sends a signal nor treats zombies as absent. A new real-process negative control
22
+ proves a live survivor times out and remains alive until the test's separate
23
+ owner explicitly stops it. Original build/cleanup deadlines and frozen helpers
24
+ are unchanged; outer test deadlines now cover the sum of the existing phases
25
+ plus the bounded observation.
26
+
27
+ All eight actual-process tests passed locally on Windows/Node 22.21.0 in 4.84
28
+ seconds. Linux verification follows through ordinary CI, not selective retries.
29
+ The senior critic approved the synchronization contract and negative control;
30
+ this is a test correction, not a server recovery-policy or runtime change.
@@ -20,6 +20,13 @@ WebSocket provides an ordered byte stream while a connection remains healthy. Re
20
20
  ## Roadmap gates
21
21
 
22
22
  1. **Bounded transport:** pre-upgrade admission, origin policy, rate limits, slow-consumer enforcement, bounded ordered processing, payload limits, and route-level heartbeat.
23
+
24
+ Heartbeat expiry is deferred to the event-loop check phase before terminating a
25
+ peer, allowing already-dispatched pong handling to win after a server stall; an
26
+ actually silent peer is terminated by the deferred check.
27
+ `timeoutMs` is therefore a liveness threshold subject to event-loop scheduling,
28
+ not a hard wall-clock resource limit. The deferral owns at most one pending check
29
+ per expired connection; bound connections and queues independently.
23
30
  2. **Multiplayer grouping:** route-scoped rooms, atomic membership cleanup, bounded session resumption, fixed-step services, and vendor-neutral metrics.
24
31
  3. **Horizontal composition:** draining/readiness, adapter lifecycle, loop prevention, bounded validation, placement hooks, and documented partition behavior.
25
32
  4. **Protocol and clients:** version negotiation, stable envelopes and error codes, generated client-facing types, binary replication hooks, and operational examples.
@@ -35,11 +42,13 @@ WebSocket provides an ordered byte stream while a connection remains healthy. Re
35
42
  - Broadcast serializes once and remains O(n) in selected recipients.
36
43
  - Slow clients cannot grow framework-owned memory without bound.
37
44
  - A 60-minute soak shows no monotonic growth in timers, listeners, rooms, sessions, or queues.
38
- - Reconnect storms return retained heap to within 10% of the warmed baseline after expiry and forced collection.
45
+ - The blocking `server-steady-v1` reconnect gate requires every storm to retain at most 110% of the same warmed **server** heap after expiry and forced collection. Exact delivery, empty measured registries, unchanged inputs, complete logs and normal worker cleanup are mandatory. Client heap is reported separately; the original shared-process diagnostic remains visible and non-blocking, without relabelling its failures.
39
46
  - Readiness becomes false before draining and shutdown completes within its documented bound.
40
47
 
41
48
  The independent senior-review gate rejects releases that weaken any invariant, hide ambiguous delivery semantics, add mandatory brokers or identity libraries, or substitute coverage percentages for race, load, soak, and failure evidence.
42
49
 
50
+ See [operations verification](MULTIPLAYER_OPERATIONS.md#verification) for the current commands and the distinction between server acceptance and the original diagnostic. These are required gates, not a statement that the current development candidate has passed them; consult the [release checklist](AGENT_READY_ACCEPTANCE.md) for outstanding failures.
51
+
43
52
  ## Horizontal composition contract
44
53
 
45
54
  - Placement runs before upgrade within the admission timeout. Redirects must use `wss`, contain no credentials or fragment, and may be restricted with `allowedPlacementOrigins`. Plain `ws` placement requires the explicit `allowInsecurePlacement` escape hatch for private development networks.
@@ -65,4 +74,4 @@ The independent senior-review gate rejects releases that weaken any invariant, h
65
74
  - Timed-out admission hooks that ignore cancellation retain their reservation until they actually settle, preventing repeated timeout waves from accumulating unbounded application work.
66
75
  - Fixed-step services clamp retained lag with `maxRetainedLagMs`; dropped time is observable rather than replayed forever.
67
76
  - Session count, ID length, and lifetime are bounded by Redweb. Session `data` is application-owned, so applications must validate and cap its shape and byte size before storing it.
68
- - Fully enabled idle routes have a 2 KiB framework-metadata budget per connection. Disabled features retain the legacy path and are compared against 0.8 by the performance gate.
77
+ - Fully enabled idle routes have a 2 KiB framework-metadata budget per connection. Disabled features retain the legacy path; the performance gate compares against an explicitly prepared, identified release baseline. Historical 0.8 evidence does not establish performance against a newer baseline.
@@ -0,0 +1,201 @@
1
+ # Client heap survival investigation — 2026-08-30
2
+
3
+ Status: surviving code-related structures identified in the instrumented client;
4
+ the original recovery acceptance gate remains open. This follows the
5
+ [deoptimization investigation](RECOVERY_DEOPTIMIZATION.md).
6
+
7
+ ## Predeclared method
8
+
9
+ One measured run after tests and senior critic preflight:
10
+
11
+ ```sh
12
+ node scripts/diagnostics/recovery-split.cjs client-heap
13
+ ```
14
+
15
+ The existing seven-phase, 7,400-connection split workload is unchanged. Both workers
16
+ retain normal `--expose-gc` flags; no compilation/deoptimization logger or coverage
17
+ is enabled. Only the native `ws` client captures snapshots, through separate RPCs
18
+ after its warm and storm-5 samples have returned. Server and client measurements
19
+ precede capture; the later workload therefore observes the warm snapshot's effects.
20
+ The client still does not import Redweb or redweb-client. No concurrent tests run
21
+ during measurement, and no rerun is selected because its memory result is greener.
22
+
23
+ [Node's pinned V8 API](https://nodejs.org/download/release/v22.21.0/docs/api/v8.html)
24
+ warns that snapshot generation blocks execution and may need roughly twice the
25
+ heap's memory. Its format is undocumented and version-specific. The analyzer is
26
+ pinned to Node 22.21.0 / V8 12.4.254.21-node.33. Snapshot capture initiates collection;
27
+ [Chrome's snapshot documentation](https://developer.chrome.com/docs/devtools/memory-problems/heap-snapshots)
28
+ distinguishes comparison, containment, shallow sizes and retained sizes. Our
29
+ comparison reports shallow bytes and graph paths, **not** dominators or retained size.
30
+
31
+ ## Capture and analysis safeguards
32
+
33
+ - Raw snapshots stay in a newly created local temporary directory, outside the
34
+ repository. They may contain secrets; do not upload or commit them. Unix permissions
35
+ are restricted to the owner; Windows uses the current user's inherited temporary
36
+ directory ACL (the Unix mode is not an independent Windows privacy guarantee).
37
+ - Files are opened exclusively before capture and limited to 64 MiB of saved data.
38
+ Partial/failed captures invalidate the run and cannot be reused. This limit does
39
+ not bound native generation memory or its pause; the coordinator has a 60-second
40
+ capture deadline and owns child termination/cleanup.
41
+ - Both captures must have the same worker-generated UUID/PID identity, runtime,
42
+ ordered phases and verified SHA-256/file lengths. Snapshots are parsed offline,
43
+ after the workers exit, not inside the measured client.
44
+ - The existing validated graph parser is shared with the earlier marker-based
45
+ analyzer. Parsing is capped at 250,000 nodes and 1,500,000 edges per snapshot.
46
+ - A single breadth-first search starts at the validated synthetic root, excluding
47
+ weak and shortcut edges. Paths use only fixed category labels and edge kinds;
48
+ arbitrary function/property names, node IDs, addresses and contents are withheld.
49
+ Paths over 32 edges are explicitly truncated; unreachable nodes remain counted.
50
+ These are shortest paths in the filtered snapshot graph, not unique ownership
51
+ proofs or a complete interpretation of ephemeron/engine retention semantics.
52
+ - Added, removed and surviving IDs are separated. Survivor bytes/counts before and
53
+ after are both included, so size/category changes reconcile with gross deltas.
54
+ The final public comparison is bounded to 1 MiB; errors are redacted. Complete
55
+ category/cohort/path-status totals are retained; at most 128 detailed path groups
56
+ are shown, prioritizing added objects then descending shallow bytes. Omitted
57
+ group counts are explicit. These examples are not representative statistics.
58
+
59
+ This run can show which code-related objects survive in a snapshot-instrumented
60
+ client. It cannot identify the earlier run's exact surviving compiled versions,
61
+ equate instruction sizes with snapshot self sizes, or explain every byte of the
62
+ original shared-process recovery failure. No code amount is subtracted from heap
63
+ usage to manufacture acceptance.
64
+
65
+ ## Verification before measurement
66
+
67
+ Sixteen focused unit and real snapshot/process/network tests pass. Native V8
68
+ coverage is 100% statements, branches, functions and lines across all five snapshot
69
+ capture/parser/analysis modules. Real integration tests use no mocks, check exact
70
+ request/reply IDs, exercise two captures in one worker, verify reusable listener
71
+ ports, reject altered identities/versions/lengths/hashes, enforce the capture size
72
+ limit, and preserve an existing file on overwrite attempts. Synthetic graph tests
73
+ cover cycles, weak/shortcut-only reachability, truncated paths and survivor changes.
74
+ The preexisting broader coordinator coverage gaps are not claimed closed by this
75
+ focused result.
76
+
77
+ ## Original run and offline repair
78
+
79
+ Exactly one workload was run, at tooling commit `4d036b4`, from
80
+ 20:37:09.177Z to 20:37:23.539Z. It reached the post-worker-cleanup comparison stage
81
+ after all 7,400 exact acknowledgements and empty client/server registries at every
82
+ sample. All four output logs were complete and empty. Source hashes were checked.
83
+
84
+ The run nevertheless **exited 1**: the initial detailed comparison was 1,391,590
85
+ bytes, exceeding the 1 MiB output cap. Its original report remains unchanged with
86
+ `deliveryAndCleanupPassed: false`. This is a failed diagnostic, not a release pass.
87
+
88
+ The correction at `bd68503` bounds detailed examples while preserving complete
89
+ numeric totals. Its new 3,000-path fixture checks omission accounting and output
90
+ size; a real CLI test checks provenance, redacted errors and overwrite refusal.
91
+ The same existing snapshots were reanalyzed offline, without another workload or
92
+ snapshot capture. Native coverage after the correction passed 17 tests and all-four
93
+ 100% across the five snapshot modules. The senior critic independently reproduced
94
+ the reanalysis and verified hashes, reconciliation, omission counts and path totals.
95
+
96
+ Reproduction uses a new output file; it never overwrites the original report:
97
+
98
+ ```sh
99
+ node scripts/diagnostics/HeapCodeComparison.cjs <original-report.json> <private-snapshot-directory> <new-summary.json>
100
+ ```
101
+
102
+ ## What survived
103
+
104
+ The snapshots contain 77,725 then 80,910 nodes: 4,771 added IDs, 1,586 removed IDs,
105
+ and 76,139 surviving IDs. Net snapshot shallow bytes increased by 937,387. The
106
+ complete V8 `code` category increased by 801,792 shallow bytes; it includes several
107
+ different kinds of internal data, not just executable instructions.
108
+
109
+ | Code-related category | Net shallow bytes |
110
+ | --- | ---: |
111
+ | Remaining unclassified code nodes | +543,408 |
112
+ | Deoptimization data | +113,880 |
113
+ | Relocation information | +91,608 |
114
+ | Bytecode arrays | +19,064 |
115
+ | Generic code objects | +14,520 |
116
+ | Feedback vectors | +9,928 |
117
+ | Constant pools | +7,440 |
118
+ | Feedback cells | +2,184 |
119
+ | Uncompiled data, combined | −240 |
120
+
121
+ These labels follow fixed tags in the pinned
122
+ [V8 snapshot generator](https://github.com/nodejs/node/blob/v22.21.0/deps/v8/src/profiler/heap-snapshot-generator.cc).
123
+ Unrecognized names remain unclassified. The other major net category was hidden
124
+ runtime data (+122,672 shallow bytes). These are distinct snapshot categories;
125
+ they must not be added to overlapping `getHeapCodeStatistics()` measurements.
126
+
127
+ There were no WebSocket, Sender, Receiver or Timeout instances in either snapshot.
128
+ All three Socket instances and all 51 HTTPParser instances survived unchanged,
129
+ with no additions. That narrows the evidence away from accumulating connection
130
+ instances in this client; it does not establish that every retained object is benign.
131
+
132
+ All 33,449 final code nodes are included in path totals: 33,441 have a path from the
133
+ root in the filtered graph; eight surviving nodes (512 shallow bytes) do not.
134
+ No path was depth-truncated. The 2,802 grouped paths yield 128 detailed examples
135
+ and 2,674 explicitly omitted groups. Some examples run through global handles,
136
+ closures and code objects; others include a Socket. A shortest path is neither a
137
+ unique owner nor evidence that such a Socket is a leftover workload connection.
138
+
139
+ ## Observer effects and remaining causal question
140
+
141
+ | Phase | Server heap bytes | Client heap bytes |
142
+ | --- | ---: | ---: |
143
+ | Preconditioning | 10,176,480 | 6,596,520 |
144
+ | Warm, before first capture | 10,195,968 | 6,567,568 |
145
+ | Storm 1 | 10,480,392 | 7,498,024 |
146
+ | Storm 2 | 10,873,856 | 7,831,056 |
147
+ | Storm 3 | 10,965,904 | 8,014,120 |
148
+ | Storm 4 | 11,055,136 | 8,040,528 |
149
+ | Storm 5, before final capture | 9,925,432 | 8,054,112 |
150
+
151
+ Client heap growth was 1,486,544 bytes (122.63% of warm), while code/metadata
152
+ statistics grew by 534,410 bytes. Bytecode/metadata statistics changed from
153
+ 758,616 to 666,216 after the warm snapshot. These readings are before capture,
154
+ whereas the snapshot inventories are collected during capture, with extra GC and
155
+ diagnostic machinery. The unequal deltas must not be treated as a missing-byte
156
+ equation or used to claim the original unsnapshotted growth is fully explained.
157
+
158
+ The next useful step requires **no new workload**: attribute the largest added
159
+ code/deoptimization groups to known Node, ws and harness functions through narrowly
160
+ allowlisted structural relationships in these snapshots. Distinguish module/cache
161
+ roots and standard-stream sockets from workload connections. This milestone does
162
+ not identify the exact earlier invalidated versions, prove exclusive retention,
163
+ explain all hidden data, or resolve the original recovery failure or historical
164
+ shutdown timeout. No speculative production optimization or acceptance change was made.
165
+
166
+ Follow-through: [offline function and root attribution](RECOVERY_CODE_ATTRIBUTION.md)
167
+ now records that analysis of the same snapshots, including persistent function
168
+ identities and all three standard-stream/prototype Socket roles. The original
169
+ capture and verification evidence below remains unchanged.
170
+
171
+ ## Evidence identity
172
+
173
+ - Original local run: `coverage/recovery-split-f7owK8`.
174
+ - Original report SHA-256: `1b894777de9ec50f53faa7e66f144bfe4feb89793ae1bfe068365000833acbe7`.
175
+ - Warm snapshot: 7,512,482 bytes; SHA-256 `339a0fe74d9bb942c64a5514975b2918376004436125ca8af169ccdc86dfdaa3`.
176
+ - Final snapshot: 7,796,848 bytes; SHA-256 `7e494dbe82222c4045d673d5bd1cf79a953708025219ebb632fcaf0fdb59576d`.
177
+ - Separate offline report: `heap-reanalysis.json`, 88,196 bytes; SHA-256 `f3904afc8ee5786fec862737404f69ba1076cd46c8f828a5d530781c7dc64aa9`.
178
+ - Offline analyzer SHA-256: `afa8981ec976a6a9405207f4297257c518483941c919b2d3f0ffd868b3155392`.
179
+
180
+ The offline report includes the original report hash, unchanged failure status and
181
+ all analyzer input hashes. Raw snapshots remain private and local; no publication,
182
+ deployment, dependency change, npm-link change or merge occurred.
183
+
184
+ ## Final verification
185
+
186
+ At implementation commit `bd68503`, the full suite passed **841 tests in 81 suites**
187
+ in 435.006 seconds, including the owned-HTTP-shutdown test. Pretest documentation,
188
+ generated examples/protocol types and all three TypeScript configurations passed.
189
+ The historical shutdown timeout is still unexplained, not waived by this pass.
190
+
191
+ Instrumented-library coverage remains all-four 100%: 5,445 statements, 4,044 branches
192
+ and 978 functions, none uncovered. The separate untransformed native snapshot-tool
193
+ run passed 17 tests with all-four 100% across `ClientHeapCapture`, `HeapSnapshotGraph`,
194
+ `HeapCodeComparison`, `recovery-heap-graph` and `recovery-heap-summary`, including the
195
+ offline CLI. Broader split-coordinator/worker coverage gaps remain outside that
196
+ five-module claim. No threshold was lowered or uncovered code excluded to obtain it.
197
+
198
+ - Full-suite JSON: `coverage/client-heap-full-suite.json`; SHA-256
199
+ `bb49cab38666d8d60c879aa970fcf44df494d7d900d5152548266662eea5d1cc`.
200
+ - Native snapshot-tool coverage JSON: `coverage/client-heap-native/coverage-final.json`;
201
+ SHA-256 `f90cdb7ce7e02d611f8c88d1fc3e224803f3dc57c51bba184969be880136a886`.