Skip to content

chore: scaffold M0 — Rust engine crate, CLI, plugin, toolchain, CI#1

Open
amondnet wants to merge 5 commits into
mainfrom
chore/m0-scaffold
Open

chore: scaffold M0 — Rust engine crate, CLI, plugin, toolchain, CI#1
amondnet wants to merge 5 commits into
mainfrom
chore/m0-scaffold

Conversation

@amondnet

@amondnet amondnet commented Jun 23, 2026

Copy link
Copy Markdown
Contributor

Summary

M0 project scaffold for adaptive-fetch — a resilient, site-agnostic public-page reader for Claude Code, with the engine in Rust (native browser TLS-fingerprint impersonation). Engine stages are stubbed; this milestone establishes the crate, CLI, plugin packaging, toolchain, and CI. Design: docs/rfcs/0001-adaptive-fetch.md.

What's included

  • engine-src/ — Rust workspace + crate with the stable public contract (fetch(), FetchResult, Verdict, FetchOptions) and stubbed engine-stage modules (transport / validators / scheduler / waf_detector / phase0 / executor / learning / safety / url_transforms) to fill across milestones M1–M5.
  • CLIadaptive-fetch <URL> [--selector --device --trace --json] with the R6 "NOT EXHAUSTED" failure-gate output; exit 0=validated success / 1=failure.
  • Toolchainmise.toml (rust + bun, fmt/clippy/test/check tasks), orca.yaml (rust worktree setup), .worktreeinclude, .gitignore, rustfmt.toml.
  • Plugin.claude-plugin/plugin.json + skills/adaptive-fetch/SKILL.md stub.
  • CI.github/workflows/ci.yml: fmt + clippy (-D warnings) + build + test, third-party actions pinned to commit SHAs.

Status

Engine currently returns an honest stop_reason="unimplemented" result; network stages land in follow-up milestones (M1: probe + 4-layer validation + SSRF transport).

Verification

Locally: cargo fmt --check, cargo clippy -D warnings, cargo build --locked, cargo test all pass (3 tests). CLI smoke test prints the failure-gate block and exits 1.

Notes

  • This is the first substantive content on the repo; opening as a PR rather than pushing to main directly to respect review workflow.

Summary by cubic

Scaffolded M0 for adaptive-fetch: a Rust engine crate, CLI, Claude Code plugin, dev toolchain, CI, and community health files. Establishes the stable fetch() contract; current runs return stop_reason="unimplemented" (no network yet).

  • New Features
    • Rust workspace + engine crate with FetchResult, Verdict, FetchOptions, and stubbed stages (transport/validators/scheduler/waf_detector/phase0/executor/learning/safety/url_transforms).
    • CLI adaptive-fetch <URL> [--selector --device --trace --json] with exit 0 on validated success, 1 on failure, and an R6 failure gate that prints "NOT EXHAUSTED".
    • Claude Code packaging: .claude-plugin/plugin.json and skills/adaptive-fetch/SKILL.md; design in docs/rfcs/0001-adaptive-fetch.md.
    • Tooling and CI: mise.toml, orca.yaml, and a CI workflow running fmt, clippy (-D warnings), build, and test with actions pinned to SHAs.
    • Community and docs: README, CONTRIBUTING, CODE_OF_CONDUCT, SECURITY; LICENSE copyright set to Passion Factory; .gitignore updated to exclude .claude/settings.local.json.

Written for commit b1f6443. Summary will update on new commits.

Summary by CodeRabbit

  • New Features
    • Launched the adaptive-fetch Claude Code plugin and initial Rust engine/CLI scaffold for adaptive public-page fetching with traceable results and clear “not implemented” exit behavior.
  • Documentation
    • Added README, an architecture RFC, and skill/UX documentation, plus contributor and security policies.
  • Chores
    • Set up CI (format/lint/build/test), pinned toolchains and task commands, workspace scaffolding, and project hygiene files (gitignore, worktree include).
  • Tests
    • Added unit tests covering the current scaffold’s result and verdict semantics.

Set up the adaptive-fetch project skeleton per docs/rfcs/0001-adaptive-fetch.md.

