Skip to content

fix(daemon): validate exported OKF documents structurally - #415

Closed
KooshaPari wants to merge 11 commits into
mainfrom
fix/okf-self-validate-20260806
Closed

fix(daemon): validate exported OKF documents structurally#415
KooshaPari wants to merge 11 commits into
mainfrom
fix/okf-self-validate-20260806

Conversation

@KooshaPari

@KooshaPari KooshaPari commented Aug 6, 2026

Copy link
Copy Markdown
Owner

User description

Summary

  • validate on-disk OKF as an OkfDocument instead of coercing graph entities into chat roles
  • enforce OKF version, provenance, duplicate IDs, and relation references
  • add daemon regression coverage for ETL export -> validation

Evidence

  • cargo test validate_on_disk_okf_accepts_daemon_generated_document (1 passed)
  • serve --once --http-bind off -> 1 OKF document
  • validate roundtrip-session --data-dir ... -> {"errors":[],"valid":true}

Known unrelated workspace issue: full cargo fmt --all -- --check is blocked by pre-existing conflict markers in crates/sl-viewer/src/corpus_loader.rs.


CodeAnt-AI Description

Validate exported OKF graphs correctly and add icons to viewer tabs

What Changed

  • The daemon now validates OKF files against their graph structure instead of treating entities as chat messages.
  • Validation reports unsupported versions, provenance mismatches, duplicate entity IDs, and relations that reference missing entities.
  • Validation output remains machine-readable with clear success and failure results, including safe handling of nested bundle IDs.
  • Viewer tabs now show inline icons alongside their labels.
  • Added coverage confirming daemon-generated OKF documents pass structural validation.

Impact

✅ Reliable OKF export validation
✅ Clearer structural validation errors
✅ Faster tab recognition in the viewer

💡 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:

@codeant-ai ask: Your question here

This lets you have a chat with CodeAnt AI about your pull request, making it easier to understand and improve your code.

Example

@codeant-ai ask: Can you suggest a safer alternative to storing this secret?

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:

@codeant-ai: Your feedback here

This helps CodeAnt AI learn and adapt to your team's coding style and standards.

Example

@codeant-ai: Do not flag unused imports.

Retrigger review

Ask CodeAnt AI to review the PR again, by typing:

@codeant-ai: review

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.

Copilot AI lite review requested due to automatic review settings August 6, 2026 11:36
@codeant-ai

codeant-ai Bot commented Aug 6, 2026

Copy link
Copy Markdown

🤖 CodeAnt AI — Review Status

Status Commit Started (UTC) Finished (UTC)
✅ Incremental review completed b00c2d1 Aug 07, 2026 · 03:36 03:37
✅ Reviewed your PR 68099b6 Aug 06, 2026 · 11:36 11:39

@codeant-ai

codeant-ai Bot commented Aug 6, 2026

Copy link
Copy Markdown

Thanks for using CodeAnt! 🎉

We're free for open-source projects. if you're enjoying it, help us grow by sharing.

Share on X ·
Reddit ·
LinkedIn

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@codeant-ai codeant-ai Bot added the size:L This PR changes 100-499 lines, ignoring generated files label Aug 6, 2026
@coderabbitai

coderabbitai Bot commented Aug 6, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@KooshaPari, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 43 minutes

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 4625d836-fbe7-4800-8322-ec4fbc23d8c3

📥 Commits

Reviewing files that changed from the base of the PR and between a58a5db and 8be7da1.

📒 Files selected for processing (1)
  • .github/workflows/ci.yml
📝 Walkthrough

Summary

This PR updates daemon validation to parse on-disk bundles as OkfDocument values. It adds checks for OKF versions, provenance, IDs, and relation references. It preserves {valid, errors} output and safely sanitizes bundle IDs for filenames. It adds ETL export and validation regression coverage.

The PR adds inline icons to viewer tabs and exposes the OKF validation API. It also adds a pull-request CI self-check for evaluation reproducibility and updates the evaluation manifest hash.

Must Fix

  • Run cargo fmt, cargo clippy --workspace -- -D warnings, and cargo test --workspace before merge.

Should Fix

  • Add documentation for validate_okf_document and OkfValidationError if public API documentation is enforced.
  • Confirm that OkfValidationError derives Debug and Clone.

Consider

  • Preserve separate CLI handling for read, parse, and structural validation errors.
  • Add regression coverage for nested bundle IDs and all filename separator escape cases.

Approve / Request Changes

Approve if formatting, clippy, workspace tests, and public API requirements pass. Otherwise, request changes.

Walkthrough

The change adds structural OKF validation, collision-safe bundle filenames, inline SVG viewer tab icons, pull-request reproducibility checks, a Cargo.lock hash update, and a canonical session handoff document.

Changes

OKF validation

Layer / File(s) Summary
OKF validation contract
src/ports/okf.rs, src/lib.rs
Adds OkfValidationError, validate_okf_document, structural document checks, public re-exports, and validation tests.
Bundle lookup and validate command integration
crates/sl-daemon/src/etl.rs, crates/sl-daemon/src/main.rs
Uses injective ID sanitization for bundle paths. The validate command deserializes OkfDocument values, emits {valid, errors}, preserves read and parse errors, and tests ETL output.

Viewer updates

Layer / File(s) Summary
Tab icon rendering
crates/sl-viewer/src/app.rs
Maps tabs to embedded SVG assets and renders each icon before its label.

Reproducibility checks

Layer / File(s) Summary
Evaluation reproducibility wiring
.github/workflows/ci.yml, docs/ops/eval-manifest.json
Adds a pull-request-only evaluation self-check and updates the recorded Cargo.lock SHA-256 digest.

Session handoff

Layer / File(s) Summary
Session handoff record
HANDOFF-session-2026-08-05.md
Documents verified repository state, prior work, unresolved items, follow-up tasks, and verification notes.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Sequence Diagram(s)

