Skip to content

interface import: scaffold an interface block from a bound object - #20

Merged
scottypate merged 1 commit into
virtual-cells-binding-modelfrom
interface-import-issue-18
Aug 11, 2026
Merged

interface import: scaffold an interface block from a bound object#20
scottypate merged 1 commit into
virtual-cells-binding-modelfrom
interface-import-issue-18

Conversation

@scottypate

Copy link
Copy Markdown
Contributor

Resolves #18. Stacked on #19 — base is virtual-cells-binding-model, not main. Review that one first.

The change to what was asked for

#18 asked for imported types and descriptions. This emits types only.

Copying warehouse prose into cell.yaml is the rot the issue complains about. Automating the copy makes rot cheap rather than fixing it. The asymmetry that matters:

  • Types are safe to copyverify checks them against the warehouse on every run, so divergence is caught.
  • Descriptions are not — no check exists, so a copy goes stale silently.

The warehouse's prose already rides observed.source_descriptions (shipped in #19), live and unrottable. An author writes a local description: only when they mean something different from the warehouse — which is authorship, not transcription.

Usage

datamk interface import -p prod --bind gold_customer --as qfai_customer
  - name: qfai_customer
    version: 1.0.0
    bind: gold_customer
    # description:                 # what ONE ROW means — yours to write
    grain: []                      # columns that make a row unique
    schema:
      customer_id: string
      credits_balance: decimal
      credits_history:
        type: unmapped             # no datamk name for STRUCT(...) —
                                   # choose one, or drop the column
    contract: experimental

stdout by default; --write splices into the interface: block by byte range rather than round-tripping through serde_yaml, which would destroy the teaching comments. Refuses an existing entry without --force. YAML to stdout, everything else to stderr, so piping is safe.

Decisions worth review

  • type: unmapped rather than dropping the column. verify only checks that declared columns exist, so a dropped column ships as a silent hole in the contract. unmapped fails the existing type check, so it cannot ship by accident.
  • No unit: inference. No warehouse carries it, and guessing USD from a column name is the failure that field exists to prevent.
  • grain: [] and no export description. Both are judgment, not transcription.
  • contract: supported now means the meaning is available — a local description or one on the bound source — rather than restated locally, which would force the copy back in. Note the consequence: an export can claim supported on the strength of prose that lives entirely upstream, so the ratchet's guarantee now depends on a comment nobody in this repo controls.

Verification

657 tests, 0 failures. fmt and clippy clean at -D warnings.

The inverse type mappings are siblings of the existing forward predicates, never edits to them — each pinned by an offline round-trip test asserting every declared name they emit satisfies the forward check. Unmappable types (STRUCT, ARRAY, GEOGRAPHY, BLOB) have explicit coverage. All default CI, no credentials.

🤖 Generated with Claude Code

Emits types, never descriptions. Copying warehouse prose into cell.yaml is
the rot issue #18 complains about, and automating the copy would only make
rot cheap. Types are safe to copy because verify checks them against the
warehouse on every run, so divergence is caught; descriptions have no such
check, so a copy goes stale silently. The warehouse's prose already rides
`observed.source_descriptions`, live and unrottable. An author writes a
local `description:` only when they mean something different from the
warehouse — authorship, not transcription.

  datamk interface import -p prod --bind gold_customer --as qfai_customer

stdout by default, `--write` splices into the `interface:` block by byte
range rather than round-tripping through serde_yaml, which would destroy
the teaching comments. Refuses an existing entry without `--force`. The
YAML goes to stdout and everything else to stderr, so piping is safe.

Types come from the warehouse's own schema; DuckDB stays the authority for
a raw-file source. An unmappable type emits `type: unmapped` with the real
type in a comment rather than dropping the column, since verify only checks
declared columns exist and a dropped one would ship as a hole. No `unit:`
is ever inferred, and `grain` and the export description stay empty because
both are judgment.

`contract: supported` is now satisfied by the meaning being available —
either a local description or one on the bound source — rather than by it
being restated locally, which would have forced the copy straight back in.

The inverse type mappings are siblings of the existing forward predicates,
never edits to them, each pinned by an offline round-trip test asserting
every declared name they emit satisfies the forward check.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@scottypate
scottypate merged commit e575ff7 into virtual-cells-binding-model Aug 11, 2026
2 checks passed
scottypate added a commit that referenced this pull request Aug 13, 2026
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