mirror of
https://github.com/morluto/rea.git
synced 2026-11-14 18:52:48 +00:00
583bb477c16eefefbefb0c7ee2144096aca61b29
2
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
b138f52e12 |
refactor: prune internal seams and preserve configuration ownership (#10430)
* refactor: prune internal seams and preserve configuration ownership * fix(setup): keep YAML aliases and inherited registration settings on refresh - Reuse an unchanged YAML collection only while every alias in it still resolves after the edit; otherwise rebuild it so the alias becomes its value. A sibling anchor replaced or moved in the same refresh no longer leaves an unresolved alias in Hermes or Goose output. - Keep a connection selector whose existing value already chooses stdio (for example an inherited Hermes transport: stdio) instead of superseding it; remote selectors are still replaced. Explicit stdio selectors are therefore no longer rewritten (Kimi expectation updated). - When the whole Hermes registration is inherited through a merge, override it with that merge and write only the changed fields. * fix(setup): edit registration fields whose YAML key is an alias A key written as an alias to a string scalar (for example *field with field: &field env) was treated as a source-only key, so any change to its value was refused in Hermes and Goose. Resolve such keys to their string, keep the aliased spelling while its anchor survives the edit, and write the plain key when the same edit rebuilds the anchor. * test(process): bound cleanup-boundary waits and always release gates Both cancellation tests awaited a bare started promise and released their gates only on success, so a missed boundary waited for the outer deadline and could leave cleanup parked. Use awaitAcknowledgement and release and join the cleanup in finally. * fix(setup): repair only aliases an edit leaves unresolved Replace the pre-edit alias survival guess, which expanded aliases to sibling anchors that survive unchanged, with an exact repair: record what each alias in the replaced value resolves to, write the edit, then replace only aliases left without a preceding anchor by that value. - Keep an aliased key's source position, so its anchor stays ahead of later aliases. - Treat an aliased key as its string only when no other key in the map resolves to the same string; an ambiguous one stays guarded. - Override an inherited Hermes registration only when the requested entry keeps every inherited field, so an explicit replacement can drop remote selectors. * fix(setup): repair aliases whose binding an edit changes, keeping comments An alias whose own anchor was removed could resolve to an earlier anchor with the same name and silently change value. Record the node each alias resolved to and repair any alias that no longer resolves to that node. Carry the alias's comments and spacing onto the repaired value. * test(setup): split the Hermes anchor and merge refresh cases * fix(setup): refuse removing an overridden key its merge would restore The merge-retention check skipped keys the mapping also overrides, so dropping such a key (for example a remote url during an explicit stdio replacement) let the retained merge restore it. Check removal before skipping overridden keys, so the edit is refused with the existing message instead of producing a registration that cannot be applied. |
||
|
|
47353e494d |
feat(config): make the bridge request ceiling configurable (#6376)
* fix(reconstruction): dedupe residual unknown ids with uniqueSorted Current main calls uniqueBy, which is not defined, so typecheck fails. Residual unknown ids are strings, and the adjacent lists already use uniqueSorted. Co-authored-by: morluto <morluto@users.noreply.github.com> * feat(config): make the bridge request ceiling configurable REA_BRIDGE_MAX_REQUEST_BYTES replaces the hard-coded 16 MiB Hopper and Cutter request payload ceiling. The default stays 16777216 bytes. Values outside 7464 to 268435456 bytes are configuration_invalid. Part of #6176. Co-authored-by: morluto <morluto@users.noreply.github.com> * fix(cutter): keep cleanup ownership when a sent command's reply is oversized An authenticated command may already have changed the Cutter document when its reply exceeds the frame ceiling. Return the existing unknown execution, with the ceiling diagnostic in the message, so receipt cleanup still waits. A frame that overflows before the command is sent remains a resource constraint. Co-authored-by: morluto <morluto@users.noreply.github.com> * style: format the bridge request ceiling sources oxfmt --check failed on the five files that set and test REA_BRIDGE_MAX_REQUEST_BYTES. Formatting only; an oversized Cutter reply still stays an unknown execution. Co-authored-by: morluto <morluto@users.noreply.github.com> * fix(cutter): exclude the LF from the response frame budget REA_BRIDGE_MAX_REQUEST_BYTES counts payload bytes. The Cutter response reader and authenticated encoder were reserving one byte for the terminating LF, so an exact-limit response was rejected. A reply that exceeds the ceiling after the command was sent still stays an unknown execution. Co-authored-by: morluto <morluto@users.noreply.github.com> * fix(bridge): measure escaped JSON before allocating the request A command of U+0001 characters can expand sixfold. JSON.stringify of that expansion can throw past Node's string ceiling before the payload check. Count the escaped size within REA_BRIDGE_MAX_REQUEST_BYTES first and refuse it as a resource constraint. Co-authored-by: morluto <morluto@users.noreply.github.com> * fix(config): derive the bridge request maximum from JSON expansion A 256 MiB ceiling still lets a shorter U+0001 command expand past Node's 536870888-character string limit. The maximum is now floor((536870888 - 296) / 7) = 76695798, the longest such command whose authenticated frame fits in one string. Requests are still measured before JSON.stringify. Co-authored-by: morluto <morluto@users.noreply.github.com> * fix(bridge): size the Cutter frame deadline and send the measured Hopper payload The authenticated Cutter command is encoded after the challenge, so a one-second read rejected an in-budget frame. That read now allows one second per mebibyte of the ceiling and never waits longer than 25 seconds. Hello stays at one second. Hopper writes the payload it already measured instead of serializing the same request again. Co-authored-by: morluto <morluto@users.noreply.github.com> * fix(config): bound the bridge request maximum by the serialized string The ceiling already measures escaped JSON, so dividing Node's string limit by the seven-byte expansion rejected encoded payloads that still fit. The maximum is 536870887, one byte under that string ceiling, leaving room for the framing LF. Co-authored-by: morluto <morluto@users.noreply.github.com> * fix(hopper): serialize a bridge request when it reaches the wire The queue kept each encoded frame, plus the caller's params, until Hopper finished the active request. A raised ceiling made a few waiting calls enough to exhaust the heap. The FIFO now keeps the params, and the frame is encoded only for the request being written. Co-authored-by: morluto <morluto@users.noreply.github.com> * fix(cutter): hash the bridge proof prefix and payload separately An exact-limit Cutter frame plus the HMAC prefix exceeds Node's single-string ceiling, so the client threw before sending an admitted command. The prefix and payload are now separate HMAC updates, including the response proof. Co-authored-by: morluto <morluto@users.noreply.github.com> * fix(cutter): keep recovery fields when a status path exceeds the frame A long current_file made the status reply miss the ceiling, and the fallback then dropped session_id and the completion receipts. The status now omits the path and version and still returns the session, connection proof, and up to 64 receipts. That required recovery frame is smaller than the 7464 floor. Co-authored-by: morluto <morluto@users.noreply.github.com> * fix(cutter): report an unknown path when status identity does not fit A bounded status kept the new document generation and omitted the path, so the client filled in the descriptor's older path. The observed path is sent when it fits. When it does not, current_file is null and is not replaced with that stale path. Co-authored-by: morluto <morluto@users.noreply.github.com> * fix(cutter): count structured replies by their encoded JSON size The response guard charged 16 bytes per primitive and two bytes per list slot, so a dense array under the configured ceiling was replaced with output_truncated. Numbers, booleans, null, and container punctuation now use their JSON lengths. Co-authored-by: morluto <morluto@users.noreply.github.com> * fix(cutter): stream authenticated responses in bounded chunks A fitting reply was signed from retained raw bytes, escaped bytes, and a joined frame, so a ceiling near 512 MiB could exhaust Cutter before send. Measure and sign JSON pieces, then write the same frame in 64 KiB chunks. Co-authored-by: morluto <morluto@users.noreply.github.com> * fix(bridge): keep Cutter admission from stalling or hiding sessions Read an unauthenticated frame off the accept loop. A command reply that does not fit keeps completion and generation and reports an oversized path as null. Discovery reports a ceiling mismatch instead of an absent session. The maximum HMAC proof is opt-in, and both bridges reject non-ASCII digits. Co-authored-by: morluto <morluto@users.noreply.github.com> * fix(cutter): bound frame scans and client response copies Search only newly read bytes for the framing LF. Unescape each socket chunk into one response string, check the proof, and then parse it. Co-authored-by: morluto <morluto@users.noreply.github.com> * fix(cutter): keep completion, admission, and dense replies bounded Report completed_connection only through connections that have terminated. Cap connection threads and keep the listener up if one fails to start. Batch scalar JSON and fail discovery when any ceiling mismatches. Co-authored-by: morluto <morluto@users.noreply.github.com> * fix(cutter): hash requests in parts and scan escapes once Update the client-proof prefix and request separately. Stop the response decoder at the first quote or backslash instead of rescanning the tail. Co-authored-by: morluto <morluto@users.noreply.github.com> * fix(cutter): confirm live ceiling mismatches and omitted output A stale descriptor from a previous ceiling is not a discovery mismatch until its hello proves a live authenticated bridge. A response discarded for the frame ceiling after dispatch reports output_truncated. Co-authored-by: morluto <morluto@users.noreply.github.com> * test(cutter): close the unauthenticated ceiling-mismatch fixture The listener that fails the hello proof is destroyed after its challenge so discovery cleanup does not wait on that socket. Co-authored-by: morluto <morluto@users.noreply.github.com> --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: morluto <morluto@users.noreply.github.com> |