Skip to content

feat(compliance): split symbol evidence from symbol coverage - #75

Merged
spydon merged 3 commits into
mainfrom
feat/supporting-symbols
Aug 7, 2026
Merged

feat(compliance): split symbol evidence from symbol coverage#75
spydon merged 3 commits into
mainfrom
feat/supporting-symbols

Conversation

@spydon

@spydon spydon commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Problem

The symbols list in sdk-compliance.yaml feeds two checks that want opposite things:

Check Reads symbols as Wants
checkDrift Evidence that a capability is implemented A short, precise list of entry points, all of which must exist
checkNewSymbols Coverage, so no new public API slips in unclassified An exhaustive account of the entire public surface

One list cannot serve both. When a capability's supporting types outnumber its methods, authors get pushed into one of two workarounds:

  1. Padding symbols with option types, result types and exceptions that do not implement anything, or
  2. Repeating one shared symbol list across several features so each has something to point at.

Both inflate what the matrix claims is implemented, fan drift warnings out across features that do not own the symbol, and leave symbol-to-feature attribution arbitrary, since buildSymbolIndex silently last-wins on collision.

This is not hypothetical. supabase/supabase-flutter#1666 hit it head-on: reconciling #74 required replicating a 330-symbol Iceberg list across 6 new feature IDs and a 22-symbol list across 3 more, for +1729 lines. Every one of those 330 symbols now resolves to storage.analytics.delete_table in the symbol index, purely because it sorts last.

The existing escape hatches do not help. @internal and .sdk-parse-ignore remove symbols from the surface entirely, but types like TableMetadata are genuinely public API that consumers construct. They just are not capabilities.

Change

Adds an optional supporting_symbols list, per feature and top level, that counts for new-symbol coverage and is never drift-verified:

storage.analytics.create_table:
  status: implemented
  symbols:
    - IcebergRestCatalog.createTable      # evidence, drift-verified
  supporting_symbols:
    - CreateTableRequest                  # coverage only
supporting_symbols:                       # top level, shared across features
  - IcebergException
  • compliance.ts: new field on RawValue and RawCompliance; validation extracted into a shared checkSymbolList helper so both lists get identical treatment; normalizeCompliance preserves it; buildSymbolIndex unions both. Entry points are indexed last, so a symbol listed both ways is attributed to the capability that implements it rather than to a supporting bucket. Top-level entries index against an exported TOP_LEVEL_SUPPORTING sentinel so removal messages stay readable.
  • drift-check.ts: unchanged. It already read only value.symbols, so the separation falls out for free.
  • api-check.ts: the failure message now teaches the distinction, since that message is exactly where an author hits this wall.
  • types.ts, docs/capability-matrix.md, tests.

Compatibility

The field is optional and the drift check already ignored anything outside symbols, so existing compliance files are unaffected. Verified that supabase-flutter's current sdk-compliance.yaml validates unchanged.

Test plan

  • 194 tests pass; 12 new, including the two that pin the semantics: supporting symbols do not satisfy drift on their own, and a missing supporting symbol produces no drift finding.
  • tsc --noEmit clean.
  • npm run validate still OK on the canonical registry.
  • Rebuilt supabase-flutter#1666's Iceberg entries in this shape as a check that it solves the motivating case: 0 drift findings, 0 uncovered symbols out of 352, attribution exact (createTable maps to create_table, not delete_table), and 2046 symbol lines become 352.

Follow-ups, deliberately not in this PR

  • Reject duplicate symbol registration. Now that supporting types have a home this becomes viable, and it would have caught supabase-flutter#1666's shape automatically. Turning it on today would fail existing compliance files, so it needs its own migration.
  • renamed_from aliases on canonical features. Separate concern and arguably higher value: today every ID rename here breaks all seven SDK repos at once, with no window in which both old and new IDs validate, because each repo pins the reusable workflow at @main.
  • The registry is narrower than the SDKs. feat!: reconcile capability matrix inconsistencies from skill audit #74 splits namespaces into create/list/delete, but the real Flutter surface has seven namespace operations. loadNamespaceMetadata, namespaceExists, updateNamespaceProperties, registerTable and tableExists map to no capability at all. This PR gives them an honest home rather than a false claim, but the underlying gap is worth deciding on separately.