sequenceDiagram
  participant ValidateCommand as validate command
  participant Filesystem
  participant OkfDocument
  participant Validator as validate_okf_document

  ValidateCommand->>Filesystem: locate sanitized bundle path
  Filesystem-->>ValidateCommand: return bundle JSON
  ValidateCommand->>OkfDocument: deserialize JSON
  ValidateCommand->>Validator: validate document
  Validator-->>ValidateCommand: return structured errors
  ValidateCommand-->>ValidateCommand: emit validation JSON and exit status
Loading

Possibly related PRs

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the primary change: structural validation of exported OKF documents in the daemon.
Description check ✅ Passed The description accurately covers structural OKF validation, regression coverage, viewer icons, and related CI changes.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches 💡 2
⚔️ Resolve merge conflicts 💡
  • Resolve merge conflict in branch fix/okf-self-validate-20260806
🛠️ Fix failing CI checks 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/okf-self-validate-20260806
✨ Simplify code
  • Create PR with simplified code
  • Commit simplified code in branch fix/okf-self-validate-20260806

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Comment on lines +207 to +215
/// Inline SVG icons for each tab.
const ICON_SVG_BUNDLES: &str = include_str!("../../../assets/icons/line/bundles.svg");
const ICON_SVG_HISTORY: &str = include_str!("../../../assets/icons/line/history.svg");
const ICON_SVG_MEMORY: &str = include_str!("../../../assets/icons/line/memory.svg");
const ICON_SVG_UNFINISHED: &str = include_str!("../../../assets/icons/line/unfinished.svg");
const ICON_SVG_TIMELINE: &str = include_str!("../../../assets/icons/line/timeline.svg");
const ICON_SVG_LIVE: &str = include_str!("../../../assets/icons/line/live.svg");
const ICON_SVG_SEARCH: &str = include_str!("../../../assets/icons/line/search.svg");
const ICON_SVG_REPLAY: &str = include_str!("../../../assets/icons/line/replay.svg");

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggestion: The new documentation and constants were inserted between #[allow(non_snake_case)] and pub fn App(), so the allow attribute now applies to the icon constant rather than the App function. With the repository's denied Clippy lints, the intentionally PascalCase App function can trigger the non_snake_case lint; move the allow attribute directly above the function. [inconsistent naming]

Severity Level: Major ⚠️
- ❌ Strict viewer builds can fail on the `App` naming lint.
- ⚠️ Normal builds may emit an avoidable non-snake-case warning.

Fix in Cursor Fix in VSCode Claude

(Use Cmd/Ctrl + Click for best experience)

Prompt for AI Agent 🤖
This is a comment left during a code review.

**Path:** crates/sl-viewer/src/app.rs
**Line:** 207:215
**Comment:**
	*Inconsistent Naming: The new documentation and constants were inserted between `#[allow(non_snake_case)]` and `pub fn App()`, so the allow attribute now applies to the icon constant rather than the `App` function. With the repository's denied Clippy lints, the intentionally PascalCase `App` function can trigger the `non_snake_case` lint; move the allow attribute directly above the function.

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
👍 | 👎

Comment thread crates/sl-viewer/src/corpus_loader.rs Outdated
Comment on lines +12 to +15
<<<<<<< Updated upstream
use crate::mock_data::sample_sessions;
=======
>>>>>>> Stashed changes

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggestion: Unresolved merge-conflict markers were committed into this Rust source file. They leave the viewer crate in an unmerged state and prevent it from compiling; remove the markers and retain the intended sample_sessions import. [possible bug]

Severity Level: Critical 🚨
- ❌ Viewer crate compilation fails immediately.
- ❌ Viewer tests and desktop/web builds are blocked.

Fix in Cursor Fix in VSCode Claude

(Use Cmd/Ctrl + Click for best experience)

Prompt for AI Agent 🤖
This is a comment left during a code review.

**Path:** crates/sl-viewer/src/corpus_loader.rs
**Line:** 12:15
**Comment:**
	*Possible Bug: Unresolved merge-conflict markers were committed into this Rust source file. They leave the viewer crate in an unmerged state and prevent it from compiling; remove the markers and retain the intended `sample_sessions` import.

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
👍 | 👎

Comment thread src/ports/okf.rs

let mut entity_ids = std::collections::HashSet::with_capacity(document.entities.len());
for (index, entity) in document.entities.iter().enumerate() {
if !entity_ids.insert(entity.id.as_str()) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggestion: The ID set only detects duplicates; it does not reject an empty entity ID. Consequently, a document containing one entity with id: "" passes this validation and relations can legally reference that unusable identifier. Reject empty IDs before inserting them into the uniqueness set. [incomplete implementation]

Severity Level: Major ⚠️
- ⚠️ On-disk OKF validation accepts unusable empty entity IDs.
- ⚠️ Downstream graph consumers may not distinguish an empty node identifier.

Fix in Cursor Fix in VSCode Claude

(Use Cmd/Ctrl + Click for best experience)

Prompt for AI Agent 🤖
This is a comment left during a code review.

**Path:** src/ports/okf.rs
**Line:** 197:197
**Comment:**
	*Incomplete Implementation: The ID set only detects duplicates; it does not reject an empty entity ID. Consequently, a document containing one entity with `id: ""` passes this validation and relations can legally reference that unusable identifier. Reject empty IDs before inserting them into the uniqueness set.

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
👍 | 👎

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 9

🤖 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 `@crates/sl-daemon/src/main.rs`:
- Around line 1359-1379: The existing test only covers successful validation;
add unit tests beside validate_okf_document in src/ports/okf.rs for
unsupported_version, source_id_mismatch, duplicate_entity_id,
dangling_relation_source, and dangling_relation_target. Each test must assert
the validator emits the expected error code and field, while retaining
validate_on_disk_okf_accepts_daemon_generated_document in main.rs for
ETL-to-validation integration coverage.
- Around line 1164-1171: Update the exit decision in run_validate to use
errors.is_empty() directly instead of reading result["valid"] through
serde_json::Value and unwrap_or(false). Preserve the current behavior by exiting
with cli::EXIT_NOT_OK whenever errors is non-empty, while leaving the JSON
output unchanged.
- Line 1178: Apply the same sanitization used by etl::transform_file when
constructing the read path in validate_on_disk_okf: make sanitize accessible as
pub(crate) and join the data directory with sanitize(&bundle_id) before
appending the .okf.json suffix. Preserve the existing filename format while
ensuring read/write round trips support session IDs containing path separators.

In `@crates/sl-viewer/src/app.rs`:
- Around line 217-230: Update icon_svg to map exhaustively from the Tab type
rather than accepting arbitrary string names with a Bundles fallback. Ensure
every Tab variant maps to its corresponding icon constant so newly added or
misspelled variants are caught at compile time.
- Around line 906-909: Update the icon wrapper span in the tab rendering near
tab.label() to include the tab-icon class, and define or reuse the corresponding
.tab-icon styling with a small margin-inline-end so the SVG and label are
visibly separated.
- Around line 906-909: Add aria-hidden="true" to the span wrapper containing
icon_svg(tab.icon()) in the tab rendering, while leaving tab.label() as the
button’s accessible name.

In `@crates/sl-viewer/src/corpus_loader.rs`:
- Around line 12-15: Resolve the merge conflict in corpus_loader.rs by removing
all conflict markers and retaining the use crate::mock_data::sample_sessions;
import required by load_sessions.

In `@HANDOFF-session-2026-08-05.md`:
- Around line 129-130: Update the handoff entry describing
crates/sl-viewer/src/corpus_loader.rs to state that unresolved conflict markers
remain and that the file still references the affected web_exports symbol.
Remove the claim that the markers were resolved, and identify this as a
remaining blocker for reliable workspace checks.
- Around line 1-2: Fix the Markdown spacing in HANDOFF-session-2026-08-05.md by
adding blank lines before and after every affected heading and around the table
near lines 118–125, including all listed ranges. Preserve the existing content
and table structure, and ensure the file passes markdownlint-cli2 MD022 and
MD058.
🪄 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: 95876ea3-1a75-40c9-9dcd-3c7ee1cd1273

📥 Commits

Reviewing files that changed from the base of the PR and between 2c712cb and 68099b6.

📒 Files selected for processing (6)
  • HANDOFF-session-2026-08-05.md
  • crates/sl-daemon/src/main.rs
  • crates/sl-viewer/src/app.rs
  • crates/sl-viewer/src/corpus_loader.rs
  • src/lib.rs
  • src/ports/okf.rs
📜 Review details
⏰ Context from checks skipped due to timeout. (3)
  • GitHub Check: Summary
  • GitHub Check: prepare
  • GitHub Check: browser e2e · axe · responsive · visual
⚠️ CI failures not shown inline (2)

GitHub Check: Summary: The current Mergify configuration is invalid

Conclusion: failure

View job details

* Invalid condition 'author=dependabot[bot] | renovate[bot]' @ root → pull_request_rules → item 1 → conditions → item 0 → author=dependabot[bot] | renovate[bot]
```
Invalid GitHub login
```
* Invalid condition 'author=trunk-io[bot] | mergify[bot] | github-actions[bot]' @ root → pull_request_rules → item 2 → conditions → item 0 → author=trunk-io[bot] | mergify[bot] | github-actions[bot]
```
Invalid GitHub login
```
* Invalid condition 'age&gt;=30d' @ root → pull_request_rules → item 8 → conditions → item 2 → age>=30d
```
Invalid attribute
```
* Extra inputs are not permitted @ root → pull_request_rules → item 0 → actions → post_merge
* Extra inputs are not permitted @ root → pull_request_rules → item 1 → actions → post_merge
* Extra inputs are not permitted @ root → pull_request_rules → item 3 → actions → request_reviews → github_accounts

GitHub Check: Mergify Merge Queue: The current Mergify configuration is invalid

Conclusion: failure

View job details

* Invalid condition 'author=dependabot[bot] | renovate[bot]' @ root → pull_request_rules → item 1 → conditions → item 0 → author=dependabot[bot] | renovate[bot]
```
Invalid GitHub login
```
* Invalid condition 'author=trunk-io[bot] | mergify[bot] | github-actions[bot]' @ root → pull_request_rules → item 2 → conditions → item 0 → author=trunk-io[bot] | mergify[bot] | github-actions[bot]
```
Invalid GitHub login
```
* Invalid condition 'age&gt;=30d' @ root → pull_request_rules → item 8 → conditions → item 2 → age>=30d
```
Invalid attribute
```
* Extra inputs are not permitted @ root → pull_request_rules → item 0 → actions → post_merge
* Extra inputs are not permitted @ root → pull_request_rules → item 1 → actions → post_merge
* Extra inputs are not permitted @ root → pull_request_rules → item 3 → actions → request_reviews → github_accounts
🧰 Additional context used
📓 Path-based instructions (6)
**/*.{rs,toml}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{rs,toml}: Use the Rust toolchain pinned in rust-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:

  • src/ports/okf.rs
  • crates/sl-daemon/src/main.rs
  • crates/sl-viewer/src/app.rs
  • crates/sl-viewer/src/corpus_loader.rs
  • src/lib.rs
**/*.rs

📄 CodeRabbit inference engine (AGENTS.md)

Fix Clippy warnings; do not add #[allow] unless it includes a tracking-issue comment.

Files:

  • src/ports/okf.rs
  • crates/sl-daemon/src/main.rs
  • crates/sl-viewer/src/app.rs
  • crates/sl-viewer/src/corpus_loader.rs
  • src/lib.rs
crates/sl-daemon/**/*.{rs,toml}

📄 CodeRabbit inference engine (AGENTS.md)

Use cargo test --manifest-path crates/sl-daemon/Cargo.toml as the fast inner-loop test command for sl-daemon changes.

Files:

  • crates/sl-daemon/src/main.rs
crates/sl-viewer/**/*.{rs,toml}

📄 CodeRabbit inference engine (AGENTS.md)

crates/sl-viewer/**/*.{rs,toml}: The sl-viewer crate uses Dioxus 0.6; use the Dioxus CLI/toolchain for desktop development and bundling.
Use cargo check -p sl-viewer as the fast inner-loop check for viewer changes.

Files:

  • crates/sl-viewer/src/app.rs
  • crates/sl-viewer/src/corpus_loader.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/src/app.rs
  • crates/sl-viewer/src/corpus_loader.rs
*

📄 CodeRabbit inference engine (AGENTS.md)

*: Perform feature work in a git worktree under .claude/worktrees/, created from origin/main on a branch named <type>/<topic>, rather than working directly on main.
Do not make direct commits to protected main; use a pull request.
Do not use git reset --hard, git stash, or git clean in worktrees.
Do not use --no-verify or bypass hooks without operator approval.
Do not work on a branch or worktree another actor is using.

Files:

  • HANDOFF-session-2026-08-05.md
🪛 LanguageTool
HANDOFF-session-2026-08-05.md

[style] ~137-~137: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ...&str) -> &'static strlookup helper. - Addeddangerous_inner_html: "{icon_svg(tab.i...

