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 +61 -0
- package/ocdiag/__init__.py +1 -1
- package/ocdiag/core/context.py +30 -19
- package/package.json +1 -1
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
|
package/ocdiag/__init__.py
CHANGED
package/ocdiag/core/context.py
CHANGED
|
@@ -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
|
|
96
|
-
|
|
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
|
|
100
|
-
``since_ms``; in the ``all``
|
|
101
|
-
|
|
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
|
|
104
|
-
|
|
105
|
-
|
|
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:
|
|
111
|
-
``limit_per_file is None
|
|
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)``.
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
it
|
|
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 —
|
|
143
|
-
#
|
|
144
|
-
#
|
|
145
|
-
#
|
|
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