Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 33 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ norbix scheduler list
| `norbix files list/info/get-by-id/upload/download/sign/delete/publish/unpublish` | Upload, download, manage and publish files |
| `norbix files integrations test <id>` | Check that a files integration really works (live upload/read/list/delete probe) |
| `norbix users list/get/invite/block/unblock/delete` | Manage project users (membership) |
| `norbix env list/use/delete` | Manage project environments (see *Environments* below) |
| `norbix env list/use/delete/promote/rollback`, `norbix env built-ins repair` | Manage project environments and move content TEST → PROD (see *Environments* below) |
| `norbix logs list/trail` | Read project logs, follow one correlation ID |
| `norbix scheduler list/get/save/enable/disable/delete` | Scheduler tasks — a cron that sends an email campaign; every scheduler endpoint, see [docs/scheduler.md](docs/scheduler.md) |
| `norbix apikeys list/create/regenerate/revoke` | Service-user API keys for scripts, CI, SDKs and agents |
Expand Down Expand Up @@ -269,6 +269,38 @@ for `--env PROD`), `NORBIX_ENV`, or a default saved with `norbix env use TEST`
exit 2 `ENV_REQUIRED` and lists the environments; nothing is sent. Apps that
use the API or an SDK directly are not affected: with no env they work in PROD.

#### Moving TEST to PROD (promotion)

Build schemas, taxonomies and terms, templates, footers, signatures and
triggers in TEST, then move them up — never re-create them in PROD by hand
(the copies would get other ids and break triggers and term links).

```sh
norbix env promote --from TEST --to PROD # preview (the default): nothing changes
norbix env promote --from TEST --to PROD --yes # promote; prints the rollback anchor
norbix env rollback --to PROD --version 279 # preview the undo; add --yes to run it
norbix env built-ins repair # built-in templates under PROD's ids; --yes to run
```

The preview shows a summary, every item by status (added / changed /
unchanged / deleted with its record count / kept), one line per source
integration with the choice that applies (`!` marks a real e-mail / SMS /
push sender) and what is never promoted (records, users, files, …).
By default Fake integrations are copied and everything else is left out;
change that per integration with `--seed <id>`, `--skip <id>` or
`--map <id>=<target id>`. A real run that would hide records stops with exit 3
until you add `--confirm-record-loss`. For these three commands `--dry-run`
means the Hub's preview (the request is sent with `dryRun: true`). `--json`
prints the Hub's answer as it is.

When a command creates or changes such content directly in an environment that
has a lower one (`db schema create --env PROD` while TEST exists), it still
runs, and stderr says:

```text
Note: PROD is promoted from TEST — make the change in TEST and run `norbix env promote --from TEST --to PROD`
```

## JSON output

Every command supports `--json` and prints clean JSON on stdout, so you can
Expand Down
26 changes: 24 additions & 2 deletions docs/AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,30 @@ A project always has PROD and may have more (TEST, STAGING, …). Check first:
on stderr. Read that line.
- Account commands (no project) and `norbix env …` are not checked.

The list of environments is cached for 5 minutes per project; `env list /
use / delete` and an "environment does not exist" error refresh it.
The list of environments (and the promotion ladder, `promotionOrder`) is
cached for 5 minutes per project; `env list / use / delete` and an
"environment does not exist" error refresh it.

### Environments: build in TEST, promote to PROD

Never build PROD by hand when the project has a lower env. Schemas,
taxonomies, terms, templates, footers, signatures and triggers are made in TEST
and promoted:

1. `norbix env promote --from TEST --to PROD --json` — a preview (the
default), nothing changes. Show the user `summary`, `items` (deleted ones
with `recordCount`), `integrations` (`action`, `warning`, `realSender`) and
`notPromoted`.
2. After the user agreed: the same command with `--yes`
(`--seed / --skip / --map id=targetId` only for integrations the user
decided; `--confirm-record-loss` only when `requiresConfirmation` is true and
the user accepts it — exit 3 `CM-ERRORS-ENVIRONMENTS-013` means it was missing).
3. Keep `fromVersion`: `norbix env rollback --to PROD --version <fromVersion>`
(preview, then `--yes`) undoes it.

A content command run straight in PROD while TEST exists prints
`Note: PROD is promoted from TEST — …` on stderr: make the change in TEST and
promote instead.

## 2. Always `--json`

Expand Down
4 changes: 4 additions & 0 deletions docs/agent-contract.md
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,10 @@ command that makes several calls (`files upload`) shows the first.
`insert`, `update --id`, `replace`, `archive`, `unarchive`, `clone`,
`enable`, `invite`, `unblock`, `upload`, `publish`, `unpublish`,
`config set / unset`, `env use`, `logout`, `raw`.
- **Preview by default** (`env promote`, `env rollback`, `env built-ins repair`):
without `--yes` they ask the Hub for the plan and change nothing — here
`--dry-run` is that preview (the request is sent with `dryRun: true`), not
"send nothing". `--yes` runs them for real.
- **Read-only**: everything else; no `--yes`, no `--dry-run`.

## 6. Shared code
Expand Down
78 changes: 78 additions & 0 deletions docs/tasks/promotion-phase2.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
# Environment promotion — phase 2 (CLI): `norbix env promote / rollback / built-ins repair`
This file: /Users/djovaisas/Projects/norbix/worktrees/cli/feat/promotion-phase2/docs/tasks/promotion-phase2.md (branch feat/promotion-phase2)
Gateway side (shipped 57b5f4bad): /Users/djovaisas/Projects/norbix/gateway/docs/tasks/promotion-phase2.md (branch refactoringV2)
Phase 1 contract: /Users/djovaisas/Projects/norbix/gateway/docs/tasks/promotion-v2.md (branch refactoringV2)

## Goal
Give developers and agents first-class promotion commands with a readable preview (dry run by default), a hint when
they change content directly in a higher environment, and `norbix ai init` guidance that says "build in TEST, preview,
promote, roll back if needed — never build PROD by hand".

Not in scope: team-member update / remove commands (another agent; may come in a later message); regenerating
`@norbix.ai/ts` (see decision below); the dashboard.

## Plan
1. [done] docs(cli:env:promotion): this task file
2. [done] feat(cli:env:promotion): `norbix env promote --from TEST --to PROD` — preview by default (`--dry-run` says it explicitly), real run with `--yes`; `--confirm-record-loss`; `--seed / --skip / --map id=targetId`; human preview (summary, items by status, integrations with choices and warnings, not-promoted list); `--json` prints the raw answer; record-loss refusal explained with the plan
3. [done] feat(cli:env:promotion): `norbix env rollback --to PROD --version N` and `norbix env built-ins repair` (same preview / `--yes` rule)
4. [done] feat(cli:env:promotion-hint): a content write (schema, taxonomy, term, template, trigger, footer, signature) into an env that has a lower one prints on stderr: "PROD is promoted from TEST — make the change in TEST and run `norbix env promote --from TEST --to PROD`"; the env ladder (`promotionOrder`) is cached with the env list
5. [done] feat(cli:ai:init): the skill and the CLAUDE.md / AGENTS.md block get a short "Environments" section
6. [done] test(cli): tests for the three commands (fixture = the phase 1 contract example), the hint, `ai init`, the old `hub account environment promote --body` path; `tsc --noEmit` clean, `npm test` 39 files, 1067/1067 passed
7. [done] docs(cli): README + docs/project.md command table
8. [done] feat(cli:env:promotion): the integrations table shows the id in the target when it differs (`targetId`, gateway 44548a144: a seeded Files integration gets its own id; a map names the target integration)
9. [done] release(cli): pull request merged by nbx-ship (rebase); semantic-release publishes the minor from CI (trusted publishing) — PR and version in the final report

## Decisions
- decision(cli:sdk-types): the CLI does not wait for a regenerated `@norbix.ai/ts`. 4.29.0 knows `promoteEnvironment` / `rollbackPromotion` but not `confirmRecordLoss`, `integrationChoices`, rollback `dryRun`, the v2 result fields, or the built-in repair endpoint. Regenerating needs a running Hub (`sync-types.mjs`) and a separate SDK release; the transport sends the whole request object, so the CLI builds the body with its own types (`src/lib/promotion.ts`) and calls the repair route through the SDK transport of the environments module (same auth, refresh, env rule, retry). Recorded under Findings for the SDK owners.
- decision(cli:env:dry-run): for these three commands `--dry-run` is the server's preview (the request is sent with `dryRun: true`, nothing changes) — not the usual "send nothing". It is also the default. A real run needs `--yes`. This is what an agent taught "dry run first" needs: the plan, not the HTTP request.
- decision(cli:env:ladder): which env feeds which comes from `promotionOrder` in the env list (gateway 57b5f4bad); it is cached with the env names (5 minutes). An older gateway sends no ladder: then PROD's lower env is TEST if the project has one, else the only other env; other envs get no hint.
- decision(cli:env:hint): an allowlist of command ids, printed on stderr only (stdout stays one JSON document), also on a `--dry-run` (that is when an agent should read it). Record commands never hint: records are not promoted.

## Changes
| file (absolute, branch feat/promotion-phase2) | what changed | step |
|------|--------------|------|
| /Users/djovaisas/Projects/norbix/worktrees/cli/feat/promotion-phase2/docs/tasks/promotion-phase2.md | this file | 1 |
| /Users/djovaisas/Projects/norbix/worktrees/cli/feat/promotion-phase2/src/lib/promotion.ts:277 | new: v2 types, `--seed/--skip/--map` parsing, the human preview, repair rendering, the hint allowlist (`:360`), `lowerEnvOf` (`:386`) | 2, 3, 4 |
| /Users/djovaisas/Projects/norbix/worktrees/cli/feat/promotion-phase2/src/commands/env/promote.ts | new command | 2 |
| /Users/djovaisas/Projects/norbix/worktrees/cli/feat/promotion-phase2/package.json | `env` topic text, `env built-ins` subtopic | 2 |
| /Users/djovaisas/Projects/norbix/worktrees/cli/feat/promotion-phase2/src/commands/env/rollback.ts | new command | 3 |
| /Users/djovaisas/Projects/norbix/worktrees/cli/feat/promotion-phase2/src/commands/env/built-ins/repair.ts | new command (repair route through the SDK transport) | 3 |
| /Users/djovaisas/Projects/norbix/worktrees/cli/feat/promotion-phase2/src/base.ts:696, :709, :839 | hint decided with the env rule, printed once on stderr after a successful call or a `--dry-run` report | 4 |
| /Users/djovaisas/Projects/norbix/worktrees/cli/feat/promotion-phase2/src/lib/hosts.ts:466 | env cache keeps `promotionOrder`; `cachedPromotionOrder` | 4 |
| /Users/djovaisas/Projects/norbix/worktrees/cli/feat/promotion-phase2/src/lib/env-rule.ts | `promotionOrderOf` | 4 |
| /Users/djovaisas/Projects/norbix/worktrees/cli/feat/promotion-phase2/src/lib/agent-files.ts:68 | "Environments" bullet in the block, "Environments — build in TEST, promote to PROD" section and an example in the skill | 5 |
| /Users/djovaisas/Projects/norbix/worktrees/cli/feat/promotion-phase2/tests/ai-init.test.ts | block bullets (+1), line limits 12→13 (block) and 40→50 (skill), a new test for the Environments guidance | 5 |
| /Users/djovaisas/Projects/norbix/worktrees/cli/feat/promotion-phase2/tests/env-promote.test.ts (+ `__snapshots__/env-promote.test.ts.snap`) | new: 14 tests | 6 |
| /Users/djovaisas/Projects/norbix/worktrees/cli/feat/promotion-phase2/tests/__snapshots__/schema.test.ts.snap | three new commands in `norbix schema` | 6 |
| /Users/djovaisas/Projects/norbix/worktrees/cli/feat/promotion-phase2/README.md, docs/AGENTS.md, docs/agent-contract.md | "Moving TEST to PROD"; preview-by-default commands in the contract | 7 |

## Findings
- gen(sdk-ts:types): `@norbix.ai/ts` 4.29.0 lags the gateway: no `confirmRecordLoss` / `integrationChoices` on `PromoteEnvironmentRequest`, no `dryRun` / `confirmRecordLoss` on `RollbackPromotionRequest`, only the old fields on `PromotionResultDto`, no built-in repair method, no `promotionOrder` on `ProjectEnvironmentsDto`. The CLI works around it with local types — open (next types regen of the SDKs)
```ts
// node_modules/@norbix.ai/ts/dist/types/hub2.dtos.d.ts:8026-8033 (4.29.0)
class PromoteEnvironmentRequest extends CodeMashRequestBase implements IReturn<PromoteEnvironmentResponse> {
sourceEnv: string;
targetEnv: string;
dryRun: boolean; // <-- missing: confirmRecordLoss, integrationChoices
```
```ts
// src/commands/env/promote.ts (branch feat/promotion-phase2) — the cast the CLI needs until then
return (await client.hub.account.promoteEnvironment(body(dryRun) as never)) as unknown as {item?: PromotionResult}
```
- gap(cli:hint): `norbix hub <module> <method>` (the generic path) and `norbix raw` never print the promotion hint — only the named content commands do — open
- gap(cli:hint): there is no `db taxonomy create` command in the CLI (taxonomies are made with `norbix hub database save-database-taxonomy`), so a taxonomy write gets no hint from the CLI; terms do (`db term create/update`) — open
- gap(cli:hint): on `--dry-run` the CLI sends nothing, so it reads the env list only from the 5-minute cache; with a cold cache a dry run prints no hint (the real run does) — open, by design
- chore(cli:git): `nbx-doctor` WARN — the main checkout /Users/djovaisas/Projects/norbix/sdks/cli is on `fix/sdk-1.3-and-deps` with an untracked `docs/tasks/agent-native-cli.md`; not mine, untouched

## Acceptance #5 — "set up PROD like TEST" leads to a promotion with a preview first
- In a fresh folder `/tmp/happy-tummy-accept.yRfs` (scratch, outside every repo): `norbix ai init` (this branch's build) wrote `.claude/skills/norbix/SKILL.md` and `CLAUDE.md`. Both carry the Environments rules (`grep -n promot` → CLAUDE.md:11, SKILL.md:3, 23, 25, 28, 29, 30, 32, 45). Log: `~/scratch/promotion-phase2/accept-ai-init.txt`, `accept-grep.txt`.
- A headless agent in that folder (`claude -p "… Set up PROD like TEST. Do not run any command now — list the exact commands …" --strict-mcp-config --setting-sources project,local --disallowedTools "Bash Edit Write WebFetch WebSearch"`) answered, in order: `norbix whoami --json` → `norbix env promote --help` → **`norbix env promote --from TEST --to PROD --json` (preview)**, show summary / items with recordCount / integrations with realSender / notPromoted, ask about each integration and record loss → **`norbix env promote --from TEST --to PROD --yes --json [--seed …] [--map …] [--confirm-record-loss]` only after you agree**, keep `fromVersion` → rollback `norbix env rollback --to PROD --version <fromVersion>` (preview, then `--yes`); "I never edit PROD directly". Full answer: `~/scratch/promotion-phase2/accept-agent.txt`.
- MCP side (gateway 57b5f4bad): `promote_environment` says "USE IT whenever the user wants PROD … to match TEST … ALWAYS two calls: (1) dryRun: true …; (2) only after the user agreed … dryRun: false"; a `dryRun: true` call needs no confirmation and no env argument (L3 test `Promote_Is_An_Environment_Tool_Whose_Dry_Run_Is_A_Preview`); the Norbix assistant prompt routes "set up PROD like TEST" to a promotion (prompt v5).

## Rejected / moved out
- decision(cli:sdk-types): regenerate `@norbix.ai/ts` first and wait for its release — rejected for this change: it needs a running Hub and a separate SDK release; the CLI's local types cover the gap — new ticket: none (listed under Findings for the next regen)

## Needs you

## Open questions
- none
7 changes: 6 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,12 @@
}
},
"env": {
"description": "Manage project environments (PROD, TEST, ...)"
"description": "Project environments (PROD, TEST, ...): list, pick a default, promote TEST → PROD, roll back, repair built-ins",
"subtopics": {
"built-ins": {
"description": "PROD's built-in templates, footer and signature in every environment"
}
}
},
"files": {
"description": "Upload, download and manage files",
Expand Down
Loading
Loading