Skip to content

ui: add transactional JsVar client validation#166

Merged
linkdata merged 1 commit into
mainfrom
feat/jsvar-client-check
Jul 20, 2026
Merged

ui: add transactional JsVar client validation#166
linkdata merged 1 commit into
mainfrom
feat/jsvar-client-check

Conversation

@linkdata

Copy link
Copy Markdown
Owner

Summary

  • Replace binding-local MaxClientJsVarBytes accounting with optional JsVar.ClientCheck validation over the complete tentative state.
  • Pass the exact browser-supplied jq path to each check and use jq.SetChecked to roll rejected or panicking mutations back atomically.
  • Add JSONSizeCheck[T] as an opt-in complete-value serialized-size policy.
  • Keep broadcast encoding protected by the shared backing locker so retained maps, slices, and pointers cannot race a correctly synchronized writer.
  • Add shared-state, concurrency, rollback, callback, panic, alias, locking, and error-identity coverage, plus API/security documentation and retained benchmarks.

Migration

This intentionally removes ui.MaxClientJsVarBytes and the default cumulative state-size policy. Applications must configure an equivalent ClientCheck on every request-scoped binding that exposes the same mutable backing object graph, or enforce bounds in PathSetter.

ClientCheck applies only to actual generic browser mutations. Rendering, server writes, invalid or unchanged writes, and PathSetter values bypass it. The supplied jq path is verbatim and may be noncanonical, so it is an inspection hint rather than an authorization key; use PathSetter to allow-list paths.

JSONSizeCheck marshals the complete tentative value for every accepted mutation attempt. It bounds JSON output rather than Go backing memory, and custom MarshalJSON or MarshalText methods, omitted fields, aliases, or collection capacity may require a domain-specific check.

Benchmarks

Ten identical-workload samples on darwin/arm64, using alternating equal-length values:

Case Baseline This PR Allocations
Unchecked, 1 item 875.1 ns/op 748.7 ns/op 11 → 11
Unchecked, 10,000 items 876.1 ns/op 877.5 ns/op 11 → 11
Checked, 1 item 1.115 µs/op, 440 B/op 16
Checked, 10,000 items 142.9 µs/op, ~129 KiB/op 16

The unchecked large-state result is statistically unchanged. The small-state result improved but had higher variance. Checked cases are absolute opt-in costs with no baseline analogue.

Verification

  • go generate ./...
  • go vet ./...
  • gofmt -l .
  • staticcheck ./...
  • golangci-lint run ./...
  • gosec ./...
  • JAWS_REQUIRE_NODE=1 go test -race -count=1 -coverprofile=coverage.out ./...
  • go build ./...
  • focused JsVar contract tests under -race -count=100

lib/ui and all library packages report 100% statement coverage; total module coverage is 99.9% because the example executable main remains uncovered.

Closes #159

Replace binding-local size accounting with an optional validation callback that observes the complete tentative state and changed jq path. Add JSONSizeCheck, atomic rollback, shared-state coverage, documentation, and retained benchmarks.
@linkdata
linkdata merged commit bbc1657 into main Jul 20, 2026
7 checks passed
@linkdata
linkdata deleted the feat/jsvar-client-check branch July 20, 2026 15:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

ui: shared JsVar backing state bypasses MaxClientJsVarBytes

1 participant