zig-waf

Metadata and non-disruptive actions

On this page 4

WAF-14 compiles rule metadata and non-disruptive actions into immutable typed plan ranges. Request processing never reparses action text. A transaction preflights macro expansion, arithmetic, persistent mutations, scalar updates, collection replacements, captures, and owned event evidence before publishing any local state.

Application API

Transaction.applyMatchedRule accepts a standalone compiled rule and borrowed MatchContext. Transaction.applyMatchedChain requires the exact compiled head-to-tail sequence; partial, missing, duplicated, or reordered members are rejected before effects. Local-only variants stage persistent actions as explicit pending work and are intended for connectors that own persistence coordination.

Successful application returns LocalEffectOutcome with a stable MatchIntentId. matchIntent exposes transaction-owned, immutable evidence: the selected/head identity, severity, post-action expanded message, log data, ordered tags, matched name/value/source, log and audit choices, capture count, effect count, and pending-persistence count. It performs no audit, telemetry, network, filesystem, UI, or database output.

Ordering and atomicity

Effective WAF-13 action ranges execute in source order. RULE metadata is staged first. Later actions see earlier TX, ENV, persistent-collection, and identity scalar writes. Message, log data, and tags expand after all members complete. capture replaces TX.0 through TX.9 as a set, clearing stale optional groups.

Collection and scalar storage use allocation-complete commit primitives. Persistent sessions take a checkpoint before a rule or chain. Any syntax, macro, capacity, arithmetic, timestamp, allocation, or backend-policy error leaves local state, event intent, bindings, mutation logs, and decay clocks at the preflight boundary.

Persistent behavior

initcol, setsid, setuid, and setrsc bind the five supported persistent namespaces. Assignment, deletion, and checked signed addition/subtraction are revisioned mutations. expirevar stores an absolute deadline derived from the injected clock. deprecatevar records amount, period, and observation time; the backend recomputes whole-period decay against its authoritative revision, including after conflicts. Values clamp at zero, partial periods are retained, and remove/recreate resets the decay clock.

Production never substitutes an in-memory backend. Missing, unavailable, timed-out, corrupt, exhausted, or conflicting persistence follows the builder's explicit fail-open/fail-closed policy and remains observable through lastPersistentFailure.

Limits and qualification

Independent limits cover match names/values, captures, macro output, scalar and collection storage, persistent records/mutations, intent count, and aggregate intent bytes. The executable qualification commands are:

zig build test --summary all
zig build fuzz-actions -Daction-fuzz-iterations=10000
zig build bench-actions -Doptimize=ReleaseFast
zig build test-plan-corpus -Dplan-corpus=<repeatable-path>

Pinned upstream paths, revisions, fixture mappings, fuzz parameters, corpus counts, and measured benchmark values are embedded in src/compatibility/evidence/non-disruptive-actions.json.