Skip to content

[osprey-ui] Rules Registry page#277

Open
haileyok wants to merge 15 commits into
mainfrom
hailey/rules-registry
Open

[osprey-ui] Rules Registry page#277
haileyok wants to merge 15 commits into
mainfrom
hailey/rules-registry

Conversation

@haileyok
Copy link
Copy Markdown
Member

@haileyok haileyok commented May 20, 2026

Description

Migrating another internal page to upstream. This one complements the features registry by displaying all of the rules that exist within Osprey.

Changes Made

Backend (osprey_worker):

  • Renamed _features_ast_utils.py_engine_ast_utils.py and promoted _collect_name_references to a public collect_name_references helper now shared by features.py and rules.py.
  • New views/rules.py Flask blueprint: _build_whenrules_ref_count (sub-pass 1, counts WhenRules → Rule refs), _extract_rules_from_engine (sub-pass 2, collects Rule nodes), and rules_list route gated by @require_ability(CanViewDocs).
  • Registered the blueprint in app.py so both /rules and /api/rules resolve.
  • New tests/test_rules.py with 7 tests covering empty engine, response shape, FormatString descriptions, back-reference regression, unused_total correctness, dual-route equality, and 401 gating.

Frontend (osprey_ui):

  • New types/RulesTypes.tsx (RuleInfo, RulesListResponse, SortKey), actions/RulesActions.tsx (getRulesList), and Routes.RULES = '/rules'.
  • New components/rules/RulesPage.tsx — five components in post-nit FeaturesPage form: thin shell uses usePromiseResult + renderFromPromiseResult; RulesPageContent owns a single useReducer<FiltersState, FiltersAction> for filters and pagination, with every filter action atomically resetting page: 1 (no cross-effect useEffect needed); RuleDetail uses the Antd 5 Descriptions styles={{ label: ... }} API.
  • Route + NavBar Manage-section entry (FileTextOutlined, label "Rules") wired in.

Confidence Level

Confidence Level: Claude

Testing

Static / type checks (passed in-session):

  • python3 -c "import ast; ast.parse(...)" on all touched .py files.
  • ruff check --select E,F,I clean on features.py, _engine_ast_utils.py, rules.py, test_rules.py, app.py.
  • cd osprey_ui && npx tsc --noEmit clean.
  • AC4 grep checks pass: no useEffect (except an explanatory comment), no useState, no unbraced arrow callbacks, no deprecated labelStyle.

Checklist

  • Tests pass locally — pending pytest run
  • uv run ruff check . passes — --select E,F,I clean on all touched files
  • uv tool run fawltydeps --check-unused --pyenv .venv passes — pending
  • Updated CHANGELOG.md with my changes, if applicable — not applicable (no CHANGELOG convention spotted in repo)

🤖 Generated with Claude Code

haileyok and others added 9 commits May 20, 2026 18:39
Rename _features_ast_utils.py to _engine_ast_utils.py and move
collect_name_references (formerly _collect_name_references) from
features.py into it. Both features.py and the upcoming rules.py
import the three helpers from one place.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
After moving _collect_name_references to _engine_ast_utils, the imports
for Name and List as AstList are no longer used. Remove them to fix ruff
F401 violations and pass linting.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds /rules endpoint gated by CanViewDocs. _extract_rules_from_engine
walks every source twice: sub-pass 1 builds a whenrules_ref_count map
(WhenRules can textually precede the Rule it references); sub-pass 2
collects Rule nodes and attaches when_all conditions, the description
template, referenced feature names, and the WhenRules reference count.

Not yet registered in app.py — that follows in the next commit.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Mounts the rules blueprint via _register_with_prefix next to the
existing features registration, so /rules and /api/rules both
resolve to the same handler.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Covers: empty engine returns zero-counts, response shape matches
RulesListResponse, referenced_features unions names from when_all
and FormatString descriptions, unused_total correctness, dual-route
equality, 401 for users without CAN_VIEW_DOCS, and the back-reference
regression where WhenRules textually precedes the Rule it names
(justifies the two-sub-pass walk).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds the data layer for the Rules Registry page: RuleInfo and
RulesListResponse types mirroring the backend, a getRulesList action
using HTTPUtils, and the /rules route constant. Page component lands
in the next commit.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Thin RulesPage shell uses usePromiseResult + renderFromPromiseResult.
RulesPageContent owns filter + pagination state in a single
useReducer<FiltersState, FiltersAction> — every filter change
atomically resets page: 1, so no cross-effect setPage useEffect is
needed. RuleDetail uses the Antd 5 styles={{ label: ... }} API
instead of the deprecated labelStyle.

