Skip to content

FR: @sqlView escape valve + managed-elsewhere marker — register a hand-written DB object instead of aborting meta migrate #208

Closed

Description

@dmealing

Summary

Formalizes the escape valve already chartered as "a separate FR to design with Fable" in the #195 follow-ups (spec/roadmap.md, #195 follow-up (a)) and the #195 design doc (2026-07-15-issue-195-projection-readmodel-origins-design.md:23,152). It is out of scope of #195 itself but blocks the same adoption path.

A genuinely irreducible view — recursive CTE, window function, set operation (UNION), or a base the metadata doesn't (yet) model — cannot be synthesized from origin.*. Today a single such view aborts the entire meta migrate run (extract-view-spec.ts:226-231), so an adopter with even one can't migrate anything. The current fallback (a hand-written, unmodeled view) is invisible to the tool: meta migrate can't own it and meta verify --db can't drift-check it.

Two distinct concepts (both must generalize to ANY DB object, not projections only)

1. @sqlView — a metadata-carried, hand-written view body the tool registers but does not author. A worst-case escape hatch inside the metadata file (keeps the SoR the single source of truth):

{ "source.rdb": { "@kind": "view", "@view": "v_report",
    "@sqlView": "SELECT … FROM … WHERE … UNION ALL …" } }

meta migrate emits the CREATE VIEW verbatim, fingerprints it (reuse view-fingerprint.ts), and meta verify --db drift-checks the fingerprint — managed-but-opaque instead of invisible. The tool never parses/derives the SQL; it owns the object's lifecycle, not its contents.

2. A distinct "managed-elsewhere" marker — "this object exists but Flyway / a hand-migration owns its DDL; do not create, drop, or drift-check it." meta migrate skips it (rather than aborting), so one un-modeled object no longer blocks the tree.

The two are orthogonal: (1) is "I give you the DDL, you manage it"; (2) is "someone else manages it, stay out of the way." Both apply to entities and other DB objects, not just view projections.

Why in-metadata (not a side migration file)

Keeps the object visible in the model and drift-gated, and lets the tool make the create-vs-skip decision per marker — the alternative (raw DDL in a Flyway file) drops the object out of the SoR entirely and out of verify --db's sight.

Scope

The two escape attrs on source.rdb (and entities); migrate emits (@sqlView) or skips ("managed-elsewhere") per marker instead of the all-or-nothing abort; verify fingerprints the raw body; generalize across paradigms so the same escape works for any future backend. Design with Fable per the #195 owner ruling (2026-07-15).

Activity

  1. dmealing commented on Jul 16, 2026

    @dmealing
    MemberAuthor

    One more requirement for the escape valve to be usable end-to-end: the external-body marker (@sqlView / managed-elsewhere) must also override derivation-classification. Today viewIsDerived flips a projection to "synthesize" the moment it carries an extends-bound field or identity. But an escape-valve view often needs to state its lineage — a borrowed identity.primary { extends: "Base.id" } (row identity / get-by-id) and/or extends-bound base fields — without the tool trying to synthesize a body it has been explicitly told is external. Please spec that an @sqlView / managed-elsewhere source suppresses synthesis even when identity/fields are extends-bound (ADR-0028's "self-declared under external assembly" already implies this). Without it, an escape-valve view can never declare its row identity — a real case is a hand-written view whose id IS the base entity's id.

  2. added 18 commits that reference this issue on Jul 16, 2026
  3. dmealing commented on Jul 18, 2026

    @dmealing
    MemberAuthor

    Shipped in the coordinated 0.17.0 (npm / PyPI / NuGet) · 7.9.0 (Maven Central) release — live on all four registries (PR #215, tag v0.17.0). Cross-port, conformance-gated. See CHANGELOG [0.17.0].

  4. added a commit that references this issue on Jul 18, 2026
  5. added 2 commits that reference this issue on Jul 26, 2026
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

    area:toolingCLI, packaging, contracts, MCPenhancementNew feature or request

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions