Skip to content

Outline first builtin rule#2695

Merged
HerringtonDarkholme merged 5 commits into
mainfrom
outline-first-builtin-rule
Jun 10, 2026
Merged

Outline first builtin rule#2695
HerringtonDarkholme merged 5 commits into
mainfrom
outline-first-builtin-rule

Conversation

@HerringtonDarkholme

@HerringtonDarkholme HerringtonDarkholme commented Jun 10, 2026

Copy link
Copy Markdown
Member

Summary by CodeRabbit

  • Documentation
    • Redesigned "sg outline" spec: top-level Item vs Member model, new flags (--items, --pub-members, --type, --match, --view) and input-kind default behavior
    • Added outline extraction design: syntax-driven extraction pipeline, required output fields, non-goals, and rule catalog guidance
    • Clarified text/JSON contracts: newline-delimited streaming, one-based ranges, revised streamed/grouped shapes, simplified examples and reduced open questions

@coderabbitai

coderabbitai Bot commented Jun 10, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: d8d89ab5-20ef-40ba-97fa-8fa107bb4141

📥 Commits

Reviewing files that changed from the base of the PR and between b3b432b and 910588e.

📒 Files selected for processing (2)
  • docs/design/outline-command.md
  • docs/design/outline-rule-extraction.md

📝 Walkthrough

Walkthrough

This PR refactors the sg outline design into an entries-based model (top-level items and nested members), adds explicit item flags (isImport,isExported) and member isPublic, revises CLI semantics around --items/--view/--json, and adds a rule-driven, syntax-only extraction design and pipeline document.

Changes

Outline command and extraction redesign

Layer / File(s) Summary
Conceptual model and glossary
docs/design/outline-command.md
Introduces "entries" with role (Item/Member), item flags (isImport,isExported), and member-only isPublic; replaces prior roles-array/record terminology.
CLI contract and item selection semantics
docs/design/outline-command.md
Adds --items selection modes and input-type defaults; documents --pub-members, --type, --match, --view, and that item selection occurs before filtering.
Text and JSON output contracts
docs/design/outline-command.md
Defines --json=stream newline-delimited entries with one-based ranges; streamed entries include role, flags, astKind, signature; grouped JSON nests members with isPublic; defines text-output printing rules and empty-output behavior.
Data model and enums
docs/design/outline-command.md
Replaces numeric SymbolType/role arrays with LSP-aligned SymbolType, OutlineRole (Item/Member), and OutlineItem/OutlineMember structs with role, is_import/is_exported (items), and is_public (members).
Runtime integration, examples, and limits
docs/design/outline-command.md
Updates runtime step order (extract → select/filter → print), agent examples to --items/--view/--json, and --limit semantics to count selected top-level items; refreshes rejected-design examples.
Extraction design: introduction & requirements
docs/design/outline-rule-extraction.md
New document: extraction is syntax-only and rule-driven; lists required output fields (items, members, ranges, signatures, flags) and explicit non-goals (no semantic/cross-file resolution).
Extraction strategy, rule catalog, and pipeline
docs/design/outline-rule-extraction.md
Specifies ast-grep-driven pipeline: parse → select extractors → run matchers → derive flags via predicates → deduplicate/merge → attach members → sort → hand model to CLI; catalogs and rule-layering guidance.
Rule catalog guidance and constraints
docs/design/outline-rule-extraction.md
Documents avoidance of export-form duplication, no new DSL, limits on metadata, and guidance for built-in vs custom rule loading (sgconfig.yml, --outline-rules).

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • ast-grep/ast-grep#2691: Adds the serialized outline extractor rule contract and related deserialization/role normalization referenced by the extraction design.
  • ast-grep/ast-grep#2685: Implementation PR for the sg outline command and extraction behavior that this documentation targets.

Poem

🐰 In burrows of docs I hop and write,

Items now sparkle in clearer light,
Imports and exports wave their flags,
Members wear publicness not tags,
Hop on — the outline’s tidy and bright.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 inconclusive)

Check name Status Explanation Resolution
Title check ❓ Inconclusive The title 'Outline first builtin rule' is vague and does not clearly communicate what changes are being made. The PR adds two design documents refactoring the outline command specification and introducing a rule-driven extraction layer, but the title suggests only adding one builtin rule without conveying the scope of design changes. Consider a more descriptive title such as 'Refactor outline command design and add rule extraction specification' to better reflect the comprehensive nature of the documentation changes.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
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.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch outline-first-builtin-rule

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 and usage tips.

@codecov

codecov Bot commented Jun 10, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 86.49%. Comparing base (a09d1f0) to head (910588e).
⚠️ Report is 3 commits behind head on main.

Additional details and impacted files
@@           Coverage Diff           @@
##             main    #2695   +/-   ##
=======================================
  Coverage   86.49%   86.49%           
=======================================
  Files         119      119           
  Lines       20342    20342           
=======================================
  Hits        17595    17595           
  Misses       2747     2747           

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🧹 Nitpick comments (6)
docs/design/outline-command.md (5)

105-105: ⚡ Quick win

Clarify --pub-members flag semantics.

The option is listed as --pub-members without indicating whether it's a boolean flag or takes a value. Based on lines 261-266, it appears to be a boolean flag that filters members. Consider adding the flag notation (e.g., no <VALUE> placeholder) to make this immediately clear in the core options list.

🤖 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 `@docs/design/outline-command.md` at line 105, The docs list the option
`--pub-members` ambiguously; update the `--pub-members` entry to clearly show
it's a boolean flag (no value expected) and that it filters output to public
members only—e.g., remove any `<VALUE>` placeholder and append a short note like
"boolean flag; filters to public members" or "use without value". Also ensure
the description aligns with the behavior implemented in the code path handling
`--pub-members` so readers understand it's an on/off flag.

316-316: 💤 Low value

Clarify metadata printing behavior.

The statement "should not print role, isImport, or isExported labels by default" uses "by default," implying there might be a mode where these are printed. However, no such mode is documented elsewhere. If text output should never print these metadata flags (since they're implicit in the item selection), consider rephrasing to remove the ambiguity: "Text output does not print role, isImport, or isExported labels."

🤖 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 `@docs/design/outline-command.md` at line 316, Update the sentence about
metadata printing to remove the ambiguous "by default" phrase: change the line
that currently reads "It should not print `role`, `isImport`, or `isExported`
labels by default." to an unambiguous statement such as "Text output does not
print `role`, `isImport`, or `isExported` labels." Ensure the exact metadata
identifiers `role`, `isImport`, and `isExported` are preserved so readers can
locate the referenced flags.

180-183: ⚖️ Poor tradeoff

Clarify match field categories for dual-role items.

The three-category model (structure items, import items, export edge items) for --match fields does not clearly specify which fields apply when an item has both isImport=true and isExported=true (e.g., pub use foo as bar in Rust).

Consider specifying that:

  • Items where isImport=true include import-related fields (target, binding name, alias)
  • Items where isExported=true include export-related fields (exported name, target, alias)
  • Items can match against the union of applicable field sets when both flags are true

This would align the match logic with the flag-based model rather than treating items as mutually exclusive categories.

🤖 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 `@docs/design/outline-command.md` around lines 180 - 183, Clarify the --match
field categories by documenting that structure items include fields "symbol
name", "signature", "first source line"; import-related fields (applies when
isImport=true) include "imported target", "binding name", "alias", "signature",
"first source line"; export-related fields (applies when isExported=true)
include "exported name", "target", "alias", "signature", "first source line";
and when an item has both isImport=true and isExported=true it should be matched
against the union of the applicable import and export field sets (not treated as
mutually exclusive) so commands like `pub use foo as bar` can match on either
import or export attributes as appropriate.

607-621: ⚖️ Poor tradeoff

Clarify flag optionality in OutlineFlatSymbol.

OutlineFlatSymbol declares is_import, is_exported, and is_public as Option<bool>, but the JSON contract (lines 448-451) states that:

  • isImport and isExported are always present on items
  • isPublic is absent or null for items, optional for members

Consider one of these approaches:

  1. Keep current flexible design: Document that consumers must check role first, then interpret flags (items ignore is_public, members ignore is_import/is_exported).

  2. Match JSON contract exactly: Make is_import/is_exported required (bool) and document that serialization should always emit them for streamed entries (since streamed entries include both items and members).

Option 1 is more flexible for internal use; option 2 matches the stated JSON contract more precisely.

