openclaw-diag-cli 1.10.1 → 1.10.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,66 @@
1
1
  # Changelog
2
2
 
3
+ ## v1.10.3 — regression test: full-cache reuse conclusion-equivalence (2026-06-16)
4
+
5
+ Test-only release. No runtime change — the shipped package is byte-identical
6
+ to v1.10.2 (the `files` whitelist excludes `tests/`). Tagged to mark the
7
+ correctness verification of the v1.10.2 prefilter cache-reuse path.
8
+
9
+ ### Tests
10
+ - `tests/test_cache_prefilter_reuse.py`: added
11
+ `test_top30_selection_identical_across_modes_when_enough_dated`. Stages 35
12
+ dated runs inside the 7d window plus 5 undated runs in an old-mtime file
13
+ (which the prefilter disk scan drops but the full-cache superset keeps), then
14
+ proves the top-30 selection (sorted by `started_ts_ms` desc) is IDENTICAL
15
+ between the full-cache-superset and prefilter-disk modes — so `plugin_diag`'s
16
+ `latest`/`recent` conclusions are mode-invariant and the only delta is
17
+ undated runs that never reach the top-30. Confirms full-cache reuse causes
18
+ no data inaccuracy. Suite: 199 passed, 1 skipped.
19
+
20
+
21
+ ## v1.10.2 — prefilter requests reuse an existing full-scan cache (2026-06-16)
22
+
23
+ Performance + docs fix for the `all` command. No behavior change to output
24
+ contents; pure cache-reuse optimization plus a stale-comment correction.
25
+
26
+ ### `collect_runs` prefilter reuse
27
+
28
+ Before: in `openclaw-diag all`, `configuration` (and `performance`) populate
29
+ the full-scan trajectory cache early, yet `plugin_diag`'s 7d `mtime_prefilter`
30
+ request still hit disk for a fresh windowed scan (~540ms observed) because the
31
+ superset-reuse path explicitly excluded `mtime_prefilter=True` requests.
32
+
33
+ Now: any windowed request (`since_ms` set, no per-file limit) — INCLUDING
34
+ `mtime_prefilter=True` — is served IN MEMORY from an EXISTING full-scan cache
35
+ when one is present. A prefilter request only falls through to the real
36
+ prefilter DISK scan when NO full cache exists (the standalone fast path). When
37
+ served from the full cache the result is the superset of a prefilter disk scan
38
+ (undated runs in old-mtime files are kept); all current windowed consumers
39
+ tolerate that (gateway counts dated runs only; plugin_diag takes the top-30
40
+ dated runs).
41
+
42
+ Measured: `plugin_diag` inside `all` dropped from ~540ms to ~100ms. Standalone
43
+ `plugin_diag` is unchanged (still does its 7d/30d prefilter disk scan).
44
+
45
+ Zero-deviation note: the displayed scope count still equals exactly what was
46
+ consumed in each run. The count may legitimately differ between modes
47
+ (`all` reuses the full-cache superset; standalone uses the prefilter subset),
48
+ but the `7d` window token is identical and each displayed count matches its
49
+ own scan.
50
+
51
+ ### Fixes
52
+ - `ocdiag/core/context.py`: corrected the `collect_runs` docstring — `plugin_diag`
53
+ is no longer listed as a no-window caller (it has been a windowed 7d→30d
54
+ prefilter caller since v1.10.0); documented the new prefilter-reuse path and
55
+ the superset semantics.
56
+
57
+ ### Tests
58
+ - New `tests/test_cache_prefilter_reuse.py` (pytest): proves a prefilter request
59
+ reuses an existing full cache (same Run objects, no disk re-scan) and that a
60
+ prefilter request with no full cache does a real disk scan without fabricating
61
+ a full-scan cache entry. Suite: 198 passed, 1 skipped.
62
+
63
+
3
64
  ## v1.10.1 — data_scope zero-drift: derive window/counts from actual scan (2026-06-16)
4
65
 
5
66
  A correctness fix on top of v1.10.0. The owner's hard requirement: the
@@ -1,3 +1,3 @@
1
1
  """ocdiag — shared library for openclaw-diag-cli scripts."""
2
2
 
3
- __version__ = "1.10.1"
3
+ __version__ = "1.10.3"
@@ -92,31 +92,36 @@ class DiagContext:
92
92
  ) -> List[Any]:
93
93
  """Memoized ``trajectory.collect_runs`` keyed on its arg tuple.
94
94
 
95
- The five no-window callers (performance.py x2, configuration,
96
- plugin_diag, run_health) all share key
95
+ The no-window callers (performance.py x2, configuration,
96
+ run_health) all share key
97
97
  ``(None, None, False, False)`` — the first call populates the cache,
98
98
  the rest are hits. Windowed callers (gateway 24h,
99
- cron_jobs/recent_errors 7d, environment 14d) each have a distinct
100
- ``since_ms``; in the ``all`` command they reuse the cached full scan
101
- via the superset path below (zero disk I/O). ``populate_raw`` MUST be
99
+ cron_jobs/recent_errors 7d, environment 14d, plugin_diag 7d→30d via
100
+ ``mtime_prefilter``) each have a distinct ``since_ms``; in the ``all``
101
+ command they reuse the cached full scan via the superset path below
102
+ (zero disk I/O), prefilter requests included. ``populate_raw`` MUST be
102
103
  in the key — a raw-less cached entry would silently miss raw fields
103
- for a raw caller. ``mtime_prefilter`` is keyed too because a
104
- prefiltered result is a SUBSET (drops undated runs in old files) and
105
- must not pollute the complete-set keys.
104
+ for a raw caller. ``mtime_prefilter`` is keyed too: a fresh prefilter
105
+ DISK scan is a SUBSET (drops undated runs in old files) and must not
106
+ pollute the complete-set keys; a prefilter request served from the
107
+ full cache instead yields the superset (keeps undated runs).
106
108
 
107
109
  Two reuse paths, in order:
108
110
 
109
111
  1) Exact key hit → return shallow copy.
110
- 2) Superset reuse: a windowed (``since_ms`` is not None,
111
- ``limit_per_file is None``, ``mtime_prefilter=False``) request,
112
+ 2) Superset reuse: any windowed request (``since_ms`` is not None,
113
+ ``limit_per_file is None``), REGARDLESS of ``mtime_prefilter``,
112
114
  when a full-scan entry under
113
115
  ``(None, None, populate_raw, False)`` already exists, is served
114
116
  by filtering that cached list IN MEMORY using the EXACT predicate
115
117
  from ``trajectory.collect_runs``: keep iff
116
- ``(not r.started_ts_ms) or (r.started_ts_ms >= since_ms)``. The
117
- filtered subset is identical (same Run objects, set-equal) to a
118
- fresh ``trajectory.collect_runs(files, since_ms=...)``. We cache
119
- it under the exact requested key to dedup repeat lookups.
118
+ ``(not r.started_ts_ms) or (r.started_ts_ms >= since_ms)``. For a
119
+ non-prefilter request the filtered list is set-equal to a fresh
120
+ ``trajectory.collect_runs(files, since_ms=...)``; for a prefilter
121
+ request it is a SUPERSET of the prefilter disk scan (keeps undated
122
+ runs the mtime floor would have skipped). We cache it under the
123
+ exact requested key to dedup repeat lookups. A prefilter request
124
+ only reaches Path 3 when NO full scan is cached (standalone path).
120
125
  3) Disk scan fall-through. When ``mtime_prefilter=True`` and
121
126
  ``since_ms`` is not None, only files whose mtime is at or after
122
127
  ``since_ms - _MTIME_PREFILTER_GRACE_MS`` are scanned (the grace
@@ -139,14 +144,20 @@ class DiagContext:
139
144
  if cached is not None:
140
145
  return list(cached)
141
146
 
142
- # Path 2: superset reuse — a windowed query (no per-file limit, no
143
- # prefilter) can be served from a cached full scan with the same
144
- # ``populate_raw``. Predicate mirrors trajectory.collect_runs exactly,
145
- # INCLUDING keeping undated runs (started_ts_ms == 0).
147
+ # Path 2: superset reuse — any windowed query (no per-file limit) can
148
+ # be served from a cached full scan with the same ``populate_raw``,
149
+ # INCLUDING prefilter requests. We only reuse an EXISTING full cache;
150
+ # a prefilter request with no full cache falls through to the Path 3
151
+ # fast disk scan (the standalone path). When a prefilter request is
152
+ # served here it yields the SUPERSET of a prefilter disk scan (keeps
153
+ # undated runs the mtime floor would skip) — all current windowed
154
+ # consumers tolerate that (gateway counts dated runs only; plugin_diag
155
+ # takes the top-30 dated runs). Predicate mirrors
156
+ # trajectory.collect_runs exactly, INCLUDING keeping undated runs
157
+ # (started_ts_ms == 0).
146
158
  if (
147
159
  since_ms is not None
148
160
  and limit_per_file is None
149
- and not mtime_prefilter
150
161
  ):
151
162
  full_key = (None, None, populate_raw, False)
152
163
  full_cached = self._trajectory_cache.get(full_key)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "openclaw-diag-cli",
3
- "version": "1.10.1",
3
+ "version": "1.10.3",
4
4
  "description": "OpenClaw observer-only diagnostic CLI. Zero-dependency Python scripts wrapped in Node for npx-friendly install.",
5
5
  "keywords": [
6
6
  "openclaw",