@forwardimpact/schema 0.6.0 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -28,14 +28,14 @@ fit:handoffs a rdf:Property ;
28
28
  rdfs:domain fit:Stage ;
29
29
  rdfs:range fit:Handoff .
30
30
 
31
- fit:entryCriteria a rdf:Property ;
32
- rdfs:label "entryCriteria"@en ;
33
- rdfs:comment "Conditions that must be met before entering this stage"@en ;
31
+ fit:readChecklist a rdf:Property ;
32
+ rdfs:label "readChecklist"@en ;
33
+ rdfs:comment "Read-Then-Do Checklist: steps to follow in order during this stage"@en ;
34
34
  rdfs:range xsd:string .
35
35
 
36
- fit:exitCriteria a rdf:Property ;
37
- rdfs:label "exitCriteria"@en ;
38
- rdfs:comment "Conditions that must be met before leaving this stage"@en ;
36
+ fit:confirmChecklist a rdf:Property ;
37
+ rdfs:label "confirmChecklist"@en ;
38
+ rdfs:comment "Do-Then-Confirm Checklist: items to verify before handing off to next stage"@en ;
39
39
  rdfs:range xsd:string .
40
40
 
41
41
  fit:summary a rdf:Property ;
@@ -74,7 +74,7 @@ fit:StageShape a sh:NodeShape ;
74
74
  sh:targetClass fit:Stage ;
75
75
  sh:property [
76
76
  sh:path fit:id ;
77
- sh:in ( "specify" "plan" "code" "review" "deploy" ) ;
77
+ sh:in ( "specify" "plan" "onboard" "code" "review" "deploy" ) ;
78
78
  sh:minCount 1 ;
79
79
  sh:maxCount 1 ;
80
80
  sh:name "id" ;
@@ -122,16 +122,16 @@ fit:StageShape a sh:NodeShape ;
122
122
  sh:description "Restrictions on behaviour in this stage" ;
123
123
  ] ;
124
124
  sh:property [
125
- sh:path fit:entryCriteria ;
125
+ sh:path fit:readChecklist ;
126
126
  sh:datatype xsd:string ;
127
- sh:name "entryCriteria" ;
128
- sh:description "Conditions that must be met before entering this stage" ;
127
+ sh:name "readChecklist" ;
128
+ sh:description "Read-Then-Do Checklist: steps to follow in order during this stage" ;
129
129
  ] ;
130
130
  sh:property [
131
- sh:path fit:exitCriteria ;
131
+ sh:path fit:confirmChecklist ;
132
132
  sh:datatype xsd:string ;
133
- sh:name "exitCriteria" ;
134
- sh:description "Conditions that must be met before leaving this stage" ;
133
+ sh:name "confirmChecklist" ;
134
+ sh:description "Do-Then-Confirm Checklist: items to verify before handing off to next stage" ;
135
135
  ] .
136
136
 
137
137
  # -----------------------------------------------------------------------------
@@ -142,7 +142,7 @@ fit:HandoffShape a sh:NodeShape ;
142
142
  sh:targetClass fit:Handoff ;
143
143
  sh:property [
144
144
  sh:path fit:targetStage ;
145
- sh:in ( "specify" "plan" "code" "review" "deploy" ) ;
145
+ sh:in ( "specify" "plan" "onboard" "code" "review" "deploy" ) ;
146
146
  sh:minCount 1 ;
147
147
  sh:maxCount 1 ;
148
148
  sh:name "targetStage" ;
package/src/levels.js CHANGED
@@ -54,30 +54,25 @@ export const BEHAVIOUR_MATURITY_ORDER = [
54
54
  BehaviourMaturity.EXEMPLIFYING,
55
55
  ];
56
56
 
57
- /**
58
- * Lifecycle stages for development workflow
59
- * @readonly
60
- * @enum {string}
61
- */
62
- export const Stage = {
63
- SPECIFY: "specify",
64
- PLAN: "plan",
65
- CODE: "code",
66
- REVIEW: "review",
67
- DEPLOY: "deploy",
68
- };
57
+ // ============================================================================
58
+ // Data-driven Stage Functions
59
+ // ============================================================================
60
+ // Stage ordering is derived from loaded stage data, not hardcoded.
61
+ // Use getStageOrder(stages) to get stage IDs in lifecycle order.
69
62
 
70
63
  /**
71
- * Ordered array of stages for lifecycle progression
72
- * @type {string[]}
64
+ * Get ordered stage IDs from loaded stage data
65
+ *
66
+ * Stages are defined in stages.yaml and their array order IS the
67
+ * canonical lifecycle order. This function extracts IDs preserving
68
+ * that order, similar to getCapabilityOrder for capabilities.
69
+ *
70
+ * @param {Object[]} stages - Loaded stages array from stages.yaml
71
+ * @returns {string[]} Stage IDs in lifecycle order
73
72
  */
74
- export const STAGE_ORDER = [
75
- Stage.SPECIFY,
76
- Stage.PLAN,
77
- Stage.CODE,
78
- Stage.REVIEW,
79
- Stage.DEPLOY,
80
- ];
73
+ export function getStageOrder(stages) {
74
+ return stages.map((s) => s.id);
75
+ }
81
76
 
82
77
  /**
83
78
  * Skill capabilities (what capability area)
package/src/validation.js CHANGED
@@ -6,7 +6,6 @@
6
6
 
7
7
  import {
8
8
  Capability,
9
- Stage,
10
9
  getSkillLevelIndex,
11
10
  getBehaviourMaturityIndex,
12
11
  } from "./levels.js";
@@ -150,14 +149,13 @@ function validateSkill(skill, index, requiredStageIds = []) {
150
149
  ),
151
150
  );
152
151
  } else {
153
- // Validate each stage
154
- const validStageIds = Object.values(Stage);
152
+ // Validate each stage against loaded stage data
155
153
  for (const [stageId, stageData] of Object.entries(skill.agent.stages)) {
156
- if (!validStageIds.includes(stageId)) {
154
+ if (requiredStageIds.length > 0 && !requiredStageIds.includes(stageId)) {
157
155
  errors.push(
158
156
  createError(
159
157
  "INVALID_VALUE",
160
- `Invalid stage ID: ${stageId}. Must be one of: ${validStageIds.join(", ")}`,
158
+ `Invalid stage ID: ${stageId}. Must be one of: ${requiredStageIds.join(", ")}`,
161
159
  `${agentPath}.stages.${stageId}`,
162
160
  stageId,
163
161
  ),
@@ -184,41 +182,41 @@ function validateSkill(skill, index, requiredStageIds = []) {
184
182
  ),
185
183
  );
186
184
  }
187
- // activities is required and must be an array
188
- if (!stageData.activities) {
185
+ // readChecklist is required and must be an array
186
+ if (!stageData.readChecklist) {
189
187
  errors.push(
190
188
  createError(
191
189
  "MISSING_REQUIRED",
192
- `Stage ${stageId} missing activities`,
193
- `${stagePath}.activities`,
190
+ `Stage ${stageId} missing readChecklist`,
191
+ `${stagePath}.readChecklist`,
194
192
  ),
195
193
  );
196
- } else if (!Array.isArray(stageData.activities)) {
194
+ } else if (!Array.isArray(stageData.readChecklist)) {
197
195
  errors.push(
198
196
  createError(
199
197
  "INVALID_VALUE",
200
- `Stage ${stageId} activities must be an array`,
201
- `${stagePath}.activities`,
202
- stageData.activities,
198
+ `Stage ${stageId} readChecklist must be an array`,
199
+ `${stagePath}.readChecklist`,
200
+ stageData.readChecklist,
203
201
  ),
204
202
  );
205
203
  }
206
- // ready is required and must be an array (these become checklist items)
207
- if (!stageData.ready) {
204
+ // confirmChecklist is required and must be an array (these become checklist items)
205
+ if (!stageData.confirmChecklist) {
208
206
  errors.push(
209
207
  createError(
210
208
  "MISSING_REQUIRED",
211
- `Stage ${stageId} missing ready criteria`,
212
- `${stagePath}.ready`,
209
+ `Stage ${stageId} missing confirmChecklist`,
210
+ `${stagePath}.confirmChecklist`,
213
211
  ),
214
212
  );
215
- } else if (!Array.isArray(stageData.ready)) {
213
+ } else if (!Array.isArray(stageData.confirmChecklist)) {
216
214
  errors.push(
217
215
  createError(
218
216
  "INVALID_VALUE",
219
- `Stage ${stageId} ready must be an array`,
220
- `${stagePath}.ready`,
221
- stageData.ready,
217
+ `Stage ${stageId} confirmChecklist must be an array`,
218
+ `${stagePath}.confirmChecklist`,
219
+ stageData.confirmChecklist,
222
220
  ),
223
221
  );
224
222
  }
@@ -284,7 +282,7 @@ function validateSkill(skill, index, requiredStageIds = []) {
284
282
  errors.push(
285
283
  createError(
286
284
  "INVALID_FIELD",
287
- "Skill agent 'verificationCriteria' field is not supported. Use stages.{stage}.ready instead.",
285
+ "Skill agent 'verificationCriteria' field is not supported. Use stages.{stage}.confirmChecklist instead.",
288
286
  `${agentPath}.verificationCriteria`,
289
287
  ),
290
288
  );
@@ -1249,15 +1247,6 @@ function validateStage(stage, index) {
1249
1247
 
1250
1248
  if (!stage.id) {
1251
1249
  errors.push(createError("MISSING_REQUIRED", "Stage missing id", path));
1252
- } else if (!Object.values(Stage).includes(stage.id)) {
1253
- errors.push(
1254
- createError(
1255
- "INVALID_VALUE",
1256
- `Invalid stage id: ${stage.id}`,
1257
- `${path}.id`,
1258
- stage.id,
1259
- ),
1260
- );
1261
1250
  }
1262
1251
 
1263
1252
  if (!stage.name) {
@@ -1997,7 +1986,7 @@ export function validateAgentData({ humanData, agentData }) {
1997
1986
 
1998
1987
  // Validate skills with agent sections have complete stage coverage
1999
1988
  const skillsWithAgent = (humanData.skills || []).filter((s) => s.agent);
2000
- const requiredStages = ["plan", "code", "review"];
1989
+ const requiredStages = ["plan", "onboard", "code", "review"];
2001
1990
 
2002
1991
  for (const skill of skillsWithAgent) {
2003
1992
  const stages = skill.agent.stages || {};
@@ -2025,28 +2014,28 @@ export function validateAgentData({ humanData, agentData }) {
2025
2014
  );
2026
2015
  }
2027
2016
  if (
2028
- !stageData.activities ||
2029
- !Array.isArray(stageData.activities) ||
2030
- stageData.activities.length === 0
2017
+ !stageData.readChecklist ||
2018
+ !Array.isArray(stageData.readChecklist) ||
2019
+ stageData.readChecklist.length === 0
2031
2020
  ) {
2032
2021
  errors.push(
2033
2022
  createError(
2034
2023
  "MISSING_REQUIRED",
2035
- `Skill '${skill.id}' agent stage '${stageId}' missing or empty activities`,
2036
- `skills.${skill.id}.agent.stages.${stageId}.activities`,
2024
+ `Skill '${skill.id}' agent stage '${stageId}' missing or empty readChecklist`,
2025
+ `skills.${skill.id}.agent.stages.${stageId}.readChecklist`,
2037
2026
  ),
2038
2027
  );
2039
2028
  }
2040
2029
  if (
2041
- !stageData.ready ||
2042
- !Array.isArray(stageData.ready) ||
2043
- stageData.ready.length === 0
2030
+ !stageData.confirmChecklist ||
2031
+ !Array.isArray(stageData.confirmChecklist) ||
2032
+ stageData.confirmChecklist.length === 0
2044
2033
  ) {
2045
2034
  errors.push(
2046
2035
  createError(
2047
2036
  "MISSING_REQUIRED",
2048
- `Skill '${skill.id}' agent stage '${stageId}' missing or empty ready criteria`,
2049
- `skills.${skill.id}.agent.stages.${stageId}.ready`,
2037
+ `Skill '${skill.id}' agent stage '${stageId}' missing or empty confirmChecklist`,
2038
+ `skills.${skill.id}.agent.stages.${stageId}.confirmChecklist`,
2050
2039
  ),
2051
2040
  );
2052
2041
  }