- engine-src/: Rust workspace + crate with the stable public contract
  (fetch(), FetchResult, Verdict, FetchOptions) and stubbed engine-stage
  modules (transport/validators/scheduler/waf_detector/phase0/executor/
  learning/safety/url_transforms) to fill across milestones M1–M5
- CLI `adaptive-fetch <URL> [--selector --device --trace --json]` with the
  R6 "NOT EXHAUSTED" failure-gate output; exit 0=success / 1=failure
- mise.toml (rust+bun toolchain, fmt/clippy/test tasks), orca.yaml (rust
  worktree setup), .worktreeinclude, .gitignore, rustfmt.toml
- .claude-plugin/plugin.json + skills/adaptive-fetch/SKILL.md stub
- CI (.github/workflows/ci.yml): fmt + clippy -D warnings + build + test,
  third-party actions pinned to commit SHAs

Engine returns an honest "unimplemented" result for now; network stages
land in follow-up milestones.
@coderabbitai

coderabbitai Bot commented Jun 23, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 83f1c1cd-88c4-4d07-91fc-6d6c3859697c

📥 Commits

Reviewing files that changed from the base of the PR and between 8b82c2e and 9034887.

📒 Files selected for processing (9)
  • .github/ISSUE_TEMPLATE/bug_report.md
  • .github/ISSUE_TEMPLATE/config.yml
  • .github/ISSUE_TEMPLATE/feature_request.md
  • .github/PULL_REQUEST_TEMPLATE.md
  • CODE_OF_CONDUCT.md
  • CONTRIBUTING.md
  • LICENSE
  • README.md
  • SECURITY.md
✅ Files skipped from review due to trivial changes (7)
  • LICENSE
  • .github/ISSUE_TEMPLATE/feature_request.md
  • .github/PULL_REQUEST_TEMPLATE.md
  • .github/ISSUE_TEMPLATE/bug_report.md
  • CONTRIBUTING.md
  • SECURITY.md
  • README.md

📝 Walkthrough

Walkthrough

Adds the adaptive-fetch RFC, Rust engine scaffold, doc-only stage modules, and repository tooling, workflow, and policy files. The engine currently exposes public options/result types, a stub fetch() entrypoint, and a CLI that prints unimplemented results.

Changes

adaptive-fetch scaffold and docs

Layer / File(s) Summary
RFC and project docs
docs/rfcs/0001-adaptive-fetch.md, README.md, skills/adaptive-fetch/SKILL.md, CODE_OF_CONDUCT.md, CONTRIBUTING.md, SECURITY.md
Adds the RFC, README, skill guide, and repository policy documents describing the adaptive-fetch project, its contract, and contribution and security processes.
Engine public types and entrypoints
engine-src/Cargo.toml, engine-src/src/lib.rs, engine-src/src/main.rs, engine-src/src/options.rs, engine-src/src/result.rs
Adds the Rust engine crate manifest, public fetch options and result types, the stub library entrypoint, and the CLI binary that parses arguments and formats output.
Doc-only engine stage modules
engine-src/src/executor.rs, engine-src/src/learning.rs, engine-src/src/phase0.rs, engine-src/src/safety.rs, engine-src/src/scheduler.rs, engine-src/src/transport.rs, engine-src/src/url_transforms.rs, engine-src/src/validators.rs, engine-src/src/waf_detector.rs
Adds documentation-only module stubs for the planned executor, learning, phase0, safety, scheduler, transport, URL transform, validator, and WAF detector modules.
Workspace, toolchain, and CI
Cargo.toml, mise.toml, rustfmt.toml, .github/workflows/ci.yml
Configures the Cargo workspace, local Rust crate manifest, formatting settings, pinned toolchain tasks, and GitHub Actions CI workflow.
Repository scaffolding and local worktree setup
.gitignore, .claude-plugin/plugin.json, .worktreeinclude, orca.yaml
Adds the plugin manifest, gitignore rules, worktree file inclusion rules, and Orca worktree setup script.

Estimated code review effort: 4 (Complex) | ~60 minutes

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main M0 scaffold work across the Rust engine, CLI, plugin, toolchain, and CI.
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
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch chore/m0-scaffold

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

