Skip to content

th-schema-pull: smoo config schema pull — sync the local schema from remote - #493

Merged
brentrager merged 2 commits into
mainfrom
th-schema-pull
Aug 20, 2026
Merged

th-schema-pull: smoo config schema pull — sync the local schema from remote#493
brentrager merged 2 commits into
mainfrom
th-schema-pull

Conversation

@brentrager

Copy link
Copy Markdown
Contributor

What

smoo config schema pull [--schema-name] [--org-id] [--dry-run] [--write] [--json] — the read direction that #490's schema show|add|rm (write direction) left open: bring the LOCAL schema representation up to date with the org's remote schema, correctly for both kinds of consumer, detected by whether .smooai-config/config.ts exists.

Design

  • JSON consumer (no config.ts): schema.json IS the local representation — overwritten with the remote doc, same effect as smoo config pull --force. Single fetch, dry-run supported.
  • TS-source consumer (config.ts present): the TypeScript is the source of truth and is never rewritten wholesale. The diff base is the built schema.json. Remote-only keys are emitted as ready-to-paste snippets targeted at the right tier block, in the file's own conventions — the JSON-Schema→TS mapping is derived from how the build actually serializes ({"type":"string"}StringSchema, booleanBooleanSchema, numberNumberSchema, limits default/minimum/maximum/multipleOfdefineLimit({ default, min, max, step }) per LimitDefinition in @smooai/config). Each snippet is headed by // pulled from remote <date> — <remote description | TODO: describe>. A remote type with no clean TS equivalent (object, array, untyped) — or a limit missing the default that defineLimit throws without — is emitted as a fully commented-out block carrying the raw remote spec, never invented syntax.
  • --write: appends the snippets into config.ts mechanically — before the tier block's closing brace, at the block's indentation + 4. All-or-nothing: every insertion is applied in memory first, and the locator refuses (touching nothing) on a missing block, a duplicated node: { line, or an unbalanced-brace scan. Default is print-only; after a write the hint is th config build to regenerate schema.json.
  • Local-only keys are reported, never deleted (a th config push would add them remotely). Tier drift and declared-type drift on shared keys are reported as tables.
  • --dry-run wins over --write; --json emits the structured report. The pure core (compute_pull_report, ts_snippet, insert_into_tier_block, flatten_with_specs — a 4-tier flatten, since the existing flatten_schema skips limits) is fully separated from IO.

Live smoke (real org, scratch copy of smooai's .smooai-config)

Dry run — the snippet path fired for real on hubspotDeltaSyncEnabled (added remotely, missing from local TS), picking up its remote description:

  Schema: smooai
  consumer: TypeScript source (.smooai-config/config.ts) — config.ts is never rewritten wholesale

  + missing locally (1) — paste into .smooai-config/config.ts:

    featureFlagSchema: {
        // pulled from remote 2026-08-20 — Scheduled HubSpot delta pull (two-way sync safety net) — Chakra rollout 2026-08
        hubspotDeltaSyncEnabled: BooleanSchema,
    }

  ● dry-run — nothing written (would write: nothing (print-only without --write))

--write on the copy produced this hunk (brace balance verified, real repo untouched):

@@ -1115,6 +1115,8 @@
         integrationStripe: BooleanSchema,
         mobileMicrosoftSignIn: BooleanSchema,
         slackChannel: BooleanSchema,
+        // pulled from remote 2026-08-20 — Scheduled HubSpot delta pull (two-way sync safety net) — Chakra rollout 2026-08
+        hubspotDeltaSyncEnabled: BooleanSchema,
     },

JSON-consumer path also smoked: bootstrap into an empty dir writes the remote doc; re-run reports in-sync.

Tests

16 new colocated tests (all green, cargo test -p smooai-smooth-cli --features admin config): clap parse; the scalar/limit/description snippet mappings incl. the commented-out fallbacks; pull-report classification (missing/local-only/tier-drift/type-drift, limits included); manifest-shape flatten; and the block locator against a fixture config.ts excerpt — right-tier append with indentation, inline defineLimit({...}) braces, and refusals for missing/ambiguous/unbalanced blocks.

Docs updated in docs/Engineering/Using-th-CLI.md; changeset minor.

🤖 Generated with Claude Code

https://claude.ai/code/session_01KF6EFZ3mMGGF4m1543yWQP

…remote

The write direction (schema add/rm, config push) shipped in #490; this is
the read direction. `smoo config schema pull` reconciles the LOCAL schema
representation with the org's remote schema, correctly for both consumer
kinds: a plain pulled schema.json is overwritten (config pull --force
semantics), while a TypeScript consumer (config.ts present) is never
rewritten wholesale — remote-only keys become ready-to-paste snippets in
the file's own conventions (value-schema names and defineLimit clamp
fields derived from how the build serializes them), and --write appends
them into the right tier block mechanically, refusing all-or-nothing when
a block can't be located unambiguously. Local-only keys are reported,
never deleted; tier/type drift on shared keys is reported as tables.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KF6EFZ3mMGGF4m1543yWQP
@brentrager
brentrager enabled auto-merge (squash) August 20, 2026 17:37
@changeset-bot

changeset-bot Bot commented Aug 20, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 2de329f

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@smooai/smooth Minor

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@brentrager
brentrager merged commit fd1077f into main Aug 20, 2026
3 checks passed
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