Skip to content

Review dp function - #62

Merged
satyamdev10 merged 5 commits into
features_set-dp-functionfrom
review_dp_function
Aug 18, 2026
Merged

Review dp function#62
satyamdev10 merged 5 commits into
features_set-dp-functionfrom
review_dp_function

Conversation

@satyamdev10

@satyamdev10 satyamdev10 commented Aug 17, 2026

Copy link
Copy Markdown
Contributor

Summary

Phase-1 integration of DP Functions into brevo-cli — adds the brevo function command group for managing Brevo Functions, plus the Function app type in brevo app create. All new commands are gated behind __BREVO_PREVIEW__ and eliminated from published builds.

Epic: PP-2110

Jira tickets

Ticket Summary Status
PP-2500 Add a new App type (Function) during app creation flow In Review / QA
PP-2579 Add brevo function list command In Review / QA
PP-2774 Add brevo function get <id> command In Review / QA
PP-2811 Add brevo function activate/deactivate/delete <id> commands In Review / QA
PP-2748 Implement feature toggle (__BREVO_PREVIEW__) for CLI DP function flow In Progress

What changed

New commands (brevo function / brevo fn)

  • brevo function list — List all functions (supports --draft for draft functions)
  • brevo function get <id> — Get details of a specific function
  • brevo function activate <id> — Activate a function (PATCH with is_active: true)
  • brevo function deactivate <id> — Deactivate a function (PATCH with is_active: false)
  • brevo function delete <id> — Delete a deployed function (--force skips confirmation)

App creation flow

  • Added Function as a third app type choice in brevo app create interactive prompt (alongside OAuth and UI app)
  • Function type is interactive-only — non-interactive runs (--json / piped stdin) default to OAuth app
  • brevo_function template flag added for app-config.json rendering

Preview gating

  • brevo-function-type added to FEATURE_STAGE as a preview feature
  • Function group definition moved to preview-definitions.ts so esbuild eliminates it from published builds
  • Function commands section in help screen gated behind __BREVO_PREVIEW__

Other

  • fn alias added for brevo function (via aliases support on SubcommandGroupDefinition)
  • New function service (src/services/function.ts) with list, draft list, get, activate, deactivate, delete
  • Smoke test suite (scripts/smoke/function.ts) — opt-in via yarn smoke --suite=function

Test plan

  • 65 test suites, 1361 tests — all passing (yarn test)
  • Unit tests for all 5 new command handlers
  • Service tests for all function service methods
  • Command registration tests in definitions.test.ts
  • Help formatting tests updated for functionCommandGroup
  • Production build verified: function commands excluded from published bundle
  • Smoke suite exercising list, list --draft, get, and get-not-found against a real account

🤖 Generated with Claude Code

satyamdev10 and others added 4 commits August 14, 2026 15:04
Add `brevo function list` and `brevo function get <id>` commands for
managing Brevo Functions, plus the "Brevo Function" app type choice
in `brevo app create`.

- New service (src/services/function.ts) with list, draft list, and get
- New command handlers (src/commands/function/list.ts, get.ts)
- Register functionCommandGroup in definitions.ts and bin/index.ts
- Add Function commands section to root help screen
- Add brevo_function template flag for app-config.json rendering
- Add Brevo Function app type to interactive create prompt (private only)
- Unit tests for service, list command, and get command (23 tests)
- Command registration tests in definitions.test.ts (4 tests)
- Help formatting tests updated for functionCommandGroup
- New smoke suite (scripts/smoke/function.ts) exercising list, list
  --draft, get, and get-not-found against a real account — opt-in via
  `yarn smoke --suite=function`

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add `brevo-function-type` to FEATURE_STAGE as a preview feature
- Move function group definition to preview-definitions.ts so esbuild
  can eliminate it from published builds
- Gate the Brevo Function choice in `app create` behind __BREVO_PREVIEW__
- Gate the Function commands section in help.ts behind __BREVO_PREVIEW__
- Add `aliases` support to SubcommandGroupDefinition so `brevo fn list`
  and `brevo fn get` work as shortcuts