@socket-security

socket-security Bot commented Jun 23, 2026

Copy link
Copy Markdown

Review the following changes in direct dependencies. Learn more about Socket for GitHub.

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Addedserde@​1.0.2288110093100100
Addedserde_json@​1.0.1508210093100100
Addedclap@​4.6.19910093100100

View full report

@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: 4

🧹 Nitpick comments (1)
orca.yaml (1)

17-17: 🩺 Stability & Availability | 🔵 Trivial

Consider documenting the @pleaseai/worktreeinclude package and its purpose.

Line 17 uses bunx @pleaseai/worktreeinclude`` but lacks inline documentation explaining what this package does. Adding a comment describing its role (e.g., "copies gitignored files to the worktree") would improve clarity for future maintainers.

🤖 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 `@orca.yaml` at line 17, Add an inline or preceding comment to the line
containing the `mise exec -- bunx `@pleaseai/worktreeinclude`` command that
clearly describes the purpose and functionality of the `@pleaseai/worktreeinclude`
package, such as explaining that it copies gitignored files to the worktree.
This comment should provide enough context for future maintainers to understand
why this package is being executed and what role it plays in the workflow.
🤖 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 20: The actions/checkout action on line 20 is missing the
persist-credentials parameter, which leaves the workflow token in git config and
creates a security vulnerability. Add persist-credentials: false as a parameter
to the actions/checkout action to ensure credentials are not persisted in the
git configuration for subsequent workflow steps, thereby hardening the CI
security posture.

In `@engine-src/src/lib.rs`:
- Around line 56-63: The FetchResult initialization lists "M4: Playwright
fallback" in the untried_routes vector, but sets must_invoke_playwright_mcp to
false. This inconsistency violates the failure-gate contract by failing to
signal that Playwright should be invoked. Change must_invoke_playwright_mcp from
false to true to correctly indicate that Playwright remains as an untried
fallback option and should be escalated by the CLI when needed.

In `@engine-src/src/result.rs`:
- Around line 80-82: The TODO comment above the `#[serde(skip)]` attribute on
the `content` field is stale and misleading. The comment claims that excluding
the field from JSON output is a TODO for M1, but the `#[serde(skip)]` macro
attribute already implements this behavior. Update or remove the TODO
designation from the comment to accurately reflect that the feature is already
implemented. You may keep the descriptive part about large HTML bloating trace
output if it provides useful context, but remove the TODO(M1) reference since it
no longer applies.
- Around line 43-49: The is_terminal_nonsuccess method incorrectly classifies
Verdict::RateLimited as terminal non-success, which contradicts the
documentation on line 27 that identifies RateLimited as transient. Remove
Verdict::RateLimited from the matches statement in the is_terminal_nonsuccess
method so that 429 rate-limited responses are treated as transient and allow
retries to continue, rather than prematurely stopping the retry loop.

---

Nitpick comments:
In `@orca.yaml`:
- Line 17: Add an inline or preceding comment to the line containing the `mise
exec -- bunx `@pleaseai/worktreeinclude`` command that clearly describes the
purpose and functionality of the `@pleaseai/worktreeinclude` package, such as
explaining that it copies gitignored files to the worktree. This comment should
provide enough context for future maintainers to understand why this package is
being executed and what role it plays in the workflow.
🪄 Autofix (Beta)

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

Review profile: CHILL

Plan: Pro Plus

Run ID: a5827764-f014-4af4-a70c-2964071ef9bf

📥 Commits

Reviewing files that changed from the base of the PR and between ca4bf02 and 8b82c2e.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (25)
  • .claude-plugin/plugin.json
  • .github/workflows/ci.yml
  • .gitignore
  • .worktreeinclude
  • Cargo.toml
  • README.md
  • docs/rfcs/0001-adaptive-fetch.md
  • engine-src/Cargo.toml
  • engine-src/src/executor.rs
  • engine-src/src/learning.rs
  • engine-src/src/lib.rs
  • engine-src/src/main.rs
  • engine-src/src/options.rs
  • engine-src/src/phase0.rs
  • engine-src/src/result.rs
  • engine-src/src/safety.rs
  • engine-src/src/scheduler.rs
  • engine-src/src/transport.rs
  • engine-src/src/url_transforms.rs
  • engine-src/src/validators.rs
  • engine-src/src/waf_detector.rs
  • mise.toml
  • orca.yaml
  • rustfmt.toml
  • skills/adaptive-fetch/SKILL.md

Comment thread .github/workflows/ci.yml
name: fmt + clippy + build + test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2

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

Disable credential persistence in checkout step.

Line 20 uses actions/checkout without persist-credentials: false; this leaves the workflow token in git config for later steps and weakens CI hardening.

Suggested patch
-      - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
+      - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
+        with:
+          persist-credentials: false
📝 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
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
persist-credentials: false
🧰 Tools
🪛 zizmor (1.26.1)

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

(artipacked)

🤖 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 20, The actions/checkout action on line 20
is missing the persist-credentials parameter, which leaves the workflow token in
git config and creates a security vulnerability. Add persist-credentials: false
as a parameter to the actions/checkout action to ensure credentials are not
persisted in the git configuration for subsequent workflow steps, thereby
hardening the CI security posture.

Source: Linters/SAST tools

Comment thread engine-src/src/lib.rs
Comment on lines +56 to +63
untried_routes: vec![
"M1: probe + 4-layer validation + SSRF transport".to_string(),
"M2: diversity grid scheduler + WAF detection".to_string(),
"M3: Phase 0 official-API router".to_string(),
"M4: Playwright fallback".to_string(),
],
must_invoke_playwright_mcp: false,
}

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 | ⚡ Quick win

Set must_invoke_playwright_mcp when Playwright remains untried.

fetch() advertises "M4: Playwright fallback" as untried, but Line 62 sets must_invoke_playwright_mcp to false. That breaks the FetchResult failure-gate contract and suppresses the CLI’s explicit MCP escalation hint.

Proposed fix
         untried_routes: vec![
             "M1: probe + 4-layer validation + SSRF transport".to_string(),
             "M2: diversity grid scheduler + WAF detection".to_string(),
             "M3: Phase 0 official-API router".to_string(),
             "M4: Playwright fallback".to_string(),
         ],
-        must_invoke_playwright_mcp: false,
+        must_invoke_playwright_mcp: 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.

Suggested change
untried_routes: vec![
"M1: probe + 4-layer validation + SSRF transport".to_string(),
"M2: diversity grid scheduler + WAF detection".to_string(),
"M3: Phase 0 official-API router".to_string(),
"M4: Playwright fallback".to_string(),
],
must_invoke_playwright_mcp: false,
}
untried_routes: vec![
"M1: probe + 4-layer validation + SSRF transport".to_string(),
"M2: diversity grid scheduler + WAF detection".to_string(),
"M3: Phase 0 official-API router".to_string(),
"M4: Playwright fallback".to_string(),
],
must_invoke_playwright_mcp: 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 `@engine-src/src/lib.rs` around lines 56 - 63, The FetchResult initialization
lists "M4: Playwright fallback" in the untried_routes vector, but sets
must_invoke_playwright_mcp to false. This inconsistency violates the
failure-gate contract by failing to signal that Playwright should be invoked.
Change must_invoke_playwright_mcp from false to true to correctly indicate that
Playwright remains as an untried fallback option and should be escalated by the
CLI when needed.

Comment thread engine-src/src/result.rs
Comment on lines +43 to +49
/// "Stop the grid — more TLS attempts cannot help." 429 is included here
/// (don't hammer) but is surfaced as a *transient* route by the failure gate.
pub fn is_terminal_nonsuccess(self) -> bool {
matches!(
self,
Verdict::AuthRequired | Verdict::NotFound | Verdict::RateLimited
)

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

Align RateLimited terminality with the transient 429 contract.

Line 27 documents RateLimited as transient, but Lines 45-49 classify it as terminal non-success. That will prematurely stop retries once this helper drives scheduler control flow.

Suggested fix
     pub fn is_terminal_nonsuccess(self) -> bool {
         matches!(
             self,
-            Verdict::AuthRequired | Verdict::NotFound | Verdict::RateLimited
+            Verdict::AuthRequired | Verdict::NotFound
         )
     }
🤖 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 `@engine-src/src/result.rs` around lines 43 - 49, The is_terminal_nonsuccess
method incorrectly classifies Verdict::RateLimited as terminal non-success,
which contradicts the documentation on line 27 that identifies RateLimited as
transient. Remove Verdict::RateLimited from the matches statement in the
is_terminal_nonsuccess method so that 429 rate-limited responses are treated as
transient and allow retries to continue, rather than prematurely stopping the
retry loop.

Comment thread engine-src/src/result.rs
Comment on lines +80 to +82
/// Fetched body. TODO(M1): exclude from `--json` (emit `content_length`
/// instead) so large HTML never bloats the trace output.
#[serde(skip)]

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

Update the stale TODO on content JSON behavior.

Lines 80-82 say JSON exclusion is TODO(M1), but #[serde(skip)] already implements it. This comment is now misleading.

Suggested fix
-    /// Fetched body. TODO(M1): exclude from `--json` (emit `content_length`
-    /// instead) so large HTML never bloats the trace output.
+    /// Fetched body. Excluded from `--json`; use `content_length()` for
+    /// lightweight reporting in structured output.
📝 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
/// Fetched body. TODO(M1): exclude from `--json` (emit `content_length`
/// instead) so large HTML never bloats the trace output.
#[serde(skip)]
/// Fetched body. Excluded from `--json`; use `content_length()` for
/// lightweight reporting in structured output.
#[serde(skip)]
🤖 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 `@engine-src/src/result.rs` around lines 80 - 82, The TODO comment above the
`#[serde(skip)]` attribute on the `content` field is stale and misleading. The
comment claims that excluding the field from JSON output is a TODO for M1, but
the `#[serde(skip)]` macro attribute already implements this behavior. Update or
remove the TODO designation from the comment to accurately reflect that the
feature is already implemented. You may keep the descriptive part about large
HTML bloating trace output if it provides useful context, but remove the
TODO(M1) reference since it no longer applies.

@cubic-dev-ai cubic-dev-ai 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.

1 issue found across 26 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name=".github/workflows/ci.yml">

<violation number="1" location=".github/workflows/ci.yml:20">
P2: Set `persist-credentials: false` on the checkout step. Without it, the workflow token remains in `.git/config` and is accessible to all subsequent steps — a security hardening gap, especially since this workflow runs third-party actions (mise-action).</violation>
</file>
Architecture diagram
sequenceDiagram
    participant Dev as Developer
    participant CLI as adaptive-fetch binary
    participant Engine as engine lib (adaptive_fetch)
    participant CI as GitHub Actions CI
    participant Tool as mise / cargo

    Note over Dev,Engine: M0 Stub Flow

    Dev->>CLI: adaptive-fetch <URL> [--json] [--trace]
    CLI->>CLI: Parse args via clap
    CLI->>Engine: fetch(url, &FetchOptions)
    Engine-->>CLI: FetchResult { ok=false, stop_reason="unimplemented", untried_routes=[...] }
    alt --json flag
        CLI->>CLI: Serialize FetchResult to JSON (content excluded)
        CLI-->>Dev: Print JSON to stdout
    else default text output
        CLI->>CLI: Print verdict, stop reason, content length
        opt --trace
            CLI->>CLI: Print each Attempt from trace
        end
        Note over CLI: R6 failure gate
        CLI->>CLI: Print "NOT EXHAUSTED" block with untried_routes
    end
    CLI-->>Dev: Exit code 1

    Note over Dev,CI: CI Pipeline (on push/PR)

    CI->>Tool: mise install (rust + bun)
    Tool-->>CI: Toolchain ready
    CI->>Tool: cargo fmt --all -- --check
    Tool-->>CI: format ok
    CI->>Tool: cargo clippy --all-targets -- -D warnings
    Tool-->>CI: clippy ok
    CI->>Tool: cargo build --locked
    Tool-->>CI: binary built
    CI->>Tool: cargo test --locked
    Tool-->>CI: 3 tests pass
    CI-->>CI: Job completes
Loading

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread .github/workflows/ci.yml
name: fmt + clippy + build + test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2: Set persist-credentials: false on the checkout step. Without it, the workflow token remains in .git/config and is accessible to all subsequent steps — a security hardening gap, especially since this workflow runs third-party actions (mise-action).

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At .github/workflows/ci.yml, line 20:

<comment>Set `persist-credentials: false` on the checkout step. Without it, the workflow token remains in `.git/config` and is accessible to all subsequent steps — a security hardening gap, especially since this workflow runs third-party actions (mise-action).</comment>

<file context>
@@ -0,0 +1,26 @@
+    name: fmt + clippy + build + test
+    runs-on: ubuntu-latest
+    steps:
+      - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
+      # Installs the toolchain pinned in mise.toml ([tools] rust + bun).
+      - uses: jdx/mise-action@e6a8b3978addb5a52f2b4cd9d91eafa7f0ab959d # v4.2.0
</file context>

@greptile-apps

greptile-apps Bot commented Jul 1, 2026

Copy link
Copy Markdown

Greptile Summary

This PR scaffolds M0 of adaptive-fetch: a Rust engine crate with the stable public contract (fetch(), FetchResult, Verdict, FetchOptions), a CLI, Claude Code plugin packaging, dev toolchain, and CI. All engine stages return an honest stop_reason="unimplemented" result; no network code lands here.

  • Engine contractresult.rs and options.rs define the stable types that M1–M5 will fill in; three unit tests cover the scaffold invariants and the R6 exhaustive-default.
  • CLI — exit 0/1, --selector/--device/--trace/--json flags, and the R6 "⛔ NOT EXHAUSTED" failure-gate are wired up correctly for smoke-testing.
  • Toolchain & CImise.toml pins Rust to 1.94 with rustfmt+clippy; the GitHub Actions workflow runs fmt → clippy (-D warnings) → build --locked → test --locked with all third-party actions pinned to commit SHAs.

Confidence Score: 5/5

Safe to merge — this is a pure scaffold with no live network code; the only runnable logic is unit tests against stub return values.

All engine stages are explicitly stubbed and return a fixed unimplemented result, so there is no behavioural regression risk. The public contract types are straightforward, the CLI is wired correctly, and CI enforces clippy with -D warnings and --locked builds. Both findings are design-level observations that do not affect the correctness of the scaffold.

engine-src/src/options.rs has a minor dependency-graph concern worth addressing before M1 adds real library consumers.

Important Files Changed

Filename Overview
engine-src/src/result.rs Defines the stable public contract (FetchResult, Verdict, Attempt). RateLimited is documented as transient but is_terminal_nonsuccess() returns true for it (flagged in previous review).
engine-src/src/lib.rs Honest M0 scaffold: fetch() immediately returns stop_reason="unimplemented" with all milestones in untried_routes. Three unit tests cover the core invariants.
engine-src/src/main.rs CLI is well-structured with correct exit codes and R6 failure gate. --trace is silently ignored when --json is also passed.
engine-src/src/options.rs DeviceClass derives clap::ValueEnum inside the library crate, making clap a transitive dependency for any downstream library consumer.
.github/workflows/ci.yml Compact CI: fmt → clippy (-D warnings) → build (--locked) → test (--locked), third-party actions pinned to commit SHAs.
engine-src/Cargo.toml Minimal deps for M0. clap is in [dependencies] rather than isolated to the binary, leaking into library consumers.
mise.toml Rust pinned to 1.94 with rustfmt+clippy; bun = "latest" is unpinned (flagged in a previous thread). Task definitions mirror CI.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    CLI["CLI: adaptive-fetch URL\n--selector --device --trace --json"]
    PARSE["Clap: parse args to FetchOptions"]
    FETCH["fetch(url, opts) in lib.rs"]
    STUB["M0 stub: ok=false, stop_reason=unimplemented"]
    JSON_OUT["--json: FetchResult to stdout"]
    HUMAN_OUT["non-json: content to stdout, summary+gate to stderr"]
    TRACE["--trace: per-attempt diagnostics to stderr"]
    EXIT["exit 0 (ok) / exit 1 (failure)"]
    CLI --> PARSE --> FETCH --> STUB
    STUB --> JSON_OUT --> EXIT
    STUB --> HUMAN_OUT --> EXIT
    STUB --> TRACE --> EXIT
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
flowchart TD
    CLI["CLI: adaptive-fetch URL\n--selector --device --trace --json"]
    PARSE["Clap: parse args to FetchOptions"]
    FETCH["fetch(url, opts) in lib.rs"]
    STUB["M0 stub: ok=false, stop_reason=unimplemented"]
    JSON_OUT["--json: FetchResult to stdout"]
    HUMAN_OUT["non-json: content to stdout, summary+gate to stderr"]
    TRACE["--trace: per-attempt diagnostics to stderr"]
    EXIT["exit 0 (ok) / exit 1 (failure)"]
    CLI --> PARSE --> FETCH --> STUB
    STUB --> JSON_OUT --> EXIT
    STUB --> HUMAN_OUT --> EXIT
    STUB --> TRACE --> EXIT
Loading

Reviews (2): Last reviewed commit: "chore: gitignore .claude/settings.local...." | Re-trigger Greptile

Comment thread mise.toml
# optional npm-distributed wrapper. The engine itself needs no JS.
[tools]
rust = { version = "1.94", components = "rustfmt,clippy", profile = "minimal" }
bun = "latest"

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 The file is titled "Pinned local toolchain" but bun = "latest" is not pinned — any new bun release will silently change the toolchain for every developer and in CI. Rust is correctly pinned to 1.94; bun should follow the same pattern with a specific version number.

Suggested change
bun = "latest"
bun = "1.2"
Prompt To Fix With AI
This is a comment left during a code review.
Path: mise.toml
Line: 8

Comment:
The file is titled "Pinned local toolchain" but `bun = "latest"` is not pinned — any new bun release will silently change the toolchain for every developer and in CI. Rust is correctly pinned to `1.94`; bun should follow the same pattern with a specific version number.

```suggestion
bun = "1.2"
```

How can I resolve this? If you propose a fix, please make it concise.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Fix in Claude Code

Comment thread engine-src/src/result.rs
Comment on lines +80 to +83
/// Fetched body. TODO(M1): exclude from `--json` (emit `content_length`
/// instead) so large HTML never bloats the trace output.
#[serde(skip)]
pub content: String,

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 The TODO says "exclude from --json (emit content_length instead)", but #[serde(skip)] already omits content from JSON. What isn't done yet is adding a serialized content_length field to the JSON output. The comment should reflect what still needs to land in M1 to avoid making future implementers think the work is already complete.

Suggested change
/// Fetched body. TODO(M1): exclude from `--json` (emit `content_length`
/// instead) so large HTML never bloats the trace output.
#[serde(skip)]
pub content: String,
/// Fetched body. Excluded from `--json` via `#[serde(skip)]`.
/// TODO(M1): add a serialized `content_length` field so JSON consumers
/// can inspect body size without the full text bloating the trace output.
#[serde(skip)]
pub content: String,
Prompt To Fix With AI
This is a comment left during a code review.
Path: engine-src/src/result.rs
Line: 80-83

Comment:
The TODO says "exclude from `--json` (emit `content_length` instead)", but `#[serde(skip)]` already omits `content` from JSON. What isn't done yet is adding a serialized `content_length` field to the JSON output. The comment should reflect what still needs to land in M1 to avoid making future implementers think the work is already complete.

```suggestion
    /// Fetched body. Excluded from `--json` via `#[serde(skip)]`.
    /// TODO(M1): add a serialized `content_length` field so JSON consumers
    /// can inspect body size without the full text bloating the trace output.
    #[serde(skip)]
    pub content: String,
```

How can I resolve this? If you propose a fix, please make it concise.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Fix in Claude Code

Keep internal marketplace config and telemetry repo labels out of
upstream — the file is personal (deep-merged by pleaseai/oss
apply-settings.sh) and must never reach the public history.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant