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

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,110 @@
1
+ # Supervisor and Actor doctrine: supervision state, shared data, the lifecycle effect
2
+
3
+ ## The problem
4
+
5
+ Two rules left the process layer without an honest shape.
6
+
7
+ - Held state lives in a dedicated data component, but a Supervisor could not
8
+ depend on a Store, Registry, Repository, Index or Query at all
9
+ (`ARCHITECTURE_VIOLATION_SUPERVISOR_DEP`). A Supervisor's own bookkeeping —
10
+ restart counts, the set of live children, the brackets of the runs it starts —
11
+ had nowhere to live.
12
+ - A component depending on a live Actor had to also depend on a Supervisor that
13
+ supervises it (`ACTOR_REACHED_WITHOUT_SUPERVISOR`). Real callers do not go
14
+ through the Supervisor: they look the Actor's live handle up by id in a
15
+ registry the Supervisor keeps. The remedy pushed a ceremonial edge instead of
16
+ the real lookup hop.
17
+
18
+ ## The rules
19
+
20
+ 1. **Supervision state.** A Supervisor may `owns` a Store or Registry that is its
21
+ own: one hop, private, read and written in full. It owns nothing else, and
22
+ nobody else depends on that state.
23
+ 2. **Shared data.** A Supervisor may call a data component it does not own only
24
+ through methods whose declared effect is `read` or `lifecycle`. A write goes
25
+ through a workflow: the Supervisor depends on the Orchestrator that does it.
26
+ Judged from the Supervisor's narrative call steps against the callee's
27
+ declared effect; a callee that declares no effect is refused too.
28
+ 3. **The lifecycle effect.** A third method effect, `lifecycle`: the method
29
+ creates, destroys, or (un)registers an entity's existence or membership and
30
+ never modifies its domain fields. It is closed under composition: a lifecycle
31
+ method calls only read and lifecycle methods besides construction and local
32
+ steps.
33
+ 4. **Supervised reach.** A component depending on a live Actor reaches it through
34
+ its supervision when it also depends on a Supervisor that supervises the
35
+ Actor, or on a Registry such a Supervisor maintains — by owning it, or by
36
+ calling it with lifecycle-effect methods.
37
+
38
+ **Honest limit.** A `read` made on behalf of a request still passes. In practice
39
+ the paired write is refused, which forces the marshalling workflow out, and the
40
+ read moves with it.
41
+
42
+ ## Codes
43
+
44
+ | Code | Severity | Rule | Reported on | Meaning |
45
+ |---|---|---|---|---|
46
+ | `SUPERVISOR_CONTAINMENT` | error | pattern-containment | the Supervisor | it owns something other than a Store or Registry |
47
+ | `SUPERVISION_STATE_INTRUSION` | error | member-visibility | the intruder | "X depends on Y, which Supervisor Z owns as its supervision state" |
48
+ | `SUPERVISOR_WRITE_SHORTCUT` | error | supervisor-shared-data (new) | the Supervisor's implementation | a call to a write-effect or untagged method on data it does not own |
49
+ | `LIFECYCLE_CALLS_WRITE` | error | lifecycle-effect-closure (new) | the implementation | a lifecycle-effect method calls a write-effect method |
50
+ | `ARCHITECTURE_VIOLATION_SUPERVISOR_DEP` | error | entrypoint-dependencies | the Supervisor | kept, narrowed: a Supervisor depending on a presentation block |
51
+ | `ACTOR_REACHED_WITHOUT_SUPERVISOR` | error | entrypoint-dependencies | the caller | kept, widened: Registry reach counts; the remedy names the Registry, or says to model one |
52
+ | `BLOCK_OWNS_MEMBERS` | error | pattern-membership | the block | kept: a Supervisor is exempt |
53
+ | `SHARED_OWNED_MEMBER` | error | pattern-membership | the later claimant | kept: Supervisors claim like patterns |
54
+ | `UNUSED_LINT_ALLOW` | warning | lint-allows | the allowing spec | kept: an allow naming an error now says an error cannot be allowed |
55
+
56
+ The existing readers of `effect` read `lifecycle` as a mutation:
57
+ `PORTAL_WRITE_SHORTCUT` refuses a Portal's direct lifecycle call as it refuses a
58
+ write, and a durable Store needs a hydration read-back for its lifecycle methods
59
+ as for its writes (`MISSING_HYDRATION`). The invariant registry still asks only
60
+ write-effect methods to assert invariants, since a lifecycle method never
61
+ modifies domain fields.
62
+
63
+ Within the brief, three choices were made:
64
+
65
+ - Exclusivity is its own code rather than a reworded `VISIBILITY_VIOLATION`:
66
+ the remedy differs (there is no facade to depend on instead; the state is
67
+ either shared data or reached through the Supervisor).
68
+ - An owned Registry counts as maintained for supervised reach, as decided. A
69
+ caller depending on it is then still an intruder, so that shape reports
70
+ `SUPERVISION_STATE_INTRUSION` once and no actor finding: a lookup Registry
71
+ callers share is shared data the Supervisor keeps through lifecycle calls.
72
+ - The lint-allow audit decides "error" from what the run saw on that spec (a
73
+ finding of the code landed there as an error) or, when nothing fired there,
74
+ from the code's resolved severity (project override, profile, default). The
75
+ validator now hands the rule context each code's default severity.
76
+
77
+ ## How the four motivating cases validate
78
+
79
+ 1. **An orchestrator calls an Actor whose handle it resolves through a router
80
+ that is really a Registry of live handles, mistyped as a Store.** Typed as a
81
+ Store, the caller reaches the Actor through no supervision and
82
+ `ACTOR_REACHED_WITHOUT_SUPERVISOR` fires on the caller. Retyped as a
83
+ Registry whose register/unregister methods are `lifecycle` and whose lookup
84
+ is `read`, with the Supervisor registering each started Actor through a
85
+ lifecycle call, the caller depending on that Registry and the Actor is
86
+ supervised reach, and the Supervisor's calls pass `SUPERVISOR_WRITE_SHORTCUT`.
87
+ A standalone Registry still needs a Store to write to
88
+ (`REGISTRY_WITHOUT_STORE`, a warning) — give the handles a Store, or wrap both
89
+ in a Repository the Supervisor keeps through lifecycle calls.
90
+ 2. **A component that spawns and owns Actors is typed Orchestrator but is a
91
+ fused Supervisor and workflow.** It depends on the Actor with no Supervisor
92
+ anywhere: `ACTOR_REACHED_WITHOUT_SUPERVISOR`, whose remedy says to give the
93
+ Actor a Supervisor that maintains a handle Registry. Split into a Supervisor
94
+ (spawns, restarts, registers handles) and a workflow (looks the Actor up in
95
+ that Registry), the tree validates.
96
+ 3. **A scheduler Supervisor reads guard state and brackets run lifetimes on a
97
+ shared repository.** The edge to the repository is no longer a finding. Its
98
+ calls — read the guard, open a run, count live runs, close the run — are
99
+ `read`, `lifecycle`, `read`, `lifecycle`: quiet. Tagging open or close as
100
+ `write`, or leaving them untagged, fires `SUPERVISOR_WRITE_SHORTCUT`; a
101
+ lifecycle open that also updates the run's fields fires
102
+ `LIFECYCLE_CALLS_WRITE` on the repository's implementation.
103
+ 4. **The same Supervisor reads and writes a shared object heap on behalf of a
104
+ call.** The read passes; the write fires `SUPERVISOR_WRITE_SHORTCUT`. Moving
105
+ the work into a marshalling Orchestrator the Supervisor calls — the read goes
106
+ with it — validates.
107
+
108
+ All four, and a fire and a control for every new or changed code, are fixtures
109
+ in `tests/rules-matrix/families/boundaries-supervision.fixtures.ts`; the
110
+ lint-allow case is in `references-lint-allows.fixtures.ts`.
@@ -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](https://github.com/SYW-Apps/Waffle-AIron/blob/main/docs/design/pack-scoping.md).
20
+ > project on the machine — see [pack scoping](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
@@ -98,7 +98,7 @@ arguments** — each selection carries its own source, so one command restores a
98
98
  project's doctrine anywhere:
99
99
 
100
100
  ```yaml
101
- - uses: SYW-Apps/Waffle-AIron/.github/actions/setup-wairon@v5
101
+ - uses: SYW-Apps/Waffle-AIron/.github/actions/setup-wairon@v<version> # the version you lock with (see docs/cli.md)
102
102
  with:
103
103
  packs: sync # sync (default) | none (bundled repos) | explicit sources
104
104
  - run: npm ci # a TS/JS project with code: its own dependencies first (see docs/cli.md)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wairon/cli",
3
- "version": "5.1.1-dev.108",
3
+ "version": "5.1.1-dev.109",
4
4
  "description": "SYW Waffle AIron — CLI for managing AI coding agent topology across projects",
5
5
  "keywords": [
6
6
  "ai",
@@ -30,7 +30,13 @@
30
30
  "schemas",
31
31
  "README.md",
32
32
  "docs/*.md",
33
- "docs/standards/**"
33
+ "docs/standards/**",
34
+ "docs/design/supervisor-doctrine.md",
35
+ "docs/design/pack-scoping.md",
36
+ "docs/design/connecting-agent-entrypoint.md",
37
+ "docs/design/execution-budgets.md",
38
+ "docs/design/approval-baseline.md",
39
+ "CONTRIBUTING.md"
34
40
  ],
35
41
  "workspaces": [
36
42
  "sdk"
@@ -72,6 +78,7 @@
72
78
  "js-yaml": "^4.1.0",
73
79
  "ora": "^5.4.1",
74
80
  "swagger-ui-dist": "^5.32.9",
81
+ "typescript": "^5.5.2",
75
82
  "yaml": "^2.9.1",
76
83
  "zod": "^3.23.8"
77
84
  },
@@ -87,7 +94,6 @@
87
94
  "rimraf": "^5.0.7",
88
95
  "tsup": "^8.1.0",
89
96
  "tsx": "^4.15.7",
90
- "typescript": "^5.5.2",
91
97
  "vitest": "^4.1.9",
92
98
  "zod-to-json-schema": "^3.25.2"
93
99
  }
@@ -1102,7 +1102,15 @@
1102
1102
  "properties": {
1103
1103
  "id": {
1104
1104
  "type": "string",
1105
- "pattern": "^[a-z0-9-_]+$"
1105
+ "maxLength": 64,
1106
+ "allOf": [
1107
+ {
1108
+ "pattern": "^[a-z0-9-_]+$"
1109
+ },
1110
+ {
1111
+ "pattern": "^(?!(?:con|prn|aux|nul|com[0-9]|lpt[0-9])$)"
1112
+ }
1113
+ ]
1106
1114
  },
1107
1115
  "description": {
1108
1116
  "type": "string",