diff --git a/404.html b/404.html index 78c38f49b..83bcbcb02 100644 --- a/404.html +++ b/404.html @@ -2509,7 +2509,7 @@ - + diff --git a/WiFi/index.html b/WiFi/index.html index 1a5aa91aa..e5bb5250f 100644 --- a/WiFi/index.html +++ b/WiFi/index.html @@ -3799,7 +3799,7 @@ and NTP diagnostics remain infrastructure features.

- + diff --git a/_javascript/filter_tool.js b/_javascript/filter_tool.js index c3739d368..f938b15f8 100644 --- a/_javascript/filter_tool.js +++ b/_javascript/filter_tool.js @@ -202,7 +202,7 @@ id: id || "rule-1", phase: "rewrite", owner: "scope", - priority: 100, + priority: 0, mode: "active", stop: "none", route: "flood", @@ -349,20 +349,29 @@ return `"${text.replace(/\\/g, "\\\\").replace(/"/g, '\\"')}"`; } + function inferredPhase(rule) { + if (rule.scopeGate !== "unchanged") return "scope_gate"; + if (rule.targetKind !== "none") return "rewrite"; + if (rule.retryBucket !== "none") return "schedule"; + if (clean(rule.sender)) return "content"; + return "forward"; + } + + function inferredOwner(phase) { + return ["scope_gate", "rewrite"].includes(phase) ? "scope" : "filter"; + } + function buildDefinition(input) { const rule = normalizeRule(input); - const header = [ - "policy", "set", rule.id, - `phase=${rule.phase}`, - `owner=${rule.owner}`, - `priority=${rule.priority}`, - ]; + const header = ["policy", "set", rule.id]; + if (rule.phase !== inferredPhase(rule)) header.push(`phase=${rule.phase}`); + if (rule.owner !== inferredOwner(rule.phase)) header.push(`owner=${rule.owner}`); + if (rule.priority !== 0) header.push(`priority=${rule.priority}`); if (rule.mode !== "active") header.push(`mode=${rule.mode}`); - const matches = [ - `route=${rule.route}`, - `type=${rule.type}`, - `hops=${rule.hops}`, - ]; + const matches = []; + if (rule.route !== "flood") matches.push(`route=${rule.route}`); + if (rule.type !== "any") matches.push(`type=${rule.type}`); + if (rule.hops !== "all") matches.push(`hops=${rule.hops}`); if (rule.channel) matches.push(`channel=${quoteDsl(rule.channel)}`); if (rule.incoming !== "any") matches.push(`rx.scope=${quoteDsl(rule.incoming)}`); if (rule.hashBytes) matches.push(`hashbytes=${rule.hashBytes}`); @@ -377,10 +386,13 @@ if (rule.scopeGate === "bypass_global") actions.push("scope-gate=bypass"); if (rule.targetKind === "scope") actions.push(`scope=${quoteDsl(`#${rule.target}`)}`); if (rule.targetKind === "region") actions.push(`region=${quoteDsl(rule.target)}`); - if (rule.rate != null) actions.push(`rate=${rule.rate}/min`, `burst=${rule.burst}`); + if (rule.rate != null) { + actions.push(`rate=${rule.rate}/min`); + if (rule.burst !== rule.rate) actions.push(`burst=${rule.burst}`); + } if (rule.timing !== "inherit") actions.push(`timing=${rule.timing}`); if (rule.queue !== "inherit") actions.push(`queue=${rule.queue}`); - if (rule.retryBucket !== "none") actions.push(`retry=${rule.retryBucket}/${rule.retryAttempts}`); + if (rule.retryBucket !== "none") actions.push(`retry=${rule.retryBucket}${rule.retryAttempts === 1 ? "" : `/${rule.retryAttempts}`}`); if (rule.tag) actions.push(`tag=${rule.tag}`); if (rule.stop !== "none") actions.push(`stop=${rule.stop}`); return [...header, "when", ...matches, "do", ...actions].join(" "); @@ -429,15 +441,18 @@ function parseDefinition(definition) { const tokens = tokenize(clean(definition)); - if (tokens.length < 8 || tokens[0].toLowerCase() !== "policy" || tokens[1].toLowerCase() !== "set") { + if (tokens.length < 6 || tokens[0].toLowerCase() !== "policy" || tokens[1].toLowerCase() !== "set") { throw new FilterToolError("Readable definitions begin with: policy set ."); } const whenIndex = tokens.findIndex((token) => token.toLowerCase() === "when"); const doIndex = tokens.findIndex((token) => token.toLowerCase() === "do"); - if (whenIndex < 3 || doIndex <= whenIndex + 1 || doIndex === tokens.length - 1) { - throw new FilterToolError("Definition requires header options, when matchers, and do actions."); + if (whenIndex < 3 || doIndex <= whenIndex || doIndex === tokens.length - 1) { + throw new FilterToolError("Definition requires when and do sections with at least one action."); } const rule = defaultRule(tokens[2]); + let explicitPhase = false; + let explicitOwner = false; + rule.type = "any"; rule.channel = ""; rule.incoming = "any"; rule.pathKind = "none"; @@ -459,8 +474,8 @@ tokens.slice(3, whenIndex).forEach((token) => { const [name, value] = splitOption(token); - if (name === "phase") rule.phase = value; - else if (name === "owner") rule.owner = value; + if (name === "phase") { rule.phase = value; explicitPhase = true; } + else if (name === "owner") { rule.owner = value; explicitOwner = true; } else if (name === "priority") rule.priority = Number(value); else if (name === "mode") rule.mode = value; else throw new FilterToolError(`Unsupported rule-header option: ${token}`); @@ -501,14 +516,16 @@ else if (name === "timing") rule.timing = value; else if (name === "queue") rule.queue = value; else if (name === "retry") { - const match = value.match(/^(bucket:[1-6])\/(\d+)$/i); - if (!match) throw new FilterToolError("Retry action must use bucket:N/attempts."); + const match = value.match(/^(bucket:[1-6])(?:\/(\d+))?$/i); + if (!match) throw new FilterToolError("Retry action must use bucket:N or bucket:N/attempts."); rule.retryBucket = match[1].toLowerCase(); - rule.retryAttempts = Number(match[2]); + rule.retryAttempts = match[2] == null ? 1 : Number(match[2]); } else if (name === "tag") rule.tag = value; else if (name === "stop") rule.stop = value; else throw new FilterToolError(`Unsupported policy action: ${token}`); }); + if (!explicitPhase) rule.phase = inferredPhase(rule); + if (!explicitOwner) rule.owner = inferredOwner(clean(rule.phase).toLowerCase()); return normalizeRule(rule); } @@ -1153,7 +1170,7 @@ ...defaultRule(id), phase: "forward", owner: "filter", - priority: priority == null ? 100 : priority, + priority: priority == null ? 0 : priority, type, hops, channel: "", @@ -1178,7 +1195,7 @@ type: "class:group", channel: "#rgdata", incoming: "any", - priority: 100, + priority: 0, }, ]), blackhole: Object.freeze([ @@ -1188,7 +1205,7 @@ hops: "all", channel: "#rgdata", incoming: "none", - priority: 100, + priority: 0, }, ]), scope_rewrite: Object.freeze([ @@ -1197,7 +1214,7 @@ type: "grp_data", channel: "#rgdata", incoming: "scope:usa", - priority: 100, + priority: 0, }, ]), prefix_rate: Object.freeze([ diff --git a/bootloader_version_stock_audit/index.html b/bootloader_version_stock_audit/index.html index d049926a6..c80dd1178 100644 --- a/bootloader_version_stock_audit/index.html +++ b/bootloader_version_stock_audit/index.html @@ -2549,7 +2549,7 @@ - + diff --git a/cad_scan_validation/index.html b/cad_scan_validation/index.html index 4b3db939c..e9a1aaeea 100644 --- a/cad_scan_validation/index.html +++ b/cad_scan_validation/index.html @@ -2549,7 +2549,7 @@ - + diff --git a/carrier_wave/index.html b/carrier_wave/index.html index f7363f300..4085bfd8a 100644 --- a/carrier_wave/index.html +++ b/carrier_wave/index.html @@ -2998,7 +2998,7 @@ reproduction steps, and the tested preamble settings.

- + diff --git a/carrier_wave_validation/index.html b/carrier_wave_validation/index.html index aece1e23b..ddbf41c17 100644 --- a/carrier_wave_validation/index.html +++ b/carrier_wave_validation/index.html @@ -2549,7 +2549,7 @@ - + diff --git a/charge_voltage/index.html b/charge_voltage/index.html index 00674f567..1b5dc4547 100644 --- a/charge_voltage/index.html +++ b/charge_voltage/index.html @@ -2666,7 +2666,7 @@ See Battery profil - + diff --git a/cli_build_matrix/index.html b/cli_build_matrix/index.html index 7e51734b2..52acdfef7 100644 --- a/cli_build_matrix/index.html +++ b/cli_build_matrix/index.html @@ -3151,7 +3151,7 @@ does not contain its linked marker is rejected during the build.

- + diff --git a/cli_command_availability/index.html b/cli_command_availability/index.html index 25fc2fe65..65ab3b0c5 100644 --- a/cli_command_availability/index.html +++ b/cli_command_availability/index.html @@ -6382,7 +6382,7 @@ selected by that manifest.

- + diff --git a/cli_commands/index.html b/cli_commands/index.html index 0e0e6b8cb..eb6c9966f 100644 --- a/cli_commands/index.html +++ b/cli_commands/index.html @@ -14554,7 +14554,7 @@ is active.

- + diff --git a/cli_settings_audit/index.html b/cli_settings_audit/index.html index 38ce0a0e0..f7f76f503 100644 --- a/cli_settings_audit/index.html +++ b/cli_settings_audit/index.html @@ -2549,7 +2549,7 @@ - + diff --git a/companion_contact_cache/index.html b/companion_contact_cache/index.html index ff989a1f2..fd07d5247 100644 --- a/companion_contact_cache/index.html +++ b/companion_contact_cache/index.html @@ -2549,7 +2549,7 @@ - + diff --git a/companion_contact_cache_results/index.html b/companion_contact_cache_results/index.html index fde5a42bb..c0e9c1333 100644 --- a/companion_contact_cache_results/index.html +++ b/companion_contact_cache_results/index.html @@ -2549,7 +2549,7 @@ - + diff --git a/companion_lost_reply/index.html b/companion_lost_reply/index.html index c8adfa82c..1af60e981 100644 --- a/companion_lost_reply/index.html +++ b/companion_lost_reply/index.html @@ -2719,7 +2719,7 @@ responder. Normal message reception and notification behavior remain in place. - + diff --git a/companion_offline_queue/index.html b/companion_offline_queue/index.html index 3adb75398..da2baf05d 100644 --- a/companion_offline_queue/index.html +++ b/companion_offline_queue/index.html @@ -2774,7 +2774,7 @@ protocol setting to resize it at runtime.

- + diff --git a/companion_power_diagnostics/index.html b/companion_power_diagnostics/index.html index a1a8e7274..5493a6817 100644 --- a/companion_power_diagnostics/index.html +++ b/companion_power_diagnostics/index.html @@ -2574,7 +2574,7 @@ an already running nRF52 watchdog cannot be stopped directly.

- + diff --git a/companion_protocol/index.html b/companion_protocol/index.html index 1d067434f..b4d01da49 100644 --- a/companion_protocol/index.html +++ b/companion_protocol/index.html @@ -5643,7 +5643,7 @@ response = wait_for_response(PACKET_MSG_SENT) - + diff --git a/companion_radio_diagnostics/index.html b/companion_radio_diagnostics/index.html index 07ed7b57f..1f7b92262 100644 --- a/companion_radio_diagnostics/index.html +++ b/companion_radio_diagnostics/index.html @@ -2594,7 +2594,7 @@ clears the sticky error flags shown by stats-core.

- + diff --git a/companion_radio_full/index.html b/companion_radio_full/index.html index 1e2f4cef0..81e18d5ee 100644 --- a/companion_radio_full/index.html +++ b/companion_radio_full/index.html @@ -4131,7 +4131,7 @@ selection, nRF52 in-place deltas, relays, trust checks, and recovery behavior. - + diff --git a/companion_usb_ascii_validation/index.html b/companion_usb_ascii_validation/index.html index eb6d54042..c03a8c748 100644 --- a/companion_usb_ascii_validation/index.html +++ b/companion_usb_ascii_validation/index.html @@ -2549,7 +2549,7 @@ - + diff --git a/companion_usb_client_validation/index.html b/companion_usb_client_validation/index.html index 57b440c12..834859ec1 100644 --- a/companion_usb_client_validation/index.html +++ b/companion_usb_client_validation/index.html @@ -2549,7 +2549,7 @@ - + diff --git a/docs/index.html b/docs/index.html index 31445698e..e25de492f 100644 --- a/docs/index.html +++ b/docs/index.html @@ -2638,7 +2638,7 @@ pip install mkdocs-material - + diff --git a/double_frequency_v4_validation/index.html b/double_frequency_v4_validation/index.html index d24fc4db4..6d565a08b 100644 --- a/double_frequency_v4_validation/index.html +++ b/double_frequency_v4_validation/index.html @@ -2549,7 +2549,7 @@ - + diff --git a/esp32_memory_budget/index.html b/esp32_memory_budget/index.html index e89947ffd..8c38a96bf 100644 --- a/esp32_memory_budget/index.html +++ b/esp32_memory_budget/index.html @@ -2549,7 +2549,7 @@ - + diff --git a/esp32_partition_catalog/index.html b/esp32_partition_catalog/index.html index 32dddfdb7..65005feb0 100644 --- a/esp32_partition_catalog/index.html +++ b/esp32_partition_catalog/index.html @@ -2859,7 +2859,7 @@ LUT. No scheduled refresh job or release upload is installed by this script.

- + diff --git a/esp32_wifi_partition_migration/index.html b/esp32_wifi_partition_migration/index.html index 6766df889..fada03434 100644 --- a/esp32_wifi_partition_migration/index.html +++ b/esp32_wifi_partition_migration/index.html @@ -3183,7 +3183,7 @@ The 16 MiB target table creates two 6.25 MiB OTA slots. See the - + diff --git a/espnow_bridge_setup/index.html b/espnow_bridge_setup/index.html index f8e3df35d..0ffcdea32 100644 --- a/espnow_bridge_setup/index.html +++ b/espnow_bridge_setup/index.html @@ -3175,7 +3175,7 @@ a crossover-only block. See the
- + diff --git a/faq/index.html b/faq/index.html index bf8f4f5f0..476e88685 100644 --- a/faq/index.html +++ b/faq/index.html @@ -5525,7 +5525,7 @@ Flash one of the Ethernet-enabled firmware variants: - + diff --git a/filter_tool/index.html b/filter_tool/index.html index b9e0c1cf7..93f863eee 100644 --- a/filter_tool/index.html +++ b/filter_tool/index.html @@ -470,6 +470,17 @@ + + +
  • + + + + Readable policy defaults + + + +
  • @@ -2562,6 +2573,17 @@ +
  • + +
  • + + + + Readable policy defaults + + + +
  • @@ -2720,27 +2742,27 @@ Four-byte paths remain unsupported.

    @@ -3006,7 +3028,8 @@ Four-byte paths remain unsupported.