@forwardimpact/pathway 0.1.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/LICENSE +201 -0
- package/README.md +104 -0
- package/app/commands/agent.js +430 -0
- package/app/commands/behaviour.js +61 -0
- package/app/commands/command-factory.js +211 -0
- package/app/commands/discipline.js +58 -0
- package/app/commands/driver.js +94 -0
- package/app/commands/grade.js +60 -0
- package/app/commands/index.js +20 -0
- package/app/commands/init.js +67 -0
- package/app/commands/interview.js +68 -0
- package/app/commands/job.js +157 -0
- package/app/commands/progress.js +77 -0
- package/app/commands/questions.js +179 -0
- package/app/commands/serve.js +143 -0
- package/app/commands/site.js +121 -0
- package/app/commands/skill.js +76 -0
- package/app/commands/stage.js +129 -0
- package/app/commands/track.js +70 -0
- package/app/components/action-buttons.js +66 -0
- package/app/components/behaviour-profile.js +53 -0
- package/app/components/builder.js +341 -0
- package/app/components/card.js +98 -0
- package/app/components/checklist.js +145 -0
- package/app/components/comparison-radar.js +237 -0
- package/app/components/detail.js +230 -0
- package/app/components/error-page.js +72 -0
- package/app/components/grid.js +109 -0
- package/app/components/list.js +120 -0
- package/app/components/modifier-table.js +142 -0
- package/app/components/nav.js +64 -0
- package/app/components/progression-table.js +320 -0
- package/app/components/radar-chart.js +102 -0
- package/app/components/skill-matrix.js +97 -0
- package/app/css/base.css +56 -0
- package/app/css/bundles/app.css +40 -0
- package/app/css/bundles/handout.css +43 -0
- package/app/css/bundles/slides.css +40 -0
- package/app/css/components/badges.css +215 -0
- package/app/css/components/buttons.css +101 -0
- package/app/css/components/forms.css +105 -0
- package/app/css/components/layout.css +209 -0
- package/app/css/components/nav.css +166 -0
- package/app/css/components/progress.css +166 -0
- package/app/css/components/states.css +82 -0
- package/app/css/components/surfaces.css +243 -0
- package/app/css/components/tables.css +362 -0
- package/app/css/components/typography.css +122 -0
- package/app/css/components/utilities.css +41 -0
- package/app/css/pages/agent-builder.css +391 -0
- package/app/css/pages/assessment-results.css +453 -0
- package/app/css/pages/detail.css +59 -0
- package/app/css/pages/interview-builder.css +148 -0
- package/app/css/pages/job-builder.css +134 -0
- package/app/css/pages/landing.css +92 -0
- package/app/css/pages/lifecycle.css +118 -0
- package/app/css/pages/progress-builder.css +274 -0
- package/app/css/pages/self-assessment.css +502 -0
- package/app/css/reset.css +50 -0
- package/app/css/tokens.css +153 -0
- package/app/css/views/handout.css +30 -0
- package/app/css/views/print.css +608 -0
- package/app/css/views/slide-animations.css +113 -0
- package/app/css/views/slide-base.css +330 -0
- package/app/css/views/slide-sections.css +597 -0
- package/app/css/views/slide-tables.css +275 -0
- package/app/formatters/agent/dom.js +540 -0
- package/app/formatters/agent/profile.js +133 -0
- package/app/formatters/agent/skill.js +58 -0
- package/app/formatters/behaviour/dom.js +91 -0
- package/app/formatters/behaviour/markdown.js +54 -0
- package/app/formatters/behaviour/shared.js +64 -0
- package/app/formatters/discipline/dom.js +187 -0
- package/app/formatters/discipline/markdown.js +87 -0
- package/app/formatters/discipline/shared.js +131 -0
- package/app/formatters/driver/dom.js +103 -0
- package/app/formatters/driver/shared.js +92 -0
- package/app/formatters/grade/dom.js +208 -0
- package/app/formatters/grade/markdown.js +94 -0
- package/app/formatters/grade/shared.js +86 -0
- package/app/formatters/index.js +50 -0
- package/app/formatters/interview/dom.js +97 -0
- package/app/formatters/interview/markdown.js +66 -0
- package/app/formatters/interview/shared.js +332 -0
- package/app/formatters/job/description.js +176 -0
- package/app/formatters/job/dom.js +411 -0
- package/app/formatters/job/markdown.js +102 -0
- package/app/formatters/progress/dom.js +135 -0
- package/app/formatters/progress/markdown.js +86 -0
- package/app/formatters/progress/shared.js +339 -0
- package/app/formatters/questions/json.js +43 -0
- package/app/formatters/questions/markdown.js +303 -0
- package/app/formatters/questions/shared.js +274 -0
- package/app/formatters/questions/yaml.js +76 -0
- package/app/formatters/shared.js +71 -0
- package/app/formatters/skill/dom.js +168 -0
- package/app/formatters/skill/markdown.js +109 -0
- package/app/formatters/skill/shared.js +125 -0
- package/app/formatters/stage/dom.js +135 -0
- package/app/formatters/stage/index.js +12 -0
- package/app/formatters/stage/shared.js +111 -0
- package/app/formatters/track/dom.js +128 -0
- package/app/formatters/track/markdown.js +105 -0
- package/app/formatters/track/shared.js +181 -0
- package/app/handout-main.js +421 -0
- package/app/handout.html +21 -0
- package/app/index.html +59 -0
- package/app/lib/card-mappers.js +173 -0
- package/app/lib/cli-output.js +270 -0
- package/app/lib/error-boundary.js +70 -0
- package/app/lib/errors.js +49 -0
- package/app/lib/form-controls.js +47 -0
- package/app/lib/job-cache.js +86 -0
- package/app/lib/markdown.js +114 -0
- package/app/lib/radar.js +866 -0
- package/app/lib/reactive.js +77 -0
- package/app/lib/render.js +212 -0
- package/app/lib/router-core.js +160 -0
- package/app/lib/router-pages.js +16 -0
- package/app/lib/router-slides.js +202 -0
- package/app/lib/state.js +148 -0
- package/app/lib/utils.js +14 -0
- package/app/lib/yaml-loader.js +327 -0
- package/app/main.js +213 -0
- package/app/model/agent.js +702 -0
- package/app/model/checklist.js +137 -0
- package/app/model/derivation.js +699 -0
- package/app/model/index-generator.js +71 -0
- package/app/model/interview.js +539 -0
- package/app/model/job.js +222 -0
- package/app/model/levels.js +591 -0
- package/app/model/loader.js +564 -0
- package/app/model/matching.js +858 -0
- package/app/model/modifiers.js +158 -0
- package/app/model/profile.js +266 -0
- package/app/model/progression.js +507 -0
- package/app/model/validation.js +1385 -0
- package/app/pages/agent-builder.js +823 -0
- package/app/pages/assessment-results.js +507 -0
- package/app/pages/behaviour.js +70 -0
- package/app/pages/discipline.js +71 -0
- package/app/pages/driver.js +106 -0
- package/app/pages/grade.js +117 -0
- package/app/pages/interview-builder.js +50 -0
- package/app/pages/interview.js +304 -0
- package/app/pages/job-builder.js +50 -0
- package/app/pages/job.js +58 -0
- package/app/pages/landing.js +305 -0
- package/app/pages/progress-builder.js +58 -0
- package/app/pages/progress.js +495 -0
- package/app/pages/self-assessment.js +729 -0
- package/app/pages/skill.js +113 -0
- package/app/pages/stage.js +231 -0
- package/app/pages/track.js +69 -0
- package/app/slide-main.js +360 -0
- package/app/slides/behaviour.js +38 -0
- package/app/slides/chapter.js +82 -0
- package/app/slides/discipline.js +40 -0
- package/app/slides/driver.js +39 -0
- package/app/slides/grade.js +32 -0
- package/app/slides/index.js +198 -0
- package/app/slides/interview.js +58 -0
- package/app/slides/job.js +55 -0
- package/app/slides/overview.js +126 -0
- package/app/slides/progress.js +83 -0
- package/app/slides/skill.js +40 -0
- package/app/slides/track.js +39 -0
- package/app/slides.html +56 -0
- package/app/types.js +147 -0
- package/bin/pathway.js +489 -0
- package/examples/agents/.claude/skills/architecture-design/SKILL.md +88 -0
- package/examples/agents/.claude/skills/cloud-platforms/SKILL.md +90 -0
- package/examples/agents/.claude/skills/code-quality-review/SKILL.md +67 -0
- package/examples/agents/.claude/skills/data-modeling/SKILL.md +99 -0
- package/examples/agents/.claude/skills/developer-experience/SKILL.md +99 -0
- package/examples/agents/.claude/skills/devops-cicd/SKILL.md +96 -0
- package/examples/agents/.claude/skills/full-stack-development/SKILL.md +90 -0
- package/examples/agents/.claude/skills/knowledge-management/SKILL.md +100 -0
- package/examples/agents/.claude/skills/pattern-generalization/SKILL.md +102 -0
- package/examples/agents/.claude/skills/sre-practices/SKILL.md +117 -0
- package/examples/agents/.claude/skills/technical-debt-management/SKILL.md +123 -0
- package/examples/agents/.claude/skills/technical-writing/SKILL.md +129 -0
- package/examples/agents/.github/agents/se-platform-code.agent.md +181 -0
- package/examples/agents/.github/agents/se-platform-plan.agent.md +178 -0
- package/examples/agents/.github/agents/se-platform-review.agent.md +113 -0
- package/examples/agents/.vscode/settings.json +8 -0
- package/examples/behaviours/_index.yaml +8 -0
- package/examples/behaviours/outcome_ownership.yaml +44 -0
- package/examples/behaviours/polymathic_knowledge.yaml +42 -0
- package/examples/behaviours/precise_communication.yaml +40 -0
- package/examples/behaviours/relentless_curiosity.yaml +38 -0
- package/examples/behaviours/systems_thinking.yaml +41 -0
- package/examples/capabilities/_index.yaml +8 -0
- package/examples/capabilities/business.yaml +251 -0
- package/examples/capabilities/delivery.yaml +352 -0
- package/examples/capabilities/people.yaml +100 -0
- package/examples/capabilities/reliability.yaml +318 -0
- package/examples/capabilities/scale.yaml +394 -0
- package/examples/disciplines/_index.yaml +5 -0
- package/examples/disciplines/data_engineering.yaml +76 -0
- package/examples/disciplines/software_engineering.yaml +76 -0
- package/examples/drivers.yaml +205 -0
- package/examples/framework.yaml +58 -0
- package/examples/grades.yaml +118 -0
- package/examples/questions/behaviours/outcome_ownership.yaml +52 -0
- package/examples/questions/behaviours/polymathic_knowledge.yaml +48 -0
- package/examples/questions/behaviours/precise_communication.yaml +55 -0
- package/examples/questions/behaviours/relentless_curiosity.yaml +51 -0
- package/examples/questions/behaviours/systems_thinking.yaml +53 -0
- package/examples/questions/skills/architecture_design.yaml +54 -0
- package/examples/questions/skills/cloud_platforms.yaml +48 -0
- package/examples/questions/skills/code_quality.yaml +49 -0
- package/examples/questions/skills/data_modeling.yaml +46 -0
- package/examples/questions/skills/devops.yaml +47 -0
- package/examples/questions/skills/full_stack_development.yaml +48 -0
- package/examples/questions/skills/sre_practices.yaml +44 -0
- package/examples/questions/skills/stakeholder_management.yaml +49 -0
- package/examples/questions/skills/team_collaboration.yaml +43 -0
- package/examples/questions/skills/technical_writing.yaml +43 -0
- package/examples/self-assessments.yaml +66 -0
- package/examples/stages.yaml +76 -0
- package/examples/tracks/_index.yaml +6 -0
- package/examples/tracks/manager.yaml +53 -0
- package/examples/tracks/platform.yaml +54 -0
- package/examples/tracks/sre.yaml +58 -0
- package/examples/vscode-settings.yaml +22 -0
- package/package.json +68 -0
|
@@ -0,0 +1,591 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Engineering Pathway Type Definitions
|
|
3
|
+
*
|
|
4
|
+
* This module defines all data structures used in the engineering pathway.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Skill levels from lowest to highest proficiency
|
|
9
|
+
* @readonly
|
|
10
|
+
* @enum {string}
|
|
11
|
+
*/
|
|
12
|
+
export const SkillLevel = {
|
|
13
|
+
AWARENESS: "awareness",
|
|
14
|
+
FOUNDATIONAL: "foundational",
|
|
15
|
+
WORKING: "working",
|
|
16
|
+
PRACTITIONER: "practitioner",
|
|
17
|
+
EXPERT: "expert",
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Ordered array of skill levels for comparison/clamping
|
|
22
|
+
* @type {string[]}
|
|
23
|
+
*/
|
|
24
|
+
export const SKILL_LEVEL_ORDER = [
|
|
25
|
+
SkillLevel.AWARENESS,
|
|
26
|
+
SkillLevel.FOUNDATIONAL,
|
|
27
|
+
SkillLevel.WORKING,
|
|
28
|
+
SkillLevel.PRACTITIONER,
|
|
29
|
+
SkillLevel.EXPERT,
|
|
30
|
+
];
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Behaviour maturity levels from lowest to highest
|
|
34
|
+
* @readonly
|
|
35
|
+
* @enum {string}
|
|
36
|
+
*/
|
|
37
|
+
export const BehaviourMaturity = {
|
|
38
|
+
EMERGING: "emerging",
|
|
39
|
+
DEVELOPING: "developing",
|
|
40
|
+
PRACTICING: "practicing",
|
|
41
|
+
ROLE_MODELING: "role_modeling",
|
|
42
|
+
EXEMPLIFYING: "exemplifying",
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Ordered array of behaviour maturity levels for comparison/clamping
|
|
47
|
+
* @type {string[]}
|
|
48
|
+
*/
|
|
49
|
+
export const BEHAVIOUR_MATURITY_ORDER = [
|
|
50
|
+
BehaviourMaturity.EMERGING,
|
|
51
|
+
BehaviourMaturity.DEVELOPING,
|
|
52
|
+
BehaviourMaturity.PRACTICING,
|
|
53
|
+
BehaviourMaturity.ROLE_MODELING,
|
|
54
|
+
BehaviourMaturity.EXEMPLIFYING,
|
|
55
|
+
];
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Lifecycle stages for development workflow
|
|
59
|
+
* @readonly
|
|
60
|
+
* @enum {string}
|
|
61
|
+
*/
|
|
62
|
+
export const Stage = {
|
|
63
|
+
PLAN: "plan",
|
|
64
|
+
CODE: "code",
|
|
65
|
+
REVIEW: "review",
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Ordered array of stages for lifecycle progression
|
|
70
|
+
* @type {string[]}
|
|
71
|
+
*/
|
|
72
|
+
export const STAGE_ORDER = [Stage.PLAN, Stage.CODE, Stage.REVIEW];
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Skill capabilities (what capability area)
|
|
76
|
+
* @readonly
|
|
77
|
+
* @enum {string}
|
|
78
|
+
*/
|
|
79
|
+
export const Capability = {
|
|
80
|
+
DELIVERY: "delivery",
|
|
81
|
+
SCALE: "scale",
|
|
82
|
+
RELIABILITY: "reliability",
|
|
83
|
+
DATA: "data",
|
|
84
|
+
AI: "ai",
|
|
85
|
+
PROCESS: "process",
|
|
86
|
+
BUSINESS: "business",
|
|
87
|
+
PEOPLE: "people",
|
|
88
|
+
DOCUMENTATION: "documentation",
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Ordered array of capabilities for consistent display
|
|
93
|
+
* Groups related capabilities logically:
|
|
94
|
+
* 1. Core delivery
|
|
95
|
+
* 2. Data & AI capabilities
|
|
96
|
+
* 3. Scale & reliability
|
|
97
|
+
* 4. People & process
|
|
98
|
+
* 5. Business & documentation
|
|
99
|
+
* @type {string[]}
|
|
100
|
+
*/
|
|
101
|
+
export const CAPABILITY_ORDER = [
|
|
102
|
+
Capability.DELIVERY,
|
|
103
|
+
Capability.DATA,
|
|
104
|
+
Capability.AI,
|
|
105
|
+
Capability.SCALE,
|
|
106
|
+
Capability.RELIABILITY,
|
|
107
|
+
Capability.PEOPLE,
|
|
108
|
+
Capability.PROCESS,
|
|
109
|
+
Capability.BUSINESS,
|
|
110
|
+
Capability.DOCUMENTATION,
|
|
111
|
+
];
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Get the index of a capability in the ordered list
|
|
115
|
+
* @param {string} capability - The capability to look up
|
|
116
|
+
* @returns {number} The index (0-based), or -1 if not found
|
|
117
|
+
*/
|
|
118
|
+
export function getCapabilityIndex(capability) {
|
|
119
|
+
return CAPABILITY_ORDER.indexOf(capability);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Compare two capabilities for sorting
|
|
124
|
+
* @param {string} a - First capability
|
|
125
|
+
* @param {string} b - Second capability
|
|
126
|
+
* @returns {number} Comparison result for sorting
|
|
127
|
+
*/
|
|
128
|
+
export function compareCapabilities(a, b) {
|
|
129
|
+
return getCapabilityIndex(a) - getCapabilityIndex(b);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Sort an array of skills by capability order, then by name
|
|
134
|
+
* @param {import('./levels.js').Skill[]} skills - Array of skills to sort
|
|
135
|
+
* @returns {import('./levels.js').Skill[]} Sorted array (new array, does not mutate input)
|
|
136
|
+
*/
|
|
137
|
+
export function sortSkillsByCapability(skills) {
|
|
138
|
+
return [...skills].sort((a, b) => {
|
|
139
|
+
const capabilityCompare = compareCapabilities(a.capability, b.capability);
|
|
140
|
+
if (capabilityCompare !== 0) return capabilityCompare;
|
|
141
|
+
return a.name.localeCompare(b.name);
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Group skills by capability in the defined order
|
|
147
|
+
* @param {import('./levels.js').Skill[]} skills - Array of skills to group
|
|
148
|
+
* @returns {Object<string, import('./levels.js').Skill[]>} Object with capabilities as keys (in order)
|
|
149
|
+
*/
|
|
150
|
+
export function groupSkillsByCapability(skills) {
|
|
151
|
+
const result = {};
|
|
152
|
+
|
|
153
|
+
// Initialize all capabilities in order (ensures consistent key order)
|
|
154
|
+
for (const capability of CAPABILITY_ORDER) {
|
|
155
|
+
result[capability] = [];
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// Populate with skills
|
|
159
|
+
for (const skill of skills) {
|
|
160
|
+
if (result[skill.capability]) {
|
|
161
|
+
result[skill.capability].push(skill);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
// Remove empty capabilities and sort skills within each capability by name
|
|
166
|
+
for (const capability of Object.keys(result)) {
|
|
167
|
+
if (result[capability].length === 0) {
|
|
168
|
+
delete result[capability];
|
|
169
|
+
} else {
|
|
170
|
+
result[capability].sort((a, b) => a.name.localeCompare(b.name));
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
return result;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// ============================================================================
|
|
178
|
+
// Data-driven Capability Functions
|
|
179
|
+
// ============================================================================
|
|
180
|
+
// These functions work with loaded capability data for responsibility derivation
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* Get capability metadata from loaded capability data
|
|
184
|
+
* @param {Object[]} capabilities - Loaded capabilities array
|
|
185
|
+
* @param {string} capabilityId - The capability ID to look up
|
|
186
|
+
* @returns {Object|undefined} The capability object or undefined
|
|
187
|
+
*/
|
|
188
|
+
export function getCapabilityById(capabilities, capabilityId) {
|
|
189
|
+
return capabilities.find((c) => c.id === capabilityId);
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* Get ordered capability IDs from loaded capability data
|
|
194
|
+
* @param {Object[]} capabilities - Loaded capabilities array
|
|
195
|
+
* @returns {string[]} Capability IDs in display order
|
|
196
|
+
*/
|
|
197
|
+
export function getCapabilityOrder(capabilities) {
|
|
198
|
+
return [...capabilities]
|
|
199
|
+
.sort((a, b) => (a.displayOrder || 0) - (b.displayOrder || 0))
|
|
200
|
+
.map((c) => c.id);
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
/**
|
|
204
|
+
* Get emoji for a capability from loaded capability data
|
|
205
|
+
* @param {Object[]} capabilities - Loaded capabilities array
|
|
206
|
+
* @param {string} capabilityId - The capability ID
|
|
207
|
+
* @returns {string} The emoji or default "💡"
|
|
208
|
+
*/
|
|
209
|
+
export function getCapabilityEmoji(capabilities, capabilityId) {
|
|
210
|
+
const capability = getCapabilityById(capabilities, capabilityId);
|
|
211
|
+
return capability?.emoji || "💡";
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
* Get responsibility statement for a capability at a specific skill level
|
|
216
|
+
*
|
|
217
|
+
* Uses professionalResponsibilities for professional tracks and
|
|
218
|
+
* managementResponsibilities for management tracks.
|
|
219
|
+
*
|
|
220
|
+
* @param {Object[]} capabilities - Loaded capabilities array
|
|
221
|
+
* @param {string} capabilityId - The capability ID
|
|
222
|
+
* @param {string} level - The skill level (awareness, foundational, working, practitioner, expert)
|
|
223
|
+
* @param {Object} [track] - Optional track to determine which responsibilities to use
|
|
224
|
+
* @param {boolean} [track.isManagement] - Whether this is a management track
|
|
225
|
+
* @returns {string|undefined} The responsibility statement or undefined
|
|
226
|
+
*/
|
|
227
|
+
export function getCapabilityResponsibility(
|
|
228
|
+
capabilities,
|
|
229
|
+
capabilityId,
|
|
230
|
+
level,
|
|
231
|
+
track,
|
|
232
|
+
) {
|
|
233
|
+
const capability = getCapabilityById(capabilities, capabilityId);
|
|
234
|
+
const responsibilityKey = track?.isManagement
|
|
235
|
+
? "managementResponsibilities"
|
|
236
|
+
: "professionalResponsibilities";
|
|
237
|
+
return capability?.[responsibilityKey]?.[level];
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
/**
|
|
241
|
+
* Skill type within a discipline
|
|
242
|
+
* @readonly
|
|
243
|
+
* @enum {string}
|
|
244
|
+
*/
|
|
245
|
+
export const SkillType = {
|
|
246
|
+
PRIMARY: "primary",
|
|
247
|
+
SECONDARY: "secondary",
|
|
248
|
+
BROAD: "broad",
|
|
249
|
+
TRACK: "track",
|
|
250
|
+
};
|
|
251
|
+
|
|
252
|
+
/**
|
|
253
|
+
* @typedef {Object} LevelDescription
|
|
254
|
+
* @property {string} level - The level identifier
|
|
255
|
+
* @property {string} description - Description of what this level means
|
|
256
|
+
*/
|
|
257
|
+
|
|
258
|
+
/**
|
|
259
|
+
* @typedef {Object} Skill
|
|
260
|
+
* @property {string} id - Unique identifier
|
|
261
|
+
* @property {string} name - Display name
|
|
262
|
+
* @property {string} capability - One of Capability values
|
|
263
|
+
* @property {string} description - General description of the skill
|
|
264
|
+
* @property {Object<string, string>} levelDescriptions - Description for each skill level
|
|
265
|
+
*/
|
|
266
|
+
|
|
267
|
+
/**
|
|
268
|
+
* @typedef {Object} Behaviour
|
|
269
|
+
* @property {string} id - Unique identifier
|
|
270
|
+
* @property {string} name - Display name
|
|
271
|
+
* @property {string} description - General description of the behaviour
|
|
272
|
+
* @property {Object<string, string>} maturityDescriptions - Description for each maturity level
|
|
273
|
+
*/
|
|
274
|
+
|
|
275
|
+
/**
|
|
276
|
+
* @typedef {Object} Driver
|
|
277
|
+
* @property {string} id - Unique identifier
|
|
278
|
+
* @property {string} name - Display name
|
|
279
|
+
* @property {string} description - Description of the organizational outcome
|
|
280
|
+
* @property {string[]} contributingSkills - Array of skill IDs that support this driver
|
|
281
|
+
* @property {string[]} contributingBehaviours - Array of behaviour IDs that support this driver
|
|
282
|
+
*/
|
|
283
|
+
|
|
284
|
+
/**
|
|
285
|
+
* @typedef {Object} Discipline
|
|
286
|
+
* @property {string} id - Unique identifier
|
|
287
|
+
* @property {string} specialization - Display name for the field (e.g., "Software Engineering")
|
|
288
|
+
* @property {string} roleTitle - Display name for a person in this role (e.g., "Software Engineer")
|
|
289
|
+
* @property {string} [name] - Legacy display name (deprecated, use specialization/roleTitle)
|
|
290
|
+
* @property {string} description - Description of the discipline
|
|
291
|
+
* @property {string[]} coreSkills - Skill IDs requiring deep expertise (Practitioner/Expert)
|
|
292
|
+
* @property {string[]} supportingSkills - Skill IDs requiring solid competence (Working/Practitioner)
|
|
293
|
+
* @property {string[]} broadSkills - Skill IDs requiring awareness (Awareness/Foundational)
|
|
294
|
+
* @property {Object<string, number>} behaviourModifiers - Map of behaviour ID to modifier (+1, 0, -1)
|
|
295
|
+
*/
|
|
296
|
+
|
|
297
|
+
/**
|
|
298
|
+
* @typedef {Object} AssessmentWeights
|
|
299
|
+
* @property {number} skillWeight - Weight for skill matching (0.0-1.0)
|
|
300
|
+
* @property {number} behaviourWeight - Weight for behaviour matching (0.0-1.0)
|
|
301
|
+
*/
|
|
302
|
+
|
|
303
|
+
/**
|
|
304
|
+
* @typedef {Object} Track
|
|
305
|
+
* @property {string} id - Unique identifier
|
|
306
|
+
* @property {string} name - Display name
|
|
307
|
+
* @property {string} description - Description of the track focus
|
|
308
|
+
* @property {boolean} [isProfessional=true] - Whether this is a professional/individual contributor track
|
|
309
|
+
* @property {boolean} [isManagement=false] - Whether this is a management/people manager track
|
|
310
|
+
* @property {Object<string, number>} skillModifiers - Map of skill ID to level modifier (positive or negative integer)
|
|
311
|
+
* @property {Object<string, number>} behaviourModifiers - Map of behaviour ID to maturity modifier (positive or negative integer)
|
|
312
|
+
* @property {AssessmentWeights} [assessmentWeights] - Optional custom weights for job matching
|
|
313
|
+
* @property {string[]} [validDisciplines] - Optional array of discipline IDs this track is valid for
|
|
314
|
+
* @property {string} [minGrade] - Optional minimum grade ID this track is valid for
|
|
315
|
+
*/
|
|
316
|
+
|
|
317
|
+
/**
|
|
318
|
+
* @typedef {Object} GradeSkillLevels
|
|
319
|
+
* @property {string} primary - Base skill level for primary skills
|
|
320
|
+
* @property {string} secondary - Base skill level for secondary skills
|
|
321
|
+
* @property {string} broad - Base skill level for broad skills
|
|
322
|
+
*/
|
|
323
|
+
|
|
324
|
+
/**
|
|
325
|
+
* @typedef {Object} GradeExpectations
|
|
326
|
+
* @property {string} impactScope - Expected scope of work/impact
|
|
327
|
+
* @property {string} autonomyExpectation - Expected level of autonomy
|
|
328
|
+
* @property {string} influenceScope - Expected sphere of influence
|
|
329
|
+
* @property {string} complexityHandled - Expected complexity of work handled
|
|
330
|
+
*/
|
|
331
|
+
|
|
332
|
+
/**
|
|
333
|
+
* @typedef {Object} BreadthCriteria
|
|
334
|
+
* @property {number} [practitioner] - Minimum number of skills at Practitioner level
|
|
335
|
+
* @property {number} [expert] - Minimum number of skills at Expert level
|
|
336
|
+
*/
|
|
337
|
+
|
|
338
|
+
/**
|
|
339
|
+
* @typedef {Object} Grade
|
|
340
|
+
* @property {string} id - Unique identifier
|
|
341
|
+
* @property {string} professionalTitle - Display name for professional/IC track (e.g., "Level I", "Staff")
|
|
342
|
+
* @property {string} managementTitle - Display name for management track (e.g., "Associate", "Director")
|
|
343
|
+
* @property {string} [name] - Legacy display name (deprecated, use professionalTitle/managementTitle)
|
|
344
|
+
* @property {string} [typicalExperienceRange] - Typical years of experience range (e.g., "0-2", "20+")
|
|
345
|
+
* @property {number} ordinalRank - Numeric level for ordering (higher = more senior)
|
|
346
|
+
* @property {GradeSkillLevels} baseSkillLevels - Base skill levels by skill type
|
|
347
|
+
* @property {string} baseBehaviourMaturity - Base behaviour maturity level
|
|
348
|
+
* @property {GradeExpectations} expectations - Role expectations
|
|
349
|
+
* @property {BreadthCriteria} [breadthCriteria] - For senior grades, breadth requirements
|
|
350
|
+
*/
|
|
351
|
+
|
|
352
|
+
/**
|
|
353
|
+
* @typedef {Object} SkillMatrixEntry
|
|
354
|
+
* @property {string} skillId - The skill ID
|
|
355
|
+
* @property {string} skillName - The skill name
|
|
356
|
+
* @property {string} capability - The skill capability
|
|
357
|
+
* @property {string} type - The skill type (primary/secondary/broad)
|
|
358
|
+
* @property {string} level - The derived skill level
|
|
359
|
+
* @property {string} levelDescription - Description for this level
|
|
360
|
+
*/
|
|
361
|
+
|
|
362
|
+
/**
|
|
363
|
+
* @typedef {Object} BehaviourProfileEntry
|
|
364
|
+
* @property {string} behaviourId - The behaviour ID
|
|
365
|
+
* @property {string} behaviourName - The behaviour name
|
|
366
|
+
* @property {string} maturity - The derived maturity level
|
|
367
|
+
* @property {string} maturityDescription - Description for this maturity level
|
|
368
|
+
|
|
369
|
+
*/
|
|
370
|
+
|
|
371
|
+
/**
|
|
372
|
+
* @typedef {Object} JobDefinition
|
|
373
|
+
* @property {string} id - Generated job ID (discipline_grade_track)
|
|
374
|
+
* @property {string} title - Generated job title
|
|
375
|
+
* @property {Discipline} discipline - Reference to the discipline
|
|
376
|
+
* @property {Grade} grade - Reference to the grade
|
|
377
|
+
* @property {Track} track - Reference to the track
|
|
378
|
+
* @property {SkillMatrixEntry[]} skillMatrix - Complete derived skill matrix
|
|
379
|
+
* @property {BehaviourProfileEntry[]} behaviourProfile - Complete derived behaviour profile
|
|
380
|
+
* @property {GradeExpectations} expectations - Grade-level expectations
|
|
381
|
+
*/
|
|
382
|
+
|
|
383
|
+
/**
|
|
384
|
+
* @typedef {Object} Question
|
|
385
|
+
* @property {string} id - Unique identifier
|
|
386
|
+
* @property {string} text - The question text
|
|
387
|
+
* @property {string} type - Question type (technical, situational, behavioural)
|
|
388
|
+
* @property {string[]} [followUps] - Optional follow-up questions
|
|
389
|
+
* @property {string[]} [lookingFor] - What good answers should include
|
|
390
|
+
* @property {number} [expectedDurationMinutes] - Estimated time to ask and answer
|
|
391
|
+
*/
|
|
392
|
+
|
|
393
|
+
/**
|
|
394
|
+
* @typedef {Object} QuestionBank
|
|
395
|
+
* @property {Object<string, Object<string, Question[]>>} skillLevels - Questions by skill ID, then by level
|
|
396
|
+
* @property {Object<string, Object<string, Question[]>>} behaviourMaturities - Questions by behaviour ID, then by maturity
|
|
397
|
+
*/
|
|
398
|
+
|
|
399
|
+
/**
|
|
400
|
+
* @typedef {Object} SelfAssessment
|
|
401
|
+
* @property {string} [id] - Optional identifier
|
|
402
|
+
* @property {Object<string, string>} skills - Map of skill ID to self-assessed level
|
|
403
|
+
* @property {Object<string, string>} behaviours - Map of behaviour ID to self-assessed maturity
|
|
404
|
+
* @property {Object} [expectations] - Optional self-assessment of scope/autonomy/influence
|
|
405
|
+
* @property {string} [expectations.scope] - Self-assessed scope
|
|
406
|
+
* @property {string} [expectations.autonomy] - Self-assessed autonomy
|
|
407
|
+
* @property {string} [expectations.influence] - Self-assessed influence
|
|
408
|
+
*/
|
|
409
|
+
|
|
410
|
+
/**
|
|
411
|
+
* @typedef {Object} MatchGap
|
|
412
|
+
* @property {string} id - Skill or behaviour ID
|
|
413
|
+
* @property {string} name - Skill or behaviour name
|
|
414
|
+
* @property {string} type - 'skill' or 'behaviour'
|
|
415
|
+
* @property {string} current - Current level
|
|
416
|
+
* @property {string} required - Required level
|
|
417
|
+
* @property {number} gap - Numeric gap (positive means below requirement)
|
|
418
|
+
*/
|
|
419
|
+
|
|
420
|
+
/**
|
|
421
|
+
* @typedef {Object} MatchAnalysis
|
|
422
|
+
* @property {number} overallScore - Combined weighted score (0-1)
|
|
423
|
+
* @property {number} skillScore - Skill match score (0-1)
|
|
424
|
+
* @property {number} behaviourScore - Behaviour match score (0-1)
|
|
425
|
+
* @property {MatchingWeights} weightsUsed - The weights used in calculation
|
|
426
|
+
* @property {MatchGap[]} gaps - Array of gaps where requirements not met
|
|
427
|
+
* @property {MatchTierInfo} tier - Match tier classification
|
|
428
|
+
* @property {MatchGap[]} priorityGaps - Top 3 gaps by severity for focused development
|
|
429
|
+
* @property {number} [expectationsScore] - For senior roles, expectations match score
|
|
430
|
+
*/
|
|
431
|
+
|
|
432
|
+
/**
|
|
433
|
+
* @typedef {Object} JobMatch
|
|
434
|
+
* @property {JobDefinition} job - The matched job
|
|
435
|
+
* @property {MatchAnalysis} analysis - Match analysis details
|
|
436
|
+
*/
|
|
437
|
+
|
|
438
|
+
/**
|
|
439
|
+
* @typedef {Object} DevelopmentItem
|
|
440
|
+
* @property {string} id - Skill or behaviour ID
|
|
441
|
+
* @property {string} name - Skill or behaviour name
|
|
442
|
+
* @property {string} type - 'skill' or 'behaviour'
|
|
443
|
+
* @property {string} currentLevel - Current level
|
|
444
|
+
* @property {string} targetLevel - Target level for the job
|
|
445
|
+
* @property {number} priority - Priority score (higher = more important)
|
|
446
|
+
* @property {string} rationale - Why this development is important
|
|
447
|
+
*/
|
|
448
|
+
|
|
449
|
+
/**
|
|
450
|
+
* @typedef {Object} DevelopmentPath
|
|
451
|
+
* @property {JobDefinition} targetJob - The target job
|
|
452
|
+
* @property {DevelopmentItem[]} items - Prioritized development items
|
|
453
|
+
* @property {number} estimatedReadiness - Current readiness score (0-1)
|
|
454
|
+
*/
|
|
455
|
+
|
|
456
|
+
/**
|
|
457
|
+
* @typedef {Object} DriverCoverage
|
|
458
|
+
* @property {string} driverId - The driver ID
|
|
459
|
+
* @property {string} driverName - The driver name
|
|
460
|
+
* @property {number} skillCoverage - Percentage of linked skills at Working+ (0-1)
|
|
461
|
+
* @property {number} behaviourCoverage - Percentage of linked behaviours at Practicing+ (0-1)
|
|
462
|
+
* @property {number} overallScore - Weighted average of skill and behaviour coverage
|
|
463
|
+
* @property {string[]} coveredSkills - Skills that meet the threshold
|
|
464
|
+
* @property {string[]} coveredBehaviours - Behaviours that meet the threshold
|
|
465
|
+
* @property {string[]} missingSkills - Skills below threshold
|
|
466
|
+
* @property {string[]} missingBehaviours - Behaviours below threshold
|
|
467
|
+
*/
|
|
468
|
+
|
|
469
|
+
/**
|
|
470
|
+
* @typedef {Object} InterviewQuestion
|
|
471
|
+
* @property {Question} question - The question details
|
|
472
|
+
* @property {string} targetId - The skill or behaviour ID this assesses
|
|
473
|
+
* @property {string} targetName - The skill or behaviour name
|
|
474
|
+
* @property {string} targetType - 'skill' or 'behaviour'
|
|
475
|
+
* @property {string} targetLevel - The level this question assesses
|
|
476
|
+
* @property {number} priority - Priority in the interview (higher = ask first)
|
|
477
|
+
*/
|
|
478
|
+
|
|
479
|
+
/**
|
|
480
|
+
* @typedef {Object} InterviewGuide
|
|
481
|
+
* @property {JobDefinition} job - The job being interviewed for
|
|
482
|
+
* @property {InterviewQuestion[]} questions - Ordered list of questions
|
|
483
|
+
* @property {number} estimatedMinutes - Total estimated time
|
|
484
|
+
* @property {Object} coverage - Coverage summary
|
|
485
|
+
* @property {string[]} coverage.skills - Skills covered
|
|
486
|
+
* @property {string[]} coverage.behaviours - Behaviours covered
|
|
487
|
+
*/
|
|
488
|
+
|
|
489
|
+
/**
|
|
490
|
+
* @typedef {Object} ValidationError
|
|
491
|
+
* @property {string} type - Error type identifier
|
|
492
|
+
* @property {string} message - Human-readable error message
|
|
493
|
+
* @property {string} [path] - Path to the invalid data
|
|
494
|
+
* @property {*} [value] - The invalid value
|
|
495
|
+
*/
|
|
496
|
+
|
|
497
|
+
/**
|
|
498
|
+
* @typedef {Object} ValidationWarning
|
|
499
|
+
* @property {string} type - Warning type identifier
|
|
500
|
+
* @property {string} message - Human-readable warning message
|
|
501
|
+
* @property {string} [path] - Path to the concerning data
|
|
502
|
+
*/
|
|
503
|
+
|
|
504
|
+
/**
|
|
505
|
+
* @typedef {Object} ValidationResult
|
|
506
|
+
* @property {boolean} valid - Whether validation passed
|
|
507
|
+
* @property {ValidationError[]} errors - Array of validation errors
|
|
508
|
+
* @property {ValidationWarning[]} warnings - Array of validation warnings
|
|
509
|
+
*/
|
|
510
|
+
|
|
511
|
+
/**
|
|
512
|
+
* @typedef {Object} JobValidationRules
|
|
513
|
+
* @property {Array<{discipline: string, grade?: string, track?: string}>} [invalidCombinations] - Invalid combinations
|
|
514
|
+
* @property {Object<string, string[]>} [validTracksByDiscipline] - Valid tracks per discipline
|
|
515
|
+
*/
|
|
516
|
+
|
|
517
|
+
/**
|
|
518
|
+
* Helper function to get skill level index
|
|
519
|
+
* @param {string} level - The skill level
|
|
520
|
+
* @returns {number} The index (0-4), or -1 if invalid
|
|
521
|
+
*/
|
|
522
|
+
export function getSkillLevelIndex(level) {
|
|
523
|
+
return SKILL_LEVEL_ORDER.indexOf(level);
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
/**
|
|
527
|
+
* Helper function to get behaviour maturity index
|
|
528
|
+
* @param {string} maturity - The maturity level
|
|
529
|
+
* @returns {number} The index (0-3), or -1 if invalid
|
|
530
|
+
*/
|
|
531
|
+
export function getBehaviourMaturityIndex(maturity) {
|
|
532
|
+
return BEHAVIOUR_MATURITY_ORDER.indexOf(maturity);
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
/**
|
|
536
|
+
* Clamp a skill level index to valid range
|
|
537
|
+
* @param {number} index - The index to clamp
|
|
538
|
+
* @returns {string} The clamped skill level
|
|
539
|
+
*/
|
|
540
|
+
export function clampSkillLevel(index) {
|
|
541
|
+
const clampedIndex = Math.max(
|
|
542
|
+
0,
|
|
543
|
+
Math.min(SKILL_LEVEL_ORDER.length - 1, index),
|
|
544
|
+
);
|
|
545
|
+
return SKILL_LEVEL_ORDER[clampedIndex];
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
/**
|
|
549
|
+
* Clamp a behaviour maturity index to valid range
|
|
550
|
+
* @param {number} index - The index to clamp
|
|
551
|
+
* @returns {string} The clamped maturity level
|
|
552
|
+
*/
|
|
553
|
+
export function clampBehaviourMaturity(index) {
|
|
554
|
+
const clampedIndex = Math.max(
|
|
555
|
+
0,
|
|
556
|
+
Math.min(BEHAVIOUR_MATURITY_ORDER.length - 1, index),
|
|
557
|
+
);
|
|
558
|
+
return BEHAVIOUR_MATURITY_ORDER[clampedIndex];
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
/**
|
|
562
|
+
* Check if a skill level meets or exceeds a requirement
|
|
563
|
+
* @param {string} actual - The actual skill level
|
|
564
|
+
* @param {string} required - The required skill level
|
|
565
|
+
* @returns {boolean} True if actual meets or exceeds required
|
|
566
|
+
*/
|
|
567
|
+
export function skillLevelMeetsRequirement(actual, required) {
|
|
568
|
+
return getSkillLevelIndex(actual) >= getSkillLevelIndex(required);
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
/**
|
|
572
|
+
* Check if a behaviour maturity meets or exceeds a requirement
|
|
573
|
+
* @param {string} actual - The actual maturity level
|
|
574
|
+
* @param {string} required - The required maturity level
|
|
575
|
+
* @returns {boolean} True if actual meets or exceeds required
|
|
576
|
+
*/
|
|
577
|
+
export function behaviourMaturityMeetsRequirement(actual, required) {
|
|
578
|
+
return (
|
|
579
|
+
getBehaviourMaturityIndex(actual) >= getBehaviourMaturityIndex(required)
|
|
580
|
+
);
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
/**
|
|
584
|
+
* Get emoji for a concept from framework data
|
|
585
|
+
* @param {Object} framework - Framework object loaded from framework.yaml
|
|
586
|
+
* @param {string} concept - The concept type: 'driver', 'skill', 'behaviour', 'discipline', 'grade', or 'track'
|
|
587
|
+
* @returns {string} The emoji for the concept or default "💡"
|
|
588
|
+
*/
|
|
589
|
+
export function getConceptEmoji(framework, concept) {
|
|
590
|
+
return framework?.entityDefinitions?.[concept]?.emoji || "💡";
|
|
591
|
+
}
|