🤖 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 `@docs/design/outline-command.md` around lines 607 - 621, OutlineFlatSymbol
currently uses Option<bool> for is_import, is_exported and is_public but the
JSON contract requires isImport and isExported to always be present while
isPublic is optional for members; update the struct to make is_import and
is_exported plain bool (retain is_public as Option<bool>), update any
constructors/serializers used by OutlineFlatSymbol to always emit those two
flags for streamed entries, and add a brief doc comment on
OutlineFlatSymbol/OutlineRole explaining that consumers should treat
is_import/is_exported as always present and is_public as optional for members to
match the JSON contract.

58-58: ⚡ Quick win

Forward reference to undefined term.

The alias definition references target before it is defined in the glossary. Consider adding a glossary entry for "Target" or reordering the definitions so that readers encounter the term before it's referenced.

🤖 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 `@docs/design/outline-command.md` at line 58, The glossary entry for "Alias"
references the term `target` before `target` is defined; fix by either adding a
dedicated glossary entry for "Target" (defining what `target` means in this
context) or by reordering the glossary so the `target` definition appears before
the "Alias" entry; update the "Alias" line to reference the newly defined
`target` symbol consistently.
docs/design/outline-rule-extraction.md (1)

788-788: 💤 Low value

Consider adding more detail on the member attachment algorithm.

Line 788 mentions "syntax containment" but doesn't fully specify how direct members are determined:

  • Is "direct" membership based on immediate AST parent-child relationship?
  • How does the algorithm distinguish between direct members and nested items to avoid "arbitrary recursive nesting" (line 358)?
  • What is the behavior when member ranges overlap or when a language has ambiguous nesting?

While this level of detail might be acceptable for a design document, adding a brief explanation of the attachment algorithm would help reviewers verify the approach is sound before implementation.

For example:

8. Attach direct members by AST containment:
   - For each top-level item, find all member-role entries whose range falls within the item's range
   - Exclude member entries that are nested inside other member entries (to avoid recursive nesting)
   - Derive member publicness where the language exposes it
🤖 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 `@docs/design/outline-rule-extraction.md` at line 788, Add a concise
specification of the member-attachment algorithm to clarify "syntax
containment": describe that direct membership is determined by AST containment
(a member-role entry whose source range is fully within the parent's range),
explain that members nested inside other member entries should be excluded to
prevent arbitrary recursive nesting, specify tie-breaking for overlapping ranges
(e.g., prefer the smallest enclosing range or the nearest sibling based on AST
depth), and note that member visibility/publicness is derived from
language-specific metadata when available; reference the terms "syntax
containment", "member-role entries", "member ranges", and "direct members" so
reviewers can map this algorithm to the rest of the document.
🤖 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 `@docs/design/outline-rule-extraction.md`:
- Around line 284-286: The spec contains a contradiction about emitting boolean
fields: reconcile lines referencing isImport, isExported (top-level) and
isPublic (members) so the extractor behavior and JSON contract are consistent;
pick one approach (Option A: always emit these booleans with true/false, or
Option B: omit when false) and update the text at both the paragraph that
currently says "The public CLI JSON contract fills `isImport` and
`isExported`..." and the paragraph that says "field omitted by extractor →
output field is absent" to reflect the chosen approach, and then update the JSON
schema, examples, and any mention of the extractor output accordingly so
consumers and validation rules reference the same rule for `isImport`,
`isExported`, and `isPublic`.
- Around line 784-787: Clarify the difference between step 6 ("Deduplicate") and
step 7 ("Merge") by explicitly stating that step 6 removes exact duplicate
entries produced by the same extractor instance (matching on range, symbol type,
name, and edge target) while step 7 combines semantically equivalent top-level
items produced by different extractor rules (matching on range, symbol type,
name, target, and alias) and then describes the merge behavior (e.g., boolean
flags like isImport and isExported are combined with logical OR, and other
fields are reconciled or preserved as specified). Also clarify whether "edge
target" in step 6 is the same concept as "target" in step 7 (rename or note
equivalence), explain why "alias" is included for top-level merge matching, and
add the suggested explicit example (exact duplicates vs cross-rule semantic
merges such as pub use vs pub export) to illustrate the intended semantics.
- Around line 218-227: The docs describe outline outputs as a placement role
('item'|'member') plus flags (isImport/isExported/isPublic) but the Rust model
currently uses OutlineRole::{Definition,Import,Export} with OutlineRoles
bitflags (see OutlineRole, OutlineRoles and roles: Vec<OutlineRole> in
crates/cli/src/outline/model.rs and rule parsing in
crates/cli/src/outline/rule.rs and default_rule.rs) and wiring is stubbed in
crates/cli/src/outline.rs; either (A) migrate the Rust model and rule parsing to
produce the docs contract (introduce a role enum Item|Member and boolean flags
isImport/isExported/isPublic and update parsing of roles: Vec<OutlineRole> and
outline extraction in outline.rs), or (B) update the docs and add a clear
mapping function/section that converts the existing OutlineRole/OutlineRoles
representation to the docs' role+flags schema (implement a converter used by
outline.rs and document it), so implementation and design stay consistent.

