@owlmeans/viable-common 0.0.18 → 0.0.20

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.
Files changed (120) hide show
  1. package/README.md +3 -3
  2. package/agent-meta/manifest.json +2 -2
  3. package/agent-meta/skills/agent-presentation/SKILL.md +2 -0
  4. package/agent-meta/skills/viable-common/SKILL.md +195 -10
  5. package/build/ba/consts.d.ts +2 -3
  6. package/build/ba/consts.d.ts.map +1 -1
  7. package/build/ba/consts.js +2 -3
  8. package/build/ba/consts.js.map +1 -1
  9. package/build/ba/helpers.d.ts +2 -1
  10. package/build/ba/helpers.d.ts.map +1 -1
  11. package/build/ba/helpers.js +3 -2
  12. package/build/ba/helpers.js.map +1 -1
  13. package/build/ba/types.d.ts +17 -2
  14. package/build/ba/types.d.ts.map +1 -1
  15. package/build/blueprint/case.js +3 -3
  16. package/build/connect/consts.d.ts +5 -8
  17. package/build/connect/consts.d.ts.map +1 -1
  18. package/build/connect/consts.js +5 -8
  19. package/build/connect/consts.js.map +1 -1
  20. package/build/connect/entrypoints.d.ts +1 -43
  21. package/build/connect/entrypoints.d.ts.map +1 -1
  22. package/build/connect/entrypoints.js +1 -18
  23. package/build/connect/entrypoints.js.map +1 -1
  24. package/build/connect/index.d.ts +1 -0
  25. package/build/connect/index.d.ts.map +1 -1
  26. package/build/connect/index.js +1 -0
  27. package/build/connect/index.js.map +1 -1
  28. package/build/connect/jobs.d.ts +25 -0
  29. package/build/connect/jobs.d.ts.map +1 -0
  30. package/build/connect/jobs.js +29 -0
  31. package/build/connect/jobs.js.map +1 -0
  32. package/build/connect/references.d.ts +1 -40
  33. package/build/connect/references.d.ts.map +1 -1
  34. package/build/connect/references.js +0 -8
  35. package/build/connect/references.js.map +1 -1
  36. package/build/connect/schemas.d.ts +1 -7
  37. package/build/connect/schemas.d.ts.map +1 -1
  38. package/build/connect/schemas.js +1 -25
  39. package/build/connect/schemas.js.map +1 -1
  40. package/build/connect/types.d.ts +30 -45
  41. package/build/connect/types.d.ts.map +1 -1
  42. package/build/design/consts.d.ts +0 -2
  43. package/build/design/consts.d.ts.map +1 -1
  44. package/build/design/consts.js +0 -2
  45. package/build/design/consts.js.map +1 -1
  46. package/build/design/helpers.d.ts +6 -2
  47. package/build/design/helpers.d.ts.map +1 -1
  48. package/build/design/helpers.js +6 -2
  49. package/build/design/helpers.js.map +1 -1
  50. package/build/design/types.d.ts +12 -11
  51. package/build/design/types.d.ts.map +1 -1
  52. package/build/execution/types.d.ts +11 -0
  53. package/build/execution/types.d.ts.map +1 -1
  54. package/build/index.d.ts +1 -0
  55. package/build/index.d.ts.map +1 -1
  56. package/build/index.js +1 -0
  57. package/build/index.js.map +1 -1
  58. package/build/planning/consts.d.ts +141 -0
  59. package/build/planning/consts.d.ts.map +1 -0
  60. package/build/planning/consts.js +170 -0
  61. package/build/planning/consts.js.map +1 -0
  62. package/build/planning/errors.d.ts +64 -0
  63. package/build/planning/errors.d.ts.map +1 -0
  64. package/build/planning/errors.js +99 -0
  65. package/build/planning/errors.js.map +1 -0
  66. package/build/planning/flows.d.ts +34 -0
  67. package/build/planning/flows.d.ts.map +1 -0
  68. package/build/planning/flows.js +174 -0
  69. package/build/planning/flows.js.map +1 -0
  70. package/build/planning/helpers.d.ts +54 -0
  71. package/build/planning/helpers.d.ts.map +1 -0
  72. package/build/planning/helpers.js +101 -0
  73. package/build/planning/helpers.js.map +1 -0
  74. package/build/planning/index.d.ts +7 -0
  75. package/build/planning/index.d.ts.map +1 -0
  76. package/build/planning/index.js +6 -0
  77. package/build/planning/index.js.map +1 -0
  78. package/build/planning/schemas.d.ts +23 -0
  79. package/build/planning/schemas.d.ts.map +1 -0
  80. package/build/planning/schemas.js +65 -0
  81. package/build/planning/schemas.js.map +1 -0
  82. package/build/planning/types.d.ts +70 -0
  83. package/build/planning/types.d.ts.map +1 -0
  84. package/build/planning/types.js +2 -0
  85. package/build/planning/types.js.map +1 -0
  86. package/build/scaffold/schemas.d.ts.map +1 -1
  87. package/build/scaffold/schemas.js +7 -2
  88. package/build/scaffold/schemas.js.map +1 -1
  89. package/build/scaffold/types.d.ts +5 -1
  90. package/build/scaffold/types.d.ts.map +1 -1
  91. package/package.json +8 -6
  92. package/src/ba/consts.ts +2 -3
  93. package/src/ba/helpers.ts +3 -2
  94. package/src/ba/types.ts +17 -2
  95. package/src/blueprint/case.ts +3 -3
  96. package/src/connect/consts.ts +5 -8
  97. package/src/connect/entrypoints.ts +2 -41
  98. package/src/connect/index.ts +1 -0
  99. package/src/connect/jobs.ts +40 -0
  100. package/src/connect/references.ts +1 -22
  101. package/src/connect/schemas.ts +2 -29
  102. package/src/connect/types.ts +30 -51
  103. package/src/design/consts.ts +0 -3
  104. package/src/design/helpers.ts +6 -2
  105. package/src/design/types.ts +12 -11
  106. package/src/execution/types.ts +11 -0
  107. package/src/index.ts +1 -0
  108. package/src/planning/consts.ts +182 -0
  109. package/src/planning/errors.ts +117 -0
  110. package/src/planning/flows.ts +204 -0
  111. package/src/planning/helpers.ts +133 -0
  112. package/src/planning/index.ts +6 -0
  113. package/src/planning/schemas.ts +70 -0
  114. package/src/planning/types.ts +75 -0
  115. package/src/scaffold/schemas.ts +7 -2
  116. package/src/scaffold/types.ts +10 -1
  117. package/tests/branding.spec.ts +37 -0
  118. package/tests/connect-entrypoints.spec.ts +35 -3
  119. package/tests/design.spec.ts +3 -3
  120. package/tests/planning.spec.ts +356 -0