Route + NavBar wiring follow in the next commit.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds /rules route to App.tsx and a Manage-section NavBar entry
('Rules', FileTextOutlined) so the Rules Registry page is reachable
from the sidebar and via direct URL.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The label column was auto-sizing to "Referenced features (N)" with no
breathing room before the value, so it visually butted up against the
chips. Bump label width to 180px and add 16px right padding so every
row has consistent gutter between label and value.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@haileyok
Copy link
Copy Markdown
Member Author

Preview:
image

haileyok and others added 5 commits May 20, 2026 19:54
Run prettier to fix line-length wrapping and ternary formatting that
slipped through Phase 6 — RulesPage.tsx hadn't been formatted before.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The original test placed a WhenRules block textually before the Rule it
referenced within main.sml. The engine validator forbids forward
references within a file ('unknown identifier'), so the fixture failed
at setup before the endpoint was ever exercised — CI caught this.

The two-sub-pass walk's actual justification is cross-source iteration
order: main.sml is iterated first (dict insertion order), and its
WhenRules can reference a Rule defined in an imported source iterated
second. A single-pass walk misses that reference because the Rule
hasn't been recorded yet. Move the Rule into extra_rules.sml,
Import it from main.sml, and rename the test accordingly.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
rules.py: merge the two-sub-pass walk into one. WhenRules counts are
keyed by Rule name (order-independent), so a single AST traversal that
accumulates counts and collects Rule entries, plus a final backfill
loop over rules, gives the same result with one fewer pass over every
statement of every source. Matches the pattern features.py already uses.

RulesPage.tsx: drop the redundant "0 — unused" branch in RuleDetail —
the "unused" tag is already shown in RuleHeader for the same case.
Trim the reducer comment to the actual invariant (no PR context).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Comment thread osprey_ui/src/components/rules/RulesPage.tsx Outdated
Comment thread osprey_ui/src/components/rules/RulesPage.tsx
Per PR review — flatter usages below the top-of-function destructure.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@haileyok haileyok marked this pull request as ready for review May 20, 2026 20:31
@haileyok haileyok requested review from a team, EXBreder, ayubun and vinaysrao1 as code owners May 20, 2026 20:31
@haileyok haileyok requested a review from Copilot May 21, 2026 18:09
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Adds a new “Rules Registry” view to the upstream UI/API, analogous to the existing Features Registry, exposing a catalog of Rule(...) definitions and their usage from WhenRules(...) blocks.

Changes:

  • Backend: adds a /rules (and /api/rules) endpoint gated by CanViewDocs, plus shared AST utilities for name-reference collection.
  • Backend tests: introduces a dedicated test_rules.py suite covering response shape, FormatString descriptions, reference counting, dual-route registration, and auth gating.
  • Frontend: adds a new /rules route and page with filtering/sorting/pagination, types/actions wiring, and a NavBar entry.

Reviewed changes

Copilot reviewed 13 out of 13 changed files in this pull request and generated no comments.

Show a summary per file
File Description
osprey_worker/src/osprey/worker/ui_api/osprey/views/tests/test_rules.py Adds coverage for the new rules registry endpoint (shape, refs, auth, route aliases).
osprey_worker/src/osprey/worker/ui_api/osprey/views/rules.py Implements the Rules API blueprint and extraction logic from the engine AST.
osprey_worker/src/osprey/worker/ui_api/osprey/views/features.py Switches to shared AST helper (collect_name_references) after util consolidation.
osprey_worker/src/osprey/worker/ui_api/osprey/views/_engine_ast_utils.py Generalizes AST helper module and exposes collect_name_references.
osprey_worker/src/osprey/worker/ui_api/osprey/app.py Registers the new rules blueprint (root + /api prefix).
osprey_ui/src/types/RulesTypes.tsx Adds frontend types for rules list payload and sorting.
osprey_ui/src/Constants.tsx Adds Routes.RULES.
osprey_ui/src/components/rules/RulesPage.tsx Implements the Rules Registry UI (filters, sorting, pagination, details view).
osprey_ui/src/components/rules/RulesPage.module.css Styles for the new Rules page.
osprey_ui/src/components/navigation/NavBar.tsx Adds “Rules” entry to the Manage section.
osprey_ui/src/App.tsx Registers the /rules route to render RulesPage.
osprey_ui/src/actions/RulesActions.tsx Adds getRulesList API call wrapper.
CHANGELOG.md Notes the new Rules Registry page addition.

@julietshen
Copy link
Copy Markdown
Member

Feedback from an adopter: Can we add a visual chart on the bottom of each rule to see when / how often it triggers?

@haileyok
Copy link
Copy Markdown
Member Author

Feedback from an adopter: Can we add a visual chart on the bottom of each rule to see when / how often it triggers?

this should be relatively easy to do i think...the data is already in druid so

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.

3 participants