The `symbols` list was serving two checks that want opposite things.
The drift check reads it as evidence a capability exists, so it wants a
short list of entry points. The new-symbol check reads it as an
exhaustive account of the public surface, so it wants every option type,
result type, schema model and exception to appear somewhere.

One list cannot do both. When a capability's supporting types outnumber
its methods, authors are pushed into padding `symbols` with types that
do not implement anything, or into repeating one shared list across
several features so each has something to point at. Both inflate what
the matrix claims is implemented, fan drift warnings out across features
that do not own the symbol, and leave symbol-to-feature attribution
arbitrary, since the index silently last-wins on collision.

Adds an optional `supporting_symbols` list, per feature and top level for
types shared across features. It counts for new-symbol coverage and is
never drift-verified, so `symbols` can stay precise.

The field is optional and the drift check already reads only `symbols`,
so existing compliance files are unaffected.
@coderabbitai

coderabbitai Bot commented Aug 7, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 86056b11-9774-438e-924c-a276c37cc744

📥 Commits

Reviewing files that changed from the base of the PR and between 936f552 and af23346.

📒 Files selected for processing (2)
  • scripts/capability-matrix/src/api-check.ts
  • scripts/capability-matrix/test/api-check.test.ts

📝 Walkthrough

Summary by CodeRabbit

  • New Features

    • Added support for declaring supporting public symbols at both feature and top-level scope.
    • Supporting symbols count toward new-symbol coverage without being treated as implementation evidence for drift verification.
    • Implementation symbols take precedence when the same symbol appears in both lists.
    • Added validation and removal detection for supporting symbols, including their associated feature or top-level scope.
  • Documentation

    • Clarified how to define implementation and supporting symbols, including configuration examples and guidance against duplication.

Walkthrough

