Summary
gate list --format json and gate issues list --format json return different top-level JSON shapes for the same conceptual operation (list records):
gate list --format json → object envelope: { "_meta": {...}, "requests": [...] }
gate issues list --format json → bare array: [ {...}, {...} ]
Why it matters
CLAUDE.md (Style) states the invariant:
text mode と json mode の両 surface を維持 — AI-first: substrate (JSON) が contract … --format json の envelope shape は verb 横断で安定
The two list surfaces violate that "envelope shape is stable across verbs" guarantee. A caller wiring a jq pipeline has to switch between .requests[] and .[] depending on which list verb it hit — exactly the kind of surface drift the AI-first contract is meant to prevent.
How it surfaced
Found while building a reflect-style skill that reads buckets from the substrate. The skill first did gate list --format json | jq '.[]' (assuming a bare array), got nothing, and only worked after discovering the .requests envelope — then broke again the opposite way against gate issues list, which is a bare array.
Repro
gate list --state completed --format json | jq 'type' # => "object" (keys: _meta, requests)
gate issues list --state open --format json | jq 'type' # => "array"
Suggested fix
Pick one and apply across both list verbs:
- Envelope both —
issues list returns { "_meta": {...}, "issues": [...] }, matching gate list. (Preferred — _meta then has a place to grow for issues too.)
- Bare-array both — drop the envelope from
gate list. (Breaking change for existing request-list consumers.)
Option 1 looks lower-risk and more consistent with the _meta pattern already established on the request side.
If the divergence is intentional, documenting it explicitly in AGENT.md (per-verb envelope notes) would at least make the contract discoverable.
Summary
gate list --format jsonandgate issues list --format jsonreturn different top-level JSON shapes for the same conceptual operation (list records):gate list --format json→ object envelope:{ "_meta": {...}, "requests": [...] }gate issues list --format json→ bare array:[ {...}, {...} ]Why it matters
CLAUDE.md(Style) states the invariant:The two
listsurfaces violate that "envelope shape is stable across verbs" guarantee. A caller wiring ajqpipeline has to switch between.requests[]and.[]depending on which list verb it hit — exactly the kind of surface drift the AI-first contract is meant to prevent.How it surfaced
Found while building a reflect-style skill that reads buckets from the substrate. The skill first did
gate list --format json | jq '.[]'(assuming a bare array), got nothing, and only worked after discovering the.requestsenvelope — then broke again the opposite way againstgate issues list, which is a bare array.Repro
Suggested fix
Pick one and apply across both list verbs:
issues listreturns{ "_meta": {...}, "issues": [...] }, matchinggate list. (Preferred —_metathen has a place to grow for issues too.)gate list. (Breaking change for existing request-list consumers.)Option 1 looks lower-risk and more consistent with the
_metapattern already established on the request side.If the divergence is intentional, documenting it explicitly in
AGENT.md(per-verb envelope notes) would at least make the contract discoverable.