@fateforge/archery-cli 1.0.4 → 1.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -5,6 +5,26 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [1.0.5] - 2026-06-16
9
+
10
+ ### Added
11
+
12
+ - **`--read-only` global switch (and `ARCHERY_CLI_READONLY` env var).** When set, every write command is refused at the shared write chokepoint with an `E_FORBIDDEN` envelope (exit 4) — before the dry-run preview or any network call. Read commands are unaffected. This lets an agent run safely against production with writes hard-disabled regardless of `--dry-run`/`--confirm`. `doctor` and `context` report the current read-only state.
13
+ - **2FA detection + `--otp` (and `ARCHERY_CLI_OTP`).** Session login now understands Archery's two-factor flow. If an account has 2FA enabled, `/authenticate/` accepts the password but does not log in (it returns a `session_key` in `data` with no `sessionid` cookie); the CLI now detects this:
14
+ - With `--otp <6-digit code>` it completes the login via `POST /api/v1/user/2fa/` and caches the resulting session, so **subsequent commands need no OTP** until the session expires.
15
+ - Without an OTP it fails fast with the new **`E_2FA_REQUIRED`** code (exit 9, "human required") and a clear hint to retry with `--otp`, instead of the old opaque "session login failed".
16
+ - 2FA codes are ~30s-lived: generate the code immediately before running. The cached `sessionid` (keyring) is reused afterwards, so OTP is a one-time cost per session.
17
+
18
+ ### Changed
19
+
20
+ - **`workflow detail` reworked to surface execution results.** Detail now reads the execution/review result rows from `/sqlworkflow/detail_content/` and exposes them as `result[]` (each row carries `stage`, `stageStatus`, `errLevel`, `error`, `affectedRows`, `executeTime`), plus the string `statusCode` (e.g. `workflow_exception`) backfilled from the workflow list. An agent can now see **why an execution failed** (e.g. `Invalid remote backup information`) straight from the CLI instead of opening the web UI. SQL content is reconstructed from the rows, with inception wrapper statements filtered out.
21
+ - **Unified instance/group flags for `workflow submit` / `sqlcheck` / `auto-review`.** Session mode now also accepts the numeric `--instance` (ID) and `--group` (ID), resolving them to names via the instance/resource-group lists — the same flags JWT mode already used, so agents no longer have to remember a different flag set per transport. The name flags (`--instance-name` / `--group-name`) still work and win when both are given; an unknown ID fails with a clear `E_NOT_FOUND`.
22
+ - **Skill schema-discovery guidance.** The Skill now steers agents to locate tables/columns by **meaning** via `dict tables` / `dict table-info` (which carry table and column comments) instead of `instance resource` / `instance describe` (bare names only), with an explicit "stop guessing, ask the user" rule when no matching column exists. Fixes all `dict` examples that omitted the required `--db-type`, which fail with `Instance.DoesNotExist` on Archery v1.8.5.
23
+
24
+ ### Notes
25
+
26
+ - **DDL execution and backups.** Executing a DDL workflow with backup enabled needs Archery's backup feature configured (`enable_backup_switch` on and a reachable backup database). On environments without it, execution fails with `Invalid remote backup information` — this is an Archery configuration prerequisite, not a CLI bug. Either have a DBA configure the backup database, or submit with backup disabled (`--backup=false`).
27
+
8
28
  ## [1.0.4] - 2026-06-16
9
29
 
10
30
  ### Added
package/README.md CHANGED
@@ -41,6 +41,10 @@ PowerShell uses `$env:NAME = "value"` for the same environment variables. Keep r
41
41
 
42
42
  **Dual-mode transport — usable by ordinary developer accounts.** By default the CLI logs in and talks to Archery over its **web session + AJAX endpoints** (`/authenticate/`, `/sqlworkflow_list/`, `/sqlquery/`, …). This path works on every Archery version and for plain accounts, where the `/api/v1` REST surface is typically closed (`403`) or simply not enabled. REST + JWT is kept as an opt-in advanced mode: pass `--mode jwt` or set `mode: jwt` on a region. Mode precedence is `--mode` flag → region config → `session` default. Verified live against `hhyo/archery:v1.8.5` with an ordinary account.
43
43
 
44
+ **Read-only mode.** Pass `--read-only` (or set `ARCHERY_CLI_READONLY` to any non-empty value) to hard-disable every write command. Writes are refused at the shared chokepoint with an `E_FORBIDDEN` envelope (exit 4) before any network call, regardless of `--dry-run`/`--confirm`; read commands are unaffected. Use it to run safely against production. `doctor` and `context` report the active state.
45
+
46
+ **Two-factor auth.** For accounts with 2FA enabled, supply a fresh 6-digit code with `--otp <code>` (or `ARCHERY_CLI_OTP`). The CLI detects when Archery requires a second factor and, without a code, fails fast with `E_2FA_REQUIRED` (exit 9) and a hint to retry with `--otp`. Codes are ~30s-lived, so generate one immediately before running; the resulting session is cached, so later commands need no OTP until it expires.
47
+
44
48
  Worst-case risk tier: **T2 high** - can execute and manage SQL workflows against configured database instances. See [SECURITY.md](SECURITY.md) and [.agent/SEC-SPEC.md](.agent/SEC-SPEC.md).
45
49
 
46
50
  ## Capabilities
@@ -86,6 +90,8 @@ Config location: `~/.archery-cli/config.json`.
86
90
  | `ARCHERY_CLI_USERNAME` | Username |
87
91
  | `ARCHERY_CLI_PASSWORD` | Password |
88
92
  | `ARCHERY_CLI_REGION` | Active region/profile |
93
+ | `ARCHERY_CLI_READONLY` | Any non-empty value disables all write commands (same as `--read-only`) |
94
+ | `ARCHERY_CLI_OTP` | 6-digit 2FA code for accounts with two-factor auth (same as `--otp`) |
89
95
  | `NO_COLOR` | Disable colored text output when text mode is explicitly requested |
90
96
 
91
97
  Saved credentials, when supported, are encrypted or stored in the OS credential store. Environment variables take precedence and are the preferred path for short-lived Agent sessions.
package/README_zh.md CHANGED
@@ -41,6 +41,10 @@ PowerShell 使用 `$env:NAME = "value"` 设置同样的环境变量。真实密
41
41
 
42
42
  **双模传输 —— 普通开发者账号即可用。** CLI **默认走 Archery 网页端的 session + AJAX 端点**(`/authenticate/`、`/sqlworkflow_list/`、`/sqlquery/` 等)登录和请求。这条路径在所有 Archery 版本、对普通账号都可用;而 `/api/v1` REST 面通常对普通账号关闭(`403`)或根本未开启。REST + JWT 作为可选的高级模式保留:传 `--mode jwt` 或在 region 配置 `mode: jwt` 即可。模式优先级为 `--mode` 参数 → region 配置 → 默认 `session`。已在 `hhyo/archery:v1.8.5` 上用普通账号真机验证。
43
43
 
44
+ **只读模式。** 传 `--read-only`(或将 `ARCHERY_CLI_READONLY` 设为任意非空值)即可硬禁用所有写命令。写命令会在统一入口处被拒,返回 `E_FORBIDDEN`(退出码 4),且发生在任何网络调用之前,不受 `--dry-run`/`--confirm` 影响;读命令不受影响。适合在生产环境安全运行。`doctor` 和 `context` 会显示当前是否只读。
45
+
46
+ **二次验证(2FA)。** 对开启了 2FA 的账号,用 `--otp <验证码>`(或 `ARCHERY_CLI_OTP`)传入新鲜的 6 位验证码。CLI 会检测到 Archery 要求二次验证;若未提供验证码,会立即失败并返回 `E_2FA_REQUIRED`(退出码 9),提示用 `--otp` 重试。验证码有效期约 30 秒,请在运行前即时生成;验证成功后会话会被缓存,后续命令在会话过期前无需再次输入 OTP。
47
+
44
48
  最坏情况风险等级:**T2 高风险** - 可对已配置数据库实例执行和管理 SQL 工单。参见 [SECURITY.md](SECURITY.md) 和 [.agent/SEC-SPEC.md](.agent/SEC-SPEC.md)。
45
49
 
46
50
  ## 能力
@@ -86,6 +90,8 @@ README 只做地图,不做完整手册。Agent 在执行任务命令前,应
86
90
  | `ARCHERY_CLI_USERNAME` | 用户名 |
87
91
  | `ARCHERY_CLI_PASSWORD` | 密码 |
88
92
  | `ARCHERY_CLI_REGION` | 当前区域/profile |
93
+ | `ARCHERY_CLI_READONLY` | 任意非空值即禁用所有写命令(等价于 `--read-only`) |
94
+ | `ARCHERY_CLI_OTP` | 开启 2FA 账号的 6 位验证码(等价于 `--otp`) |
89
95
  | `NO_COLOR` | 显式使用 text 模式时禁用彩色输出 |
90
96
 
91
97
  支持保存凭据时,凭据会加密或进入 OS 凭据库。环境变量优先级更高,也是短生命周期 Agent 会话的推荐方式。
@@ -361,6 +361,37 @@ intermittently returned `用户名或密码错误`. Using `http://127.0.0.1:9123
361
361
  defect; the session login flow itself (GET csrf → POST authenticate → cookie)
362
362
  matches the verified curl flow byte-for-byte.
363
363
 
364
+ ## 2026-06-16 — 1.0.5 features (read-only, 2FA, param unification, detail rework)
365
+
366
+ Verified against the same `tools-e2e-archery` container (`hhyo/archery:v1.8.5`,
367
+ base `http://localhost:9123`) with the ordinary superuser account `cli_verify`,
368
+ binary built from this working tree (`go build -o /tmp/a.exe ./cmd/archery-cli`),
369
+ `ARCHERY_CLI_NO_KEYRING=1`.
370
+
371
+ ### Result by feature
372
+
373
+ | Feature | Status | Evidence |
374
+ |---------|--------|----------|
375
+ | `--read-only` reflected in `doctor` | live (read) | PASS — `doctor` JSON shows `readOnly:true` and a `read-only` warn check; `auth` still `pass` (logged in to the real server). |
376
+ | `--read-only` reflected in `context` | live (read) | PASS — `context.data.readOnly == true`. |
377
+ | `--read-only` refuses a write | live | PASS — `workflow submit ... --read-only --dry-run` → `E_FORBIDDEN`, exit 4, before any network call. |
378
+ | `ARCHERY_CLI_READONLY` env | live | PASS — read command (`workflow list`) succeeds under the env var; the env is a pure read-allow path. |
379
+ | Param unification: `--instance`/`--group` IDs (session) | live | PASS — `workflow submit --instance 1 --group 1 --dry-run` preview resolves `instanceName:e2e-mysql`, `groupName:smoke-rg`; confirm submitted real workflow id 4. |
380
+ | Unknown instance ID | live | PASS — `--instance 999` → `E_NOT_FOUND` (exit 3) with a clear "check 'instance list'" message. |
381
+ | `workflow detail` result rework | live | PASS — `detail 4` returns `result[]` (real auto-review rejection "仅支持DML和DDL语句…") + `statusCode:workflow_autoreviewwrong` + numeric `status:3`. |
382
+ | `--otp` harmless for non-2FA account | live | PASS — passing `--otp 000000` for `cli_verify` (no 2FA) does not break login; the OTP path only fires when the server signals 2FA. |
383
+ | 2FA detection + `--otp` completion | **mock only** | The `cli_verify` account has **no 2FA enabled**, so the 2FA login branch cannot be exercised live. Covered by unit tests `TestEnsureSession_2FARequiredNoOTP` / `2FAWithOTPSucceeds` / `2FAWrongOTP` against an httptest server that mimics v1.8.5's `/authenticate/` (status 0 + `data` session_key, no sessionid) and `/api/v1/user/2fa/`. **Honest gap: the real `/api/v1/user/2fa/` round-trip is not live-verified.** |
384
+
385
+ Test workflow id 4 was cancelled after verification (`workflow cancel 4`) to
386
+ leave the container clean.
387
+
388
+ ### Honesty notes
389
+
390
+ - **Race detector not run on this host:** `go test -race` needs cgo + gcc, which
391
+ are unavailable on the verifier machine. The non-race suite (`go test ./...`)
392
+ is fully green, and `golangci-lint run` reports 0 issues.
393
+ - **2FA is mock-verified only** for the reason above.
394
+
364
395
  ## Reproduce
365
396
 
366
397
  ```bash
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fateforge/archery-cli",
3
- "version": "1.0.4",
3
+ "version": "1.0.5",
4
4
  "description": "Archery SQL audit CLI for AI Agents - manage SQL workflows, queries, instances, diagnostics, and data dictionaries with a machine-readable contract",
5
5
  "keywords": [
6
6
  "archery",
@@ -26,12 +26,12 @@
26
26
  "archery-cli": "scripts/run.js"
27
27
  },
28
28
  "optionalDependencies": {
29
- "@fateforge/archery-cli-darwin-arm64": "1.0.4",
30
- "@fateforge/archery-cli-darwin-x64": "1.0.4",
31
- "@fateforge/archery-cli-linux-arm64": "1.0.4",
32
- "@fateforge/archery-cli-linux-x64": "1.0.4",
33
- "@fateforge/archery-cli-win32-arm64": "1.0.4",
34
- "@fateforge/archery-cli-win32-x64": "1.0.4"
29
+ "@fateforge/archery-cli-darwin-arm64": "1.0.5",
30
+ "@fateforge/archery-cli-darwin-x64": "1.0.5",
31
+ "@fateforge/archery-cli-linux-arm64": "1.0.5",
32
+ "@fateforge/archery-cli-linux-x64": "1.0.5",
33
+ "@fateforge/archery-cli-win32-arm64": "1.0.5",
34
+ "@fateforge/archery-cli-win32-x64": "1.0.5"
35
35
  },
36
36
  "files": [
37
37
  "scripts/run.js",
@@ -1,10 +1,10 @@
1
1
  ---
2
2
  name: archery-cli
3
- version: "1.0.4"
3
+ version: "1.0.5"
4
4
  description: "Archery SQL audit platform CLI for managing SQL workflows, queries, instances, diagnostics. Use when the user asks about SQL审核, database operations, Archery platform management, or needs to submit/review/execute SQL against database instances."
5
5
  license: MIT
6
6
  user-invocable: true
7
- metadata: {"requires":{"bins":["archery-cli"],"min_version":"1.0.4"}}
7
+ metadata: {"requires":{"bins":["archery-cli"],"min_version":"1.0.5"}}
8
8
  ---
9
9
 
10
10
  # archery-cli
@@ -58,6 +58,10 @@ First-time setup: ask user for Archery URL + credentials, then run `archery-cli
58
58
  | Dangerous writes | If `reference` shows `requiresDangerous`, include `--dangerous` in both dry-run and confirm commands |
59
59
  | Discovery | `archery-cli reference` is the machine truth for params, `write`, `requiresConfirmation`, `requiresDangerous`, `riskLevel`, output schemas, and errors |
60
60
  | Transport | Defaults to **session** mode (Archery web AJAX endpoints) — works for ordinary accounts on all versions. REST + JWT is opt-in via `--mode jwt` or a region's `mode: jwt`. Precedence: `--mode` flag → region config → `session`. |
61
+ | Read-only | Pass `--read-only` (or set `ARCHERY_CLI_READONLY`) to hard-disable all writes; they fail with `E_FORBIDDEN` (exit 4) before any network call. Use it when the task is read-only/analysis. |
62
+ | 2FA | If a command fails with `E_2FA_REQUIRED` (exit 9), the account has 2FA on. Ask the user for a fresh 6-digit code and retry the **same** command with `--otp <code>` (codes last ~30s). The session is then cached, so later commands need no OTP. |
63
+ | Instance/group IDs | `workflow submit/sqlcheck/auto-review` accept either `--instance`/`--group` (numeric IDs, resolved automatically) **or** `--instance-name`/`--group-name`. IDs work in both transport modes. |
64
+ | Schema discovery | To locate a table/column by **meaning** (not its exact name), use `dict tables` → `{name, comment}` then `dict table-info` → per-column `column_comment`: those carry the human labels (e.g. `班级学生表`, `性别`). `instance resource`/`instance describe` return **bare names with no comments** — use them only when you already know the exact identifier. Already know the table name but not which instance holds it? `instance table-instances --table <name>`. `dict` needs `--instance <name>` (not ID) **and** `--db-type <mysql/...>` (db-type is required on v1.8.5; omitting it fails with `Instance.DoesNotExist`). |
61
65
 
62
66
  ## Trigger list
63
67
 
@@ -99,7 +103,8 @@ First-time setup: ask user for Archery URL + credentials, then run `archery-cli
99
103
  | Review slow queries | `archery-cli slowquery review --instance mydb --start "2024-01-01 00:00:00" --end "2024-01-31 23:59:59"` |
100
104
  | List processes | `archery-cli diagnostic process --instance mydb` |
101
105
  | List binlog files | `archery-cli binlog list --instance mydb` |
102
- | Browse tables | `archery-cli dict tables --instance mydb --db test` |
106
+ | Find a table/column by meaning | `archery-cli dict tables --instance mydb --db test --db-type mysql` (scan `comment`), then `dict table-info ... --table t` (scan `column_comment`) |
107
+ | Browse tables | `archery-cli dict tables --instance mydb --db test --db-type mysql` |
103
108
  | Test instance connectivity | `archery-cli instance test-instance --instance 1 --compact` |
104
109
  | Create a database on an instance | `archery-cli instance create-db --instance 1 --db reporting --owner alice --dangerous --dry-run`, then `--dangerous --confirm <token>` |
105
110
  | Create a database account | `archery-cli instance create-user --instance 1 --user app --host '%' --password '...' --dangerous --dry-run`, then `--dangerous --confirm <token>` |
@@ -177,6 +182,7 @@ Check `ok` first, then act on exit code:
177
182
  | 6 | `E_CONFLICT` | Stale or invalid token | Re-run `--dry-run`, get fresh token, retry |
178
183
  | 7 | `E_NETWORK`/`E_RATE_LIMIT`/`E_SERVER` | Transient error | Back off and retry |
179
184
  | 8 | `E_TIMEOUT` | Timeout | Back off and retry |
185
+ | 9 | `E_2FA_REQUIRED` | Account needs a 2FA code | Ask user for a fresh 6-digit code, retry same command with `--otp <code>` (~30s validity) |
180
186
 
181
187
  ## Permission and security boundary declarations
182
188
 
@@ -218,8 +224,13 @@ archery-cli workflow detail 42
218
224
  # After approval, execute
219
225
  archery-cli workflow execute 42 --mode auto --dangerous --dry-run
220
226
  archery-cli workflow execute 42 --mode auto --dangerous --confirm ct_...
227
+
228
+ # If execution fails, `workflow detail 42` now shows the reason in result[]:
229
+ archery-cli workflow detail 42 --compact # look at result[].error / statusCode
221
230
  ```
222
231
 
232
+ **DDL execution + backups.** If a DDL execution fails with `result[].error = "Invalid remote backup information"`, the target Archery environment has not configured backups (no `enable_backup_switch` / no reachable backup database). This is an **Archery configuration prerequisite, not a CLI bug**. Either ask a DBA to configure the backup database, or submit the workflow with backup disabled (`--backup=false`). The cause is visible directly from `workflow detail` (as of 1.0.5), so check `result[]` before escalating.
233
+
223
234
  ### 2. Query a database and analyze results
224
235
 
225
236
  ```bash
@@ -269,23 +280,37 @@ archery-cli diagnostic kill --instance prod-mysql --threads "12345,12346" --dang
269
280
 
270
281
  ### 5. Browse data dictionary and table structure
271
282
 
283
+ **Locating a table/column from a vague ask** (e.g. "how old is 张三") — the comment is your map, don't guess at names:
284
+
285
+ ```bash
286
+ # 1. Scan table comments to find the table that matches the concept ("学生")
287
+ archery-cli dict tables --instance prod-mysql --db mydb --db-type mysql --compact
288
+ # → [{"name":"students","comment":"班级学生表"}, ...]
289
+
290
+ # 2. Scan column comments to map the concept to a column ("年龄")
291
+ archery-cli dict table-info --instance prod-mysql --db mydb --db-type mysql --table students --compact
292
+ # → if no age/birthday column exists, STOP guessing — ask the user or derive it.
293
+ ```
294
+
295
+ Prefer the two steps above over `instance resource` (bare names) and `instance describe` (no comments) whenever the user names a **concept**, not an exact identifier. `dict` requires `--db-type` on v1.8.5.
296
+
272
297
  ```bash
273
298
  # List all tables in a database
274
- archery-cli dict tables --instance prod-mysql --db mydb
299
+ archery-cli dict tables --instance prod-mysql --db mydb --db-type mysql
275
300
 
276
- # Show table metadata and indexes
277
- archery-cli dict table-info --instance prod-mysql --db mydb --table orders
301
+ # Show table metadata and indexes (includes column_comment)
302
+ archery-cli dict table-info --instance prod-mysql --db mydb --db-type mysql --table orders
278
303
 
279
- # Describe table columns
304
+ # Describe table columns (bare structure, no comments — use when the name is already known)
280
305
  archery-cli instance describe --instance prod-mysql --db mydb --table orders
281
306
 
282
307
  # List views, triggers, procedures
283
- archery-cli dict views --instance prod-mysql --db mydb
284
- archery-cli dict triggers --instance prod-mysql --db mydb
285
- archery-cli dict procedures --instance prod-mysql --db mydb
308
+ archery-cli dict views --instance prod-mysql --db mydb --db-type mysql
309
+ archery-cli dict triggers --instance prod-mysql --db mydb --db-type mysql
310
+ archery-cli dict procedures --instance prod-mysql --db mydb --db-type mysql
286
311
 
287
312
  # Export data dictionary as HTML
288
- archery-cli dict export --instance prod-mysql --db mydb --format raw > dict.html
313
+ archery-cli dict export --instance prod-mysql --db mydb --db-type mysql --format raw > dict.html
289
314
  ```
290
315
 
291
316
  ### 6. Binlog parsing and data recovery
@@ -46,11 +46,17 @@ archery-cli workflow sqlcheck --instance 1 --db mydb --sql "ALTER TABLE users AD
46
46
  |------|------|-------------|
47
47
  | `--fields` | string | Comma-separated output fields |
48
48
 
49
+ `workflow detail` returns the execution/review result rows in `result[]` (each
50
+ `{stage, stageStatus, errLevel, error, affectedRows, executeTime}`) plus the
51
+ string `statusCode` (e.g. `workflow_exception`). When an execution failed, the
52
+ reason is in `result[].error` — read it before escalating.
53
+
49
54
  ### `workflow sqlcheck` flags
50
55
 
51
56
  | Flag | Type | Required | Description |
52
57
  |------|------|----------|-------------|
53
- | `--instance` | int | yes | Target instance ID |
58
+ | `--instance` | int | one of | Target instance ID (resolved to a name in session mode) |
59
+ | `--instance-name` | string | one of | Target instance name (session mode; wins over `--instance`) |
54
60
  | `--db` | string | yes | Target database name |
55
61
  | `--sql` | string | yes | SQL to check |
56
62
 
@@ -71,13 +77,21 @@ archery-cli workflow submit --name "Add email index" --instance 1 --db mydb \
71
77
  | Flag | Type | Required | Default | Description |
72
78
  |------|------|----------|---------|-------------|
73
79
  | `--name` | string | yes | -- | Workflow title |
74
- | `--instance` | int | yes | -- | Target instance ID |
80
+ | `--instance` | int | one of | -- | Target instance ID (resolved to a name in session mode) |
81
+ | `--instance-name` | string | one of | -- | Target instance name (session mode; wins over `--instance`) |
75
82
  | `--db` | string | yes | -- | Target database name |
76
83
  | `--sql` | string | yes | -- | SQL content |
77
- | `--group` | int | no | (auto) | Resource group ID |
78
- | `--backup` | bool | no | true | Require backup before execution |
84
+ | `--group` | int | one of | (auto) | Resource group ID (resolved to a name in session mode) |
85
+ | `--group-name` | string | one of | -- | Resource group name (session mode; wins over `--group`) |
86
+ | `--backup` | bool | no | true | Require backup before execution (needs Archery backups configured; see note below) |
79
87
  | `--demand-url` | string | no | -- | Related demand/requirement URL |
80
88
 
89
+ > **Backup prerequisite:** with `--backup=true` (the default), DDL execution
90
+ > needs Archery's backup feature configured (`enable_backup_switch` + a reachable
91
+ > backup DB). Without it, execution fails with `Invalid remote backup
92
+ > information` (visible in `workflow detail` → `result[].error`). Submit with
93
+ > `--backup=false` to skip backups, or have a DBA configure the backup database.
94
+
81
95
  ### Audit (approve or reject) a workflow
82
96
 
83
97
  ```bash