Add JsonReadHelpers and WslShellQuoting canonical helpers (additive)#994
Open
bkudiess wants to merge 1 commit into
Open
Add JsonReadHelpers and WslShellQuoting canonical helpers (additive)#994bkudiess wants to merge 1 commit into
bkudiess wants to merge 1 commit into
Conversation
Additive PR 2 of the architecture refactor. Introduces two single-source helpers previously copy-pasted across the codebase, with thorough tests and ledger updates. No runtime behavior change beyond one behavior-identical call-site routing. - JsonReadHelpers: canonical, total (never-throwing) JsonElement coercion for the non-nullable, fallback-returning helper family (GetString, TryGetString, GetInt/GetLong/GetDouble, GetArrayLength, FirstNonEmpty). Docs explicitly scope out the divergent null-sentinel / non-negative / whitespace-absent / trimming variants that must not be blindly migrated. - WslShellQuoting: POSIX/WSL single-quote quoting (the '\'' idiom), deliberately separate from the cmd/PowerShell ShellQuoting. Escape-only and fully-wrapped are two distinct operations. - OpenClawGatewayClient.ParseUsageCost: route 3 GetInt sites to JsonReadHelpers.GetInt; remove the duplicate private GetInt. - docs/ARCHITECTURE.md: move json-read-helpers and wsl-posix-quoting from planned to authoritative with behavioral guard tests; narrow the ledger scope to the non-nullable fallback family. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Additive PR 2 of the architecture refactor. It establishes two canonical, single-source helpers that were previously copy-pasted across the codebase, with thorough tests and ledger updates.
JsonReadHelpers(src/OpenClaw.Shared/JsonReadHelpers.cs,internal static) — the canonical home for the non-nullable, fallback-returning family ofJsonElementcoercion helpers:GetString,TryGetString,GetInt/GetLong/GetDouble,GetArrayLength,FirstNonEmpty. All accessors are total (never throw) — a missing property, JSON null, wrongJsonValueKind, or non-object parent yields the documented fallback, folding in the defensiveGetStringSafenon-object guard.WslShellQuoting(src/OpenClaw.Shared/WslShellQuoting.cs,internal static) — POSIX/WSL single-quote quoting using the'\''idiom, kept deliberately separate from the cmd.exe/PowerShellShellQuoting(which doubles single quotes — wrong and injection-unsafe for WSL command lines). Two distinct operations:EscapePosixSingleQuoteInner(escape-only) andQuotePosixSingleQuote(fully-wrapped token).OpenClawGatewayClient.ParseUsageCostnow usesJsonReadHelpers.GetInt(3 sites); the duplicate privateGetIntis removed. Behavior-identical — those payloads are always JSON objects.docs/ARCHITECTURE.md):json-read-helpersandwsl-posix-quotingmovedplanned→authoritativewith real behavioral guard tests; single-source-owners table and the SetupSteps "extract-toward" guidance updated.Scope of the canonical contract (intentionally narrow)
JsonReadHelperscanonicalizes the non-nullable fallback-returning family only. It is not a drop-in for every private JSON helper — several existing helpers have deliberately different contracts and must not be blindly routed through it (each needs a call-site guard or a dedicated variant). This is documented in the type's XML doc and the ledger residue:Models.GetInt/GetLongreturnint?/long?(null sentinel = missing);Models.GetLonghas no double→long fallback (canonical truncates instead).WorkspaceFilesModel.GetLongrejects negatives (>= 0); canonical accepts negatives.WindowsNodeClient.TryGetStringtreats empty/whitespace as absent; canonical returnstruefor""(present).Mxc.MxcAvailability.FirstNonEmptytrims;SetupSteps.FirstNonEmptytrims + returns"no output"; canonical is verbatim /null.Validation
$env:OPENCLAW_REPO_ROOT=(Get-Location).Pathset for all runs (linked worktree)..\build.ps1TreatWarningsAsErrors=true)dotnet test .\tests\OpenClaw.Shared.Tests\OpenClaw.Shared.Tests.csprojdotnet test .\tests\OpenClaw.Tray.Tests\OpenClaw.Tray.Tests.csprojArchitectureLedgerConsistencyTests(ledger format + guard-test existence) andGatewayProtocolDriftTests(unaffected by the routing) are green.Real behavior proof
Proof profile: pure helper. No UI/MCP/node-capability/gateway surface is touched, so the proof is the automated unit tests that directly exercise the changed behavior:
JsonReadHelpersTests— missing property, JSON null, wrong kind, valid string/number, empty-string-vs-null, empty array,int64clamp tointrange, fractional→longtruncation, fallback params, non-object parent, andFirstNonEmptyselection/verbatim/whitespace/null-array.WslShellQuotingTests— empty→'', whitespace, embedded/single/multiple quotes, newlines, multi-line fragments,$(...), backticks, URLs, JSON arrays, Windows backslash paths, already-quoted input, a quote-breakout payload (x'; rm -rf / #), the escape-only-vs-wrapped invariant, the no-bare-unescaped-quote invariant, and a guard asserting divergence from PowerShell quoting.Rubber-duck review
Adversarial dual-model review (GPT-5.5 + Claude Opus 4.8) was run on the diff, and the coordinator independently ran a second dual-model pass:
GetIntrouting is behavior-identical,WslShellQuotingis POSIX-correct/injection-safe, the hand-computed'\''test expectations are correct, and the ledger is well-formed with existing guard tests.FirstNonEmptywouldNullReferenceExceptionon a single barenullargument (latent, unreachable today, matched the pre-existing helpers) → added avalues is nullguard + regression test.TryGetString'soutparam now carries[NotNullWhen(true)].GetInt's XML doc clarifies that numbers withinlongrange but beyondintare clamped, while numbers beyondlongrange return the fallback (behavior unchanged from the deleted private helper).