{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "title": "ajaxUpdatePaginationLinks",
  "description": "Admin table pagination/filter AJAX request from view_updater_pagination.js to ViewUpdater.php",
  "type": "object",
  "required": ["nonce", "subpage"],
  "additionalProperties": false,
  "properties": {
    "nonce": { "type": "string", "minLength": 1 },
    "subpage": {
      "type": "string",
      "enum": ["abj404_redirects", "abj404_captured", "abj404_logs"]
    },
    "part": {
      "type": "string",
      "enum": ["all", "table", "counts", "pagination"],
      "description": "Optional progressive response part; omitted requests retain the legacy all-in-one response"
    },
    "page": { "type": "string" },
    "rowsPerPage": { "type": ["string", "integer"], "description": "Sent as string from JS, parsed via absint()" },
    "filterText": { "type": "string" },
    "filter": { "type": "string" },
    "orderby": { "type": "string" },
    "order": { "type": "string" },
    "paged": { "type": ["string", "integer"] },
    "id": { "type": ["string", "integer"] },
    "score_range": { "type": "string" },
    "detectOnly": { "type": "string", "enum": ["0", "1"] },
    "cacheMode": { "type": "string", "enum": ["normal", "cache_or_pending", "refresh_cache"] },
    "currentSignature": { "type": "string", "maxLength": 128 },
    "requestId": { "type": "string", "pattern": "^[a-zA-Z0-9]{8,64}$" },
    "retryCount": { "type": "integer", "minimum": 0, "maximum": 2 },
    "sessionId": { "type": "string", "maxLength": 64, "description": "Immutable request ledger: joins retried requests from the same browser tab/session." },
    "retryParentId": { "type": "string", "pattern": "^[a-zA-Z0-9]{8,64}$", "description": "Immutable request ledger: requestId of the attempt this retry is following up on." },
    "clientSentAt": { "type": "string", "maxLength": 64, "description": "Immutable request ledger: client-side send timestamp, for boot-delta/queueing diagnostics." },
    "clientBuild": { "type": "string", "maxLength": 64, "description": "Client transport telemetry: FNV-1a hash of the browser's executing build probe, compared server-side against the shipped JS to detect a stale or rewritten bundle. Bounded well above the 8-char hash on purpose: a diagnostic field must never be the reason a table request is rejected, and a malformed value is normalized away by ClientBuildFingerprint::compare() rather than reflected." },
    "clientBuildModules": { "type": "string", "maxLength": 1024, "description": "Client transport telemetry: compact 'name:hash,name:hash' map of the per-module build hashes behind clientBuild, so a mismatch names the drifted module (request driver, transport, storage, delivery, canary, support) instead of only reporting that the client differs. Bounded here well above the shipped module set; ClientBuildFingerprint::parseReportedModules() discards any pair that is not a known module name paired with a well-formed hash." },
    "clientReport": { "type": "string", "maxLength": 8192, "description": "Client transport telemetry: JSON record of the PREVIOUS attempt's browser-side timeline, journaled server-side and joined to the server trace by request id. The client trims to 4000 chars and the server journals at most ClientTransportReport::MAX_REPORT_BYTES; this ceiling sits above both so an oversized report is bounded on arrival instead of failing the request that carried it." },
    "clientInflight": { "type": "string", "maxLength": 8, "description": "Client transport telemetry: how many other plugin AJAX requests this browser tab had in flight when this one was sent, for correlating client-side queueing against server-side admission." },
    "clientInflightIds": { "type": "string", "maxLength": 256, "description": "Client transport telemetry: comma-separated attempt ids of the other plugin AJAX requests in flight at send time, so the journal can be checked for whether those requests ever reached PHP." },
    "clientTabs": { "type": "string", "maxLength": 8, "description": "Client transport telemetry: how many admin tabs of this page the browser had open at send time, from the cross-tab presence registry in view_updater_client_telemetry_store.js. '-1' means the browser could not observe it, which is a different finding from '0' and is preserved as such server-side." },
    "clientForeignInflight": { "type": "string", "maxLength": 8, "description": "Client transport telemetry: how many NON-plugin AJAX requests (the WordPress Heartbeat poll, another plugin's polling) this tab had outstanding at send time, for separating same-site worker contention from host-wide load. '-1' means the browser could not observe it." },
    "clientStorageHealth": { "type": "string", "maxLength": 512, "description": "Client transport telemetry: bounded JSON proving whether localStorage was accessible and writable, whether quota was exhausted, whether the last round-trip write succeeded, and whether the attempt record is using the page-lifetime memory fallback." },
    "clientReportOnly": { "type": "string", "enum": ["0", "1"], "description": "Client transport telemetry: this request is a sendBeacon delivering a report only; the handler journals it and answers without doing table work." },
    "clientThresholdMs": { "type": ["string", "integer"], "enum": ["20000", 20000], "description": "Client transport telemetry: the original attempt remained pending for 20 seconds, so this authenticated carrier asks the server to snapshot that attempt's active operation before the 25-second browser deadline." },
    "reportedAttemptId": { "type": "string", "pattern": "^[a-zA-Z0-9]{8,64}$", "description": "Client transport telemetry: the attempt a clientReportOnly beacon is reporting ON, as opposed to requestId, which is now the beacon's own carrier id. Optional and additive: a beacon sent by an older client omits it and still rides under the attempt's own id, which the server journals as an empty reported_attempt_id rather than an absent field." }
  }
}
