Skip to content

feat(config): expose config defaults and provide sparse mapping functions - #6205

Merged
Coly010 merged 11 commits into
developfrom
kanad-claude/config-default-values-mapping-ced354
Aug 24, 2026
Merged

feat(config): expose config defaults and provide sparse mapping functions#6205
Coly010 merged 11 commits into
developfrom
kanad-claude/config-default-values-mapping-ced354

Conversation

@kanadgupta

@kanadguptakanadgupta commented Aug 14, 2026

Copy link
Copy Markdown
Member

Implements CLI-2155: a stored reference of config default values and a mapping function that omits values matching them, so config diff (CLI-2156) and config pull (CLI-2064) can compare sparse configs instead of full effective ones.

What changed

New API in @supabase/config (packages/config/src/sparse.ts, all pure and synchronous, operating on decoded ProjectConfig values):

  • getDefaultProjectConfig() — the default config, derived by decoding {} through ProjectConfigSchema (memoized). The schema's existing default annotations and decoding defaults remain the single source of truth; there is no hand-maintained defaults table to drift.
  • subtractProjectConfig(config, baseline) — returns the sparse config config − baseline: strict deep equality (order-sensitive arrays), sections emptied by subtraction dropped recursively. Directional, so CLI-2156 can subtract a remote block against the merged base config.
  • omitDefaultValues(config)subtractProjectConfig with the default config as baseline. The result is itself a valid config document: re-decoding refills the removed defaults, yielding the same effective config under the current schema's defaults. [remotes.*] blocks (config overrides for a specific persistent Supabase branch, bound by project_id) pass through untouched — pruning them against global defaults would silently change what a branch resolves to.

Refactor:io.ts had a private stripDefaults/isEqualValue walk used for writing minimal config files; that walk is now the shared subtractValue core in sparse.ts, consumed by both the new API and the save path, so there is one subtraction implementation in the package.

Design docs: ADR 0018 (docs/adr/0018-sparse-config-subtraction.md) records the decision, the remote-block baseline rule, what the output is depending on the baseline (defaults → a valid, effectively-equivalent config document whose meaning leans on the current defaults version; any other baseline → an overlay meaningful only relative to that baseline), and defines the working vocabulary inline (default config, sparse config, subtract, base config, remote block, drift).

Reviewer notes

  • The scope split with CLI-2156 is deliberate: the merge cascade and the Management-API-response→config shape translation land with the diff core, keeping this package free of packages/api types. See the ticket comment and ADR 0018's Alternatives.
  • subtractProjectConfig uses an overload with an untyped implementation signature rather than an as cast — TypeScript can't verify that a structural walk over unknown reconstructs a DeepPartial of its input; the unit tests pin the contract.
  • A sparse file's effective meaning leans on the schema's defaults, so a default changed in a future schema version changes what the file denotes — this is the PRFAQ's versioned-defaults open question, deliberately out of scope here per ADR 0018.

🤖 Generated with Claude Code

kanadguptaand others added 7 commits August 14, 2026 15:45
Adds ADR 0017 pinning the design for the config defaults mapping
function ahead of implementation: a pure, parameterized subtract core
in @supabase/config, defaults derived from schema annotations, strict
deep equality, and the remote-block baseline rule. Also seeds a root
CONTEXT.md glossary with the project's config vocabulary.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ons (CLI-2155)
Adds getDefaultProjectConfig() (memoized decode of {} through the
schema, keeping annotations as the single source of truth for
defaults), subtractProjectConfig(config, baseline), and
omitDefaultValues(config), per ADR 0017. The generic subtraction walk
is extracted from io.ts's private stripDefaults so the save-time
minimal encoding and the new sparse API share one implementation.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…y (CLI-2155)
Introduces [remotes.*] blocks as config overrides for a specific
persistent Supabase branch (project_id binds the block; the label is a
user-chosen alias) in ADR 0017, CONTEXT.md, and the sparse.ts doc
comments. Replaces the flat "not a valid complete config" framing with
a split by baseline: subtracting the default config yields a valid
config document that re-decodes to the same effective config under the
current schema's defaults, while any other baseline yields an overlay
meaningful only relative to that baseline.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…I-2155)
CONTEXT.md is not a convention this codebase follows. Its only content
not already defined in the ADR (base config, drift) is woven into ADR
0018's problem statement; the stale post-renumbering references (the
ADR's own 0017 heading, sparse.ts and sparse.unit.test.ts pointing at
ADR 0017) now say 0018.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@kanadguptakanadgupta changed the title feat(config): store config defaults and provide sparse mapping functionsfeat(config): expose config defaults and provide sparse mapping functionsAug 18, 2026
@kanadgupta
kanadgupta marked this pull request as ready for review August 18, 2026 23:46
@kanadgupta
kanadgupta requested a review from a team as a code ownerAugust 18, 2026 23:46
@github-actions

github-actionsBot commented Aug 18, 2026

Copy link
Copy Markdown
Contributor

Supabase CLI preview

npx --yes https://pkg.pr.new/supabase/cli/supabase@4c025738bd6c3502fac2f03e6249a0a64e3f9bbc

Preview package for commit 4c02573.

