@forwardimpact/schema 0.3.0 → 0.6.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.
- package/bin/fit-schema.js +2 -2
- package/examples/capabilities/business.yaml +1 -1
- package/examples/capabilities/delivery.yaml +9 -7
- package/examples/capabilities/people.yaml +1 -1
- package/examples/capabilities/reliability.yaml +32 -11
- package/examples/capabilities/scale.yaml +1 -1
- package/examples/framework.yaml +1 -1
- package/examples/questions/behaviours/outcome_ownership.yaml +226 -49
- package/examples/questions/behaviours/polymathic_knowledge.yaml +273 -45
- package/examples/questions/behaviours/precise_communication.yaml +246 -52
- package/examples/questions/behaviours/relentless_curiosity.yaml +246 -48
- package/examples/questions/behaviours/systems_thinking.yaml +236 -50
- package/examples/questions/capabilities/business.yaml +107 -0
- package/examples/questions/capabilities/delivery.yaml +104 -0
- package/examples/questions/capabilities/people.yaml +104 -0
- package/examples/questions/capabilities/reliability.yaml +103 -0
- package/examples/questions/capabilities/scale.yaml +103 -0
- package/examples/questions/skills/architecture_design.yaml +102 -51
- package/examples/questions/skills/cloud_platforms.yaml +90 -44
- package/examples/questions/skills/code_quality.yaml +86 -45
- package/examples/questions/skills/data_modeling.yaml +93 -43
- package/examples/questions/skills/devops.yaml +91 -44
- package/examples/questions/skills/full_stack_development.yaml +93 -45
- package/examples/questions/skills/sre_practices.yaml +92 -41
- package/examples/questions/skills/stakeholder_management.yaml +97 -46
- package/examples/questions/skills/team_collaboration.yaml +87 -40
- package/examples/questions/skills/technical_writing.yaml +89 -40
- package/examples/stages.yaml +6 -0
- package/package.json +9 -9
- package/schema/json/behaviour-questions.schema.json +53 -26
- package/schema/json/capability-questions.schema.json +95 -0
- package/schema/json/capability.schema.json +3 -3
- package/schema/json/skill-questions.schema.json +34 -19
- package/schema/json/stages.schema.json +5 -1
- package/schema/rdf/behaviour-questions.ttl +39 -7
- package/schema/rdf/capability.ttl +5 -5
- package/schema/rdf/defs.ttl +3 -3
- package/schema/rdf/skill-questions.ttl +28 -1
- package/schema/rdf/stages.ttl +27 -3
- package/{lib → src}/levels.js +37 -80
- package/{lib → src}/loader.js +9 -5
- package/{lib → src}/modifiers.js +3 -3
- package/{lib → src}/validation.js +74 -37
- /package/{lib → src}/index-generator.js +0 -0
- /package/{lib → src}/index.js +0 -0
- /package/{lib → src}/schema-validation.js +0 -0
|
@@ -7,7 +7,8 @@
|
|
|
7
7
|
# =============================================================================
|
|
8
8
|
# Skill Questions Schema
|
|
9
9
|
# =============================================================================
|
|
10
|
-
# Interview questions for assessing skills
|
|
10
|
+
# Interview questions for assessing skills, organized by role type
|
|
11
|
+
# (professional/management) and level.
|
|
11
12
|
# =============================================================================
|
|
12
13
|
|
|
13
14
|
# -----------------------------------------------------------------------------
|
|
@@ -18,6 +19,18 @@ fit:Question a rdfs:Class ;
|
|
|
18
19
|
rdfs:label "Question"@en ;
|
|
19
20
|
rdfs:comment "Interview question for assessing skills or behaviours"@en .
|
|
20
21
|
|
|
22
|
+
fit:RoleType a rdfs:Class ;
|
|
23
|
+
rdfs:label "RoleType"@en ;
|
|
24
|
+
rdfs:comment "Type of role: professional (IC) or management"@en .
|
|
25
|
+
|
|
26
|
+
fit:professional a fit:RoleType ;
|
|
27
|
+
rdfs:label "professional"@en ;
|
|
28
|
+
rdfs:comment "Professional/individual contributor roles"@en .
|
|
29
|
+
|
|
30
|
+
fit:management a fit:RoleType ;
|
|
31
|
+
rdfs:label "management"@en ;
|
|
32
|
+
rdfs:comment "Management roles"@en .
|
|
33
|
+
|
|
21
34
|
# -----------------------------------------------------------------------------
|
|
22
35
|
# Properties
|
|
23
36
|
# -----------------------------------------------------------------------------
|
|
@@ -58,6 +71,12 @@ fit:atLevel a rdf:Property ;
|
|
|
58
71
|
rdfs:domain fit:Question ;
|
|
59
72
|
rdfs:range fit:SkillLevel .
|
|
60
73
|
|
|
74
|
+
fit:forRoleType a rdf:Property ;
|
|
75
|
+
rdfs:label "forRoleType"@en ;
|
|
76
|
+
rdfs:comment "The role type this question is intended for (professional or management)"@en ;
|
|
77
|
+
rdfs:domain fit:Question ;
|
|
78
|
+
rdfs:range fit:RoleType .
|
|
79
|
+
|
|
61
80
|
# =============================================================================
|
|
62
81
|
# SHACL SHAPES
|
|
63
82
|
# =============================================================================
|
|
@@ -125,4 +144,12 @@ fit:SkillQuestionShape a sh:NodeShape ;
|
|
|
125
144
|
sh:maxCount 1 ;
|
|
126
145
|
sh:name "atLevel" ;
|
|
127
146
|
sh:description "The skill level this question is for" ;
|
|
147
|
+
] ;
|
|
148
|
+
sh:property [
|
|
149
|
+
sh:path fit:forRoleType ;
|
|
150
|
+
sh:in ( fit:professional fit:management ) ;
|
|
151
|
+
sh:minCount 1 ;
|
|
152
|
+
sh:maxCount 1 ;
|
|
153
|
+
sh:name "forRoleType" ;
|
|
154
|
+
sh:description "The role type this question is for" ;
|
|
128
155
|
] .
|
package/schema/rdf/stages.ttl
CHANGED
|
@@ -33,6 +33,17 @@ fit:entryCriteria a rdf:Property ;
|
|
|
33
33
|
rdfs:comment "Conditions that must be met before entering 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 ;
|
|
39
|
+
rdfs:range xsd:string .
|
|
40
|
+
|
|
41
|
+
fit:summary a rdf:Property ;
|
|
42
|
+
rdfs:label "summary"@en ;
|
|
43
|
+
rdfs:comment "Third-person summary for metadata, listings, and sub-agent descriptions"@en ;
|
|
44
|
+
rdfs:domain fit:Stage ;
|
|
45
|
+
rdfs:range xsd:string .
|
|
46
|
+
|
|
36
47
|
fit:targetStage a rdf:Property ;
|
|
37
48
|
rdfs:label "targetStage"@en ;
|
|
38
49
|
rdfs:comment "The stage to transition to"@en ;
|
|
@@ -63,7 +74,7 @@ fit:StageShape a sh:NodeShape ;
|
|
|
63
74
|
sh:targetClass fit:Stage ;
|
|
64
75
|
sh:property [
|
|
65
76
|
sh:path fit:id ;
|
|
66
|
-
sh:in ( "plan" "code" "review" ) ;
|
|
77
|
+
sh:in ( "specify" "plan" "code" "review" "deploy" ) ;
|
|
67
78
|
sh:minCount 1 ;
|
|
68
79
|
sh:maxCount 1 ;
|
|
69
80
|
sh:name "id" ;
|
|
@@ -89,7 +100,14 @@ fit:StageShape a sh:NodeShape ;
|
|
|
89
100
|
sh:datatype xsd:string ;
|
|
90
101
|
sh:maxCount 1 ;
|
|
91
102
|
sh:name "description" ;
|
|
92
|
-
sh:description "Description of the stage's purpose" ;
|
|
103
|
+
sh:description "Description of the stage's purpose (second-person, for agent body)" ;
|
|
104
|
+
] ;
|
|
105
|
+
sh:property [
|
|
106
|
+
sh:path fit:summary ;
|
|
107
|
+
sh:datatype xsd:string ;
|
|
108
|
+
sh:maxCount 1 ;
|
|
109
|
+
sh:name "summary" ;
|
|
110
|
+
sh:description "Third-person summary for metadata, listings, and sub-agent descriptions" ;
|
|
93
111
|
] ;
|
|
94
112
|
sh:property [
|
|
95
113
|
sh:path fit:handoffs ;
|
|
@@ -108,6 +126,12 @@ fit:StageShape a sh:NodeShape ;
|
|
|
108
126
|
sh:datatype xsd:string ;
|
|
109
127
|
sh:name "entryCriteria" ;
|
|
110
128
|
sh:description "Conditions that must be met before entering this stage" ;
|
|
129
|
+
] ;
|
|
130
|
+
sh:property [
|
|
131
|
+
sh:path fit:exitCriteria ;
|
|
132
|
+
sh:datatype xsd:string ;
|
|
133
|
+
sh:name "exitCriteria" ;
|
|
134
|
+
sh:description "Conditions that must be met before leaving this stage" ;
|
|
111
135
|
] .
|
|
112
136
|
|
|
113
137
|
# -----------------------------------------------------------------------------
|
|
@@ -118,7 +142,7 @@ fit:HandoffShape a sh:NodeShape ;
|
|
|
118
142
|
sh:targetClass fit:Handoff ;
|
|
119
143
|
sh:property [
|
|
120
144
|
sh:path fit:targetStage ;
|
|
121
|
-
sh:in ( "plan" "code" "review" ) ;
|
|
145
|
+
sh:in ( "specify" "plan" "code" "review" "deploy" ) ;
|
|
122
146
|
sh:minCount 1 ;
|
|
123
147
|
sh:maxCount 1 ;
|
|
124
148
|
sh:name "targetStage" ;
|
package/{lib → src}/levels.js
RENAMED
|
@@ -98,72 +98,44 @@ export const Capability = {
|
|
|
98
98
|
PRODUCT: "product",
|
|
99
99
|
};
|
|
100
100
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
* 2. Data & AI capabilities
|
|
106
|
-
* 3. Scale & reliability
|
|
107
|
-
* 4. People & process
|
|
108
|
-
* 5. Business, documentation & product
|
|
109
|
-
* @type {string[]}
|
|
110
|
-
*/
|
|
111
|
-
export const CAPABILITY_ORDER = [
|
|
112
|
-
Capability.DELIVERY,
|
|
113
|
-
Capability.DATA,
|
|
114
|
-
Capability.AI,
|
|
115
|
-
Capability.ML,
|
|
116
|
-
Capability.SCALE,
|
|
117
|
-
Capability.RELIABILITY,
|
|
118
|
-
Capability.PEOPLE,
|
|
119
|
-
Capability.PROCESS,
|
|
120
|
-
Capability.BUSINESS,
|
|
121
|
-
Capability.DOCUMENTATION,
|
|
122
|
-
Capability.PRODUCT,
|
|
123
|
-
];
|
|
124
|
-
|
|
125
|
-
/**
|
|
126
|
-
* Get the index of a capability in the ordered list
|
|
127
|
-
* @param {string} capability - The capability to look up
|
|
128
|
-
* @returns {number} The index (0-based), or -1 if not found
|
|
129
|
-
*/
|
|
130
|
-
export function getCapabilityIndex(capability) {
|
|
131
|
-
return CAPABILITY_ORDER.indexOf(capability);
|
|
132
|
-
}
|
|
101
|
+
// ============================================================================
|
|
102
|
+
// Data-driven Capability Functions
|
|
103
|
+
// ============================================================================
|
|
104
|
+
// These functions work with loaded capability data for responsibility derivation
|
|
133
105
|
|
|
134
106
|
/**
|
|
135
|
-
*
|
|
136
|
-
* @param {
|
|
137
|
-
* @param {string}
|
|
138
|
-
* @returns {
|
|
107
|
+
* Get capability metadata from loaded capability data
|
|
108
|
+
* @param {Object[]} capabilities - Loaded capabilities array
|
|
109
|
+
* @param {string} capabilityId - The capability ID to look up
|
|
110
|
+
* @returns {Object|undefined} The capability object or undefined
|
|
139
111
|
*/
|
|
140
|
-
export function
|
|
141
|
-
return
|
|
112
|
+
export function getCapabilityById(capabilities, capabilityId) {
|
|
113
|
+
return capabilities.find((c) => c.id === capabilityId);
|
|
142
114
|
}
|
|
143
115
|
|
|
144
116
|
/**
|
|
145
|
-
*
|
|
146
|
-
* @param {
|
|
147
|
-
* @returns {
|
|
117
|
+
* Get ordered capability IDs from loaded capability data
|
|
118
|
+
* @param {Object[]} capabilities - Loaded capabilities array
|
|
119
|
+
* @returns {string[]} Capability IDs in display order
|
|
148
120
|
*/
|
|
149
|
-
export function
|
|
150
|
-
return [...
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
return a.name.localeCompare(b.name);
|
|
154
|
-
});
|
|
121
|
+
export function getCapabilityOrder(capabilities) {
|
|
122
|
+
return [...capabilities]
|
|
123
|
+
.sort((a, b) => (a.ordinalRank || 0) - (b.ordinalRank || 0))
|
|
124
|
+
.map((c) => c.id);
|
|
155
125
|
}
|
|
156
126
|
|
|
157
127
|
/**
|
|
158
|
-
* Group skills by capability in
|
|
128
|
+
* Group skills by capability in display order
|
|
159
129
|
* @param {import('./levels.js').Skill[]} skills - Array of skills to group
|
|
160
|
-
* @
|
|
130
|
+
* @param {Object[]} capabilities - Loaded capabilities array for ordering
|
|
131
|
+
* @returns {Object<string, import('./levels.js').Skill[]>} Object with capabilities as keys (in display order)
|
|
161
132
|
*/
|
|
162
|
-
export function groupSkillsByCapability(skills) {
|
|
133
|
+
export function groupSkillsByCapability(skills, capabilities) {
|
|
134
|
+
const capabilityOrder = getCapabilityOrder(capabilities);
|
|
163
135
|
const result = {};
|
|
164
136
|
|
|
165
|
-
// Initialize all capabilities in order (ensures consistent key order)
|
|
166
|
-
for (const capability of
|
|
137
|
+
// Initialize all capabilities in display order (ensures consistent key order)
|
|
138
|
+
for (const capability of capabilityOrder) {
|
|
167
139
|
result[capability] = [];
|
|
168
140
|
}
|
|
169
141
|
|
|
@@ -186,32 +158,6 @@ export function groupSkillsByCapability(skills) {
|
|
|
186
158
|
return result;
|
|
187
159
|
}
|
|
188
160
|
|
|
189
|
-
// ============================================================================
|
|
190
|
-
// Data-driven Capability Functions
|
|
191
|
-
// ============================================================================
|
|
192
|
-
// These functions work with loaded capability data for responsibility derivation
|
|
193
|
-
|
|
194
|
-
/**
|
|
195
|
-
* Get capability metadata from loaded capability data
|
|
196
|
-
* @param {Object[]} capabilities - Loaded capabilities array
|
|
197
|
-
* @param {string} capabilityId - The capability ID to look up
|
|
198
|
-
* @returns {Object|undefined} The capability object or undefined
|
|
199
|
-
*/
|
|
200
|
-
export function getCapabilityById(capabilities, capabilityId) {
|
|
201
|
-
return capabilities.find((c) => c.id === capabilityId);
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
/**
|
|
205
|
-
* Get ordered capability IDs from loaded capability data
|
|
206
|
-
* @param {Object[]} capabilities - Loaded capabilities array
|
|
207
|
-
* @returns {string[]} Capability IDs in display order
|
|
208
|
-
*/
|
|
209
|
-
export function getCapabilityOrder(capabilities) {
|
|
210
|
-
return [...capabilities]
|
|
211
|
-
.sort((a, b) => (a.displayOrder || 0) - (b.displayOrder || 0))
|
|
212
|
-
.map((c) => c.id);
|
|
213
|
-
}
|
|
214
|
-
|
|
215
161
|
/**
|
|
216
162
|
* Get emoji for a capability from loaded capability data
|
|
217
163
|
* @param {Object[]} capabilities - Loaded capabilities array
|
|
@@ -400,10 +346,21 @@ export const SkillType = {
|
|
|
400
346
|
* @property {number} [expectedDurationMinutes] - Estimated time to ask and answer
|
|
401
347
|
*/
|
|
402
348
|
|
|
349
|
+
/**
|
|
350
|
+
* @typedef {Object<string, Question[]>} LevelQuestions - Questions organized by level
|
|
351
|
+
*/
|
|
352
|
+
|
|
353
|
+
/**
|
|
354
|
+
* @typedef {Object} RoleTypeQuestions
|
|
355
|
+
* @property {LevelQuestions} [professionalQuestions] - Questions for professional/IC roles
|
|
356
|
+
* @property {LevelQuestions} [managementQuestions] - Questions for management roles
|
|
357
|
+
*/
|
|
358
|
+
|
|
403
359
|
/**
|
|
404
360
|
* @typedef {Object} QuestionBank
|
|
405
|
-
* @property {Object<string,
|
|
406
|
-
* @property {Object<string,
|
|
361
|
+
* @property {Object<string, RoleTypeQuestions>} skillLevels - Questions by skill ID, then by role type (professional/management), then by level
|
|
362
|
+
* @property {Object<string, RoleTypeQuestions>} behaviourMaturities - Questions by behaviour ID, then by role type, then by maturity
|
|
363
|
+
* @property {Object<string, RoleTypeQuestions>} [capabilityLevels] - Questions by capability ID, then by role type, then by level
|
|
407
364
|
*/
|
|
408
365
|
|
|
409
366
|
/**
|
package/{lib → src}/loader.js
RENAMED
|
@@ -281,12 +281,16 @@ async function loadCapabilitiesFromDir(capabilitiesDir) {
|
|
|
281
281
|
* @returns {Promise<import('./levels.js').QuestionBank>}
|
|
282
282
|
*/
|
|
283
283
|
export async function loadQuestionFolder(questionsDir) {
|
|
284
|
-
const [skillLevels, behaviourMaturities] =
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
284
|
+
const [skillLevels, behaviourMaturities, capabilityLevels] =
|
|
285
|
+
await Promise.all([
|
|
286
|
+
loadQuestionsFromDir(join(questionsDir, "skills")),
|
|
287
|
+
loadQuestionsFromDir(join(questionsDir, "behaviours")),
|
|
288
|
+
loadQuestionsFromDir(join(questionsDir, "capabilities")).catch(
|
|
289
|
+
() => ({}),
|
|
290
|
+
),
|
|
291
|
+
]);
|
|
288
292
|
|
|
289
|
-
return { skillLevels, behaviourMaturities };
|
|
293
|
+
return { skillLevels, behaviourMaturities, capabilityLevels };
|
|
290
294
|
}
|
|
291
295
|
|
|
292
296
|
/**
|
package/{lib → src}/modifiers.js
RENAMED
|
@@ -5,13 +5,13 @@
|
|
|
5
5
|
* Full modifier logic is in @forwardimpact/model.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
import {
|
|
8
|
+
import { Capability } from "./levels.js";
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
|
-
* Valid skill capability names
|
|
11
|
+
* Valid skill capability names (derived from Capability enum)
|
|
12
12
|
* @type {Set<string>}
|
|
13
13
|
*/
|
|
14
|
-
const VALID_CAPABILITIES = new Set(
|
|
14
|
+
const VALID_CAPABILITIES = new Set(Object.values(Capability));
|
|
15
15
|
|
|
16
16
|
/**
|
|
17
17
|
* Check if a key is a skill capability
|
|
@@ -1774,6 +1774,7 @@ export function validateQuestionBank(questionBank, skills, behaviours) {
|
|
|
1774
1774
|
const warnings = [];
|
|
1775
1775
|
const skillIds = new Set(skills.map((s) => s.id));
|
|
1776
1776
|
const behaviourIds = new Set(behaviours.map((b) => b.id));
|
|
1777
|
+
const validRoleTypes = ["professionalQuestions", "managementQuestions"];
|
|
1777
1778
|
|
|
1778
1779
|
if (!questionBank) {
|
|
1779
1780
|
return createValidationResult(false, [
|
|
@@ -1784,7 +1785,7 @@ export function validateQuestionBank(questionBank, skills, behaviours) {
|
|
|
1784
1785
|
// Validate skill questions
|
|
1785
1786
|
if (questionBank.skillLevels) {
|
|
1786
1787
|
Object.entries(questionBank.skillLevels).forEach(
|
|
1787
|
-
([skillId,
|
|
1788
|
+
([skillId, roleTypeQuestions]) => {
|
|
1788
1789
|
if (!skillIds.has(skillId)) {
|
|
1789
1790
|
errors.push(
|
|
1790
1791
|
createError(
|
|
@@ -1795,27 +1796,46 @@ export function validateQuestionBank(questionBank, skills, behaviours) {
|
|
|
1795
1796
|
),
|
|
1796
1797
|
);
|
|
1797
1798
|
}
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
-
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
|
|
1811
|
-
|
|
1812
|
-
|
|
1813
|
-
|
|
1814
|
-
|
|
1815
|
-
|
|
1799
|
+
// Validate each role type (professional/management)
|
|
1800
|
+
Object.entries(roleTypeQuestions || {}).forEach(
|
|
1801
|
+
([roleType, levelQuestions]) => {
|
|
1802
|
+
if (!validRoleTypes.includes(roleType)) {
|
|
1803
|
+
errors.push(
|
|
1804
|
+
createError(
|
|
1805
|
+
"INVALID_VALUE",
|
|
1806
|
+
`Question bank has invalid role type: ${roleType}`,
|
|
1807
|
+
`questionBank.skillLevels.${skillId}.${roleType}`,
|
|
1808
|
+
roleType,
|
|
1809
|
+
),
|
|
1810
|
+
);
|
|
1811
|
+
return;
|
|
1812
|
+
}
|
|
1813
|
+
// Validate each level within the role type
|
|
1814
|
+
Object.entries(levelQuestions || {}).forEach(
|
|
1815
|
+
([level, questions]) => {
|
|
1816
|
+
if (getSkillLevelIndex(level) === -1) {
|
|
1817
|
+
errors.push(
|
|
1818
|
+
createError(
|
|
1819
|
+
"INVALID_VALUE",
|
|
1820
|
+
`Question bank has invalid skill level: ${level}`,
|
|
1821
|
+
`questionBank.skillLevels.${skillId}.${roleType}.${level}`,
|
|
1822
|
+
level,
|
|
1823
|
+
),
|
|
1824
|
+
);
|
|
1825
|
+
}
|
|
1826
|
+
if (!Array.isArray(questions) || questions.length === 0) {
|
|
1827
|
+
warnings.push(
|
|
1828
|
+
createWarning(
|
|
1829
|
+
"EMPTY_QUESTIONS",
|
|
1830
|
+
`No questions for skill ${skillId} (${roleType}) at level ${level}`,
|
|
1831
|
+
`questionBank.skillLevels.${skillId}.${roleType}.${level}`,
|
|
1832
|
+
),
|
|
1833
|
+
);
|
|
1834
|
+
}
|
|
1835
|
+
},
|
|
1816
1836
|
);
|
|
1817
|
-
}
|
|
1818
|
-
|
|
1837
|
+
},
|
|
1838
|
+
);
|
|
1819
1839
|
},
|
|
1820
1840
|
);
|
|
1821
1841
|
}
|
|
@@ -1823,7 +1843,7 @@ export function validateQuestionBank(questionBank, skills, behaviours) {
|
|
|
1823
1843
|
// Validate behaviour questions
|
|
1824
1844
|
if (questionBank.behaviourMaturities) {
|
|
1825
1845
|
Object.entries(questionBank.behaviourMaturities).forEach(
|
|
1826
|
-
([behaviourId,
|
|
1846
|
+
([behaviourId, roleTypeQuestions]) => {
|
|
1827
1847
|
if (!behaviourIds.has(behaviourId)) {
|
|
1828
1848
|
errors.push(
|
|
1829
1849
|
createError(
|
|
@@ -1834,27 +1854,44 @@ export function validateQuestionBank(questionBank, skills, behaviours) {
|
|
|
1834
1854
|
),
|
|
1835
1855
|
);
|
|
1836
1856
|
}
|
|
1837
|
-
|
|
1838
|
-
|
|
1839
|
-
|
|
1857
|
+
// Validate each role type (professional/management)
|
|
1858
|
+
Object.entries(roleTypeQuestions || {}).forEach(
|
|
1859
|
+
([roleType, maturityQuestions]) => {
|
|
1860
|
+
if (!validRoleTypes.includes(roleType)) {
|
|
1840
1861
|
errors.push(
|
|
1841
1862
|
createError(
|
|
1842
1863
|
"INVALID_VALUE",
|
|
1843
|
-
`Question bank has invalid
|
|
1844
|
-
`questionBank.behaviourMaturities.${behaviourId}.${
|
|
1845
|
-
|
|
1846
|
-
),
|
|
1847
|
-
);
|
|
1848
|
-
}
|
|
1849
|
-
if (!Array.isArray(questions) || questions.length === 0) {
|
|
1850
|
-
warnings.push(
|
|
1851
|
-
createWarning(
|
|
1852
|
-
"EMPTY_QUESTIONS",
|
|
1853
|
-
`No questions for behaviour ${behaviourId} at maturity ${maturity}`,
|
|
1854
|
-
`questionBank.behaviourMaturities.${behaviourId}.${maturity}`,
|
|
1864
|
+
`Question bank has invalid role type: ${roleType}`,
|
|
1865
|
+
`questionBank.behaviourMaturities.${behaviourId}.${roleType}`,
|
|
1866
|
+
roleType,
|
|
1855
1867
|
),
|
|
1856
1868
|
);
|
|
1869
|
+
return;
|
|
1857
1870
|
}
|
|
1871
|
+
// Validate each maturity level within the role type
|
|
1872
|
+
Object.entries(maturityQuestions || {}).forEach(
|
|
1873
|
+
([maturity, questions]) => {
|
|
1874
|
+
if (getBehaviourMaturityIndex(maturity) === -1) {
|
|
1875
|
+
errors.push(
|
|
1876
|
+
createError(
|
|
1877
|
+
"INVALID_VALUE",
|
|
1878
|
+
`Question bank has invalid behaviour maturity: ${maturity}`,
|
|
1879
|
+
`questionBank.behaviourMaturities.${behaviourId}.${roleType}.${maturity}`,
|
|
1880
|
+
maturity,
|
|
1881
|
+
),
|
|
1882
|
+
);
|
|
1883
|
+
}
|
|
1884
|
+
if (!Array.isArray(questions) || questions.length === 0) {
|
|
1885
|
+
warnings.push(
|
|
1886
|
+
createWarning(
|
|
1887
|
+
"EMPTY_QUESTIONS",
|
|
1888
|
+
`No questions for behaviour ${behaviourId} (${roleType}) at maturity ${maturity}`,
|
|
1889
|
+
`questionBank.behaviourMaturities.${behaviourId}.${roleType}.${maturity}`,
|
|
1890
|
+
),
|
|
1891
|
+
);
|
|
1892
|
+
}
|
|
1893
|
+
},
|
|
1894
|
+
);
|
|
1858
1895
|
},
|
|
1859
1896
|
);
|
|
1860
1897
|
},
|
|
File without changes
|
/package/{lib → src}/index.js
RENAMED
|
File without changes
|
|
File without changes
|