@owlmeans/viable-common 0.0.40 → 0.0.41

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/README.md CHANGED
@@ -21,7 +21,7 @@ filesystem, no inference SDK. It is safe to import from a browser bundle.
21
21
  ## Installation
22
22
 
23
23
  ```bash
24
- bun add @owlmeans/viable-common@^0.0.40
24
+ bun add @owlmeans/viable-common@^0.0.41
25
25
  ```
26
26
 
27
27
  ## Rules worth knowing before you change something
@@ -39,7 +39,7 @@ means "inherit" has no other spelling. `tests/convert.spec.ts` walks every expor
39
39
  both faults, and for draft-04 tuple `items`.
40
40
 
41
41
  **A field that crosses a version skew carries no `enum`.** A connector is installed with
42
- `npx -y @owlmeans/viable-mcp@^0.1.18-rc.37` and talks to a separately deployed platform, so an executor kind it
42
+ `npx -y @owlmeans/viable-mcp@^0.1.18-rc.39` and talks to a separately deployed platform, so an executor kind it
43
43
  sends must remain an unused capability on an older platform rather than a refused session.
44
44
 
45
45
  **A ceiling exists once.** The inquiry answer cap here equals `DEFAULT_INQUIRY_ANSWER_CHARS` in
@@ -59,7 +59,7 @@ This package ships embedded agent skills under `agent-meta/`. After installing y
59
59
  your project's skill store (`.agents/skills/`):
60
60
 
61
61
  ```sh
62
- npx @owlmeans/agent-skills@^0.1.18-rc.45
62
+ npx @owlmeans/agent-skills@^0.1.18-rc.46
63
63
  ```
64
64
 
65
65
  The embedded files are version-matched to this package release. Do not edit them
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "schemaVersion": 2,
3
3
  "package": "@owlmeans/viable-common",
4
- "version": "0.0.40",
5
- "generatedAt": "2026-10-01T23:27:48.744Z",
4
+ "version": "0.0.41",
5
+ "generatedAt": "2026-10-03T11:19:50.795Z",
6
6
  "canonicalRepo": "https://github.com/owlmeans/common",