(ENGLISH_WORD_REPEAT_BEGINNING_RULE)


[style] ~182-~182: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ...b-pages / per-page additional panels. - No "feed data" affordance — user cannot po...

(ENGLISH_WORD_REPEAT_BEGINNING_RULE)

🪛 markdownlint-cli2 (0.23.2)
HANDOFF-session-2026-08-05.md

[warning] 1-1: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


[warning] 85-85: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


[warning] 91-91: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


[warning] 95-95: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


[warning] 99-99: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


[warning] 109-109: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


[warning] 117-117: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


[warning] 118-118: Tables should be surrounded by blank lines

(MD058, blanks-around-tables)


[warning] 128-128: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


[warning] 133-133: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


[warning] 140-140: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


[warning] 160-160: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


[warning] 164-164: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


[warning] 170-170: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


[warning] 173-173: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


[warning] 178-178: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


[warning] 184-184: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


[warning] 189-189: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


[warning] 192-192: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)

🔇 Additional comments (7)
src/ports/okf.rs (3)

126-139: LGTM!


195-223: LGTM!


176-182: 🩺 Stability & Availability

No change needed.

Exports are anchored at OkfDocument::new(okf: "1.0".into()), and the docs treat okf == "1.0" as the canonical OKF contract for this pipeline.

src/lib.rs (1)

65-68: LGTM!

crates/sl-daemon/src/main.rs (1)

296-300: 🎯 Functional Correctness

The documented exit codes match the CLI constants.

crates/sl-viewer/src/app.rs (2)

97-110: LGTM!


906-909: 📐 Maintainability & Code Quality

Align the Dioxus dependency with the repository guidance and recheck the feature under the pinned Rust toolchain.

crates/sl-viewer/Cargo.toml declares dioxus = "0.7", while the repository guidance states sl-viewer use Dioxus 0.6. The full lockfile build cannot complete in this environment due to missing pkg-config for glib-sys, so the Rust check should be rerun with the pinned toolchain to rule out a local dependency/installation failure.

Comment thread crates/sl-daemon/src/main.rs
Comment thread crates/sl-daemon/src/main.rs Outdated
Comment thread crates/sl-daemon/src/main.rs
Comment on lines +217 to +230
/// Lookup table for tab icon SVGs.
fn icon_svg(tab_icon: &str) -> &'static str {
match tab_icon {
"bundles" => ICON_SVG_BUNDLES,
"history" => ICON_SVG_HISTORY,
"memory" => ICON_SVG_MEMORY,
"unfinished" => ICON_SVG_UNFINISHED,
"timeline" => ICON_SVG_TIMELINE,
"live" => ICON_SVG_LIVE,
"search" => ICON_SVG_SEARCH,
"replay" => ICON_SVG_REPLAY,
_ => ICON_SVG_BUNDLES,
}
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Avoid silently using the Bundles icon for unknown names.

If a new or misspelled icon name is missing from this lookup, the UI displays the Bundles icon without an error. Match directly on Tab, or use one exhaustive mapping, so missing cases fail during compilation.

🤖 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/src/app.rs` around lines 217 - 230, Update icon_svg to map
exhaustively from the Tab type rather than accepting arbitrary string names with
a Bundles fallback. Ensure every Tab variant maps to its corresponding icon
constant so newly added or misspelled variants are caught at compile time.

Comment on lines +906 to +909
span {
dangerous_inner_html: "{icon_svg(tab.icon())}"
}
"{tab.label()}"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Add explicit spacing between the icon and label.

The SVG wrapper has no class or margin. The following text node starts immediately after it. The icon and label can render without visible separation.

Proposed fix
                                         span {
+                                            class: "tab-icon",
                                             dangerous_inner_html: "{icon_svg(tab.icon())}"
                                         }

Add a small margin-inline-end to .tab-icon.

🤖 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/src/app.rs` around lines 906 - 909, Update the icon wrapper
span in the tab rendering near tab.label() to include the tab-icon class, and
define or reuse the corresponding .tab-icon styling with a small
margin-inline-end so the SVG and label are visibly separated.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Mark the decorative SVG as hidden from assistive technology.

The button already exposes tab.label() as its accessible name. Add aria-hidden="true" to the wrapper so screen readers ignore the decorative SVG.

Proposed fix
                                         span {
+                                            "aria-hidden": "true",
                                             dangerous_inner_html: "{icon_svg(tab.icon())}"
                                         }
📝 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.

Suggested change
span {
dangerous_inner_html: "{icon_svg(tab.icon())}"
}
"{tab.label()}"
span {
"aria-hidden": "true",
dangerous_inner_html: "{icon_svg(tab.icon())}"
}
"{tab.label()}"
🤖 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/src/app.rs` around lines 906 - 909, Add aria-hidden="true"
to the span wrapper containing icon_svg(tab.icon()) in the tab rendering, while
leaving tab.label() as the button’s accessible name.

Comment thread crates/sl-viewer/src/corpus_loader.rs Outdated
Comment on lines +1 to +2
# Session Handoff — SessionLedger / Grapheon / asset-engine
**Captured:** 2026-08-05 (final state of the Forge session the user is closing due to length + hallucination drift).

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Fix the reported Markdown lint violations.

markdownlint-cli2 reports MD022 for headings without surrounding blank lines and MD058 for the table near Lines 118-125. Add the required blank lines so the handoff passes the configured Markdown checks.

Also applies to: 85-86, 91-92, 95-96, 99-100, 109-110, 117-125, 128-129, 133-134, 140-141, 160-161, 164-165, 170-171, 173-174, 178-179, 184-185, 189-190, 192-193

🧰 Tools
🪛 markdownlint-cli2 (0.23.2)

[warning] 1-1: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)

🤖 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 `@HANDOFF-session-2026-08-05.md` around lines 1 - 2, Fix the Markdown spacing
in HANDOFF-session-2026-08-05.md by adding blank lines before and after every
affected heading and around the table near lines 118–125, including all listed
ranges. Preserve the existing content and table structure, and ensure the file
passes markdownlint-cli2 MD022 and MD058.

Source: Linters/SAST tools

Comment on lines +129 to +130
- Prior merge deleted `crates/sl-viewer/src/web_exports.rs` but left `mod web_exports;` declaration gone and `use web_exports::*;` remaining in `corpus_loader.rs` (test code) and call sites in production code → `cargo build` broke.
- Fix: recreated `web_exports.rs` with `WebExportProvider::{ChatGpt, Claude, Gemini}`, `web_export_roots_with_env()`, `load_web_export_corpus()`. Re-added `pub mod web_exports;` to `lib.rs`. Fixed `.cloned().collect()` on `Option<&str>` in SVG parts extraction. Resolved `<<<<<<<` conflict markers in `corpus_loader.rs`.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Record the unresolved corpus_loader.rs state accurately.

Line 130 says that the conflict markers were resolved. The current PR context states that crates/sl-viewer/src/corpus_loader.rs still contains unresolved conflict markers and references the affected imported symbol. Update this handoff to record the remaining blocker. Otherwise, the next session may skip a source state that still prevents reliable workspace checks.

🤖 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 `@HANDOFF-session-2026-08-05.md` around lines 129 - 130, Update the handoff
entry describing crates/sl-viewer/src/corpus_loader.rs to state that unresolved
conflict markers remain and that the file still references the affected
web_exports symbol. Remove the claim that the markers were resolved, and
identify this as a remaining blocker for reliable workspace checks.

@codeant-ai

codeant-ai Bot commented Aug 7, 2026

Copy link
Copy Markdown

Thanks for using CodeAnt! 🎉

We're free for open-source projects. if you're enjoying it, help us grow by sharing.

Share on X ·
Reddit ·
LinkedIn

@codeant-ai codeant-ai Bot added size:L This PR changes 100-499 lines, ignoring generated files and removed size:L This PR changes 100-499 lines, ignoring generated files labels Aug 7, 2026
Comment thread crates/sl-daemon/src/main.rs Outdated
"valid": errors.is_empty(),
"errors": errors,
});
println!("{result}");

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

WARNING: JSON output format changed from pretty-printed to compact

The old code used serde_json::to_string_pretty(&result), while the new code uses println!("{result}") which produces compact JSON via Display. This is a behavioral change in the validate command's stdout that could break downstream consumers expecting pretty-printed output.


Reply with @kilocode-bot fix it to have Kilo Code address this issue.

Comment thread src/ports/okf.rs
}

let mut entity_ids = std::collections::HashSet::with_capacity(document.entities.len());
for (index, entity) in document.entities.iter().enumerate() {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

WARNING: Empty entity IDs are not validated

This loop only detects duplicate IDs via HashSet::insert. An entity with id: "" passes validation and is not flagged. Empty IDs are structurally invalid and can cause downstream issues when relations attempt to reference them.


Reply with @kilocode-bot fix it to have Kilo Code address this issue.

@kilo-code-bot

kilo-code-bot Bot commented Aug 7, 2026

Copy link
Copy Markdown

Code Review Summary

Status: No Issues Found | Recommendation: Merge

Files Reviewed (1 file)
  • crates/sl-daemon/src/etl.rs
Previous Review Summaries (4 snapshots, latest commit 3d6e099)

Current summary above is authoritative. Previous snapshots are kept for context only.

Previous review (commit 3d6e099)

Status: No Issues Found | Recommendation: Merge

Files Reviewed (1 file)
  • crates/sl-daemon/src/etl.rs

Previous review (commit c9fa5fd)

Status: No Issues Found | Recommendation: Merge

Files Reviewed (1 file)
  • crates/sl-daemon/src/etl.rs

Previous review (commit fd93386)

Status: 7 Issues Found | Recommendation: Request Changes

Overview

Severity Count
CRITICAL 1
WARNING 3
SUGGESTION 3
Issue Details (click to expand)

CRITICAL

File Line Issue
crates/sl-viewer/src/corpus_loader.rs 15 Unresolved merge-conflict markers prevent compilation

WARNING

File Line Issue
crates/sl-daemon/src/main.rs 1168 JSON output format changed from pretty-printed to compact
crates/sl-viewer/src/app.rs 909 Missing explicit spacing between icon and label / Mark decorative SVG as hidden from assistive technology
src/ports/okf.rs 196 Empty entity IDs are not validated
HANDOFF-session-2026-08-05.md 130 Record the unresolved corpus_loader.rs state accurately

SUGGESTION

File Line Issue
crates/sl-viewer/src/app.rs 230 Avoid silently using the Bundles icon for unknown names
src/ports/okf.rs 197 The ID set only detects duplicates; it does not preserve insertion order
HANDOFF-session-2026-08-05.md 2 Fix the reported Markdown lint violations
Files Reviewed (7 files)
  • HANDOFF-session-2026-08-05.md - 2 issues
  • crates/sl-daemon/src/etl.rs - 0 issues
  • crates/sl-daemon/src/main.rs - 1 issue
  • crates/sl-viewer/src/app.rs - 2 issues
  • crates/sl-viewer/src/corpus_loader.rs - 1 issue
  • src/lib.rs - 0 issues
  • src/ports/okf.rs - 2 issues

Fix these issues in Kilo Cloud

Previous review (commit b00c2d1)

Status: 7 Issues Found | Recommendation: Request Changes

Overview

Severity Count
CRITICAL 1
WARNING 3
SUGGESTION 3
Issue Details (click to expand)

CRITICAL

File Line Issue
crates/sl-viewer/src/corpus_loader.rs 15 Unresolved merge-conflict markers prevent compilation

WARNING

File Line Issue
crates/sl-daemon/src/main.rs 1168 JSON output format changed from pretty-printed to compact
crates/sl-viewer/src/app.rs 909 Missing explicit spacing between icon and label / Mark decorative SVG as hidden from assistive technology
src/ports/okf.rs 196 Empty entity IDs are not validated
HANDOFF-session-2026-08-05.md 130 Record the unresolved corpus_loader.rs state accurately

SUGGESTION

File Line Issue
crates/sl-viewer/src/app.rs 230 Avoid silently using the Bundles icon for unknown names
src/ports/okf.rs 197 The ID set only detects duplicates; it does not preserve insertion order
HANDOFF-session-2026-08-05.md 2 Fix the reported Markdown lint violations
Files Reviewed (7 files)
  • HANDOFF-session-2026-08-05.md - 2 issues
  • crates/sl-daemon/src/etl.rs - 0 issues
  • crates/sl-daemon/src/main.rs - 1 issue
  • crates/sl-viewer/src/app.rs - 2 issues
  • crates/sl-viewer/src/corpus_loader.rs - 1 issue
  • src/lib.rs - 0 issues
  • src/ports/okf.rs - 2 issues

Fix these issues in Kilo Cloud


Reviewed by step-3.7-flash · Input: 64.6K · Output: 12.4K · Cached: 180K

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 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 `@crates/sl-daemon/src/etl.rs`:
- Around line 150-151: Replace the lossy sanitize function in
crates/sl-daemon/src/etl.rs:150-151 with an injective encoding that remains a
single path component, and preserve or migrate existing filenames if supported.
Update the lookup at crates/sl-daemon/src/main.rs:1179-1179 to use the same
mapping. Add an ETL-to-validation regression test covering bundle IDs a/b and
a_b, asserting distinct output paths and preserved source IDs.
🪄 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: 1832e228-b606-4a07-a8e9-a57712826914

📥 Commits

Reviewing files that changed from the base of the PR and between 68099b6 and fd93386.

📒 Files selected for processing (3)
  • crates/sl-daemon/src/etl.rs
  • crates/sl-daemon/src/main.rs
  • src/ports/okf.rs
📜 Review details
⏰ Context from checks skipped due to timeout. (3)
  • GitHub Check: semgrep-cloud-platform/scan
  • GitHub Check: prepare
  • GitHub Check: Summary
⚠️ CI failures not shown inline (2)

GitHub Check: Summary: The current Mergify configuration is invalid

Conclusion: failure

View job details

* Invalid condition 'author=dependabot[bot] | renovate[bot]' @ root → pull_request_rules → item 1 → conditions → item 0 → author=dependabot[bot] | renovate[bot]
```
Invalid GitHub login
```
* Invalid condition 'author=trunk-io[bot] | mergify[bot] | github-actions[bot]' @ root → pull_request_rules → item 2 → conditions → item 0 → author=trunk-io[bot] | mergify[bot] | github-actions[bot]
```
Invalid GitHub login
```
* Invalid condition 'age&gt;=30d' @ root → pull_request_rules → item 8 → conditions → item 2 → age>=30d
```
Invalid attribute
```
* Extra inputs are not permitted @ root → pull_request_rules → item 0 → actions → post_merge
* Extra inputs are not permitted @ root → pull_request_rules → item 1 → actions → post_merge
* Extra inputs are not permitted @ root → pull_request_rules → item 3 → actions → request_reviews → github_accounts

GitHub Check: Mergify Merge Queue: The current Mergify configuration is invalid

Conclusion: failure

View job details

* Invalid condition 'author=dependabot[bot] | renovate[bot]' @ root → pull_request_rules → item 1 → conditions → item 0 → author=dependabot[bot] | renovate[bot]
```
Invalid GitHub login
```
* Invalid condition 'author=trunk-io[bot] | mergify[bot] | github-actions[bot]' @ root → pull_request_rules → item 2 → conditions → item 0 → author=trunk-io[bot] | mergify[bot] | github-actions[bot]
```
Invalid GitHub login
```
* Invalid condition 'age&gt;=30d' @ root → pull_request_rules → item 8 → conditions → item 2 → age>=30d
```
Invalid attribute
```
* Extra inputs are not permitted @ root → pull_request_rules → item 0 → actions → post_merge
* Extra inputs are not permitted @ root → pull_request_rules → item 1 → actions → post_merge
* Extra inputs are not permitted @ root → pull_request_rules → item 3 → actions → request_reviews → github_accounts
🧰 Additional context used
📓 Path-based instructions (3)
**/*.{rs,toml}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{rs,toml}: Use the Rust toolchain pinned in rust-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:

  • src/ports/okf.rs
  • crates/sl-daemon/src/etl.rs
  • crates/sl-daemon/src/main.rs
**/*.rs

📄 CodeRabbit inference engine (AGENTS.md)

Fix Clippy warnings; do not add #[allow] unless it includes a tracking-issue comment.

Files:

  • src/ports/okf.rs
  • crates/sl-daemon/src/etl.rs
  • crates/sl-daemon/src/main.rs
crates/sl-daemon/**/*.{rs,toml}

📄 CodeRabbit inference engine (AGENTS.md)

Use cargo test --manifest-path crates/sl-daemon/Cargo.toml as the fast inner-loop test command for sl-daemon changes.

Files:

  • crates/sl-daemon/src/etl.rs
  • crates/sl-daemon/src/main.rs
🔇 Additional comments (2)
src/ports/okf.rs (1)

197-203: LGTM!

Also applies to: 263-346

crates/sl-daemon/src/main.rs (1)

1360-1379: LGTM!

Comment thread crates/sl-daemon/src/etl.rs Outdated
Comment on lines 150 to 151
pub(crate) fn sanitize(id: &str) -> String {
id.chars().map(|c| if matches!(c, '/' | '\\' | ':') { '_' } else { c }).collect()

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift

Use a collision-free filename encoding for bundle IDs.

sanitize("a/b") and sanitize("a_b") both produce a_b. ETL can overwrite the first document with the second document. Validation can then load and validate the wrong document.

  • crates/sl-daemon/src/etl.rs#L150-L151: replace the lossy mapping with an injective, single-path-component encoding. Preserve or migrate existing output filenames if they are supported.
  • crates/sl-daemon/src/main.rs#L1179-L1179: use the same collision-free mapping for lookup.
  • Add an ETL-to-validation regression test for a/b and a_b that asserts distinct output paths and source IDs.
📍 Affects 2 files
  • crates/sl-daemon/src/etl.rs#L150-L151 (this comment)
  • crates/sl-daemon/src/main.rs#L1179-L1179
🤖 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-daemon/src/etl.rs` around lines 150 - 151, Replace the lossy
sanitize function in crates/sl-daemon/src/etl.rs:150-151 with an injective
encoding that remains a single path component, and preserve or migrate existing
filenames if supported. Update the lookup at
crates/sl-daemon/src/main.rs:1179-1179 to use the same mapping. Add an
ETL-to-validation regression test covering bundle IDs a/b and a_b, asserting
distinct output paths and preserved source IDs.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 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:
- Line 221: Update the actions/checkout step to reference the approved full
commit SHA instead of the mutable v7 tag, and set persist-credentials to false
for this checkout action.
🪄 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: c99a6624-ee45-4db8-aa12-b8c38a86701b

📥 Commits

Reviewing files that changed from the base of the PR and between 3d6e099 and a58a5db.

📒 Files selected for processing (2)
  • .github/workflows/ci.yml
  • docs/ops/eval-manifest.json
📜 Review details
⏰ Context from checks skipped due to timeout. (4)
  • GitHub Check: semgrep-cloud-platform/scan
  • GitHub Check: prepare
  • GitHub Check: browser e2e · axe · responsive · visual
  • GitHub Check: Summary
⚠️ CI failures not shown inline (2)

GitHub Check: Summary: The current Mergify configuration is invalid

Conclusion: failure

View job details

* Invalid condition 'author=dependabot[bot] | renovate[bot]' @ root → pull_request_rules → item 1 → conditions → item 0 → author=dependabot[bot] | renovate[bot]
```
Invalid GitHub login
```
* Invalid condition 'author=trunk-io[bot] | mergify[bot] | github-actions[bot]' @ root → pull_request_rules → item 2 → conditions → item 0 → author=trunk-io[bot] | mergify[bot] | github-actions[bot]
```
Invalid GitHub login
```
* Invalid condition 'age&gt;=30d' @ root → pull_request_rules → item 8 → conditions → item 2 → age>=30d
```
Invalid attribute
```
* Extra inputs are not permitted @ root → pull_request_rules → item 0 → actions → post_merge
* Extra inputs are not permitted @ root → pull_request_rules → item 1 → actions → post_merge
* Extra inputs are not permitted @ root → pull_request_rules → item 3 → actions → request_reviews → github_accounts

