fix(cli): match Go machine-format encoder output for -o toml/yaml/json (CLI-1975) - #6002
Conversation
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 9b583fd807
ℹ️ 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".
… (review: codex) - yamlIsTimestamp now mirrors time.Parse's calendar validation (days-in-month with proleptic-Gregorian leap years) and zone-offset range checks (hour > 24, minute > 60 rejected), so strings like "2025-02-31" stay plain exactly as yaml.v3 leaves them. - TOML map keys sort by UTF-8 byte order (sort.Strings) and yaml.v3's keyList.Less rune comparisons use code points, not JS UTF-16 units, fixing astral-vs-high-BMP key ordering in both encoders. - yamlHasSpecialChars/yamlDoubleQuoted now port libyaml's is_printable: astral characters, U+FEFF, and U+FFFE/U+FFFF double-quote with \x/\u/\U escapes. All new golden bytes captured from Go's own utils.EncodeOutput with the pinned BurntSushi toml v1.6.0 / yaml.v3 v3.0.1.
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: e020a45acf
ℹ️ 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".
…s (review: codex)
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: a479e84f36
ℹ️ 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".
…es (review: codex)
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: c701b9ae64
ℹ️ 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".
…erflow quoting (review: codex)
…5--o-toml-o-yaml-emit-wrong-key-casing-on-struct-payloads-o
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: b7522fec63
ℹ️ 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".
Supabase CLI previewnpx --yes https://pkg.pr.new/supabase/cli/supabase@1d72d37c01b7a32690c7fe71781cf35ded9d8294Preview package for commit |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: dddbf6b880
ℹ️ 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".
|
Codex Review: Didn't find any major issues. Another round soon, please! Reviewed commit: ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
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". |
kanadgupta
left a comment
There was a problem hiding this comment.
A couple of future-proofing suggestions from Claude but LGTM!
…gic (CLI-1975) Hoist the map-sort + direct/sub table partitioning shared by tomlTable and tomlArrayOfTables into tomlOrderedEntries; tomlInlineTable keeps its own copy since its position-based separator logic doesn't unify cleanly (review kanadgupta). Also notes in the Go Parity Checklist that a types.gen.go regen requires re-auditing every go-payload.ts spec.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 95d24f6b75
ℹ️ 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".
Parses the real Go struct declarations out of types.gen.go and structurally compares them against the LegacyGoType specs the *.go-payload.ts files hand-declare, so a future field add/remove/reorder/rename in the Go API types desyncs a spec loudly instead of silently corrupting -o yaml/-o toml output (review kanadgupta, PR #6002).
…5--o-toml-o-yaml-emit-wrong-key-casing-on-struct-payloads-o # Conflicts: # apps/cli/src/legacy/commands/sso/add/add.handler.ts # apps/cli/src/legacy/commands/sso/update/update.handler.ts
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 1d72d37c01
ℹ️ 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".
⚖ Parity ruling applied
This issue was decision-gated. Colum ruled (2026-07-30) to take the issue's recommended option: remap the
-o toml/-o yamlencoders to Go field-name casing and structure — full Go parity. The alternative (declaring the TS snake_case casing intentional) was rejected. The Go CLI (apps/cli-go/) is the byte-parity oracle: for every affected command the machine output now matches what the Go binary prints, including field-name casing, ordering, zero-value inclusion, datetime rendering, and null rendering.User-visible change: scripts consuming
-o toml/-o yamlfrom the affected commands will now see Go-shaped keys (ProjectRef/[[branches]]-style PascalCase in TOML,projectref-style lowercased names in YAML) instead of the snake_case keys the TS CLI emitted until now — i.e. scripts written against the long-lived Go CLI work again.-o jsonvalues additionally carry Go's default HTML escaping (<>&as\u003c-style escapes); any JSON parser decodes these transparently.Fixes CLI-1975
What changed
Go's
utils.EncodeOutputhands raw Go structs to BurntSushi TOML and yaml.v3, and neither library readsjson:tags — keys come from the Go struct field names. The TS legacy shell was instead re-encoding the decoded snake_case JSON. This PR closes that gap for every struct-payload command.New shared encoder (
legacy/shared/legacy-go-struct-output.encoders.ts)A pure, spec-driven pair of encoders that reproduce the Go binary byte-for-byte, driven by per-payload-family Go struct specs (field order = Go declaration order, mirrored from
apps/cli-go/pkg/api/types.gen.goand command-local structs):[[array-of-tables]]element, nil pointers/slices/maps omitted, empty decoded arrays askey = [],time.Timeas native RFC3339Nano datetimes, Go float'g'formatting with the TOML.0rule, BurntSushi's exact string-escape table, and Go's runtime failure for populatednullable.Nullablefields.nullfor nil pointers,[]/{}for nil slices/maps, yaml.v3's 4-column indentation algorithm (+2 inside sequence items), its scalar-quoting resolver (old-bools, base-0 ints, floats, base-60, timestamps → double-quoted; emitter-plain-disallowed → single-quoted), block literals with chomping/indentation indicators,map[bool]Trendering for oapinullablefields, yaml.v3's natural map-key sort, and Gostrconv.FormatFloat(_, 'g', -1, bits)float formatting incl. float32 rounding.Every golden byte string in the unit tests was captured empirically from a scratch Go program running the repo's own
utils.EncodeOutputwith the exact library versions pinned inapps/cli-go/go.mod.Commands rewired to the spec encoders
branches list/create/update(sharedbranches.go-payload.ts)orgs list/create(orgs.go-payload.ts)projects list(Go'slinkedProjectembed: inlinedV1ProjectWithDatabaseResponsefields first,Linkedlast),projects create(shared create core),projects api-keys(-o yamlonly — Go's-o toml|envencode theSUPABASE_*_KEYenv map, unchanged)secrets list,sso list/show/add/update/remove(sso.go-payload.ts),domains get/create/activate/reverify,ssl-enforcement get/update(ssl-enforcement.go-payload.ts),functions list(replaces its bespoke per-command key maps),backups list,snippets list,services,vanity-subdomains get/activate/check-availability(YAML was snake_case; TOML gains Go's declaration order)Nil-vs-empty slice semantics follow each Go command: append-built lists (
branches list,projects list) emit nothing for-o tomlwhen empty (Go nil slice), decoded lists emitkey = [].Bug-for-bug parity notes
snippets list -o tomlnow fails with Go's exact error (failed to output toml: toml: cannot encode a map with non-string key type) whenever a snippet carries adescription— BurntSushi cannot encodenullable.Nullable[string](map[bool]string), and the Management API always sends the key. Go fails identically.projects api-keys -o yamlrenders nullable fields as yaml.v3 rendersmap[bool]T:apikey:+ indentedtrue: <value>when set,{}when absent,false: ""for explicit JSON null.JSON HTML escaping
encodeGoJson(-o json) andencodeGoStructJsonBody(raw-HTTP request bodies forsso add/update) now produce Go'sencoding/jsondefault escaping:<>&→\u003c\u003e\u0026,\u0008/\u000cfor backspace/form feed, and escaped U+2028/U+2029 — materially visible insso … metadata_xml. Both now route through the shared Go-faithful JSON walker (legacy-go-json.ts, which gains a compact mode);functions list's bespoke post-escaper was deleted. The cli-e2e replay server compares parsed bodies, so recorded fixtures are unaffected.Tests & docs
-0, nullable shapes, nil/empty slices, natural key sort, hostnames nesting).-o tomlno-output case), sso show (json escape + yaml + toml), backups list (incl.[[Backups]]), snippets (both the Go failure and the description-absent success bytes), plus casing fixes across orgs/projects/secrets/services/ssl-enforcement/domains/vanity tests. The previously-wrongbranches listtoml assertion (name = "feat-1") is now the full Go-golden document.branches get -o toml(map payload) keeps its env-map keys verbatim — the struct remap must not apply to map payloads (sso info,status,postgres-config,network-bans,branches getare unchanged).Deliberately out of scope (pre-existing divergences, noted for the record)
network-restrictions get/update: Go never encodes-ooutput for these commands (it always prints three fixedPrintflines), so there is no Go byte oracle; the TS handlers' existing-o json|yaml|toml|envsupport is left untouched. Follow-up candidate.branches list -o jsonwith zero branches: TS emits[], Go emitsnull(append-built nil slice). JSON values were out of CLI-1975's scope (HTML escaping only).projects list -o json: TS sorts keys alphabetically solinkedsorts mid-object; Go emits it last. Same out-of-scope reasoning.domainsdata.errors/data.messagesare modeled as raw JSON values; Go's generated element type marshals as an empty struct — unobservable because these arrays are empty on every reachable path (both sides emit[]).