feat(refs): hub→hub composition, lint validation pass (#4)#148
Merged
Conversation
Resolve `refs` from forward-declared/inert to a validated hub-composition graph — the first of two stages, deliberately stopping short of verdict propagation per the §9.3 unlock discipline (composition compounds the granularity problem, so prove the base before stacking the cascade). A `refs:` entry now names another hub by a path relative to the referencing hub, optionally `> symbol` to address one claim within it (matched against that claim's `at:` anchor, reusing the segment grammar). `surf lint` blocks a ref that is malformed, doesn't resolve to a loaded hub, points at its own hub, or names a claim the target lacks — the same fail-on-typo reasoning as `covers`. The `check` verdict is untouched: a referenced hub going stale does not yet flag its referrers (PR2). The repo's own hubs now declare their cross-hub refs, and the two prior doc-pointing refs were reclassified to prose links (docs aren't hubs). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Connorrmcd6
added a commit
that referenced
this pull request
Jun 29, 2026
* feat(refs): propagate hub staleness across refs (#4) Second and final stage of refs hub composition (PR1, #148, shipped the validated graph). `surf check` now propagates staleness one hop: a hub that directly references a stale hub — or a stale claim within one, via `> symbol` — inherits a `ReferencedStale` divergence and fails the gate. The signal that flags a dependency now flags everything composed on it. Propagation is one-hop by construction: the stale set is built only from base per-claim divergences, never from other propagated ones, so a chain A → B → C does not cascade. Claim-level refs match the specific diverged claim by anchor-segment suffix, so a ref to a still-clean sibling claim stays green. Dogfood surfaced itself: this change to `check_workspace` diverged its own claim in cli-check.md, which propagated REF-STALE to the two hubs that ref it — re-sealed after documenting the new behavior. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * docs(dogfood): log refs propagation firing on its own commit (#4) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Resolves
refsfrom forward-declared/inert into a validated hub-composition graph — PR1 of 2. This stage deliberately stops short of verdict propagation, per the §9.3 unlock discipline: composition compounds the granularity problem (§8/§11.3), so the validated base ships first and staleness propagation (ReferencedStale) follows in PR2.What changed and why
surf-coreanchor.rs— extractedparse_segmentso the@Npositional-collision grammar is shared rather than duplicated.refs.rs—parse_ref→Ref { path, segments }. A ref is a hub path (./cli-verify.md) optionally followed by> symbolto address one claim within the target (./resolve.md > resolve_nodes), reusing theat:segment grammar. Pure parsing; exported fromlib.rs.surf-cliworkspace.rs—resolve_ref_pathnormalizes a hub-relative ref to a workspace-rel path by component arithmetic (no filesystem access).lint.rs— the workspace loop builds arel → &Hubindex once; newlint_refsblocks a ref that is malformed, doesn't resolve to a loaded hub, points at its own hub, or names a claim the target lacks (same fail-on-typo reasoning ascovers). Thecheckverdict is untouched.Samples + docs
refs:in the 5 hubs that already cross-linked in prose (hash→cli-verify; hub-format→cli-lint/cli-check; cli-workspace→cli-check/cli-lint/config; cli-check→cli-git/cli-verify; cli-git→rename).[].authoring-hubs.md, thehub-formathub's prose, and CHANGELOG.hubs/anchor.md— re-sealed theparse_anchorclaim hash (theparse_segmentextraction is a purechange ≠ falsificationrefactor; the claim's prose is unchanged). The diff is the single hash line.Verification
All run on this branch:
cargo fmt --all --check— cleancargo clippy --all-targets --all-features -- -D warnings— cleancargo test --all— 229 passed, 0 failed (2 pre-existing#[ignore]), incl. 4 newparse_ref+ 7 newlint_refstestssurf lint→ 0 errors (18 pre-existing advisory warnings),surf check→ all anchored spans matchScope
Part of #4 (does not close it). PR2 will add
ReferencedStaleverdict propagation — a hub flagged when a hub it refs goes stale — which completes the issue.🤖 Generated with Claude Code