GitHub Check: Mergify Merge Queue: The current Mergify configuration is invalid

Conclusion: failure

View job details

* Invalid condition 'author=dependabot[bot] | renovate[bot]' @ root → pull_request_rules → item 1 → conditions → item 0 → author=dependabot[bot] | renovate[bot]
```
Invalid GitHub login
```
* Invalid condition 'author=trunk-io[bot] | mergify[bot] | github-actions[bot]' @ root → pull_request_rules → item 2 → conditions → item 0 → author=trunk-io[bot] | mergify[bot] | github-actions[bot]
```
Invalid GitHub login
```
* Invalid condition 'age&gt;=30d' @ root → pull_request_rules → item 8 → conditions → item 2 → age>=30d
```
Invalid attribute
```
* Extra inputs are not permitted @ root → pull_request_rules → item 0 → actions → post_merge
* Extra inputs are not permitted @ root → pull_request_rules → item 1 → actions → post_merge
* Extra inputs are not permitted @ root → pull_request_rules → item 3 → actions → request_reviews → github_accounts
🧰 Additional context used
🪛 zizmor (1.29.0)
.github/workflows/ci.yml

[warning] 221-221: credential persistence through GitHub Actions artifacts (artipacked): does not set persist-credentials: false

(artipacked)


[error] 221-221: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)

