Repository navigation
Harden log retention, cancellation gates, and inventory scanning - #13
Merged
Merged
Conversation
There was a problem hiding this comment.
🔵 Needs a closer look
It modifies multiple cross-cutting concurrency and filesystem I/O paths (locks, cancellation, retention, inventory capture) where subtle regressions are hard to fully validate without final human review despite strong test coverage.
Pull request overview
This PR continues the repo’s adversarial hardening work by tightening resource bounds and cancellation/locking behavior across logging, request gates, inventory scanning, and the gh skill list cache, with regression tests added to lock in the new guarantees.
Changes:
- Enforces aggregate file-log retention during active-file growth (not just on rotation), with regression coverage.
- Refactors cancellation gates (
LatestRequestGate,CancellationTokenSourceSlot) to avoid runningCancel()callbacks under ownership locks, with deterministic deadlock-regression tests. - Makes local inventory capture bounded and cancellation-aware end-to-end (root resolution, filesystem enumeration, bounded SKILL.md reads, bounded lockfile reads), and runs it concurrently with
gh skill list.
File summaries
| File | Description |
|---|---|
| tests/SkillView.Tests/Ui/LatestRequestGateTests.cs | Adds a regression test proving cancellation callbacks don’t execute under the gate lock. |
| tests/SkillView.Tests/Ui/CancellationTokenSourceSlotTests.cs | Adds a regression test proving slot cancellation callbacks don’t execute under the slot lock. |
| tests/SkillView.Tests/Logging/FileLogSinkTests.cs | Adds coverage that retention is rechecked as the active log file grows. |
| tests/SkillView.Tests/Inventory/SkillLockFileReaderTests.cs | New tests for bounded lockfile parsing and pre-I/O cancellation. |
| tests/SkillView.Tests/Inventory/LocalSkillScannerTests.cs | Adds tests for mid-scan cancellation, bounded SKILL.md reads, and iteration-time enumeration failures. |
| tests/SkillView.Tests/Inventory/LocalInventoryServiceMergeTests.cs | Adds coverage that merge honors pre-canceled tokens. |
| tests/SkillView.Tests/Inventory/CleanupClassifierTests.cs | Adds coverage that cleanup classification honors pre-canceled tokens before enumeration. |
| tests/SkillView.Tests/Gh/GhSkillListCacheTests.cs | Adds a regression ensuring the injected clock callback runs outside the cache lock. |
| src/SkillView.Core/Ui/SkillViewWorkflowCoordinator.cs | Routes cleanup classification through the cancellation-aware classifier entrypoint. |
| src/SkillView.Core/Ui/LatestRequestGate.cs | Refactors ownership/cancellation/disposal sequencing to avoid lock + callback hazards. |
| src/SkillView.Core/Ui/CancellationTokenSourceSlot.cs | Refactors ownership/cancellation/disposal sequencing to avoid lock + callback hazards. |
| src/SkillView.Core/Logging/FileLogSink.cs | Tracks retained bytes and re-enforces aggregate disk budget during active growth without per-line directory scans. |
| src/SkillView.Core/Inventory/SkillLockFileReader.cs | Adds a hard size bound (1 MiB) with pooled-buffer reads and cancellation checks. |
| src/SkillView.Core/Inventory/ScanRootResolver.cs | Adds cancellation-aware root resolution and git-root probing. |
| src/SkillView.Core/Inventory/LocalSkillScanner.cs | Makes enumeration cancellation-aware, catches iteration-time failures, and bounds SKILL.md reads (64 KiB). |
| src/SkillView.Core/Inventory/LocalInventoryService.cs | Moves sync filesystem work off the UI thread, runs local scan concurrently with gh skill list, and propagates cancellation throughout. |
| src/SkillView.Core/Inventory/CleanupClassifier.cs | Adds cancellation-aware classification and fixes lazy-enumerator failure handling for scan-root enumeration. |
| src/SkillView.Core/Gh/GhSkillListCache.cs | Captures clock outside cache lock and ensures clock failures become shared load outcomes. |
| docs/reviews/adversarial-concurrency-resource-cancellation-audit-2026-08-28.md | Updates audit status and documents the new remediation checkpoint details. |
| AGENTS.md | Records durable repo rules for callback-safe cancellation and bounded inventory/log retention behavior. |
| agent_docs/ui-lifecycle-and-resource-bounds.md | Updates lifecycle/resource-bound guidance to match the new cancellation + inventory + retention invariants. |
Review details
- Files reviewed: 21/21 changed files
- Comments generated: 0
- Review effort level: Lite
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
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.
Summary
Starts the second adversarial hardening batch after PR #12. This closes the final PR #12 log-retention follow-up, fixes two analogous lock/callback hazards found by re-auditing the prior Copilot misses as bug families, and completes the bounded/cancellable local-inventory portion of the remaining audit.
Why
The final PR #12 review noted that aggregate log usage was only enforced when a writer opened or rotated. Older parts could remain while the active part grew, temporarily exceeding the advertised disk budget.
The follow-up audit then found the same broader patterns elsewhere:
Changes
Enforce aggregate log retention during active growth
Remove cancellation callbacks from ownership locks
CancellationTokenSourceSlotandLatestRequestGateto publish ownership changes under their gates, then callCancel()outside the gate.Bound and cancel local inventory work
gh skill listso disk and subprocess latency do not add serially.MoveNext, where disappearing directories, ACL changes, and disconnected mounts actually surface.ghduration diagnostics while the two sources run concurrently.Bound untrusted local files
SKILL.md, enough for normal front matter without retaining the full Markdown body..skill-lock.jsonthrough a pooled buffer and reject manifests over 1 MiB.Avoid injected work under the cache lock
_gate.Documentation and follow-up ordering
async voidhandlers repeatedly access ausing-owned cancellation source after awaits, the same disposed-source family found in Discover.AGENTS.mdand the lifecycle/resource guide with the durable cancellation-lock, bounded-inventory, and incremental-retention rules.Validation
dotnet build --no-restore: passed with 0 warnings and 0 errors.dotnet test --no-build: 625 passed, 0 failed, including the ANSI-driver integration suite.--versionsmoke checks.git diff --check: passed.CI will repeat tests and AOT smoke publishing on Linux, macOS, and Windows, plus CodeQL.
Release notes
SKILL.mdand.skill-lock.jsonfiles from causing large inventory-time allocations.Remaining ordered work
The next checkpoint is intentionally separate because it crosses destructive-operation and modal-lifetime boundaries: