Skip to content

Make spacetime describe support human-readable versions - #5947

Open
krisajenkins wants to merge 1 commit into
clockworklabs:masterfrom
krisajenkins:describe-human-readable
Open

krisajenkins wants to merge 1 commit into
clockworklabs:masterfrom
krisajenkins:describe-human-readable

Conversation

@krisajenkins

@krisajenkins krisajenkins commented Sep 16, 2026

Copy link
Copy Markdown
Contributor

Run spacetime describe mydb today and it refuses: --json is a required
flag, and its help text promises that "in the future, omitting this will give
human-readable output". This patch brings that glorious future. 😁

spacetime describe [db] now prints the module as readable text, in the
sections Tables, Views, Reducers, Procedures, and Types:

Screenshot 2026-09-16 at 10 39 33

You can narrow it to every entity of one kind, or to one entity by name. The
entity types are tables, reducers, procedures and types, matching the
section headings:

    $ spacetime describe wikiwatch procedures
    fetch_edits(timer: FetchEditsSchedule)  [private]
    fetch_previews(timer: FetchPreviewsSchedule)  [private]

    $ spacetime describe wikiwatch types Thumbnail
    Thumbnail = { url: String, width: U32, height: U32 }

The singular forms (table person) still work, since that's what the
JSON-only command accepted. --format json, or the existing --json
shorthand, prints the raw definitions instead: the whole module, an array for
a listing, or a single def. Text is styled like the migration plan that
spacetime publish prints, and is coloured only when stdout is a terminal and
NO_COLOR is unset.

The renderer is a new describe module in the schema crate, next to the
migration printer whose look it shares.

  • StyledWriter: the colour scheme, colour/no-colour buffer and indent
    helpers move out of TermColorFormatter into a pub(crate) writer that
    both printers use. Migration output is unchanged, and its snapshots pass
    untouched.
  • type_name spells types language-neutrally: U64, Array<T>,
    Option<T>, Timestamp, and named types by their scoped name joined with
    .. It reads the "for generate" typespace, which keeps special types and
    refs intact.
  • Field and variant names come from the case-converted typespace, because
    typespace_for_generate keeps source names (imageUrl, not image_url).
    Column defaults are formatted through WithTypespace, so a sum prints as
    (red = ()) rather than ( = ()).
  • Reducer names arrive already qualified with their submodule
    (lib.end_session), while table, view, procedure and type names are local
    and have the prefix added. Prefixing reducers too would print
    lib.lib.end_session, and a test pins that.
  • Types lists only named types reachable from a column or a signature, and
    leaves out table row types, which their table's block already shows.
    types <name> searches every named type, so a row type seen in a signature
    (FetchEditsSchedule) can still be looked up.
  • Each listing (describe_tables and friends) shares its sorted source with
    the whole-module renderer, and tests pin each one to its module section.
  • CLI: --format text|json defaults to text, using a Format enum now
    shared with sql and logs in common_args. --json conflicts with an
    explicit --format. Whole-module JSON is still the raw, unvalidated def,
    returned before validation, so a module that fails validation can still be
    dumped for debugging. Existing JSON output is byte-for-byte unchanged.
  • Tests: insta snapshots of a fixture covering every section, submodules,
    indexes, constraints, defaults and schedules. The describe smoketest now
    checks the text output, exact single-entity output, --json against
    --format json, and the flag conflict.
  • Docs: the regenerated CLI reference, the cheat sheet, and the CLI agent
    skill, plus its codex-plugin copy, which must match byte for byte.
  • Known gap: inside a submodule table, a column whose type is defined in that
    submodule prints the bare type name, while Types prefixes it with lib..

API and ABI breaking changes

None. spacetime describe <db> without --json used to be an error, so no
existing invocation changes meaning, and JSON output is byte-for-byte
unchanged. --json combined with an explicit --format is now rejected as a
conflict, but --format is new to this command.

Rollback safety impact

n/a

Expected complexity level and risk

  1. The diff is large, but most of it is the new, self-contained renderer and
    its snapshots. The parts that touch existing code are the StyledWriter
    extraction from the migration printer (its snapshots pass untouched) and
    the shared Format enum now used by sql and logs.

Testing

  • Insta snapshots for the renderer: whole module (colour and no colour), a single table, a single reducer.
  • Unit tests pinning each listing to its module section, and submodule reducer names not being double-prefixed.
  • describe smoketest covers text output, exact single-entity output, --json vs --format json, and the flag conflict.
  • Reviewer: run spacetime describe against a real module of your own and check the output reads well.

@krisajenkins krisajenkins changed the title Make spacetime describe print a human-readable schema by default Make spacetime describe support human-readable versions Sep 16, 2026
…uired

flag, and its help text promises that "in the future, omitting this will give
human-readable output". This patch brings that glorious future. 😁

`spacetime describe [db]` now prints the module as readable text, in the
sections Tables, Views, Reducers, Procedures, and Types:

```
    page_previews (public)
      Columns:
        title          String             primary key
        page_id        U64
        rev_id         U64
        display_title  String
        description    Option<String>
        extract        String
        thumbnail      Option<Thumbnail>
        fetched_at     Timestamp
      Indexes:
        page_previews_title_idx_btree  btree (title)
```

You can narrow it to every entity of one kind, or to one entity by name. The
entity types are `tables`, `reducers`, `procedures` and `types`, matching the
section headings:

```
    $ spacetime describe wikiwatch procedures
    fetch_edits(timer: FetchEditsSchedule)  [private]
    fetch_previews(timer: FetchPreviewsSchedule)  [private]

    $ spacetime describe wikiwatch types Thumbnail
    Thumbnail = { url: String, width: U32, height: U32 }
```

The singular forms (`table person`) still work, since that's what the
JSON-only command accepted. `--format json`, or the existing `--json`
shorthand, prints the raw definitions instead: the whole module, an array for
a listing, or a single def. Text is styled like the migration plan that
`spacetime publish` prints, and is coloured only when stdout is a terminal and
`NO_COLOR` is unset.

The renderer is a new `describe` module in the schema crate, next to the
migration printer whose look it shares.

- `StyledWriter`: the colour scheme, colour/no-colour buffer and indent
  helpers move out of `TermColorFormatter` into a `pub(crate)` writer that
  both printers use. Migration output is unchanged, and its snapshots pass
  untouched.
- `type_name` spells types language-neutrally: `U64`, `Array<T>`,
  `Option<T>`, `Timestamp`, and named types by their scoped name joined with
  `.`. It reads the "for generate" typespace, which keeps special types and
  refs intact.
- Field and variant names come from the case-converted typespace, because
  `typespace_for_generate` keeps source names (`imageUrl`, not `image_url`).
  Column defaults are formatted through `WithTypespace`, so a sum prints as
  `(red = ())` rather than `( = ())`.
- Reducer names arrive already qualified with their submodule
  (`lib.end_session`), while table, view, procedure and type names are local
  and have the prefix added. Prefixing reducers too would print
  `lib.lib.end_session`, and a test pins that.
- Types lists only named types reachable from a column or a signature, and
  leaves out table row types, which their table's block already shows.
  `types <name>` searches every named type, so a row type seen in a signature
  (`FetchEditsSchedule`) can still be looked up.
- Each listing (`describe_tables` and friends) shares its sorted source with
  the whole-module renderer, and tests pin each one to its module section.
- CLI: `--format text|json` defaults to `text`, using a `Format` enum now
  shared with `sql` and `logs` in `common_args`. `--json` conflicts with an
  explicit `--format`. Whole-module JSON is still the raw, unvalidated def,
  returned before validation, so a module that fails validation can still be
  dumped for debugging. Existing JSON output is byte-for-byte unchanged.
- Tests: insta snapshots of a fixture covering every section, submodules,
  indexes, constraints, defaults and schedules. The `describe` smoketest now
  checks the text output, exact single-entity output, `--json` against
  `--format json`, and the flag conflict.
- Docs: the regenerated CLI reference, the cheat sheet, and the CLI agent
  skill, plus its codex-plugin copy, which must match byte for byte.
- Known gap: inside a submodule table, a column whose type is defined in that
  submodule prints the bare type name, while Types prefixes it with `lib.`.

# API and ABI breaking changes

None. `spacetime describe <db>` without `--json` used to be an error, so no
existing invocation changes meaning, and JSON output is byte-for-byte
unchanged. `--json` combined with an explicit `--format` is now rejected as a
conflict, but `--format` is new to this command.

# Rollback safety impact

n/a

# Expected complexity level and risk

2. The diff is large, but most of it is the new, self-contained renderer and
its snapshots. The parts that touch existing code are the `StyledWriter`
extraction from the migration printer (its snapshots pass untouched) and
the shared `Format` enum now used by `sql` and `logs`.

# Testing

- [x] Insta snapshots for the renderer: whole module (colour and no colour), a single table, a single reducer.
- [x] Unit tests pinning each listing to its module section, and submodule reducer names not being double-prefixed.
- [x] `describe` smoketest covers text output, exact single-entity output, `--json` vs `--format json`, and the flag conflict.
- [ ] Reviewer: run `spacetime describe` against a real module of your own and check the output reads well.
@krisajenkins
krisajenkins force-pushed the describe-human-readable branch from 3e48393 to e1ca570 Compare September 16, 2026 08:31
@krisajenkins
krisajenkins marked this pull request as ready for review September 16, 2026 09:28
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