The capability matrix now supports supporting_symbols at feature and top-level scope. Validation checks these lists as arrays of strings, and normalization preserves feature-level values. Symbol indexing records supporting symbols separately from implementation entry points. Implementation symbols take precedence for duplicate entries. Supporting symbols remain excluded from drift evidence but count toward new-symbol coverage. Documentation, error messages, and tests describe these registration and coverage rules.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@scripts/capability-matrix/src/api-check.ts`:
- Around line 47-67: Update the registration examples around the `example`
placeholder and `lines.push` so `symbols` and `supporting_symbols` use distinct,
role-appropriate placeholders. Do not reuse the first `uncoveredSymbols` entry
for both fields; use neutral placeholders or select each value according to the
symbol kind, preserving the documented distinction between implementation entry
points and supporting types.

In `@scripts/capability-matrix/src/compliance.ts`:
- Around line 133-154: The symbol index populated in compliance processing
currently mixes coverage-only supporting symbols with implementation symbols
used by checkNewSymbols to compute removedRegisteredSymbols. Introduce a
separate implementation-symbol index containing only feature symbols, use it for
removedRegisteredSymbols, and retain the existing index for new-symbol coverage.
Add a test covering a supporting symbol present in the base API but absent from
the PR API, ensuring it is not reported as removed.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 7d7046c3-308a-4a6c-af05-85e0a7a1a470

📥 Commits

Reviewing files that changed from the base of the PR and between 9c53a70 and 936f552.

📒 Files selected for processing (5)
  • docs/capability-matrix.md
  • scripts/capability-matrix/src/api-check.ts
  • scripts/capability-matrix/src/compliance.ts
  • scripts/capability-matrix/src/types.ts
  • scripts/capability-matrix/test/compliance.test.ts

Comment thread scripts/capability-matrix/src/api-check.ts Outdated
Comment thread scripts/capability-matrix/src/compliance.ts
The new-symbol failure message showed the same uncovered symbol under both
`symbols` and `supporting_symbols`, which contradicts the distinction the
message is trying to teach. The check cannot know which of the two a new
symbol belongs in, so the example now uses neutral placeholders for each
role and the offending names are left to the list above it.

Also pins removal detection across supporting symbols with a test. The
check asks whether the compliance file references API that no longer
exists, which is equally true for a supporting type, and since the drift
check reads only `symbols` nothing else would catch a stale entry.
@spydon
spydon merged commit abc8e71 into main Aug 7, 2026
5 checks passed
@spydon
spydon deleted the feat/supporting-symbols branch August 7, 2026 12:30
spydon added a commit to supabase/supabase-flutter that referenced this pull request Aug 7, 2026
…nd splits (#1667)

## Summary

Reconciles `sdk-compliance.yaml` with three upstream changes that have
now landed in `supabase/sdk`:

- **supabase/sdk#74** renamed and split several canonical feature IDs.
- **supabase/sdk#75** separated symbol *evidence* from symbol
*coverage*, adding `supporting_symbols`.
- **supabase/sdk#76** added the five Iceberg catalog capabilities that
#74's split left without an ID.

### Renames and merges

- `auth.sign_in.reset_password` →
`auth.sign_in.send_password_reset_email`
- `realtime.channel.send` → `realtime.channel.broadcast`
- `storage.file_buckets.list_files_paginated` merged into `list_files`
- `storage.analytics.iceberg_namespace` split into `create_namespace` /
`list_namespaces` / `delete_namespace`
- `storage.analytics.iceberg_table` split into `create_table` /
`list_tables` / `load_table` / `update_table` / `rename_table` /
`delete_table`

### New capabilities declared

`load_namespace_metadata`, `namespace_exists`,
`update_namespace_properties`, `register_table`, `table_exists`.

## Why the Iceberg entries look the way they do

Splitting two bundled entries into fifteen raises the question of which
symbols belong where. The Iceberg surface is 352 symbols, only 18 of
which are catalog entry points; the rest are option types, result types,
the schema and type model, and the exception hierarchy.

`symbols` now holds **only** the methods a caller invokes, because the
drift check treats every name in it as evidence the capability exists.
Everything else sits under `supporting_symbols`, which counts for
new-symbol coverage without claiming to implement anything.

Owners for the supporting types are derived from the source rather than
assigned by hand: build the type graph from
`packages/storage_client/lib/src/iceberg/`, including subtype edges
since a signature naming a sealed base reaches every variant a caller
can pass, then ask which entry points reach each type. A type reachable
from exactly one feature belongs to that feature.

| | count |
|---|---|
| Sole natural owner | 37 of 67 |
| Genuinely shared across several features | 20 |
| Reachable from no entry point (thrown, not passed) | 10 |

So all 28 `*Update` and `Assert*` classes land on `update_table`,
`ListTablesOptions`/`ListTablesResult` on `list_tables`,
`RegisterTableRequest` on `register_table`. The schema and type model
and the exception hierarchy stay in the top-level `supporting_symbols`
list, which is the honest answer rather than a coin flip.

The alternative was to replicate the full 330-symbol list across all six
table IDs and the 22-symbol list across all three namespace IDs (+1729
lines, as in the now-closed #1666). That inflates what the file claims
is implemented, fans drift findings across features that do not own the
symbol, and leaves attribution arbitrary, since `buildSymbolIndex`
last-wins on collision. Under that shape only 2 of 9 split features
resolved to their own entry point; here it is 9 of 9.

## Test plan

Validated against current `supabase/sdk@main`, with #74, #75 and #76 all
merged:

- [x] `validate-compliance`: `OK — compliance file is valid.` Two
features remain undeclared (`postgres_changes_multiple_filters`,
`error_codes`); both are pre-existing and out of scope here.
- [x] `check-drift` against symbols extracted with the real Dart
extractor: `✅ No capability matrix drift detected.`
- [x] `check-api-symbols`: all public API accounted for; 887 symbols
covered, unchanged from before this PR.
- [x] Verified no unintended edits: every feature outside the rename and
split scope is byte-identical to `main` after re-serialization.
- [x] CI re-run after the upstream merges: `Validate compliance file`
and `Check public API against capability matrix` both green.

No SDK code changes, only capability declarations.

Context: [SDK-1439](https://linear.app/supabase/issue/SDK-1439)


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Improvements**
* Standardized capability names for password reset and realtime
broadcast functionality.
* Clarified storage file listing capabilities, including pagination and
sorting support.
* Added more granular capability definitions for Iceberg namespaces and
tables.
* Consolidated shared Iceberg models, errors, catalog access, and
supporting symbols for more consistent capability descriptions.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
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.

3 participants