@wirecat/cli-base 0.40.4 → 0.42.0

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.
@@ -0,0 +1,214 @@
1
+ # Architecture
2
+
3
+ ## Scope
4
+
5
+ How the code is split: the layers and the direction of dependencies, no vendor type above the adapter, and what
6
+ belongs in cli-base, in cli-core or in the CLI itself.
7
+
8
+ Rule ids on this page are `WC-ARCH-<n>`. How to read a rule, how ids work and which rule wins are in the
9
+ [index](README.md).
10
+
11
+ Related pages: file size, one job per file and how a large unit is split are in [Layout](layout.md); import cycles
12
+ and the lint that holds the layers are in [Toolchain](toolchain.md); who opens and closes a resource, what may open
13
+ at start-up and the `serve` relay are in [Lifecycle](lifecycle.md); the store's own rules are in [Store](store.md).
14
+
15
+ ### Words used here
16
+
17
+ - **Adapter:** the code that talks to one provider (Telegram, MAX, WhatsApp, Google Drive, Zoom) and translates its
18
+ objects into our own types.
19
+ - **Port:** an interface that says what a service needs, for example `MessengerAdapter` or a store area.
20
+ - **Service:** a use case, written once, that both a command and an MCP tool call.
21
+ - **Composition root:** the place in a CLI where real implementations are chosen and connected, usually
22
+ `program.ts` and the command context.
23
+ - **Vendor type:** a type from a provider library, such as `@mtcute/*` or `ws`.
24
+
25
+ ## Rules
26
+
27
+ ### WC-ARCH-1 · Call only the layers below you: interface, then service, then port, then adapter
28
+
29
+ - **Why:** when a command calls an adapter directly, the MCP tool for the same job does something different.
30
+ - **Enforced by:** `cli-core: biome noRestrictedImports`.
31
+ - **Example:** cli-core has five layers: domain (`src/domain/`), adapters, ports (`port.ts`, the store), services
32
+ (`src/services/`) and the interface (commands and MCP tools). Its `biome.json` refuses an import of
33
+ `commander` or of `src/cli/` from the services and the layers below them, and an import of a command file from
34
+ `src/mcp/`. What a
35
+ command and a service share lives below the command.
36
+ - **Exceptions:** none. A new adapter method goes into a named group in `port.ts`, never into the domain. In Biome, a later
37
+ override that sets `noRestrictedImports` for the same file replaces the earlier one's options, so every block that
38
+ sets the rule carries the complete list for its paths.
39
+ - **Applies to:** all CLIs. Each repository's `biome.json` holds its own import rules. **Since:** cli-base 0.41.0.
40
+ **Rulings:** none.
41
+
42
+ ### WC-ARCH-2 · Dependencies point one way: a CLI depends on cli-core, cli-core on cli-base, never back
43
+
44
+ - **Why:** a shared package that imports an app cannot be shared.
45
+ - **Enforced by:** `cli-core: biome noRestrictedImports`.
46
+ - **Example:** cli-base has no dependency on cli-core or on any CLI. cli-core's `biome.json` refuses an import of a
47
+ messenger library or an adapter directory ("cli-core speaks no provider").
48
+ - **Exceptions:** none.
49
+ - **Applies to:** cli-base, cli-core and all CLIs. **Since:** cli-base 0.41.0. **Rulings:** none.
50
+
51
+ ### WC-ARCH-3 · Only the adapter imports a vendor library; nothing above it sees a vendor type
52
+
53
+ - **Why:** the provider library underneath must be replaceable, and the layers above must not change when it is.
54
+ - **Enforced by:** `max-cli: biome noRestrictedImports` · `tg-cli: biome noRestrictedImports` ·
55
+ `whatsapp-cli: biome noRestrictedImports`.
56
+ - **Example:** in max-cli, `biome.json` lets only `src/client.ts` and `src/client/` reach the protocol, and only
57
+ `src/adapter/` maps the client onto the shared messenger port. A field that only one provider has travels in
58
+ `providerMetadata`.
59
+ - **Exceptions:** a bot slice that talks to an official HTTP API keeps its own transport, beside the personal
60
+ account's adapter, never above it.
61
+ - **Applies to:** all CLIs. **Since:** cli-base 0.41.0. **Rulings:** NEED-12.
62
+
63
+ ### WC-ARCH-4 · Put code in the lowest shared package that can hold it
64
+
65
+ - **Why:** the CLIs keep to one standard by sharing code, not by copying text.
66
+ - **Enforced by:** review only.
67
+ - **Example:**
68
+ - cli-base: general CLI infrastructure that needs no domain knowledge. This includes the streams, the renderer,
69
+ errors and exit codes, the keyring, config and paths, clocks, retry, the command registry and format-neutral code
70
+ generation.
71
+ - cli-core: provider-neutral models, ports and use cases, even when only one CLI uses them today. Meeting discovery
72
+ is in cli-core although Zoom was its first user.
73
+ - The CLI: vendor translation, profile binding, resource lifetimes and rules that only make sense for that product.
74
+ - **Exceptions:** share an invariant or a real capability. Lines that only look alike are not a reason for a new
75
+ shared abstraction.
76
+ - **Applies to:** cli-base, cli-core and all CLIs. **Since:** cli-base 0.41.0. **Rulings:** NEED-292, NEED-440.
77
+
78
+ ### WC-ARCH-5 · Build a feature that another provider could have as a shared command behind a capability
79
+
80
+ - **Why:** a command written once in cli-core gives every messenger the same path, flags and output.
81
+ - **Enforced by:** review only.
82
+ - **Example:** topics and polls are port groups and shared commands in cli-core. A messenger that lacks a capability
83
+ refuses the command; it does not silently do less. A bot is another messenger with fewer capabilities, and tg and
84
+ max share the bot code.
85
+ - **Exceptions:** a feature stays in one CLI only when the other providers cannot have it, such as MAX's socket server
86
+ or Telegram's app registration.
87
+ - **Applies to:** messenger CLIs (tg, max, wa). **Since:** cli-base 0.41.0. **Rulings:** NEED-820, NEED-440,
88
+ NEED-301, NEED-444.
89
+
90
+ ### WC-ARCH-6 · Replace a use case, not a command
91
+
92
+ - **Why:** when a CLI replaces the service method, its command and its MCP tool both get the change.
93
+ - **Enforced by:** review only.
94
+ - **Example:** `Messenger.services` receives the shared services and returns only the ones it changes:
95
+ `services: (base) => ({ messages: { ...base.messages, list: maxList } })`. To add a subcommand, a CLI calls
96
+ `addCommand` on the command a factory returns.
97
+ - **Exceptions:** none.
98
+ - **Applies to:** messenger CLIs. **Since:** cli-base 0.41.0. **Rulings:** none.
99
+
100
+ ### WC-ARCH-7 · Keep policy in the service; a command or MCP handler only parses input and presents the result
101
+
102
+ - **Why:** two transports that each interpret a query or a write policy drift apart.
103
+ - **Enforced by:** review only.
104
+ - **Example:** query interpretation, cursor binding, evidence checks and write policy live in the service. Each
105
+ caller parses its own input, so an error names `--since` in a command and `since` in a tool, but both run the same
106
+ method and give the same error for the same input.
107
+ - **Exceptions:** none.
108
+ - **Applies to:** all CLIs. **Since:** cli-base 0.41.0. **Rulings:** none.
109
+
110
+ ### WC-ARCH-8 · Cross a module boundary only through the module's entry point
111
+
112
+ - **Why:** a deep import ties the caller to another module's internals.
113
+ - **Enforced by:** `cli-core: biome noRestrictedImports` · `cli-memo: biome noRestrictedImports` ·
114
+ `drive-cli: biome noRestrictedImports` · `zoom-cli: biome noRestrictedImports`.
115
+ - **Example:** in cli-core, `src/tasks/` and `src/meetings/` are entered only through their `index.ts`, `cli/`, `mcp/`
116
+ and `testing/` entries; its `biome.json` refuses the rest. memo, drive and zoom have a "public exports only" rule. A
117
+ package's own entry points are its `exports`
118
+ ([WC-LAY-5](layout.md#wc-lay-5--add-an-entry-point-as-an-exports-entry-built-from-srcindexts)).
119
+ - **Exceptions:** a test inside a module may import what it tests; a test outside the module uses the entry point.
120
+ - **Applies to:** all CLIs. tg, max and wa do not have the import rule yet. **Since:** cli-base 0.41.0.
121
+ **Rulings:** none.
122
+
123
+ ### WC-ARCH-9 · Pass the narrow port or callback a use case needs, not a whole store or container
124
+
125
+ - **Why:** a narrow dependency shows what the use case touches and is easy to replace in a test.
126
+ - **Enforced by:** review only.
127
+ - **Example:** a service sees the messenger as `MessengerTraits`, only the fields it reads. The CLI's `Messenger`
128
+ adds how commands connect.
129
+ - **Exceptions:** none. Add a factory, inheritance or a dependency-injection framework only for a concrete benefit.
130
+ - **Applies to:** all CLIs. **Since:** cli-base 0.41.0. **Rulings:** none.
131
+
132
+ ### WC-ARCH-10 · Pass every effect on the machine as an argument, with the real one only as the default
133
+
134
+ - **Why:** a test then replaces the clock, the keyring or the network, and never touches the real machine.
135
+ - **Enforced by:** review only.
136
+ - **Example:** clock, sleep, keyring, `env`, `fetch`, streams, stdin and the TTY check are parameters or fields of the
137
+ command environment. Production code uses `environment.sleep ?? realSleep`. A new effect gets a new field, not a
138
+ module mock.
139
+ - **Exceptions:** none. Watch the defaults: `new Credentials({...})` without `keyring` is the owner's real keychain,
140
+ and `resolvePaths` without `env` reads `process.env`.
141
+ - **Applies to:** all CLIs and the shared packages. **Since:** cli-base 0.41.0. **Rulings:** none.
142
+
143
+ ### WC-ARCH-11 · Keep one command environment per program, cli-core's
144
+
145
+ - **Why:** two registries of the same environment must both be filled on every run, and one is always forgotten.
146
+ - **Enforced by:** review only.
147
+ - **Example:** a CLI extends `BaseEnvironment`, hands it to cli-core's `provide(program, environment)`, and its
148
+ commands read it with `environmentOf<Environment>(command)`, never with `process.*`.
149
+ - **Exceptions:** a CLI that does not use cli-core's command skeleton keeps one environment of its own.
150
+ - **Applies to:** CLIs built on cli-core's command skeleton. **Since:** cli-base 0.41.0. **Rulings:** none.
151
+
152
+ ### WC-ARCH-12 · Merged into [WC-LIFE-6](lifecycle.md#wc-life-6--open-nothing-until-an-action-needs-it)
153
+
154
+ ### WC-ARCH-13 · Merged into [WC-LIFE-1](lifecycle.md#wc-life-1--the-code-that-opens-a-resource-closes-it-so-a-one-shot-command-exits-when-it-has-answered)
155
+
156
+ ### WC-ARCH-14 · Merged into [WC-LIFE-11](lifecycle.md#wc-life-11--run-commands-through-serve-when-the-messenger-allows-one-connection-per-account)
157
+
158
+ ### WC-ARCH-15 · Each CLI runs its own background server, built on cli-core's process library
159
+
160
+ - **Why:** a server shared between CLIs couples their releases and their failures.
161
+ - **Enforced by:** review only.
162
+ - **Example:** cli-core's `./background` export holds the lock per app and profile, the PID check and the systemd and
163
+ launchd units. `tg serve` and `max serve` are each built on it.
164
+ - **Exceptions:** none.
165
+ - **Applies to:** CLIs with a background process. **Since:** cli-base 0.41.0. **Rulings:** NEED-492.
166
+
167
+ ### WC-ARCH-16 · Layers below the commands never name a command
168
+
169
+ - **Why:** an adapter that prints "check `tg polls show`" breaks when the command is renamed and cannot be shared.
170
+ - **Enforced by:** review only.
171
+ - **Example:** a tg adapter error carries a typed reason, such as `{ check: "polls.show" }`. The command layer turns
172
+ the reason into the words `tg polls show`.
173
+ - **Exceptions:** none.
174
+ - **Applies to:** all CLIs. **Since:** cli-base 0.41.0. **Rulings:** none.
175
+
176
+ ### WC-ARCH-17 · Merged into [WC-LAY-8](layout.md#wc-lay-8--give-each-module-one-reason-to-change)
177
+
178
+ ### WC-ARCH-18 · An optional capability that is missing fails out loud
179
+
180
+ - **Why:** a request that quietly becomes a smaller one gives the caller a wrong answer that looks right.
181
+ - **Enforced by:** review only.
182
+ - **Example:** a new adapter method is optional and reached with `capability()`. When it is absent, the command
183
+ refuses with a reason; it does not drop the filter or the scope it could not apply.
184
+ - **Exceptions:** none.
185
+ - **Applies to:** all CLIs. **Since:** cli-base 0.41.0. **Rulings:** NEED-820.
186
+
187
+ ### WC-ARCH-19 · Shared packages print nothing and log nothing on their own
188
+
189
+ - **Why:** what is written, and where, is the host's decision; a stray line breaks machine output.
190
+ - **Enforced by:** review only.
191
+ - **Example:** cli-base hands the host a `Logger` interface, a Pino adapter and a renderer. It never calls
192
+ `console.log`, nor `console.error`, which the lint allows elsewhere
193
+ ([WC-TOOL-9](toolchain.md#wc-tool-9--write-to-the-console-only-with-consoleerror-except-in-scripts)).
194
+ - **Exceptions:** none.
195
+ - **Applies to:** cli-base and cli-core. **Since:** cli-base 0.41.0. **Rulings:** none.
196
+
197
+ ### WC-ARCH-20 · Keep HTTP out of cli-base's root export
198
+
199
+ - **Why:** a CLI that only speaks a socket must not depend on an HTTP stack.
200
+ - **Enforced by:** review only.
201
+ - **Example:** a helper that reads a status code or a header goes to `@wirecat/cli-base/http`. How an entry point
202
+ is added is [WC-LAY-5](layout.md#wc-lay-5--add-an-entry-point-as-an-exports-entry-built-from-srcindexts).
203
+ - **Exceptions:** none.
204
+ - **Applies to:** cli-base. **Since:** cli-base 0.41.0. **Rulings:** NEED-15.
205
+
206
+ ## Sources
207
+
208
+ These documents explain the rules on this page in more detail. Where one of them disagrees with this page, this page
209
+ holds.
210
+
211
+ - [cli-base `MODULARITY.md`](https://github.com/WireCatLabs/cli-base/blob/main/docs/dev/MODULARITY.md)
212
+ - [cli-base `ARCHITECTURE.md`](https://github.com/WireCatLabs/cli-base/blob/main/docs/dev/ARCHITECTURE.md)
213
+ - [cli-core `ARCHITECTURE.md`](https://github.com/WireCatLabs/cli-core/blob/main/docs/dev/ARCHITECTURE.md)
214
+ - [cli-core `ADAPTERS.md`](https://github.com/WireCatLabs/cli-core/blob/main/docs/dev/ADAPTERS.md)
@@ -0,0 +1,159 @@
1
+ # CI
2
+
3
+ ## Scope
4
+
5
+ What runs where: the local hooks, the checks on every pull request and their time budget, full validation on each
6
+ merge to `main`, and the monthly runs.
7
+
8
+ Rule ids on this page are `WC-CI-<n>`. How to read a rule, how ids work and which rule wins are in the
9
+ [index](README.md). What each tool checks is on the [Toolchain page](toolchain.md); the release workflow is on the
10
+ [Releases page](releases.md); which scanners must exist and how workflows are hardened is on the
11
+ [Security page](security.md).
12
+
13
+ "The ten repositories" on this page means the six CLIs (tg, max, memo, drive, zoom, wa), cli-base, cli-core,
14
+ cli-testing, cli-docs, plus community itself.
15
+
16
+ ## Rules
17
+
18
+ ### WC-CI-1 · Run only staged lint and a staged secret scan before a commit
19
+
20
+ - **Why:** a hook that takes more than a second makes people skip it, which is worse than a small hook.
21
+ - **Enforced by:** `pnpm standards:check` · `standards.yml:standards`.
22
+ - **Example:** the shared `lefthook` config runs, in parallel, Biome on the staged files and
23
+ `gitleaks git --staged --redact`. A clone without gitleaks gets a warning and can still commit; CI scans anyway.
24
+ The `prepare` script installs the hooks; `LEFTHOOK=0 git commit` skips them for one commit.
25
+ - **Exceptions:** none.
26
+ - **Applies to:** the ten repositories. **Since:** cli-base 0.41.0. **Rulings:** none.
27
+
28
+ ### WC-CI-2 · Add no push hook, and no hook that installs, builds, checks types, generates or tests
29
+
30
+ - **Why:** every check in a hook runs again in CI, so a slow hook only costs time and teaches people to bypass hooks.
31
+ - **Enforced by:** review only.
32
+ - **Example:** a repository's `lefthook.yml` holds only the `extends` line for `config/wirecat/lefthook.yml`. An agent
33
+ does not run `standards:check`, the full lint, spelling, a build or the test suite on each commit or push; it runs a
34
+ targeted check when it needs one.
35
+ - **Exceptions:** none. cli-base `config/lefthook.yml` still has a pre-push typecheck, but no repository extends it.
36
+ - **Applies to:** the ten repositories. **Since:** cli-base 0.41.0. **Rulings:** none.
37
+
38
+ ### WC-CI-3 · Run the fast standards job on every pull request and every push to `main`
39
+
40
+ - **Why:** it catches broken presets, lint, Markdown, types and new secrets in well under a minute, before review.
41
+ - **Enforced by:** `standards.yml:standards`.
42
+ - **Example:** the job does one cached install with lifecycle scripts off, then runs `pnpm standards:check`,
43
+ `pnpm lint`, `pnpm docs:lint`, `pnpm run --if-present ci:quick` and a gitleaks scan of the new commits only. A new
44
+ commit cancels the run it replaces. The job times out after five minutes, a ceiling for a stalled setup, not an
45
+ expected time.
46
+ - **Exceptions:** none. Runner queues and cold downloads are outside the budget.
47
+ - **Applies to:** the ten repositories. **Since:** cli-base 0.41.0. **Rulings:** none.
48
+
49
+ ### WC-CI-4 · Keep `ci:quick` to early bug checks that finish within two minutes
50
+
51
+ - **Why:** it is the only build-level check on a pull request, so it must stay fast enough that nobody wants it gone.
52
+ - **Enforced by:** `standards.yml:standards` · `pnpm ci:quick`.
53
+ - **Example:** what each repository runs today:
54
+ - tg, max, memo and wa: `pnpm typecheck && pnpm build && pnpm lint:commands`;
55
+ - drive: `pnpm typecheck && pnpm lint:commands`, which builds first;
56
+ - zoom, cli-base and cli-testing: `pnpm typecheck`;
57
+ - cli-core: `pnpm typecheck` and its command lint test;
58
+ - cli-docs: its unit tests, without the one that needs generated pages;
59
+ - community: its script tests.
60
+ - **Exceptions:** never put live-account suites, agent suites, full tests, coverage or platform jobs here.
61
+ - **Applies to:** the ten repositories. **Since:** cli-base 0.41.0. **Rulings:** none.
62
+
63
+ ### WC-CI-5 · Keep full tests, builds of documents, parity and platform suites out of pull request CI
64
+
65
+ - **Why:** pull request CI is the step people wait on; the heavy suites run once on `main`, where a failure still
66
+ shows within minutes of the merge.
67
+ - **Enforced by:** review only.
68
+ - **Example:** on a pull request, only the standards job, the changelog guard and small path-scoped jobs run. Coverage,
69
+ contracts, the test matrix, `docs:check`, parity, Windows and macOS run in full validation (WC-CI-7).
70
+ - **Exceptions:** a path-scoped job that tests one platform-specific file may run on pull requests, such as cli-base
71
+ `macos.yml` for the path code. cli-docs and community run `security-pr.yml`, a new-commit secret scan. Third-party
72
+ security apps may post their own checks.
73
+ - **Applies to:** the ten repositories. **Since:** cli-base 0.41.0. **Rulings:** none.
74
+
75
+ ### WC-CI-6 · Run the changelog guard on every pull request
76
+
77
+ - **Why:** the guard is the only check that reads the changelog on a pull request.
78
+ - **Enforced by:** `changelog-guard.yml:guard`.
79
+ - **Example:** each repository's `changelog-guard.yml` calls
80
+ `WireCatLabs/cli-base/.github/workflows/changelog-guard.yml` at a pinned commit, on `opened`, `edited`,
81
+ `synchronize` and `reopened`. The changelog rules it applies are on the [Documents page](docs.md).
82
+ - **Exceptions:** cli-testing, cli-docs and community have no changelog guard yet.
83
+ - **Applies to:** the CLIs, cli-base and cli-core. **Since:** cli-base 0.41.0. **Rulings:** none.
84
+
85
+ ### WC-CI-7 · Run full validation once on each merge to `main`, on Linux, without publishing
86
+
87
+ - **Why:** a merge that breaks the full suite shows up the same hour, not at the next release.
88
+ - **Enforced by:** `main.yml:validation` · `node-ci.yml:check` · `node-ci.yml:bun` · `node-ci.yml:secrets`.
89
+ - **Example:** `main.yml` calls the repository's own `ci.yml`, which calls cli-base `node-ci.yml`. That runs
90
+ `pnpm lint`, `pnpm typecheck`, `pnpm test:coverage`, `pnpm build`, then the project's `checks` lines (for max:
91
+ contracts, the no-leak scan, the version check, `pnpm generate` and `git diff --exit-code`, the test matrix,
92
+ `docs:check` and parity), a Bun job, and a gitleaks scan of the whole history.
93
+ - **Exceptions:** platform suites (Windows, macOS, install checks) are skipped here and run at release, monthly or on
94
+ request. Nothing in this run publishes or tags. cli-docs runs its full validation before each deployment and monthly
95
+ instead; community has no build to validate.
96
+ - **Applies to:** the CLIs, cli-base, cli-core and cli-testing. **Since:** cli-base 0.41.0. **Rulings:** none.
97
+
98
+ ### WC-CI-8 · Call cli-base `node-ci.yml` from `ci.yml`, pinned to a tag or commit
99
+
100
+ - **Why:** one shared workflow keeps the full suite the same everywhere, and a pin keeps a cli-base change from
101
+ breaking ten repositories at once.
102
+ - **Enforced by:** `ci.yml:ci`.
103
+ - **Example:** `uses: WireCatLabs/cli-base/.github/workflows/node-ci.yml@<commit> # v0.31.0`, with the project's own
104
+ checks in the `checks` input and `bun-run` for the Bun job. A job that only one repository needs stays beside it in
105
+ that repository's `ci.yml`.
106
+ - **Exceptions:** never pin to `main`. cli-base itself calls `./.github/workflows/node-ci.yml`. cli-docs has its own
107
+ full workflow for the site, and community has none.
108
+ - **Applies to:** the CLIs, cli-core and cli-testing. **Since:** cli-base 0.41.0. **Rulings:** none.
109
+
110
+ ### WC-CI-9 · Run full validation and release security on the first day of each month, without publishing
111
+
112
+ - **Why:** a repository with no merges for weeks still meets new advisories, new runner images and expired pins.
113
+ - **Enforced by:** `monthly.yml:validation` · `monthly.yml:security`.
114
+ - **Example:** `monthly.yml`, from the community template, calls the repository's `ci.yml` and the pinned cli-base
115
+ `release-checks.yml`. Each repository has its own minute, between 02:17 and 03:21 UTC, so runs do not overlap.
116
+ - **Exceptions:** community has no build, so it runs only the release security checks, at 03:47 UTC. A monthly run
117
+ never publishes a package or deploys the site.
118
+ - **Applies to:** the ten repositories. **Since:** cli-base 0.41.0. **Rulings:** none.
119
+
120
+ ### WC-CI-10 · Run heavy security checks only at release, monthly or on request
121
+
122
+ - **Why:** a pull request needs a fast secret check; source scanners take minutes and find nothing new on most
123
+ changes.
124
+ - **Enforced by:** `release.yml:checks` · `monthly.yml:security`.
125
+ - **Example:** cli-base `release-checks.yml` runs the production dependency audit, the workflow scan (`zizmor`),
126
+ CodeQL and a full-history gitleaks scan. A release depends on it. A pull request runs only the new-commit gitleaks
127
+ scan in the standards job.
128
+ - **Exceptions:** none. Do not add a heavy scanner to an editor hook, a stop hook or an ordinary pull request job.
129
+ - **Applies to:** the ten repositories. **Since:** cli-base 0.41.0. **Rulings:** sc:9.
130
+
131
+ ### WC-CI-11 · Moved to [WC-SECR-20](security.md#wc-secr-20--pin-each-third-party-action-to-a-commit-and-give-each-workflow-read-only-defaults)
132
+
133
+ ### WC-CI-12 · Merge to `main` only through a pull request whose checks all passed
134
+
135
+ - **Why:** a red merge breaks `main` for every parallel branch, and an admin merge skips the only gate there is.
136
+ - **Enforced by:** review only.
137
+ - **Example:** `gh pr checks <number>` shows every line as pass before `gh pr merge`. Never merge with `--admin`. A
138
+ release changes `main` the same way
139
+ ([WC-REL-2](releases.md#wc-rel-2--main-changes-only-through-a-pull-request-also-during-a-release)).
140
+ - **Exceptions:** none.
141
+ - **Applies to:** the ten repositories. **Since:** cli-base 0.41.0. **Rulings:** NEED-381.
142
+
143
+ ### WC-CI-13 · Start no live messenger or account test from a workflow
144
+
145
+ - **Why:** a live test acts on a real account; only a person who chose to run it may start it.
146
+ - **Enforced by:** review only.
147
+ - **Example:** the offline contracts run in full validation. The live scenarios run only by hand, through the CLI's
148
+ live-test procedure, on test accounts.
149
+ - **Exceptions:** none.
150
+ - **Applies to:** all CLIs. **Since:** cli-base 0.41.0. **Rulings:** none.
151
+
152
+ ## Sources
153
+
154
+ These documents explain the rules on this page in more detail. Where one of them disagrees with this page, this page
155
+ holds. The procedures stay in their own homes.
156
+
157
+ - [community check schedule](https://github.com/WireCatLabs/community/blob/main/standards/CHECKS.md): the rough timings
158
+ - [cli-testing CI folder](https://github.com/WireCatLabs/cli-testing/tree/main/docs/ci): the cross-project timing
159
+ table, the monthly runbook and the contract runner