fix(engine): normalize actionClass once and read policies/buckets own-property in write-rate-limit - #10073
Conversation
|
Tip ✅ LoopOver review result - approve/merge recommendedReview updated: 2026-07-31 06:47:06 UTC
Review summary Nits — 5 non-blocking
Decision drivers
Context & advisory signals — never blocks the verdict
Linked issue satisfactionAddressed Review context
Contributor next steps
Signal definitions
🧪 Chat with LoopOverAsk LoopOver a question about this PR directly in a comment — grounded only in the same cached, public-safe facts shown above, never a new claim.
Full command reference: https://loopover.ai/docs/loopover-commands 🧪 Experimental — new and may change. 🟩 Safe / merged · 🟦 Advisory · 🟨 Held for review · 🟥 Blocked / closed 💰 Earn for open-source contributions like this. Gittensor lets GitHub contributors earn for the work they already do — register to start earning →. Checked by LoopOver, a quiet PR intelligence layer for OSS maintainers.
|
|
Superagent didn't find any vulnerabilities or security issues in this PR. |
…-property in write-rate-limit
writeRateLimitRepoKey trimmed actionClass for the per-repo key, but evaluateWriteRateLimit,
recordWriteRateLimitAllowed, recordWriteRateLimitDenied and clearWriteRateLimitBackoff used
the RAW value for the global bucket key and both policy lookups. So " open_pr " resolved the
per-repo key trimmed while the global bucket and both policies fell through to
PERMISSIVE_CONFIG's 1_000_000 ceiling, and recordWriteRateLimitAllowed keyed the global
bucket under the raw string — permanently diverging a decision from the state written for it.
Separately, policyFor and the bucket reads used bare table[actionClass], so an actionClass
naming an Object.prototype member ("constructor"/"toString") resolved an inherited value
(a fabricated limit:0) instead of the intended fallback.
Normalize actionClass exactly once at the top of each function and use it for every lookup,
and read policies/buckets via an ownValue(Object.hasOwn) helper. writeRateLimitRepoKey's
output, DEFAULT_WRITE_RATE_LIMIT_POLICIES, PERMISSIVE_CONFIG's fallback role, and the verdict
shape are all unchanged.
Closes JSONbored#9999
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #10073 +/- ##
=======================================
Coverage 91.88% 91.88%
=======================================
Files 930 930
Lines 113827 113843 +16
Branches 27466 27467 +1
=======================================
+ Hits 104588 104610 +22
+ Misses 7940 7930 -10
- Partials 1299 1303 +4
Flags with carried forward coverage won't be shown. Click here to find out more.
|
Summary
writeRateLimitRepoKeynormalizesactionClass(.trim()) for the per-repo bucket key, butevaluateWriteRateLimit,recordWriteRateLimitAllowed,recordWriteRateLimitDeniedandclearWriteRateLimitBackoffused the raw value for the global bucket key and bothpolicyForlookups. Consequences:" open_pr "resolves the per-repo key trimmed, but the global bucket and both policies fall through toPERMISSIVE_CONFIG's1_000_000/min ceiling on the raw string — so the write is effectively unlimited on both scopes.recordWriteRateLimitAllowedkeyed the global bucket under the raw" open_pr "whileevaluateWriteRateLimitread it under… whatever it was passed, so the two scopes' bookkeeping split permanently for that action class.policies.global/buckets.globalare plain records, sotable[actionClass]withactionClass === "constructor"(or"toString"/"valueOf") resolves an inherited member —policyForreturnedObject.prototype.constructorand the write was scored against a fabricatedlimit: 0(denied) instead ofPERMISSIVE_CONFIG.Fix
actionClassonce at the top and uses that single value for the global bucket key, the per-repo key, and both policy lookups — the same.trim()writeRateLimitRepoKeyalready applies.recordWriteRateLimitAllowedkeys the global bucket by the normalized class, so a decision and the state written for it always address the same bucket.policyForand both bucket reads go through anownValue(table, key)helper (Object.hasOwn(...) ? table[key] : undefined), so anactionClassnaming anObject.prototypemember resolves the intended fallback.writeRateLimitRepoKey's output,DEFAULT_WRITE_RATE_LIMIT_POLICIES,PERMISSIVE_CONFIG's fallback role,incrementBucket's window math, theblockedByprecedence,retryAfterMscomposition, and the ledger-event shape are all unchanged.Tests
A regression test in
packages/loopover-engine/test/write-rate-limit-enforcement.test.tscovering all four bullets:" open_pr "resolves the same30/3limits as"open_pr";recordWriteRateLimitAllowed(_, " open_pr ", …)keys the global bucket under"open_pr"and a later evaluate observes the count;actionClass: "constructor"returnsallowed: true/under_limitwithPERMISSIVE_CONFIGlimits (today:allowed: false,limit: 0); and a backoff recorded with" open_pr "is cleared by"open_pr". Three of the four bullets fail against the current raw-lookup code; existing assertions pass unchanged. Engine-flag coverage of the changed lines verified (source-mapped lcov).Closes #9999