@@ -0,0 +1,40 @@
1
+ import type { ConnectJobKind } from './consts.js'
2
+
3
+ /**
4
+ * The separator a job id is joined with.
5
+ *
6
+ * `~`, because every other separator in play is already spoken for: a route alias is
7
+ * colon-delimited and so is every run id (`init:<projectId>`, `story:<storyId>`), so a job id
8
+ * built with one could not be split back apart.
9
+ */
10
+ export const JOB_SEPARATOR = '~'
11
+
12
+ /**
13
+ * A job's id: its kind, the project card it belongs to, and the subject it is about.
14
+ *
15
+ * The suffix is a CARD id for a story job and a run id for a pipeline job — never a story code.
16
+ * Declared here rather than by whoever answers the job, because the SDK composes the id it then
17
+ * polls for: two spellings of one id is a job nobody can find.
18
+ */
19
+ export const jobIdOf = (kind: ConnectJobKind, projectId: string, suffix?: string): string =>
20
+ [kind, projectId, ...(suffix != null ? [suffix] : [])].join(JOB_SEPARATOR)
21
+
22
+ export interface ParsedJobId {
23
+ kind: ConnectJobKind
24
+ projectId: string
25
+ suffix?: string
26
+ }
27
+
28
+ /** Split a job id back into what {@link jobIdOf} composed it from. */
29
+ export const parseJobId = (jobId: string): ParsedJobId => {
30
+ const [kind, projectId, ...rest] = jobId.split(JOB_SEPARATOR)
31
+ // A suffix may carry the separator back if one ever ends up in a card or run id, so the tail is
32
+ // rejoined rather than taken as its first segment.
33
+ const suffix = rest.length > 0 ? rest.join(JOB_SEPARATOR) : undefined
34
+
35
+ return {
36
+ kind: kind as ConnectJobKind,
37
+ projectId: projectId ?? '',
38
+ ...(suffix != null ? { suffix } : {}),
39
+ }
40
+ }
@@ -10,8 +10,7 @@ import type {
10
10
  ConnectModifyBody, ConnectOpSubmission, ConnectPipelineParams, ConnectPipelineResumeBody,
11
11
  ConnectPipelineState, ConnectProjectLlmBody, ConnectProjectSettings, ConnectProjectStatus,
12
12
  ConnectProjectSummary, ConnectSessionOpen, ConnectSessionParams, ConnectSessionView,
13
- ConnectStoryBody, ConnectStoryDeletion, ConnectStoryItem, ConnectStoryList, ConnectStoryMutation,
14
- ConnectStoryQuery, ConnectWaitQuery, ConversionStatusView, ConvertCheck,
13
+ ConnectWaitQuery, ConversionStatusView, ConvertCheck,
15
14
  } from './types.js'
