Skip to content

feat(entrypoints): accept heuristics.calls in the rules loader for cross-analyzer parity #187

Description

@rahlk

Problem

codeanalyzer/entrypoints/rules.py accepts exactly one matcher kind under heuristics:
decorators — and rejects unknown keys by design (_TOP_LEVEL_KEYS, and the comment at rules.py:22:
blocks not implemented are "deliberately absent here rather than accepted-and-ignored, so a user file
using them fails loudly instead of loading clean and doing nothing").

codeanalyzer-typescript is adding a second matcher kind to the same block, heuristics.calls, because
its ecosystem declares entrypoints by call as often as by decorator — Express, Koa and Fastify are
app.get('/p', handler), not @Get('/p'). Design and rationale:
codeanalyzer-typescript docs/design/specs/entrypoint-detection.md,
section "The heuristic tier".

The semantics are the ones #185 defined — written spelling, no resolution, runs on every node
regardless of frameworks_detected, confidence: heuristic forced by the loader, runs last, never
doubles a record a framework rule made — applied to a call expression's callee instead of a
decorator. Same tier, same engine, one more shape.

Consequence today: a rules file shared between the two analyzers that contains heuristics.calls is a
hard error in python. That is the loader working as intended, which is exactly why this needs a
decision rather than a workaround.

Scope boundary

Loader acceptance only. Python does not need to act on calls: — it has no call-declared
entrypoint frameworks in its shipped ruleset.

Not in scope: implementing a call-site matcher in python.

Goals

  • heuristics.calls is a known key: validated for shape (a list of rules with id, match, and
    the same optional route/methods spec as decorators, plus handler), then ignored
  • A rules file carrying both heuristics.decorators and heuristics.calls loads clean
  • heuristics.<anything else> still fails loudly, so the "no silent no-ops" property is kept

Caveats and known risks

  • Accepted-and-ignored is the thing rules.py:22 argues against, and rightly. The distinction
    here: calls: is not an unimplemented python feature a user might be relying on — it is a matcher
    kind that has no python meaning. Validating its shape while not acting on it keeps a malformed
    rule loud without pretending python matches calls. Worth stating in the code comment, so the next
    reader does not see it as an exception to the rule.
  • If python ever grows a call-declared framework worth shipping rules for, the key is already there.

Definition of done

  • The shared-format test loads a file with both keys and asserts python produced entrypoints only
    from decorators
  • A heuristics.calls entry with a malformed shape still raises RulesError
  • An unknown key under heuristics still raises RulesError

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions