Skip to content

fix(check): fail closed on malformed hubs + shared iter_hubs() helper#50

Merged
Connorrmcd6 merged 2 commits into
mainfrom
feat/iter-hubs-gate-fix
Jun 9, 2026
Merged

fix(check): fail closed on malformed hubs + shared iter_hubs() helper#50
Connorrmcd6 merged 2 commits into
mainfrom
feat/iter-hubs-gate-fix

Conversation

@Connorrmcd6

Copy link
Copy Markdown
Owner

Summary

Closes #35 and #36 (one logical change set — the issues recommend doing #36 first so #35 lands cleaner).

#36 — shared hub-iteration helper

Adds Workspace::iter_hubs() (surf-cli/src/workspace.rs) returning Vec<LoadedHub>, each carrying the parse Result<Hub, HubError> per-hub. I/O failure still hard-errors the run; the parse result — the thing that was being handled inconsistently across commands — is now surfaced so every caller must match on it. The four filesystem commands (check, lint, suggest, for) migrate onto it.

stats is intentionally not migrated: it reads hubs from git revisions (git::list_files_at + git::show), not the live filesystem via hub_paths(), so the filesystem-based helper doesn't fit it.

#35 — close the gate's fail-open paths

  • An unparseable hub now emits an Unresolvable divergence (gate exits non-zero) instead of being silently continued.
  • A hash error returns Unresolvable instead of .ok()? mapping it to "no divergence".

Tests

  • New malformed_hub_blocks_check: a frontmatter typo produces one Unresolvable divergence with an invalid hub: … detail.
  • The hash-failure branch is defensive: resolve() runs before hash_anchor_with, so a reachable input that resolves but fails to hash is not readily constructible; existing resolve-error tests already cover the Unresolvable path. No contrived test added.

Verification

  • cargo test --all, cargo clippy --all-targets --all-features -- -D warnings, cargo fmt --all --check all pass.
  • Manual: a scratch workspace with a broken hub makes surf check exit 1 with an UNRESOLVED line and a matching unresolvable JSON divergence.
  • Dogfood: surf lint + surf check pass on this repo (the two anchored functions I edited, check_claim and find, were re-verified — their prose still holds).

🤖 Generated with Claude Code

Connorrmcd6 and others added 2 commits June 9, 2026 20:36
Extract `Workspace::iter_hubs()` so the four filesystem commands (check,
lint, suggest, for) share one hub-load loop that carries the parse result
per-hub, forcing each caller to handle a malformed hub explicitly (#36).

On that helper, close two fail-open paths in the gate (#35): an unparseable
hub now emits an `Unresolvable` divergence instead of being silently skipped,
and a hash error returns `Unresolvable` instead of `.ok()?` counting it clean.

Closes #35, #36

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add a claim on check_workspace governing #35's invariant — an unparseable
hub yields an Unresolvable divergence rather than being silently skipped —
so a future refactor can't quietly reintroduce the fail-open.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@Connorrmcd6 Connorrmcd6 merged commit 8bcbf75 into main Jun 9, 2026
2 checks passed
@Connorrmcd6 Connorrmcd6 deleted the feat/iter-hubs-gate-fix branch June 9, 2026 18:42
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.

check: gate fails open — malformed hubs are skipped and hash errors count as clean

1 participant