16
15
 
17
16
  type ConnectReference<Request extends RequestShape, Response> =
@@ -47,16 +46,6 @@ export interface ConnectReferences {
47
46
  }, ConnectProjectSettings>
48
47
  job: ConnectReference<{ params: ConnectJobParams, query: ConnectWaitQuery }, ConnectJob>
49
48
  }
50
- story: {
51
- list: ConnectReference<{ params: { id: string }, query: ConnectStoryQuery }, ConnectStoryList>
52
- get: ConnectReference<{ params: { id: string, storyId: string } }, ConnectStoryItem>
53
- create: ConnectReference<{ params: { id: string }, body: ConnectStoryBody }, ConnectStoryMutation>
54
- update: ConnectReference<{
55
- params: { id: string, storyId: string }, body: ConnectStoryBody
56
- }, ConnectStoryMutation>
57
- delete: ConnectReference<{ params: { id: string, storyId: string } }, ConnectStoryDeletion>
58
- develop: ConnectReference<{ params: { id: string, storyId: string } }, ConnectJob>
59
- }
60
49
  files: {
61
50
  list: ConnectReference<{ params: { id: string } }, string[]>
62
51
  }
@@ -139,16 +128,6 @@ export const connectRef: ConnectReferences = {
139
128
  params: { id: string, inquiryId: string }, body: ConnectInquiryAnswerBody
140
129
  }, unknown>(connect.inquiry.answer),
141
130
  },
142
- story: {
143
- list: entrypointRef<{ params: { id: string }, query: ConnectStoryQuery }, ConnectStoryList>(connect.story.list),
144
- get: entrypointRef<{ params: { id: string, storyId: string } }, ConnectStoryItem>(connect.story.get),
145
- create: entrypointRef<{ params: { id: string }, body: ConnectStoryBody }, ConnectStoryMutation>(connect.story.create),
146
- update: entrypointRef<{
147
- params: { id: string, storyId: string }, body: ConnectStoryBody
148
- }, ConnectStoryMutation>(connect.story.update),
149
- delete: entrypointRef<{ params: { id: string, storyId: string } }, ConnectStoryDeletion>(connect.story.delete),
150
- develop: entrypointRef<{ params: { id: string, storyId: string } }, ConnectJob>(connect.story.develop),
151
- },
152
131
  files: {
153
132
  list: entrypointRef<{ params: { id: string } }, string[]>(connect.files.list),
154
133
  },
@@ -9,7 +9,7 @@ import type {
9
9
  ConnectAttachBody, ConnectConfirmBody, ConnectConvertCreateBody, ConnectConvertProceedBody,
10
10
  ConnectCreateBody, ConnectJobParams, ConnectLlmBody, ConnectModifyBody, ConnectPipelineParams,
11
11
  ConnectPipelineResumeBody, ConnectProjectLlmBody, ConnectSession, ConnectSessionOpen,
12
- ConnectSessionParams, ConnectStoryBody, ConnectStoryQuery, ConnectWaitQuery
12
+ ConnectSessionParams, ConnectWaitQuery
13
13
  } from './types.js'
14
14
 
15
15
  /**
@@ -26,7 +26,6 @@ import type {
26
26
  */
27
27
 
28
28
  const idValue = { type: 'string', minLength: 1, maxLength: 128 } as const
29
- const textValue = { type: 'string', minLength: 1, maxLength: 65536 } as const
30
29
 
31
30
  export const ConnectCapabilitiesSchema = {
32
31
  type: 'object',
@@ -156,13 +155,6 @@ export const ConnectProjectIdSchema = {
156
155
  additionalProperties: false,
157
156
  } as JSONSchemaType<{ id: string }>
158
157
 
159
- export const ConnectStoryParamsSchema = {
160
- type: 'object',
161
- properties: { id: idValue, storyId: idValue },
162
- required: ['id', 'storyId'],
163
- additionalProperties: false,
164
- } as JSONSchemaType<{ id: string, storyId: string }>
165
-
166
158
  export const ConnectOpParamsSchema = {
167
159
  type: 'object',
168
160
  properties: { sessionId: idValue, opId: idValue },
@@ -177,19 +169,6 @@ export const ConnectJobParamsSchema = {
177
169
  additionalProperties: false,
178
170
  } as JSONSchemaType<ConnectJobParams>
179
171
 
180
- export const ConnectStoryQuerySchema = {
181
- type: 'object',
182
- properties: {
183
- page: { type: 'integer', minimum: 0, nullable: true },
184
- size: { type: 'integer', minimum: 1, maximum: 100, nullable: true },
185
- status: { type: 'string', maxLength: 32, nullable: true },
186
- area: { type: 'string', maxLength: 32, nullable: true },
187
- q: { type: 'string', maxLength: 256, nullable: true },
188
- },
189
- required: [],
190
- additionalProperties: false,
191
- } as JSONSchemaType<ConnectStoryQuery>
192
-
193
172
  export const ConnectCreateBodySchema = {
194
173
  type: 'object',
195
174
  properties: {
@@ -207,6 +186,7 @@ export const ConnectConfirmBodySchema = {
207
186
  description: { type: 'string', maxLength: 16384, nullable: true },
208
187
  specification: { type: 'string', maxLength: 262144, nullable: true },
209
188
  vision: { type: 'string', maxLength: 16384, nullable: true },
189
+ designSystem: { type: 'string', maxLength: 262144, nullable: true },
210
190
  target: { type: 'string', enum: [...Object.values(ConnectTarget), null], nullable: true },
211
191
  },
212
192
  required: [],
@@ -220,13 +200,6 @@ export const ConnectModifyBodySchema = {
220
200
  additionalProperties: false,
221
201
  } as JSONSchemaType<ConnectModifyBody>
222
202
 
223
- export const ConnectStoryBodySchema = {
224
- type: 'object',
225
- properties: { story: textValue },
226
- required: ['story'],
227
- additionalProperties: false,
228
- } as JSONSchemaType<ConnectStoryBody>
229
-
230
203
  export const ConnectAttachBodySchema = {
231
204
  type: 'object',
232
205
  properties: {
@@ -86,15 +86,24 @@ export interface ConnectSessionView {
86
86
  * A derived view of "what the platform is doing for this project right now".
87
87
  *
88
88
  * Never stored. It is composed per request from the project lock, the slot record, the story
89
- * record, the latest pipeline run row and the operations queued for the project — the same facts
89
+ * card, the latest pipeline run row and the operations queued for the project — the same facts
90
90
  * the manager UI reads, arranged for a caller that has one question ("may I stop waiting?") and
91
91
  * one follow-up ("what do I call next?").
92
+ *
93
+ * Its `id` is composed and parsed only through `jobIdOf` / `parseJobId`.
92
94
  */
93
95
  export interface ConnectJob {
94
96
  id: string
95
97
  kind: ConnectJobKind
96
98
  status: ConnectJobStatus
99
+ /** The project CARD id. */
97
100
  projectId: string
101
+ /**
102
+ * The story CARD id — never the story's code.
103
+ *
104
+ * The name is kept because a parent agent reads it: a wire field name is that agent's
105
+ * vocabulary and is never renamed, only re-documented.
106
+ */
98
107
  storyId?: string
99
108
  runId?: string
100
109
  /** The pipeline step in flight, when a run row says. */
@@ -137,43 +146,27 @@ export interface ConnectWaitQuery {
137
146
  wait?: number
138
147
  }
139
148
 
140
- /** Paging and filtering for the story list a connector reads. */
141
- export interface ConnectStoryQuery {
142
- page?: number
143
- size?: number
144
- status?: string
145
- area?: string
146
- /** Free-text match against the story narrative and its code. */
147
- q?: string
148
- }
149
-
150
- export interface ConnectStoryList {
151
- items: ConnectStoryItem[]
152
- page: number
153
- size: number
154
- total: number
155
- }
156
-
157
- export interface ConnectStoryItem {
158
- id: string
159
- code?: string
160
- story: string
161
- area?: string
162
- status: string
163
- primary: boolean
164
- warning?: string
165
- createdAt: string
166
- }
167
-
168
149
  /** What a connector needs to know about a project in one call. */
169
150
  export interface ConnectProjectStatus {
151
+ /**
152
+ * The project card, flattened into the names a parent agent already reads.
153
+ *
154
+ * `name` is the card's `title` and `alias` its `code`; the three brief parts are the bodies of
155
+ * the project's `specification`, `vision` and `design-system` specifications. `status` and
156
+ * `intrinsic` are the card's own — a key of the project flow and the intrinsic state it maps to —
157
+ * typed as plain strings because this view crosses a version skew and a newer platform may
158
+ * answer with a status an older connector has never heard of.
159
+ */
170
160
  project: {
171
161
  id: string
172
162
  name: string
173
163
  alias: string
174
164
  description?: string
165
+ status: string
166
+ intrinsic: string
175
167
  specification?: string
176
168
  vision?: string
169
+ designSystem?: string
177
170
  }
178
171
  slot?: {
179
172
  id: string
@@ -297,12 +290,19 @@ export interface ConnectCreateBody {
297
290
  target?: ConnectTarget
298
291
  }
299
292
 
300
- /** Confirm a drafted project, optionally editing what the analysis produced. */
293
+ /**
294
+ * Confirm a drafted project, optionally editing what the analysis produced.
295
+ *
296
+ * The keys are a parent agent's vocabulary and stay as they are: `name` becomes the card's
297
+ * `title`, and each brief part present is written into the project's specification of that
298
+ * category before the confirm transition runs.
299
+ */
301
300
  export interface ConnectConfirmBody {
302
301
  name?: string
303
302
  description?: string
304
303
  specification?: string
305
304
  vision?: string
305
+ designSystem?: string
306
306
  target?: ConnectTarget
307
307
  }
308
308
 
@@ -310,10 +310,6 @@ export interface ConnectModifyBody {
310
310
  prompt: string
311
311
  }
312
312
 
313
- export interface ConnectStoryBody {
314
- story: string
315
- }
316
-
317
313
  export interface ConnectPipelineParams {
318
314
  id: string
319
315
  runId: string
@@ -419,23 +415,6 @@ export interface ConnectProjectSummary {
419
415
  alias: string
420
416
  }
421
417
 
422
- /** A story item returned after creating, editing or fetching one story. */
423
- export interface ConnectStoryMutation {
424
- id: string
425
- code?: string
426
- story: string
427
- area?: string
428
- status: string
429
- primary: boolean
430
- warning?: string
431
- createdAt: string
432
- }
433
-
434
- /** The success answer for deleting a story. */
435
- export interface ConnectStoryDeletion {
436
- deleted: boolean
437
- }
438
-
439
418
  /** The persistent state of one pipeline run, read by a connector without platform internals. */
440
419
  export interface ConnectPipelineState {
441
420
  runId: string
@@ -8,9 +8,6 @@
8
8
  */
9
9
  export const STORY_DESIGN_VERSION = 1
10
10
 
11
- /** The code a scaffold plan is filed under, since it belongs to a project rather than a story. */
12
- export const SCAFFOLD_CODE = 'scaffold'
13
-
14
11
  /** How far a design may drift from the project it was written against before it is stale. */
15
12
  export enum DesignStaleness {
16
13
  /** Usable as it stands. */
@@ -4,15 +4,19 @@ import { DesignStaleness, STORY_DESIGN_VERSION } from './consts.js'
4
4
  import type { StoryDesign } from './types.js'
5
5
 
6
6
  /**
7
- * The in-memory aggregate the coders take, derived from the design.
7
+ * The in-memory aggregate the coders take, derived from the design ALONE.
8
8
  *
9
9
  * Derived rather than stored, and derived HERE rather than at the platform: the aggregate is what
10
10
  * every generation helper reads, and a second place that assembles it is a second place that can
11
11
  * assemble it differently. The `code` in particular is load-bearing - the scaffold stamps every
12
12
  * placeholder it draws with it, so a run keyed by anything else cannot recognise its own
13
13
  * reservation.
14
+ *
15
+ * For a context with no card behind it. Where a story card exists, `userStoryOf(card, design)` is
16
+ * the reader: the card wins on the narrative, code, area and actor, which a person may have
17
+ * changed since the design was written.
14
18
  */
15
- export const userStoryOf = (design: StoryDesign): UserStory => {
19
+ export const userStoryOfDesign = (design: StoryDesign): UserStory => {
16
20
  const componentOf = (name: string): StoryComponent | null => {
17
21
  const component = design.components.find(entry => entry.name === name)
18
22
  if (component == null) {
@@ -168,24 +168,25 @@ export interface StoryDesign {
168
168
  provenance: StoryDesignProvenance
169
169
  }
170
170
 
171
- /** What a caller hands the store; the revision is the store's to allocate. */
172
- export interface StoryDesignInput {
173
- projectId: string
174
- storyId?: string
175
- code: string
176
- kind: string
177
- payload: unknown
171
+ /** Who wrote a design revision and why — recorded on the transition, never in the design. */
172
+ export interface StoryDesignPutOptions {
178
173
  runId?: string
174
+ cause?: string
179
175
  }
180
176
 
181
177
  /**
182
178
  * How the implementation stage reaches the design, without knowing where it lives.
183
179
  *
184
180
  * A port rather than a resource for the usual reason: two questions is the whole of what an
185
- * implementation step needs, and a port that small is satisfiable by a record store, a file, or a
186
- * test double.
181
+ * implementation step needs, and a port that small is satisfiable by a planning facade, a file,
182
+ * or a test. Both methods are addressed by a CARD id — the story card for a story design, the
183
+ * project card for a scaffold plan — and the port decides which specification slot of that card
184
+ * holds the payload. The code a design carries is the target's vocabulary; it never addresses a
185
+ * record.
187
186
  */
188
187
  export interface StoryDesignPort {
189
- current: (projectId: string, code: string) => Promise<{ revision: number, design: StoryDesign } | null>
190
- put: (input: StoryDesignInput) => Promise<number>
188
+ /** The card's current design and its revision; `null` when none was written or its version differs. */
189
+ current: (cardId: string) => Promise<{ revision: number, design: StoryDesign } | null>
190
+ /** Write a design as the card's next revision and answer the revision number it received. */
191
+ put: (cardId: string, design: StoryDesign, opts?: StoryDesignPutOptions) => Promise<number>
191
192
  }
@@ -6,6 +6,7 @@ import type { PurposeMetadata } from '../agent/types.js'
6
6
  import type { AgentProject, Entity, UserStory } from '../ba/types.js'
7
7
  import type { UXTransition } from '../ux/types.js'
8
8
  import type { SeniorityMode } from '../consts.js'
9
+ import type { ViableProjectCard, ViableStoryCard } from '../planning/types.js'
9
10
 
10
11
  /**
11
12
  * Model-selection contracts are owned by `@owlmeans/llm-common` — the JSON-safe config
@@ -26,7 +27,15 @@ export interface ExecutionState extends LlmExecutionState {
26
27
  slot?: string
27
28
  projectId?: string
28
29
  entityId?: string
30
+ /** The brief the run reads — assembled from {@link ExecutionState.projectCard} and its specifications. */
29
31
  project?: AgentProject
32
+ /**
33
+ * The project card the run acts on, as plain data.
34
+ *
35
+ * Carried beside the brief rather than in place of it: a generator reads the brief, while
36
+ * whatever writes back — a status transition, a specification — needs the card's id and head.
37
+ */
38
+ projectCard?: ViableProjectCard
30
39
  entities?: Entity[]
31
40
  /**
32
41
  * Which blueprint this run is building against, as an id plus an override patch.
@@ -51,5 +60,7 @@ export interface TaskExecutionState
51
60
  extends ExecutionState, Omit<LlmTaskExecutionState, keyof LlmExecutionState> {
52
61
  mode?: SeniorityMode
53
62
  story?: UserStory
63
+ /** The story card the task develops, as plain data — the aggregate above is derived from it. */
64
+ card?: ViableStoryCard
54
65
  transitions?: UXTransition[]
55
66
  }
package/src/index.ts CHANGED
@@ -19,4 +19,5 @@ export * from './connect/index.js'
19
19
  export * from './convert/index.js'
20
20
  export * from './scaffold/index.js'
21
21
  export * from './design/index.js'
22
+ export * from './planning/index.js'
22
23
  export * from './branding.js'
@@ -0,0 +1,182 @@
1
+ import { CodeScope, CodeStyle } from '@owlmeans/planning'
2
+ import type { CodePolicy } from '@owlmeans/planning'
3
+
4
+ /**
5
+ * The OwlMeans Viable vocabulary over `@owlmeans/planning`.
6
+ *
7
+ * A project, a user story and the documents behind them are planning WORKCARDS of the types
8
+ * declared here. Everything generic — the record, the transition, the fold, the store, the protocol
9
+ * tree — belongs to the planning packages; what a Viable project or story IS, which statuses it
10
+ * moves through and which documents it carries, is declared once in this module and read by every
11
+ * runtime that writes one.
12
+ */
13
+
14
+ /** A Viable project — the card every story, document and platform record of a product hangs under. */
15
+ export const VIABLE_PROJECT_TYPE = 'viable:project'
16
+ /** A user story — the unit of development a person starts. */
17
+ export const VIABLE_STORY_TYPE = 'viable:user-story'
18
+ /** Every document a project or story card carries (specification, vision, design system, plans). */
19
+ export const VIABLE_SPEC_TYPE = 'viable:spec'
20
+
21
+ /**
22
+ * Reserved card types. Declared in full so their code prefix and flow are decided once, and
23
+ * deliberately absent from the project type's `cardTypes`: nothing may create one yet.
24
+ */
25
+ export const VIABLE_BUG_TYPE = 'viable:bug'
26
+ export const VIABLE_IMPROVEMENT_TYPE = 'viable:improvement'
27
+ export const VIABLE_REQUIREMENT_TYPE = 'viable:requirement'
28
+
29
+ export const VIABLE_PROJECT_FLOW = 'viable:project'
30
+ export const VIABLE_STORY_FLOW = 'viable:user-story'
31
+ /** The one-status flow a document runs — a specification has no lifecycle of its own. */
32
+ export const VIABLE_SPEC_FLOW = 'viable:spec'
33
+
34
+ /**
35
+ * The story flow's status keys.
36
+ *
37
+ * Byte-identical to the strings a story has always carried — the frontmatter of
38
+ * `docs/stories/<code>.md`, the connector's job status mapping, the board's columns, their i18n
39
+ * keys and every end-to-end selector read these exact values. A key is a wire contract and is
40
+ * never renamed.
41
+ */
42
+ export enum ViableStoryStatus {
43
+ Planned = 'planned',
44
+ InProgress = 'in-progress',
45
+ Completed = 'completed',
46
+ /** Intrinsically PLANNED: a failed story is work still to do, and retrying it is `start`. */
47
+ Failed = 'failed',
48
+ }
49
+
50
+ export enum ViableStoryTransition {
51
+ /** `planned | failed → in-progress` — the only move that asks for development. */
52
+ Start = 'start',
53
+ Complete = 'complete',
54
+ Fail = 'fail',
55
+ /** `* → planned` — the manual recovery, and the one move a completed story still accepts. */
56
+ Reset = 'reset',
57
+ }
58
+
59
+ export enum ViableProjectStatus {
60
+ /** Created from a prompt, specification drafted, nothing provisioned. */
61
+ Draft = 'draft',
62
+ /** The owner confirmed the brief; initialization is running or has run. */
63
+ Confirmed = 'confirmed',
64
+ /** Initialization finished at least once. */
65
+ Active = 'active',
66
+ Archived = 'archived',
67
+ }
68
+
69
+ export enum ViableProjectTransition {
70
+ Confirm = 'confirm',
71
+ Activate = 'activate',
72
+ Archive = 'archive',
73
+ Reopen = 'reopen',
74
+ }
75
+
76
+ /** The single status a document holds. */
77
+ export enum ViableSpecStatus {
78
+ Current = 'current',
79
+ }
80
+
81
+ /** The palette key a board renders a status with. Presentation data, carried on the flow. */
82
+ export enum ViableTone {
83
+ Blue = 'blue',
84
+ Yellow = 'yellow',
85
+ Green = 'green',
86
+ Red = 'red',
87
+ Neutral = 'neutral',
88
+ }
89
+
90
+ /**
91
+ * The specification slots Viable cards carry.
92
+ *
93
+ * Project: `specification`, `vision`, `design-system` (the brief) and `scaffold` (the drawn plan).
94
+ * Story: `design`. The co-located `*.spec/.ux/.ui.md` files of a target are FILES, not slots — that
95
+ * prose already lives inside the `design` payload — so `SpecCategory` is not a slot vocabulary.
96
+ */
97
+ export enum ViableSpecCategory {
98
+ Specification = 'specification',
99
+ Vision = 'vision',
100
+ DesignSystem = 'design-system',
101
+ Scaffold = 'scaffold',
102
+ Design = 'design',
103
+ }
104
+
105
+ /** How many revisions of a `design` or `scaffold` document the history must be able to answer. */
106
+ export const VIABLE_DESIGN_REVISIONS_KEPT = 3
107
+
108
+ /**
109
+ * Relationship types between story cards.
110
+ *
111
+ * `follows` is WRITTEN: a connective story follows the flow story it was anchored after, created in
112
+ * the same transition as the card. `shares-widget` and `shares-screen` are DECLARED ONLY — the
113
+ * `scaffold` specification is their single authority, and a second copy as links would be a second
114
+ * answer that can disagree with it.
115
+ */
116
+ export enum ViableRelationship {
117
+ Follows = 'follows',
118
+ SharesWidget = 'shares-widget',
119
+ SharesScreen = 'shares-screen',
120
+ }
121
+
122
+ /**
123
+ * Where a write came from, carried on `PlanningScope.channel` and recorded on the transition's
124
+ * `actor.channel`.
125
+ *
126
+ * It is never read from the wire: the manager API derives `Connect` from an access-token request
127
+ * and `Web` from everything else; the agent writes as `Agent` or `Pipeline`. Three rules key on it
128
+ * — the balance refusal class (`ConnectOutOfCredits` for `Connect`), re-formatting a narrative
129
+ * (`Web`/`Connect` only), and the develop trigger (a committed `start` by `Web`/`Connect` only).
130
+ */
131
+ export enum ViableChannel {
132
+ Web = 'web',
133
+ Connect = 'connect',
134
+ Agent = 'agent',
135
+ Pipeline = 'pipeline',
136
+ }
137
+
138
+ /** The channels a PERSON writes through. */
139
+ export const VIABLE_USER_CHANNELS: readonly string[] = Object.freeze([
140
+ ViableChannel.Web, ViableChannel.Connect,
141
+ ])
142
+
143
+ export const VIABLE_STORY_CODE_PREFIX = 'US-'
144
+ export const VIABLE_BUG_CODE_PREFIX = 'BUG-'
145
+ export const VIABLE_IMPROVEMENT_CODE_PREFIX = 'IMP-'
146
+ export const VIABLE_REQUIREMENT_CODE_PREFIX = 'REQ-'
147
+ export const VIABLE_CARD_CODE_LENGTH = 5
148
+
149
+ /** `US-` + five uppercase characters, unique within the project. The code a target is keyed by. */
150
+ export const VIABLE_STORY_CODE: CodePolicy = Object.freeze({
151
+ prefix: VIABLE_STORY_CODE_PREFIX,
152
+ style: CodeStyle.Random,
153
+ length: VIABLE_CARD_CODE_LENGTH,
154
+ uppercase: true,
155
+ uniqueWithin: CodeScope.Parent,
156
+ })
157
+
158
+ /**
159
+ * A project's code is its alias — a slug unique within the organization.
160
+ *
161
+ * Minted by the platform's name ladder, which knows about retired aliases and refused hostnames;
162
+ * a code policy only guards uniqueness, so a create always supplies the code.
163
+ */
164
+ export const VIABLE_PROJECT_CODE: CodePolicy = Object.freeze({
165
+ style: CodeStyle.Slug,
166
+ uniqueWithin: CodeScope.Entity,
167
+ // The alias moves: a rename changes it, and a refused preview certificate walks it to `alias-2`.
168
+ // A story code never moves — the target's files are named after it.
169
+ mutable: true,
170
+ })
171
+
172
+ export const VIABLE_BUG_CODE: CodePolicy = Object.freeze({
173
+ ...VIABLE_STORY_CODE, prefix: VIABLE_BUG_CODE_PREFIX,
174
+ })
175
+
176
+ export const VIABLE_IMPROVEMENT_CODE: CodePolicy = Object.freeze({
177
+ ...VIABLE_STORY_CODE, prefix: VIABLE_IMPROVEMENT_CODE_PREFIX,
178
+ })
179
+
180
+ export const VIABLE_REQUIREMENT_CODE: CodePolicy = Object.freeze({
181
+ ...VIABLE_STORY_CODE, prefix: VIABLE_REQUIREMENT_CODE_PREFIX,
182
+ })