- Update tests for the conditional export and gated app-type prompt

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add three management commands to the Brevo Function group:
- `brevo function activate <id>` — PATCH with is_active: true
- `brevo function deactivate <id>` — PATCH with is_active: false
- `brevo function delete <id>` — DELETE with --force to skip confirmation

All three are gated behind __BREVO_PREVIEW__ alongside the existing
list and get commands.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
feat: add brevo function activate, deactivate and delete commands

@piyushsarin-sib piyushsarin-sib left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Review — Brevo Function commands + Function app type

Reviewed the full diff against features_set-dp-function. Verified locally on this head: yarn lint clean, yarn test 65 suites / 1361 tests pass, yarn build succeeds. The findings below are the things those green checks don't cover.

Blocking

  1. brevo_function is never written to app-config.json — no template consumes {{BREVO_FUNCTION_JSON}}, so a Function app is byte-identical to an OAuth app on disk. Details inline on project-writer.ts.
  2. functionService ships in the published bundlecontainer.ts instantiates it unconditionally, so esbuild can't drop it. Inline on container.ts.
  3. function delete --json deletes with no confirmation and no --force. Inline on delete.ts.
  4. The function smoke suite can never passscripts/smoke/core.ts:714 still gates the preview build on the public suite only. Inline on smoke/function.ts.

Not anchored to a diff line

scripts/build.mjs:127LEAK_MARKERS not extended. The list stops at resolveDeploymentTarget; there are no previewFunctionGroup / *FunctionCommand entries. The in-file comment calls this array the real elimination guard, so it's now blind in both directions for this feature: a future stray import that ships the function commands publicly passes, and a preview build that eliminates them by mistake also passes. Elimination does work today — nothing enforces that it keeps working. This is also what would have caught finding 2.

yarn.lock: +270/−383 with package.json untouched. Incidental lockfile re-resolution riding along in a feature PR. It silently moves transitive versions in a diff nobody will review for that — worth dropping or splitting out.

Test gaps. Three pieces of new logic have no coverage:

  • that the Function choice is hidden when --distribution public (the new conditional at create.ts:142-148)
  • that a Function app's app-config.json differs from an OAuth app's — this is precisely why finding 1 slipped through green tests
  • the fn alias

Repo conventions. No changeset, no RELEASE-CHECKLIST.md Before Brevo-Functions GA section, no ## Per-branch verification entry, nothing in docs.md. All four are called for by CLAUDE.md when a new gated feature lands. (SKILL.md / AGENTS.md correctly left alone — gated features carry no reference text until GA.)

Checked and fine

The command surface itself is eliminated from a public build — I confirmed Manage Brevo Functions, all four spinner strings, and every handler are absent from dist/bin/index.js after a plain yarn build. The gating pattern is right; it's the service and the core-lang strings that leak past it.

Also checked and not an issue: the let response; / let fn; declarations in list.ts / get.ts. TypeScript's evolving-let narrows them to the service return types, so the new DpFunction* interfaces do constrain the print sites — I probed it with a bogus property read and it fails typecheck as expected. Explicit annotations would read better, but it's style, not a hole.

Comment thread src/commands/app/project-writer.ts
Comment thread src/container.ts
Comment thread src/commands/function/delete.ts
Comment thread scripts/smoke/function.ts
Comment thread src/commands/definitions.ts
Comment thread src/services/function.ts
Comment thread src/commands/function/activate.ts
Comment thread src/lang/en.ts
Comment thread src/lib/constants.ts
Comment thread src/commands/app/create.ts
@piyushsarin-sib

Copy link
Copy Markdown
Collaborator

Blocking issues — reproductions

Following up on my review with concrete reproductions for the four blocking items. Each was reproduced on this head (0500fe4); the command output below is captured, not illustrative. Inline threads carry the analysis — this comment is just so the repro steps live in one place.


1. Picking "Brevo Function" produces an OAuth project

brevo app create        # choose "Brevo Function" at the app-type prompt
cat app-config.json     # byte-identical to an OAuth app — no brevo_function key