@chatgpt-codex-connectorchatgpt-codex-connectorBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit:635c7dd81a

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment threadpackages/config/src/sparse.ts
Comment threadpackages/config/src/sparse.ts Outdated
Comment threadpackages/config/src/sparse.ts
Comment threadpackages/config/src/sparse.ts Outdated
…defaults memo (CLI-2155)
Review follow-ups on #6205: subtractProjectConfig/omitDefaultValues now
take BaseProjectConfig (ProjectConfig without the nested remotes), so
the ADR 0018 remote-block call type-checks without a cast; the memoized
default config is deeply frozen so a caller mutation cannot poison the
shared subtraction baseline. Both pinned by unit tests.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

@avalleteavallete left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM a few nitpicks

Comment threaddocs/adr/0018-sparse-config-subtraction.md Outdated
Comment threadpackages/config/src/sparse.ts
…e encoded defaults (CLI-2155)
Review follow-ups on #6205:
- A record entry named `__proto__` (a valid function name or remote label —
both smol-toml and JSON.parse produce it as an own key, and the schema
decode preserves it) was silently dropped by `result[key] = value` hitting
the legacy prototype setter, and `baseline[key]` read `Object.prototype`
off the prototype chain. All three record walks (`subtractValue`,
`mergeRemoteSubtree`, `stripFunctionRecordDefaults`) now use `Object.hasOwn`
lookups and define own data properties via a shared `setOwnProperty`; a unit
test pins the `__proto__` round-trip.
- `io.ts`'s encoded-defaults constant is now memoized like
`getDefaultProjectConfig`, so importing `@supabase/config` no longer pays a
schema decode+encode at module load — making sparse.ts's lazy-memo comment
actually true.
- Documented that `omitDefaultValues` output is sparse at the root scope only
(record-keyed entries carry materialized per-entry decoding defaults), in
the docstring and ADR 0018's Negatives, and that baseline-only keys are
ignored by design (absence means inherit).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

@chatgpt-codex-connectorchatgpt-codex-connectorBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit:24fab701f3

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment threadpackages/config/src/sparse.ts
kanadguptaand others added 2 commits August 19, 2026 15:45
…s (CLI-2155)
Review follow-up on #6205: subtractProjectConfig's advertised remote-block
call shape passed a standalone-decoded `[remotes.*]` block, but decoding a
sparse fragment materializes global defaults in every omitted section —
where the block meant to inherit from the base config. With base
`db.port = 54399` and a remote that omits `db`, the decoded block carries
the global default `54322`, the overlay retains it, and writing it back
flips the branch from inheriting the base's value to pinning the default.
The subtraction core is unchanged; the contract is corrected: both operands
must be *effective* configs, and a branch's is the raw remote subtree merged
over the raw base document before decoding (the same pre-decode order
`mergeRemoteSubtree` documents, precisely so remote schema defaults never
leak in). ADR 0018, the docstrings, and the unit test now pin that call
shape, with the base-only-override counterexample as the regression test.
`BaseProjectConfig` stays, re-justified: it keeps `remotes` out of the
contract so API-translated effective configs fit without a fabricated field.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…g-default-values-mapping-ced354
# Conflicts:
#	docs/adr/README.md
@Coly010
Coly010 added this pull request to the merge queueAug 24, 2026
Merged via the queue into develop with commit 464692fAug 24, 2026
20 of 22 checks passed
@Coly010
Coly010 deleted the kanad-claude/config-default-values-mapping-ced354 branch August 24, 2026 14:23
pullBot pushed a commit to oogalieboogalie/cli that referenced this pull request Aug 25, 2026
supabase#6310)
## What changed
Adds ADR 0019, recording the design guardrails for the `_apiResponse`
escape hatch on API-sourced config values in `@supabase/config` — the
raw `/v2/projects/{ref}/config` `data.attributes` object carried
alongside the typed mapping so package consumers can read API fields
added faster than the package publishes.
The five rules it records:
1. `_apiResponse?: Record<string, unknown>` — optional, present only on
API-sourced values; absence does not mean "fully mapped".
2. Lenient decode of the v2 attributes — unknown keys never fail; this
is the primary protection, `_apiResponse` is the access mechanism.
3. One metadata-key rule: `$`/`_`-prefixed keys are excluded from all
structural walks and encodes (extends the existing `$schema` precedent,
implemented once in the shared walk core from ADR 0018).
4. Never persisted — the raw response carries HMAC'd secret digests and
must not land in config files.
5. Fallback, not contract — typed fields win once a raw key graduates
into the mapping; unmapped-field discovery is a registry-derived helper,
not a second stored field.
## Why
Discussed 2026-08-24 in the context of publishing `@supabase/config` for
multiple consumers (CLI `config diff`/`pull`, Studio's config-drift work
in supabase/supabase#48906, which vendors a temporary schema mirror
explicitly awaiting this package). The Management API moves faster than
deliberate package releases; without a designed escape hatch the
package's cadence bottlenecks every service team's API velocity, and
without the guardrails a naive passthrough causes phantom drift in the
ADR 0018 subtraction walks and risks persisting secret digests.
Note: numbered 0019 because 0018 is taken by supabase#6205 (currently in the
merge queue); the README index row may need a trivial rebase once
supabase#6205's 0018 row lands.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Sign up for freeto 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.

3 participants

@kanadgupta@avallete@Coly010