agent foundation

This commit is contained in:
2026-03-06 00:44:52 +01:00
parent 9819cba733
commit 9a08f96c11
199 changed files with 8522 additions and 1880 deletions

View File

@@ -98,6 +98,9 @@ class RateLimiterService
$nowTs = time();
$nowSql = gmdate('Y-m-d H:i:s', $nowTs);
// Two-attempt loop handles a creation race: if two requests arrive simultaneously for a
// new subject, both may find no row and try to INSERT. The second INSERT fails (unique key),
// so we retry once and the second attempt reads the now-existing row.
for ($attempt = 0; $attempt < 2; $attempt++) {
$row = $this->rateLimitRepository->findByScopeAndHash($normalized['scope'], $normalized['subject_hash']);
@@ -136,6 +139,7 @@ class RateLimiterService
}
$windowStartedTs = $this->parseTimestamp((string) ($row['window_started_at'] ?? ''));
// Sliding window expired — reset the window start and hit count.
if ($windowStartedTs === null || ($windowStartedTs + $windowSeconds) <= $nowTs) {
$windowStartedTs = $nowTs;
$hits = 0;
@@ -189,6 +193,7 @@ class RateLimiterService
$scope = substr($scope, 0, 64);
}
// Hash the subject (e.g. email or IP) so PII is never stored in the rate limit table.
return [
'scope' => $scope,
'subject_hash' => hash(self::HASH_ALGO, $subject),