Skip to content

Rate regulator: at most 500 keep-count lines per service per window past its total (E90) - #116

Merged
talwgx merged 2 commits into
mainfrom
fix/e90-keep-max-over-total
Oct 26, 2026
Merged

talwgx merged 2 commits into
mainfrom
fix/e90-keep-max-over-total

Conversation

@talwgx

@talwgx talwgx commented Oct 26, 2026 •

Copy link
Copy Markdown
Contributor

Engineering ask E90, option B as ruled. Needs log-10x/modules#157 (the declaration of rateReceiverKeepMaxOverTotal); a config key without its declaration fails launch, so modules#157 merges first.

Change

keepMaxOverTotal (option rateReceiverKeepMaxOverTotal, default 500, 0 = unbounded) in both cap-file regulators (rate-object-cap.js, rate-object-lookup-cap.js), modelled on baselineMaxOverTotal:

  • A held line of a level in keepCounts whose pattern is under K this window (rg_kc_, unchanged) is a keep line.
  • With no service total, or with the option at 0, it passes as before.
  • Otherwise it reserves the service total (rg_pas_) like a regular line. If it fits, it passes and counts toward the total.
  • If it does not fit, it is past the total and passes only while rg_kx_<container> is under the allowance. The rest take the service's action.

Past the total means what it means for the sample bound: a line the reservation against rg_pas_ refuses. rg_sx_ counts only sample lines the total refused; rg_kx_ counts only keep lines the total refused. Every other path is unchanged: regular lines, the sample bound, K per pattern, and mute-entry lines (the mute path returns before the keep test). With 0, the units added to rg_pas_ match today's for every line.

Worst case per service per node per window with the shipped settings: total + 50 sample lines + 500 keep-count lines (+ mute passes, + warm-up when set). rate-object-local.js and rate-object-lookup.js read no total and are unchanged. config.yaml adds the key and updates the keepCounts and total-file comments. schema.json is regenerated from the modules#157 text the way JsonSchemaGenerator builds it (checked against the untouched baselineMaxOverTotal and baselineCount entries).

Gate: tests/regulator, ghcr.io/log-10x/edge-10x:1.1.150 (sha256:3e755bbc), fix = this branch + modules#157 mounted

The image's bundled rate files and module.yaml are byte-identical to config/modules main, so the main arm is main.

case main fix
e1-keep-bound (1,422 new ERROR patterns x 7 lines, cap 1 byte, total 100 lines) FAIL: 9,954 passed, 0 held PASS: 650 passed (100 + 50 + 500), 9,304 tier_down
e2-keep-bound-off (option 0) n/a PASS: 9,954 passed
e3-keep-bound-mute (e1, mute + cap regulator) FAIL: 9,954 passed PASS: 650 passed
k1-errors PASS 58 PASS 58
k2-mute PASS 50 PASS 50
k3-mute-nocap PASS 50 PASS 50
k4-keepcounts-unset n/a PASS 58
u1-events PASS 40 PASS 40
u2-unit-typo PASS (launch fails) PASS
u3-unit-typo-mute PASS (launch fails) PASS
m1-mute-counts PASS (others 50 of 80) PASS (others 50 of 80)
t3-reservation PASS 19,939 / 20,000 B PASS 19,939 / 20,000 B
g0-gitops-off PASS 300 PASS 300
t1-total PASS 247 (51,422 B) PASS 247 (51,422 B)
t2-noisiest PASS 346 PASS 346
s1-star PASS 300 PASS 300
d1-defaults PASS 66 PASS 66
b1-sample-bound PASS 100 PASS 100
b2-sample-bound-off n/a PASS 400
b3-sample-bound-mute PASS 100 PASS 100
w1-windows PASS 192 / 213 PASS 192 / 213
w2-windows-mute (windows 1, 2; total 517) PASS 547, 517 PASS 547, 517
w3-windows-scaled (windows 1, 2; total 301) PASS 312, 301 PASS 312, 301
w4-windows-late (windows 1 to 4; total 301) PASS 21, 309, 301, 301 PASS 21, 309, 301, 301

Every existing case passes on the fix with the same counts as main. The paced cases w2 to w4 ran after the rest, with run.sh's wait for the Forward input's listening line, which needed no change.

Harness

  • Three cases e1 to e3.
  • run.sh runs each engine with docker run -d --name $PREFIX-... and removes it with docker rm -f -v (it no longer uses docker run --rm in the foreground).
  • A paced case waits for the engine's "Forward protocol server listening" line before sending.
  • The default image is now 1.1.150.

🤖 Generated with Claude Code

talwgx and others added 2 commits October 25, 2026 20:48
…ast its total

A keep-count line (one of the first K held lines of an ERROR, CRITICAL or FATAL
pattern in a window) now reserves the service total like any line. Past the
total, a service passes at most keepMaxOverTotal of them per window (default
500, counter rg_kx_<container>); the rest take the service's action. 0 removes
the bound. Lines an active mute entry passes are unchanged. Both cap-file
variants; config.yaml and schema.json carry the key.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
e1: 1,422 new ERROR patterns of 7 lines over a 1-byte cap and a 100-line total
pass 650 (the total, 50 sample lines, 500 keep-count lines), not 9,954. e2:
keepMaxOverTotal 0 passes all 9,954. e3: e1 with a mute file present, the mute
and cap regulator. On edge-10x 1.1.150: e1 and e3 fail on main and pass on the
fix; k1 to b3 and w1 pass on both.

run.sh starts each engine with docker run -d --name (PREFIX) and removes it with
docker rm -f -v, waits for the Forward input's listening line before a paced
case sends, and defaults to edge-10x 1.1.150.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@talwgx
talwgx merged commit 63d77a7 into main Oct 26, 2026
6 checks passed
@talwgx
talwgx deleted the fix/e90-keep-max-over-total branch October 26, 2026 01:23
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.

1 participant