---

Nitpick comments:
In `@docs/design/outline-command.md`:
- Line 105: The docs list the option `--pub-members` ambiguously; update the
`--pub-members` entry to clearly show it's a boolean flag (no value expected)
and that it filters output to public members only—e.g., remove any `<VALUE>`
placeholder and append a short note like "boolean flag; filters to public
members" or "use without value". Also ensure the description aligns with the
behavior implemented in the code path handling `--pub-members` so readers
understand it's an on/off flag.
- Line 316: Update the sentence about metadata printing to remove the ambiguous
"by default" phrase: change the line that currently reads "It should not print
`role`, `isImport`, or `isExported` labels by default." to an unambiguous
statement such as "Text output does not print `role`, `isImport`, or
`isExported` labels." Ensure the exact metadata identifiers `role`, `isImport`,
and `isExported` are preserved so readers can locate the referenced flags.
- Around line 180-183: Clarify the --match field categories by documenting that
structure items include fields "symbol name", "signature", "first source line";
import-related fields (applies when isImport=true) include "imported target",
"binding name", "alias", "signature", "first source line"; export-related fields
(applies when isExported=true) include "exported name", "target", "alias",
"signature", "first source line"; and when an item has both isImport=true and
isExported=true it should be matched against the union of the applicable import
and export field sets (not treated as mutually exclusive) so commands like `pub
use foo as bar` can match on either import or export attributes as appropriate.
- Around line 607-621: OutlineFlatSymbol currently uses Option<bool> for
is_import, is_exported and is_public but the JSON contract requires isImport and
isExported to always be present while isPublic is optional for members; update
the struct to make is_import and is_exported plain bool (retain is_public as
Option<bool>), update any constructors/serializers used by OutlineFlatSymbol to
always emit those two flags for streamed entries, and add a brief doc comment on
OutlineFlatSymbol/OutlineRole explaining that consumers should treat
is_import/is_exported as always present and is_public as optional for members to
match the JSON contract.
- Line 58: The glossary entry for "Alias" references the term `target` before
`target` is defined; fix by either adding a dedicated glossary entry for
"Target" (defining what `target` means in this context) or by reordering the
glossary so the `target` definition appears before the "Alias" entry; update the
"Alias" line to reference the newly defined `target` symbol consistently.

In `@docs/design/outline-rule-extraction.md`:
- Line 788: Add a concise specification of the member-attachment algorithm to
clarify "syntax containment": describe that direct membership is determined by
AST containment (a member-role entry whose source range is fully within the
parent's range), explain that members nested inside other member entries should
be excluded to prevent arbitrary recursive nesting, specify tie-breaking for
overlapping ranges (e.g., prefer the smallest enclosing range or the nearest
sibling based on AST depth), and note that member visibility/publicness is
derived from language-specific metadata when available; reference the terms
"syntax containment", "member-role entries", "member ranges", and "direct
members" so reviewers can map this algorithm to the rest of the document.
🪄 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: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: dbe71c9a-3455-4d4f-8eac-3f22a22d6e27

📥 Commits

Reviewing files that changed from the base of the PR and between 7d37c15 and ec482d3.

📒 Files selected for processing (2)
  • docs/design/outline-command.md
  • docs/design/outline-rule-extraction.md

Comment thread docs/design/outline-rule-extraction.md Outdated
Comment thread docs/design/outline-rule-extraction.md Outdated
Comment thread docs/design/outline-rule-extraction.md Outdated
@HerringtonDarkholme
HerringtonDarkholme added this pull request to the merge queue Jun 10, 2026
Merged via the queue into main with commit f4be826 Jun 10, 2026
3 of 4 checks passed
@HerringtonDarkholme
HerringtonDarkholme deleted the outline-first-builtin-rule branch June 10, 2026 05:02
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