WBS-6.2: viewer unfinished_tab properties + fuzz/rootless/clippy CI drift fixes - #429
Conversation
…hed_tab properties Four bounded cleanups observed while CI was running on #425/#427: 1) scripts/fuzz-cadence-check.ps1: the "PR smoke stays short" anchor was checking ci.yml for max_total_time=10, but the 10s fuzz-smoke job no longer lives there (consolidated into fuzz-blocking.yml at 30s). Re-pointed the check at the actual PR fuzz budget: fuzz-blocking.yml with max_total_time=30. 2) scripts/rootless-nonet-check.ps1 + .github/workflows/ci.yml: the script expected ci.yml to cross-reference rootless-nonet.yml, but that anchor had drifted out of ci.yml while security.yml retained it. Added a small rootless-nonet-policy smoke job to ci.yml (matches the docs/ops/sandbox-boundary.md C04 L40 contract that 'ci.yml cross-reference | done') and tightened the script's regex so continue-on-error detection can't bleed across jobs. 3) clippy -D warnings under --all-targets --all-features: * tests/alloc_profile.rs: panic-in-if-then — folded the Windows panic into an explicit else branch. * tests/replay_breadth.rs: 6 unnecessary trailing commas in assert! macros. 4) crates/sl-viewer/tests/properties_viewer_unfinished_tab.rs: 6 proptest properties covering reason_label (non-empty, injective) and unfinished_items (deterministic, descending by ts_ms, tiebreak by session_id asc, length-monotonic). Adds to WBS-6.2 viewer property surface alongside #425/#427. WBS-6.2 evidence list and CHANGELOG Unreleased reflect the new property file.
WBS-6.2 evidence list and TRACEABILITY.json gain the new properties_viewer_unfinished_tab.rs and reference #428 for the unfinished-tab properties + CI drift fixups. Status stays partial (fuzzing cadence, full loom/shuttle, perf-budget gates remain).
🤖 CodeAnt AI — Review Status
|
Thanks for using CodeAnt! 🎉We're free for open-source projects. if you're enjoying it, help us grow by sharing. Share on X · |
📝 WalkthroughSummaryThis PR fixes CI drift and adds property-based coverage for viewer unfinished-tab behavior.
Must FixNo blocking issues are reported. The stated validation passed for Clippy, viewer property tests, affected test suites, and updated scripts. Should FixNo non-blocking issues are reported. ConsiderWBS-6.2 remains partial. The traceability updates correctly record the additional test evidence. Approve / Request ChangesApprove. WalkthroughThe PR adds property-based coverage for unfinished viewer tabs, updates CI self-checks for rootless networking and fuzz cadence, adjusts portable profile validation, and records the new evidence and maintenance changes. ChangesViewer and CI validation
Estimated code review effort: 3 (Moderate) | ~20 minutes Possibly related PRs
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches 💡 2📝 Generate docstrings 💡
🛠️ Fix failing CI checks 💡
🧪 Generate unit tests (beta)
✨ Simplify code
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
| if ($blockingWorkflow -notmatch 'max_total_time=30') { | ||
| throw "fuzz-blocking.yml must keep -max_total_time=30 for the PR fuzz budget (do not slow PR CI here)." | ||
| } | ||
| [void](Write-Check -Label "ci.yml fuzz-smoke max_total_time=10" -Ok $true) | ||
| [void](Write-Check -Label "fuzz-blocking.yml PR fuzz max_total_time=30" -Ok $true) |
There was a problem hiding this comment.
Suggestion: This replacement check no longer validates the separate blocking ci.yml fuzz-smoke lane or its 10-second limit. Because $ci is no longer checked here, removing that job or weakening its budget still passes SelfCheck, despite the documentation continuing to define it as required blocking PR coverage. Keep an explicit ci.yml smoke-job anchor in addition to the sustained-workflow check. [incomplete implementation]
Severity Level: Major ⚠️
- ❌ Required 10-second PR fuzz coverage is not enforced.
- ⚠️ CI drift checks ignore the documented `ci.yml` lane.
- ⚠️ Fuzz validation changes from short smoke to sustained coverage.(Use Cmd/Ctrl + Click for best experience)
Prompt for AI Agent 🤖
This is a comment left during a code review.
**Path:** scripts/fuzz-cadence-check.ps1
**Line:** 176:179
**Comment:**
*Incomplete Implementation: This replacement check no longer validates the separate blocking `ci.yml` `fuzz-smoke` lane or its 10-second limit. Because `$ci` is no longer checked here, removing that job or weakening its budget still passes SelfCheck, despite the documentation continuing to define it as required blocking PR coverage. Keep an explicit `ci.yml` smoke-job anchor in addition to the sustained-workflow check.
Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix| if cfg!(target_os = "windows") { | ||
| panic!("failed to spawn pwsh for self-check: {error}"); | ||
| } else { | ||
| let (max_bytes, total_blocks) = load_profile(); | ||
| println!( | ||
| "pwsh unavailable; running portable alloc-profile SelfCheck fallback.\nSelf-check passed\nMax bytes ceiling: {max_bytes}\nTotal blocks ceiling: {total_blocks}\nProfiler: dhat" |
There was a problem hiding this comment.
Suggestion: The non-Windows fallback converts every pwsh spawn failure—including permission errors, invalid invocation failures, and other environment problems—into a fabricated successful SelfCheck result. This means the test can pass without executing scripts/alloc-profile-check.ps1 or validating its documented workflow and path anchors. Only use the fallback for an explicitly detected missing executable, or fail the test for other spawn errors. [possible bug]
Severity Level: Major ⚠️
- ⚠️ Linux tests can pass without executing alloc-profile SelfCheck.
- ⚠️ PowerShell workflow-anchor regressions may be missed.
- ⚠️ Non-missing-executable spawn failures are misreported as success.(Use Cmd/Ctrl + Click for best experience)
Prompt for AI Agent 🤖
This is a comment left during a code review.
**Path:** tests/alloc_profile.rs
**Line:** 90:95
**Comment:**
*Possible Bug: The non-Windows fallback converts every `pwsh` spawn failure—including permission errors, invalid invocation failures, and other environment problems—into a fabricated successful SelfCheck result. This means the test can pass without executing `scripts/alloc-profile-check.ps1` or validating its documented workflow and path anchors. Only use the fallback for an explicitly detected missing executable, or fail the test for other spawn errors.
Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fixThere was a problem hiding this comment.
Actionable comments posted: 5
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In @.github/workflows/ci.yml:
- Around line 203-206: Update the actions/checkout step in the rootless / no-net
SelfCheck job to use an immutable commit SHA instead of the floating v7 tag, and
configure checkout with persist-credentials disabled.
In `@crates/sl-viewer/tests/properties_viewer_unfinished_tab.rs`:
- Around line 120-123: Update the test around the with_ts filtering in the
unfinished-work sorting assertions to retain all items, including those with
last_activity_ms == None. Add an assertion that no item with
Some(last_activity_ms) appears after an item with None, while preserving the
existing descending-order check for known timestamps.
- Around line 35-55: Update the property generator around the session message
construction to generate an independent Option<i64> timestamp for each message
instead of one session-wide value, while preserving the None unknown-timestamp
case. Track the maximum known timestamp per session and assert the projected
unfinished_items last_activity_ms matches that maximum, following the contract
used by unfinished_items.
In `@scripts/rootless-nonet-check.ps1`:
- Around line 134-145: Update the validation around $policyBlockMatch in
rootless-nonet-check.ps1 to throw when the rootless-nonet-policy block is
absent, rather than treating a failed match as success. Keep the existing
continue-on-error validation for a present block and only call Write-Check with
Ok $true after confirming the block exists and is blocking.
In `@tests/alloc_profile.rs`:
- Around line 85-96: Update the non-Windows error handling around the pwsh
`Command::output()` call so the portable fallback runs only when `error.kind()
== std::io::ErrorKind::NotFound`; panic with the existing failure context for
all other spawn errors, including permission failures. Preserve the Windows
behavior and the successful output path.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: 8959c577-3a15-42af-a795-3598bf1728d5
📒 Files selected for processing (9)
.github/workflows/ci.ymlCHANGELOG.mdcrates/sl-viewer/tests/properties_viewer_unfinished_tab.rsdocs/ops/TRACEABILITY.jsondocs/ops/WBS.mdscripts/fuzz-cadence-check.ps1scripts/rootless-nonet-check.ps1tests/alloc_profile.rstests/replay_breadth.rs
📜 Review details
⏰ Context from checks skipped due to timeout. (28)
- GitHub Check: semgrep-cloud-platform/scan
- GitHub Check: load macro gate · macro routes smoke
- GitHub Check: update check hard · root SelfCheck wrapper
- GitHub Check: CVE feed subscription smoke (soft)
- GitHub Check: update check hard · sl-daemon tests
- GitHub Check: Socket posture SelfCheck
- GitHub Check: gitleaks
- GitHub Check: tsan permutation · race_model
- GitHub Check: cargo deny check
- GitHub Check: SLSA protected-environment SelfCheck
- GitHub Check: env.example hygiene
- GitHub Check: jemalloc default-on · SelfCheck
- GitHub Check: jemalloc default-on · windows default build
- GitHub Check: trufflehog
- GitHub Check: fuzz blocking · sustained 30s
- GitHub Check: cargo audit
- GitHub Check: browser e2e · axe · responsive · visual
- GitHub Check: visual contract · WCAG AA
- GitHub Check: prepare
- GitHub Check: shuttle permutation · cargo test shuttle_permutation
- GitHub Check: daemon graph hard · tokio graph
- GitHub Check: sl-daemon build · windows-latest
- GitHub Check: sl-daemon build · macos-latest
- GitHub Check: sl-viewer help · unit tests
- GitHub Check: sl-viewer macOS app · artifact
- GitHub Check: Summary
- GitHub Check: browser e2e · axe · responsive · visual
- GitHub Check: prepare
⚠️ CI failures not shown inline (2)
GitHub Actions: Trunk Check / 0_Lint & Format.txt: WBS-6.2: viewer unfinished_tab properties + fuzz/rootless/clippy CI drift fixes
Conclusion: failure
##[group]Run cat >>$GITHUB_ENV <<EOF
�[36;1mcat >>$GITHUB_ENV <<EOF�[0m
�[36;1mGITHUB_***REDACTED_SECRET_ASSIGNMENT***
�[36;1mTRUNK_LAUNCHER_QUIET=false�[0m
�[36;1mEOF�[0m
�[36;1m�[0m
�[36;1m# First arg is field to fetch, second arg is default value or empty�[0m
�[36;1mpayload() {�[0m
�[36;1m if [ $# -lt 2 ]; then�[0m
�[36;1m DEFAULT_VALUE=empty�[0m
�[36;1m else�[0m
�[36;1m DEFAULT_VALUE=\"$2\"�[0m
�[36;1m fi�[0m
�[36;1m if command -v jq >/dev/null; then�[0m
�[36;1m jq -r ".inputs.payload | fromjson | .$1 // ${DEFAULT_VALUE}" ${TEST_GITHUB_EVENT_PATH:-${GITHUB_EVENT_PATH}}�[0m
�[36;1m else�[0m
�[36;1m echo "::error::jq not installed on system!"�[0m
GitHub Actions: Trunk Check / Lint & Format: WBS-6.2: viewer unfinished_tab properties + fuzz/rootless/clippy CI drift fixes
Conclusion: failure
##[group]Run cat >>$GITHUB_ENV <<EOF
�[36;1mcat >>$GITHUB_ENV <<EOF�[0m
�[36;1mGITHUB_***REDACTED_SECRET_ASSIGNMENT***
�[36;1mTRUNK_LAUNCHER_QUIET=false�[0m
�[36;1mEOF�[0m
�[36;1m�[0m
�[36;1m# First arg is field to fetch, second arg is default value or empty�[0m
�[36;1mpayload() {�[0m
�[36;1m if [ $# -lt 2 ]; then�[0m
�[36;1m DEFAULT_VALUE=empty�[0m
�[36;1m else�[0m
�[36;1m DEFAULT_VALUE=\"$2\"�[0m
�[36;1m fi�[0m
�[36;1m if command -v jq >/dev/null; then�[0m
�[36;1m jq -r ".inputs.payload | fromjson | .$1 // ${DEFAULT_VALUE}" ${TEST_GITHUB_EVENT_PATH:-${GITHUB_EVENT_PATH}}�[0m
�[36;1m else�[0m
�[36;1m echo "::error::jq not installed on system!"�[0m
🧰 Additional context used
📓 Path-based instructions (5)
**/*.{rs,toml}
📄 CodeRabbit inference engine (AGENTS.md)
**/*.{rs,toml}: Use the Rust toolchain pinned inrust-toolchain.toml; the workspace MSRV is Rust 1.85.
Validate Rust workspace changes with the prescribed locked build, all-features test suite, Clippy, and rustfmt checks where applicable.
Files:
crates/sl-viewer/tests/properties_viewer_unfinished_tab.rstests/replay_breadth.rstests/alloc_profile.rs
**/*.rs
📄 CodeRabbit inference engine (AGENTS.md)
Fix Clippy warnings; do not add
#[allow]unless it includes a tracking-issue comment.
Files:
crates/sl-viewer/tests/properties_viewer_unfinished_tab.rstests/replay_breadth.rstests/alloc_profile.rs
crates/sl-viewer/**/*.{rs,toml}
📄 CodeRabbit inference engine (AGENTS.md)
crates/sl-viewer/**/*.{rs,toml}: Thesl-viewercrate uses Dioxus 0.6; use the Dioxus CLI/toolchain for desktop development and bundling.
Usecargo check -p sl-vieweras the fast inner-loop check for viewer changes.
Files:
crates/sl-viewer/tests/properties_viewer_unfinished_tab.rs
crates/sl-viewer/**/*
📄 CodeRabbit inference engine (AGENTS.md)
When packaging the macOS viewer, account for the documented Electrobun/Dioxus code-signing requirements.
Files:
crates/sl-viewer/tests/properties_viewer_unfinished_tab.rs
*
📄 CodeRabbit inference engine (AGENTS.md)
*: Perform feature work in a git worktree under.claude/worktrees/, created fromorigin/mainon a branch named<type>/<topic>, rather than working directly onmain.
Do not make direct commits to protectedmain; use a pull request.
Do not usegit reset --hard,git stash, orgit cleanin worktrees.
Do not use--no-verifyor bypass hooks without operator approval.
Do not work on a branch or worktree another actor is using.
Files:
CHANGELOG.md
🪛 GitHub Actions: rootless matrix / 0_rootless-only matrix · SelfCheck.txt
.github/workflows/ci.yml
[error] 1-1: Rootless matrix self-check failed: ci.yml is missing the required reference to 'rootless-matrix.yml'. Command './scripts/rootless-matrix-check.ps1 -SelfCheck' exited with code 1.
🪛 GitHub Actions: rootless matrix / rootless-only matrix · SelfCheck
.github/workflows/ci.yml
[error] 1-1: Rootless matrix scaffold self-check failed: ci.yml is missing the required reference to 'rootless-matrix.yml'. Command './scripts/rootless-matrix-check.ps1 -SelfCheck' exited with code 1.
🪛 LanguageTool
CHANGELOG.md
[uncategorized] ~17-~17: The official name of this software platform is spelled with a capital “H”.
Context: ...e. scripts/rootless-nonet-check.ps1 + .github/workflows/ci.yml restore the documente...
(GITHUB)
docs/ops/WBS.md
[uncategorized] ~32-~32: The official name of this software platform is spelled with a capital “H”.
Context: ...; fuzz/fuzz_targets/jsonl_ingest.rs; .github/workflows/ci.yml; .github/workflows/b...
(GITHUB)
[uncategorized] ~32-~32: The official name of this software platform is spelled with a capital “H”.
Context: ...ingest.rs; .github/workflows/ci.yml; .github/workflows/bench-gate.yml; docs/ops/pe...
(GITHUB)
🪛 zizmor (1.29.0)
.github/workflows/ci.yml
[warning] 203-203: credential persistence through GitHub Actions artifacts (artipacked): does not set persist-credentials: false
(artipacked)
[error] 203-203: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)
(unpinned-uses)
🔇 Additional comments (4)
scripts/fuzz-cadence-check.ps1 (1)
172-179: LGTM!CHANGELOG.md (1)
15-18: LGTM!tests/alloc_profile.rs (1)
97-105: LGTM!tests/replay_breadth.rs (1)
122-122: LGTM!Also applies to: 131-144
| - uses: actions/checkout@v7 | ||
| - name: rootless / no-net SelfCheck | ||
| shell: pwsh | ||
| run: ./scripts/rootless-nonet-check.ps1 -SelfCheck |
There was a problem hiding this comment.
🔒 Security & Privacy | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== workflow excerpt =="
sed -n '185,215p' .github/workflows/ci.yml 2>/dev/null || true
echo
echo "== checkout references in workflows =="
rg -n "actions/checkout|persist-credentials" .github/workflows || true
echo
echo "== git workflow related file listing =="
fd -a '^\..*\.ya?ml$' .github 2>/dev/null | sed 's#^\./##' | sortRepository: KooshaPari/SessionLedger
Length of output: 14581
🌐 Web query:
actions/checkout v7 GitHub tag target commit
💡 Result:
The actions/checkout v7 release was officially released on June 18, 2026 [1][2]. It introduces a significant security change designed to prevent common pwn request vulnerabilities in GitHub Actions [2]. Specifically, actions/checkout v7 defaults to blocking the checkout of fork pull request code when used within pull_request_target and certain workflow_run events [2][3]. This enforcement applies when the target repository is a fork and the requested ref matches typical pull request head or merge commit patterns [2]. Key details regarding this release: - Security Enforcement: By default, the action now refuses to fetch fork PR code in privileged contexts (pull_request_target and workflow_run) to mitigate risks associated with untrusted code execution [2]. - Versioning: The release, tagged as v7.0.0, was prepared via PR #2464 [4] and includes updates to dependencies and internal documentation [4][5]. - Upgrading: Workflows pinned to major tags (like actions/checkout@v4 or @v6) will eventually be affected by backported enforcements, as GitHub planned to extend this protection to all supported major versions by July 16, 2026 [2]. Workflows pinned to specific SHAs or minor/patch versions remain unaffected until explicitly updated [2]. You can reference the latest version in your workflows using - uses: actions/checkout@v7 [6][7].
Citations:
- 1: https://github.com/actions/checkout/releases/tag/v7.0.0
- 2: https://github.blog/changelog/2026-06-18-safer-pull_request_target-defaults-for-github-actions-checkout/
- 3: https://github.com/actions/checkout/blob/main/CHANGELOG.md
- 4: getting ready for checkout v7 release actions/checkout#2464
- 5: actions/checkout@v6.0.3...v7.0.0
- 6: https://github.com/actions/checkout
- 7: https://github.com/actions/checkout?tab=readme-ov-file
🌐 Web query:
actions/checkout v7 GitHub release commit SHA
💡 Result:
The actions/checkout@v7 tag is a mutable Git reference that points to the latest release within the v7 major version series [1][2]. Because it is a branch/tag reference, its associated commit SHA changes as new patch releases (e.g., v7.0.1, v7.0.2) are published [3][4]. As of August 8, 2026, the initial v7.0.0 release occurred on June 18, 2026 [5][2]. A subsequent patch, v7.0.1, was released on July 20, 2026 [4]. Consequently, the v7 tag currently points to the commit SHA associated with v7.0.1 [3][4]. For production environments and to ensure supply-chain security, it is best practice to pin your GitHub Actions to a specific, immutable commit SHA rather than a mutable tag like @v7 [1][6]. You can find the specific SHA for any release by viewing the tags in the official actions/checkout repository [3]. As noted in community discussions, using a specific SHA prevents your workflows from automatically pulling in new, potentially breaking, or untested code when a tag is updated [6].
Citations:
- 1: fix: CI uses actions/checkout@v7 which does not exist wiki-mod/lancache-ng#67
- 2: getting ready for checkout v7 release actions/checkout#2464
- 3: https://github.com/actions/checkout/releases
- 4: https://github.com/actions/checkout/releases/tag/v7.0.1
- 5: https://github.com/actions/checkout/releases/tag/v7.0.0
- 6: Update actions/checkout to v7 Apitomy/apitomy-data-models-mcp#31
🌐 Web query:
actions/checkout persist-credentials defaults persist-credentials false
💡 Result:
The persist-credentials input for the actions/checkout GitHub Action controls whether the repository's authentication token (or SSH key) is configured in the local git config [1][2]. By default, persist-credentials is set to true [1][3]. When set to true, the action configures the Git credential helper or local git config to use the provided token, which allows subsequent steps in the same job to run authenticated Git commands without additional setup [1][2]. The token is then automatically removed during the post-job cleanup [1][2]. Setting persist-credentials to false disables this behavior [1]. This is often used as a security measure to prevent subsequent, potentially untrusted, steps in a workflow from accessing the repository's authentication token through the git configuration [4][5]. There has been significant community discussion regarding changing the default value to false to enhance security [4][5], but as of August 2026, the default value remains true [1][3]. Security improvements have been made in recent versions of the action (such as storing credentials in a separate file under $RUNNER_TEMP rather than directly in.git/config) to mitigate some risks while keeping the feature enabled by default [1][2].
Citations:
- 1: https://github.com/actions/checkout
- 2: https://github.com/actions/checkout/tree/v6.0.2?tab=readme-ov-file
- 3: https://github.com/actions/checkout/blob/cbb722410c2e876e24abbe8de2cc27693e501dcb/action.yml
- 4: Remove
persist-credentialsor change the default tofalseactions/checkout#485 - 5: [security] Escalate concerning default
persist-credentials=trueplease actions/checkout#2312
🌐 Web query:
"actions/checkout@v7" "3d3c42e5aac5ba805825da76410c181273ba90b1"
💡 Result:
The SHA-1 commit hash 3d3c42e5aac5ba805825da76410c181273ba90b1 corresponds to the release preparation for actions/checkout v7.0.1 [1][2]. Key details regarding this commit and version: - Release Context: This commit is labeled as prep for the v7.0.1 release of the official GitHub actions/checkout repository [1][2]. - Version v7: GitHub released actions/checkout v7 in mid-2026, which introduced significant security improvements by blocking common pwn-request patterns by default in privileged pull_request_target workflows [3][4]. - Enforcement: While v7 includes these safer defaults, GitHub also backported this security enforcement to other supported major versions (e.g., v4) on July 20, 2026 [3]. - Usage: For workflows pinned to a specific SHA (like the one you specified) or a specific patch version, the automatic security backport is not applied; users must manually update these pins to incorporate the necessary security changes [3][4]. For security-conscious setups, it is recommended to ensure your checkout actions are updated to versions that include these security guardrails, especially if utilizing pull_request_target workflows [3][4].
Citations:
- 1: actions/checkout@de0fac2...3d3c42e
- 2: actions/checkout@v4.3.1...3d3c42e
- 3: https://github.blog/changelog/2026-06-18-safer-pull_request_target-defaults-for-github-actions-checkout/
- 4: https://linkloot.io/blog/github-actions-checkout-v7-pwn-request-backport
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== actions/checkout v7 dereference =="
gh api repos/actions/checkout/git/refs/tags/v7 --jq '.object' || true
echo
echo "== suggested SHA validity =="
gh api repos/actions/checkout/commits/3d3c42e5aac5ba805825da76410c181273ba90b0 --jq '.sha' || true
gh api repos/actions/checkout/commits/3d3c42e5aac5ba805825da76410c181273ba90b1 --jq '.sha' || true
echo
echo "== compare suggested SHA to v7 dereferenced commit =="
python3 - <<'PY'
import subprocess, sys
try:
ref = subprocess.check_output(['gh', 'api', 'repos/actions/checkout/git/refs/tags/v7'], text=True)
object_ = subprocess.check_output(['gh', 'api', 'repos/actions/checkout/git/refs/tags/v7'], text=True)
except Exception as e:
print(f"gh refused: {e}")
sys.exit(0)
PYRepository: KooshaPari/SessionLedger
Length of output: 755
Pin checkout and disable credential persistence.
This PR job checks out repository code and then runs ./scripts/rootless-nonet-check.ps1, so actions/checkout@v7 should be immutable and should not leave the token in local Git configuration.
Suggested fix
- - uses: actions/checkout@v7
+++ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
+ with:
+ persist-credentials: false🧰 Tools
🪛 zizmor (1.29.0)
[warning] 203-203: credential persistence through GitHub Actions artifacts (artipacked): does not set persist-credentials: false
(artipacked)
[error] 203-203: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)
(unpinned-uses)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In @.github/workflows/ci.yml around lines 203 - 206, Update the actions/checkout
step in the rootless / no-net SelfCheck job to use an immutable commit SHA
instead of the floating v7 tag, and configure checkout with persist-credentials
disabled.
Source: Linters/SAST tools
| prop::collection::vec( | ||
| (0u8..5, "[ -~]{1,40}"), | ||
| 0..6, | ||
| ), | ||
| // last_activity_ms — Some(i64) or None. None is the "unknown | ||
| // last activity" sentinel the worklog projector uses. | ||
| prop::option::of(0i64..1_000_000_000_000), | ||
| ) | ||
| .prop_map(|(session_id, messages, ts_ms)| { | ||
| let mut session = Session::new(format!("sess-{session_id}"), Corpus::Forge); | ||
| for (role_idx, content) in messages { | ||
| let role = match role_idx % 5 { | ||
| 0 => Role::User, | ||
| 1 => Role::Assistant, | ||
| 2 => Role::Subagent, | ||
| 3 => Role::Tool, | ||
| _ => Role::System, | ||
| }; | ||
| let mut msg = Message::new(role, content); | ||
| msg.ts_ms = ts_ms; | ||
| session.messages.push(msg); |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
Generate timestamps per message.
Lines 39-55 assign one ts_ms value to every message in a session. The property therefore cannot detect a regression where unfinished_items uses the first or last message timestamp instead of the maximum timestamp. The upstream contract uses the maximum timestamp in crates/sl-viewer/src/corpus_tab.rs, lines 37-39.
Generate Option<i64> with each message. Then assert that each projected last_activity_ms equals that session’s maximum known message timestamp.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@crates/sl-viewer/tests/properties_viewer_unfinished_tab.rs` around lines 35 -
55, Update the property generator around the session message construction to
generate an independent Option<i64> timestamp for each message instead of one
session-wide value, while preserving the None unknown-timestamp case. Track the
maximum known timestamp per session and assert the projected unfinished_items
last_activity_ms matches that maximum, following the contract used by
unfinished_items.
| // Filter to items with a known timestamp so the descending | ||
| // invariant applies cleanly. | ||
| let with_ts: Vec<&UnfinishedWorkItem> = | ||
| items.iter().filter(|i| i.last_activity_ms.is_some()).collect(); |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
Assert that unknown activity sorts last.
Lines 120-123 discard every item with last_activity_ms == None. The test cannot verify the documented invariant that known activity precedes unknown activity. Keep the full item list and assert that no Some(_) item follows a None item.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@crates/sl-viewer/tests/properties_viewer_unfinished_tab.rs` around lines 120
- 123, Update the test around the with_ts filtering in the unfinished-work
sorting assertions to retain all items, including those with last_activity_ms ==
None. Add an assertion that no item with Some(last_activity_ms) appears after an
item with None, while preserving the existing descending-order check for known
timestamps.
| # Extract just the rootless-nonet-policy: block (until the next top-level | ||
| # job or end of file) so the continue-on-error check can't bleed across | ||
| # into unrelated jobs like `security:`. (?ms) = multi-line + dotall so | ||
| # `.*?` can span newlines. | ||
| $policyBlockMatch = [regex]::Match( | ||
| $ciWf, | ||
| '(?ms)^ rootless-nonet-policy:.*?(?=^ [A-Za-z][\w-]*:\s|\z)' | ||
| ) | ||
| if ($policyBlockMatch.Success -and $policyBlockMatch.Value -match 'continue-on-error:\s*true') { | ||
| throw "ci.yml rootless-nonet-policy job must be blocking (no continue-on-error)." | ||
| } | ||
| [void](Write-Check -Label "ci.yml rootless-nonet-policy job is blocking when present" -Ok $true) |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
Fail when the policy job is absent.
The condition skips the error when $policyBlockMatch.Success is $false. If rootless-nonet-policy is removed, the comments in .github/workflows/ci.yml at Lines 191-194 can still satisfy the string checks at Lines 129-132. The script then reports a passing blocking-policy check at Line 145. Throw when the policy block is missing.
Suggested fix
-if ($policyBlockMatch.Success -and $policyBlockMatch.Value -match 'continue-on-error:\s*true') {
+if (-not $policyBlockMatch.Success) {
+ throw "ci.yml must define the rootless-nonet-policy job."
+}
+if ($policyBlockMatch.Value -match 'continue-on-error:\s*true') {📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| # Extract just the rootless-nonet-policy: block (until the next top-level | |
| # job or end of file) so the continue-on-error check can't bleed across | |
| # into unrelated jobs like `security:`. (?ms) = multi-line + dotall so | |
| # `.*?` can span newlines. | |
| $policyBlockMatch = [regex]::Match( | |
| $ciWf, | |
| '(?ms)^ rootless-nonet-policy:.*?(?=^ [A-Za-z][\w-]*:\s|\z)' | |
| ) | |
| if ($policyBlockMatch.Success -and $policyBlockMatch.Value -match 'continue-on-error:\s*true') { | |
| throw "ci.yml rootless-nonet-policy job must be blocking (no continue-on-error)." | |
| } | |
| [void](Write-Check -Label "ci.yml rootless-nonet-policy job is blocking when present" -Ok $true) | |
| # Extract just the rootless-nonet-policy: block (until the next top-level | |
| # job or end of file) so the continue-on-error check can't bleed across | |
| # into unrelated jobs like `security:`. (?ms) = multi-line + dotall so | |
| # `.*?` can span newlines. | |
| $policyBlockMatch = [regex]::Match( | |
| $ciWf, | |
| '(?ms)^ rootless-nonet-policy:.*?(?=^ [A-Za-z][\w-]*:\s|\z)' | |
| ) | |
| if (-not $policyBlockMatch.Success) { | |
| throw "ci.yml must define the rootless-nonet-policy job." | |
| } | |
| if ($policyBlockMatch.Value -match 'continue-on-error:\s*true') { | |
| throw "ci.yml rootless-nonet-policy job must be blocking (no continue-on-error)." | |
| } | |
| [void](Write-Check -Label "ci.yml rootless-nonet-policy job is blocking when present" -Ok $true) |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@scripts/rootless-nonet-check.ps1` around lines 134 - 145, Update the
validation around $policyBlockMatch in rootless-nonet-check.ps1 to throw when
the rootless-nonet-policy block is absent, rather than treating a failed match
as success. Keep the existing continue-on-error validation for a present block
and only call Write-Check with Ok $true after confirming the block exists and is
blocking.
| // Windows can't fall back to a portable load + print, so the | ||
| // spawn failure is unrecoverable there. Other targets run the | ||
| // portable fallback below. The clippy `panic_in_if_then` lint | ||
| // requires the if-then to have an else branch — fold the | ||
| // fallback into `else` so the panic sits on the windows-only path. | ||
| if cfg!(target_os = "windows") { | ||
| panic!("failed to spawn pwsh for self-check: {error}"); | ||
| } else { | ||
| let (max_bytes, total_blocks) = load_profile(); | ||
| println!( | ||
| "pwsh unavailable; running portable alloc-profile SelfCheck fallback.\nSelf-check passed\nMax bytes ceiling: {max_bytes}\nTotal blocks ceiling: {total_blocks}\nProfiler: dhat" | ||
| ); |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
rg -n -C 8 'Command::new\("pwsh"\)|ErrorKind::NotFound|pwsh unavailable|failed to spawn pwsh' .Repository: KooshaPari/SessionLedger
Length of output: 50380
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== alloc_profile relevant section =="
sed -n '54,110p' tests/alloc_profile.rs
echo
echo "== imports =="
sed -n '1,35p' tests/alloc_profile.rs
echo
echo "== cfg target_os windows patterns in Rust files =="
python3 - <<'PY'
from pathlib import Path
hits=[]
for p in Path('.').rglob('*.rs'):
text=p.read_text(errors='replace')
if 'cfg!(target_os = "windows")' in text or 'cfg!(target_os=\"windows\")' in text:
for i,line in enumerate(text.splitlines(),1):
if 'cfg!' in line and ('windows' in line):
hits.append((str(p), i, line.strip()))
for p,i,l in hits:
print(f"{p}:{i}:{l}")
PYRepository: KooshaPari/SessionLedger
Length of output: 4433
Use the fallback only when pwsh is missing.
Command::output() returns an Err for any spawn failure, not only missing executables. In non-Windows targets, errors such as std::io::ErrorKind::PermissionDenied currently fall through to the portable fallback and print Self-check passed without running scripts/alloc-profile-check.ps1. Make the fallback conditional on error.kind() == std::io::ErrorKind::NotFound; panic for all other spawn errors.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@tests/alloc_profile.rs` around lines 85 - 96, Update the non-Windows error
handling around the pwsh `Command::output()` call so the portable fallback runs
only when `error.kind() == std::io::ErrorKind::NotFound`; panic with the
existing failure context for all other spawn errors, including permission
failures. Preserve the Windows behavior and the successful output path.
#432) * fix: tighten per-CodeRabbit review + harden rootless-matrix policy scoping Follow-up to #428 + #429 carrying the CodeRabbit review items that landed after #429's merge. Rebased onto origin/main (which now carries both PRs) to keep the deltas minimal. 1) crates/sl-viewer/tests/properties_viewer_unfinished_tab.rs — redesign the session strategy around per-message Option<i64> timestamps (instead of session-wide) so the detect_unfinished.find_map(|m| m.ts_ms).rev() projection is exercised naturally. Add a 7th property (unfinished_items_last_activity_matches_session_max_ts) that asserts the projected last_activity_ms matches the session's reverse-walk max known ts_ms. Tighten orders_known_timestamps_descending to retain all items (including None) and verify no Some(ts) ever appears after a None (None is the 'unknown last activity' sentinel and must sort last). 2) tests/alloc_profile.rs — narrow non-Windows fallback to NotFound. Hard-panic on any other io::ErrorKind (permission, broken pipe, etc.) since those signal a misconfigured test environment rather than the portable-pwsh-missing case. 3) scripts/rootless-nonet-check.ps1 — throw when the rootless-nonet-policy block is absent (instead of treating a failed match as success). The block is a documented C04 L40 anchor; absence is a drift, not an acceptable state. 4) scripts/rootless-matrix-check.ps1 — same throw-on-absent fix plus the '^ rootless-matrix-policy:.*?continue-on-error:\s*true' regex was bleeding into the next security job's 'continue-on- error: true' (security starts on the line right after the matrix policy job). Replaced with [regex]::Match + a proper terminator ('(?=^ [A-Za-z][\w-]*:\s|\z)') so the check scopes to just the policy block. Mirrors the fix already applied to rootless-nonet-check.ps1 in #429. 5) .github/workflows/ci.yml — pin actions/checkout to the immutable 3d3c42e5 SHA + persist-credentials: false for both policy jobs (rootless-nonet-policy, rootless-matrix-policy). Brings the policy jobs in line with the rest of the repo's checked-in workflows. * fix(viewer): use WebExportProvider::default_subdir instead of hardcoded literals The `WebExportProvider::default_subdir` method has been a dead_code warning since it was added (sl-viewer help unit tests compile the library with RUSTFLAGS=-D warnings, so the lint fails the PR gate). Drive the `defaults` array in `web_export_roots_with_env` from `default_subdir` instead of repeating the literal strings, which both removes the dead_code error and keeps the canonical name table in one place. `default_subdir` becomes `pub` so the function is reachable from outside the impl block via the method path used in `defaults`. Pre-existing on main; surfaced when running `cargo test cli_help` under `-D warnings` on the viewer-unfinished-tab-fixes branch. * fix(ci): align hermetic.yml reusable workflow pin with documented SHA `scripts/reusable-provenance-check.ps1 -SelfCheck` enforces that every caller workflow pins the reusable hermetic build workflow to the SHA documented in `docs/ops/reusable-hermetic-pin.{md,json}` (currently `ec8916547e5678f72fe6894509249f9b23367b80`). `hermetic.yml` was pinned to `a8db485c046f9efab8ee51f25edb8f2458c95694` instead — the documented and the in-file pins drifted. Update the in-file pin to the documented SHA so the C06 L53 anchor holds. Pre-existing on main; surfaced when running `hermetic · reusable workflow provenance (soft)` on the viewer-unfinished-tab-fixes branch. * chore(changelog): WBS-6.2 #432 CI drift follow-ups --------- Co-authored-by: SessionLedger Bot <team@sessionledger.local>
User description
Summary
Four bounded cleanups that were visible as soft CI failures during PR #425/#427 but pre-existed on main. Plus a third viewer property-test file.
scripts/fuzz-cadence-check.ps1drift — the "PR smoke stays short" anchor checkedci.ymlformax_total_time=10, but the 10 sfuzz-smokejob no longer lives there (consolidated intofuzz-blocking.ymlat 30 s). Re-pointed the check at the actual PR fuzz budget:fuzz-blocking.ymlwithmax_total_time=30.scripts/rootless-nonet-check.ps1+.github/workflows/ci.ymldrift — the script expectedci.ymlto cross-referencerootless-nonet.yml, but that anchor had drifted out ofci.ymlwhilesecurity.ymlretained it. Added a smallrootless-nonet-policysmoke job toci.yml(matches thedocs/ops/sandbox-boundary.mdC04 L40 contract that "ci.yml cross-reference | done") and tightened the script's regex socontinue-on-errordetection can't bleed across jobs.cargo clippy --all-targets --all-features -- -D warningscleanups:tests/alloc_profile.rs—clippy::panic_in_if_then: folded the Windowspanic!into an explicitelsebranch.tests/replay_breadth.rs— 6 ×clippy::unnecessary_trailing_commainassert!macros.crates/sl-viewer/tests/properties_viewer_unfinished_tab.rs— 6 proptest properties:reason_label_is_non_empty_for_every_variantreason_label_is_injectiveunfinished_items_is_deterministicunfinished_items_orders_known_timestamps_descendingunfinished_items_ties_break_by_session_id_ascendingunfinished_items_is_length_monotonicValidation
pwsh ./scripts/fuzz-cadence-check.ps1 -SelfCheck— passes.pwsh ./scripts/rootless-nonet-check.ps1 -SelfCheck— passes.cargo clippy --all-targets --all-features --locked -- -D warnings— clean.cargo test -p sl-viewer --test properties_viewer --test properties_viewer_theme_url --test properties_viewer_unfinished_tab --features "desktop parquet" --locked— 16 passed.cargo test --test alloc_profile --all-features --locked— 2 passed.cargo test --test replay_breadth --all-features --locked— 5 passed.WBS / TRACEABILITY
WBS-6.2 evidence list and
TRACEABILITY.jsongaincrates/sl-viewer/tests/properties_viewer_unfinished_tab.rs. Status stayspartial(fuzzing cadence, full loom/shuttle, perf-budget gates remain). CHANGELOG Unreleased documents the new surface and the drift cleanups.Out of scope
tests/sl-viewer/src/settings.rs:351clippy::len_zero (already on main, unrelated).tests/sl-viewer/src/web_exports.rs:48dead_code warning (already on main, unrelated).CodeAnt-AI Description
Add unfinished-tab property coverage and restore accurate CI drift checks
What Changed
Impact
✅ Catches unfinished-tab ordering and labeling regressions✅ Keeps rootless/no-network policy checks visible in pull-request CI✅ Prevents drift from weakening the bounded PR fuzz budget💡 Usage Guide
Checking Your Pull Request
Every time you make a pull request, our system automatically looks through it. We check for security issues, mistakes in how you're setting up your infrastructure, and common code problems. We do this to make sure your changes are solid and won't cause any trouble later.
Talking to CodeAnt AI
Got a question or need a hand with something in your pull request? You can easily get in touch with CodeAnt AI right here. Just type the following in a comment on your pull request, and replace "Your question here" with whatever you want to ask:
This lets you have a chat with CodeAnt AI about your pull request, making it easier to understand and improve your code.
Example
Preserve Org Learnings with CodeAnt
You can record team preferences so CodeAnt AI applies them in future reviews. Reply directly to the specific CodeAnt AI suggestion (in the same thread) and replace "Your feedback here" with your input:
This helps CodeAnt AI learn and adapt to your team's coding style and standards.
Example
Retrigger review
Ask CodeAnt AI to review the PR again, by typing:
Check Your Repository Health
To analyze the health of your code repository, visit our dashboard at https://app.codeant.ai. This tool helps you identify potential issues and areas for improvement in your codebase, ensuring your repository maintains high standards of code health.