chore(openwolf): update session memory, buglog, and anatomy tracking
Records bug-1461/1462 fixes, admin-config-tool completion, and config-upgrade-snapshot spec work across anatomy.md, buglog.json, cerebrum.md, memory.md, and the session/token-ledger state files.
This commit is contained in:
parent
8ee98beed7
commit
60c25c39c4
6 changed files with 23648 additions and 59 deletions
|
|
@ -9316,7 +9316,8 @@
|
|||
"bug-851"
|
||||
],
|
||||
"occurrences": 3,
|
||||
"last_seen": "2026-07-18T00:20:00.000Z"
|
||||
"last_seen": "2026-07-18T00:20:00.000Z",
|
||||
"gitea_issue": 29
|
||||
},
|
||||
{
|
||||
"id": "bug-1096",
|
||||
|
|
@ -13186,7 +13187,8 @@
|
|||
],
|
||||
"related_bugs": [],
|
||||
"occurrences": 4,
|
||||
"last_seen": "2026-07-20T00:00:00Z"
|
||||
"last_seen": "2026-07-20T00:00:00Z",
|
||||
"gitea_issue": 30
|
||||
},
|
||||
{
|
||||
"id": "bug-1440",
|
||||
|
|
@ -13353,7 +13355,8 @@
|
|||
],
|
||||
"related_bugs": [],
|
||||
"occurrences": 1,
|
||||
"last_seen": "2026-07-18T00:47:00Z"
|
||||
"last_seen": "2026-07-18T00:47:00Z",
|
||||
"gitea_issue": 31
|
||||
},
|
||||
{
|
||||
"id": "bug-1447",
|
||||
|
|
@ -13387,7 +13390,8 @@
|
|||
"bug-1298"
|
||||
],
|
||||
"occurrences": 1,
|
||||
"last_seen": "2026-07-18T14:30:00.000Z"
|
||||
"last_seen": "2026-07-18T14:30:00.000Z",
|
||||
"gitea_issue": 32
|
||||
},
|
||||
{
|
||||
"id": "bug-1448",
|
||||
|
|
@ -13410,7 +13414,8 @@
|
|||
],
|
||||
"related_bugs": [],
|
||||
"occurrences": 1,
|
||||
"last_seen": "2026-07-18T01:54:00Z"
|
||||
"last_seen": "2026-07-18T01:54:00Z",
|
||||
"gitea_issue": 33
|
||||
},
|
||||
{
|
||||
"id": "bug-1449",
|
||||
|
|
@ -13433,7 +13438,8 @@
|
|||
],
|
||||
"related_bugs": [],
|
||||
"occurrences": 1,
|
||||
"last_seen": "2026-07-18T13:00:00.000Z"
|
||||
"last_seen": "2026-07-18T13:00:00.000Z",
|
||||
"gitea_issue": 34
|
||||
},
|
||||
{
|
||||
"id": "bug-1450",
|
||||
|
|
@ -13458,7 +13464,8 @@
|
|||
"bug-1451"
|
||||
],
|
||||
"occurrences": 1,
|
||||
"last_seen": "2026-07-18"
|
||||
"last_seen": "2026-07-18",
|
||||
"gitea_issue": 25
|
||||
},
|
||||
{
|
||||
"id": "bug-1451",
|
||||
|
|
@ -13484,7 +13491,8 @@
|
|||
"bug-1450"
|
||||
],
|
||||
"occurrences": 1,
|
||||
"last_seen": "2026-07-18"
|
||||
"last_seen": "2026-07-18",
|
||||
"gitea_issue": 35
|
||||
},
|
||||
{
|
||||
"id": "bug-1452",
|
||||
|
|
@ -13517,7 +13525,8 @@
|
|||
"bug-1451"
|
||||
],
|
||||
"occurrences": 1,
|
||||
"last_seen": "2026-07-19"
|
||||
"last_seen": "2026-07-19",
|
||||
"gitea_issue": 36
|
||||
},
|
||||
{
|
||||
"id": "bug-1453",
|
||||
|
|
@ -13540,7 +13549,8 @@
|
|||
],
|
||||
"related_bugs": [],
|
||||
"occurrences": 1,
|
||||
"last_seen": "2026-07-20"
|
||||
"last_seen": "2026-07-20",
|
||||
"gitea_issue": 26
|
||||
},
|
||||
{
|
||||
"id": "bug-1454",
|
||||
|
|
@ -13559,7 +13569,8 @@
|
|||
],
|
||||
"related_bugs": [],
|
||||
"occurrences": 1,
|
||||
"last_seen": "2026-07-20"
|
||||
"last_seen": "2026-07-20",
|
||||
"gitea_issue": 37
|
||||
},
|
||||
{
|
||||
"id": "bug-1455",
|
||||
|
|
@ -13580,7 +13591,8 @@
|
|||
"bug-1454"
|
||||
],
|
||||
"occurrences": 1,
|
||||
"last_seen": "2026-07-20"
|
||||
"last_seen": "2026-07-20",
|
||||
"gitea_issue": 38
|
||||
},
|
||||
{
|
||||
"id": "bug-1456",
|
||||
|
|
@ -13603,15 +13615,16 @@
|
|||
"bug-1455"
|
||||
],
|
||||
"occurrences": 1,
|
||||
"last_seen": "2026-07-20"
|
||||
"last_seen": "2026-07-20",
|
||||
"gitea_issue": 39
|
||||
},
|
||||
{
|
||||
"id": "bug-1457",
|
||||
"timestamp": "2026-07-20T22:56:00Z",
|
||||
"error_message": "xce_controller with no --peers flag exits with -EINVAL from cluster_open_listener instead of starting as single-node primary",
|
||||
"file": "src/controller/myapp.c",
|
||||
"root_cause": "Discovered while independently reviewing clusterconfig-schema-split task 5.3 by building and running the actual pre-spec baseline (commit 94f50ce) for comparison. Single-node startup (no --peers) was ALREADY broken before this spec began: myapp_run() calls cluster_open_listener() before the primary config (cluster_config) is loaded from disk, so the pre-spec fallback branch (cluster_config->port, only reachable when cluster_config != NULL) always hit its else branch and returned -EINVAL, unconditionally, for every zero-flag single-node start. This invalidates part of clusterconfig-schema-split's premise (requirements.md's Introduction claimed cluster_config->port was 'the sole live port-sourcing mechanism for single-node deployments' and 'single-node controller startup SHALL continue to work exactly as it does today' — in reality it did not work today). Not caused by, or a regression from, clusterconfig-schema-split's changes — task 2.1's port-resolution rewrite (commit 1229f9a) incidentally fixed this as a side effect, since its hardcoded-default fallback no longer depends on cluster_config being loaded.",
|
||||
"fix": "Not fixed as its own change — already incidentally repaired by clusterconfig-schema-split task 2.1 (cluster_open_listener now falls back to a hardcoded XCE_CONTROLLER_DEFAULT_PORT constant instead of an unloaded cluster_config->port). Live-verified post-fix: single-node startup with no --peers now correctly binds port 9990 and reaches CTRL_PRIMARY. No further action needed unless a future audit wants to correct the historical claim in clusterconfig-schema-split's requirements.md/design.md that pre-spec single-node startup was previously working — it was not, for an unrelated reason (myapp_run's listener-open/config-load ordering).",
|
||||
"root_cause": "Discovered while independently reviewing clusterconfig-schema-split task 5.3 by building and running the actual pre-spec baseline (commit 94f50ce) for comparison. Single-node startup (no --peers) was ALREADY broken before this spec began: myapp_run() calls cluster_open_listener() before the primary config (cluster_config) is loaded from disk, so the pre-spec fallback branch (cluster_config->port, only reachable when cluster_config != NULL) always hit its else branch and returned -EINVAL, unconditionally, for every zero-flag single-node start. This invalidates part of clusterconfig-schema-split's premise (requirements.md's Introduction claimed cluster_config->port was 'the sole live port-sourcing mechanism for single-node deployments' and 'single-node controller startup SHALL continue to work exactly as it does today' \u2014 in reality it did not work today). Not caused by, or a regression from, clusterconfig-schema-split's changes \u2014 task 2.1's port-resolution rewrite (commit 1229f9a) incidentally fixed this as a side effect, since its hardcoded-default fallback no longer depends on cluster_config being loaded.",
|
||||
"fix": "Not fixed as its own change \u2014 already incidentally repaired by clusterconfig-schema-split task 2.1 (cluster_open_listener now falls back to a hardcoded XCE_CONTROLLER_DEFAULT_PORT constant instead of an unloaded cluster_config->port). Live-verified post-fix: single-node startup with no --peers now correctly binds port 9990 and reaches CTRL_PRIMARY. No further action needed unless a future audit wants to correct the historical claim in clusterconfig-schema-split's requirements.md/design.md that pre-spec single-node startup was previously working \u2014 it was not, for an unrelated reason (myapp_run's listener-open/config-load ordering).",
|
||||
"tags": [
|
||||
"controller",
|
||||
"startup",
|
||||
|
|
@ -13624,6 +13637,121 @@
|
|||
],
|
||||
"related_bugs": [],
|
||||
"occurrences": 1,
|
||||
"last_seen": "2026-07-20"
|
||||
"last_seen": "2026-07-20",
|
||||
"gitea_issue": 27
|
||||
},
|
||||
{
|
||||
"id": "bug-1458",
|
||||
"timestamp": "2026-07-22T03:22:00Z",
|
||||
"error_message": "tools/xce-build.sh: line 134: pip: command not found (inside nix develop ./src, running the new `xceadmin` build case, exit 127)",
|
||||
"file": "src/nixSupport/xce.nix",
|
||||
"root_cause": "admin-config-tool task 1.3 added python3Packages.{pycapnp,pyyaml,jsonschema,click,pytest,ruff} to xce.nix nativeBuildInputs per brief.md's Nix Environment section, but that list (copied verbatim from brief.md) omits python3Packages.pip. None of those packages transitively pull in a `pip` executable on PATH in a nix devShell built this way, so `pip install -e .` in the new xce-build.sh `xceadmin)` case failed immediately with command-not-found the first time it was actually exercised end-to-end inside `nix develop ./src`.",
|
||||
"fix": "Added python3Packages.pip to xce.nix nativeBuildInputs alongside the other python3Packages.* additions. Verified via `nix develop ./src --command bash -c 'which pip; pip --version'`.",
|
||||
"tags": [
|
||||
"nix",
|
||||
"xceadmin",
|
||||
"python",
|
||||
"pip",
|
||||
"xce-build",
|
||||
"admin-config-tool",
|
||||
"task-1.3"
|
||||
],
|
||||
"related_bugs": [],
|
||||
"occurrences": 1,
|
||||
"last_seen": "2026-07-22"
|
||||
},
|
||||
{
|
||||
"id": "bug-1459",
|
||||
"timestamp": "2026-07-22T03:45:00Z",
|
||||
"error_message": "pip install -e . inside `nix develop ./src` fails: \"error: externally-managed-environment ... This command has been disabled as it tries to modify the immutable /nix/store filesystem\" (PEP 668)",
|
||||
"file": "src/tools/xce-build.sh",
|
||||
"root_cause": "The `xceadmin)` case (admin-config-tool task 1.3) ran bare `pip install -e .`/`pip install .` against the nix-provided python3 directly, matching brief.md's harness sketch. But nixpkgs' python3 site-packages lives under the read-only /nix/store, and nixpkgs patches pip to refuse writes there (PEP 668 externally-managed-environment guard) even with --break-system-packages in some configurations. brief.md's sketch was never actually exercised end-to-end against a real nix devShell before this task, so the guard was never hit.",
|
||||
"fix": "Changed the `xceadmin)` case to create a throwaway venv (`$XCEADMIN_DIR/.venv`, recreated fresh every invocation) via `python3 -m venv --system-site-packages`, which inherits the nix-provided pycapnp/pyyaml/jsonschema/click/pytest (so pip never needs to rebuild those heavy binary deps from PyPI) while giving pip a normal writable site-packages to install xceadmin itself into. All subsequent commands (pip install, pytest) now run via $VENV_DIR/bin/pip and $VENV_DIR/bin/python. Verified end-to-end for both the default (editable) and release (pinned) profiles.",
|
||||
"tags": [
|
||||
"nix",
|
||||
"xceadmin",
|
||||
"python",
|
||||
"pip",
|
||||
"pep668",
|
||||
"externally-managed-environment",
|
||||
"xce-build",
|
||||
"admin-config-tool",
|
||||
"task-1.3"
|
||||
],
|
||||
"related_bugs": [
|
||||
"bug-1458"
|
||||
],
|
||||
"occurrences": 1,
|
||||
"last_seen": "2026-07-22"
|
||||
},
|
||||
{
|
||||
"id": "bug-1460",
|
||||
"timestamp": "2026-07-22T03:52:00Z",
|
||||
"error_message": "Under `xce-build.sh xceadmin release` (pinned, non-editable install), the installed xcecommon package in site-packages has no schema_files/ directory at all \u2014 controller.capnp/c.capnp/JSON schemas are silently dropped from the wheel",
|
||||
"file": "src/xceadmin/pyproject.toml",
|
||||
"root_cause": "pyproject.toml had no [tool.setuptools.package-data] entry for xcecommon, so setuptools' default wheel build only includes *.py files. The xce-build.sh sync step correctly copies controller.capnp/c.capnp/*.schema.json into src/xcecommon/schema_files/ in the SOURCE tree, but `pip install .` (non-editable) builds a wheel from that source tree and, without package-data config, drops every non-.py file. An editable install (`pip install -e .`) never surfaces this because it resolves imports straight into the checked-out source tree, bypassing wheel packaging entirely \u2014 exactly the gap design.md's Testing Strategy 'Unit \u2014 schema bundling' note warned only a release-profile test run could catch (Requirement 5.5).",
|
||||
"fix": "Added [tool.setuptools.package-data] xcecommon = [\"schema_files/*.capnp\", \"schema_files/json/*.schema.json\"] to src/xceadmin/pyproject.toml. Verified: after `xce-build.sh xceadmin release`, site-packages/xcecommon/schema_files/ now contains controller.capnp, c.capnp, and json/*.schema.json, byte-identical to the synced source copies.",
|
||||
"tags": [
|
||||
"xceadmin",
|
||||
"python",
|
||||
"packaging",
|
||||
"setuptools",
|
||||
"package-data",
|
||||
"wheel",
|
||||
"admin-config-tool",
|
||||
"task-1.3",
|
||||
"requirement-5.5"
|
||||
],
|
||||
"related_bugs": [
|
||||
"bug-1458",
|
||||
"bug-1459"
|
||||
],
|
||||
"occurrences": 1,
|
||||
"last_seen": "2026-07-22"
|
||||
},
|
||||
{
|
||||
"id": "bug-1461",
|
||||
"timestamp": "2026-07-22T02:00:00Z",
|
||||
"error_message": "pycapnp / capn-c: setting UpgradeConfigRequest.sha256 or .bytes raises capnp.lib.capnp.KjException: 'expected reader.type == STRUCT [6 == 10]; Value type mismatch' -- and the generated C accessors (UpgradeConfigRequest_get_sha256 etc.) were typed Data_ptr instead of a real byte blob",
|
||||
"file": "src/schema/controller.capnp",
|
||||
"root_cause": "controller.capnp declares `struct Data $C.mapname(\"xce_data_t\")` at line 355 (a tagged union of OPCode_get query-result shapes: schedjobs/schedworkers/jobs/workers/resources/resvals/jobArray). Cap'n Proto resolves unqualified type names lexically within a file, so this local struct SHADOWS the Cap'n Proto builtin `Data` blob type for every later `: Data` field declaration in the same file -- confirmed against the real compiled schema via `capnp compile -o-` + `capnp decode`, and against the actual capnpc-c generated C output (fields typed `Data_ptr`/`XceData_ptr`, a struct-pointer wrapper, using `capn_getp`/`encode_Data_ptr`/`decode_Data_ptr`/`free_Data_ptr`, instead of the correct `capn_data` blob type + `capn_get_data`). Affected 7 fields across 6 structs, several HA-critical: UpgradeConfigRequest.sha256/.bytes, ReplConfigReply.sha256/.bytes, ReplConfigPushRequest.sha256/.bytes, ReplEnvelope.payload (WAL replication envelope), SnapshotTransfer's chunk payload, WalCatchupEntry.payload/.batchPayloads (WAL catchup), CtrlHelloRequest.key. Production C code had already worked around this for years via hand-rolled raw capn_ptr manipulation (see request.c's own comment: \"Pull sha256 and bytes via raw capn_list8 access (NOT decode_Data which would corrupt via xce_data_t)\") -- the bug was known-and-routed-around, never fixed at the root, because nothing before xceadmin's pycapnp-based dynamic reflection needed the generated codec/accessors to work correctly for these fields (the C raw-workaround functions never called them). Two fields, `getdata` (RequestReply's OPCode_get reply payload) and `pushmsg` (Request's generic OPCode_push payload), correctly and intentionally referenced the LOCAL struct Data all along -- their surrounding dispatch code (Data_data_jobArray/jobs/workers/etc. switches in apiserver.c/opget.c/sched.c/handler.c/xceapi.c/helper.c) depends on it.",
|
||||
"fix": "Renamed `struct Data` to `struct XceData` in controller.capnp (kept `$C.mapname(\"xce_data_t\")` so the generated C typedef name is unchanged), and explicitly repointed `getdata`/`pushmsg` at `XceData` by name (since removing the shadow means bare `Data` now correctly means the builtin blob, which those two fields do NOT want). Updated every derived-identifier reference (`Data_ptr`->`XceData_ptr`, `Data_data_<variant>`->`XceData_data_<variant>`, `struct Data`->`struct XceData`, `read_/write_/new_/encode_/decode_/free_Data(_ptr)?`->the `XceData` equivalents) across 19 hand-written files spanning controller, lib, scheduler, and the Go apiserver/xcecli CGo bindings (generated controller.capnp.c/.h regenerate automatically, never hand-edited). Fixed 5 call sites in src/lib/request.c (extract_data_bytes's parameter + 4 local variables) that had been declared XceData_ptr but now legitimately receive capn_data from the now-correct UpgradeConfigRequest_get_sha256/_get_bytes/ReplConfigPushRequest_get_sha256/_get_bytes accessors -- a pure type-name swap with zero logic change, since Data_ptr/XceData_ptr and capn_data share the identical {capn_ptr p} memory layout (confirmed: request.c already had a comment noting this exact equivalence). Verified via full rebuild+test of lib (1/1), controller (3/3, including the job-array push regression tests), scheduler (15/15), and the Go apiserver+xcecli backends (all packages green), plus a direct pycapnp round-trip proving UpgradeConfigRequest.sha256/.bytes now encode/decode correctly. Unblocks admin-config-tool task 3.3 (xceadmin.push's push_config()).",
|
||||
"tags": [
|
||||
"capnp",
|
||||
"schema",
|
||||
"controller.capnp",
|
||||
"shadowing",
|
||||
"type-collision",
|
||||
"wal-replication",
|
||||
"snapshot-transfer",
|
||||
"admin-config-tool",
|
||||
"task-3.3",
|
||||
"xceadmin",
|
||||
"cross-component"
|
||||
],
|
||||
"related_bugs": [],
|
||||
"occurrences": 1,
|
||||
"last_seen": "2026-07-22"
|
||||
},
|
||||
{
|
||||
"id": "bug-1462",
|
||||
"timestamp": "2026-07-23T03:04:50.000Z",
|
||||
"error_message": "ctrl-3 conf/ empty after HA failover deploy at /tmp/xce-ha-deploy -- config never replicated, but WAL/jobs replicated fine",
|
||||
"file": "src/controller/ha.c",
|
||||
"root_cause": "Post-election baseline for ha->committed_config_tag (raft_cb_become_leader, ha.c:1279, set to safe_tag from ha_compute_safe_committed_lsn, ha.c:744-802) is computed as the MAJORITY-SAFE FLOOR across granted voters' self-reported tags (median of sorted tags, same conservative math used for WAL safe_committed_lsn). On a cluster where no admin config push has ever happened live (deploy-ha.sh places cluster.bin on disk pre-boot, not via a live push), every peer voter reports tag=0 except the newly-elected primary itself (self_tag=nonzero, e.g. 860cfd4f59ef9381) -- so the majority-floor computation picks 0, even though the primary demonstrably has a real, valid, currently-loaded config. This 0-floor is CORRECT for WAL LSN safety (a leader must not assume unacknowledged entries are durable) but WRONG for config_tag: a node's own actively-loaded config is not speculative the way an unacknowledged WAL entry is.\n\nEffect: the ONLY path that successfully pushes config after promotion is the one-shot, promotion-instant fan-out (ha.c:1583-1602) to vote endpoints still connected AT THAT EXACT MOMENT (ectx->votes[i].ep != NULL) -- it correctly bypasses committed_config_tag and reads myconf->config_version_tag directly. Any standby that is NOT connected at that instant (a late joiner reconnecting seconds later via on_standby_connected, or any future reconnect/ restart for the rest of the term) relies entirely on the ONGOING heartbeat-driven decision loop (ha_dispatch_repl_action_for_standby -> ha_evaluate_repl_action, ha.c:3633-3663 / 3194-3199: 'if standby_tag < committed_tag -> HA_REPL_PUSH_CONFIG'). Since committed_config_tag is permanently floored at 0 for the rest of the term (nothing advances it except a live admin xceadmin config push via config_commit_change -> push_config_to_standbys, config_repl.c:1524/1556-1558, which never happens in a normal deploy-ha.sh-deployed cluster), standby_tag(0) < committed_tag(0) is false forever -> HA_REPL_PUSH_CONFIG never fires for that standby. Meanwhile WAL/job replication is unaffected since it correctly tracks committed_lsn (a genuinely-advancing value, set from real job commits), not the broken config_tag floor -- exactly matching the observed symptom (jobs replicate, config does not).\n\nReproduced live: /tmp/xce-ha-deploy, peers ctrl-1=9901/ctrl-2=9902/ctrl-3=9903 (src/build.dbg/controller/xce_controller). ctrl-1 promoted primary at term=2 via PreVote failover (ha_compute_safe_committed_lsn logged safe_committed_lsn=0 safe_config_tag=0 'from 2 granted voters'). ctrl-2 (already-connected vote ep[0]) received handle_repl_config_push 45ms after promotion (one-shot path). ctrl-3 connected 3s later as 'late-joiner standby peer[2]' (ha.c on_standby_connected), got WAL-caught-up correctly (ha_process_standby_state: standby[2] converged: config_tag=0 applied_lsn=1 committed_tag=0 committed_lsn=1) but NEVER received a config push -- ctrl-1's full log has zero further push_config/repl_config lines after promotion, and ctrl-3's log stays stuck at 'CTRL_STANDBY -- waiting for primary to connect and push config'. ctrl-3/conf/ is empty on disk (no cluster.bin.*, no current pointer) while ctrl-1/ctrl-2 both have cluster.bin.860cfd4f59ef + current.",
|
||||
"fix": "FIXED 2026-07-23. Implemented candidate direction (a): added ha_promotion_config_tag_floor(safe_tag, self_tag) (ha.h/ha.c, declared beside ha_promotion_truncate_floor) returning safe_tag > self_tag ? safe_tag : self_tag -- mirrors bug-1060's WAL-truncation clamp pattern but for config_tag instead of LSN. raft_cb_become_leader (ha.c ~1279) now clamps committed_config_tag to this floor instead of the raw majority-safe tag, so a newly-elected primary's own actively-loaded config tag is never dropped back to a stale majority-of-zero baseline. RED test added: test_promotion_config_tag_never_drops_below_own_loaded_config (testsuite/test_ha_election.c), covers the exact bug-1462 repro (safe_tag=0, self_tag=0x860cfd4f59ef9381 -> floor=self_tag), the equal case, safe_tag-above-self_tag case, and fresh-boot (0,0)->0. Unit suite green 977/977, zero regressions. Live regression: 20-round sequential soak (xce-test-ha, ~/tmp/xce-ha-soak-seq) PASS -- 63 jobs, zero job loss, all 3 nodes (ctrl-1/ctrl-2/ctrl-3) cycled through leadership across 20 promotions, 9m00.8s wall-clock. 20-round chaotic (overlapping-kill) soak (~/tmp/xce-ha-soak-chaos) also PASS -- VERDICT mode=chaotic rounds=20 jobs=57 committed_divergence=0 committed_job_loss=0 excluded_bug854_discovery=8 excluded_bug924_fdatasync=0 result=PASS (the 8 excluded bug-854 hits are client primary-discovery misses during overlapping-kill windows, not server-side loss). Confirms the fix holds under both normal and double-fault-within-reconvergence-window failover.",
|
||||
"tags": [
|
||||
"ha",
|
||||
"config-replication",
|
||||
"late-joiner",
|
||||
"committed_config_tag",
|
||||
"raft-promotion",
|
||||
"auto-detected"
|
||||
],
|
||||
"related_bugs": [
|
||||
"bug-1060"
|
||||
],
|
||||
"occurrences": 1,
|
||||
"last_seen": "2026-07-23T03:29:19.000Z"
|
||||
}
|
||||
]
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue