@wairon/cli 5.1.1-dev.107 → 5.1.1-dev.108

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.
@@ -110,7 +110,7 @@ schemas:
110
110
  - **Libraries are called directly**: another project's `InProcess` Portal (a crate, a package, a jar, an FFI/DLL surface) is called from ANY component — `alias::portal` in `dependsOn`, `alias::portal.verb` in a call step — with no client Adapter. Pure logic may call only library verbs declared `effect: none`, read logic also `effect: read` (`LIBRARY_CALL_IMPURE`); a native library (no `abi`) called from another `targetLanguage` needs `abi: c` or `abi: wasm` (`LANGUAGE_BRIDGE_MISSING`). Wrapping a volatile third-party API in your own Adapter is a good habit, not a rule. Within one project a sibling subsystem is still reached through a client Adapter or a `trustedLink`.
111
111
  - **Transport and naming**: name a Portal for what it serves, not its wire (`order_portal`, not `http_handler`); the `transport` says the wire. Method names follow the project's method casing — camelCase for TypeScript and Java, snake_case for Rust and Python, from `targetLanguage` unless `rules.naming` says otherwise — and a wire name that differs (an HTTP path, a CLI command like `lock-check`, a JSON-RPC method like `tools/call`) lives on the method's `endpoint`, never in the method name.
112
112
  - **trustedLinks (L1)**: `{ subsystem, reason }` — declared on the SOURCE subsystem, it licenses a direct in-process edge into the named sibling **without the client-Adapter shim** (the deliberate fast lane). The target must still be in the sibling's `publicInterfaces` (its published Portal); a target-side declaration grants nothing. It also acknowledges a mutual-dependency pair.
113
- - **Declare planned code at design time**: give each implementation the `sourcePath` its code will live at (and a method its own `sourcePath` when its body lives elsewhere). Code linkage — `sourcePath`, `symbol`, `exportedVia`, `simPath`, `injectedParams`, conformance tiers — is not part of the approval, so declaring or changing it never asks for a re-lock. A file not written yet is `SOURCE_FILE_PLANNED` (a notice, never a `--ci` failure) until the component's realization begins; never strip a planned path to quiet anything. A team that wants CI to demand code for every designed implementation sets `rules.conformance.requireCode: true`.
113
+ - **Declare planned code at design time**: give each implementation the `sourcePath` its code will live at (and a method its own `sourcePath` when its body lives elsewhere) — and each TYPE the `sourcePath` of the file that will declare it (with `symbol` when the code name differs): a type without one is never compared with the code's shape, which is `MISSING_TYPE_SOURCE_PATH` (a notice while its subsystem has no code, a warning once it has). Code linkage — `sourcePath`, `symbol`, `exportedVia`, `simPath`, `injectedParams`, conformance tiers — is not part of the approval, so declaring or changing it never asks for a re-lock. A file not written yet is `SOURCE_FILE_PLANNED` (a notice, never a `--ci` failure) until the component's realization begins; never strip a planned path to quiet anything. A team that wants CI to demand code for every designed implementation sets `rules.conformance.requireCode: true`.
114
114
  - **Externals — the pin gates, live drift is visible**: declare a project this one consumes with `sdd_add_external` (alias; source `../sibling`, `hosted:<id>`, `<git url>` or `<git url>#<commit>`; optional `project`, `use`, `description`) instead of editing `.wai/project.yaml`. It refuses in one sentence what cannot be declared, takes the declaration back out when the producer contradicts it (another id, an unexported `use` name), and pins it by default. The owner's gate judges each external against its pin; `sdd_validate_tree` and `sdd_get_status` add ADVISORY live-drift findings (`EXTERNAL_LIVE_INCOMPATIBLE`, `EXTERNAL_DRIFTED`, `EXTERNAL_LIVE_UNCOMPARED`) that never make the tree invalid — adapt the uses, then the human re-pins. `wairon externals status` is the human's opt-in live gate.
115
115
  - **Growing a system — subsystems → parts → projects**: boundaries are earned. Keep subsystems in one folder until a piece needs its own folder or repository; then make it a **part** — `members: { scheduler: services/scheduler }` (or `../admin`, or `git-url#<commit>`), created by `sdd_add_member` (a part by default) or `sdd_externalize_subsystem`. A part's subsystems stay this project's own: local ids, the ordinary subsystem rules, this project's lock. Make a **project** — its own id, exports and lock, referenced as `alias::name` — only when it needs its own team, release, approval or public surface: `sdd_promote_member`, and `sdd_demote_member` to undo it. What a member is follows from its content (an id, an L0 or a lock); `as:` only asserts it.
116
116
  - **Members & the family's shape**: relocate a member with `sdd_move_member`. Every other change of a family's shape is a **family migration**: `sdd_attach_member` (an existing project becomes a member), `sdd_detach_member` / `sdd_adopt_member` (out of the family and back), `sdd_rename_project`, `sdd_rename_member_alias`, `sdd_internalize_member` (a member folded back in, its metadata sent to explicit homes) and `sdd_externalize_subsystem`. Call it with `dryRun: true` first and show the human the plan; applied, it writes every project it touches or none, and it never locks — it names the projects to re-lock.
@@ -71,7 +71,7 @@ to the artifacts the host AI tool consumes:
71
71
  (`runWithProjectRoot`) — reusing the core, validation, and MCP layers unchanged.
72
72
  - **Everything is file-based** under `.wai/` — no database, and no daemon for the
73
73
  core workflow. `wairon serve` is an **opt-in** hosting daemon (see the
74
- [hosted server guide](design/hosted-mcp-server.md)) that serves the same
74
+ [hosted server guide](https://github.com/SYW-Apps/Waffle-AIron/blob/main/docs/design/hosted-mcp-server.md)) that serves the same
75
75
  file-based tools over HTTP.
76
76
 
77
77
  ---
package/docs/cli.md CHANGED
@@ -74,8 +74,11 @@ warnings as errors (notices are printed and counted, never fatal).
74
74
  **family root** (the project that declares the members). A member validated on
75
75
  its own judges its own gate with its `network` entries counted as declared, and
76
76
  says so in one line, so a green member run is never read as a proven one.
77
- **In CI, run `wairon validate --ci` at the family root**; a member in its own
78
- repository adds the root's run to its pipeline or relies on the root
77
+ **In CI, run `wairon validate --ci` at the family root**, after installing
78
+ the project's dependencies (`npm ci` or your package manager's equivalent —
79
+ the gate reads TypeScript/JavaScript code with the project's own TypeScript;
80
+ see [Using it in GitHub Actions](#using-it-in-github-actions)); a member in
81
+ its own repository adds the root's run to its pipeline or relies on the root
79
82
  repository's.
80
83
  - **Externals, compared live (advisory: the pin gates).** The gate judges each
81
84
  external against its pin. Then every external the run did not compose is
@@ -97,6 +100,9 @@ warnings as errors (notices are printed and counted, never fatal).
97
100
  `METHOD_SOURCE_PATH_MISSING` (warning). `rules.conformance.requireCode: true`
98
101
  in `project.yaml` reports the two notices as errors, for a CI that must say
99
102
  every designed implementation has code.
103
+ - **Types are linked to code too.** A type spec without a `sourcePath` is
104
+ `MISSING_TYPE_SOURCE_PATH` — a notice before its subsystem has code, a
105
+ warning after. Plan a type's `sourcePath` when you plan the implementations'.
100
106
  - **What the closing line says.** Plain `validate` passes with warnings and
101
107
  says so — `Passed with N warning(s)` (`--ci` fails on them); `All checks
102
108
  passed` means none. A tree holding no design yet (no L0, or an L0 with nothing
@@ -112,14 +118,40 @@ warnings as errors (notices are printed and counted, never fatal).
112
118
  `UNDECLARED_DEPENDENCY`; a Portal calling a write- or lifecycle-effect method
113
119
  of a Repository, Index, Store or Registry that way is
114
120
  `PORTAL_WRITE_SHORTCUT_IN_CODE` (error, the code twin of
115
- `PORTAL_WRITE_SHORTCUT`); and a file importing a technology's package — a
116
- package named by one of the technology's declared tokens (its name, or its
117
- `matches`), never a guessed vendor list — outside the components that bind it
118
- is `TECH_LEAKAGE_IN_CODE`. An Adapter's call step to a verb of a Portal that
119
- declares an out-of-process transport (HTTP, gRPC, a database, a bus, a CLI…)
120
- is the link the design models: it is never resolved to the remote Portal's
121
- file, so it never reads as `CALL_ORIGIN_UNRESOLVED`; the call to the Adapter
122
- stays checked.
121
+ `PORTAL_WRITE_SHORTCUT`); and a file importing a technology's package
122
+ outside the components that bind it is `TECH_LEAKAGE_IN_CODE`. A technology's
123
+ packages are its declared tokens (its name, or its `matches`) plus the common
124
+ packages wairon knows for it — see [Technologies and their
125
+ packages](#technologies-and-their-packages). An Adapter's call step to a verb
126
+ of a Portal that declares an out-of-process transport (HTTP, gRPC, a
127
+ database, a bus, a CLI…) is the link the design models: it is never resolved
128
+ to the remote Portal's file, so it never reads as `CALL_ORIGIN_UNRESOLVED`;
129
+ the call to the Adapter stays checked. Likewise the Adapter's `dependsOn` to
130
+ that Portal is realized by the link, never reported `UNREALIZED_DEPENDENCY`:
131
+ never add an import across a network boundary to satisfy a check.
132
+
133
+ #### Technologies and their packages
134
+
135
+ `TECH_LEAKAGE_IN_CODE` compares each import's package with the packages of the
136
+ technologies an implementation binds. A design writes the technology the way
137
+ people say it (`postgres`) while the code imports its driver (`pg`), so wairon
138
+ knows the common packages of the common technologies by default:
139
+
140
+ | Technology (any of these names) | Packages |
141
+ | --- | --- |
142
+ | `postgres`, `postgresql`, `pg` | `pg`, `postgres`, `pg-promise`, `@neondatabase/serverless`, `@vercel/postgres` |
143
+ | `mysql`, `mariadb` | `mysql2`, `mysql`, `mariadb` |
144
+ | `redis`, `valkey` | `redis`, `ioredis`, `@redis/client` |
145
+ | `mongodb`, `mongo` | `mongodb`, `mongoose` |
146
+ | `sqlite`, `sqlite3` | `better-sqlite3`, `sqlite3`, `sqlite` |
147
+ | `kafka` | `kafkajs`, `node-rdkafka` |
148
+ | `rabbitmq`, `amqp` | `amqplib`, `amqp-connection-manager` |
149
+
150
+ An HTTP client (`fetch`, `axios`, `got`, `undici`) is never a technology — it is
151
+ how an Adapter reaches anything — so no entry names one. To extend the list,
152
+ write the technology as `{ name, matches }` (each `matches` token is a package
153
+ too), or have a pack contribute `technologyPackages: { <technology>: [<package>,
154
+ …] }`.
123
155
 
124
156
  ### `wairon generate [--target <name>] [--domain <id>] [--domains <ids>] [--root] [--family] [--no-prune] [--global] [--dry-run]`
125
157
  Reconcile the generated guides, skills and context, and — only when the project
@@ -299,9 +331,12 @@ merging is the thing that was reviewed.
299
331
 
300
332
  #### Using it in GitHub Actions
301
333
 
302
- This repository publishes it as a **reusable workflow** (from v6.0.0 — the
303
- workflow and the `lock-check` command do not exist in earlier releases). Add one
304
- job to your own workflow:
334
+ This repository publishes it as a **reusable workflow**. **6.0.0 is the first
335
+ release that ships the workflow and the `lock-check` command** — earlier releases
336
+ have neither, and no `v6.0.0` tag exists before that release. On a dev build (and
337
+ until 6.0.0 is out), pin the dev tag matching `wairon --version` instead: a CLI
338
+ reporting `5.1.1-dev.107` pins `@v5.1.1-dev.107` with `wairon-version:
339
+ '5.1.1-dev.107'`. Add one job to your own workflow:
305
340
 
306
341
  ```yaml
307
342
  # .github/workflows/ci.yml in YOUR repository
@@ -325,6 +360,7 @@ With inputs (all optional):
325
360
  wairon-version: '6.0.0' # version or npm dist-tag, 6.0.0 or later (default: latest)
326
361
  strict: true # fail when nothing was approved — use it once you have locked (default: false)
327
362
  validate: true # also run `wairon validate --ci` there (default: true)
363
+ install: auto # the project's dependencies before validate: auto | none | <command> (default: auto)
328
364
  node-version: '20' # (default: '20')
329
365
  runs-on: ubuntu-latest # (default: ubuntu-latest)
330
366
  ```
@@ -343,6 +379,44 @@ directory (`validate: false` turns it off). Point `working-directory` at the
343
379
  **family root** — the project that declares the members — so that run is the
344
380
  family run, which judges the network proofs no member's own gate can.
345
381
 
382
+ **The project's dependencies come first.** The conformance gate reads
383
+ TypeScript/JavaScript code with the project's own TypeScript compiler. A fresh
384
+ checkout has none until the project's dependencies are installed, and then every
385
+ file is analyzed below exact grade and `--ci` fails on `CONFORMANCE_DEGRADED` —
386
+ a finding about the runner, not your design. So before `validate --ci` the job
387
+ installs them with the project's own package manager (`install: auto`, the
388
+ default): nothing without a `package.json`; otherwise the nearest lockfile from
389
+ `working-directory` up to the repository root decides — `package-lock.json` →
390
+ `npm ci`, `pnpm-lock.yaml` → `pnpm install --frozen-lockfile`, `yarn.lock` →
391
+ `yarn install` (`--immutable`, or `--frozen-lockfile` for Yarn 1). `install:
392
+ none` skips it; any other value is run as the install command. The approval
393
+ check alone (`validate: false`) installs nothing.
394
+
395
+ #### Without the reusable workflow
396
+
397
+ The same gate as plain steps — for another CI system, or a job of your own. For
398
+ a TypeScript/JavaScript project with code, **install the project's dependencies
399
+ before `wairon validate --ci`** (`npm ci`, `pnpm install --frozen-lockfile` or
400
+ `yarn install --immutable`, whichever your lockfile is for):
401
+
402
+ ```yaml
403
+ # .github/workflows/design.yml in YOUR repository
404
+ on: [pull_request]
405
+
406
+ jobs:
407
+ design:
408
+ runs-on: ubuntu-latest
409
+ steps:
410
+ - uses: actions/checkout@v4
411
+ - uses: actions/setup-node@v4
412
+ with:
413
+ node-version: '20'
414
+ - run: npm install --global @wairon/cli@6.0.0 # the version you lock with
415
+ - run: wairon lock-check --strict
416
+ - run: npm ci # the project's dependencies: the gate reads your code with your TypeScript
417
+ - run: wairon validate --ci
418
+ ```
419
+
346
420
  **A failing job does not block a merge on its own.** A workflow can only fail;
347
421
  making a failing job stop a merge is a branch-protection / ruleset setting on
348
422
  your repository ("Require status checks to pass" → add this job). No workflow
@@ -597,6 +671,20 @@ field that does not exist, a name that is not an identifier, and a name another
597
671
  field of the type holds or retired. The MCP twin is `sdd_rename_field`. As with
598
672
  any design edit, the next `wairon lock` approves it.
599
673
 
674
+ ### `wairon method rename-param <component> <method> <param> <new-name>`
675
+ Renames a parameter of a contract method. The parameter moves on every
676
+ interface of the component that declares the method, keeping its place, type,
677
+ description and optionality; its old name joins the parameter's rename trace
678
+ (`previousNames`), which `wairon export` shows as `formerly`, so a generator or
679
+ consumer reads a rename, not a signature change. Each signature is re-derived
680
+ from the params (a method whose `signatureFrom` names this one follows by
681
+ itself), and an HTTP endpoint path placeholder `{old}` on the method's own
682
+ binding is respelled — the URL a caller sends is unchanged. Prose is never
683
+ rewritten. It refuses, writing nothing, a component, method or parameter that
684
+ does not exist (or a parameter the method takes from a `signatureFrom`), a name
685
+ that is not an identifier, and a name another parameter of the method holds or
686
+ retired. The MCP twin is `sdd_rename_param`. The next `wairon lock` approves it.
687
+
600
688
  ### `wairon network flows|policy|diagram|check|why|declare|undeclare`
601
689
  Networking derived from the design: the reach the validator already models
602
690
  (modelled calls, Portal entries and their scopes, declared networks and their
@@ -767,7 +855,13 @@ included); applying it stages every change with a backup under each project's
767
855
  `.wai/transactions/<id>/` (never committed) and swaps them in, restoring every
768
856
  backup on any failure. A crash mid-swap leaves a journal: `wairon status` and
769
857
  `wairon validate` show it as a notice, and `wairon doctor --fix` rolls it back.
770
- No verb ever locks — each names the projects to re-lock. A member stored in a
858
+ No verb ever locks — each names the projects to re-lock. A promote (or `externalize --as project`) re-roots every
859
+ source path that moves with the new project: a path inside the new project's folder becomes
860
+ member-relative, and one outside it (source code you have not moved yet) becomes a member-relative
861
+ *planned* path — `SOURCE_FILE_PLANNED`, never a path that escapes the root — so the new project
862
+ validates on day one and you move the code when you are ready. A topic finding
863
+ (`UNCONSUMED_TOPIC`, `UNSOURCED_SUBSCRIPTION`) is sited at its topic: an allow names it
864
+ with `at: <topic>`. A member stored in a
771
865
  `../` sibling checkout on the same volume joins the same transaction: its files
772
866
  change all-or-nothing with the family's, the coordinator's journal names every
773
867
  owner (so `wairon doctor --fix` recovers from either root), and the plan says
@@ -841,21 +935,23 @@ project, so it holds nothing machine-specific: it runs `wairon mcp serve` from t
841
935
  and the server attaches to the project it is started in. A `--global` registration is
842
936
  machine-wide and names the running CLI by its absolute path.
843
937
 
844
- The local server offers 38 tools:
938
+ The local server offers 47 tools:
845
939
 
846
940
  | Group | Tools |
847
941
  |-------|-------|
848
942
  | Topology (read) | `listAgents`, `getAgent`, `listDomains`, `validateTopology`, `getProjectConfig` |
849
943
  | Authoring | `sdd_initialize_system`, `sdd_add_subsystem`, `sdd_set_public_interfaces`, `sdd_add_component`, `sdd_define_interface`, `sdd_set_endpoints`, `sdd_write_narrative`, `sdd_add_type`, `sdd_update_spec`, `sdd_delete_spec` |
850
944
  | Reading and checking | `sdd_get_spec`, `sdd_get_status`, `sdd_validate_tree` |
851
- | Renames and moves (in this tree) | `sdd_rename_component`, `sdd_rename_method`, `sdd_rename_type`, `sdd_move_methods` |
945
+ | Renames and moves (in this tree) | `sdd_rename_component`, `sdd_rename_method`, `sdd_rename_param`, `sdd_rename_type`, `sdd_rename_field`, `sdd_move_methods` |
852
946
  | Members and family migrations (each takes `dryRun`) | `sdd_add_member`, `sdd_move_member`, `sdd_externalize_subsystem`, `sdd_promote_member`, `sdd_demote_member`, `sdd_internalize_member`, `sdd_attach_member`, `sdd_detach_member`, `sdd_adopt_member`, `sdd_rename_project`, `sdd_rename_member_alias` |
853
947
  | Externals | `sdd_add_external`, `sdd_update_external`, `sdd_remove_external`, `sdd_pin_externals`, `sdd_get_externals_status` |
948
+ | Public surface (the producer's side) | `sdd_list_consumers`, `sdd_surface_diff` |
949
+ | Network | `sdd_set_network`, `sdd_get_network_flows`, `sdd_explain_flow` |
854
950
  | Packs | `sdd_pack_impact` |
855
951
  | Delegation | `sdd_get_agent_brief` (the live brief for one agent; also served as the `wairon-agent://` resource) |
856
952
 
857
953
  A hosted server adds its own `sdd_host_*` and `sdd_landscape_*` tools; see the
858
- [hosted server guide](design/hosted-mcp-server.md).
954
+ [hosted server guide](https://github.com/SYW-Apps/Waffle-AIron/blob/main/docs/design/hosted-mcp-server.md).
859
955
 
860
956
  ---
861
957
 
@@ -865,7 +961,7 @@ A hosted server adds its own `sdd_host_*` and `sdd_landscape_*` tools; see the
865
961
  projects behind one endpoint — a public **data plane** (the `sdd_*` tools over
866
962
  streamable HTTP, per-project API-key scoped) and an admin **control plane**
867
963
  (project & key lifecycle, state-scoped lock). See the
868
- [hosted server guide](design/hosted-mcp-server.md) for the architecture, Docker
964
+ [hosted server guide](https://github.com/SYW-Apps/Waffle-AIron/blob/main/docs/design/hosted-mcp-server.md) for the architecture, Docker
869
965
  self-hosting, auth, and sizing.
870
966
 
871
967
  ### `wairon serve [--host <h>] [--port <p>] [--admin-host <h>] [--admin-port <p>] [--data-dir <path>] [--no-auth]`
@@ -9,7 +9,7 @@ rules) that wairon reads and imports. A product built this way (a
9
9
  wairon installation: no fork, no build step, and wairon core never learns
10
10
  the platform exists.
11
11
 
12
- A working wrapper lives at [`examples/wrapper/`](../examples/wrapper/) and
12
+ A working wrapper lives at [`examples/wrapper/`](https://github.com/SYW-Apps/Waffle-AIron/blob/main/examples/wrapper/) and
13
13
  is guarded by `tests/examples/wrapper-example.test.ts`, so it cannot
14
14
  silently rot.
15
15
 
@@ -17,7 +17,7 @@ silently rot.
17
17
 
18
18
  > **New model (preferred).** Installing a pack makes it *available*; a project
19
19
  > then *selects* it. Installing no longer grants a pack authority over every
20
- > project on the machine — see [pack scoping](design/pack-scoping.md).
20
+ > project on the machine — see [pack scoping](https://github.com/SYW-Apps/Waffle-AIron/blob/main/docs/design/pack-scoping.md).
21
21
 
22
22
  ```sh
23
23
  wairon pack install ./appenser-1.2.0.wpack # into this wairon install's store
@@ -101,6 +101,7 @@ project's doctrine anywhere:
101
101
  - uses: SYW-Apps/Waffle-AIron/.github/actions/setup-wairon@v5
102
102
  with:
103
103
  packs: sync # sync (default) | none (bundled repos) | explicit sources
104
+ - run: npm ci # a TS/JS project with code: its own dependencies first (see docs/cli.md)
104
105
  - run: wairon validate --ci
105
106
  ```
106
107
 
@@ -267,7 +268,7 @@ wairon pack add ./my-product-pack --global # machine-wide
267
268
 
268
269
  The installer injects once and leaves — from then on plain `wairon
269
270
  validate` enforces the doctrine, and `wairon pack remove` undoes it. See
270
- [`examples/wrapper/install.js`](../examples/wrapper/install.js) for the
271
+ [`examples/wrapper/install.js`](https://github.com/SYW-Apps/Waffle-AIron/blob/main/examples/wrapper/install.js) for the
271
272
  template. A spec-only product (implementation lives on a cloud platform)
272
273
  needs nothing more: the wrapped repository holds specs + docs, wairon holds
273
274
  the gate.
@@ -595,7 +596,7 @@ project's externals against their live producers, and the family checks),
595
596
  `globalPacksDir`, `discoverPacks`, `setProjectRoot`, the `SddRule` /
596
597
  `RuleContext` / `LoadedExtensions` / `DeclarativePack` types, `SDD_RULES`,
597
598
  `composeRuleSequence`, and the spec loaders/savers. See
598
- [`examples/wrapper/wrapper.js`](../examples/wrapper/wrapper.js).
599
+ [`examples/wrapper/wrapper.js`](https://github.com/SYW-Apps/Waffle-AIron/blob/main/examples/wrapper/wrapper.js).
599
600
 
600
601
  ## Spec-only wrappers
601
602
 
package/docs/network.md CHANGED
@@ -6,14 +6,14 @@ wairon derives a system's network from its design. The inputs are the calls you
6
6
 
7
7
  Specs never hold an address, a port, a namespace or a label. Those deployment facts come from a **bindings file** that the team keeps outside `.wai/` and passes when generating policy. The design stays logical, and the deployment stays yours.
8
8
 
9
- Every command runs at the project you are in. At a project that declares members, the commands cover its whole family; `--no-recursive` limits them to that project alone. Run them at the family root: only the family run can narrow a `network` entry to the callers it really has.
9
+ Every command runs at the project you are in. At a project that declares members, the commands cover its whole family; `--no-recursive` limits them to that project alone. Inside a member, they answer from the enclosing family — the parent's network declaration and the callers the parent models, the same answer the family root gives — and `--no-recursive` judges the member alone. Only the family run can narrow a `network` entry to the callers it really has.
10
10
 
11
11
  ## The outputs, and what each is for
12
12
 
13
13
  | Command | Output | What a team does with it |
14
14
  |---|---|---|
15
- | `wairon network flows [--format json\|csv\|markdown] [--out <file>]` | The **allowed-flows matrix**: one row per flow (from, to, transport, binding, networks crossed, gateway, evidence) | Review it in pull requests as the authoritative "who talks to whom". A design change that adds a dependency shows up as a new row before any code or firewall change exists. The CSV suits spreadsheets and audits, and the Markdown suits review comments. |
16
- | `wairon network policy --bindings <file> [--out <file>]` | **Kubernetes `NetworkPolicy`** YAML: one ingress policy per called workload | Commit it to the deployment repository and diff it in CI. A design change becomes a policy diff that the security reviewer reads in the same PR. A design that fails the gate exits 1: the refused flows are left out and named at the head of the file. |
15
+ | `wairon network flows [--format json\|csv\|markdown] [--out <file>]` | The **allowed-flows matrix**: one row per flow (from, to, transport, binding, networks crossed, gateway, evidence) | Review it in pull requests as the authoritative "who talks to whom". A design change that adds a dependency shows up as a new row before any code or firewall change exists. The CSV suits spreadsheets and audits, and the Markdown suits review comments. A design that fails the gate exits 1. |
16
+ | `wairon network policy --bindings <file> [--out <file>]` | **Kubernetes `NetworkPolicy`** YAML: one ingress policy per called workload | Commit it to the deployment repository and diff it in CI. A design change becomes a policy diff that the security reviewer reads in the same PR. A design that fails the gate exits 1: the refused flows are left out and named at the head of the file. A design name the bindings leave unbound also exits 1. |
17
17
  | `wairon network diagram [--out <file>]` | A **Mermaid** flowchart: declared networks as nested boundaries, gateways on them, an `outside` node, and flows aggregated per workload pair | Use it as the data-flow diagram with trust boundaries that threat modelling starts from: each boundary an edge crosses is a place to ask the STRIDE questions. It also works for onboarding and on architecture pages. The hosted canvas draws the same picture in its **Network** view (`/canvas/<project>/network`; the system spec's `diagram.defaultView: network` opens the canvas there). |
18
18
  | `wairon network check --observed <file> [--bindings <file>]` | **Unexpected** flows (seen, but nothing allows the pair), **disallowed** flows (a verb the destination declares, but not allowed from that source, or only by a flow the gate refuses), **unknown verbs** (an allowed pair, but a method and path no contract of the destination declares) and **unexercised** flows (allowed, never seen) | Audit a live system against its design. Exits 1 on anything unexpected, disallowed or unknown, so it can gate a pipeline. Unexercised flows are review items, such as dead dependencies or rules to tighten, and never fail the command. |
19
19
  | `wairon network why <from> <to>` | The modelled chain behind a flow: the entry or call step, each network entered, the gateway, and the verb with its binding | Answer a firewall change request or an incident question ("why does checkout talk to payments?") from the design, in one command. Exits 1 when nothing allows the flow, and names what does reach the target instead; says so when the gate refuses the flow, when a name is unknown (a typo, not a refusal), and — exiting 0 — when the callee is reached in-process, which is never a network flow. |
@@ -69,7 +69,11 @@ outside: # what "outside" means for a policy
69
69
  - `outside` lists the CIDR blocks admitted for callers from outside, for example the internet, a load balancer range or an intranet. Without it, nothing from outside is admitted.
70
70
  - A source in another namespace gets a `namespaceSelector` on `kubernetes.io/metadata.name`. A network-wide source bound without a namespace matches in any namespace (`namespaceSelector: {}`).
71
71
 
72
- **Nothing is guessed.** A design name the bindings do not map is selected by the placeholder label `wairon.dev/workload: <name>`, which matches no pod until you bind it or label one. It is listed in the document and on stderr, and at the top of the output under `# UNBOUND:`. MessageBus flows travel through the broker rather than pod to pod, so they are listed as `# NOT EXPRESSED` instead of opening ingress. Default deny is implied: each policy selects its workload and admits only what the design allows.
72
+ **Nothing is guessed.** A design name the bindings do not map is selected by the placeholder label `wairon.dev/workload: <name>`, which matches no pod until you bind it or label one. It is listed in the document and on stderr, and at the top of the output under `# UNBOUND:`, and `policy` exits 1 so a pipeline notices. MessageBus flows travel through the broker rather than pod to pod, so they are listed as `# NOT EXPRESSED` instead of opening ingress. Default deny is implied: each policy selects its workload and admits only what the design allows.
73
+
74
+ **Renamed projects.** A bindings key, or a name in an observed-flow file, that is a project's former id (its rename trace, `previousIds`) still resolves to the renamed project, and the output carries a `# NOTE` naming the rename, so you can update the key at your pace instead of finding a policy that selects nothing or a legitimate flow filed as unexpected. `wairon project rename` lists the binding and telemetry keys to rename in its plan.
75
+
76
+ **Mixed reach.** A NetworkPolicy cannot split traffic by path. When one workload serves verbs of different reach on one port — a verb entered from `outside` and a verb only the network may call — its policy has to admit the union, and `policy` says so in a `# NOTE` naming the verbs. To keep the narrower verb narrow at L4, bind the Portal on its own (a `<project>::<portal>` key with its own selector or port): it then gets a policy of its own.
73
77
 
74
78
  ## The observed-flow format
75
79
 
@@ -93,6 +97,7 @@ Or JSON with the same fields, as a list or as `{ "flows": [...] }`:
93
97
  - A row without `method` and `path` is an L4 observation: it exercises every allowed flow between the pair.
94
98
  - A row with both is checked at L7 against the verbs' bindings. `{id}` and `:id` path segments match any value, and gRPC paths (`/pkg.Service/Method`) match the `service/method` binding.
95
99
  - A malformed row (no source or destination, or a non-integer count) is refused with its row number, and nothing is half-read.
100
+ - A name that is a project's former id is mapped to the renamed project, with a `# NOTE` (see **Renamed projects** above).
96
101
 
97
102
  ## A typical loop
98
103
 
package/docs/roadmap.md CHANGED
@@ -4,7 +4,7 @@
4
4
 
5
5
  wairon is an AIDD support tool built around Spec-Driven Development. This roadmap
6
6
  reflects what is actually shipped in `src/` and what is planned. The
7
- [CHANGELOG](../CHANGELOG.md) has the per-release detail.
7
+ [CHANGELOG](https://github.com/SYW-Apps/Waffle-AIron/blob/main/CHANGELOG.md) has the per-release detail.
8
8
 
9
9
  ---
10
10
 
@@ -79,7 +79,7 @@ reflects what is actually shipped in `src/` and what is planned. The
79
79
  and SSO; a state-scoped `lock` with approval requests; hosted members as
80
80
  records of their own; git-backed projects; Notion / Miro producers; a web UI
81
81
  (canvas, specs, admin). Self-host via Docker. See the
82
- [hosted server guide](design/hosted-mcp-server.md).
82
+ [hosted server guide](https://github.com/SYW-Apps/Waffle-AIron/blob/main/docs/design/hosted-mcp-server.md).
83
83
 
84
84
  ---
85
85
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wairon/cli",
3
- "version": "5.1.1-dev.107",
3
+ "version": "5.1.1-dev.108",
4
4
  "description": "SYW Waffle AIron — CLI for managing AI coding agent topology across projects",
5
5
  "keywords": [
6
6
  "ai",
@@ -638,6 +638,12 @@
638
638
  },
639
639
  "description": {
640
640
  "type": "string"
641
+ },
642
+ "formerly": {
643
+ "type": "array",
644
+ "items": {
645
+ "type": "string"
646
+ }
641
647
  }
642
648
  },
643
649
  "required": [