{{BREVO_FUNCTION_JSON}} is set in project-writer.ts:463 and read back by resolveTemplateFlags, but no .tmpl consumes itapp-config.json.tmpl has only {{#if ui_app}} and {{#if oauth}}. So the app type is discarded at write time and app upload, the app scaffold bootstrap, and isUiAppConfig all see a plain OAuth app.

Fix: add the {{#if brevo_function}} block to app-config.json.tmpl, or drop the isBrevoFunction path entirely along with the comments at project-writer.ts:461-462 and create.ts:412-413, which currently assert the opposite.

Why CI is green: nothing asserts on a Function app's rendered config. A test that creates with appType: 'function' and diffs the config against the OAuth one would have caught it.


2. The gated service ships in the published bundle

yarn build                                      # no PREVIEW=1
grep -o 'DP_FUNCTIONS:"[^"]*"' dist/bin/index.js
grep -c 'activateFunction\|deleteFunction'  dist/bin/index.js

Output:

DP_FUNCTIONS:"/v3/dp-functions/functions"
1

Verbatim from the public bundle:

async activateFunction(id){await client2.patch(ENDPOINTS.DP_FUNCTION(id),{is_active:!0})},
async deactivateFunction(id){...},
async deleteFunction(id){await client2.delete(ENDPOINTS.DP_FUNCTION(id))}

container.ts:28 holds a live reference, so esbuild can't drop it. To be clear about the scope: the commands are correctly eliminated — I confirmed Manage Brevo Functions, all four spinner strings, and every handler are absent from a public build. It's the service, its endpoint paths, and the coreMessages strings that get past the gate.

Fix: gate the export behind __BREVO_PREVIEW__ as functionCommandGroup is, or construct the service inside the handlers so the only import sits in an eliminated module.


3. function delete --json deletes with no confirmation and no --force

$ brevo function delete fn-001 --json
{"deleted":true,"id":"fn-001"}

No prompt, no --force, already gone. delete.ts:12 guards on !options.force && !options.json, so --json is treated as consent for an irreversible operation.

brevo app delete sets the opposite precedent (app/delete.ts:89): it guards on !options.force alone, so --json still prompts and --force is the only skip. Anyone calibrated on that loses data here.

Fix: guard on !options.force only, and raise a CliError under --json without --force rather than prompting into a pipe.


4. The function smoke suite cannot pass

scripts/smoke/core.ts:714 is unchanged:

const needsPreview = state.opts.suites.includes('public');

brevo function exists only in a PREVIEW=1 build, so yarn smoke --suite=function builds the published surface and the first step dies on Commander's unknown command 'function'. --against=published fails the same way. There's no skip path to soften it either: GATED_COMMANDS is upload/submit/status/withdraw, GATED_FEATURES is public-distribution, and scripts/smoke/function.ts has no capability probe.

Fix: suites.includes('public') || suites.includes('function'), plus a caps entry if a published run should skip rather than fail.

This one has a knock-on: it means the "Smoke suite exercising list, list --draft, get, and get-not-found against a real account" checkbox can't have been satisfied through yarn smoke --suite=function, so the feature's only integration check isn't currently running.


One more that isn't blocking but guards all of the above

scripts/build.mjs:127LEAK_MARKERS was not extended. No previewFunctionGroup or *FunctionCommand entries, so the array the file itself describes as the real elimination guard is blind in both directions for this feature. Adding those six names is a one-line change and is what would have caught item 2 automatically.

@piyushsarin-sib

Copy link
Copy Markdown
Collaborator

What matters here, in priority order

Consolidating the review into a merge checklist. The four blocking items and their reproductions are in the comment above — not repeating them. This is everything else, ranked, so it's clear what's a merge gate and what's a follow-up.


Must fix before merge

Beyond the four blocking items, two of these are cheap and have consequences well past this PR:

1. Route the service through rethrowNotFound — a 404 currently exits 0.

$ brevo function get fn-999 --json && echo "SUCCESS"
{"error":"not_found","message":"Brevo Function \"fn-999\" not found."}
SUCCESS

Same for activate, deactivate, delete. The primitive already exists (services/app.ts:95) and is used at five call sites; it raises a CliError carrying EXIT_CODES.NOT_FOUND. app rollback is the one exception in the codebase and its reason — a DELETE that answers 404 for two indistinguishable causes — doesn't transfer to any of these four.

This is a scripting contract. Fixing it after release is a breaking change; fixing it now costs nothing.

2. Add requires to all five command definitions. Without it previewFeatureOf returns undefined, so registerCommand marks them non-hidden and installs no assertFeatureAvailable — the gate hides them from the root help screen while leaving them listed and callable in brevo function --help. That inverts the hide-and-refuse invariant at command-registry.ts:84-95. It also makes the whole group invisible to command-capabilities.test.ts (filters on cmd.requires) and preview-gate.test.ts (its buildTree still passes only [appCommandGroup, skillCommandGroup]) — worth adding the group there in the same change.

3. Fix the three comments that assert the opposite of what the code doesproject-writer.ts:461-462, create.ts:412-413, definitions.ts:284-289. Normally a nit; in this repo the comments are the documentation of why the gating works, and definitions.ts:288 in particular tells a future reader that flipping FEATURE_STAGE to 'ga' releases the group when it does not. That's the exact trap CLAUDE.md warns about, written into the code as reassurance.

4. Extend LEAK_MARKERS (scripts/build.mjs:127). Six names, one line. It's what the file itself calls the real elimination guard, and it's what would have caught blocking item 2 without anyone noticing manually.


Should fix in this PR

5. Pagination. limit=50, offset=0 hardcoded, has_more never read, so Total: 120 / 200 can print above 50 rows. --limit/--offset, or auto-paginate, or at minimum showing 50 of 120 — the current output contradicts itself.

6. Move FUNCTION_LIST_* / FUNCTION_GET_* to preview-messages.ts. They went into coreMessages while the activate/deactivate/delete strings in the same branch went to the gated module. Their only readers are eliminated, so they ship as dead strings — Your Brevo Functions is in dist/bin/index.js after a plain yarn build.

7. Collapse the duplicated 404 branch. The same 12-line catch appears in all four handlers, and activate.ts / deactivate.ts are ~95% identical files. One helper — or one handler parameterised on is_active — removes it, and makes item 1 above a single-site fix instead of four.

8. Test the three untested behaviours: the Function choice hidden under --distribution public (new logic at create.ts:142-148), a Function app's rendered app-config.json (this is exactly why blocking item 1 passed CI), and the fn alias.

9. Add the root-help lines for activate / deactivate / delete. brevo --help lists two of five. CLAUDE.md treats that screen as the complete surface agents rely on. If any are deliberately held back, they need a comment saying so, the way app withdraw has one.

10. Process artifacts: changeset, RELEASE-CHECKLIST.md Before Brevo-Functions GA section, a ## Per-branch verification entry, docs.md follow-ups — and drop the incidental yarn.lock churn (+270/−383 with package.json untouched).


Follow-up, not merge gates

Total: 2 / 7 doesn't say 7 is the account cap; the empty-state message says the same thing twice and names no next step; long formula / description values wrap raggedly against the label column; activating an already-active function reports ✓ activated without inspecting the response; delete's help says "deployed" to imply drafts can't be deleted, which the user has to infer from one word; CreateAppInputs.appType is a dead field with a misleading doc comment; the smoke suite bolts _functionId onto shared State via module augmentation where a closure variable would do.


Checked and explicitly not asking for

Two things that look like convention violations but aren't, so nobody spends time on them:

  • Hardcoded spinner strings ('Activating Brevo Function...') — init.ts, login.ts, whoami.ts and project-writer.ts all do this. The en.ts rule covers messages, not transient spinner labels.
  • Raw process.stdout.write with padded labelsapp/list.ts:80-134 is the same shape, same indent, same label column. function list / get are idiomatic as written.

Also verified sound: the command-elimination pattern itself. Manage Brevo Functions, all four spinner strings and every handler are absent from a public build — the gating design is right, it's the service and the core-lang strings that slip past it.

@sonarqubecloud

Copy link
Copy Markdown

@piyushsarin-sib piyushsarin-sib left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

LGTM

@satyamdev10
satyamdev10 merged commit a9bf6c3 into features_set-dp-function Aug 18, 2026
2 checks passed
@satyamdev10
satyamdev10 deleted the review_dp_function branch August 18, 2026 06:50
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.

2 participants