Skip to content

API surface: pre-1.0 DSL keyword renames (project→projection, nav/NavDefinitionSpec drift, hless acronym) #1069

@manwithacat

Description

@manwithacat

Background

The first api_surface_audit cycle (improve-log cycle 113, 2026-05-14) walked the 57-entry docs/api-surface/dsl-constructs.txt baseline and surfaced three concrete keyword renames worth doing pre-1.0.

Pattern across all three: the DSL keyword the user writes diverges from the IR-class the parser builds, or the keyword is opaque to anyone not already onboarded. Each rename is mechanical, well-bounded, and breaking by design — clean breaks before 1.0 per ADR-0003 ("no backward compat shims").

This issue is the tracking umbrella. Each rename can ship as its own PR.


API-001 — projectprojection

Today:

project order_summary "Order summary":
  ...

_dispatch_project at src/dazzle/core/dsl_parser_impl/__init__.py:376 actually calls parse_projection() and appends to fragment.projections. The IR class is ProjectionSpec, the fragment field is projections. Only the keyword is project.

Friction:

  • The keyword and IR-class name disagree, so an agent reading IR cannot reverse-derive the keyword. They have to either grep the dispatch table or guess wrong.
  • project collides with the universal "code project / git repo / package" sense — a DSL reader sees project foo "..." and reasonably assumes "this is the project declaration," not "this is a CQRS projection."

Proposed:

  • Rename keyword projectprojection. Token, dispatch entry, grammar, docs, examples.

Blast radius:

  • Grep ^project across examples/, fixtures/ to find call sites (likely small — projections are an advanced feature).
  • dazzle inspect-api dsl-constructs --write to regenerate baseline.
  • CHANGELOG under Changed.

API-002 — navNavDefinitionSpec drift

Today:

  • Keyword: nav
  • Fragment field: nav_definitions
  • IR class: NavDefinitionSpec

Friction:

  • Same "agent cannot reverse-derive keyword from IR" problem as API-001, just less acute.

Proposed:

  • Pick one canonical form. Options:
    • (a) Rename keyword navnav_definition (matches IR + fragment field; verbose but consistent)
    • (b) Rename IR class NavDefinitionSpecNavSpec + fragment field nav_definitionsnavs (matches the short keyword; matches the pattern of EntitySpec, SurfaceSpec, StorySpec, etc.)

Option (b) is the lighter touch and aligns with the dominant pattern. Recommended.

Blast radius:

  • IR-class rename ripples through every nav_definitions: list[NavDefinitionSpec] annotation. Likely manageable: ~few dozen sites.
  • CHANGELOG under Changed + Removed (the old class export disappears).

API-003 — hless opaque acronym

Today:

hless: strict

grammar_gen.py:47 labels this construct "HLESS Event Semantics" in the eventing category. The acronym is unrecoverable from the keyword hless or the IR class HLESSPragma.

Friction:

  • Every fresh agent / operator who hits this keyword has to grep for its meaning. Unlike most domain terms (entity, surface, ledger), there's no way to recover the meaning from the spelling.
  • New downstream users of the framework will see hless: strict in someone else's DSL and have no breadcrumb.

Proposed:

  • Expand the acronym in both the keyword and the IR class. Options depend on what HLESS expands to:
    • If "Headerless Event Semantics" → event_semantics_pragma keyword + EventSemanticsPragma class
    • If "Hierarchical Less-Strict Event Semantics" (or similar) → spell it out
    • Whatever expansion is canonical: the keyword should be self-describing.
  • If the framework wants to keep a short keyword for brevity, accept it as event_pragma with the IR class still spelled out (similar to how nav is short for NavDefinitionSpec, but in that case we're proposing the OPPOSITE direction). Pick one principle and apply it.

Blast radius:

  • Smaller than the other two — hless_pragma field on ModuleFragment likely has a handful of references.
  • Requires a one-line answer from a maintainer on what HLESS actually stands for. (cc maintainers — I could not derive this from the code.)

Sequencing

API-001 is the highest-leverage and cleanest — recommend doing that first. API-002 next (alignment with the dominant short-keyword pattern). API-003 last because it needs the maintainer's answer on the expansion.

Each can land as a separate PR with its own CHANGELOG entry under Changed; the test_api_surface_drift.py baseline regenerates via dazzle inspect-api dsl-constructs --write once per PR.


Filed by /improve cycle 113 (framework-ux lane, api_surface_audit sub-strategy). See dev_docs/api-surface-audit-log.md and dev_docs/improve-backlog.md (API-001..003 rows) for the audit trail.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions