Sync filter docs with the canonical envelope and cut 1.2.0 - #34
Conversation
The `contains` operator is no longer social-only: the profiles surface supports it on routable string attributes (case-sensitive) and, since P-2387, on `labels.value` (case-insensitive). `startsWith`/`endsWith` were missing from the CLI's operator list entirely even though the validator already accepted them. Replace the one-line claim with the per-field support table the API actually enforces. Also document `page_scope` (new on kpis/top_*/revenue_*/volume_by_metric) and note that the retired per-family analytics params are rejected with a 400 if pushed through `--params`. Version 1.2.0 covers the five unreleased canonical-envelope commits (#29–#33) on top of v1.1.1. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 05a737b430
ℹ️ 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".
|
|
||
| On `kpis`, `top_*`, `revenue_*` and `volume_by_metric`, `--params '{"page_scope":"session"}'` widens a `page` filter from page-scoped metrics (the default) to the legacy session scope. | ||
|
|
||
| All user-attribute, profile, social, lifecycle and resource predicates go in the single `--filters` array, using the canonical envelope with named qualifiers (`chain_id`, `app_id`, `token_address`, `scope`, `tag_id`). The retired per-family params — `socials`, `chain_filters`, `app_filters`, `token_filters`, `label_filters`, `profile_filters`, `lifecycle_filter` — are rejected with a `400` if passed through `--params`. |
There was a problem hiding this comment.
Align analytics qualifier support with the CLI validator
When a user follows this guidance for a resource predicate, such as --filters '[{"field":"chains.balance","op":"gt","value":1,"chain_id":"1"}]', the command fails locally instead of reaching the API: validateAnalyticsFilter only permits field, op, value, and optional filters (src/commands/analytics.ts:61-82), so every named qualifier listed here is rejected as an extra key. Either teach the analytics validator to accept and validate these qualifiers or avoid documenting them as usable through this CLI.
Useful? React with 👍 / 👎.
| 'contains works on routable string attributes (users.device, users.os, users.referrer, users.utm_*, users.click_id — case-sensitive), ' + | ||
| 'on social fields and on labels.value (case-insensitive); ' + | ||
| 'startsWith/endsWith are routable string attributes only; ' + | ||
| 'notEmpty/isEmpty are value-less existence checks on string fields; ' + |
There was a problem hiding this comment.
Qualify existence-operator support in profile help
When users consult profiles search --help for social or lifecycle string fields, this sentence advertises both existence operators even though the support table added by the same change says isEmpty is rejected for social fields and users.lifecycle accepts only eq and in (README.md:538-540). Following the generated CLI help therefore produces an API 400; list the actual eligible string field classes or explicitly say these operators apply only where supported.
Useful? React with 👍 / 👎.
Why
The CLI's filter code is already current with the API — commits #29–#33 track P-2378 (#2108), P-2386 (#2125) and P-2387 (#2129), and
openapi.jsonhas not changed since 2026-07-31. The docs drifted in one place that matters.containswas documented as "social fields only". Perpackages/shared/constants/filterCapability.ts, the profiles surface supports it on routable string attributes (case-sensitive) and — new in P-2387 — onlabels.value(case-insensitive).startsWith/endsWithwere missing from the operator list entirely even thoughisCanonicalFilterOperatoralready accepted them, so anyone reading the help text would not know they exist.What changed
src/commands/profiles.tshelp text,README.md,SKILLS.md).page_scope, added in P-2378 onkpis,top_*,revenue_*andvolume_by_metric. It passes through--paramstoday but was undocumented.socials,chain_filters,app_filters,token_filters,label_filters,profile_filters,lifecycle_filter) are rejected with a400rather than silently ignored.No behaviour changes — documentation and the version field only.
Verification
pnpm build,pnpm lintand 174 unit tests pass.Wire shapes were checked by running the built CLI against a recording server and diffing every request against
openapi.json:profiles search(GET +{filters, logic}body with named qualifiers),analytics kpis/lifecycle/funnel/flow,segments create(filters, notfilterSet),alerts create({field, op, value}, not{name, operator}). All match.Ten retired forms reject client-side: legacy operators, bare field names,
chains.1.balance,appId,labels.valuewithouttag_id, empty membership arrays, a literal|inside an array member, two-level nesting, the legacy alert envelope, and the legacy segment key.TEST_TOKENis rejected byhttps://api.formo.sowith HTTP 401, so they skip silently. They should be run against a fresh key before tagging v1.2.0.🤖 Generated with Claude Code
Need help on this PR? Tag
@codesmith-botwith what you need. Autofix is disabled.