Repository navigation
Merge dev → main (automated) - #2124
Merged
Merged
Conversation
added 30 commits
October 18, 2026 00:34
…t, WL-0MVF3PYO3000EVJ3)
…rst, WL-0MUYJ8WJG0087VSU) Add three specs for the grey background on In Review headings: - In Review heading contains \x1b[48;5; background prefix (it.fails) - Other headings do NOT contain background escape (it, regression guard) - Selected In Review heading has both reverse-video and grey bg (it.fails) All 17 tests green. Implementation child WL-0MVD2OFRK000JA2Q flips it.fails → it once the grey background lands.
…hing (test-first)
added 28 commits
October 22, 2026 21:26
…er one
A background `wl sync` could replace a just-persisted audit with an older
copy of the same item's audit, leaving the item's lifecycle (status/stage,
comments) intact while the stored audit showed a stale verdict — e.g. an
item demoted to open/plan_complete while `wl audit-show` reported the old
"Ready to close: Yes".
Root cause: the audit merge was local-precedence only. The local side won
regardless of audit time, so whichever side was stale could shadow the other
indefinitely; and the destructive full-snapshot import re-inserted the merged
snapshot after `clearWorkItems()` cascade-deleted the audit rows, so any
stale snapshot reaching the persist layer silently replaced a newer audit.
- `mergeAuditResults` (src/sync.ts) is now last-write-wins by `auditedAt`:
the newest audit wins whichever side it comes from, local wins exact ties,
and unparseable timestamps fall back to local precedence. Sync converges in
both directions but can never downgrade.
- `SqlitePersistentStore.saveAuditResults` (bulk path used by every sync
import: pull merge, JSONL refresh, doctor/import bulk loads) is monotonic:
an incoming audit strictly older than the stored row is skipped. Explicit
single-item writes (`wl audit-set` -> `saveAuditResult`) stay unrestricted.
- `WorklogDatabase.import` snapshots audits before the cascade-deleting
`clearWorkItems()`, keeps them when no audit set is supplied, and folds an
incoming set with the same newest-wins rule instead of blind replacement.
- Docs: DATA_SYNCING.md ("Audit Results: Newest Wins, Never Downgraded") and
docs/design/incremental-sync.md section 4.3 record the decision (AC2/AC3).
Tests: tests/cli/sync-audit-newest-wins.test.ts (real git + bare remote E2E:
newer local survives an older remote snapshot, newer remote wins over a stale
local, audit-less legacy snapshot leaves the local audit unchanged) and
tests/unit/audit-sync-monotonic.test.ts (merge LWW + bulk/full persist
guards). tests/sync-audit-results.test.ts updated for the new merge semantics.
Full node suite: 109 cli files + 47 unit files green.
…in_progress claim)
A sync can no longer downgrade a held claim. Before persisting a pull the sync re-reads the store's current rows (cache-bypassing, so a claim written by another process during the sync window is visible) and refuses any status/stage downgrade of a claim held within syncClaimHoldTtlHours (default 24h, 0 disables), preserving the claim's status/stage pair and its updatedAt/activityAt. Newer, more active transitions, attributed deletes and expired claims are unaffected. Every refusal is recorded in the sync log and in --json output (sync.claimHolds), and the sync's store identity is reported as sync.store. Root cause: the sync's merged set is built from the pre-fetch snapshot, so a claim landing in the read->write window (lock age-expiry) is absent from it; import()/upsertItems() then wrote the stale row back and re-stamped it newer. Also fixes the stage-ordering gap (plan_complete -> prd_complete resolved by timestamp).
.worklog/config.yaml is tracked, so every managed worktree checks out a .worklog/ directory that holds configuration but no store, and the shared resolver treated it as a valid root: a wl command run inside a worktree bound to a second store with its own mutation lock and last-synced-ref watermark. resolveWorklogDir() now honours a worktree .worklog/ only when it is a genuine store (wl init wrote 'initialized' and/or worklog.db), otherwise binds to the main checkout's store, and fails with an actionable error naming --worklog-dir when neither exists. A sync also reports the store it operated on and flags the second-store condition (sync.store.secondStore).
CLI.md documents the new sync.claimHolds/sync.store JSON fields; DATA_SYNCING.md documents what a held claim is, what the guard does and does not do (TTL bound, attributed deletes, newer-more-active transitions), the syncClaimHoldTtlHours config key, and the worktree store-resolution rule.
…vent-loop load sensitivity
…sitive suite timing
…eadings; keep documented per-call timeouts
…ent (post-run host load)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Automated release created by ship skill.\n\nIncludes CHANGELOG.md with work-item summaries from this release.