7
7
  "entries": [
8
8
  {
@@ -6,7 +6,7 @@ description: Shared, runtime-free taxonomy for presenting OwlMeans Viable agent
6
6
 
7
7
  # Agent output presentation
8
8
 
9
- **Install:** `"@owlmeans/viable-common": "^0.0.40"` in `dependencies`
9
+ **Install:** `"@owlmeans/viable-common": "^0.0.41"` in `dependencies`
10
10
 
11
11
  `@owlmeans/viable-common`'s `agent/presentation.ts` owns the browser-safe vocabulary for agent
12
12
  output. Keep the server and every client on `classifyAgentMessage()`; consumers may refine a
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: viable-common
3
- description: How to use @owlmeans/viable-common — the runtime-free contract package of the OwlMeans Viable platform. Covers planning cards and flows (including the landing-gate fields), project/story refusals, slot commands and layouts, slot metadata keys, target integrity, connector domain statuses and routes, the intent-first hand-off (`./intent`), conversion vocabulary, blueprint layer types and the case vocabulary, the ViableSkill/ViablePersona names (never the catalogue behind them), what belongs here versus in @owlmeans/viable, generated-project analysis/design/scaffold/metadata shapes, StoryDesignPort, schema conventions, and wire-version rules. Auto-invoked when importing a viable card type or flow, a slot command, a connector or conversion type, a target-integrity helper, or any *Schema this package exports.
3
+ description: How to use @owlmeans/viable-common — the runtime-free contract package of the OwlMeans Viable platform. Covers planning cards and flows (including the landing-gate and tenancy fields), project/story refusals, slot commands and layouts, slot metadata keys, target integrity, connector domain statuses and routes, the intent-first hand-off (`./intent`), conversion vocabulary, blueprint layer types and the case vocabulary, the ViableSkill/ViablePersona names (never the catalogue behind them), what belongs here versus in @owlmeans/viable, generated-project analysis/design/scaffold/metadata shapes, StoryDesignPort, schema conventions, and wire-version rules. Auto-invoked when importing a viable card type or flow, a slot command, a connector or conversion type, a target-integrity helper, or any *Schema this package exports.
4
4
  user-invocable: false
5
5
  ---
6
6
  <!-- AUTO-GENERATED — do not edit. Regenerate via sync-agent-meta. -->
@@ -8,103 +8,84 @@ user-invocable: false
8
8
  # @owlmeans/viable-common
9
9
 
10
10
  **Layer:** Cross-cutting domain (contracts only)
11
- **Install:** `"@owlmeans/viable-common": "^0.0.40"` in `dependencies`
12
- **Subpaths:** `.` · `./slot` · `./connect` · `./convert` · `./integrity` · `./intent`
11
+ **Install:** `"@owlmeans/viable-common": "^0.0.41"` in `dependencies`
12
+ **Subpaths:** `.` · `./slot` · `./connect` · `./convert` · `./integrity` · `./intent` — the barrel
13
+ re-exports every subpath except `./intent`.
13
14
  **Runtime-free:** no `@langchain/*`, no filesystem, no Ajv at run time (a devDependency, for the
14
- tests that compile the schemas). It depends on `@owlmeans/planning`, `@owlmeans/resource`,
15
- `@owlmeans/entrypoint`, `@owlmeans/route`, `@owlmeans/error`, `@owlmeans/agent-common`,
16
- `@owlmeans/llm-common` and — for `./intent` alone — `@owlmeans/flow`, `@owlmeans/auth` and
17
- `@owlmeans/context`, and on nothing else.
18
-
19
- Every name the OwlMeans Viable platform puts on a wire, on a volume or in a prompt is declared
20
- here once, and the four runtimes that must agree about it — the platform's API services, the
21
- agent, the publisher/production runtime, and the connector SDK on somebody's laptop — all read the same
22
- declaration. A vocabulary copied instead of imported is how one tree gets two totals, one
23
- refusal two spellings, and one ceiling two values.
24
-
25
- **Names, not agent-only data.** This package is imported by the BROWSER too, so everything in it
26
- ships in every visitor's bundle. Prompt, persona and blueprint-case DATA that only the AI agent
27
- library ever reads — never the browser or another server package — belongs in `@owlmeans/viable`
28
- instead: the skill bodies and their order, the persona prompt
29
- policies, the blueprint case table and resolution, the BA model-answer schemas. What stays here is
30
- what another package's contract references by type — the `ViableSkill` / `ViablePersona` enums and
31
- the `Blueprint` types and vocabulary that execution state and card fields name.
15
+ tests that compile the schemas); it depends on the packages under Depends On and nothing else.
16
+
17
+ Every name the Viable platform puts on a wire, on a volume or in a prompt is declared here once,
18
+ and the runtimes that must agree about it — the platform's API services, the agent, the
19
+ publisher/production runtime and the connector SDK on somebody's laptop — read the same
20
+ declaration. A vocabulary copied instead of imported is how one tree gets two totals, one refusal
21
+ two spellings and one ceiling two values.
22
+
23
+ **Names, not agent-only data.** The BROWSER imports this package, so everything in it ships in
24
+ every visitor's bundle. Data only the AI agent library reads — skill bodies and their order,
25
+ persona prompt policies, the blueprint case table and its resolution, the BA model-answer schemas
26
+ — belongs in `@owlmeans/viable`. What stays here is what another package's contract references by
27
+ type: the `ViableSkill` / `ViablePersona` enums and the `Blueprint` types and vocabulary that
28
+ execution state and card fields name.
32
29
 
33
30
  ## Key Exports
34
31
 
35
32
  | Subpath | What it declares |
36
33
  |---|---|
37
- | `.` (barrel) | The planning module (`VIABLE_*_TYPE`, `VIABLE_TYPE_SCHEMAS`, `VIABLE_FLOW_SCHEMAS`, `ViableStoryStatus`/`ViableProjectStatus` and their transitions, `ViableSpecCategory`, `ViableRelationship`, `ViableChannel`, `ViableProjectCard`/`ViableStoryCard`, the card helpers, the landing sentence helpers, the `Project*` refusals); `SlotMetadata` and the three metadata vocabularies (`metadataConfigs`, `metadataLists`, `metadataSecrets`), `BRANDING_ENV_KEYS` / `brandingEnv`; `ProjectArea` / `AREA_PATHS` / `AREA_ACCESS` / `AREA_TIER`; `ModelRole` and the viable `ExecutionState`; the `ViableSkill` / `ViablePersona` enums (names only); the `Blueprint` layer types, `BlueprintRef` / `BlueprintPatch`, `BlueprintCase` / `GameKind`, `DEFAULT_BLUEPRINT_ID` / `BLUEPRINT_META_KEY` and `landingGatePreferenceOf`; the BA shapes and helpers (`mergeConnectingStories`), the dev, UX, design and scaffold shapes and their schemas, `StoryDesignPort`; `ModerationCategory` / `ModerationSubject` / `decideModeration`; the `docs/` metadata paths; `PreviewEventType` |
38
- | `./slot` | `SlotCommandType` and the `SlotFileCommand` / `SlotShellCommand` / `SlotGitCommand` sets, `SubProject`, `WorkloadKind`, the target ports and process markers, `slotOrigin` / `targetRedirectUrisForOrigin` |
34
+ | `.` (barrel) | The planning module (`VIABLE_*_TYPE`, `VIABLE_TYPE_SCHEMAS`, `VIABLE_FLOW_SCHEMAS`, `ViableStoryStatus`/`ViableProjectStatus` and their transitions, `ViableSpecCategory`, `ViableRelationship`, `ViableChannel`, `ViableProjectCard`/`ViableStoryCard`, the card helpers, the landing sentence helpers, the `Project*` refusals); `SlotMetadata` and the three metadata vocabularies (`metadataConfigs`, `metadataLists`, `metadataSecrets`), `BRANDING_ENV_KEYS` / `brandingEnv`; `ProjectArea` / `AREA_PATHS` / `AREA_ACCESS` / `AREA_TIER`, `ADMIN_PERMISSION` / `OPERATOR_PERMISSION`; the tenancy contract (`ProjectTenancy`, `ViableTenancyDecision`, `NO_TENANCY`, `tenancyOf`, `tenantedArea`, `TENANCY_QUOTE_MAX`); `ModelRole` and the viable `ExecutionState`; the `ViableSkill` / `ViablePersona` enums; the `Blueprint` layer types, `BlueprintRef` / `BlueprintPatch`, `BlueprintCase` / `GameKind`, `DEFAULT_BLUEPRINT_ID` / `BLUEPRINT_META_KEY`, `landingGatePreferenceOf`; the target topology (`TopologyDescriptor`, `LAYOUT_TOPOLOGIES`, `resolveTopology`, `packageForRole` — meaning in `/blueprints`); the BA shapes (`mergeConnectingStories`), the dev (`AccessBlock`, `AccessLevel`, `PermissionDefault`), UX, design and scaffold shapes and their schemas, `StoryDesignPort`; `ModerationCategory` / `ModerationSubject` / `decideModeration`; the `docs/` metadata paths; `PreviewEventType`; the agent-output taxonomy (`classifyAgentMessage`, `isAgentMessageHidden` — `/agent-presentation`) and the spectator entry types |
35
+ | `./slot` | `SlotCommandType` and the `SlotFileCommand` / `SlotShellCommand` / `SlotGitCommand` sets, the per-command deadlines and timeouts (`commandDeadline`, `commandTimeout`), `SubProject`, `LAYOUTS` / `ROLE_DIRS` / `subprojectDirOf`, `WorkloadKind`, the target ports and process markers, `slotOrigin` / `targetRedirectUrisForOrigin` |
39
36
  | `./connect` | `ConnectTarget`, `ConnectLlm`, `ConnectHarness`, `ConnectExecutor`, `ConnectOpKind`, `ConnectProjectStatus`, `ConnectStoryStatus`, `ConnectPipelineState`, `ConnectWaitReason`, `ConnectProjectBranding` / `ConnectProjectBrandingSave`, `ModelTier` + `tierOfRole`/`clampTier`, `ModelTask*`, `InquiryPayload` + `ConnectInquiryKind`, the session and domain-status views, the `Connect*` error family, `connectProtocols(opts)` and every `*Schema` behind them |
40
- | `./convert` | `ConversionStage`/`Status`/`Decision` and the `stageAfter`/`decisionFor`/`canEnter` transitions, `OriginKind`/`Shape`/`State`, `StackId` + `STACK_FAMILY`, `ArchitectureCase`, `ConvertibilityVerdict`/`Reason`, the census classifiers (`fileClassOf`, `sizeClassOf`, `entropyClassOf`, `binaryByExtension`), the `docs/conversion/` paths, `CONVERTED_ORIGIN_DIR`, `SOURCE_LIST_EXCLUSIONS`, `CENSUS_SKIP_DIRS`, `RELOCATE_ALWAYS_KEEP`, and the model-answer schemas the conversion asks with |
37
+ | `./convert` | `ConversionStage`/`Status`/`Decision` and the `stageAfter`/`decisionFor`/`canEnter` transitions, `OriginKind`/`OriginShape`/`OriginState`, `StackId` + `STACK_FAMILY`, `ArchitectureCase`, `ConvertibilityVerdict`/`ConvertibilityReason`, the census classifiers (`fileClassOf`, `sizeClassOf`, `entropyClassOf`, `binaryByExtension`), the `docs/conversion/` paths, `CONVERTED_ORIGIN_DIR`, `SOURCE_LIST_EXCLUSIONS`, `CENSUS_SKIP_DIRS`, `RELOCATE_ALWAYS_KEEP`, and the model-answer schemas the conversion asks with |
41
38
  | `./integrity` | `TargetLayout` + `TARGET_LAYOUTS`, `detectTargetLayout`, `verifyTargetShape`, `TARGET_INTEGRITY_FILES`, `TARGET_PROTECTED_FILES`, `isLegacyLayout`, `targetPackageName` |
42
- | `./intent` | The intent-first hand-off from the public site to the platform: `intent` (the four aliases), `makeIntentProtocols(opts?)` (two GUEST API routes + the `/start` landing screen), `intentFlow` + `IntentFlowStep` + `INTENT_PAYLOAD_REF`, `IntentStashBodySchema` / `IntentPickupBodySchema`, the `INTENT_*` constants (TTL, prompt cap, reference pattern, draft and suspend windows), `IntentDraft`, `IntentExpired` (404) / `IntentThrottled` (429) |
39
+ | `./intent` | `intent` (the four aliases), `makeIntentProtocols(opts?)`, `intentFlow` + `IntentFlowStep` + `INTENT_PAYLOAD_REF`, `IntentStashBodySchema` / `IntentPickupBodySchema`, the `INTENT_*` constants, `IntentDraft`, `IntentExpired` (404) / `IntentThrottled` (429) |
43
40
 
44
41
  ## The planning module
45
42
 
46
43
  A Viable project, its user stories and the documents behind them are `@owlmeans/planning`
47
- WORKCARDS. The planning packages own the record, the transition, the fold, the stores and the
48
- protocol tree; this module owns what a Viable card IS — its type, its flow, its `fields`, its
49
- slots, its code — and every runtime that writes one (the platform API services, the agent, the library, the
50
- SDK) reads that declaration from here. A plugin registers `VIABLE_TYPE_SCHEMAS` and
51
- `VIABLE_FLOW_SCHEMAS`; nothing redeclares a type or a flow locally.
44
+ WORKCARDS. The planning packages own the record, transition, fold, stores and protocol tree
45
+ (`/planning`); this module owns what a Viable card IS — its type, flow, `fields`, slots and code.
46
+ A plugin registers `VIABLE_TYPE_SCHEMAS` and `VIABLE_FLOW_SCHEMAS`; nothing redeclares a type or a
47
+ flow locally.
52
48
 
53
49
  ### Types
54
50
 
55
51
  | Type | Kind | Primary flow | Code | May hold |
56
52
  |---|---|---|---|---|
57
- | `viable:project` (`VIABLE_PROJECT_TYPE`) | project | `viable:project` | slug, unique in the entity, mutable (rename, host ladder) | `viable:user-story` |
53
+ | `viable:project` (`VIABLE_PROJECT_TYPE`) | project | `viable:project` | slug, unique in the organization, mutable (rename, host ladder) | `viable:user-story` |
58
54
  | `viable:user-story` (`VIABLE_STORY_TYPE`) | card | `viable:user-story` | `US-` + 5 uppercase, unique in the project, never changes | — |
59
55
  | `viable:spec` (`VIABLE_SPEC_TYPE`) | specification | `viable:spec` (one status, `current`) | none | — |
60
56
  | `viable:bug` / `viable:improvement` / `viable:requirement` | card | `viable:user-story` | `BUG-` / `IMP-` / `REQ-` | — |
61
57
 
62
58
  The three RESERVED types are declared in full so their prefix and flow are decided once, and are
63
- deliberately absent from the project type's `cardTypes`: nothing can create one until a feature
64
- adds it there. A type always runs at least one flow — the planning executor has no status for a
65
- flowless card, which is why a document runs the one-status `viable:spec` flow.
59
+ absent from the project type's `cardTypes`: nothing creates one until a feature adds it there. A
60
+ type always runs a flow — the planning executor has no status for a flowless card, so a document
61
+ runs the one-status `viable:spec` flow.
66
62
 
67
63
  ### The two flows
68
64
 
69
- Story flow — the keys are the strings a story has always carried, and they are wire contracts:
70
- the `docs/stories/<code>.md` frontmatter, the connector's story-status mapping, the board columns,
71
- their i18n keys and every end-to-end selector read them. A key is never renamed.
72
-
73
- | Status | Intrinsic | Tone |
74
- |---|---|---|
75
- | `planned` (initial) | planned | blue |
76
- | `in-progress` | in-progress | yellow |
77
- | `completed` | closed | green |
78
- | `failed` | **planned** | red |
65
+ Story flow — the keys are wire contracts (the `docs/stories/<code>.md` frontmatter, the
66
+ connector's story-status mapping, the board columns, their i18n keys, every e2e selector), and a
67
+ key is never renamed.
79
68
 
80
- | Transition | From | To |
81
- |---|---|---|
82
- | `start` | `planned`, `failed` | `in-progress` |
83
- | `complete` | `in-progress` | `completed` |
84
- | `fail` | `in-progress` | `failed` |
85
- | `reset` | `*` | `planned` |
69
+ | Status | Intrinsic | Tone | | Transition | From | To |
70
+ |---|---|---|---|---|---|---|
71
+ | `planned` (initial) | planned | blue | | `start` | `planned`, `failed` | `in-progress` |
72
+ | `in-progress` | in-progress | yellow | | `complete` | `in-progress` | `completed` |
73
+ | `completed` | closed | green | | `fail` | `in-progress` | `failed` |
74
+ | `failed` | **planned** | red | | `reset` | `*` | `planned` |
86
75
 
87
76
  `failed` is intrinsically planned: a failed story is work still to do, so "done" is the closed
88
- count of a summary and a retry is `start` again. `reset` is the manual recovery and the only move a
89
- completed story accepts.
90
-
91
- Project flow:
92
-
93
- | Status | Intrinsic | Tone |
94
- |---|---|---|
95
- | `draft` (initial) | planned | blue |
96
- | `confirmed` | in-progress | yellow |
97
- | `active` | in-progress | green |
98
- | `archived` | closed | neutral |
77
+ count and a retry is `start` again. `reset` is the manual recovery and the only move a completed
78
+ story accepts.
99
79
 
100
- `confirm` (`draft → confirmed`), `activate` (`confirmed → active`), `archive` (`* → archived`),
101
- `reopen` (`archived → active`). A create lands at `draft`, confirming the brief is `confirm`, the end
102
- of an initialization is `activate`. A reinitialization and a failed initialization are facts of the
103
- SLOT, not transitions; destroying a project is a `delete` plus the platform's cascade, never
104
- `archive`.
80
+ Project flow: `draft` (initial; planned, blue), `confirmed` (in-progress, yellow), `active`
81
+ (in-progress, green), `archived` (closed, neutral); `confirm` (`draft → confirmed`), `activate`
82
+ (`confirmed → active`), `archive` (`* → archived`), `reopen` (`archived → active`). A create lands
83
+ at `draft`, confirming the brief is `confirm`, the end of an initialization is `activate`. A
84
+ reinitialization and a failed initialization are facts of the SLOT, not transitions; destroying a
85
+ project is a `delete` plus the platform's cascade, never `archive`.
105
86
 
106
- Every status carries a `tone` (`ViableTone`): a board draws its columns and their palette from the
107
- flow, never from a local table.
87
+ Every status carries a `tone` (`ViableTone`): a board draws its columns and palette from the flow,
88
+ never from a local table.
108
89
 
109
90
  ### Where each fact lives on a card
110
91
 
@@ -115,48 +96,63 @@ the wire and in target files — a parent agent's vocabulary, which never change
115
96
  | Fact | On the card |
116
97
  |---|---|
117
98
  | project `id` / story `id` | `id` (a card id) |
118
- | project `alias` | `code` |
119
- | project `name` | `title` |
120
- | project `description` | `description` |
99
+ | project `alias` / `name` / `description` | `code` / `title` / `description` |
121
100
  | project `specification` / `vision` / `designSystem` | specification bodies, categories `specification` / `vision` / `design-system` |
122
101
  | project `formerAliases`, `language`, `blueprint`, `blueprintCase`, `gameKind`, `target`, `origin`, `connectLlmMode`, `converterLlmMode` | `fields.*` |
123
102
  | the landing-gate decision | project `fields.landing` — `{ story: code \| null, at }` |
124
- | story narrative (`story`) | `title` |
125
- | story `code` | `code` |
126
- | story `status` | `status` (same strings) |
103
+ | the tenancy decision | project `fields.tenancy` — `ViableTenancyDecision` `{ operators, users, quotes?, by: 'model' \| 'owner', at }` |
104
+ | story narrative (`story`) / `code` / `status` | `title` / `code` / `status` (same strings) |
127
105
  | story `projectId` | `parent` |
128
106
  | story position in the flow | `order` — a double; a connective story sits between two flow steps (`3.5`) |
129
- | story `area`, `primary`, `actor`, `warning`, `kind`, `landing` | `fields.*` (`kind` is persisted) |
130
- | a story's design | specification `design` under the STORY card |
131
- | the scaffold plan | specification `scaffold` under the PROJECT card |
107
+ | story `area`, `primary`, `actor`, `warning`, `kind`, `landing` | `fields.*` |
108
+ | a story's design / the scaffold plan | specification `design` under the STORY card / `scaffold` under the PROJECT card |
132
109
 
133
- `area` and `primary` are required in `ViableStoryFieldsSchema`; a create that carries no area is
134
- still valid when it is checked, because validation runs after the planning middlewares and the
135
- viable plugin fills the area of a narrative a person wrote. `storyFieldsOf` answers an absent area
136
- as `guest` and an absent flag as `false`.
110
+ `area` and `primary` are required in `ViableStoryFieldsSchema`; a create without an area still
111
+ validates, because validation runs after the planning middlewares and the viable plugin fills the
112
+ area of a narrative a person wrote. `storyFieldsOf` answers an absent area as `guest` and an
113
+ absent flag as `false`.
137
114
 
138
115
  ### The landing gate on the cards
139
116
 
140
117
  The landing gate is the key end-user story a guest starts on the landing page and continues on its
141
- full-scale screen after signing in. Two fields record it, and they answer different questions:
142
-
143
- - project `fields.landing` is the DECISION, in three states: absent — never decided (a run that has
144
- not reached it, a project older than the gate); `{ story: null, at }` — decided, no gate;
145
- `{ story: <code>, at }` — that story. A failed decision is never written: `null` would read as a
146
- decided "none" and nothing would ask again. The schema keeps `story` nullable for exactly that
147
- reason, and `at` carries no `format` because the planning registry compiles without ajv-formats.
148
- - story `fields.landing: true` marks the chosen card — at most one per project — and is what the
149
- design and development stages key on. `storyWriteInputOf` copies it into
150
- `StoryWriteInput.landing` only when set, so `StoryMeta.landing` appears only in that story's
151
- `docs/stories/<code>.md`; like `primary` it is the CARD's and is never passed in
152
- `StoryWriteContent`.
153
-
154
- The chosen narrative also carries `LANDING_STORY_SENTENCE`, appended by `withLandingSentence` — a
155
- note for the people reading the board, never the authority. It is idempotent (checked with
156
- `hasLandingSentence`, whitespace-insensitive), joined with one space, and never pushes a title past
157
- `TITLE_MAX`: a narrative with no room is returned uncut rather than truncated.
158
-
159
- ### Slots
118
+ full-scale screen after signing in (`/target-areas`). Two fields record it:
119
+
120
+ - project `fields.landing` is the DECISION, in three states: absent — never decided;
121
+ `{ story: null, at }` — decided, no gate; `{ story: <code>, at }` — that story. A failed decision
122
+ is never written, since `null` would read as a decided "none" that nothing asks again. `at`
123
+ carries no `format` because the planning registry compiles without ajv-formats.
124
+ - story `fields.landing: true` marks the chosen card — at most one per project — and is what design
125
+ and development key on. `storyWriteInputOf` copies it into `StoryWriteInput.landing` only when
126
+ set, so `StoryMeta.landing` appears only in that story's `docs/stories/<code>.md`; like `primary`
127
+ it is the CARD's and is never passed in `StoryWriteContent`.
128
+
129
+ `withLandingSentence` appends `LANDING_STORY_SENTENCE` to the chosen narrative — a note for people
130
+ reading the board, never the authority. It is idempotent (`hasLandingSentence`,
131
+ whitespace-insensitive), joins with one space, and never pushes a title past `TITLE_MAX`: a
132
+ narrative with no room is returned uncut.
133
+
134
+ ### The tenancy decision on the card
135
+
136
+ `ProjectTenancy` is two independent flags: `operators` (the back office's staff split into tenant
137
+ organizations) and `users` (end users distributed across tenant organizations). An organization is
138
+ an IAM-managed tenant, never a table the target keeps; both flags off is a single-organization
139
+ application, the project owner's, that every person acts in.
140
+
141
+ - project `fields.tenancy` (`ViableTenancyDecision`): ABSENT means never decided and reads as
142
+ single-organization; a recorded one always carries BOTH flags, `by` (`'model'` inferred,
143
+ `'owner'` set) and `at`, and may carry `quotes` — the requester's own sentences, verbatim, each
144
+ at most `TENANCY_QUOTE_MAX` (1024) characters. A partial decision, another decider or a stray key
145
+ is refused.
146
+ - It reaches a run only through `BlueprintRef.tenancy`, and only when a flag is on; resolution
147
+ alone writes it into `experience.tenancy` — never a blueprint or a case table. Read it through
148
+ `tenancyOf(blueprint)`: `NO_TENANCY` (frozen, both off) for no blueprint, layer, key or an
149
+ unreadable value — only a literal `true` turns a flag on.
150
+ - `tenantedArea(area, tenancy)` — `user` follows `users`, `operator` follows `operators`; `guest`
151
+ and `admin` (the project owner, above every tenant) are never tenanted.
152
+ - Classification, the access policy, per-record kinds and the IAM client config live in
153
+ `@owlmeans/viable` (`/target-tenancy`).
154
+
155
+ ### Slots, codes, relationships
160
156
 
161
157
  | Card | Category | Format | Rule |
162
158
  |---|---|---|---|
@@ -166,121 +162,82 @@ note for the people reading the board, never the authority. It is idempotent (ch
166
162
  | story | `design` | json | revisioned, keeps 3, body is a `StoryDesign` at `STORY_DESIGN_VERSION` |
167
163
 
168
164
  The co-located `*.spec.md` / `*.ux.md` / `*.ui.md` files of a target are FILES, never slots — that
169
- prose already lives in the `design` payload — so `SpecCategory` is not a slot vocabulary and no
170
- type declares a `ux` or `ui` slot.
171
-
172
- ### Codes
165
+ prose lives in the `design` payload — so no type declares a `ux` or `ui` slot.
173
166
 
174
167
  A story CODE (`US-XXXXX`) is the target's vocabulary: every file, registry entry and widget stamp
175
- in a generated project names the code, and a card id never reaches a target file —
176
- `storyWriteInputOf` refuses a card with no code (`ProjectStoryMissconfigured('no-code')`) rather
177
- than file it under its id. A project's code is its alias, minted by the platform's name ladder
178
- (which knows retired aliases and refused hostnames); the slug policy only guards uniqueness.
179
-
180
- ### Relationships
168
+ names the code, and a card id never reaches a target file — `storyWriteInputOf` refuses a card
169
+ with no code (`ProjectStoryMissconfigured('no-code')`). A project's code is its alias, minted by
170
+ the platform's name ladder; the slug policy only guards uniqueness.
181
171
 
182
- `follows`, `shares-widget` and `shares-screen` run story → story, one each per card. Only `follows`
183
- is WRITTEN: a connective story follows the flow story it was anchored after, created in the same
184
- transition as the card from `MergedStoryDraft.after` (the clamped 1-based position among the flow
185
- entries, filled by `mergeConnectingStories` and nowhere else). The two `shares-*` types are
186
- declared only — the `scaffold` specification is their single authority, and links would be a
187
- second answer that can disagree with it.
172
+ `follows`, `shares-widget` and `shares-screen` run story → story. Only `follows` is WRITTEN: a
173
+ connective story follows the flow story it was anchored after, created in the same transition from
174
+ `MergedStoryDraft.after` (the clamped 1-based position, filled by `mergeConnectingStories` alone).
175
+ The `shares-*` types are declared only — the `scaffold` specification is their single authority.
188
176
 
189
177
  ### The write channel
190
178
 
191
179
  `ViableChannel` (`web`, `connect`, `agent`, `pipeline`) is what a planning write carries on
192
- `PlanningScope.channel` and records on `actor.channel`. It is never read from the wire: the platform's
193
- API services derive `connect` from an access-token request and `web` from everything else; the agent's own
194
- writes are `agent` or `pipeline`. Three rules key on it, and `isUserChannel` is how they ask:
180
+ `PlanningScope.channel` and records on `actor.channel`. It is never read from the wire: the API
181
+ services derive `connect` from an access-token request and `web` from everything else; the agent's
182
+ own writes are `agent` or `pipeline`. Three rules ask `isUserChannel`:
195
183
 
196
184
  - the balance refusal — `ConnectOutOfCredits` for `connect`, `AgentOutOfTokens` otherwise;
197
- - re-formatting a narrative through the analyst — `web`/`connect` only, so a pipeline-created card
198
- is never rewritten;
199
- - the develop trigger — only a committed `start` written by `web`/`connect` asks for development,
200
- never the `start` a conversion or free flight writes for itself.
185
+ - re-formatting a narrative through the analyst — `web`/`connect` only;
186
+ - the develop trigger — only a committed `start` written by `web`/`connect`, never the `start` a
187
+ conversion or free flight writes for itself.
201
188
 
202
- ### Card helpers
189
+ ### Card helpers and the design port
203
190
 
204
191
  `isViableProject` / `isViableStory` check kind AND type. `projectBriefOf(project, specs)` assembles
205
- the `AgentProject` brief a generator reads (highest revision per part, `''` for a part nobody
206
- wrote, `alias` from the code). `userStoryOf(card, design?)` builds the coders' aggregate — the card
207
- wins on narrative, code, area and actor, the design supplies entities and screens;
208
- `userStoryOfDesign(design)` is the design-only reading for a context with no card.
209
- `storyDraftOf(card)` feeds the analysis prompts and moderation. `ExecutionState.projectCard` and
210
- `TaskExecutionState.card` carry the cards as plain data beside the brief and the aggregate.
192
+ the `AgentProject` brief (highest revision per part, `''` for an unwritten part, `alias` from the
193
+ code). `userStoryOf(card, design?)` builds the coders' aggregate — the card wins on narrative,
194
+ code, area and actor, the design supplies entities and screens; `userStoryOfDesign(design)` is the
195
+ design-only reading. `storyDraftOf(card)` feeds the analysis prompts and moderation.
196
+ `ExecutionState.projectCard` and `TaskExecutionState.card` carry the cards as plain data.
211
197
 
212
- ### The design port
213
-
214
- `StoryDesignPort` is two questions addressed by CARD id — `current(cardId)` and
215
- `put(cardId, design, { runId?, cause? })` answering the revision. The port decides which slot of
216
- that card holds the payload (`design` for a story card, `scaffold` for the project card) and answers
217
- `null` for a stored design of another version; the code inside a design is the target's vocabulary
218
- and never addresses a record.
198
+ `StoryDesignPort` is addressed by CARD id — `current(cardId)` and
199
+ `put(cardId, design, { runId?, cause? })` answering the revision. The port picks the slot (`design`
200
+ for a story, `scaffold` for the project) and answers `null` for a stored design of another
201
+ version; the code inside a design never addresses a record.
219
202
 
220
203
  ## A schema here is written for the reader that will refuse it
221
204
 
222
- Two populations live side by side and are written differently on purpose. Getting the population
223
- wrong is not a style error — each reader refuses a different thing, and one of them refuses at
224
- boot rather than at the call.
225
-
226
- **Model-answer schemas** are the shape a model's single JSON object must take. Annotate them
227
- `JSONSchemaType<T>` — checked, not cast — because the answer is parsed straight back into that
228
- type, and a schema that drifted fails at run time with a message about a document rather than
229
- about a field.
230
-
231
- **Record-element schemas** describe what the platform stores and puts on the wire. They are
232
- hand-written and cast, because they are re-applied as a Mongo `$jsonSchema`, which is stricter
233
- than Ajv: no `Record<>` maps (an open key space cannot be validated), no `integer` (a stored
234
- number is a double), dates as ISO strings rather than objects.
235
-
236
- Three rules hold for both, and `tests/convert.spec.ts` walks **the package barrel** for each —
237
- not the conversion barrel, although the file is the conversion's, because none of the three
238
- faults is particular to a conversion and a walk over one directory lets the same shape through
239
- in a design, a slot or a connector schema:
240
-
241
- - **`nullable: true` always carries its `type`.** Ajv refuses `nullable` on its own, and a schema
242
- that fails to compile takes down whatever compiled it — the route registration, the collection
243
- validator — instead of the one call that would have carried the value.
244
- - **A nullable ENUM lists `null` among its values**: `enum: [...Object.values(X), null]`.
245
- `nullable` and `enum` are separate keywords checked independently, so the pair written apart
246
- widens the type check to admit `null` and then refuses that very value by enum — the field can
247
- only ever be OMITTED, never sent empty. Nothing fails at compile time and nothing fails for a
248
- caller that leaves the key out, which is why it survives review; it surfaces as the one caller
249
- that spells absence as `null`. Both callers exist here: a provider's structured output writes an
250
- unset optional as `null` (an intake stack call was retried three times and discarded as
251
- `llm:retry-exceeded`), and a wire body where `null` MEANS something — `llmMode`, "inherit the
252
- profile's setting" — has no other spelling at all.
253
- - **`items` is never an array.** A draft-04 tuple is refused wherever the schema reaches a
254
- provider or a collection validator.
205
+ **Model-answer schemas** — the shape of a model's single JSON object — are annotated
206
+ `JSONSchemaType<T>` (checked, not cast), because the answer is parsed straight back into that type.
207
+
208
+ **Record-element schemas** — what the platform stores and puts on the wire — are hand-written and
209
+ cast, because they are re-applied as a Mongo `$jsonSchema`, stricter than Ajv: no `Record<>` maps,
210
+ no `integer` (a stored number is a double), dates as ISO strings.
211
+
212
+ Three rules hold for both; `tests/convert.spec.ts` walks the PACKAGE barrel for each:
213
+
214
+ - **`nullable: true` always carries its `type`.** Ajv refuses `nullable` alone, and a schema that
215
+ fails to compile takes down whatever compiled it (route registration, collection validator).
216
+ - **A nullable ENUM lists `null` among its values**: `enum: [...Object.values(X), null]`. Written
217
+ apart, the type check admits `null` and the enum refuses it, so the field can only be omitted.
218
+ Both kinds of caller send `null`: a provider's structured output for an unset optional, and a
219
+ wire body where `null` MEANS something (`llmMode` — "inherit the profile's setting").
220
+ - **`items` is never an array.** A draft-04 tuple is refused by providers and collection validators.
255
221
 
256
222
  **A schema that validates a STORED document only grows optional.** `ScaffoldPlanSchema` is both a
257
- model-answer schema and the validator of the project card's `scaffold` slot, so a plan written
258
- before a field existed must still pass whenever it is carried into a new revision. Every field
259
- added to it — the hero's `secondary`/`browse` links, `steps`, `labels`, `closing`, a feature's bento
260
- `fragment`, the landing `gate` — is optional in the type and `nullable` in the schema, and a count
261
- the model should respect ("4 tiles", "5–8 chips") lives in the `description` and is clamped in
262
- code, never as `minItems`/`maxItems`. The descriptions are what the planning model reads, so they
263
- state each field's purpose and bounds; `gate.target` is filled by code and described as such.
264
-
265
- **A field that crosses a version skew carries no `enum`.** Users run
266
- `npx -y @owlmeans/viable-mcp@^0.1.18-rc.37` (the moving prerelease tag) against a separately deployed
267
- platform, so `ConnectCapabilitiesSchema.executors.items`
268
- is a bare string: a newer executor kind must stay an unused capability on an older platform, never
269
- a refused session. Apply the same reasoning to anything else a newer connector may send an older
270
- platform, and nowhere else — a closed set is worth more than a tolerant one everywhere both ends
271
- deploy together.
223
+ model-answer schema and the `scaffold` slot's validator, so an older plan must still pass when
224
+ carried into a new revision: every added field is optional in the type and `nullable` in the
225
+ schema, and a count the model should respect lives in the `description` and is clamped in code,
226
+ never as `minItems`/`maxItems`. The descriptions are what the planning model reads; `gate.target`
227
+ is filled by code and described as such.
228
+
229
+ **A field that crosses a version skew carries no `enum`.** Users run `viable-mcp` from a moving
230
+ `npx` range against a separately deployed platform, so `ConnectCapabilitiesSchema.executors.items`
231
+ is a bare string: a newer executor kind is an unused capability on an older platform, never a
232
+ refused session. Apply this to what a newer connector may send an older platform and nowhere else.
272
233
 
273
234
  ## One immutable protocol tree, bound in each runtime
274
235
 
275
236
  `connectProtocols(opts)` is the connector's whole immutable HTTP tree — aliases, paths, methods,
276
- contracts and protocol parents. The platform and the SDK bind their own local materializations
277
- from those declarations, so a path or schema cannot differ across a server and client. Only what
278
- belongs to the DEPLOYMENT is injected: the guard alias, the ownership gate and the paid local-LLM
279
- gate (on `session.openDelegated` alone).
280
-
281
- The tree holds exactly the routes a connector calls, under one base (`/connect` unless the `path`
282
- option says otherwise), and `connect` (aliases) and `connectRef` (typed references) name the same
283
- set:
237
+ contracts, parents. The platform and the SDK bind their own materializations of it; only the
238
+ DEPLOYMENT's parts are injected: the guard alias, the ownership gate, and the paid local-LLM gate
239
+ (on `session.openDelegated` alone). One base (`/connect` unless `path` says otherwise); `connect`
240
+ (aliases) and `connectRef` (typed references) name the same set:
284
241
 
285
242
  | Branch | Routes |
286
243
  |---|---|
@@ -293,263 +250,225 @@ set:
293
250
  | `inquiry` | `answer` POST `/project/:id/inquiry/:inquiryId` |
294
251
  | `pipeline` | `state` GET `/pipeline/:id/:runId`, `resume` POST `/pipeline/:id/:runId/resume` |
295
252
 
296
- There is no socket, capability view, session read or heartbeat, conversion cancel or project
297
- inference-settings route: nothing a connector does calls one. A project's inference modes are the
298
- browser's to set, through the platform's own API — `ConnectProjectSettings`,
299
- `ConnectProjectLlmBody(Schema)` and `ConverterProjectLlmBody(Schema)` stay here as that API's
300
- shapes. Adding a route means adding it here first (alias, declaration, `connectRef` entry), then
301
- binding that named protocol in every runtime that serves or calls it. A route declared on one side
302
- alone is a 404 nobody can explain from the failing end. Keep raw aliases private to declaration modules; consumers receive protocol objects, and a
303
- dynamic adapter reads `.alias` only at its string-addressed boundary.
304
-
305
- The connector tree has NO story routes. A story is a planning card, listed, created, edited,
306
- deleted and started through the planning protocol tree the platform mounts beside the connector
307
- (`makePlanningProtocols` in `@owlmeans/planning`) — one surface for the browser and a connector, so
308
- a story rule cannot hold on one of them only. `ConnectProjectStatus.project` flattens the project
309
- card into the names a parent agent reads (`name` = title, `alias` = code, the three brief bodies)
310
- plus the card's `status` and `intrinsic` as plain strings, and `ConnectConfirmBody` carries the
311
- three brief parts including `designSystem`.
312
-
313
- A project's branding is read and saved at `/project/:id/branding` (`connect.project.branding.get`
314
- GET, `.save` POST) under `base` — the guard and the ownership gate, no paid gate. The save body
315
- (`ConnectProjectBrandingSaveSchema`) is a PATCH of strings with structural bounds only
316
- (`CONNECT_BRANDING_*_MAX`, each equal to its twin in the platform's branding contract); what makes a
317
- value acceptable — non-empty copyright and organization, a legal link that is `https://` or a
318
- same-origin path, a real Google tag id — is the platform's rule, applied to the MERGED record. The
319
- platform credit is never part of either record: hiding it is a paid capability with its own route.
320
-
321
- Long work is read through the domain that owns it: `ConnectProjectStatus`, `ConnectStoryStatus`,
322
- `ConversionStatusView` and `ConnectPipelineState`. Each view composes its current card/record, run,
323
- pending inquiry and `waitingFor` reason; none exposes a generic technical operation identity. Add a
324
- new long-running domain by extending its status view and endpoint, not by adding a parallel polling
325
- vocabulary.
253
+ - No socket, capability view, session read, heartbeat, conversion cancel or inference-settings
254
+ route exists. A project's inference modes are set by the browser through the platform's own API;
255
+ `ConnectProjectSettings`, `ConnectProjectLlmBody(Schema)`, `ConverterProjectLlmBody(Schema)` stay
256
+ here as that API's shapes.
257
+ - A new route is added here first (alias, declaration, `connectRef` entry), then bound in every
258
+ runtime that serves or calls it — a route declared on one side alone is an unexplained 404. Raw
259
+ aliases stay private to declaration modules; consumers receive protocol objects.
260
+ - NO story routes: a story is a planning card, listed, created, edited, deleted and started through
261
+ the planning tree the platform mounts beside the connector (`makePlanningProtocols`).
262
+ `ConnectProjectStatus.project` flattens the project card into a parent agent's names (`name` =
263
+ title, `alias` = code, the three brief bodies) plus `status` and `intrinsic`;
264
+ `ConnectConfirmBody` carries the three brief parts including `designSystem`.
265
+ - Branding routes hang under `base` (guard + ownership gate, no paid gate). The save body
266
+ (`ConnectProjectBrandingSaveSchema`) is a PATCH of strings with structural bounds only
267
+ (`CONNECT_BRANDING_*_MAX`, each equal to its platform twin); value acceptability is the
268
+ platform's rule on the MERGED record. The platform credit is a paid capability with its own route.
269
+ - Long work is read through its domain view — `ConnectProjectStatus`, `ConnectStoryStatus`,
270
+ `ConversionStatusView`, `ConnectPipelineState` — each composing its record, run, pending inquiry
271
+ and `waitingFor` reason; none exposes a generic operation id. A new long-running domain extends
272
+ its view and endpoint, never a parallel polling vocabulary.
326
273
 
327
274
  ## The intent-first hand-off (`./intent`)
328
275
 
329
- A prompt typed on the PUBLIC site (owlmeans.com, a static Astro app that cannot import the platform
330
- repo) reaches the platform through this one subpath, which is why it lives here and not in viable:
331
- the site, the platform's API services (the stash and the pickup may be served by different ones)
332
- and the manager web must agree on every address, schema and step.
333
-
334
- - **Two guest routes and one screen, no guard, no gate, no service.** `makeIntentProtocols()` declares
335
- `stash` (POST `/public/intent`, body `{ prompt 1..8192, consent: const true }` → `{ ref, expiresAt }`),
336
- `pickup` (POST `/public/intent/pickup`, body `{ ref }` where `ref` is exactly `createIdOfLength(24)`
337
- Base58 → `{ prompt }`) and `landing` (`frontend()` at `/start`, `sticky`). A consumer mounts the
338
- tree OUTSIDE any guarded parent — a route inherits every ancestor's guard, so under the account
339
- base a visitor with no account would be refused — and fills `service` itself (the site binds
340
- `landing` with `{ routeOptions: { overrides: { service } } }`, which is also what makes its `url()`
341
- absolute). `consent` is a schema constant so a request without the data-processing confirmation
342
- cannot exist on the wire.
276
+ A prompt typed on the PUBLIC site (a static app that cannot import the platform repo) reaches the
277
+ platform through this subpath: the site, the API services (stash and pickup may be served by
278
+ different ones) and the manager web agree on every address, schema and step. Platform side:
279
+ `/intent-first`.
280
+
281
+ - **Two guest routes and one screen, no guard, no gate, no service.** `stash` POST
282
+ `/public/intent` (`{ prompt 1..INTENT_PROMPT_MAX (8192), consent: const true }` →
283
+ `{ ref, expiresAt }`), `pickup` POST `/public/intent/pickup` (`{ ref }`, exactly
284
+ `INTENT_REF_LENGTH` (24) Base58 → `{ prompt }`), `landing` (`frontend()` at `/start`, `sticky`).
285
+ Mount the tree OUTSIDE any guarded parent (a route inherits every ancestor's guard) and fill
286
+ `service` yourself (the site binds `landing` with `{ routeOptions: { overrides: { service } } }`,
287
+ which also makes its `url()` absolute).
343
288
  - **The prompt never travels in a URL or a flow token.** The server keeps it `INTENT_TTL_SECONDS`
344
- (120) under the unguessable `ref`, and collects it with one `GETDEL` (`pickup`); only `?ref=`
345
- crosses. The flow payload is CSV-joined without escaping and the token is unsigned, so the flow
346
- carries the reference or nothing.
289
+ (120) under the unguessable `ref` and collects it with one `GETDEL`; only `?ref=`
290
+ crosses (the flow payload is unescaped CSV and the token unsigned).
347
291
  - **`intentFlow` is walked on both sides and never becomes the live flow model.** `compose`
348
- (initial, the site) →`handoff`→ `land` (initial, module = the landing) →`review`→ `review`
349
- (module `HOME`), plus the EXPLICIT `land` →`sign-in`→ `sign-in` (module `DISPATCHER`) →`next`→
350
- `review`. The site does `transit('handoff', true, { ref })` and redirects to `land`'s module URL
351
- with the payload as query; the landing enters at `land` fresh, and a signed-out visitor is parked
352
- with `suspendFlow` at `sign-in`, whose `next()` is the home screen. The parameter is `?ref=` —
353
- never `?flow=`, which `web-flow`'s `lazyInit` parses on every page load of an app that registered
354
- the flow service, and never `?intent=`, which the login surrogate window owns.
355
- - **CORS is not declared here.** The routes ride the framework's global `origin: '*'` (no
356
- credentials); `makeIntentProtocols` carries a `TODO(cors)` naming the origins to keep allowed if a
357
- deployment ever restricts them globally.
358
- - **The browser draft is IndexedDB, per origin.** `IntentDraft` (`id`, `ref`, `prompt`, `expiresAt`) is
359
- what the platform's own browser keeps between pickup and the decision (`INTENT_DRAFT_TTL_MS`, 24 h,
360
- checked on read — a client resource has no TTL). The public site cannot write it; that is the whole
361
- reason for the server detour.
362
-
363
- Tests: `tests/intent.spec.ts` (the four declarations and their absence of guards, the schema
364
- accept/reject cases including crafted references, the flow walk both sides and what `suspendFlow`
365
- would persist, the error statuses).
292
+ (initial, the site) →`handoff`→ `land` (initial, the landing) →`review`→ `review` (`HOME`), plus
293
+ the EXPLICIT `land` →`sign-in`→ `sign-in` (`DISPATCHER`) →`next`→ `review`. A signed-out visitor
294
+ is parked with `suspendFlow` at `sign-in`. The parameter is `?ref=` — never `?flow=` (`web-flow`
295
+ parses it on every page load) and never `?intent=` (the login surrogate window owns it).
296
+ - **CORS is not declared here**: the routes ride the global `origin: '*'` (no credentials);
297
+ `makeIntentProtocols` carries a `TODO(cors)` naming the origins to keep if that is restricted.
298
+ - **The browser draft is IndexedDB, per origin.** `IntentDraft` (`id`, `ref`, `prompt`,
299
+ `expiresAt`) is kept by the platform's browser between pickup and decision
300
+ (`INTENT_DRAFT_TTL_MS`, 24 h, checked on read).
366
301
 
367
302
  ## Slot metadata keys: optional means omitted
368
303
 
369
- `SlotMetadata` is what the platform signs and pushes into a slot, and a slot publisher validates it
370
- against its own declared schema — refusing the WHOLE configuration with a 401 when the body carries
371
- a key it does not know. A key added after slots exist is therefore OPTIONAL in the type and OMITTED
372
- from a push while unset: `brandingGoogleTag` (in `metadataConfigs`), `cspSources` (in
373
- `SlotListMetadata`). The build ENVIRONMENT is different — `brandingEnv` always emits every
374
- `BRANDING_ENV_KEYS` entry, `BRANDING_GOOGLE_TAG` as `''` when unset, because the application's own
375
- build reads `''` as "none".
304
+ `SlotMetadata` is what the platform signs and pushes into a slot; the publisher refuses the WHOLE
305
+ configuration with a 401 when the body carries a key its schema does not know. A key added after
306
+ slots exist is therefore OPTIONAL in the type and OMITTED from a push while unset:
307
+ `brandingGoogleTag` (in `metadataConfigs`), `cspSources` (in `SlotListMetadata`). The build
308
+ ENVIRONMENT differs: `brandingEnv` always emits every `BRANDING_ENV_KEYS` entry,
309
+ `BRANDING_GOOGLE_TAG` as `''` when unset.
376
310
 
377
- `metadataConfigs` / `metadataLists` / `metadataSecrets` enumerate what an owner STORES — one
378
- `project-config` / `project-secret` row per key, loaded on every metadata read. `cspSources` is not
379
- an owner setting, so it is declared on the type and kept out of them. The Google tag's CSP hosts
380
- never travel in it: the publisher derives them from `brandingGoogleTag` itself (and from the record a
381
- production build writes), so the tag and the hosts it needs cannot disagree.
311
+ `metadataConfigs` / `metadataLists` / `metadataSecrets` enumerate what an owner STORES (one
312
+ `project-config` / `project-secret` row per key). `cspSources` is not an owner setting, so it is
313
+ on the type only; the Google tag's CSP hosts never travel in it — the publisher derives them from
314
+ `brandingGoogleTag`. Push rules: `/slot-config`.
382
315
 
383
- ## Blueprint types and the case vocabulary
316
+ ## Blueprint types, cases, skill and persona names
384
317
 
385
318
  `src/blueprint/` holds only types and constants. A `Blueprint` has five REQUIRED build layers
386
319
  (`technology`, `stack`, `template`, `createApp`, `packages`) and one OPTIONAL `experience` layer —
387
- what the product should do for its users, changing no dependency and no coder prompt. Read it only
388
- through a helper that answers the default for an absent layer: `landingGatePreferenceOf(blueprint)`
389
- answers `LandingGatePreference.Allow` for no layer, no key or a value this deploy does not know.
390
- An execution carries a `BlueprintRef` — an id, an optional `case` and an override patch — never a
391
- resolved blueprint.
392
-
393
- `BlueprintCase` (`web`, `scalable`, `ai-pipeline`, `ai-agent`, `game`) and `GameKind` are the
394
- vocabulary a project card's `fields.blueprintCase` / `fields.gameKind` carry. What a case MEANS —
395
- the `BLUEPRINT_CASES` table with each case's patch, landing-gate prior and persona skills,
396
- `applyBlueprintCase`, `applyBlueprintPatch` / `freezeBlueprint`, `joinPersonaSkills` and the
397
- classification schema — lives in `@owlmeans/viable` (its `blueprints` / `blueprint-cases` skills).
398
- That table is typed `Record<BlueprintCase, …>`, so a member added here fails to compile there until
399
- it has a row.
400
-
401
- ## Skill and persona names
402
-
403
- `src/skills/` holds two enums and nothing else: `ViableSkill` (prompt-skill aliases) and
404
- `ViablePersona` (who a helper's model is told it is). They are here because a `Blueprint`'s
405
- `stack.skills` / `packages.skills` / `personaSkills` name them. The catalogue behind them — every
406
- skill body (`VIABLE_SKILLS`) and weight (`SKILL_ORDER`), `FRAMEWORK_OWNED_SKILLS` /
407
- `skillsForBlueprint`, each persona's prompt policy (`VIABLE_PERSONAS`), the design house style and
408
- the landing-gate teaching — lives in `@owlmeans/viable` `src/skills/` (its `personas-and-skills`
409
- skill). Adding a member here is half a change: `SKILL_ORDER` and `VIABLE_PERSONAS` are total records
410
- and fail to compile until the new member has a weight or a policy, but `VIABLE_SKILLS` is a list,
411
- and the prompt service skips an alias it cannot resolve — a missing body is a rule no model ever
412
- receives.
320
+ what the product does for its users, changing no dependency and no coder prompt. Read `experience`
321
+ only through a total helper: `landingGatePreferenceOf` (`LandingGatePreference.Allow` for no layer,
322
+ no key or an unknown value) and `tenancyOf`. An execution carries a `BlueprintRef` — `id`,
323
+ optional `case`, optional `tenancy`, an override patch — never a resolved blueprint.
324
+
325
+ `BlueprintCase` (`web`, `scalable`, `ai-pipeline`, `ai-agent`, `game`) and `GameKind` are what
326
+ `fields.blueprintCase` / `fields.gameKind` carry. What a case MEANS (`BLUEPRINT_CASES`,
327
+ `applyBlueprintCase`, `applyBlueprintPatch` / `freezeBlueprint`, `joinPersonaSkills`, the
328
+ classification schema) lives in `@owlmeans/viable` (`/blueprints`, `/blueprint-cases`); that table
329
+ is `Record<BlueprintCase, …>`, so a new member fails to compile there until it has a row.
330
+
331
+ `src/skills/` holds two enums: `ViableSkill` (prompt-skill aliases) and `ViablePersona`, named by
332
+ a `Blueprint`'s `stack.skills` / `packages.skills` / `personaSkills`. The catalogue (`VIABLE_SKILLS`,
333
+ `SKILL_ORDER`, `FRAMEWORK_OWNED_SKILLS` / `skillsForBlueprint`, `VIABLE_PERSONAS`) lives in
334
+ `@owlmeans/viable` (`/personas-and-skills`). A new member is half a change: `SKILL_ORDER` and
335
+ `VIABLE_PERSONAS` fail to compile without it, but `VIABLE_SKILLS` is a list and the prompt service
336
+ skips an unresolved alias — a missing body is a rule no model receives.
413
337
 
414
338
  ## Closed sets that mean something
415
339
 
416
340
  - **`ProjectArea`** — guest `/`, user `/frontoffice`, admin `/admin`, operator `/backoffice`. A
417
- generated product's own roles map onto `user` or `operator`; there is no fifth area. `AREA_PATHS`,
418
- `AREA_ACCESS` and `AREA_TIER` are total over it.
341
+ product's own roles map onto `user` or `operator`; there is no fifth area. `AREA_PATHS`,
342
+ `AREA_ACCESS` and `AREA_TIER` are total over it (`/target-areas`).
343
+ - **`PermissionDefault`** — `none` / `user` / `member` / `owner`, the default class of a generated
344
+ permission (the IAM's `IamDefaultClass` values, `/iam`): evaluated when claims are issued, never
345
+ copied onto rows; `member` / `owner` are the organization being acted in, so they apply only to
346
+ an organization-bound permission.
347
+ - **`AccessBlock`** — a model writes `permissions` (`<resource>--<action>`, optionally
348
+ `@<routeParam>`), `level` and `defaultEnabledPermissions?` (the subset safe for every signed-in
349
+ user). CODE writes `defaults` (`PermissionDefault` per permission name, keyed with the `@` selector
350
+ stripped) and `entityScoped` from the tenancy and the area, and empties
351
+ `defaultEnabledPermissions` in a tenanted area. `AccessBlockSchema` declares only the model keys
352
+ and is pinned byte for byte (`tests/access-schema.spec.ts`); widening it changes every access
353
+ prompt. Per-record kinds and their three names (`<kind>--view` / `--modify` / `--create`) are
354
+ declared by the library's access policy (`/target-tenancy`).
419
355
  - **`TargetLayout` + `TARGET_LAYOUTS`** — the integrity manifest is PER LAYOUT. A volume never
420
- migrates, so a project created before the restructure stays on the legacy tree forever and must
421
- verify **clean**; `TARGET_INTEGRITY_FILES` is the union over layouts so a caller has both probes
422
- before it knows which tree it holds, and an absent layout reads as the CURRENT one.
423
- - **`SubProject`** — a ROLE vocabulary mapped per layout, never joined onto a path. Both
424
- generations arrive on the wire at once, so the enum must stay total over what any live agent may
425
- send, and no role but `Common` may resolve to the `common` directory.
426
- - **`ConversionStage`** — advanced only through `stageAfter` / `canEnter` / `decisionFor`. A stage
427
- transition computed at a call site is how a conversion re-enters a stage it already paid for.
428
- - **`ModerationCategory`** — a wire contract with eight languages of wording behind it. A fifth
356
+ migrates, so a legacy-layout (v1) project stays on its tree and must verify **clean**;
357
+ `TARGET_INTEGRITY_FILES` is the union over layouts, so a caller has both probes before it knows
358
+ its tree, and an absent layout reads as the CURRENT one (`/workload-integrity`).
359
+ - **`SubProject`** — a ROLE vocabulary mapped per layout (`ROLE_DIRS`), never joined onto a path.
360
+ Both generations arrive on the wire, so the enum stays total over what any live agent sends, and
361
+ no role but `Common` resolves to the `common` directory.
362
+ - **`ConversionStage`** — advanced only through `stageAfter` / `canEnter` / `decisionFor`; a
363
+ transition computed at a call site re-enters a stage already paid for.
364
+ - **`ModerationCategory`** — a wire contract with eight languages of wording behind it; a fifth
429
365
  shape is PHRASED into one of the four, never added.
430
366
 
431
- ## The conversion vocabulary is shared with three executors that walk the same tree
367
+ ## The conversion vocabulary is shared by three executors
432
368
 
433
- The census, listing and relocation commands are one contract with three implementations — the
434
- SDK's local executor, the publisher's file helper, and the library's in-process helper — so
435
- anything they could disagree about is a constant HERE rather than a matching local copy:
436
- `CENSUS_SKIP_DIRS` (`node_modules`, `.git` — and deliberately not `dist`/`build`/`.next`, ordinary
437
- directory names an origin may keep sources in), `SOURCE_LIST_EXCLUSIONS` (the metadata directories
438
- plus `CONVERTED_ORIGIN_DIR`), `BINARY_PROBE_BYTES`, `CENSUS_MAX_HEAD_BYTES`, `RELOCATE_ALWAYS_KEEP`.
439
- The one thing they are allowed to differ about is stated rather than inherited: the platform's two
440
- keep what a volume it owns must not lose, the SDK's keeps what a DEVELOPER owns (`.viable`, the two
441
- `.env` files).
369
+ The census, listing and relocation commands have three implementations — the SDK's local executor,
370
+ the publisher's file helper, the library's in-process helper — so whatever they could disagree
371
+ about is a constant HERE: `CENSUS_SKIP_DIRS` (`node_modules`, `.git` — never `dist`/`build`/`.next`,
372
+ which an origin may keep sources in), `SOURCE_LIST_EXCLUSIONS` (the metadata directories plus
373
+ `CONVERTED_ORIGIN_DIR`), `BINARY_PROBE_BYTES`, `CENSUS_MAX_HEAD_BYTES`, `RELOCATE_ALWAYS_KEEP`. The
374
+ one allowed difference is stated: the platform's two keep what a volume it owns must not lose, the
375
+ SDK's keeps what a DEVELOPER owns (`.viable`, the two `.env` files).
442
376
 
443
- `docs/conversion/` is likewise addressed only through the exported path builders
444
- (`CONVERSION_*_FILE`, `conversionStoryDoc`, `conversionSeedDoc`) — a conversion's own artifacts are
445
- read back by the purge, and a path spelled at a call site is a file the purge leaves behind.
377
+ `docs/conversion/` is addressed only through the path builders (`CONVERSION_*_FILE`,
378
+ `conversionStoryDoc`, `conversionSeedDoc`) — the purge reads them back, and a path spelled at a
379
+ call site is a file the purge leaves behind.
446
380
 
447
- ## The inquiry vocabulary is a deliberate COPY, and the ceiling is not
381
+ ## The inquiry vocabulary is a deliberate COPY; the ceiling is not
448
382
 
449
383
  `ConnectInquiryKind` / `InquiryPayload` / `InquiryAnswerPayload` mirror `@owlmeans/llm-common`'s
450
- `Inquiry` family, renamed so both vocabularies can be imported into one file and so the platform's API services,
451
- which do not depend on the model runtime, stay free of it. Values are byte-identical, so the
452
- platform's mapper is a widening rather than a translation table, and a test pins that — the same
453
- arrangement `ModelTask` has with `DelegatedTask`.
454
-
455
- The CEILING is not copied twice over: `CONNECT_INQUIRY_MAX_TEXT` equals
456
- `DEFAULT_INQUIRY_ANSWER_CHARS` and must stay equal, and `./convert`'s own
457
- `INQUIRY_STATE_TEXT_CHARS` — what a pipeline STATE may keep of an answer's prose, the rest going to
458
- `docs/conversion/inquiries.md` — equals its twin of the same name there. Two ceilings for one value means the layer with the larger one
459
- truncates silently at the smaller, and the caller records an assumption about an answer the person
460
- actually gave. Never introduce a local cap; import the one that exists.
384
+ `Inquiry` family under other names, so both import into one file and the API services stay free of
385
+ the model runtime. Values are byte-identical (the platform's mapper is a widening; a test pins it),
386
+ as `ModelTask` is with `DelegatedTask`.
387
+
388
+ The CEILING exists once: `CONNECT_INQUIRY_MAX_TEXT` equals `DEFAULT_INQUIRY_ANSWER_CHARS`, and
389
+ `./convert`'s `INQUIRY_STATE_TEXT_CHARS` (what a pipeline STATE keeps of an answer; the rest goes
390
+ to `docs/conversion/inquiries.md`) equals its namesake there. Two ceilings for one value truncate
391
+ silently at the smaller; never introduce a local cap.
461
392
 
462
393
  ## Errors: declared here, phrased where they are read
463
394
 
464
395
  `ConnectError` and its family (`ConnectSessionNotFound`, `ConnectSessionGone`, `ConnectOpTimeout`,
465
396
  `ConnectOpRefused`, `LocalSlotUnsupported`, `ConnectOpUnknown`, `ConnectOutOfCredits`,
466
- `ConnectConsentRequired`) are `ResilientError` classes with markers under `viable-connect:`. The two
467
- refusals a connector turns into words for a person pack their fields into the message (only `type`
468
- and `message` survive a marshal) and rebuild them in `finalizeUnmarshal()`: `ConnectOutOfCredits`
469
- `out-of-credits:<gate>:<requiredUsd>:<balanceUsd>:<encodeURIComponent(topUpUrl)>` →
470
- `gate`, `requiredUsd`, `balanceUsd`, `topUpUrl`; `ConnectConsentRequired`
471
- `consent-required:<gate>:<deadline epoch ms | 0>:<encodeURIComponent(consentUrl)>` → `gate`,
472
- `deadline?` (the latest withdrawal deadline waiting for consent; `0` = unknown), `consentUrl` —
473
- build either with its `static encode(...)`. The deadline is epoch milliseconds and the URL goes
474
- last because an ISO date and a URL both contain colons. `ConnectConsentRequired` is the connector's
475
- face of the EU spend consent (`@owlmeans/payment` `PerformanceConsentRequired` on the web): only a
476
- PERSON can give it, in the browser at `consentUrl`. `ConnectSessionGone` is registered FATAL on the agent side: a run
477
- whose executor has gone away must stop at once rather than spend a retry ladder, and the step fails
478
- as an OUTCOME so the run row records where it stopped and `pipeline.resume` picks it up when a
479
- connector returns.
397
+ `ConnectConsentRequired`) are `ResilientError` classes with `viable-connect:` markers. The two
398
+ refusals a connector phrases for a person pack their fields into the message (only `type` and
399
+ `message` survive a marshal), are built with `static encode(...)` and rebuilt in
400
+ `finalizeUnmarshal()`:
401
+
402
+ - `ConnectOutOfCredits` — `out-of-credits:<gate>:<requiredUsd>:<balanceUsd>:<encodeURIComponent(topUpUrl)>`;
403
+ - `ConnectConsentRequired` — `consent-required:<gate>:<deadline epoch ms | 0>:<encodeURIComponent(consentUrl)>`
404
+ (`0` = unknown; epoch ms and the URL last because ISO dates and URLs contain colons). It is the
405
+ connector's face of the EU spend consent (`PerformanceConsentRequired` on the web, `/payment`):
406
+ only a PERSON gives it, in the browser at `consentUrl`.
407
+
408
+ `ConnectSessionGone` is registered FATAL on the agent side: the step fails as an OUTCOME, so the
409
+ run row records where it stopped and `pipeline.resume` picks it up when a connector returns.
480
410
 
481
411
  The project and story refusals — `ProjectNotFound`, `ProjectPermissionError`,
482
- `ProjectStoryNotFound`, `ProjectStoryMissconfigured`, `ProjectAgentOccupied` and the bases they
483
- extend (`ProjectResourceError`, `ProjectStoryError`, `ProjectError`, `ProjectAgentError`) — ARE
484
- declared here, because the viable planning plugin throws them from a process-neutral package.
485
- Their type names and `viable-project:` markers are wire contracts. The platform re-exports the
486
- whole family and never redeclares a base: a class is unmarshalled by type name with the last
487
- registration winning, so a second declaration replaces this one and `instanceof` stops matching.
412
+ `ProjectStoryNotFound`, `ProjectStoryMissconfigured`, `ProjectAgentOccupied` and their bases
413
+ (`ProjectResourceError`, `ProjectStoryError`, `ProjectError`, `ProjectAgentError`) — are declared
414
+ here because the viable planning plugin throws them from a process-neutral package. Type names and
415
+ `viable-project:` markers are wire contracts. The platform re-exports the family and never
416
+ redeclares a base: unmarshalling is by type name with the last registration winning, so a second
417
+ declaration breaks `instanceof`.
488
418
 
489
- Every refusal here declares its HTTP status on its leaf class (the `error` skill's principle), and
490
- `tests/error-status.spec.ts` refuses an exported class whose status was not decided:
419
+ Every refusal declares its HTTP status on its leaf class (`/error`); `tests/error-status.spec.ts`
420
+ refuses an exported class whose status was not decided:
491
421
 
492
422
  | Status | Classes |
493
423
  |---|---|
494
424
  | 402 | `ConnectOutOfCredits` |
495
- | 428 | `ConnectConsentRequired` (a precondition only a person can meet) |
425
+ | 428 | `ConnectConsentRequired` |
496
426
  | 404 | `ProjectNotFound`, `ProjectStoryNotFound`, `ConnectSessionNotFound`, `ConnectOpUnknown` |
497
- | 409 | `ProjectAgentOccupied`, `ProjectStoryMissconfigured`, `ConnectSessionGone` (no connector attached), `LocalSlotUnsupported` (the project's target) |
498
- | 422 | `ConnectOpRefused` (the connector refused the operation) |
427
+ | 409 | `ProjectAgentOccupied`, `ProjectStoryMissconfigured`, `ConnectSessionGone` (no connector attached), `LocalSlotUnsupported` |
428
+ | 422 | `ConnectOpRefused` |
499
429
  | none (500) | the bases, `ConnectOpTimeout` (a peer's fault), `ProjectPermissionError` (never thrown; a permission refusal extends `AuthForbidden`) |
500
430
 
501
- The platform's other refusals — conversion, moderation, reserved names, integrity — are declared in
502
- the product repo, not here, so a consumer that cannot `instanceof` them matches by MARKER instead:
503
- `@owlmeans/viable-sdk`'s `REFUSALS` map and the manager's `useErrorPhrase` read the same substrings,
504
- which is what stops one refusal being phrased two ways. When a marker changes, both readers change
505
- with it.
431
+ The platform's other refusals (conversion, moderation, reserved names, integrity) are declared in
432
+ the product repo, so a consumer matches them by MARKER: `@owlmeans/viable-sdk`'s `REFUSALS` map and
433
+ the manager's `useErrorPhrase` read the same substrings. A marker change changes both readers.
506
434
 
507
435
  ## Tests
508
436
 
509
- `bun test ./tests` — offline. `planning.spec.ts` (the story and project flows through the planning
510
- helpers — status keys as literals, `failed` intrinsically planned, the transition table — the type
511
- declarations, slots with no co-located category, code policies, reserved types outside `cardTypes`,
512
- the field schemas accepting `null` and refusing an undeclared field or a value outside a closed
513
- set, the landing fields and the landing sentence, the card helpers, the `follows` anchor, and the
514
- refusals' type names surviving a marshal), `scaffold.spec.ts` (an old-shape and a new-shape plan
515
- both passing the schema and the `scaffold` slot, `null` optionals accepted, no `minItems`),
516
- `blueprint.spec.ts` (`landingGatePreferenceOf` — the default for an absent layer or an unknown
517
- value), `branding.spec.ts` (the build env and the metadata vocabulary),
518
- `connect-entrypoints.spec.ts` (the tree's protocol count, every route's method and path, no
519
- socket, the alias table and `connectRef` naming the tree's routes, the paid gate on the delegated
520
- session alone, no story route, the branding routes and their save body),
521
- `convert.spec.ts` (the three structural walks over the barrel, the
522
- conversion schemas compiling, a nullable enum accepting `null` under Ajv while still refusing an
523
- unknown member, the census classifiers and the stage transitions), `connect-convert.spec.ts` (the
524
- conversion routes at their paths and methods, hanging under the connector base and carrying no paid
525
- gate; capabilities accepting an executor kind this platform has never heard of; the answer and
526
- resume bodies), `design.spec.ts` (the design aggregate, staleness ranking, and the design schema
527
- refusing an undeclared field or an area outside the closed set, and `userStoryOfDesign`),
528
- `error-status.spec.ts` (every exported refusal's declared status, and its class and status after a
529
- marshal round trip), `connect-errors.spec.ts` (the packed fields of `ConnectOutOfCredits` and
530
- `ConnectConsentRequired` fresh and after a round trip, an unknown deadline as `0`).
437
+ `bun test ./tests` — offline.
438
+
439
+ | File | Pins |
440
+ |---|---|
441
+ | `planning.spec.ts` | the two flows and transition tables, type declarations, slots, code policies, reserved types outside `cardTypes`, field schemas (null optionals, refused strays and closed-set values), landing fields and sentence, the tenancy decision, card helpers, the `follows` anchor, refusal type names after a marshal |
442
+ | `tenancy.spec.ts` | `NO_TENANCY` frozen, `tenancyOf` defaults and the literal-`true` rule, `tenantedArea` |
443
+ | `access-schema.spec.ts` | the model-facing access schema: model keys only, byte-identical |
444
+ | `scaffold.spec.ts` | old- and new-shape plans passing the schema and slot, `null` optionals, no `minItems` |
445
+ | `blueprint.spec.ts` · `branding.spec.ts` | `landingGatePreferenceOf` defaults · the build env and metadata vocabulary |
446
+ | `connect-entrypoints.spec.ts` · `connect-convert.spec.ts` | every route's method and path, aliases = `connectRef`, the paid gate on the delegated session alone, no socket or story route, branding body · conversion routes, an unknown executor kind accepted |
447
+ | `convert.spec.ts` | the three structural walks over the barrel, nullable enums under Ajv, census classifiers, stage transitions |
448
+ | `design.spec.ts` | the design aggregate, staleness ranking, schema refusals, `userStoryOfDesign` |
449
+ | `error-status.spec.ts` · `connect-errors.spec.ts` | declared statuses through a marshal · packed refusal fields fresh and after a round trip |
450
+ | `intent.spec.ts` | the four declarations without guards, schema cases incl. crafted refs, the flow walk and `suspendFlow` payload, error statuses |
451
+ | `presentation.spec.ts` | the agent-output classifier (`/agent-presentation`) |
531
452
 
532
453
  ## Depends On
533
454
 
534
- - `@owlmeans/planning` — the workcard contracts the planning module declares its types over
455
+ - `@owlmeans/planning` — the workcard contracts the planning module declares over
535
456
  - `@owlmeans/resource` — the `ResourceError` base of the project refusals
536
457
  - `@owlmeans/entrypoint`, `@owlmeans/route` — the entrypoint declarations
537
458
  - `@owlmeans/error` — the `Connect*` error family
538
459
  - `@owlmeans/llm-common` — `ExecutionEffort`/`ExecutionLevel`, `LlmPurpose`, the spectator
539
460
  contracts, and the inquiry ceilings this package's copies are pinned to
540
- - `@owlmeans/agent-common` — the run and pipeline contracts a conversion's runs are declared against
541
- - `@owlmeans/flow`, `@owlmeans/auth`, `@owlmeans/context` — `./intent` only: `ShallowFlow`/`UnknownFlow`,
542
- the `DISPATCHER` alias and the `HOME` alias its flow steps address
461
+ - `@owlmeans/agent-common` — the run and pipeline contracts (re-exported `AgentRunStatus`)
462
+ - `@owlmeans/flow`, `@owlmeans/auth`, `@owlmeans/context` — `./intent` only: `ShallowFlow`, the
463
+ `DISPATCHER` and `HOME` aliases its flow steps address
543
464
 
544
465
  ## Related
545
466
 
546
- - [[viable-sdk]] — the connector SDK written entirely against these contracts
547
- - [[viable-mcp]] — the npx stdio server built on that SDK
548
- - [[flow]] · [[client-flow]] — the model `intentFlow` is walked with, and `suspendFlow`, which parks it across sign-in
549
- - [[inquiry]] — the primitive `InquiryPayload` mirrors, and the one answer ceiling
550
- - [[llm-common]] — the contracts half of the model runtime
551
- - [[planning]] — the workcard model, flows, fold and protocol tree the planning module builds on
552
- - The DOMAIN rules for what these shapes mean — target areas and navigation, the scaffold, target
553
- integrity, the metadata files, the converter — live in the downstream repos that implement them
554
- (`target-areas`, `scaffolding`, `workload-integrity`, `viable-metadata`, `converter`). This skill
555
- owns the CONTRACT: how a name is declared, and what refuses it.
467
+ - [[viable-sdk]] · [[viable-mcp]] — the connector SDK written against these contracts, and its npx
468
+ stdio server
469
+ - [[flow]] · [[client-flow]] — the model `intentFlow` is walked with, and `suspendFlow`
470
+ - [[inquiry]] · [[llm-common]] — the primitive `InquiryPayload` mirrors; the model runtime's contracts
471
+ - [[planning]] — the workcard model the planning module builds on
472
+ - DOMAIN meaning lives downstream (`target-areas`, `target-tenancy`, `scaffolding`,
473
+ `workload-integrity`, `viable-metadata`, `converter`); this skill owns the CONTRACT — how a name
474
+ is declared and what refuses it.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@owlmeans/viable-common",
3
- "version": "0.0.40",
3
+ "version": "0.0.41",
4
4
  "license": "MIT",
5
5
  "description": "Runtime-free contracts of the OwlMeans Viable platform — the analysis, design and metadata shapes of a generated project, its target-shape manifest, the slot command vocabulary, the connector protocol and the conversion vocabulary, and the intent-first hand-off from the public site to the platform.",
6
6
  "type": "module",
@@ -66,14 +66,14 @@
66
66
  "typescript": "^7.0.2"
67
67
  },
68
68
  "dependencies": {
69
- "@owlmeans/agent-common": "^0.1.18-rc.44",
70
- "@owlmeans/auth": "^0.1.18-rc.37",
69
+ "@owlmeans/agent-common": "^0.1.18-rc.45",
70
+ "@owlmeans/auth": "^0.1.18-rc.38",
71
71
  "@owlmeans/context": "^0.1.18-rc.32",
72
- "@owlmeans/entrypoint": "^0.1.18-rc.38",
72
+ "@owlmeans/entrypoint": "^0.1.18-rc.39",
73
73
  "@owlmeans/error": "^0.1.18-rc.36",
74
- "@owlmeans/flow": "^0.1.18-rc.41",
74
+ "@owlmeans/flow": "^0.1.18-rc.42",
75
75
  "@owlmeans/llm-common": "^0.1.18-rc.37",
76
- "@owlmeans/planning": "^0.1.18-rc.14",
76
+ "@owlmeans/planning": "^0.1.18-rc.15",
77
77
  "@owlmeans/resource": "^0.1.18-rc.37",
78
78
  "@owlmeans/route": "^0.1.18-rc.33"
79
79
  },