(unpinned-uses)

🔇 Additional comments (2)
.github/workflows/ci.yml (1)

213-220: LGTM!

Also applies to: 222-225

docs/ops/eval-manifest.json (1)

47-47: 🗄️ Data Integrity & Integration

cargo_lock_sha256 matches Cargo.lock.

Comment thread .github/workflows/ci.yml
if: github.event_name == 'pull_request'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== workflow excerpt =="
if [ -f .github/workflows/ci.yml ]; then
  nl -ba .github/workflows/ci.yml | sed -n '200,240p'
else
  echo "missing .github/workflows/ci.yml"
fi

echo
echo "== checkout occurrences =="
rg -n "actions/checkout|persist-credentials|permissions:|pull|GITHUB_TOKEN|pull_request" .github/workflows/ci.yml || true

echo
echo "== repository approved actions? =="
if [ -d .github/actions ]; then
  rg -n "actions/checkout|full commit|commit SHA|actions/checkout@" .github || true
else
  echo "no .github/actions directory"
fi

Repository: KooshaPari/SessionLedger

Length of output: 225


🌐 Web query:

actions/checkout persist-credentials true by default README

💡 Result:

The persist-credentials input for the GitHub actions/checkout action is set to true by default [1][2]. This setting configures the action to persist the authentication token or SSH key in the local git configuration of the checked-out repository [1][3]. This allows your workflow scripts to run authenticated git commands (e.g., git push) without needing to manually configure credentials [1][4]. Important security and operational details regarding this default behavior include: - Purpose: By persisting the token in the local git config, the action enables seamless, authenticated git operations within your workflow steps [1][5]. - Opt-out: You can disable this behavior by explicitly setting persist-credentials: false in your workflow YAML file if you prefer not to have credentials stored in the local git config [1][4]. - Security Enhancement: In newer versions of the action, the credentials are stored in a separate file under the $RUNNER_TEMP directory, rather than being written directly into the standard.git/config file [1][5]. This is designed to improve security by isolating the credential file [1][5]. - Automatic Cleanup: Regardless of the persistence, the credentials are removed during the post-job cleanup phase of the action [1][5]. While there has been community discussion and debate regarding whether this should be true by default due to security concerns [6], it remains the established default configuration in the official actions/checkout action [1][2].

Citations:


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== workflow excerpt =="
if [ -f .github/workflows/ci.yml ]; then
  awk 'NR>=200 && NR<=240 { printf "%4d\t%s\n", NR, $0 }' .github/workflows/ci.yml
else
  echo "missing .github/workflows/ci.yml"
fi

echo
echo "== checkout occurrences =="
grep -n "actions/checkout\|persist-credentials\|permissions:\|pull\|GITHUB_TOKEN\|pull_request" .github/workflows/ci.yml || true

echo
echo "== repository approved actions? =="
if [ -d .github/actions ]; then
  grep -R "actions/checkout\|commit SHA\|actions/checkout@" .github || true
else
  echo "no .github/actions directory"
fi

Repository: KooshaPari/SessionLedger

Length of output: 2744


🌐 Web query:

actionlint GITHUB_TOKEN pull_request workflow syntax warning persist-credentials false actions/checkout default true

💡 Result:

The actionlint tool includes a specific security check that flags the use of actions/checkout without explicitly setting persist-credentials: false [1]. This check is designed to mitigate security risks associated with the default behavior of actions/checkout [2][3]. By default, actions/checkout persists the GITHUB_TOKEN (or other authentication credentials) in the local git configuration of the runner [4][5]. While this allows subsequent steps in the same job to execute authenticated git commands, it also means that any subsequent step—including those executing untrusted code—can access these credentials [6][3]. Setting persist-credentials: false explicitly opts out of this behavior, ensuring the token is not stored in the git configuration [4]. Actionlint identifies this as a potential vulnerability because leaving the default enabled (true) increases the attack surface if a workflow job is compromised [2][7]. Even though the GITHUB_TOKEN is available to the entire job regardless of this setting, minimizing its exposure by not writing it to disk is considered a security best practice [8][6].

Citations:


Pin actions/checkout to a full SHA and set persist-credentials: false.

actions/checkout@v7 is a mutable tag, and this job runs PR-controlled PowerShell with access to the workflow token. Persisting credentials would let unchecked checkout output write a git credential alias to the local runner. Pin the approved commit and disable persistence.

Proposed hardening
-      - uses: actions/checkout@v7
+      - uses: actions/checkout@<approved-40-character-commit-sha> # v7
+        with:
+          persist-credentials: false
🧰 Tools
🪛 zizmor (1.29.0)

[warning] 221-221: credential persistence through GitHub Actions artifacts (artipacked): does not set persist-credentials: false

(artipacked)


[error] 221-221: 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 at line 221, Update the actions/checkout step to
reference the approved full commit SHA instead of the mutable v7 tag, and set
persist-credentials to false for this checkout action.

Source: Linters/SAST tools

@KooshaPari

Copy link
Copy Markdown
Owner Author

Closing as superseded. Cannot auto-rebase due to merge conflicts. Branch preserved locally for reference.

@KooshaPari KooshaPari closed this Aug 7, 2026
@KooshaPari
KooshaPari deleted the fix/okf-self-validate-20260806 branch August 7, 2026 08:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:L This PR changes 100-499 lines, ignoring generated files

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants