Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
88 commits
Select commit Hold shift + click to select a range
34ccb2e
WL-0MU2GCNKT004W6KK: Implementation complete
Oct 17, 2026
92b4d1e
WL-0MV6C6SLB005HX7B: Implementation complete
Oct 18, 2026
d5c8499
test(herdr): request-priority mapping & dispatch env specs (test-firs…
Oct 19, 2026
ba54612
test(headings): In Review heading background escape sequence (test-fi…
Oct 18, 2026
521d267
WL-0MVF3Q0QQ0001I2P: Implementation complete
Oct 19, 2026
b454fc5
WL-0MVD2OFRK000JA2Q: Implementation complete
Oct 19, 2026
8c0702b
WL-0MVD2OFRK000JA2Q: Implementation complete
Oct 19, 2026
5190a01
WL-0MVF3PZNY003413F: Implementation complete
Oct 19, 2026
f1914ea
WL-0MVF3Q1ZB0038IPA: Implementation complete
Oct 19, 2026
1def93a
WL-0MVF3Q2YC003RJPF: Implementation complete
Oct 19, 2026
d6a89a1
WL-0MVF3Q3VL000UNCN: Implementation complete
Oct 19, 2026
2909014
WL-0MVF3Q5W8006KVY2: Implementation complete
Oct 19, 2026
d1c9e46
WL-0MVF3Q4X5001FOXV: Implementation complete
Oct 19, 2026
66c957e
WL-0MVFRAENV0074IHJ: Implementation complete
Oct 19, 2026
4444af0
WL-0MVFE0T0M009ZCPM: Add RED-witness specs for depth-aware audit batc…
Oct 19, 2026
eb1f2e9
WL-0MVFRALLB0065UIW: Implementation complete
Oct 19, 2026
120d258
WL-0MVFRR98A008MM19: Implementation complete
Oct 19, 2026
3937ee2
WL-0MVFE1AB0002PEPN: Implementation complete
Oct 20, 2026
1870c85
WL-0MVFRRAXD001E7AN: Implementation complete
Oct 20, 2026
458430f
WL-0MVFE1BTB0084T17: Implementation complete
Oct 20, 2026
6e368bb
WL-0MVFRRCP7007UWS7: Implementation complete
Oct 20, 2026
896d8ad
WL-0MVFRRGGC001IQK1: Implementation complete
Oct 20, 2026
b60faeb
WL-0MVFE1EWW004VAW2: Implementation complete
Oct 20, 2026
bec96e2
chore(standup): add standup report 2026_10_20.md
Oct 20, 2026
956b79d
WL-0MVFRRKKN00544PQ: Implementation complete
Oct 20, 2026
30c8564
WL-0MVFX70SB000YRQH: Implementation complete
Oct 20, 2026
098a3d2
WL-0MVFX6404003TE2E: Implementation complete
Oct 20, 2026
31bacce
WL-0MVFE1DD8000D8T2: Implementation complete
Oct 20, 2026
72bdd33
chore(standup): add standup report 2026_10_20.md
Oct 20, 2026
1abb001
WL-0MVFRRQ9W003KEFL: Implementation complete
Oct 20, 2026
4bdc120
WL-0MVFE1GQF003LLSX: Implementation complete
Oct 20, 2026
4a0e070
WL-0MVFRREMZ0085G7I: Implementation complete
Oct 20, 2026
50c7508
WL-0MVFRRMX3003UPP3: Implementation complete
Oct 20, 2026
d31946c
WL-0MVFE1IRB0004X1U: Implementation complete
Oct 20, 2026
e165b32
WL-0MVFRROLM002K98B: Implementation complete
Oct 20, 2026
57dbbf4
WL-0MVFRRS2I000G93J: Implementation complete
Oct 20, 2026
cf9a3bc
WL-0MVFRRTY5001KTNH: Implementation complete
Oct 20, 2026
833b52b
WL-0MVGC6JVP00812DS: Implementation complete
Oct 20, 2026
388ceac
WL-0MVGU4S58003IRXV: Implementation complete
Oct 20, 2026
a0ec6f9
WL-0MVH2T0ZV006KIOU: Implementation complete
Oct 20, 2026
93ecb0e
WL-0MVGU7H24009G8II: Implementation complete
Oct 21, 2026
1648fa1
WL-0MVF9JJUH0077OB8: Implementation complete
Oct 21, 2026
598cdea
WL-0MVGUA9EY003XFAD: Docs update — Line-3 state table, model_select s…
Oct 21, 2026
80511a3
Merge branch 'dev' of github.com:TheWizardsCode/ContextHub into dev
Oct 21, 2026
92f3a63
WL-0MVH751AJ009R4SN: Implementation complete
Oct 21, 2026
6b93846
WL-0MVH44JRR000A23U: Implementation complete
Oct 21, 2026
4e2c648
WL-0MVH47YF300087AQ: Implementation complete
Oct 21, 2026
c927bc2
WL-0MVH75NY3002TTX9: Implementation complete
Oct 21, 2026
104103b
WL-0MVHSZQVX0000T6P: consume truthful per-slot capacity (lease_state …
Oct 21, 2026
b4d5e0d
WL-0MVFNMSRW002FI6B: AC1 targets accepted at measured floor (700 ms /…
Oct 21, 2026
32b8945
WL-0MVI0HH740065Z2T: query-set selector + seeded fixture for consolid…
Oct 21, 2026
e740d6d
WL-0MVHSZR9C0012NQY: Implementation complete
Oct 21, 2026
0f246fa
WL-0MVHSZRZQ00482QX: Implementation complete
Oct 21, 2026
c8d8197
WL-0MVI0HX58009JJRF: consolidated wl worklist command + shared browse…
Oct 21, 2026
e1cedba
WL-0MVI0IS6Y0028KTO: serve wl worklist from the read cache as one entry
Oct 21, 2026
6db386b
WL-0MVI0IT4S0070G78: one consolidated wl worklist read per default-vi…
Oct 21, 2026
7e27a4d
WL-0MVI0IW8V007DFM6: default-view doRefresh drives one consolidated w…
Oct 21, 2026
5926464
WL-0MVI0IX6E000N6IZ: document the consolidated worklist read with mea…
Oct 21, 2026
5c462c3
WL-0MVII17N3003FJWT: spawn the CLI through the bundle in the last dis…
Oct 21, 2026
f8e1b8d
chore(standup): add standup report 2026_10_22.md
Oct 22, 2026
09ac2db
SA-0MUJNFF3K009BF03: wl sync never downgrades a newer audit to an old…
Oct 22, 2026
8ab3139
WL-0MVJV2N3A001LE5G: Implementation complete
Oct 22, 2026
457adaf
WL-0MVJV2NNG00771C6: F2 profile of remaining Herdr refresh cost drivers
Oct 22, 2026
213a96b
WL-0MVK5SWZE00254Y7: Implementation complete
Oct 23, 2026
9be5923
WL-0MVJV2O7H003HY9N: Implementation complete
Oct 23, 2026
0449922
WL-0MVJV2ORY002MNFF: Implementation complete
Oct 23, 2026
1b68def
WL-0MVJV2PC2008PY64: Implementation complete
Oct 23, 2026
d982d1a
chore(standup): add standup report 2026_10_23.md
Oct 23, 2026
a8d79cf
WL-0MVJV2PX4005JH8D: Implementation complete
Oct 23, 2026
65fd4fd
WL-0MVKNC2N50025HXE: Implementation complete
Oct 23, 2026
3ce1171
WL-0MVKVJYV6008SL9G: Implementation complete
Oct 23, 2026
5fbd5f1
WL-0MVJV2QHO003K6H3: F7 end-to-end parent AC verification report
Oct 23, 2026
d09fd2c
WL-0MVJV2QHO003K6H3: Implementation complete
Oct 23, 2026
af653c5
SA-0MVKWV26Y000G3B9: reproduce the claim-revert (sync reverts a held …
Oct 23, 2026
4eb0cc6
SA-0MVKWV2V2006JC8E: TTL-bounded monotonic claim-hold guard
Oct 23, 2026
3709688
SA-0MVKWV3IV007W16K: one store per repository for worktrees
Oct 23, 2026
478ff6e
SA-0MVKWV4UH003D78K: document claim-hold and one-store-per-repo rules
Oct 23, 2026
558c172
WL-0MVJV2QHO003K6H3: fix herdr-group tests after AC enforcement and e…
Oct 23, 2026
ff9bc11
WL-0MVJV2QHO003K6H3: bound queued-read timeouts and de-flake load-sen…
Oct 23, 2026
0fb317b
WL-0MVJV2QHO003K6H3: skip the absolute event-loop reading on an overl…
Oct 23, 2026
bc35cec
WL-0MVJV2QHO003K6H3: host-load-aware gating for absolute event-loop r…
Oct 23, 2026
425cf66
WL-0MVJV2QHO003K6H3: validate absolute timing readings after measurem…
Oct 23, 2026
4b313f2
WL-0MVJV2QHO003K6H3: gate lock-contention timing readings on a quiet …
Oct 23, 2026
0dad613
WL-0MVJV2QHO003K6H3: de-flake the auto-sync isolation gates for a sha…
Oct 23, 2026
9705863
Bump version to v1.0.23
Oct 23, 2026
3515088
Update CHANGELOG.md for v1.0.23
Oct 23, 2026
7cda682
Merge origin/dev into main (automated)
Oct 23, 2026
6268813
Regenerate derived version files for v1.0.23
Oct 23, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 4 additions & 6 deletions .pi/skills/heartbeat/scripts/heartbeat.py
Original file line number Diff line number Diff line change
Expand Up @@ -113,21 +113,19 @@ def check_queue():
return "No items in completed/in_review queue."

if count < 10:
# Sparse queue — hold the next item for the producer (assign to the
# producer-hold identity; the assignee hold replaced the removed
# producer-review flag).
# Sparse queue — flag next item for producer review
next_data = run_wl(['next', '--json'])
next_item = next_data.get('workItem')
if next_item:
item_id = next_item['id']
item_title = next_item.get('title', item_id)
run_wl(['update', item_id, '--assignee', 'Map', '--json'])
run_wl(['update', item_id, '--needs-producer-review', 'true', '--json'])
return (
f"Held {item_title} ({item_id}) for the producer.\n"
f"Flagged {item_title} ({item_id}) for producer review.\n"
f"Queue has {count} completed/in_review items (below threshold of 10)."
)
else:
return "No next item found to hold for the producer."
return "No next item found to flag for review."
else:
# Full queue — find first non-ready item by sortIndex
items_sorted = sorted(items, key=lambda x: x.get('sortIndex', 0) or 0)
Expand Down
5 changes: 5 additions & 0 deletions .pi/skills_extensions/test/extension.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"types": {
"herdr": "npm --silent test -- packages/herdr/src"
}
}
8 changes: 7 additions & 1 deletion .pi/test-config.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,11 @@
"npm --silent test -- tests/cli",
"npm --silent test -- tests/unit"
],
"timeoutPerCommand": 1800
"timeoutPerCommand": 1800,
"groups": {
"herdr": {
"commands": ["npm --silent test -- packages/herdr/src"],
"paths": ["packages/herdr/**"]
}
}
}
27 changes: 27 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,32 @@
# Changelog

## v1.0.23 (2026-10-23)
> **Release focus:** This release focuses on performance and responsiveness across the app, with faster `wl` commands, quicker tests, and lower CPU use in Herdr panes and the Work Items pane. It also improves GPU scheduling so downtime tasks start promptly and run one at a time, ensures your own dispatched work jumps ahead of background tasks, and fixes several reliability issues including late-joining agent status, test gate failure messages, and long-running AI sessions blocking overnight work.
### Features
- `wl` commands now start much faster and use less CPU, keeping your host responsive. (WL-0MVFNMSRW002FI6B)
- Downtime tasks now start right away when your GPU has already been idle long enough. (WL-0MVHSZR9C0012NQY)
- Downtime sessions now start one at a time so each gets the full GPU speed instead of waiting in line. (WL-0MVHSZRZQ00482QX)
- Tests now run much faster, so you get quicker feedback and less waiting. (WL-0MVF9JJUH0077OB8)
- Downtime work now starts whenever the local GPU is truly free, instead of waiting on idle reservations. (WL-0MVHSZQVX0000T6P)
- Work you dispatch yourself now reliably jumps ahead of background tasks. (WL-0MVGC6JVP00812DS)
- Herdr panes now refresh with far less CPU load, keeping your machine responsive. (WL-0MVGYLU0S004WZUS)
- Urgent tasks now get faster responses automatically, while background work stays efficient. (WL-0MVE1NZ4J000H5NH)
- Herdr tests can now be run through the official test runner, making it easier to catch bugs before they ship. (WL-0MVGJ4WSS005BMSI)
- Downtime now clears deep review backlogs faster by running several audits per idle window. (WL-0MVEDM8OT007WDRS)
- The In Review section now has a grey background so you can spot it instantly in long lists. (WL-0MUYJ8WJG0087VSU)
- Background refreshes no longer cause brief typing pauses in the Work Items pane. (WL-0MV6C6SLB005HX7B)
### Bug Fixes
- Fixed flaky Blocked By display tests so work item lists render reliably. (WL-0MVFX6404003TE2E)
- Fixes a timing issue so late-joining agents reliably show their green status circle. (WL-0MVFX70SB000YRQH)
- Fixed a test setup issue so version checks now run reliably against the latest build. (WL-0MVH44JRR000A23U)
- Speeds up the test suite so updates reach you faster and more reliably. (WL-0MVH47YF300087AQ)
- Test gate failures now explain why they failed instead of showing an empty message. (WL-0MVGUT787000LNDG)
- Long-running AI sessions can no longer silently block overnight work from running. (WL-0MVKNC2N50025HXE)
- The Work Items pane now stays responsive and updates quickly, even on very large worklogs. (WL-0MVJC1EQX001QR9W)
- Work item freshness checks are now faster and more reliable. (WL-0MVK5SWZE00254Y7)
- The model display now updates instantly when you switch models mid-session. (WL-0MVGEB3IP002V8IB)
- Fixed flaky pane visibility checks so tests behave reliably when run inside a herdr pane. (WL-0MU2GCNKT004W6KK)

## v1.0.22 (2026-10-17)
> **Release focus:** This release focuses on making the worklist clearer and more responsive, with better visibility into blocked items, priorities, review status, and in-progress markers, plus instant refresh and a new help screen for shortcuts. It also improves reliability around audits, quick-create, rejections, and finish-gate so work isn't stranded or interrupted.
### Features
Expand Down
229 changes: 221 additions & 8 deletions CLI.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,112 @@ These options apply to any command:
- `-w, --watch [seconds]` — Rerun the command every N seconds (default: 5).


### Read cache (environment variables)

The read cache serves repeat JSON read queries (`list`/`next`/`show`/`search`/`status`); see
`CONFIG.md` for the full model and the cache-maintenance guidance. Runtime knobs:

- `WL_CACHE_DISABLED=1` — bypass the cache entirely (baseline behaviour).
- `WL_CACHE_DIR=<path>` — override the cache directory (default `$XDG_CACHE_HOME/wl` or `~/.cache/wl`).
- `WL_CACHE_TTL_MS=<n>` — cache-entry TTL safety net (default 30000).
- `WL_CACHE_DEBUG=1` — log cache hits, misses and invalidation reasons to stderr.
- `WL_STATE_MAX_FILES=<n>` — bound on per-worklog-dir state counters (default 1000).
- `WL_STATE_TTL_MS=<n>` — prune counters untouched for this long (default 604800000, 7 days).

Maintenance: `wl doctor cache` reports the state directory (file count, bytes,
stale-by-TTL, over-bound) and `wl doctor cache --prune` reclaims it;
`--max-files`/`--ttl-days` override the bound for one run. See
[`CONFIG.md`](CONFIG.md#read-cache-state-boundedness-f9--wl-0mvfrrq9w003kefl).

### Startup architecture (fast path vs heavy graph)

Every `wl` invocation starts in a **thin fast path** (`src/cli.ts`) and only
loads the **heavy graph** (`src/cli-main.ts`: Commander, the command modules,
the plugin loader and the SQLite runtime) when it has to:

| Invocation | What loads |
|---|---|
| `wl --version` / `-V` | `src/version.ts` + the spawn recorder only — the version is printed and the process exits before anything else is imported |
| warm cache hit (`list`/`next`/`show`/`search`/`status` with `--json`) | the fast path prints the cached JSON and exits — no Commander, no command module, no DB, no plugins |
| `wl <command> …` (miss, write, help) | the fast path dynamically imports `cli-main.ts`, which registers commands through a lazy registry (`src/command-registry.ts`) |

The lazy registry loads **only the command being run**; `--help`, bare `wl`,
`wl help <cmd>` and `wl completion <shell>` register the full set because their
output enumerates commands. If a command module fails to import, the CLI logs
one warning and falls back to registering every other command, so a broken
module can never take the whole CLI down.

**Contributor rule — the static import allowlist.** `src/cli.ts` must only
statically import what every invocation needs (`src/argv-normalize.ts`,
`src/spawn-counter.ts`, `src/version.ts`). Anything optional is deferred with
`await import(…)` **and recorded in the budget**. A new module — static or
dynamic — fails `tests/cli/startup-import-budget.test.ts` until the budget is
deliberately regenerated:

```sh
npm run benchmark:wl-startup -- --target src --update-budget
npm run benchmark:wl-startup -- --target dist --update-budget # needs `npm run build`
```

`bench/startup-import-budget.json` records the static boot graph, the fast
path's dynamic entrypoints and their runtime module union, plus the measured
`src`/`dist` baselines and regression headroom. Background and re-run
instructions: [`docs/dev/wl-startup-import-budget.md`](docs/dev/wl-startup-import-budget.md).

### Spawn instrumentation and CPU-seconds per refresh cycle

When `WL_SPAWN_COUNT_FILE=<path>` is set, every `wl` process appends one line
to that file:

```
<kind>\t<iso-timestamp>\t<pid>\t<cpuMs>\t<maxRssKb>
```

- `kind` — `cache-hit` (served from the read cache), `read-work` (a read that
did DB work), or `version` (`--version`).
- `cpuMs` — user + system CPU time from `process.resourceUsage()`.
- `maxRssKb` — that process's peak RSS.

Set `WL_SPAWN_COUNT=1` to also print the record to stderr. Legacy three-field
lines still parse (CPU/RSS reported as unknown rather than 0).

**Totalling CPU-seconds per refresh cycle (the AC2 procedure).** The bundled
harness reproduces the herdr worklist workload — 4 panes sharing one worklog,
each running the refresh query set (critical / review-queue / in-progress /
blocked subsets plus `wl next`) once per tick:

```sh
npm run benchmark:herdr-refresh:json -- --items 20 --cycle-seconds 30 --tick-seconds 5
# measure a different build (e.g. a pre-change worktree):
npx tsx bench/herdr-refresh-cycle.ts --json --cli /path/to/dist/cli.js
# no-cache baseline variant:
WL_CACHE_DISABLED=1 npm run benchmark:herdr-refresh:json -- --items 20 --cycle-seconds 30 --tick-seconds 5
```

It reports total `cpuSeconds` per cycle, `spawns` by kind, `cpuSecondsPerSpawn`,
p95 per-spawn wall time and peak RSS. Reference numbers (4 panes, 30 s cycle,
120 spawns) are recorded on the epic work item — the verdict is that per-spawn
CPU has hit the process-startup floor, so further gains must come from fewer
spawns per refresh tick.

Since the consolidated read landed (WL-0MVGYLU0S004WZUS) the harness accepts
`--query-set legacy|consolidated`, so the two workloads can be measured on the
same host and build:

```sh
# the five-query workload (byte-identical to the recorded F10 baseline)
npm run benchmark:herdr-refresh:json -- --items 20 --cycle-seconds 30 --tick-seconds 5 --query-set legacy
# the shipped one-read workload: one `wl worklist --json` per tick
npm run benchmark:herdr-refresh:json -- --items 20 --cycle-seconds 30 --tick-seconds 5 --query-set consolidated
```

Measured on one host/build (4 panes, 30 s cycle, 20 items): **5 → 1 spawn per
refresh** (120 → 24 per cycle), **75.68 → 11.89 CPU-s per cycle** (0.157×), p95
per-spawn wall time 1228 → 568 ms. See
[`docs/dev/herdr-event-driven-refresh.md`](docs/dev/herdr-event-driven-refresh.md#3-cold-refresh-cost-fetcherts)
for the full table and the comparison against the pre-F4 baseline (159.44 CPU-s)
and the F10 target (≤ 63.78 CPU-s).

### GitHub throttling (environment variables)

Worklog includes a central client-side throttler to coordinate outgoing GitHub API
Expand Down Expand Up @@ -603,6 +709,62 @@ wl --json show WL-ABC # tolerant JSON output
wl show --exact WL-ABC # strict: fails if not an exact match
```

### `worklist` [options]

One consolidated read of every subset a worklist UI needs — the response a
Herdr pane otherwise assembles from five separate `wl` processes per refresh
tick. It opens the database **once** and returns the critical, review-queue,
in-progress-root, blocked-root and browse-feed subsets in a single JSON
payload (WL-0MVI0HX58009JJRF, parent WL-0MVGYLU0S004WZUS).

**Pure read.** `worklist` never re-sorts and never writes, so the payload is a
deterministic function of `(DB state, argv)` and is served from the shared
read cache as **one** entry (WL-0MVI0IS6Y0028KTO). It is also classified as a
pure read by the CLI write-invalidation hook, so it never bumps the cache state
counter.

```sh
wl worklist --json # 20 browse-feed items (default)
wl worklist --json -n 40 # a wider browse window
wl --worklog-dir /proj/.worklog worklist --json
```

Options:

- `-n, --number <n>` — browse-feed window size (default `20`). Bounds **only**
the `browse` subset; the four mandatory subsets are always complete.
- `--prefix <prefix>` — override the default work-item prefix.

Payload (stable — the Herdr fetcher caches it verbatim and parses it directly,
WL-0MVI0IT4S0070G78):

```jsonc
{
"success": true,
"worklogDir": "/abs/path/.worklog", // resolved worklog dir (honours --worklog-dir)
"requestedCount": 20, // the -n value that was used
"subsets": {
// priority critical, status open|in-progress|blocked|completed, ALL parent levels
"critical": [ /* WorkItem[] */ ],
// status completed|in-progress, stage in_review, root-only
"reviewQueue": [ /* WorkItem[] */ ],
// status in-progress, root-only
"inProgressRoots": [ /* WorkItem[] */ ],
// status blocked, root-only
"blockedRoots": [ /* WorkItem[] */ ],
// identical to `wl next -n <count> --include-in-progress --include-blocked --no-re-sort --json`
"browse": [ /* { workItem, reason, group?, groupLabel? }[] */ ]
}
}
```

Every subset key is always present — an empty array, never omitted. Items carry
the same enrichment `wl list --json` emits (`auditResult`, `auditedAt`,
`fingerprint`, `currentFingerprint`, `childCount`), and the list subsets use the
same filter expressions and hierarchy ordering as the equivalent `wl list`
invocations. `browse` is item-for-item and order-for-order identical to
`wl next` with the same browse window and `--no-re-sort`.

### `next` [options]

Suggest the next work item(s) to work on. Non-actionable items (deleted, completed, in-review, in-progress, dependency-blocked) are excluded by default.
Expand Down Expand Up @@ -822,15 +984,15 @@ wl list --needs-producer-review

When `--json` is used, each work item includes the audit enrichment fields
`auditResult`, `auditedAt`, and `fingerprint` (from the `audit_results`
table), plus `currentFingerprint` — the canonical content fingerprint of the
item's *current* content (per-touched-path git state + description hash + Key
Files, matching the audit skill's algorithm). `currentFingerprint` is
computed only for items that carry a stored `fingerprint`; it is `null`
otherwise, or when git cannot determine it. Comparing `fingerprint` with
table), plus `currentFingerprint` — the canonical content fingerprint (schema
2) of the item's *current* content (its own `title` + `description` only, no
git state — matching the audit skill's algorithm).
`currentFingerprint` is computed only for items that carry a stored
`fingerprint`; it is `null` otherwise. Comparing `fingerprint` with
`currentFingerprint` is the primary `isAuditFresh` gate, so a fresh audit
stays fresh across `updatedAt` churn (WL-0MUN7QWFP0010EQC). Like the other
enrichment fields, `currentFingerprint` is omitted when an explicit `--fields`
projection is active.
stays fresh across `updatedAt` churn (WL-0MUN7QWFP0010EQC,
WL-0MVK5SWZE00254Y7). Like the other enrichment fields, `currentFingerprint`
is omitted when an explicit `--fields` projection is active.

---

Expand Down Expand Up @@ -943,6 +1105,47 @@ wl sync debug
wl --json sync debug
```

#### Held claims and store identity

A sync never downgrades an item that another session is actively working. Items
that are `in-progress` (or carry a non-empty `assignee`) and were active within
`syncClaimHoldTtlHours` (default 24 h, `0` disables) keep their claimed
`status`/`stage` pair **and** their `updatedAt`/`activityAt` when a sync pulls a
stale row for them — the stale row is not re-stamped as the newest row. Newer,
more active transitions (a close, `in_review`, an audit demotion of a completed
item, a reassignment) and attributed deletes still propagate, and a claim older
than the TTL is released. Full behaviour:
[DATA_SYNCING.md](DATA_SYNCING.md#held-claims-are-never-downgraded-by-a-sync).

`--json` reports both the store identity and every refusal:

```json
{
"success": true,
"sync": {
"store": { "worklogDir": "/repo/.worklog", "databasePath": "/repo/.worklog/worklog.db", "secondStore": false },
"claimHolds": [
{
"workItemId": "WL-0ABC",
"keptStatus": "in-progress", "keptStage": "plan_complete",
"attemptedStatus": "open", "attemptedStage": "intake_complete",
"fields": ["status", "stage"],
"claimAgeHours": 0.42, "ttlHours": 24,
"reason": "held claim (status+stage downgrade refused): in-progress/plan_complete → open/intake_complete"
}
],
"summary": { "itemsAdded": 0, "itemsUpdated": 0 }
}
}
```

`sync.store.secondStore` is `true` when the sync operated on a store inside a
managed worktree (`.worklog/worktrees/<name>`) instead of the main checkout's
store — two stores for one prefix hold independent locks and watermarks. `wl`
refuses to create such a store implicitly and binds to the main checkout
instead (see
[DATA_SYNCING.md](DATA_SYNCING.md#one-store-per-repository-worktrees)).

Example (JSON / dry-run):

```sh
Expand Down Expand Up @@ -1086,6 +1289,7 @@ Subcommands:
- `file-paths [options]` — Check intake-stage items for missing or incorrect `**Key Files:**` sections. Options: `--add-placeholder` (add a placeholder section).
- `foreign-items [options]` — Report work items whose ID prefix does not match the project prefix (cross-project pollution detection). Options: `--dry-run` (read-only; default), `--apply` (hard-delete foreign items with full cascade — destructive, requires explicit opt-in), `--push` (after `--apply`, rewrite the remote worklog ref so it contains only own items — destructive; requires `--apply`), `--prefix <prefix>` (override classification prefix).
- `audit-gaps [options]` — Read-only report of every `completed`/`in_review` item with **no audit record**, showing root vs `child of <parent-id>`, age (from `activityAt`/`updatedAt`), and coverage/waiver status (`uncovered` / `covered` / `waived`). Omits items with a fresh audit; a child covered by a fresh-audited direct parent is reported as `covered`, not flagged. Options: `--prefix <prefix>`. No `--apply` (read-only).
- `cache [options]` — Report or prune the bounded read-cache **state directory** (`<cache-dir>/state`, one small counter file per worklog dir ever seen; see `CONFIG.md`). Options: `--prune` (remove stale counters and enforce the file bound; default is report-only), `--dry-run` (report-only; always wins when combined with `--prune`), `--max-files <n>` (counter bound, default 1000), `--ttl-days <n>` (remove counters untouched for this many days, default 7). Works without a worklog (pure cache hygiene).

Examples:

Expand All @@ -1107,6 +1311,10 @@ wl doctor foreign-items --apply # Hard-delete foreign items (destructiv
wl doctor foreign-items --apply --push # Clean DB and rewrite remote worklog ref
wl doctor audit-gaps # Report completed/in_review items with no audit (read-only)
wl doctor audit-gaps --json # Machine-readable audit-gap report
wl doctor cache # Report read-cache state counters (dry run)
wl doctor cache --json # Machine-readable state report
wl doctor cache --prune # Reclaim stale counters and enforce the bound
wl doctor cache --prune --max-files 500 # Custom bound (Pi-class host example)

Known stale combinations detected by `stage-sync`:

Expand All @@ -1133,6 +1341,11 @@ shape unchanged). Its `context` carries machine-readable pending-upgrade data:
`outdatedHookCount`. Consumers grouping findings by work item should skip this
entry (`itemId: null`).

When the read-cache state directory holds pruneable counters, a synthetic
finding with `checkId: "read-cache.state"` and `type: "maintenance"` is appended
the same additive way (`itemId: null`); its `message` names the counts and points
at `wl doctor cache` / `wl doctor cache --prune`.

### `re-sort` [options]

Recompute `sort_index` values for active work items (excluding completed/deleted) using the current database values.
Expand Down
Loading
Loading