Compare commits
29
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f7a68d7e37 | ||
|
|
c934ddb5e0 | ||
|
|
e22d3a5c13 | ||
|
|
386133c8b6 | ||
|
|
abe00994a1 | ||
|
|
c4b4c38e62 | ||
|
|
85852f0744 | ||
|
|
b9c2047c61 | ||
|
|
a35cade49c | ||
|
|
ef169cec58 | ||
|
|
e0afa78eb2 | ||
|
|
e087adab1e | ||
|
|
325363d89c | ||
|
|
ad7312b65a | ||
|
|
3238e1d809 | ||
|
|
fe4c3509d1 | ||
|
|
8a7dbea852 | ||
|
|
e10b03dff4 | ||
|
|
733d6f2ece | ||
|
|
2a4e058684 | ||
|
|
63f38597a6 | ||
|
|
0248baa97b | ||
|
|
7e3696d2d7 | ||
|
|
15c5dcb31d | ||
|
|
64b2d6dae8 | ||
|
|
20e6f4899c | ||
|
|
2f68e60cec | ||
|
|
e149131307 | ||
|
|
2d63313180 |
No files matched your search
@@ -2,138 +2,244 @@
|
||||
"schema_version": 1,
|
||||
"diagram_type": "architecture",
|
||||
"meta": {
|
||||
"title": "TO-BE: Learn before expanding",
|
||||
"title": "TO-BE: Adoption",
|
||||
"output": "static/diagrams/strategy-adoption-mobile/index.html",
|
||||
"quality_profile": "showcase",
|
||||
"legend": {
|
||||
"mode": "hidden"
|
||||
}
|
||||
},
|
||||
"viewBox": [
|
||||
880,
|
||||
2040
|
||||
]
|
||||
},
|
||||
"components": [
|
||||
{
|
||||
"id": "choose",
|
||||
"type": "backend",
|
||||
"label": "Choose workflow",
|
||||
"sublabel": "Department outcome",
|
||||
"id": "delivery",
|
||||
"type": "external",
|
||||
"label": "Delivery first",
|
||||
"tag": "Start with a real workflow",
|
||||
"sublabel": "Workflow baseline + canary",
|
||||
"pos": [
|
||||
20,
|
||||
20
|
||||
60,
|
||||
120
|
||||
],
|
||||
"size": [
|
||||
180,
|
||||
60
|
||||
]
|
||||
740,
|
||||
220
|
||||
],
|
||||
"icon": "none"
|
||||
},
|
||||
{
|
||||
"id": "coach",
|
||||
"id": "human",
|
||||
"type": "backend",
|
||||
"label": "Coach people",
|
||||
"sublabel": "Verify + recover",
|
||||
"label": "Human",
|
||||
"tag": "Direct + guide + review",
|
||||
"sublabel": "Define outcome; inspect artifacts",
|
||||
"pos": [
|
||||
20,
|
||||
140
|
||||
60,
|
||||
1280
|
||||
],
|
||||
"size": [
|
||||
180,
|
||||
60
|
||||
]
|
||||
740,
|
||||
220
|
||||
],
|
||||
"icon": "none"
|
||||
},
|
||||
{
|
||||
"id": "canary",
|
||||
"type": "backend",
|
||||
"label": "Run bounded canary",
|
||||
"sublabel": "Qualified skill + client",
|
||||
"id": "agent",
|
||||
"type": "external",
|
||||
"label": "AI Agent",
|
||||
"tag": "Qualified client + authorized pilot",
|
||||
"sublabel": "Produce work within the boundary",
|
||||
"pos": [
|
||||
20,
|
||||
260
|
||||
60,
|
||||
910
|
||||
],
|
||||
"size": [
|
||||
180,
|
||||
60
|
||||
]
|
||||
740,
|
||||
220
|
||||
],
|
||||
"icon": "none"
|
||||
},
|
||||
{
|
||||
"id": "accept",
|
||||
"type": "backend",
|
||||
"label": "Accept real work",
|
||||
"sublabel": "Independent review",
|
||||
"id": "learn",
|
||||
"type": "external",
|
||||
"label": "Learn from real work",
|
||||
"tag": "Ongoing, reviewed improvement",
|
||||
"sublabel": "Feedback + selected measures\nRetain a manual path\nNo quotas or rankings",
|
||||
"pos": [
|
||||
20,
|
||||
380
|
||||
60,
|
||||
490
|
||||
],
|
||||
"size": [
|
||||
180,
|
||||
60
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "feedback",
|
||||
"type": "backend",
|
||||
"label": "Review feedback",
|
||||
"sublabel": "Usefulness + non-use",
|
||||
"pos": [
|
||||
20,
|
||||
500
|
||||
740,
|
||||
270
|
||||
],
|
||||
"size": [
|
||||
180,
|
||||
60
|
||||
]
|
||||
"icon": "none"
|
||||
},
|
||||
{
|
||||
"id": "expand",
|
||||
"type": "backend",
|
||||
"label": "Expand or revise",
|
||||
"sublabel": "Keep a manual path",
|
||||
"label": "Expand on evidence",
|
||||
"tag": "Other SDLC phases",
|
||||
"sublabel": "Later order undecided\nDelivery keeps improving",
|
||||
"pos": [
|
||||
20,
|
||||
620
|
||||
60,
|
||||
1650
|
||||
],
|
||||
"size": [
|
||||
180,
|
||||
60
|
||||
]
|
||||
740,
|
||||
240
|
||||
],
|
||||
"icon": "none"
|
||||
}
|
||||
],
|
||||
"connections": [
|
||||
{
|
||||
"id": "flow-0",
|
||||
"from": "choose",
|
||||
"to": "coach",
|
||||
"label": "Prepare"
|
||||
},
|
||||
{
|
||||
"id": "flow-1",
|
||||
"from": "coach",
|
||||
"to": "canary",
|
||||
"label": "support pilot"
|
||||
},
|
||||
{
|
||||
"id": "flow-2",
|
||||
"from": "canary",
|
||||
"to": "accept",
|
||||
"label": "Verify"
|
||||
},
|
||||
{
|
||||
"id": "flow-3",
|
||||
"from": "accept",
|
||||
"to": "feedback",
|
||||
"label": "learn"
|
||||
},
|
||||
{
|
||||
"id": "flow-4",
|
||||
"from": "feedback",
|
||||
"to": "expand",
|
||||
"label": "decide"
|
||||
},
|
||||
{
|
||||
"id": "feedback-loop",
|
||||
"from": "expand",
|
||||
"to": "coach",
|
||||
"label": "Review revision",
|
||||
"variant": "dashed",
|
||||
"id": "delivery-agent",
|
||||
"from": "delivery",
|
||||
"to": "agent",
|
||||
"label": "Practice",
|
||||
"fromSide": "right",
|
||||
"toSide": "right"
|
||||
"toSide": "right",
|
||||
"route": "straight",
|
||||
"width": 4,
|
||||
"variant": "default",
|
||||
"via": [
|
||||
[
|
||||
850,
|
||||
230.0
|
||||
],
|
||||
[
|
||||
850,
|
||||
1020.0
|
||||
]
|
||||
],
|
||||
"labelAt": [
|
||||
780,
|
||||
870
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "human-agent",
|
||||
"from": "human",
|
||||
"to": "agent",
|
||||
"label": "Direction",
|
||||
"fromSide": "right",
|
||||
"toSide": "right",
|
||||
"route": "straight",
|
||||
"width": 4,
|
||||
"variant": "default",
|
||||
"via": [
|
||||
[
|
||||
824,
|
||||
1390.0
|
||||
],
|
||||
[
|
||||
824,
|
||||
1020.0
|
||||
]
|
||||
],
|
||||
"labelAt": [
|
||||
770,
|
||||
1240
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "agent-human",
|
||||
"from": "agent",
|
||||
"to": "human",
|
||||
"label": "Work to inspect",
|
||||
"fromSide": "bottom",
|
||||
"toSide": "top",
|
||||
"route": "straight",
|
||||
"width": 4,
|
||||
"variant": "default",
|
||||
"labelAt": [
|
||||
610,
|
||||
1185
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "agent-learn",
|
||||
"from": "agent",
|
||||
"to": "learn",
|
||||
"label": "Observe",
|
||||
"fromSide": "top",
|
||||
"toSide": "bottom",
|
||||
"route": "straight",
|
||||
"width": 4,
|
||||
"variant": "default",
|
||||
"labelAt": [
|
||||
610,
|
||||
815
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "learn-delivery",
|
||||
"from": "learn",
|
||||
"to": "delivery",
|
||||
"label": "Improve",
|
||||
"fromSide": "left",
|
||||
"toSide": "left",
|
||||
"route": "straight",
|
||||
"width": 4,
|
||||
"variant": "default",
|
||||
"via": [
|
||||
[
|
||||
42,
|
||||
625.0
|
||||
],
|
||||
[
|
||||
42,
|
||||
230.0
|
||||
]
|
||||
],
|
||||
"labelAt": [
|
||||
620,
|
||||
80
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "human-expand",
|
||||
"from": "human",
|
||||
"to": "expand",
|
||||
"label": "Accepted work",
|
||||
"fromSide": "bottom",
|
||||
"toSide": "top",
|
||||
"route": "straight",
|
||||
"width": 4,
|
||||
"variant": "default",
|
||||
"labelAt": [
|
||||
610,
|
||||
1555
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "learn-expand",
|
||||
"from": "learn",
|
||||
"to": "expand",
|
||||
"label": "Feedback",
|
||||
"fromSide": "left",
|
||||
"toSide": "left",
|
||||
"route": "straight",
|
||||
"width": 4,
|
||||
"variant": "default",
|
||||
"via": [
|
||||
[
|
||||
20,
|
||||
625.0
|
||||
],
|
||||
[
|
||||
20,
|
||||
1770.0
|
||||
]
|
||||
],
|
||||
"labelAt": [
|
||||
620,
|
||||
1610
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -2,138 +2,242 @@
|
||||
"schema_version": 1,
|
||||
"diagram_type": "architecture",
|
||||
"meta": {
|
||||
"title": "TO-BE: Learn before expanding",
|
||||
"title": "TO-BE: Adoption",
|
||||
"output": "static/diagrams/strategy-adoption/index.html",
|
||||
"quality_profile": "showcase",
|
||||
"legend": {
|
||||
"mode": "hidden"
|
||||
}
|
||||
},
|
||||
"viewBox": [
|
||||
2040,
|
||||
1160
|
||||
]
|
||||
},
|
||||
"components": [
|
||||
{
|
||||
"id": "choose",
|
||||
"type": "backend",
|
||||
"label": "Choose workflow",
|
||||
"sublabel": "Department outcome",
|
||||
"id": "delivery",
|
||||
"type": "external",
|
||||
"label": "Delivery first",
|
||||
"tag": "Start with a real workflow",
|
||||
"sublabel": "Workflow baseline + canary",
|
||||
"pos": [
|
||||
20,
|
||||
20
|
||||
60,
|
||||
350
|
||||
],
|
||||
"size": [
|
||||
180,
|
||||
60
|
||||
]
|
||||
470,
|
||||
210
|
||||
],
|
||||
"icon": "none"
|
||||
},
|
||||
{
|
||||
"id": "coach",
|
||||
"id": "human",
|
||||
"type": "backend",
|
||||
"label": "Coach people",
|
||||
"sublabel": "Verify + recover",
|
||||
"label": "Human",
|
||||
"tag": "Direct + guide + review",
|
||||
"sublabel": "Define outcome; inspect artifacts",
|
||||
"pos": [
|
||||
260,
|
||||
20
|
||||
700,
|
||||
90
|
||||
],
|
||||
"size": [
|
||||
180,
|
||||
60
|
||||
]
|
||||
570,
|
||||
190
|
||||
],
|
||||
"icon": "none"
|
||||
},
|
||||
{
|
||||
"id": "canary",
|
||||
"type": "backend",
|
||||
"label": "Run bounded canary",
|
||||
"sublabel": "Qualified skill + client",
|
||||
"id": "agent",
|
||||
"type": "external",
|
||||
"label": "AI Agent",
|
||||
"tag": "Qualified client + authorized pilot",
|
||||
"sublabel": "Produce work within the boundary",
|
||||
"pos": [
|
||||
260,
|
||||
150
|
||||
700,
|
||||
440
|
||||
],
|
||||
"size": [
|
||||
180,
|
||||
60
|
||||
]
|
||||
570,
|
||||
190
|
||||
],
|
||||
"icon": "none"
|
||||
},
|
||||
{
|
||||
"id": "accept",
|
||||
"type": "backend",
|
||||
"label": "Accept real work",
|
||||
"sublabel": "Independent review",
|
||||
"id": "learn",
|
||||
"type": "external",
|
||||
"label": "Learn from real work",
|
||||
"tag": "Ongoing, reviewed improvement",
|
||||
"sublabel": "Feedback + selected measures\nRetain a manual path\nNo quotas or rankings",
|
||||
"pos": [
|
||||
20,
|
||||
150
|
||||
700,
|
||||
800
|
||||
],
|
||||
"size": [
|
||||
180,
|
||||
60
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "feedback",
|
||||
"type": "backend",
|
||||
"label": "Review feedback",
|
||||
"sublabel": "Usefulness + non-use",
|
||||
"pos": [
|
||||
20,
|
||||
280
|
||||
570,
|
||||
270
|
||||
],
|
||||
"size": [
|
||||
180,
|
||||
60
|
||||
]
|
||||
"icon": "none"
|
||||
},
|
||||
{
|
||||
"id": "expand",
|
||||
"type": "backend",
|
||||
"label": "Expand or revise",
|
||||
"sublabel": "Keep a manual path",
|
||||
"label": "Expand on evidence",
|
||||
"tag": "Other SDLC phases",
|
||||
"sublabel": "Later order undecided\nDelivery keeps improving",
|
||||
"pos": [
|
||||
260,
|
||||
280
|
||||
1460,
|
||||
360
|
||||
],
|
||||
"size": [
|
||||
180,
|
||||
60
|
||||
]
|
||||
520,
|
||||
240
|
||||
],
|
||||
"icon": "none"
|
||||
}
|
||||
],
|
||||
"connections": [
|
||||
{
|
||||
"id": "flow-0",
|
||||
"from": "choose",
|
||||
"to": "coach",
|
||||
"label": "Prepare"
|
||||
},
|
||||
{
|
||||
"id": "flow-1",
|
||||
"from": "coach",
|
||||
"to": "canary",
|
||||
"label": "support pilot"
|
||||
},
|
||||
{
|
||||
"id": "flow-2",
|
||||
"from": "canary",
|
||||
"to": "accept",
|
||||
"label": "Verify"
|
||||
},
|
||||
{
|
||||
"id": "flow-3",
|
||||
"from": "accept",
|
||||
"to": "feedback",
|
||||
"label": "learn"
|
||||
},
|
||||
{
|
||||
"id": "flow-4",
|
||||
"from": "feedback",
|
||||
"to": "expand",
|
||||
"label": "decide"
|
||||
},
|
||||
{
|
||||
"id": "feedback-loop",
|
||||
"from": "expand",
|
||||
"to": "coach",
|
||||
"label": "Review revision",
|
||||
"variant": "dashed",
|
||||
"id": "delivery-agent",
|
||||
"from": "delivery",
|
||||
"to": "agent",
|
||||
"label": "Practice",
|
||||
"fromSide": "right",
|
||||
"toSide": "right"
|
||||
"toSide": "left",
|
||||
"route": "straight",
|
||||
"width": 4,
|
||||
"variant": "default",
|
||||
"via": [
|
||||
[
|
||||
585,
|
||||
455
|
||||
],
|
||||
[
|
||||
585,
|
||||
535
|
||||
]
|
||||
],
|
||||
"labelAt": [
|
||||
570,
|
||||
600
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "human-agent",
|
||||
"from": "human",
|
||||
"to": "agent",
|
||||
"label": "Direction",
|
||||
"fromSide": "bottom",
|
||||
"toSide": "top",
|
||||
"route": "straight",
|
||||
"width": 4,
|
||||
"variant": "default",
|
||||
"labelAt": [
|
||||
1100,
|
||||
360
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "agent-human",
|
||||
"from": "agent",
|
||||
"to": "human",
|
||||
"label": "Work to inspect",
|
||||
"fromSide": "left",
|
||||
"toSide": "left",
|
||||
"route": "straight",
|
||||
"width": 4,
|
||||
"variant": "default",
|
||||
"via": [
|
||||
[
|
||||
630,
|
||||
535
|
||||
],
|
||||
[
|
||||
630,
|
||||
185
|
||||
]
|
||||
],
|
||||
"labelAt": [
|
||||
470,
|
||||
240
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "agent-learn",
|
||||
"from": "agent",
|
||||
"to": "learn",
|
||||
"label": "Observe",
|
||||
"fromSide": "bottom",
|
||||
"toSide": "top",
|
||||
"route": "straight",
|
||||
"width": 4,
|
||||
"variant": "default",
|
||||
"labelAt": [
|
||||
1100,
|
||||
720
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "learn-delivery",
|
||||
"from": "learn",
|
||||
"to": "delivery",
|
||||
"label": "Improve",
|
||||
"fromSide": "left",
|
||||
"toSide": "bottom",
|
||||
"route": "straight",
|
||||
"width": 4,
|
||||
"variant": "default",
|
||||
"via": [
|
||||
[
|
||||
295,
|
||||
935
|
||||
]
|
||||
],
|
||||
"labelAt": [
|
||||
450,
|
||||
900
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "human-expand",
|
||||
"from": "human",
|
||||
"to": "expand",
|
||||
"label": "Accepted work",
|
||||
"fromSide": "right",
|
||||
"toSide": "top",
|
||||
"route": "straight",
|
||||
"width": 4,
|
||||
"variant": "default",
|
||||
"via": [
|
||||
[
|
||||
1720,
|
||||
185
|
||||
]
|
||||
],
|
||||
"labelAt": [
|
||||
1550,
|
||||
140
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "learn-expand",
|
||||
"from": "learn",
|
||||
"to": "expand",
|
||||
"label": "Feedback",
|
||||
"fromSide": "right",
|
||||
"toSide": "bottom",
|
||||
"route": "straight",
|
||||
"width": 4,
|
||||
"variant": "default",
|
||||
"via": [
|
||||
[
|
||||
1720,
|
||||
935
|
||||
]
|
||||
],
|
||||
"labelAt": [
|
||||
1480,
|
||||
895
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,144 @@
|
||||
{
|
||||
"schema_version": 1,
|
||||
"diagram_type": "architecture",
|
||||
"meta": {
|
||||
"title": "Workflow baseline",
|
||||
"output": "static/diagrams/strategy-baseline-mobile/index.html",
|
||||
"quality_profile": "showcase",
|
||||
"legend": {
|
||||
"mode": "hidden"
|
||||
},
|
||||
"viewBox": [
|
||||
880,
|
||||
2050
|
||||
]
|
||||
},
|
||||
"components": [
|
||||
{
|
||||
"id": "workflow",
|
||||
"type": "external",
|
||||
"label": "Current workflow",
|
||||
"tag": "01 / Understand",
|
||||
"sublabel": "Task, scope, people\nTools + handoffs\nCurrent practice",
|
||||
"pos": [
|
||||
90,
|
||||
50
|
||||
],
|
||||
"size": [
|
||||
700,
|
||||
350
|
||||
],
|
||||
"icon": "none"
|
||||
},
|
||||
{
|
||||
"id": "selection",
|
||||
"type": "frontend",
|
||||
"label": "Relevant selection",
|
||||
"tag": "02 / Choose",
|
||||
"sublabel": "Registry candidates\nReasons for inclusion\nDefer what does not fit",
|
||||
"pos": [
|
||||
90,
|
||||
450
|
||||
],
|
||||
"size": [
|
||||
700,
|
||||
350
|
||||
],
|
||||
"icon": "none"
|
||||
},
|
||||
{
|
||||
"id": "evidence",
|
||||
"type": "frontend",
|
||||
"label": "Feasible evidence",
|
||||
"tag": "03 / Agree",
|
||||
"sublabel": "Sources + period\nPrivacy, access, owner\nTest joins + coverage",
|
||||
"pos": [
|
||||
90,
|
||||
850
|
||||
],
|
||||
"size": [
|
||||
700,
|
||||
350
|
||||
],
|
||||
"icon": "none"
|
||||
},
|
||||
{
|
||||
"id": "position",
|
||||
"type": "backend",
|
||||
"label": "Starting position",
|
||||
"tag": "04 / Record",
|
||||
"sublabel": "Actual values + limits\nOr unavailable gaps\nNo invented baseline",
|
||||
"pos": [
|
||||
90,
|
||||
1250
|
||||
],
|
||||
"size": [
|
||||
700,
|
||||
350
|
||||
],
|
||||
"icon": "none"
|
||||
},
|
||||
{
|
||||
"id": "comparison",
|
||||
"type": "backend",
|
||||
"label": "Later comparison",
|
||||
"tag": "05 / Evaluate",
|
||||
"sublabel": "Comparable rules\nContext + uncertainty\nNot causal ROI",
|
||||
"pos": [
|
||||
90,
|
||||
1650
|
||||
],
|
||||
"size": [
|
||||
700,
|
||||
350
|
||||
],
|
||||
"icon": "none"
|
||||
}
|
||||
],
|
||||
"connections": [
|
||||
{
|
||||
"id": "workflow-selection",
|
||||
"from": "workflow",
|
||||
"to": "selection",
|
||||
"label": "",
|
||||
"fromSide": "bottom",
|
||||
"toSide": "top",
|
||||
"route": "straight",
|
||||
"width": 4,
|
||||
"variant": "default"
|
||||
},
|
||||
{
|
||||
"id": "selection-evidence",
|
||||
"from": "selection",
|
||||
"to": "evidence",
|
||||
"label": "",
|
||||
"fromSide": "bottom",
|
||||
"toSide": "top",
|
||||
"route": "straight",
|
||||
"width": 4,
|
||||
"variant": "default"
|
||||
},
|
||||
{
|
||||
"id": "evidence-position",
|
||||
"from": "evidence",
|
||||
"to": "position",
|
||||
"label": "",
|
||||
"fromSide": "bottom",
|
||||
"toSide": "top",
|
||||
"route": "straight",
|
||||
"width": 4,
|
||||
"variant": "default"
|
||||
},
|
||||
{
|
||||
"id": "position-comparison",
|
||||
"from": "position",
|
||||
"to": "comparison",
|
||||
"label": "",
|
||||
"fromSide": "bottom",
|
||||
"toSide": "top",
|
||||
"route": "straight",
|
||||
"width": 4,
|
||||
"variant": "default"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,184 @@
|
||||
{
|
||||
"schema_version": 1,
|
||||
"diagram_type": "architecture",
|
||||
"meta": {
|
||||
"title": "Workflow baseline",
|
||||
"output": "static/diagrams/strategy-baseline/index.html",
|
||||
"quality_profile": "showcase",
|
||||
"legend": {
|
||||
"mode": "hidden"
|
||||
},
|
||||
"viewBox": [
|
||||
2400,
|
||||
1120
|
||||
]
|
||||
},
|
||||
"components": [
|
||||
{
|
||||
"id": "workflow",
|
||||
"type": "external",
|
||||
"label": "Current workflow",
|
||||
"tag": "01 / Understand",
|
||||
"sublabel": "Task, scope, people\nTools + handoffs\nCurrent practice",
|
||||
"pos": [
|
||||
40,
|
||||
55
|
||||
],
|
||||
"size": [
|
||||
440,
|
||||
290
|
||||
],
|
||||
"icon": "none"
|
||||
},
|
||||
{
|
||||
"id": "selection",
|
||||
"type": "frontend",
|
||||
"label": "Relevant selection",
|
||||
"tag": "02 / Choose",
|
||||
"sublabel": "Registry candidates\nReasons for inclusion\nDefer what does not fit",
|
||||
"pos": [
|
||||
510,
|
||||
235
|
||||
],
|
||||
"size": [
|
||||
440,
|
||||
290
|
||||
],
|
||||
"icon": "none"
|
||||
},
|
||||
{
|
||||
"id": "evidence",
|
||||
"type": "frontend",
|
||||
"label": "Feasible evidence",
|
||||
"tag": "03 / Agree",
|
||||
"sublabel": "Sources + period\nPrivacy, access, owner\nTest joins + coverage",
|
||||
"pos": [
|
||||
980,
|
||||
415
|
||||
],
|
||||
"size": [
|
||||
440,
|
||||
290
|
||||
],
|
||||
"icon": "none"
|
||||
},
|
||||
{
|
||||
"id": "position",
|
||||
"type": "backend",
|
||||
"label": "Starting position",
|
||||
"tag": "04 / Record",
|
||||
"sublabel": "Actual values + limits\nOr unavailable gaps\nNo invented baseline",
|
||||
"pos": [
|
||||
1450,
|
||||
595
|
||||
],
|
||||
"size": [
|
||||
440,
|
||||
290
|
||||
],
|
||||
"icon": "none"
|
||||
},
|
||||
{
|
||||
"id": "comparison",
|
||||
"type": "backend",
|
||||
"label": "Later comparison",
|
||||
"tag": "05 / Evaluate",
|
||||
"sublabel": "Comparable rules\nContext + uncertainty\nNot causal ROI",
|
||||
"pos": [
|
||||
1920,
|
||||
775
|
||||
],
|
||||
"size": [
|
||||
440,
|
||||
290
|
||||
],
|
||||
"icon": "none"
|
||||
}
|
||||
],
|
||||
"connections": [
|
||||
{
|
||||
"id": "workflow-selection",
|
||||
"from": "workflow",
|
||||
"to": "selection",
|
||||
"label": "",
|
||||
"fromSide": "right",
|
||||
"toSide": "left",
|
||||
"route": "straight",
|
||||
"width": 4,
|
||||
"variant": "default",
|
||||
"via": [
|
||||
[
|
||||
495.0,
|
||||
200.0
|
||||
],
|
||||
[
|
||||
495.0,
|
||||
380.0
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "selection-evidence",
|
||||
"from": "selection",
|
||||
"to": "evidence",
|
||||
"label": "",
|
||||
"fromSide": "right",
|
||||
"toSide": "left",
|
||||
"route": "straight",
|
||||
"width": 4,
|
||||
"variant": "default",
|
||||
"via": [
|
||||
[
|
||||
965.0,
|
||||
380.0
|
||||
],
|
||||
[
|
||||
965.0,
|
||||
560.0
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "evidence-position",
|
||||
"from": "evidence",
|
||||
"to": "position",
|
||||
"label": "",
|
||||
"fromSide": "right",
|
||||
"toSide": "left",
|
||||
"route": "straight",
|
||||
"width": 4,
|
||||
"variant": "default",
|
||||
"via": [
|
||||
[
|
||||
1435.0,
|
||||
560.0
|
||||
],
|
||||
[
|
||||
1435.0,
|
||||
740.0
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "position-comparison",
|
||||
"from": "position",
|
||||
"to": "comparison",
|
||||
"label": "",
|
||||
"fromSide": "right",
|
||||
"toSide": "left",
|
||||
"route": "straight",
|
||||
"width": 4,
|
||||
"variant": "default",
|
||||
"via": [
|
||||
[
|
||||
1905.0,
|
||||
740.0
|
||||
],
|
||||
[
|
||||
1905.0,
|
||||
920.0
|
||||
]
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -2,129 +2,246 @@
|
||||
"schema_version": 1,
|
||||
"diagram_type": "architecture",
|
||||
"meta": {
|
||||
"title": "TO-BE: Independent approval",
|
||||
"title": "TO-BE: Governance",
|
||||
"output": "static/diagrams/strategy-governance-mobile/index.html",
|
||||
"quality_profile": "showcase",
|
||||
"legend": {
|
||||
"mode": "hidden"
|
||||
}
|
||||
},
|
||||
"viewBox": [
|
||||
880,
|
||||
2710
|
||||
]
|
||||
},
|
||||
"components": [
|
||||
{
|
||||
"id": "owner",
|
||||
"type": "security",
|
||||
"label": "Owner proposes",
|
||||
"sublabel": "Existing accountable team",
|
||||
"type": "external",
|
||||
"label": "01 Propose",
|
||||
"tag": "Owning team",
|
||||
"sublabel": "Scope + testable outcome",
|
||||
"pos": [
|
||||
20,
|
||||
20
|
||||
60,
|
||||
120
|
||||
],
|
||||
"size": [
|
||||
180,
|
||||
60
|
||||
]
|
||||
740,
|
||||
220
|
||||
],
|
||||
"icon": "none"
|
||||
},
|
||||
{
|
||||
"id": "review",
|
||||
"type": "security",
|
||||
"label": "Independent review",
|
||||
"sublabel": "Quality + risk evidence",
|
||||
"type": "external",
|
||||
"label": "02 Review independently",
|
||||
"tag": "Quality + Security",
|
||||
"sublabel": "Author is not sole approver",
|
||||
"pos": [
|
||||
20,
|
||||
140
|
||||
60,
|
||||
490
|
||||
],
|
||||
"size": [
|
||||
180,
|
||||
60
|
||||
]
|
||||
740,
|
||||
220
|
||||
],
|
||||
"icon": "none"
|
||||
},
|
||||
{
|
||||
"id": "canary",
|
||||
"type": "security",
|
||||
"label": "Bounded canary",
|
||||
"sublabel": "Qualified client path",
|
||||
"type": "external",
|
||||
"label": "03 Authorize pilot",
|
||||
"tag": "Owning team approver",
|
||||
"sublabel": "Qualified; bounded pilot",
|
||||
"pos": [
|
||||
20,
|
||||
260
|
||||
60,
|
||||
860
|
||||
],
|
||||
"size": [
|
||||
180,
|
||||
60
|
||||
]
|
||||
740,
|
||||
220
|
||||
],
|
||||
"icon": "none"
|
||||
},
|
||||
{
|
||||
"id": "approve",
|
||||
"type": "security",
|
||||
"label": "Approve revision",
|
||||
"sublabel": "Exact digest + scope",
|
||||
"type": "backend",
|
||||
"label": "04 Approve exact scope",
|
||||
"tag": "Accountable approvers",
|
||||
"sublabel": "Pilot evidence + digest + expiry",
|
||||
"pos": [
|
||||
20,
|
||||
380
|
||||
60,
|
||||
1230
|
||||
],
|
||||
"size": [
|
||||
180,
|
||||
60
|
||||
]
|
||||
740,
|
||||
220
|
||||
],
|
||||
"icon": "none"
|
||||
},
|
||||
{
|
||||
"id": "publish",
|
||||
"type": "security",
|
||||
"label": "Publish bundle",
|
||||
"sublabel": "Data & AI catalog",
|
||||
"type": "backend",
|
||||
"label": "05 Publish the bundle",
|
||||
"tag": "Data & AI catalog",
|
||||
"sublabel": "Pin skill, adapter + dependencies",
|
||||
"pos": [
|
||||
20,
|
||||
500
|
||||
60,
|
||||
1600
|
||||
],
|
||||
"size": [
|
||||
180,
|
||||
60
|
||||
]
|
||||
740,
|
||||
220
|
||||
],
|
||||
"icon": "none"
|
||||
},
|
||||
{
|
||||
"id": "distribute",
|
||||
"type": "security",
|
||||
"label": "Verify effective state",
|
||||
"sublabel": "Platform & IT",
|
||||
"type": "backend",
|
||||
"label": "06 Verify loaded state",
|
||||
"tag": "Platform & IT",
|
||||
"sublabel": "Read revision; verify reload",
|
||||
"pos": [
|
||||
20,
|
||||
620
|
||||
60,
|
||||
1970
|
||||
],
|
||||
"size": [
|
||||
180,
|
||||
60
|
||||
]
|
||||
740,
|
||||
220
|
||||
],
|
||||
"icon": "none"
|
||||
},
|
||||
{
|
||||
"id": "withdraw",
|
||||
"type": "security",
|
||||
"label": "Withdraw / roll back",
|
||||
"tag": "Unsafe revision",
|
||||
"sublabel": "Revoke; restore last-known-good",
|
||||
"pos": [
|
||||
60,
|
||||
2340
|
||||
],
|
||||
"size": [
|
||||
740,
|
||||
220
|
||||
],
|
||||
"icon": "none"
|
||||
}
|
||||
],
|
||||
"connections": [
|
||||
{
|
||||
"id": "flow-0",
|
||||
"id": "owner-review",
|
||||
"from": "owner",
|
||||
"to": "review",
|
||||
"label": "submit"
|
||||
"label": "",
|
||||
"fromSide": "bottom",
|
||||
"toSide": "top",
|
||||
"route": "straight",
|
||||
"width": 4,
|
||||
"variant": "default",
|
||||
"labelAt": [
|
||||
610,
|
||||
395
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "flow-1",
|
||||
"id": "review-canary",
|
||||
"from": "review",
|
||||
"to": "canary",
|
||||
"label": "qualify"
|
||||
"label": "",
|
||||
"fromSide": "bottom",
|
||||
"toSide": "top",
|
||||
"route": "straight",
|
||||
"width": 4,
|
||||
"variant": "default",
|
||||
"labelAt": [
|
||||
610,
|
||||
765
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "flow-2",
|
||||
"id": "canary-approve",
|
||||
"from": "canary",
|
||||
"to": "approve",
|
||||
"label": "Accept"
|
||||
"label": "",
|
||||
"fromSide": "bottom",
|
||||
"toSide": "top",
|
||||
"route": "straight",
|
||||
"width": 4,
|
||||
"variant": "default",
|
||||
"labelAt": [
|
||||
610,
|
||||
1135
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "flow-3",
|
||||
"id": "approve-publish",
|
||||
"from": "approve",
|
||||
"to": "publish",
|
||||
"label": "record approval"
|
||||
"label": "",
|
||||
"fromSide": "bottom",
|
||||
"toSide": "top",
|
||||
"route": "straight",
|
||||
"width": 4,
|
||||
"variant": "default",
|
||||
"labelAt": [
|
||||
610,
|
||||
1505
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "flow-4",
|
||||
"id": "publish-distribute",
|
||||
"from": "publish",
|
||||
"to": "distribute",
|
||||
"label": "Deliver"
|
||||
"label": "",
|
||||
"fromSide": "bottom",
|
||||
"toSide": "top",
|
||||
"route": "straight",
|
||||
"width": 4,
|
||||
"variant": "default",
|
||||
"labelAt": [
|
||||
610,
|
||||
1875
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "approve-owner",
|
||||
"from": "approve",
|
||||
"to": "owner",
|
||||
"label": "Rework",
|
||||
"fromSide": "left",
|
||||
"toSide": "left",
|
||||
"route": "straight",
|
||||
"width": 4,
|
||||
"variant": "security",
|
||||
"via": [
|
||||
[
|
||||
20,
|
||||
1340.0
|
||||
],
|
||||
[
|
||||
20,
|
||||
230.0
|
||||
]
|
||||
],
|
||||
"labelAt": [
|
||||
620,
|
||||
80
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "distribute-withdraw",
|
||||
"from": "distribute",
|
||||
"to": "withdraw",
|
||||
"label": "Unsafe",
|
||||
"fromSide": "bottom",
|
||||
"toSide": "top",
|
||||
"route": "straight",
|
||||
"width": 4,
|
||||
"variant": "security",
|
||||
"labelAt": [
|
||||
610,
|
||||
2245
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -2,129 +2,276 @@
|
||||
"schema_version": 1,
|
||||
"diagram_type": "architecture",
|
||||
"meta": {
|
||||
"title": "TO-BE: Independent approval",
|
||||
"title": "TO-BE: Governance",
|
||||
"output": "static/diagrams/strategy-governance/index.html",
|
||||
"quality_profile": "showcase",
|
||||
"legend": {
|
||||
"mode": "hidden"
|
||||
}
|
||||
},
|
||||
"viewBox": [
|
||||
1760,
|
||||
1420
|
||||
]
|
||||
},
|
||||
"components": [
|
||||
{
|
||||
"id": "owner",
|
||||
"type": "security",
|
||||
"label": "Owner proposes",
|
||||
"sublabel": "Existing accountable team",
|
||||
"type": "external",
|
||||
"label": "01 Propose",
|
||||
"tag": "Owning team",
|
||||
"sublabel": "Scope + testable outcome",
|
||||
"pos": [
|
||||
20,
|
||||
20
|
||||
80,
|
||||
60
|
||||
],
|
||||
"size": [
|
||||
180,
|
||||
60
|
||||
]
|
||||
500,
|
||||
170
|
||||
],
|
||||
"icon": "none"
|
||||
},
|
||||
{
|
||||
"id": "review",
|
||||
"type": "security",
|
||||
"label": "Independent review",
|
||||
"sublabel": "Quality + risk evidence",
|
||||
"type": "external",
|
||||
"label": "02 Review independently",
|
||||
"tag": "Quality + Security",
|
||||
"sublabel": "Author is not sole approver",
|
||||
"pos": [
|
||||
260,
|
||||
20
|
||||
300,
|
||||
280
|
||||
],
|
||||
"size": [
|
||||
180,
|
||||
60
|
||||
]
|
||||
500,
|
||||
170
|
||||
],
|
||||
"icon": "none"
|
||||
},
|
||||
{
|
||||
"id": "canary",
|
||||
"type": "security",
|
||||
"label": "Bounded canary",
|
||||
"sublabel": "Qualified client path",
|
||||
"type": "external",
|
||||
"label": "03 Authorize pilot",
|
||||
"tag": "Owning team approver",
|
||||
"sublabel": "Qualified; bounded pilot",
|
||||
"pos": [
|
||||
260,
|
||||
150
|
||||
520,
|
||||
500
|
||||
],
|
||||
"size": [
|
||||
180,
|
||||
60
|
||||
]
|
||||
500,
|
||||
170
|
||||
],
|
||||
"icon": "none"
|
||||
},
|
||||
{
|
||||
"id": "approve",
|
||||
"type": "security",
|
||||
"label": "Approve revision",
|
||||
"sublabel": "Exact digest + scope",
|
||||
"type": "backend",
|
||||
"label": "04 Approve exact scope",
|
||||
"tag": "Accountable approvers",
|
||||
"sublabel": "Pilot evidence + digest + expiry",
|
||||
"pos": [
|
||||
20,
|
||||
150
|
||||
740,
|
||||
720
|
||||
],
|
||||
"size": [
|
||||
180,
|
||||
60
|
||||
]
|
||||
500,
|
||||
170
|
||||
],
|
||||
"icon": "none"
|
||||
},
|
||||
{
|
||||
"id": "publish",
|
||||
"type": "security",
|
||||
"label": "Publish bundle",
|
||||
"sublabel": "Data & AI catalog",
|
||||
"type": "backend",
|
||||
"label": "05 Publish the bundle",
|
||||
"tag": "Data & AI catalog",
|
||||
"sublabel": "Pin skill, adapter + dependencies",
|
||||
"pos": [
|
||||
20,
|
||||
280
|
||||
960,
|
||||
940
|
||||
],
|
||||
"size": [
|
||||
180,
|
||||
60
|
||||
]
|
||||
500,
|
||||
170
|
||||
],
|
||||
"icon": "none"
|
||||
},
|
||||
{
|
||||
"id": "distribute",
|
||||
"type": "security",
|
||||
"label": "Verify effective state",
|
||||
"sublabel": "Platform & IT",
|
||||
"type": "backend",
|
||||
"label": "06 Verify loaded state",
|
||||
"tag": "Platform & IT",
|
||||
"sublabel": "Read revision; verify reload",
|
||||
"pos": [
|
||||
260,
|
||||
280
|
||||
1180,
|
||||
1160
|
||||
],
|
||||
"size": [
|
||||
180,
|
||||
60
|
||||
]
|
||||
500,
|
||||
170
|
||||
],
|
||||
"icon": "none"
|
||||
},
|
||||
{
|
||||
"id": "withdraw",
|
||||
"type": "security",
|
||||
"label": "Withdraw / roll back",
|
||||
"tag": "Unsafe revision",
|
||||
"sublabel": "Revoke; restore last-known-good",
|
||||
"pos": [
|
||||
80,
|
||||
1160
|
||||
],
|
||||
"size": [
|
||||
660,
|
||||
170
|
||||
],
|
||||
"icon": "none"
|
||||
}
|
||||
],
|
||||
"connections": [
|
||||
{
|
||||
"id": "flow-0",
|
||||
"id": "owner-review",
|
||||
"from": "owner",
|
||||
"to": "review",
|
||||
"label": "submit"
|
||||
"label": "",
|
||||
"fromSide": "bottom",
|
||||
"toSide": "top",
|
||||
"route": "straight",
|
||||
"width": 4,
|
||||
"variant": "default",
|
||||
"via": [
|
||||
[
|
||||
330,
|
||||
255
|
||||
],
|
||||
[
|
||||
550,
|
||||
255
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "flow-1",
|
||||
"id": "review-canary",
|
||||
"from": "review",
|
||||
"to": "canary",
|
||||
"label": "qualify"
|
||||
"label": "",
|
||||
"fromSide": "bottom",
|
||||
"toSide": "top",
|
||||
"route": "straight",
|
||||
"width": 4,
|
||||
"variant": "default",
|
||||
"via": [
|
||||
[
|
||||
550,
|
||||
475
|
||||
],
|
||||
[
|
||||
770,
|
||||
475
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "flow-2",
|
||||
"id": "canary-approve",
|
||||
"from": "canary",
|
||||
"to": "approve",
|
||||
"label": "Accept"
|
||||
"label": "",
|
||||
"fromSide": "bottom",
|
||||
"toSide": "top",
|
||||
"route": "straight",
|
||||
"width": 4,
|
||||
"variant": "default",
|
||||
"via": [
|
||||
[
|
||||
770,
|
||||
695
|
||||
],
|
||||
[
|
||||
990,
|
||||
695
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "flow-3",
|
||||
"id": "approve-publish",
|
||||
"from": "approve",
|
||||
"to": "publish",
|
||||
"label": "record approval"
|
||||
"label": "",
|
||||
"fromSide": "bottom",
|
||||
"toSide": "top",
|
||||
"route": "straight",
|
||||
"width": 4,
|
||||
"variant": "default",
|
||||
"via": [
|
||||
[
|
||||
990,
|
||||
915
|
||||
],
|
||||
[
|
||||
1210,
|
||||
915
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "flow-4",
|
||||
"id": "publish-distribute",
|
||||
"from": "publish",
|
||||
"to": "distribute",
|
||||
"label": "Deliver"
|
||||
"label": "",
|
||||
"fromSide": "bottom",
|
||||
"toSide": "top",
|
||||
"route": "straight",
|
||||
"width": 4,
|
||||
"variant": "default",
|
||||
"via": [
|
||||
[
|
||||
1210,
|
||||
1135
|
||||
],
|
||||
[
|
||||
1430,
|
||||
1135
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "approve-owner",
|
||||
"from": "approve",
|
||||
"to": "owner",
|
||||
"label": "Rework",
|
||||
"fromSide": "left",
|
||||
"toSide": "left",
|
||||
"route": "straight",
|
||||
"width": 4,
|
||||
"variant": "security",
|
||||
"via": [
|
||||
[
|
||||
40,
|
||||
805
|
||||
],
|
||||
[
|
||||
40,
|
||||
145
|
||||
]
|
||||
],
|
||||
"labelAt": [
|
||||
180,
|
||||
680
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "distribute-withdraw",
|
||||
"from": "distribute",
|
||||
"to": "withdraw",
|
||||
"label": "Unsafe",
|
||||
"fromSide": "left",
|
||||
"toSide": "right",
|
||||
"route": "straight",
|
||||
"width": 4,
|
||||
"variant": "security",
|
||||
"labelAt": [
|
||||
950,
|
||||
1220
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -2,140 +2,337 @@
|
||||
"schema_version": 1,
|
||||
"diagram_type": "architecture",
|
||||
"meta": {
|
||||
"title": "TO-BE: Maintain trust over time",
|
||||
"title": "TO-BE: Maintenance",
|
||||
"output": "static/diagrams/strategy-maintenance-mobile/index.html",
|
||||
"quality_profile": "showcase",
|
||||
"legend": {
|
||||
"mode": "hidden"
|
||||
}
|
||||
},
|
||||
"viewBox": [
|
||||
880,
|
||||
3080
|
||||
]
|
||||
},
|
||||
"components": [
|
||||
{
|
||||
"id": "monitor",
|
||||
"type": "backend",
|
||||
"label": "Monitor skills",
|
||||
"sublabel": "Usefulness + safety",
|
||||
"id": "observe",
|
||||
"type": "external",
|
||||
"label": "Observe use",
|
||||
"tag": "Owner + Data & AI",
|
||||
"sublabel": "Selected evidence + drift",
|
||||
"pos": [
|
||||
20,
|
||||
20
|
||||
60,
|
||||
120
|
||||
],
|
||||
"size": [
|
||||
180,
|
||||
60
|
||||
]
|
||||
740,
|
||||
220
|
||||
],
|
||||
"icon": "none"
|
||||
},
|
||||
{
|
||||
"id": "triage",
|
||||
"type": "backend",
|
||||
"label": "Triage changes",
|
||||
"sublabel": "Owner + risk review",
|
||||
"type": "external",
|
||||
"label": "Triage the signal",
|
||||
"tag": "Owning team",
|
||||
"sublabel": "Useful? Safe? Still needed?",
|
||||
"pos": [
|
||||
20,
|
||||
140
|
||||
60,
|
||||
1970
|
||||
],
|
||||
"size": [
|
||||
180,
|
||||
60
|
||||
]
|
||||
740,
|
||||
220
|
||||
],
|
||||
"icon": "none"
|
||||
},
|
||||
{
|
||||
"id": "correct",
|
||||
"type": "backend",
|
||||
"label": "Correct and test",
|
||||
"sublabel": "Independent regression",
|
||||
"id": "change",
|
||||
"type": "external",
|
||||
"label": "Change the skill",
|
||||
"tag": "Reviewed correction",
|
||||
"sublabel": "New immutable revision",
|
||||
"pos": [
|
||||
20,
|
||||
260
|
||||
60,
|
||||
1230
|
||||
],
|
||||
"size": [
|
||||
180,
|
||||
60
|
||||
]
|
||||
740,
|
||||
220
|
||||
],
|
||||
"icon": "none"
|
||||
},
|
||||
{
|
||||
"id": "decision",
|
||||
"type": "backend",
|
||||
"label": "Approve or hold",
|
||||
"sublabel": "Exact revised bundle",
|
||||
"id": "validate",
|
||||
"type": "external",
|
||||
"label": "Revalidate",
|
||||
"tag": "Quality Engineering reviewer",
|
||||
"sublabel": "Fitness + regression + client checks",
|
||||
"pos": [
|
||||
20,
|
||||
380
|
||||
60,
|
||||
860
|
||||
],
|
||||
"size": [
|
||||
180,
|
||||
60
|
||||
]
|
||||
740,
|
||||
220
|
||||
],
|
||||
"icon": "none"
|
||||
},
|
||||
{
|
||||
"id": "promote",
|
||||
"id": "release",
|
||||
"type": "backend",
|
||||
"label": "Promote safely",
|
||||
"sublabel": "Verify state + monitor",
|
||||
"label": "Approve + version",
|
||||
"tag": "Accountable human authority",
|
||||
"sublabel": "Verify distribution and recovery",
|
||||
"pos": [
|
||||
20,
|
||||
500
|
||||
60,
|
||||
490
|
||||
],
|
||||
"size": [
|
||||
180,
|
||||
60
|
||||
]
|
||||
740,
|
||||
220
|
||||
],
|
||||
"icon": "none"
|
||||
},
|
||||
{
|
||||
"id": "observe",
|
||||
"id": "safe",
|
||||
"type": "backend",
|
||||
"label": "Quarantine / rollback",
|
||||
"sublabel": "Revoke unsafe revision",
|
||||
"label": "Continue safe use",
|
||||
"tag": "Substantive review passes",
|
||||
"sublabel": "Keep owner + next review date",
|
||||
"pos": [
|
||||
20,
|
||||
620
|
||||
60,
|
||||
2710
|
||||
],
|
||||
"size": [
|
||||
180,
|
||||
60
|
||||
]
|
||||
740,
|
||||
220
|
||||
],
|
||||
"icon": "none"
|
||||
},
|
||||
{
|
||||
"id": "retire",
|
||||
"type": "external",
|
||||
"label": "Retire deliberately",
|
||||
"tag": "No longer useful",
|
||||
"sublabel": "Reconcile consumers; no new use",
|
||||
"pos": [
|
||||
60,
|
||||
2340
|
||||
],
|
||||
"size": [
|
||||
740,
|
||||
220
|
||||
],
|
||||
"icon": "none"
|
||||
},
|
||||
{
|
||||
"id": "contain",
|
||||
"type": "security",
|
||||
"label": "Contain unsafe use",
|
||||
"tag": "Security + Platform & IT",
|
||||
"sublabel": "Revoke + quarantine + roll back\nNo automatic reinstatement",
|
||||
"pos": [
|
||||
60,
|
||||
1600
|
||||
],
|
||||
"size": [
|
||||
740,
|
||||
220
|
||||
],
|
||||
"icon": "none"
|
||||
}
|
||||
],
|
||||
"connections": [
|
||||
{
|
||||
"id": "flow-0",
|
||||
"from": "monitor",
|
||||
"to": "triage",
|
||||
"label": "Detect"
|
||||
},
|
||||
{
|
||||
"id": "flow-1",
|
||||
"from": "triage",
|
||||
"to": "correct",
|
||||
"label": "scope correction"
|
||||
},
|
||||
{
|
||||
"id": "flow-2",
|
||||
"from": "correct",
|
||||
"to": "decision",
|
||||
"label": "Prove"
|
||||
},
|
||||
{
|
||||
"id": "flow-3",
|
||||
"from": "decision",
|
||||
"to": "promote",
|
||||
"label": "authorize"
|
||||
},
|
||||
|
||||
{
|
||||
"id": "unsafe",
|
||||
"from": "triage",
|
||||
"to": "observe",
|
||||
"label": "Unsafe",
|
||||
"variant": "security",
|
||||
"fromSide": "right",
|
||||
"toSide": "right"
|
||||
},
|
||||
{
|
||||
"id": "review-loop",
|
||||
"id": "observe-triage",
|
||||
"from": "observe",
|
||||
"to": "correct",
|
||||
"label": "Requalify",
|
||||
"variant": "dashed"
|
||||
"to": "triage",
|
||||
"label": "",
|
||||
"fromSide": "left",
|
||||
"toSide": "left",
|
||||
"route": "straight",
|
||||
"width": 4,
|
||||
"variant": "default",
|
||||
"via": [
|
||||
[
|
||||
20,
|
||||
230.0
|
||||
],
|
||||
[
|
||||
20,
|
||||
2080.0
|
||||
]
|
||||
],
|
||||
"labelAt": [
|
||||
620,
|
||||
1930
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "triage-change",
|
||||
"from": "triage",
|
||||
"to": "change",
|
||||
"label": "Correct",
|
||||
"fromSide": "right",
|
||||
"toSide": "right",
|
||||
"route": "straight",
|
||||
"width": 4,
|
||||
"variant": "default",
|
||||
"via": [
|
||||
[
|
||||
850,
|
||||
2080.0
|
||||
],
|
||||
[
|
||||
850,
|
||||
1340.0
|
||||
]
|
||||
],
|
||||
"labelAt": [
|
||||
780,
|
||||
1560
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "change-validate",
|
||||
"from": "change",
|
||||
"to": "validate",
|
||||
"label": "",
|
||||
"fromSide": "top",
|
||||
"toSide": "bottom",
|
||||
"route": "straight",
|
||||
"width": 4,
|
||||
"variant": "default",
|
||||
"labelAt": [
|
||||
610,
|
||||
1135
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "validate-release",
|
||||
"from": "validate",
|
||||
"to": "release",
|
||||
"label": "",
|
||||
"fromSide": "top",
|
||||
"toSide": "bottom",
|
||||
"route": "straight",
|
||||
"width": 4,
|
||||
"variant": "default",
|
||||
"labelAt": [
|
||||
610,
|
||||
765
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "release-observe",
|
||||
"from": "release",
|
||||
"to": "observe",
|
||||
"label": "",
|
||||
"fromSide": "top",
|
||||
"toSide": "bottom",
|
||||
"route": "straight",
|
||||
"width": 4,
|
||||
"variant": "default",
|
||||
"labelAt": [
|
||||
610,
|
||||
395
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "triage-safe",
|
||||
"from": "triage",
|
||||
"to": "safe",
|
||||
"label": "Safe",
|
||||
"fromSide": "right",
|
||||
"toSide": "right",
|
||||
"route": "straight",
|
||||
"width": 4,
|
||||
"variant": "default",
|
||||
"via": [
|
||||
[
|
||||
824,
|
||||
2080.0
|
||||
],
|
||||
[
|
||||
824,
|
||||
2820.0
|
||||
]
|
||||
],
|
||||
"labelAt": [
|
||||
620,
|
||||
2670
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "triage-retire",
|
||||
"from": "triage",
|
||||
"to": "retire",
|
||||
"label": "Retire",
|
||||
"fromSide": "bottom",
|
||||
"toSide": "top",
|
||||
"route": "straight",
|
||||
"width": 4,
|
||||
"variant": "default",
|
||||
"labelAt": [
|
||||
610,
|
||||
2245
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "triage-contain",
|
||||
"from": "triage",
|
||||
"to": "contain",
|
||||
"label": "Unsafe",
|
||||
"fromSide": "top",
|
||||
"toSide": "bottom",
|
||||
"route": "straight",
|
||||
"width": 4,
|
||||
"variant": "security",
|
||||
"labelAt": [
|
||||
610,
|
||||
1875
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "contain-change",
|
||||
"from": "contain",
|
||||
"to": "change",
|
||||
"label": "Reviewed fix",
|
||||
"fromSide": "top",
|
||||
"toSide": "bottom",
|
||||
"route": "straight",
|
||||
"width": 4,
|
||||
"variant": "security",
|
||||
"labelAt": [
|
||||
610,
|
||||
1505
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "safe-observe",
|
||||
"from": "safe",
|
||||
"to": "observe",
|
||||
"label": "Keep watching",
|
||||
"fromSide": "left",
|
||||
"toSide": "left",
|
||||
"route": "straight",
|
||||
"width": 4,
|
||||
"variant": "default",
|
||||
"via": [
|
||||
[
|
||||
42,
|
||||
2820.0
|
||||
],
|
||||
[
|
||||
42,
|
||||
230.0
|
||||
]
|
||||
],
|
||||
"labelAt": [
|
||||
620,
|
||||
80
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -2,140 +2,369 @@
|
||||
"schema_version": 1,
|
||||
"diagram_type": "architecture",
|
||||
"meta": {
|
||||
"title": "TO-BE: Maintain trust over time",
|
||||
"title": "TO-BE: Maintenance",
|
||||
"output": "static/diagrams/strategy-maintenance/index.html",
|
||||
"quality_profile": "showcase",
|
||||
"legend": {
|
||||
"mode": "hidden"
|
||||
}
|
||||
},
|
||||
"viewBox": [
|
||||
2630,
|
||||
1300
|
||||
]
|
||||
},
|
||||
"components": [
|
||||
{
|
||||
"id": "monitor",
|
||||
"type": "backend",
|
||||
"label": "Monitor skills",
|
||||
"sublabel": "Usefulness + safety",
|
||||
"id": "observe",
|
||||
"type": "external",
|
||||
"label": "Observe use",
|
||||
"tag": "Owner + Data & AI",
|
||||
"sublabel": "Selected evidence + drift",
|
||||
"pos": [
|
||||
20,
|
||||
20
|
||||
670,
|
||||
60
|
||||
],
|
||||
"size": [
|
||||
180,
|
||||
60
|
||||
]
|
||||
560,
|
||||
170
|
||||
],
|
||||
"icon": "none"
|
||||
},
|
||||
{
|
||||
"id": "triage",
|
||||
"type": "backend",
|
||||
"label": "Triage changes",
|
||||
"sublabel": "Owner + risk review",
|
||||
"type": "external",
|
||||
"label": "Triage the signal",
|
||||
"tag": "Owning team",
|
||||
"sublabel": "Useful? Safe? Still needed?",
|
||||
"pos": [
|
||||
260,
|
||||
20
|
||||
1340,
|
||||
330
|
||||
],
|
||||
"size": [
|
||||
180,
|
||||
60
|
||||
]
|
||||
500,
|
||||
190
|
||||
],
|
||||
"icon": "none"
|
||||
},
|
||||
{
|
||||
"id": "correct",
|
||||
"type": "backend",
|
||||
"label": "Correct and test",
|
||||
"sublabel": "Independent regression",
|
||||
"id": "change",
|
||||
"type": "external",
|
||||
"label": "Change the skill",
|
||||
"tag": "Reviewed correction",
|
||||
"sublabel": "New immutable revision",
|
||||
"pos": [
|
||||
260,
|
||||
150
|
||||
1240,
|
||||
750
|
||||
],
|
||||
"size": [
|
||||
180,
|
||||
60
|
||||
]
|
||||
520,
|
||||
180
|
||||
],
|
||||
"icon": "none"
|
||||
},
|
||||
{
|
||||
"id": "decision",
|
||||
"type": "backend",
|
||||
"label": "Approve or hold",
|
||||
"sublabel": "Exact revised bundle",
|
||||
"id": "validate",
|
||||
"type": "external",
|
||||
"label": "Revalidate",
|
||||
"tag": "Quality Engineering reviewer",
|
||||
"sublabel": "Fitness + regression + client checks",
|
||||
"pos": [
|
||||
20,
|
||||
150
|
||||
560,
|
||||
970
|
||||
],
|
||||
"size": [
|
||||
180,
|
||||
60
|
||||
]
|
||||
560,
|
||||
180
|
||||
],
|
||||
"icon": "none"
|
||||
},
|
||||
{
|
||||
"id": "promote",
|
||||
"id": "release",
|
||||
"type": "backend",
|
||||
"label": "Promote safely",
|
||||
"sublabel": "Verify state + monitor",
|
||||
"label": "Approve + version",
|
||||
"tag": "Accountable human authority",
|
||||
"sublabel": "Verify distribution and recovery",
|
||||
"pos": [
|
||||
20,
|
||||
280
|
||||
70,
|
||||
570
|
||||
],
|
||||
"size": [
|
||||
180,
|
||||
60
|
||||
]
|
||||
540,
|
||||
180
|
||||
],
|
||||
"icon": "none"
|
||||
},
|
||||
{
|
||||
"id": "observe",
|
||||
"id": "safe",
|
||||
"type": "backend",
|
||||
"label": "Quarantine / rollback",
|
||||
"sublabel": "Revoke unsafe revision",
|
||||
"label": "Continue safe use",
|
||||
"tag": "Substantive review passes",
|
||||
"sublabel": "Keep owner + next review date",
|
||||
"pos": [
|
||||
260,
|
||||
280
|
||||
2010,
|
||||
80
|
||||
],
|
||||
"size": [
|
||||
180,
|
||||
60
|
||||
]
|
||||
550,
|
||||
180
|
||||
],
|
||||
"icon": "none"
|
||||
},
|
||||
{
|
||||
"id": "retire",
|
||||
"type": "external",
|
||||
"label": "Retire deliberately",
|
||||
"tag": "No longer useful",
|
||||
"sublabel": "Reconcile consumers; no new use",
|
||||
"pos": [
|
||||
2010,
|
||||
430
|
||||
],
|
||||
"size": [
|
||||
550,
|
||||
180
|
||||
],
|
||||
"icon": "none"
|
||||
},
|
||||
{
|
||||
"id": "contain",
|
||||
"type": "security",
|
||||
"label": "Contain unsafe use",
|
||||
"tag": "Security + Platform & IT",
|
||||
"sublabel": "Revoke + quarantine + roll back\nNo automatic reinstatement",
|
||||
"pos": [
|
||||
2010,
|
||||
800
|
||||
],
|
||||
"size": [
|
||||
550,
|
||||
220
|
||||
],
|
||||
"icon": "none"
|
||||
}
|
||||
],
|
||||
"connections": [
|
||||
{
|
||||
"id": "flow-0",
|
||||
"from": "monitor",
|
||||
"to": "triage",
|
||||
"label": "Detect"
|
||||
},
|
||||
{
|
||||
"id": "flow-1",
|
||||
"from": "triage",
|
||||
"to": "correct",
|
||||
"label": "scope correction"
|
||||
},
|
||||
{
|
||||
"id": "flow-2",
|
||||
"from": "correct",
|
||||
"to": "decision",
|
||||
"label": "Prove"
|
||||
},
|
||||
{
|
||||
"id": "flow-3",
|
||||
"from": "decision",
|
||||
"to": "promote",
|
||||
"label": "authorize"
|
||||
},
|
||||
|
||||
{
|
||||
"id": "unsafe",
|
||||
"from": "triage",
|
||||
"to": "observe",
|
||||
"label": "Unsafe",
|
||||
"variant": "security",
|
||||
"fromSide": "right",
|
||||
"toSide": "right"
|
||||
},
|
||||
{
|
||||
"id": "review-loop",
|
||||
"id": "observe-triage",
|
||||
"from": "observe",
|
||||
"to": "correct",
|
||||
"label": "Requalify",
|
||||
"variant": "dashed"
|
||||
"to": "triage",
|
||||
"label": "",
|
||||
"fromSide": "right",
|
||||
"toSide": "top",
|
||||
"route": "straight",
|
||||
"width": 4,
|
||||
"variant": "default",
|
||||
"via": [
|
||||
[
|
||||
1590,
|
||||
145
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "triage-change",
|
||||
"from": "triage",
|
||||
"to": "change",
|
||||
"label": "Correct",
|
||||
"fromSide": "bottom",
|
||||
"toSide": "top",
|
||||
"route": "straight",
|
||||
"width": 4,
|
||||
"variant": "default",
|
||||
"via": [
|
||||
[
|
||||
1590,
|
||||
620
|
||||
],
|
||||
[
|
||||
1500,
|
||||
620
|
||||
]
|
||||
],
|
||||
"labelAt": [
|
||||
1450,
|
||||
680
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "change-validate",
|
||||
"from": "change",
|
||||
"to": "validate",
|
||||
"label": "",
|
||||
"fromSide": "bottom",
|
||||
"toSide": "right",
|
||||
"route": "straight",
|
||||
"width": 4,
|
||||
"variant": "default",
|
||||
"via": [
|
||||
[
|
||||
1500,
|
||||
1060
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "validate-release",
|
||||
"from": "validate",
|
||||
"to": "release",
|
||||
"label": "",
|
||||
"fromSide": "left",
|
||||
"toSide": "bottom",
|
||||
"route": "straight",
|
||||
"width": 4,
|
||||
"variant": "default",
|
||||
"via": [
|
||||
[
|
||||
340,
|
||||
1060
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "release-observe",
|
||||
"from": "release",
|
||||
"to": "observe",
|
||||
"label": "",
|
||||
"fromSide": "top",
|
||||
"toSide": "left",
|
||||
"route": "straight",
|
||||
"width": 4,
|
||||
"variant": "default",
|
||||
"via": [
|
||||
[
|
||||
340,
|
||||
145
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "triage-safe",
|
||||
"from": "triage",
|
||||
"to": "safe",
|
||||
"label": "Safe",
|
||||
"fromSide": "right",
|
||||
"toSide": "left",
|
||||
"route": "straight",
|
||||
"width": 4,
|
||||
"variant": "default",
|
||||
"via": [
|
||||
[
|
||||
1920,
|
||||
425
|
||||
],
|
||||
[
|
||||
1920,
|
||||
170
|
||||
]
|
||||
],
|
||||
"labelAt": [
|
||||
1930,
|
||||
210
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "triage-retire",
|
||||
"from": "triage",
|
||||
"to": "retire",
|
||||
"label": "Retire",
|
||||
"fromSide": "right",
|
||||
"toSide": "left",
|
||||
"route": "straight",
|
||||
"width": 4,
|
||||
"variant": "default",
|
||||
"via": [
|
||||
[
|
||||
1950,
|
||||
425
|
||||
],
|
||||
[
|
||||
1950,
|
||||
520
|
||||
]
|
||||
],
|
||||
"labelAt": [
|
||||
1930,
|
||||
490
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "triage-contain",
|
||||
"from": "triage",
|
||||
"to": "contain",
|
||||
"label": "Unsafe",
|
||||
"fromSide": "bottom",
|
||||
"toSide": "left",
|
||||
"route": "straight",
|
||||
"width": 4,
|
||||
"variant": "security",
|
||||
"via": [
|
||||
[
|
||||
1590,
|
||||
580
|
||||
],
|
||||
[
|
||||
1850,
|
||||
580
|
||||
],
|
||||
[
|
||||
1850,
|
||||
910
|
||||
]
|
||||
],
|
||||
"labelAt": [
|
||||
1900,
|
||||
720
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "contain-change",
|
||||
"from": "contain",
|
||||
"to": "change",
|
||||
"label": "Reviewed fix",
|
||||
"fromSide": "bottom",
|
||||
"toSide": "bottom",
|
||||
"route": "straight",
|
||||
"width": 4,
|
||||
"variant": "security",
|
||||
"via": [
|
||||
[
|
||||
2285,
|
||||
1230
|
||||
],
|
||||
[
|
||||
1500,
|
||||
1230
|
||||
]
|
||||
],
|
||||
"labelAt": [
|
||||
1900,
|
||||
1190
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "safe-observe",
|
||||
"from": "safe",
|
||||
"to": "observe",
|
||||
"label": "Keep watching",
|
||||
"fromSide": "top",
|
||||
"toSide": "top",
|
||||
"route": "straight",
|
||||
"width": 4,
|
||||
"variant": "default",
|
||||
"via": [
|
||||
[
|
||||
2285,
|
||||
20
|
||||
],
|
||||
[
|
||||
950,
|
||||
20
|
||||
]
|
||||
],
|
||||
"labelAt": [
|
||||
1640,
|
||||
45
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,130 +1,20 @@
|
||||
{
|
||||
"schema_version": 1,
|
||||
"diagram_type": "architecture",
|
||||
"meta": {
|
||||
"title": "TO-BE: Measure skills adoption",
|
||||
"output": "static/diagrams/strategy-measurement-mobile/index.html",
|
||||
"quality_profile": "showcase",
|
||||
"legend": {
|
||||
"mode": "hidden"
|
||||
}
|
||||
},
|
||||
"meta": {"title": "Two connected measurement tracks", "output": "static/diagrams/strategy-measurement-mobile/index.html", "quality_profile": "showcase", "legend": {"mode": "hidden"}, "viewBox": [880, 2450]},
|
||||
"components": [
|
||||
{
|
||||
"id": "collect",
|
||||
"type": "backend",
|
||||
"label": "Establish baseline",
|
||||
"sublabel": "Current workflow",
|
||||
"pos": [
|
||||
20,
|
||||
20
|
||||
],
|
||||
"size": [
|
||||
180,
|
||||
60
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "validate",
|
||||
"type": "backend",
|
||||
"label": "Join evidence",
|
||||
"sublabel": "Tasks / versions / costs",
|
||||
"pos": [
|
||||
20,
|
||||
140
|
||||
],
|
||||
"size": [
|
||||
180,
|
||||
60
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "calculate",
|
||||
"type": "backend",
|
||||
"label": "Measure the pilot",
|
||||
"sublabel": "Outcomes / quality",
|
||||
"pos": [
|
||||
20,
|
||||
260
|
||||
],
|
||||
"size": [
|
||||
180,
|
||||
60
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "balance",
|
||||
"type": "backend",
|
||||
"label": "Report together",
|
||||
"sublabel": "Cost / confidence / gaps",
|
||||
"pos": [
|
||||
20,
|
||||
380
|
||||
],
|
||||
"size": [
|
||||
180,
|
||||
60
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "weigh",
|
||||
"type": "backend",
|
||||
"label": "Broader adoption",
|
||||
"sublabel": "Availability + use",
|
||||
"pos": [
|
||||
20,
|
||||
500
|
||||
],
|
||||
"size": [
|
||||
180,
|
||||
60
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "decide",
|
||||
"type": "backend",
|
||||
"label": "Ongoing monitoring",
|
||||
"sublabel": "Review + maintenance",
|
||||
"pos": [
|
||||
20,
|
||||
620
|
||||
],
|
||||
"size": [
|
||||
180,
|
||||
60
|
||||
]
|
||||
}
|
||||
{"id": "workflow", "type": "backend", "label": "Workflow effectiveness", "tag": "01 / Baseline current work", "sublabel": "Accepted work, time, failures\nCost, effort + experience\nSelect relevant contracts only\nSkills need not exist yet", "pos": [90, 50], "size": [700, 350], "icon": "none"},
|
||||
{"id": "compare", "type": "backend", "label": "Compare the same outcomes", "tag": "02 / After introducing skills", "sublabel": "Same workflow + acceptance\nSame follow-up + source coverage\nKeep gaps and task mix visible\nBefore / after is not causality", "pos": [90, 450], "size": [700, 350], "icon": "none"},
|
||||
{"id": "interpret", "type": "external", "label": "Is work getting better?", "tag": "03 / Interpret workflow evidence", "sublabel": "Balance value, quality and risk\nMore adoption is not better work\nKeep live outcomes separate\nfrom skill evaluation cases", "pos": [90, 850], "size": [700, 350], "icon": "none"},
|
||||
{"id": "skills", "type": "frontend", "label": "Skills effectiveness & health", "tag": "01 / Qualify named skill versions", "sublabel": "Quality: artifact fitness + safety\nCandidate / approved regression\nSelection precision + recall\nNo applicable skills: N/A", "pos": [90, 1250], "size": [700, 350], "icon": "none"},
|
||||
{"id": "observe", "type": "frontend", "label": "Observe use + upkeep", "tag": "02 / Adoption and maintenance", "sublabel": "Supported bundle coverage\nApproved-workflow adoption\nSubstantive review evidence\nMissing observations: unknown", "pos": [90, 1650], "size": [700, 350], "icon": "none"},
|
||||
{"id": "improve", "type": "external", "label": "Improve, retain or retire", "tag": "03 / Use both tracks together", "sublabel": "Owner + independent evidence\nRetain / improve / stop\nNew scope needs new comparison\nNo mandatory collection", "pos": [90, 2050], "size": [700, 350], "icon": "none"}
|
||||
],
|
||||
"connections": [
|
||||
{
|
||||
"id": "flow-0",
|
||||
"from": "collect",
|
||||
"to": "validate",
|
||||
"label": "prepare"
|
||||
},
|
||||
{
|
||||
"id": "flow-1",
|
||||
"from": "validate",
|
||||
"to": "calculate",
|
||||
"label": "collect"
|
||||
},
|
||||
{
|
||||
"id": "flow-2",
|
||||
"from": "calculate",
|
||||
"to": "balance",
|
||||
"label": "calculate"
|
||||
},
|
||||
{
|
||||
"id": "flow-3",
|
||||
"from": "balance",
|
||||
"to": "weigh",
|
||||
"label": "extend"
|
||||
},
|
||||
{
|
||||
"id": "flow-4",
|
||||
"from": "weigh",
|
||||
"to": "decide",
|
||||
"label": "repeat"
|
||||
}
|
||||
{"id": "workflow-compare", "from": "workflow", "to": "compare", "label": "", "fromSide": "bottom", "toSide": "top", "route": "straight", "width": 4, "variant": "default"},
|
||||
{"id": "compare-interpret", "from": "compare", "to": "interpret", "label": "", "fromSide": "bottom", "toSide": "top", "route": "straight", "width": 4, "variant": "default"},
|
||||
{"id": "skills-observe", "from": "skills", "to": "observe", "label": "", "fromSide": "bottom", "toSide": "top", "route": "straight", "width": 4, "variant": "default"},
|
||||
{"id": "observe-improve", "from": "observe", "to": "improve", "label": "", "fromSide": "bottom", "toSide": "top", "route": "straight", "width": 4, "variant": "default"},
|
||||
{"id": "interpret-improve", "from": "interpret", "to": "improve", "label": "", "fromSide": "right", "toSide": "right", "route": "straight", "width": 4, "variant": "default", "via": [[835, 1025], [835, 2225]]}
|
||||
]
|
||||
}
|
||||
@@ -1,130 +1,20 @@
|
||||
{
|
||||
"schema_version": 1,
|
||||
"diagram_type": "architecture",
|
||||
"meta": {
|
||||
"title": "TO-BE: Measure skills adoption",
|
||||
"output": "static/diagrams/strategy-measurement/index.html",
|
||||
"quality_profile": "showcase",
|
||||
"legend": {
|
||||
"mode": "hidden"
|
||||
}
|
||||
},
|
||||
"meta": {"title": "Two connected measurement tracks", "output": "static/diagrams/strategy-measurement/index.html", "quality_profile": "showcase", "legend": {"mode": "hidden"}, "viewBox": [2400, 960]},
|
||||
"components": [
|
||||
{
|
||||
"id": "collect",
|
||||
"type": "backend",
|
||||
"label": "Establish baseline",
|
||||
"sublabel": "Current workflow",
|
||||
"pos": [
|
||||
20,
|
||||
20
|
||||
],
|
||||
"size": [
|
||||
180,
|
||||
60
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "validate",
|
||||
"type": "backend",
|
||||
"label": "Join evidence",
|
||||
"sublabel": "Tasks / versions / costs",
|
||||
"pos": [
|
||||
260,
|
||||
20
|
||||
],
|
||||
"size": [
|
||||
180,
|
||||
60
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "calculate",
|
||||
"type": "backend",
|
||||
"label": "Measure the pilot",
|
||||
"sublabel": "Outcomes / quality",
|
||||
"pos": [
|
||||
260,
|
||||
150
|
||||
],
|
||||
"size": [
|
||||
180,
|
||||
60
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "balance",
|
||||
"type": "backend",
|
||||
"label": "Report together",
|
||||
"sublabel": "Cost / confidence / gaps",
|
||||
"pos": [
|
||||
20,
|
||||
150
|
||||
],
|
||||
"size": [
|
||||
180,
|
||||
60
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "weigh",
|
||||
"type": "backend",
|
||||
"label": "Broader adoption",
|
||||
"sublabel": "Availability + use",
|
||||
"pos": [
|
||||
20,
|
||||
280
|
||||
],
|
||||
"size": [
|
||||
180,
|
||||
60
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "decide",
|
||||
"type": "backend",
|
||||
"label": "Ongoing monitoring",
|
||||
"sublabel": "Review + maintenance",
|
||||
"pos": [
|
||||
260,
|
||||
280
|
||||
],
|
||||
"size": [
|
||||
180,
|
||||
60
|
||||
]
|
||||
}
|
||||
{"id": "workflow", "type": "backend", "label": "Workflow effectiveness", "tag": "01 / Baseline current work", "sublabel": "Accepted work, time, failures\nCost, effort + experience\nSelect relevant contracts only\nSkills need not exist yet", "pos": [40, 40], "size": [720, 310], "icon": "none"},
|
||||
{"id": "compare", "type": "backend", "label": "Compare the same outcomes", "tag": "02 / After introducing skills", "sublabel": "Same workflow + acceptance\nSame follow-up + source coverage\nKeep gaps and task mix visible\nBefore / after is not causality", "pos": [840, 40], "size": [720, 310], "icon": "none"},
|
||||
{"id": "interpret", "type": "external", "label": "Is work getting better?", "tag": "03 / Interpret workflow evidence", "sublabel": "Balance value, quality and risk\nMore adoption is not better work\nKeep live outcomes separate\nfrom skill evaluation cases", "pos": [1640, 40], "size": [720, 310], "icon": "none"},
|
||||
{"id": "skills", "type": "frontend", "label": "Skills effectiveness & health", "tag": "01 / Qualify named skill versions", "sublabel": "Quality: artifact fitness + safety\nCandidate / approved regression\nSelection precision + recall\nNo applicable skills: N/A", "pos": [40, 590], "size": [720, 310], "icon": "none"},
|
||||
{"id": "observe", "type": "frontend", "label": "Observe use + upkeep", "tag": "02 / Adoption and maintenance", "sublabel": "Supported bundle coverage\nApproved-workflow adoption\nSubstantive review evidence\nMissing observations: unknown", "pos": [840, 590], "size": [720, 310], "icon": "none"},
|
||||
{"id": "improve", "type": "external", "label": "Improve, retain or retire", "tag": "03 / Use both tracks together", "sublabel": "Owner + independent evidence\nRetain / improve / stop\nNew scope needs new comparison\nNo mandatory collection", "pos": [1640, 590], "size": [720, 310], "icon": "none"}
|
||||
],
|
||||
"connections": [
|
||||
{
|
||||
"id": "flow-0",
|
||||
"from": "collect",
|
||||
"to": "validate",
|
||||
"label": "prepare"
|
||||
},
|
||||
{
|
||||
"id": "flow-1",
|
||||
"from": "validate",
|
||||
"to": "calculate",
|
||||
"label": "collect"
|
||||
},
|
||||
{
|
||||
"id": "flow-2",
|
||||
"from": "calculate",
|
||||
"to": "balance",
|
||||
"label": "calculate"
|
||||
},
|
||||
{
|
||||
"id": "flow-3",
|
||||
"from": "balance",
|
||||
"to": "weigh",
|
||||
"label": "extend"
|
||||
},
|
||||
{
|
||||
"id": "flow-4",
|
||||
"from": "weigh",
|
||||
"to": "decide",
|
||||
"label": "repeat"
|
||||
}
|
||||
{"id": "workflow-compare", "from": "workflow", "to": "compare", "label": "", "fromSide": "right", "toSide": "left", "route": "straight", "width": 4, "variant": "default"},
|
||||
{"id": "compare-interpret", "from": "compare", "to": "interpret", "label": "", "fromSide": "right", "toSide": "left", "route": "straight", "width": 4, "variant": "default"},
|
||||
{"id": "skills-observe", "from": "skills", "to": "observe", "label": "", "fromSide": "right", "toSide": "left", "route": "straight", "width": 4, "variant": "default"},
|
||||
{"id": "observe-improve", "from": "observe", "to": "improve", "label": "", "fromSide": "right", "toSide": "left", "route": "straight", "width": 4, "variant": "default"},
|
||||
{"id": "interpret-improve", "from": "interpret", "to": "improve", "label": "", "fromSide": "bottom", "toSide": "top", "route": "straight", "width": 4, "variant": "default"}
|
||||
]
|
||||
}
|
||||
@@ -2,129 +2,261 @@
|
||||
"schema_version": 1,
|
||||
"diagram_type": "architecture",
|
||||
"meta": {
|
||||
"title": "TO-BE: Risk-tiered qualification",
|
||||
"title": "TO-BE: Quality",
|
||||
"output": "static/diagrams/strategy-quality-mobile/index.html",
|
||||
"quality_profile": "showcase",
|
||||
"legend": {
|
||||
"mode": "hidden"
|
||||
}
|
||||
},
|
||||
"viewBox": [
|
||||
880,
|
||||
2800
|
||||
]
|
||||
},
|
||||
"components": [
|
||||
{
|
||||
"id": "risk",
|
||||
"type": "security",
|
||||
"label": "Classify risk",
|
||||
"sublabel": "R1 / R2 / R3",
|
||||
"id": "selection",
|
||||
"type": "external",
|
||||
"label": "Right skill?",
|
||||
"tag": "Selection evidence",
|
||||
"sublabel": "Triggers, near misses, negatives",
|
||||
"pos": [
|
||||
20,
|
||||
20
|
||||
60,
|
||||
120
|
||||
],
|
||||
"size": [
|
||||
180,
|
||||
60
|
||||
]
|
||||
740,
|
||||
220
|
||||
],
|
||||
"icon": "none"
|
||||
},
|
||||
{
|
||||
"id": "plan",
|
||||
"type": "security",
|
||||
"label": "Agree evaluation",
|
||||
"sublabel": "Task mix + thresholds",
|
||||
"id": "safety",
|
||||
"type": "external",
|
||||
"label": "Safe execution?",
|
||||
"tag": "Safety evidence",
|
||||
"sublabel": "Permissions + adversarial trials",
|
||||
"pos": [
|
||||
20,
|
||||
140
|
||||
60,
|
||||
490
|
||||
],
|
||||
"size": [
|
||||
180,
|
||||
60
|
||||
]
|
||||
740,
|
||||
220
|
||||
],
|
||||
"icon": "none"
|
||||
},
|
||||
{
|
||||
"id": "trial",
|
||||
"type": "security",
|
||||
"label": "Repeat trials",
|
||||
"sublabel": "Candidate vs approved",
|
||||
"id": "artifact",
|
||||
"type": "external",
|
||||
"label": "Valid artifact?",
|
||||
"tag": "Independent inspection",
|
||||
"sublabel": "Tests + human assessment",
|
||||
"pos": [
|
||||
20,
|
||||
260
|
||||
60,
|
||||
860
|
||||
],
|
||||
"size": [
|
||||
180,
|
||||
60
|
||||
]
|
||||
740,
|
||||
220
|
||||
],
|
||||
"icon": "none"
|
||||
},
|
||||
{
|
||||
"id": "verify",
|
||||
"type": "security",
|
||||
"label": "Verify artifacts",
|
||||
"sublabel": "Independent checks",
|
||||
"id": "outcome",
|
||||
"type": "external",
|
||||
"label": "Useful outcome?",
|
||||
"tag": "Declared evaluation cases",
|
||||
"sublabel": "Fitness + revision regression",
|
||||
"pos": [
|
||||
20,
|
||||
380
|
||||
60,
|
||||
1230
|
||||
],
|
||||
"size": [
|
||||
180,
|
||||
60
|
||||
]
|
||||
740,
|
||||
220
|
||||
],
|
||||
"icon": "none"
|
||||
},
|
||||
{
|
||||
"id": "gate",
|
||||
"type": "security",
|
||||
"label": "All gates pass?",
|
||||
"sublabel": "Safety cannot be traded",
|
||||
"label": "Every gate must pass",
|
||||
"tag": "Risk sets evaluation depth",
|
||||
"sublabel": "No averaging away harm\nCritical effect blocks promotion\nMissing coverage = incomplete",
|
||||
"pos": [
|
||||
20,
|
||||
500
|
||||
60,
|
||||
1600
|
||||
],
|
||||
"size": [
|
||||
180,
|
||||
60
|
||||
]
|
||||
740,
|
||||
310
|
||||
],
|
||||
"icon": "none"
|
||||
},
|
||||
{
|
||||
"id": "promote",
|
||||
"type": "security",
|
||||
"label": "Promote or hold",
|
||||
"sublabel": "Owner decision",
|
||||
"id": "accept",
|
||||
"type": "backend",
|
||||
"label": "Accept evidence",
|
||||
"tag": "Quality Engineering reviewer",
|
||||
"sublabel": "Owner decides bounded pilot",
|
||||
"pos": [
|
||||
20,
|
||||
620
|
||||
60,
|
||||
2060
|
||||
],
|
||||
"size": [
|
||||
180,
|
||||
60
|
||||
]
|
||||
740,
|
||||
220
|
||||
],
|
||||
"icon": "none"
|
||||
},
|
||||
{
|
||||
"id": "rework",
|
||||
"type": "security",
|
||||
"label": "Rework / retest",
|
||||
"tag": "Any failure or missing evidence",
|
||||
"sublabel": "Keep failures in the record",
|
||||
"pos": [
|
||||
60,
|
||||
2430
|
||||
],
|
||||
"size": [
|
||||
740,
|
||||
220
|
||||
],
|
||||
"icon": "none"
|
||||
}
|
||||
],
|
||||
"connections": [
|
||||
{
|
||||
"id": "flow-0",
|
||||
"from": "risk",
|
||||
"to": "plan",
|
||||
"label": "Scope"
|
||||
},
|
||||
{
|
||||
"id": "flow-1",
|
||||
"from": "plan",
|
||||
"to": "trial",
|
||||
"label": "freeze plan"
|
||||
},
|
||||
{
|
||||
"id": "flow-2",
|
||||
"from": "trial",
|
||||
"to": "verify",
|
||||
"label": "Assess"
|
||||
},
|
||||
{
|
||||
"id": "flow-3",
|
||||
"from": "verify",
|
||||
"id": "selection-gate",
|
||||
"from": "selection",
|
||||
"to": "gate",
|
||||
"label": "review evidence"
|
||||
"label": "",
|
||||
"fromSide": "right",
|
||||
"toSide": "right",
|
||||
"route": "straight",
|
||||
"width": 4,
|
||||
"variant": "default",
|
||||
"via": [
|
||||
[
|
||||
850,
|
||||
230.0
|
||||
],
|
||||
[
|
||||
850,
|
||||
1755.0
|
||||
]
|
||||
],
|
||||
"labelAt": [
|
||||
620,
|
||||
1560
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "flow-4",
|
||||
"id": "safety-gate",
|
||||
"from": "safety",
|
||||
"to": "gate",
|
||||
"label": "",
|
||||
"fromSide": "right",
|
||||
"toSide": "right",
|
||||
"route": "straight",
|
||||
"width": 4,
|
||||
"variant": "default",
|
||||
"via": [
|
||||
[
|
||||
850,
|
||||
600.0
|
||||
],
|
||||
[
|
||||
850,
|
||||
1755.0
|
||||
]
|
||||
],
|
||||
"labelAt": [
|
||||
620,
|
||||
1560
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "artifact-gate",
|
||||
"from": "artifact",
|
||||
"to": "gate",
|
||||
"label": "",
|
||||
"fromSide": "right",
|
||||
"toSide": "right",
|
||||
"route": "straight",
|
||||
"width": 4,
|
||||
"variant": "default",
|
||||
"via": [
|
||||
[
|
||||
850,
|
||||
970.0
|
||||
],
|
||||
[
|
||||
850,
|
||||
1755.0
|
||||
]
|
||||
],
|
||||
"labelAt": [
|
||||
620,
|
||||
1560
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "outcome-gate",
|
||||
"from": "outcome",
|
||||
"to": "gate",
|
||||
"label": "",
|
||||
"fromSide": "bottom",
|
||||
"toSide": "top",
|
||||
"route": "straight",
|
||||
"width": 4,
|
||||
"variant": "default",
|
||||
"labelAt": [
|
||||
610,
|
||||
1505
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "gate-accept",
|
||||
"from": "gate",
|
||||
"to": "promote",
|
||||
"label": "decide"
|
||||
"to": "accept",
|
||||
"label": "Pass",
|
||||
"fromSide": "bottom",
|
||||
"toSide": "top",
|
||||
"route": "straight",
|
||||
"width": 4,
|
||||
"variant": "default",
|
||||
"labelAt": [
|
||||
610,
|
||||
1965
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "gate-rework",
|
||||
"from": "gate",
|
||||
"to": "rework",
|
||||
"label": "Fail",
|
||||
"fromSide": "right",
|
||||
"toSide": "right",
|
||||
"route": "straight",
|
||||
"width": 4,
|
||||
"variant": "security",
|
||||
"via": [
|
||||
[
|
||||
824,
|
||||
1755.0
|
||||
],
|
||||
[
|
||||
824,
|
||||
2540.0
|
||||
]
|
||||
],
|
||||
"labelAt": [
|
||||
620,
|
||||
2390
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -2,129 +2,265 @@
|
||||
"schema_version": 1,
|
||||
"diagram_type": "architecture",
|
||||
"meta": {
|
||||
"title": "TO-BE: Risk-tiered qualification",
|
||||
"title": "TO-BE: Quality",
|
||||
"output": "static/diagrams/strategy-quality/index.html",
|
||||
"quality_profile": "showcase",
|
||||
"legend": {
|
||||
"mode": "hidden"
|
||||
}
|
||||
},
|
||||
"viewBox": [
|
||||
2000,
|
||||
1050
|
||||
]
|
||||
},
|
||||
"components": [
|
||||
{
|
||||
"id": "risk",
|
||||
"type": "security",
|
||||
"label": "Classify risk",
|
||||
"sublabel": "R1 / R2 / R3",
|
||||
"id": "selection",
|
||||
"type": "external",
|
||||
"label": "Right skill?",
|
||||
"tag": "Selection evidence",
|
||||
"sublabel": "Triggers, near misses, negatives",
|
||||
"pos": [
|
||||
20,
|
||||
20
|
||||
60,
|
||||
70
|
||||
],
|
||||
"size": [
|
||||
180,
|
||||
60
|
||||
]
|
||||
510,
|
||||
170
|
||||
],
|
||||
"icon": "none"
|
||||
},
|
||||
{
|
||||
"id": "plan",
|
||||
"type": "security",
|
||||
"label": "Agree evaluation",
|
||||
"sublabel": "Task mix + thresholds",
|
||||
"id": "safety",
|
||||
"type": "external",
|
||||
"label": "Safe execution?",
|
||||
"tag": "Safety evidence",
|
||||
"sublabel": "Permissions + adversarial trials",
|
||||
"pos": [
|
||||
260,
|
||||
20
|
||||
60,
|
||||
310
|
||||
],
|
||||
"size": [
|
||||
180,
|
||||
60
|
||||
]
|
||||
510,
|
||||
170
|
||||
],
|
||||
"icon": "none"
|
||||
},
|
||||
{
|
||||
"id": "trial",
|
||||
"type": "security",
|
||||
"label": "Repeat trials",
|
||||
"sublabel": "Candidate vs approved",
|
||||
"id": "artifact",
|
||||
"type": "external",
|
||||
"label": "Valid artifact?",
|
||||
"tag": "Independent inspection",
|
||||
"sublabel": "Tests + human assessment",
|
||||
"pos": [
|
||||
260,
|
||||
150
|
||||
60,
|
||||
550
|
||||
],
|
||||
"size": [
|
||||
180,
|
||||
60
|
||||
]
|
||||
510,
|
||||
170
|
||||
],
|
||||
"icon": "none"
|
||||
},
|
||||
{
|
||||
"id": "verify",
|
||||
"type": "security",
|
||||
"label": "Verify artifacts",
|
||||
"sublabel": "Independent checks",
|
||||
"id": "outcome",
|
||||
"type": "external",
|
||||
"label": "Useful outcome?",
|
||||
"tag": "Declared evaluation cases",
|
||||
"sublabel": "Fitness + revision regression",
|
||||
"pos": [
|
||||
20,
|
||||
150
|
||||
60,
|
||||
790
|
||||
],
|
||||
"size": [
|
||||
180,
|
||||
60
|
||||
]
|
||||
510,
|
||||
170
|
||||
],
|
||||
"icon": "none"
|
||||
},
|
||||
{
|
||||
"id": "gate",
|
||||
"type": "security",
|
||||
"label": "All gates pass?",
|
||||
"sublabel": "Safety cannot be traded",
|
||||
"label": "Every gate must pass",
|
||||
"tag": "Risk sets evaluation depth",
|
||||
"sublabel": "No averaging away harm\nCritical effect blocks promotion\nMissing coverage = incomplete",
|
||||
"pos": [
|
||||
20,
|
||||
280
|
||||
740,
|
||||
350
|
||||
],
|
||||
"size": [
|
||||
180,
|
||||
60
|
||||
]
|
||||
520,
|
||||
310
|
||||
],
|
||||
"icon": "none"
|
||||
},
|
||||
{
|
||||
"id": "promote",
|
||||
"type": "security",
|
||||
"label": "Promote or hold",
|
||||
"sublabel": "Owner decision",
|
||||
"id": "accept",
|
||||
"type": "backend",
|
||||
"label": "Accept evidence",
|
||||
"tag": "Quality Engineering reviewer",
|
||||
"sublabel": "Owner decides bounded pilot",
|
||||
"pos": [
|
||||
260,
|
||||
280
|
||||
1430,
|
||||
160
|
||||
],
|
||||
"size": [
|
||||
180,
|
||||
60
|
||||
]
|
||||
510,
|
||||
190
|
||||
],
|
||||
"icon": "none"
|
||||
},
|
||||
{
|
||||
"id": "rework",
|
||||
"type": "security",
|
||||
"label": "Rework / retest",
|
||||
"tag": "Any failure or missing evidence",
|
||||
"sublabel": "Keep failures in the record",
|
||||
"pos": [
|
||||
1430,
|
||||
760
|
||||
],
|
||||
"size": [
|
||||
510,
|
||||
190
|
||||
],
|
||||
"icon": "none"
|
||||
}
|
||||
],
|
||||
"connections": [
|
||||
{
|
||||
"id": "flow-0",
|
||||
"from": "risk",
|
||||
"to": "plan",
|
||||
"label": "Scope"
|
||||
},
|
||||
{
|
||||
"id": "flow-1",
|
||||
"from": "plan",
|
||||
"to": "trial",
|
||||
"label": "freeze plan"
|
||||
},
|
||||
{
|
||||
"id": "flow-2",
|
||||
"from": "trial",
|
||||
"to": "verify",
|
||||
"label": "Assess"
|
||||
},
|
||||
{
|
||||
"id": "flow-3",
|
||||
"from": "verify",
|
||||
"id": "selection-gate",
|
||||
"from": "selection",
|
||||
"to": "gate",
|
||||
"label": "review evidence"
|
||||
"label": "",
|
||||
"fromSide": "right",
|
||||
"toSide": "left",
|
||||
"route": "straight",
|
||||
"width": 4,
|
||||
"variant": "default",
|
||||
"via": [
|
||||
[
|
||||
650,
|
||||
155
|
||||
],
|
||||
[
|
||||
650,
|
||||
505
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "flow-4",
|
||||
"id": "safety-gate",
|
||||
"from": "safety",
|
||||
"to": "gate",
|
||||
"label": "",
|
||||
"fromSide": "right",
|
||||
"toSide": "left",
|
||||
"route": "straight",
|
||||
"width": 4,
|
||||
"variant": "default",
|
||||
"via": [
|
||||
[
|
||||
650,
|
||||
395
|
||||
],
|
||||
[
|
||||
650,
|
||||
505
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "artifact-gate",
|
||||
"from": "artifact",
|
||||
"to": "gate",
|
||||
"label": "",
|
||||
"fromSide": "right",
|
||||
"toSide": "left",
|
||||
"route": "straight",
|
||||
"width": 4,
|
||||
"variant": "default",
|
||||
"via": [
|
||||
[
|
||||
650,
|
||||
635
|
||||
],
|
||||
[
|
||||
650,
|
||||
505
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "outcome-gate",
|
||||
"from": "outcome",
|
||||
"to": "gate",
|
||||
"label": "",
|
||||
"fromSide": "right",
|
||||
"toSide": "left",
|
||||
"route": "straight",
|
||||
"width": 4,
|
||||
"variant": "default",
|
||||
"via": [
|
||||
[
|
||||
650,
|
||||
875
|
||||
],
|
||||
[
|
||||
650,
|
||||
505
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "gate-accept",
|
||||
"from": "gate",
|
||||
"to": "promote",
|
||||
"label": "decide"
|
||||
"to": "accept",
|
||||
"label": "Pass",
|
||||
"fromSide": "right",
|
||||
"toSide": "left",
|
||||
"route": "straight",
|
||||
"width": 4,
|
||||
"variant": "default",
|
||||
"via": [
|
||||
[
|
||||
1340,
|
||||
505
|
||||
],
|
||||
[
|
||||
1340,
|
||||
255
|
||||
]
|
||||
],
|
||||
"labelAt": [
|
||||
1330,
|
||||
210
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "gate-rework",
|
||||
"from": "gate",
|
||||
"to": "rework",
|
||||
"label": "Fail",
|
||||
"fromSide": "right",
|
||||
"toSide": "left",
|
||||
"route": "straight",
|
||||
"width": 4,
|
||||
"variant": "security",
|
||||
"via": [
|
||||
[
|
||||
1340,
|
||||
505
|
||||
],
|
||||
[
|
||||
1340,
|
||||
855
|
||||
]
|
||||
],
|
||||
"labelAt": [
|
||||
1325,
|
||||
900
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
{
|
||||
"schema_version": 2,
|
||||
"diagram_type": "workflow",
|
||||
"meta": {
|
||||
"title": "Stage 1: Delivery first",
|
||||
"output": "static/diagrams/strategy-roadmap-adoption-mobile/index.html",
|
||||
"quality_profile": "showcase",
|
||||
"animation": "none",
|
||||
"legend": {
|
||||
"mode": "hidden"
|
||||
}
|
||||
},
|
||||
"lanes": [
|
||||
{
|
||||
"id": "adoption",
|
||||
"label": "Stage 1: Delivery first"
|
||||
}
|
||||
],
|
||||
"mainPath": [
|
||||
"delivery",
|
||||
"remaining"
|
||||
],
|
||||
"nodes": [
|
||||
{
|
||||
"id": "delivery",
|
||||
"lane": "adoption",
|
||||
"col": 0,
|
||||
"yOffset": -140.0,
|
||||
"type": "backend",
|
||||
"label": "Delivery first",
|
||||
"sublabel": "Human + AI Agent; keep improving.",
|
||||
"width": 340,
|
||||
"height": 240
|
||||
},
|
||||
{
|
||||
"id": "remaining",
|
||||
"lane": "adoption",
|
||||
"col": 0,
|
||||
"yOffset": 140.0,
|
||||
"type": "backend",
|
||||
"label": "Other SDLC phases",
|
||||
"sublabel": "Expand adoption; order not yet decided.",
|
||||
"width": 340,
|
||||
"height": 240
|
||||
}
|
||||
],
|
||||
"edges": [
|
||||
{
|
||||
"id": "flow-0",
|
||||
"from": "delivery",
|
||||
"to": "remaining",
|
||||
"role": "main",
|
||||
"fromSide": "bottom",
|
||||
"toSide": "top"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
{
|
||||
"schema_version": 2,
|
||||
"diagram_type": "workflow",
|
||||
"meta": {
|
||||
"title": "Stage 1: Delivery first",
|
||||
"output": "static/diagrams/strategy-roadmap-adoption/index.html",
|
||||
"quality_profile": "showcase",
|
||||
"animation": "none",
|
||||
"legend": {
|
||||
"mode": "hidden"
|
||||
}
|
||||
},
|
||||
"lanes": [
|
||||
{
|
||||
"id": "adoption",
|
||||
"label": "Stage 1: Delivery first"
|
||||
}
|
||||
],
|
||||
"mainPath": [
|
||||
"delivery",
|
||||
"remaining"
|
||||
],
|
||||
"nodes": [
|
||||
{
|
||||
"id": "delivery",
|
||||
"lane": "adoption",
|
||||
"col": 0,
|
||||
"yOffset": 0,
|
||||
"type": "backend",
|
||||
"label": "Delivery first",
|
||||
"sublabel": "Human + AI Agent; keep improving.",
|
||||
"width": 340,
|
||||
"height": 240
|
||||
},
|
||||
{
|
||||
"id": "remaining",
|
||||
"lane": "adoption",
|
||||
"col": 1,
|
||||
"yOffset": 0,
|
||||
"type": "backend",
|
||||
"label": "Other SDLC phases",
|
||||
"sublabel": "Expand adoption; order not yet decided.",
|
||||
"width": 340,
|
||||
"height": 240
|
||||
}
|
||||
],
|
||||
"edges": [
|
||||
{
|
||||
"id": "flow-0",
|
||||
"from": "delivery",
|
||||
"to": "remaining",
|
||||
"role": "main",
|
||||
"fromSide": "right",
|
||||
"toSide": "left"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,143 @@
|
||||
{
|
||||
"schema_version": 2,
|
||||
"diagram_type": "workflow",
|
||||
"meta": {
|
||||
"title": "Improve within each phase",
|
||||
"output": "static/diagrams/strategy-roadmap-loop-mobile/index.html",
|
||||
"quality_profile": "showcase",
|
||||
"animation": "none",
|
||||
"legend": {
|
||||
"mode": "hidden"
|
||||
}
|
||||
},
|
||||
"lanes": [
|
||||
{
|
||||
"id": "adoption",
|
||||
"label": "Improve within each phase"
|
||||
}
|
||||
],
|
||||
"mainPath": [
|
||||
"understand",
|
||||
"baseline",
|
||||
"topology"
|
||||
],
|
||||
"nodes": [
|
||||
{
|
||||
"id": "understand",
|
||||
"lane": "adoption",
|
||||
"col": 0,
|
||||
"yOffset": -700.0,
|
||||
"type": "backend",
|
||||
"label": "Understand today",
|
||||
"sublabel": "Actual practices, tools and problems.",
|
||||
"width": 340,
|
||||
"height": 240
|
||||
},
|
||||
{
|
||||
"id": "baseline",
|
||||
"lane": "adoption",
|
||||
"col": 0,
|
||||
"yOffset": -420.0,
|
||||
"type": "backend",
|
||||
"label": "Set metrics / KPIs",
|
||||
"sublabel": "Establish a baseline before changes.",
|
||||
"width": 340,
|
||||
"height": 240
|
||||
},
|
||||
{
|
||||
"id": "topology",
|
||||
"lane": "adoption",
|
||||
"col": 0,
|
||||
"yOffset": -140.0,
|
||||
"type": "backend",
|
||||
"label": "Engineer topology",
|
||||
"sublabel": "Connect skills, triggers and handoffs.",
|
||||
"width": 340,
|
||||
"height": 240
|
||||
},
|
||||
{
|
||||
"id": "use",
|
||||
"lane": "adoption",
|
||||
"col": 0,
|
||||
"yOffset": 140.0,
|
||||
"type": "backend",
|
||||
"label": "Qualify, then pilot",
|
||||
"sublabel": "Authorize bounded human + AI work.",
|
||||
"width": 340,
|
||||
"height": 240
|
||||
},
|
||||
{
|
||||
"id": "collect",
|
||||
"lane": "adoption",
|
||||
"col": 0,
|
||||
"yOffset": 420.0,
|
||||
"type": "backend",
|
||||
"label": "Collect results",
|
||||
"sublabel": "Metrics, friction and human feedback.",
|
||||
"width": 340,
|
||||
"height": 240
|
||||
},
|
||||
{
|
||||
"id": "reassess",
|
||||
"lane": "adoption",
|
||||
"col": 0,
|
||||
"yOffset": 700.0,
|
||||
"type": "backend",
|
||||
"label": "Understand anew",
|
||||
"sublabel": "Compare with baseline; repeat the loop.",
|
||||
"width": 340,
|
||||
"height": 240
|
||||
}
|
||||
],
|
||||
"edges": [
|
||||
{
|
||||
"id": "flow-0",
|
||||
"from": "understand",
|
||||
"to": "baseline",
|
||||
"role": "main",
|
||||
"fromSide": "bottom",
|
||||
"toSide": "top"
|
||||
},
|
||||
{
|
||||
"id": "flow-1",
|
||||
"from": "baseline",
|
||||
"to": "topology",
|
||||
"role": "main",
|
||||
"fromSide": "bottom",
|
||||
"toSide": "top"
|
||||
},
|
||||
{
|
||||
"id": "flow-2",
|
||||
"from": "topology",
|
||||
"to": "use",
|
||||
"role": "main",
|
||||
"fromSide": "bottom",
|
||||
"toSide": "top"
|
||||
},
|
||||
{
|
||||
"id": "flow-3",
|
||||
"from": "use",
|
||||
"to": "collect",
|
||||
"role": "main",
|
||||
"fromSide": "bottom",
|
||||
"toSide": "top"
|
||||
},
|
||||
{
|
||||
"id": "flow-4",
|
||||
"from": "collect",
|
||||
"to": "reassess",
|
||||
"role": "main",
|
||||
"fromSide": "bottom",
|
||||
"toSide": "top"
|
||||
},
|
||||
{
|
||||
"id": "repeat",
|
||||
"from": "reassess",
|
||||
"to": "understand",
|
||||
"role": "return",
|
||||
"fromSide": "left",
|
||||
"toSide": "left",
|
||||
"route": "return-left"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,143 @@
|
||||
{
|
||||
"schema_version": 2,
|
||||
"diagram_type": "workflow",
|
||||
"meta": {
|
||||
"title": "Improve within each phase",
|
||||
"output": "static/diagrams/strategy-roadmap-loop/index.html",
|
||||
"quality_profile": "showcase",
|
||||
"animation": "none",
|
||||
"legend": {
|
||||
"mode": "hidden"
|
||||
}
|
||||
},
|
||||
"lanes": [
|
||||
{
|
||||
"id": "adoption",
|
||||
"label": "Improve within each phase"
|
||||
}
|
||||
],
|
||||
"mainPath": [
|
||||
"understand",
|
||||
"baseline",
|
||||
"topology"
|
||||
],
|
||||
"nodes": [
|
||||
{
|
||||
"id": "understand",
|
||||
"lane": "adoption",
|
||||
"col": 0,
|
||||
"yOffset": -160,
|
||||
"type": "backend",
|
||||
"label": "Understand today",
|
||||
"sublabel": "Actual practices, tools and problems.",
|
||||
"width": 340,
|
||||
"height": 240
|
||||
},
|
||||
{
|
||||
"id": "baseline",
|
||||
"lane": "adoption",
|
||||
"col": 1,
|
||||
"yOffset": -160,
|
||||
"type": "backend",
|
||||
"label": "Set metrics / KPIs",
|
||||
"sublabel": "Establish a baseline before changes.",
|
||||
"width": 340,
|
||||
"height": 240
|
||||
},
|
||||
{
|
||||
"id": "topology",
|
||||
"lane": "adoption",
|
||||
"col": 2,
|
||||
"yOffset": -160,
|
||||
"type": "backend",
|
||||
"label": "Engineer topology",
|
||||
"sublabel": "Connect skills, triggers and handoffs.",
|
||||
"width": 340,
|
||||
"height": 240
|
||||
},
|
||||
{
|
||||
"id": "use",
|
||||
"lane": "adoption",
|
||||
"col": 2,
|
||||
"yOffset": 160,
|
||||
"type": "backend",
|
||||
"label": "Qualify, then pilot",
|
||||
"sublabel": "Authorize bounded human + AI work.",
|
||||
"width": 340,
|
||||
"height": 240
|
||||
},
|
||||
{
|
||||
"id": "collect",
|
||||
"lane": "adoption",
|
||||
"col": 1,
|
||||
"yOffset": 160,
|
||||
"type": "backend",
|
||||
"label": "Collect results",
|
||||
"sublabel": "Metrics, friction and human feedback.",
|
||||
"width": 340,
|
||||
"height": 240
|
||||
},
|
||||
{
|
||||
"id": "reassess",
|
||||
"lane": "adoption",
|
||||
"col": 0,
|
||||
"yOffset": 160,
|
||||
"type": "backend",
|
||||
"label": "Understand anew",
|
||||
"sublabel": "Compare with baseline; repeat the loop.",
|
||||
"width": 340,
|
||||
"height": 240
|
||||
}
|
||||
],
|
||||
"edges": [
|
||||
{
|
||||
"id": "flow-0",
|
||||
"from": "understand",
|
||||
"to": "baseline",
|
||||
"role": "main",
|
||||
"fromSide": "right",
|
||||
"toSide": "left"
|
||||
},
|
||||
{
|
||||
"id": "flow-1",
|
||||
"from": "baseline",
|
||||
"to": "topology",
|
||||
"role": "main",
|
||||
"fromSide": "right",
|
||||
"toSide": "left"
|
||||
},
|
||||
{
|
||||
"id": "flow-2",
|
||||
"from": "topology",
|
||||
"to": "use",
|
||||
"role": "main",
|
||||
"fromSide": "bottom",
|
||||
"toSide": "top"
|
||||
},
|
||||
{
|
||||
"id": "flow-3",
|
||||
"from": "use",
|
||||
"to": "collect",
|
||||
"role": "main",
|
||||
"fromSide": "left",
|
||||
"toSide": "right"
|
||||
},
|
||||
{
|
||||
"id": "flow-4",
|
||||
"from": "collect",
|
||||
"to": "reassess",
|
||||
"role": "main",
|
||||
"fromSide": "left",
|
||||
"toSide": "right"
|
||||
},
|
||||
{
|
||||
"id": "repeat",
|
||||
"from": "reassess",
|
||||
"to": "understand",
|
||||
"role": "return",
|
||||
"fromSide": "top",
|
||||
"toSide": "bottom",
|
||||
"route": "straight"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,110 +0,0 @@
|
||||
{
|
||||
"schema_version": 1,
|
||||
"diagram_type": "architecture",
|
||||
"meta": {
|
||||
"title": "Recommended roadmap: assess before adoption",
|
||||
"output": "static/diagrams/strategy-roadmap-mobile/index.html",
|
||||
"quality_profile": "showcase",
|
||||
"legend": {
|
||||
"mode": "hidden"
|
||||
}
|
||||
},
|
||||
"components": [
|
||||
{
|
||||
"id": "assessment",
|
||||
"type": "backend",
|
||||
"label": "1 · Assess current state",
|
||||
"sublabel": "Code quality + delivery flow",
|
||||
"pos": [
|
||||
20,
|
||||
20
|
||||
],
|
||||
"size": [
|
||||
180,
|
||||
60
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "readiness",
|
||||
"type": "backend",
|
||||
"label": "2 · Improve readiness",
|
||||
"sublabel": "Critical gaps + safe scope",
|
||||
"pos": [
|
||||
20,
|
||||
140
|
||||
],
|
||||
"size": [
|
||||
180,
|
||||
60
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "pilot",
|
||||
"type": "backend",
|
||||
"label": "3 · Bounded pilot",
|
||||
"sublabel": "Compare accepted outcomes",
|
||||
"pos": [
|
||||
20,
|
||||
260
|
||||
],
|
||||
"size": [
|
||||
180,
|
||||
60
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "expansion",
|
||||
"type": "backend",
|
||||
"label": "4 · Expand on evidence",
|
||||
"sublabel": "Controls + support proven",
|
||||
"pos": [
|
||||
20,
|
||||
380
|
||||
],
|
||||
"size": [
|
||||
180,
|
||||
60
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "sustain",
|
||||
"type": "backend",
|
||||
"label": "5 · Sustain & improve",
|
||||
"sublabel": "Monitor + reassess",
|
||||
"pos": [
|
||||
20,
|
||||
500
|
||||
],
|
||||
"size": [
|
||||
180,
|
||||
60
|
||||
]
|
||||
}
|
||||
],
|
||||
"connections": [
|
||||
{
|
||||
"id": "flow-0",
|
||||
"from": "assessment",
|
||||
"to": "readiness",
|
||||
"label": "Gaps"
|
||||
},
|
||||
{
|
||||
"id": "flow-1",
|
||||
"from": "readiness",
|
||||
"to": "pilot",
|
||||
"label": "Ready"
|
||||
},
|
||||
{
|
||||
"id": "flow-2",
|
||||
"from": "pilot",
|
||||
"to": "expansion",
|
||||
"label": "Evidence"
|
||||
},
|
||||
{
|
||||
"id": "flow-3",
|
||||
"from": "expansion",
|
||||
"to": "sustain",
|
||||
"label": "Review"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
{
|
||||
"schema_version": 2,
|
||||
"diagram_type": "workflow",
|
||||
"meta": {
|
||||
"title": "Two stages toward Target",
|
||||
"output": "static/diagrams/strategy-roadmap-mobile/index.html",
|
||||
"quality_profile": "showcase",
|
||||
"animation": "none",
|
||||
"legend": {
|
||||
"mode": "hidden"
|
||||
}
|
||||
},
|
||||
"lanes": [
|
||||
{
|
||||
"id": "adoption",
|
||||
"label": "Two stages toward Target"
|
||||
}
|
||||
],
|
||||
"mainPath": [
|
||||
"skills",
|
||||
"autonomy"
|
||||
],
|
||||
"nodes": [
|
||||
{
|
||||
"id": "skills",
|
||||
"lane": "adoption",
|
||||
"col": 0,
|
||||
"yOffset": -140.0,
|
||||
"type": "backend",
|
||||
"label": "Adopt skills",
|
||||
"sublabel": "Human + AI Agent in each SDLC phase.",
|
||||
"width": 340,
|
||||
"height": 240
|
||||
},
|
||||
{
|
||||
"id": "autonomy",
|
||||
"lane": "adoption",
|
||||
"col": 0,
|
||||
"yOffset": 140.0,
|
||||
"type": "backend",
|
||||
"label": "Autonomous Agent",
|
||||
"sublabel": "Future: separately justified authority.",
|
||||
"width": 340,
|
||||
"height": 240
|
||||
}
|
||||
],
|
||||
"edges": [
|
||||
{
|
||||
"id": "flow-0",
|
||||
"from": "skills",
|
||||
"to": "autonomy",
|
||||
"role": "main",
|
||||
"fromSide": "bottom",
|
||||
"toSide": "top"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,110 +0,0 @@
|
||||
{
|
||||
"schema_version": 1,
|
||||
"diagram_type": "architecture",
|
||||
"meta": {
|
||||
"title": "Recommended roadmap: assess before adoption",
|
||||
"output": "static/diagrams/strategy-roadmap/index.html",
|
||||
"quality_profile": "showcase",
|
||||
"legend": {
|
||||
"mode": "hidden"
|
||||
}
|
||||
},
|
||||
"components": [
|
||||
{
|
||||
"id": "assessment",
|
||||
"type": "backend",
|
||||
"label": "1 · Assess current state",
|
||||
"sublabel": "Code quality + delivery flow",
|
||||
"pos": [
|
||||
20,
|
||||
20
|
||||
],
|
||||
"size": [
|
||||
180,
|
||||
60
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "readiness",
|
||||
"type": "backend",
|
||||
"label": "2 · Improve readiness",
|
||||
"sublabel": "Critical gaps + safe scope",
|
||||
"pos": [
|
||||
260,
|
||||
20
|
||||
],
|
||||
"size": [
|
||||
180,
|
||||
60
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "pilot",
|
||||
"type": "backend",
|
||||
"label": "3 · Bounded pilot",
|
||||
"sublabel": "Compare accepted outcomes",
|
||||
"pos": [
|
||||
260,
|
||||
150
|
||||
],
|
||||
"size": [
|
||||
180,
|
||||
60
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "expansion",
|
||||
"type": "backend",
|
||||
"label": "4 · Expand on evidence",
|
||||
"sublabel": "Controls + support proven",
|
||||
"pos": [
|
||||
20,
|
||||
150
|
||||
],
|
||||
"size": [
|
||||
180,
|
||||
60
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "sustain",
|
||||
"type": "backend",
|
||||
"label": "5 · Sustain & improve",
|
||||
"sublabel": "Monitor + reassess",
|
||||
"pos": [
|
||||
20,
|
||||
280
|
||||
],
|
||||
"size": [
|
||||
180,
|
||||
60
|
||||
]
|
||||
}
|
||||
],
|
||||
"connections": [
|
||||
{
|
||||
"id": "flow-0",
|
||||
"from": "assessment",
|
||||
"to": "readiness",
|
||||
"label": "Gaps"
|
||||
},
|
||||
{
|
||||
"id": "flow-1",
|
||||
"from": "readiness",
|
||||
"to": "pilot",
|
||||
"label": "Ready"
|
||||
},
|
||||
{
|
||||
"id": "flow-2",
|
||||
"from": "pilot",
|
||||
"to": "expansion",
|
||||
"label": "Evidence"
|
||||
},
|
||||
{
|
||||
"id": "flow-3",
|
||||
"from": "expansion",
|
||||
"to": "sustain",
|
||||
"label": "Review"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
{
|
||||
"schema_version": 2,
|
||||
"diagram_type": "workflow",
|
||||
"meta": {
|
||||
"title": "Two stages toward Target",
|
||||
"output": "static/diagrams/strategy-roadmap/index.html",
|
||||
"quality_profile": "showcase",
|
||||
"animation": "none",
|
||||
"legend": {
|
||||
"mode": "hidden"
|
||||
}
|
||||
},
|
||||
"lanes": [
|
||||
{
|
||||
"id": "adoption",
|
||||
"label": "Two stages toward Target"
|
||||
}
|
||||
],
|
||||
"mainPath": [
|
||||
"skills",
|
||||
"autonomy"
|
||||
],
|
||||
"nodes": [
|
||||
{
|
||||
"id": "skills",
|
||||
"lane": "adoption",
|
||||
"col": 0,
|
||||
"yOffset": 0,
|
||||
"type": "backend",
|
||||
"label": "Adopt skills",
|
||||
"sublabel": "Human + AI Agent in each SDLC phase.",
|
||||
"width": 340,
|
||||
"height": 240
|
||||
},
|
||||
{
|
||||
"id": "autonomy",
|
||||
"lane": "adoption",
|
||||
"col": 1,
|
||||
"yOffset": 0,
|
||||
"type": "backend",
|
||||
"label": "Autonomous Agent",
|
||||
"sublabel": "Future: separately justified authority.",
|
||||
"width": 340,
|
||||
"height": 240
|
||||
}
|
||||
],
|
||||
"edges": [
|
||||
{
|
||||
"id": "flow-0",
|
||||
"from": "skills",
|
||||
"to": "autonomy",
|
||||
"role": "main",
|
||||
"fromSide": "right",
|
||||
"toSide": "left"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,249 @@
|
||||
{
|
||||
"schema_version": 1,
|
||||
"diagram_type": "architecture",
|
||||
"meta": {
|
||||
"title": "TO-BE: stage01",
|
||||
"output": "static/diagrams/strategy-stage01-mobile/index.html",
|
||||
"quality_profile": "showcase",
|
||||
"legend": {
|
||||
"mode": "hidden"
|
||||
},
|
||||
"viewBox": [
|
||||
1000,
|
||||
2950
|
||||
]
|
||||
},
|
||||
"components": [
|
||||
{
|
||||
"id": "baseline",
|
||||
"type": "external",
|
||||
"label": "Understand + baseline",
|
||||
"tag": "Product Engineering workflow owner",
|
||||
"sublabel": "Workflow map + desired improvement\nSelected measures + starting evidence\nGovernance: people, scope, authority",
|
||||
"pos": [
|
||||
200,
|
||||
40
|
||||
],
|
||||
"size": [
|
||||
740,
|
||||
300
|
||||
],
|
||||
"icon": "none"
|
||||
},
|
||||
{
|
||||
"id": "engineer",
|
||||
"type": "external",
|
||||
"label": "Engineer connected skills",
|
||||
"tag": "Owning team + independent reviewer",
|
||||
"sublabel": "Triggers, inputs and output handoffs\nPinned candidate + client + limits\nDeliver: patch and regression tests",
|
||||
"pos": [
|
||||
200,
|
||||
450
|
||||
],
|
||||
"size": [
|
||||
740,
|
||||
300
|
||||
],
|
||||
"icon": "none"
|
||||
},
|
||||
{
|
||||
"id": "qualify",
|
||||
"type": "security",
|
||||
"label": "Fit for a bounded pilot?",
|
||||
"tag": "Quality evidence \u2192 owning approver",
|
||||
"sublabel": "Artifact + safety + regression report\nPass: authorize exact pilot scope\nFail / incomplete: hold or rework",
|
||||
"pos": [
|
||||
200,
|
||||
860
|
||||
],
|
||||
"size": [
|
||||
740,
|
||||
300
|
||||
],
|
||||
"icon": "none"
|
||||
},
|
||||
{
|
||||
"id": "pilot",
|
||||
"type": "external",
|
||||
"label": "Pilot real work",
|
||||
"tag": "Human + AI Agent; independent review",
|
||||
"sublabel": "Use qualified revision within scope\nAccepted / failed work + feedback\nManual path; no new release power",
|
||||
"pos": [
|
||||
200,
|
||||
1270
|
||||
],
|
||||
"size": [
|
||||
740,
|
||||
300
|
||||
],
|
||||
"icon": "none"
|
||||
},
|
||||
{
|
||||
"id": "decide",
|
||||
"type": "security",
|
||||
"label": "Retain, improve or stop?",
|
||||
"tag": "Workflow owner + reviewed evidence",
|
||||
"sublabel": "Compare with baseline, not trials\nNo justified benefit: hold / stop\nNew scope: baseline + new approval",
|
||||
"pos": [
|
||||
200,
|
||||
1680
|
||||
],
|
||||
"size": [
|
||||
740,
|
||||
300
|
||||
],
|
||||
"icon": "none"
|
||||
},
|
||||
{
|
||||
"id": "maintain",
|
||||
"type": "external",
|
||||
"label": "Maintain + requalify",
|
||||
"tag": "Owner, Quality, Platform & Security",
|
||||
"sublabel": "Retain: support approved revision\nDrift / defects: revise and retest\nHarm: contain; never auto-restore",
|
||||
"pos": [
|
||||
200,
|
||||
2090
|
||||
],
|
||||
"size": [
|
||||
740,
|
||||
300
|
||||
],
|
||||
"icon": "none"
|
||||
},
|
||||
{
|
||||
"id": "reference",
|
||||
"type": "backend",
|
||||
"label": "Governance + Measurement",
|
||||
"tag": "Throughout, not one-time gates",
|
||||
"sublabel": "Named people + controlled authority\nSelected workflow + skill evidence\nKeep populations and gaps explicit",
|
||||
"pos": [
|
||||
200,
|
||||
2500
|
||||
],
|
||||
"size": [
|
||||
740,
|
||||
300
|
||||
],
|
||||
"icon": "none"
|
||||
}
|
||||
],
|
||||
"connections": [
|
||||
{
|
||||
"id": "baseline-engineer",
|
||||
"from": "baseline",
|
||||
"to": "engineer",
|
||||
"label": "Map",
|
||||
"fromSide": "bottom",
|
||||
"toSide": "top",
|
||||
"route": "straight",
|
||||
"width": 4,
|
||||
"variant": "default",
|
||||
"labelAt": [
|
||||
570,
|
||||
405
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "engineer-qualify",
|
||||
"from": "engineer",
|
||||
"to": "qualify",
|
||||
"label": "Candidate",
|
||||
"fromSide": "bottom",
|
||||
"toSide": "top",
|
||||
"route": "straight",
|
||||
"width": 4,
|
||||
"variant": "default",
|
||||
"labelAt": [
|
||||
570,
|
||||
815
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "qualify-pilot",
|
||||
"from": "qualify",
|
||||
"to": "pilot",
|
||||
"label": "Authorized",
|
||||
"fromSide": "bottom",
|
||||
"toSide": "top",
|
||||
"route": "straight",
|
||||
"width": 4,
|
||||
"variant": "default",
|
||||
"labelAt": [
|
||||
570,
|
||||
1225
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "pilot-decide",
|
||||
"from": "pilot",
|
||||
"to": "decide",
|
||||
"label": "Outcomes",
|
||||
"fromSide": "bottom",
|
||||
"toSide": "top",
|
||||
"route": "straight",
|
||||
"width": 4,
|
||||
"variant": "default",
|
||||
"labelAt": [
|
||||
570,
|
||||
1635
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "decide-maintain",
|
||||
"from": "decide",
|
||||
"to": "maintain",
|
||||
"label": "Retain",
|
||||
"fromSide": "bottom",
|
||||
"toSide": "top",
|
||||
"route": "straight",
|
||||
"width": 4,
|
||||
"variant": "default",
|
||||
"labelAt": [
|
||||
570,
|
||||
2045
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "maintain-engineer",
|
||||
"from": "maintain",
|
||||
"to": "engineer",
|
||||
"label": "",
|
||||
"fromSide": "left",
|
||||
"toSide": "left",
|
||||
"route": "straight",
|
||||
"width": 4,
|
||||
"variant": "default",
|
||||
"via": [
|
||||
[
|
||||
145,
|
||||
2240
|
||||
],
|
||||
[
|
||||
145,
|
||||
600
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "decide-baseline",
|
||||
"from": "decide",
|
||||
"to": "baseline",
|
||||
"label": "",
|
||||
"fromSide": "right",
|
||||
"toSide": "right",
|
||||
"route": "straight",
|
||||
"width": 4,
|
||||
"variant": "default",
|
||||
"via": [
|
||||
[
|
||||
980,
|
||||
1830
|
||||
],
|
||||
[
|
||||
980,
|
||||
190
|
||||
]
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,271 @@
|
||||
{
|
||||
"schema_version": 1,
|
||||
"diagram_type": "architecture",
|
||||
"meta": {
|
||||
"title": "TO-BE: stage01",
|
||||
"output": "static/diagrams/strategy-stage01/index.html",
|
||||
"quality_profile": "showcase",
|
||||
"legend": {
|
||||
"mode": "hidden"
|
||||
},
|
||||
"viewBox": [
|
||||
2400,
|
||||
1580
|
||||
]
|
||||
},
|
||||
"components": [
|
||||
{
|
||||
"id": "baseline",
|
||||
"type": "external",
|
||||
"label": "Understand + baseline",
|
||||
"tag": "Product Engineering workflow owner",
|
||||
"sublabel": "Workflow map + desired improvement\nSelected measures + starting evidence\nGovernance: people, scope, authority",
|
||||
"pos": [
|
||||
100,
|
||||
100
|
||||
],
|
||||
"size": [
|
||||
600,
|
||||
260
|
||||
],
|
||||
"icon": "none"
|
||||
},
|
||||
{
|
||||
"id": "engineer",
|
||||
"type": "external",
|
||||
"label": "Engineer connected skills",
|
||||
"tag": "Owning team + independent reviewer",
|
||||
"sublabel": "Triggers, inputs and output handoffs\nPinned candidate + client + limits\nDeliver: patch and regression tests",
|
||||
"pos": [
|
||||
900,
|
||||
100
|
||||
],
|
||||
"size": [
|
||||
600,
|
||||
260
|
||||
],
|
||||
"icon": "none"
|
||||
},
|
||||
{
|
||||
"id": "qualify",
|
||||
"type": "security",
|
||||
"label": "Fit for a bounded pilot?",
|
||||
"tag": "Quality evidence \u2192 owning approver",
|
||||
"sublabel": "Artifact + safety + regression report\nPass: authorize exact pilot scope\nFail / incomplete: hold or rework",
|
||||
"pos": [
|
||||
1700,
|
||||
100
|
||||
],
|
||||
"size": [
|
||||
600,
|
||||
260
|
||||
],
|
||||
"icon": "none"
|
||||
},
|
||||
{
|
||||
"id": "pilot",
|
||||
"type": "external",
|
||||
"label": "Pilot real work",
|
||||
"tag": "Human + AI Agent; independent review",
|
||||
"sublabel": "Use qualified revision within scope\nAccepted / failed work + feedback\nManual path; no new release power",
|
||||
"pos": [
|
||||
1700,
|
||||
730
|
||||
],
|
||||
"size": [
|
||||
600,
|
||||
260
|
||||
],
|
||||
"icon": "none"
|
||||
},
|
||||
{
|
||||
"id": "decide",
|
||||
"type": "security",
|
||||
"label": "Retain, improve or stop?",
|
||||
"tag": "Workflow owner + reviewed evidence",
|
||||
"sublabel": "Compare with baseline, not trials\nNo justified benefit: hold / stop\nNew scope: baseline + new approval",
|
||||
"pos": [
|
||||
900,
|
||||
730
|
||||
],
|
||||
"size": [
|
||||
600,
|
||||
260
|
||||
],
|
||||
"icon": "none"
|
||||
},
|
||||
{
|
||||
"id": "maintain",
|
||||
"type": "external",
|
||||
"label": "Maintain + requalify",
|
||||
"tag": "Owner, Quality, Platform & Security",
|
||||
"sublabel": "Retain: support approved revision\nDrift / defects: revise and retest\nHarm: contain; never auto-restore",
|
||||
"pos": [
|
||||
100,
|
||||
730
|
||||
],
|
||||
"size": [
|
||||
600,
|
||||
260
|
||||
],
|
||||
"icon": "none"
|
||||
},
|
||||
{
|
||||
"id": "reference",
|
||||
"type": "backend",
|
||||
"label": "Governance + Measurement",
|
||||
"tag": "Throughout, not one-time gates",
|
||||
"sublabel": "Named people + controlled authority\nSelected workflow + skill evidence\nKeep populations and gaps explicit",
|
||||
"pos": [
|
||||
100,
|
||||
1270
|
||||
],
|
||||
"size": [
|
||||
2200,
|
||||
260
|
||||
],
|
||||
"icon": "none"
|
||||
}
|
||||
],
|
||||
"connections": [
|
||||
{
|
||||
"id": "baseline-engineer",
|
||||
"from": "baseline",
|
||||
"to": "engineer",
|
||||
"label": "Map",
|
||||
"fromSide": "right",
|
||||
"toSide": "left",
|
||||
"route": "straight",
|
||||
"width": 4,
|
||||
"variant": "default",
|
||||
"labelAt": [
|
||||
800,
|
||||
210
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "engineer-qualify",
|
||||
"from": "engineer",
|
||||
"to": "qualify",
|
||||
"label": "Candidate",
|
||||
"fromSide": "right",
|
||||
"toSide": "left",
|
||||
"route": "straight",
|
||||
"width": 4,
|
||||
"variant": "default",
|
||||
"labelAt": [
|
||||
1600,
|
||||
210
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "qualify-pilot",
|
||||
"from": "qualify",
|
||||
"to": "pilot",
|
||||
"label": "Authorized",
|
||||
"fromSide": "bottom",
|
||||
"toSide": "top",
|
||||
"route": "straight",
|
||||
"width": 4,
|
||||
"variant": "default",
|
||||
"via": [
|
||||
[
|
||||
2000,
|
||||
520
|
||||
]
|
||||
],
|
||||
"labelAt": [
|
||||
2010,
|
||||
535
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "pilot-decide",
|
||||
"from": "pilot",
|
||||
"to": "decide",
|
||||
"label": "Outcomes",
|
||||
"fromSide": "left",
|
||||
"toSide": "right",
|
||||
"route": "straight",
|
||||
"width": 4,
|
||||
"variant": "default",
|
||||
"labelAt": [
|
||||
1600,
|
||||
840
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "decide-maintain",
|
||||
"from": "decide",
|
||||
"to": "maintain",
|
||||
"label": "Retain",
|
||||
"fromSide": "left",
|
||||
"toSide": "right",
|
||||
"route": "straight",
|
||||
"width": 4,
|
||||
"variant": "default",
|
||||
"labelAt": [
|
||||
800,
|
||||
840
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "maintain-engineer",
|
||||
"from": "maintain",
|
||||
"to": "engineer",
|
||||
"label": "Changed revision",
|
||||
"fromSide": "top",
|
||||
"toSide": "bottom",
|
||||
"route": "straight",
|
||||
"width": 4,
|
||||
"variant": "default",
|
||||
"via": [
|
||||
[
|
||||
400,
|
||||
550
|
||||
],
|
||||
[
|
||||
1200,
|
||||
550
|
||||
]
|
||||
],
|
||||
"labelAt": [
|
||||
800,
|
||||
535
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "decide-baseline",
|
||||
"from": "decide",
|
||||
"to": "baseline",
|
||||
"label": "New scope",
|
||||
"fromSide": "bottom",
|
||||
"toSide": "bottom",
|
||||
"route": "straight",
|
||||
"width": 4,
|
||||
"variant": "default",
|
||||
"via": [
|
||||
[
|
||||
1200,
|
||||
1150
|
||||
],
|
||||
[
|
||||
60,
|
||||
1150
|
||||
],
|
||||
[
|
||||
60,
|
||||
430
|
||||
],
|
||||
[
|
||||
400,
|
||||
430
|
||||
]
|
||||
],
|
||||
"labelAt": [
|
||||
620,
|
||||
1135
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,212 @@
|
||||
{
|
||||
"schema_version": 1,
|
||||
"diagram_type": "architecture",
|
||||
"meta": {
|
||||
"title": "TO-BE: stage02",
|
||||
"output": "static/diagrams/strategy-stage02-mobile/index.html",
|
||||
"quality_profile": "showcase",
|
||||
"legend": {
|
||||
"mode": "hidden"
|
||||
},
|
||||
"viewBox": [
|
||||
1000,
|
||||
2540
|
||||
]
|
||||
},
|
||||
"components": [
|
||||
{
|
||||
"id": "proven",
|
||||
"type": "external",
|
||||
"label": "Dependable Stage 01",
|
||||
"tag": "Existing human-directed workflow",
|
||||
"sublabel": "Proven skills + limits + outcome record\nNo inherited autonomous authority",
|
||||
"pos": [
|
||||
200,
|
||||
40
|
||||
],
|
||||
"size": [
|
||||
740,
|
||||
300
|
||||
],
|
||||
"icon": "none"
|
||||
},
|
||||
{
|
||||
"id": "case",
|
||||
"type": "external",
|
||||
"label": "Justify extra authority",
|
||||
"tag": "Owning department proposes scope",
|
||||
"sublabel": "Why needed? Exact data + effects\nObservation first, then proposals",
|
||||
"pos": [
|
||||
200,
|
||||
450
|
||||
],
|
||||
"size": [
|
||||
740,
|
||||
300
|
||||
],
|
||||
"icon": "none"
|
||||
},
|
||||
{
|
||||
"id": "decision",
|
||||
"type": "security",
|
||||
"label": "Authorize or hold",
|
||||
"tag": "Human decision; roles named first",
|
||||
"sublabel": "Security: boundary; Quality: evidence\nPlatform & IT: enforcement + takeover\nOwning approver: exact permitted scope",
|
||||
"pos": [
|
||||
200,
|
||||
860
|
||||
],
|
||||
"size": [
|
||||
740,
|
||||
300
|
||||
],
|
||||
"icon": "none"
|
||||
},
|
||||
{
|
||||
"id": "execute",
|
||||
"type": "backend",
|
||||
"label": "Bounded execution",
|
||||
"tag": "Only within recorded authorization",
|
||||
"sublabel": "Exact-artifact checks + audit\nChanged boundary: reopen decision",
|
||||
"pos": [
|
||||
200,
|
||||
1270
|
||||
],
|
||||
"size": [
|
||||
740,
|
||||
300
|
||||
],
|
||||
"icon": "none"
|
||||
},
|
||||
{
|
||||
"id": "stop",
|
||||
"type": "security",
|
||||
"label": "Independent stop + takeover",
|
||||
"tag": "Platform & IT + Security + owner",
|
||||
"sublabel": "Revoke mutations; preserve evidence\nRecover manually; requalify correction",
|
||||
"pos": [
|
||||
200,
|
||||
1680
|
||||
],
|
||||
"size": [
|
||||
740,
|
||||
300
|
||||
],
|
||||
"icon": "none"
|
||||
},
|
||||
{
|
||||
"id": "hold",
|
||||
"type": "external",
|
||||
"label": "Hold / return to Stage 01",
|
||||
"tag": "Missing authority or readiness",
|
||||
"sublabel": "Fix gaps, narrow scope or stay here\nNo automatic progression",
|
||||
"pos": [
|
||||
200,
|
||||
2090
|
||||
],
|
||||
"size": [
|
||||
740,
|
||||
300
|
||||
],
|
||||
"icon": "none"
|
||||
}
|
||||
],
|
||||
"connections": [
|
||||
{
|
||||
"id": "proven-case",
|
||||
"from": "proven",
|
||||
"to": "case",
|
||||
"label": "Need / limits",
|
||||
"fromSide": "bottom",
|
||||
"toSide": "top",
|
||||
"route": "straight",
|
||||
"width": 4,
|
||||
"variant": "default",
|
||||
"labelAt": [
|
||||
570,
|
||||
405
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "case-decision",
|
||||
"from": "case",
|
||||
"to": "decision",
|
||||
"label": "Proposal",
|
||||
"fromSide": "bottom",
|
||||
"toSide": "top",
|
||||
"route": "straight",
|
||||
"width": 4,
|
||||
"variant": "default",
|
||||
"labelAt": [
|
||||
570,
|
||||
815
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "decision-execute",
|
||||
"from": "decision",
|
||||
"to": "execute",
|
||||
"label": "Authorized",
|
||||
"fromSide": "bottom",
|
||||
"toSide": "top",
|
||||
"route": "straight",
|
||||
"width": 4,
|
||||
"variant": "default",
|
||||
"labelAt": [
|
||||
570,
|
||||
1225
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "execute-stop",
|
||||
"from": "execute",
|
||||
"to": "stop",
|
||||
"label": "Harm / stop",
|
||||
"fromSide": "bottom",
|
||||
"toSide": "top",
|
||||
"route": "straight",
|
||||
"width": 4,
|
||||
"variant": "security",
|
||||
"labelAt": [
|
||||
570,
|
||||
1635
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "decision-hold",
|
||||
"from": "decision",
|
||||
"to": "hold",
|
||||
"label": "",
|
||||
"fromSide": "left",
|
||||
"toSide": "left",
|
||||
"route": "straight",
|
||||
"width": 4,
|
||||
"variant": "security",
|
||||
"via": [
|
||||
[
|
||||
105,
|
||||
1010
|
||||
],
|
||||
[
|
||||
105,
|
||||
2240
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "stop-hold",
|
||||
"from": "stop",
|
||||
"to": "hold",
|
||||
"label": "Requalify",
|
||||
"fromSide": "bottom",
|
||||
"toSide": "top",
|
||||
"route": "straight",
|
||||
"width": 4,
|
||||
"variant": "security",
|
||||
"labelAt": [
|
||||
570,
|
||||
2045
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,236 @@
|
||||
{
|
||||
"schema_version": 1,
|
||||
"diagram_type": "architecture",
|
||||
"meta": {
|
||||
"title": "TO-BE: stage02",
|
||||
"output": "static/diagrams/strategy-stage02/index.html",
|
||||
"quality_profile": "showcase",
|
||||
"legend": {
|
||||
"mode": "hidden"
|
||||
},
|
||||
"viewBox": [
|
||||
2740,
|
||||
1260
|
||||
]
|
||||
},
|
||||
"components": [
|
||||
{
|
||||
"id": "proven",
|
||||
"type": "external",
|
||||
"label": "Dependable Stage 01",
|
||||
"tag": "Existing human-directed workflow",
|
||||
"sublabel": "Proven skills + limits + outcome record\nNo inherited autonomous authority",
|
||||
"pos": [
|
||||
60,
|
||||
100
|
||||
],
|
||||
"size": [
|
||||
680,
|
||||
230
|
||||
],
|
||||
"icon": "none"
|
||||
},
|
||||
{
|
||||
"id": "case",
|
||||
"type": "external",
|
||||
"label": "Justify extra authority",
|
||||
"tag": "Owning department proposes scope",
|
||||
"sublabel": "Why needed? Exact data + effects\nObservation first, then proposals",
|
||||
"pos": [
|
||||
60,
|
||||
550
|
||||
],
|
||||
"size": [
|
||||
680,
|
||||
230
|
||||
],
|
||||
"icon": "none"
|
||||
},
|
||||
{
|
||||
"id": "decision",
|
||||
"type": "security",
|
||||
"label": "Authorize or hold",
|
||||
"tag": "Human decision; roles named first",
|
||||
"sublabel": "Security: boundary; Quality: evidence\nPlatform & IT: enforcement + takeover\nOwning approver: exact permitted scope",
|
||||
"pos": [
|
||||
1000,
|
||||
340
|
||||
],
|
||||
"size": [
|
||||
720,
|
||||
290
|
||||
],
|
||||
"icon": "none"
|
||||
},
|
||||
{
|
||||
"id": "execute",
|
||||
"type": "backend",
|
||||
"label": "Bounded execution",
|
||||
"tag": "Only within recorded authorization",
|
||||
"sublabel": "Exact-artifact checks + audit\nChanged boundary: reopen decision",
|
||||
"pos": [
|
||||
1980,
|
||||
100
|
||||
],
|
||||
"size": [
|
||||
680,
|
||||
230
|
||||
],
|
||||
"icon": "none"
|
||||
},
|
||||
{
|
||||
"id": "stop",
|
||||
"type": "security",
|
||||
"label": "Independent stop + takeover",
|
||||
"tag": "Platform & IT + Security + owner",
|
||||
"sublabel": "Revoke mutations; preserve evidence\nRecover manually; requalify correction",
|
||||
"pos": [
|
||||
1980,
|
||||
650
|
||||
],
|
||||
"size": [
|
||||
680,
|
||||
230
|
||||
],
|
||||
"icon": "none"
|
||||
},
|
||||
{
|
||||
"id": "hold",
|
||||
"type": "external",
|
||||
"label": "Hold / return to Stage 01",
|
||||
"tag": "Missing authority or readiness",
|
||||
"sublabel": "Fix gaps, narrow scope or stay here\nNo automatic progression",
|
||||
"pos": [
|
||||
1000,
|
||||
960
|
||||
],
|
||||
"size": [
|
||||
720,
|
||||
230
|
||||
],
|
||||
"icon": "none"
|
||||
}
|
||||
],
|
||||
"connections": [
|
||||
{
|
||||
"id": "proven-case",
|
||||
"from": "proven",
|
||||
"to": "case",
|
||||
"label": "Need / limits",
|
||||
"fromSide": "bottom",
|
||||
"toSide": "top",
|
||||
"route": "straight",
|
||||
"width": 4,
|
||||
"variant": "default",
|
||||
"labelAt": [
|
||||
410,
|
||||
440
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "case-decision",
|
||||
"from": "case",
|
||||
"to": "decision",
|
||||
"label": "Proposal",
|
||||
"fromSide": "right",
|
||||
"toSide": "left",
|
||||
"route": "straight",
|
||||
"width": 4,
|
||||
"variant": "default",
|
||||
"via": [
|
||||
[
|
||||
860,
|
||||
665
|
||||
],
|
||||
[
|
||||
860,
|
||||
485
|
||||
]
|
||||
],
|
||||
"labelAt": [
|
||||
860,
|
||||
650
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "decision-execute",
|
||||
"from": "decision",
|
||||
"to": "execute",
|
||||
"label": "Authorized",
|
||||
"fromSide": "right",
|
||||
"toSide": "left",
|
||||
"route": "straight",
|
||||
"width": 4,
|
||||
"variant": "default",
|
||||
"via": [
|
||||
[
|
||||
1850,
|
||||
485
|
||||
],
|
||||
[
|
||||
1850,
|
||||
215
|
||||
]
|
||||
],
|
||||
"labelAt": [
|
||||
1840,
|
||||
200
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "execute-stop",
|
||||
"from": "execute",
|
||||
"to": "stop",
|
||||
"label": "Harm / stop",
|
||||
"fromSide": "bottom",
|
||||
"toSide": "top",
|
||||
"route": "straight",
|
||||
"width": 4,
|
||||
"variant": "security",
|
||||
"labelAt": [
|
||||
2320,
|
||||
500
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "decision-hold",
|
||||
"from": "decision",
|
||||
"to": "hold",
|
||||
"label": "Hold",
|
||||
"fromSide": "bottom",
|
||||
"toSide": "top",
|
||||
"route": "straight",
|
||||
"width": 4,
|
||||
"variant": "security",
|
||||
"labelAt": [
|
||||
1360,
|
||||
810
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "stop-hold",
|
||||
"from": "stop",
|
||||
"to": "hold",
|
||||
"label": "Requalify",
|
||||
"fromSide": "left",
|
||||
"toSide": "right",
|
||||
"route": "straight",
|
||||
"width": 4,
|
||||
"variant": "security",
|
||||
"via": [
|
||||
[
|
||||
1840,
|
||||
765
|
||||
],
|
||||
[
|
||||
1840,
|
||||
1075
|
||||
]
|
||||
],
|
||||
"labelAt": [
|
||||
1840,
|
||||
1060
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -12,14 +12,14 @@
|
||||
{"id":"uat","type":"backend","label":"UAT","sublabel":"06","pos":[100,1540],"size":[240,100]},
|
||||
{"id":"security","type":"backend","label":"Security","sublabel":"07","pos":[100,1760],"size":[240,100]},
|
||||
{"id":"releases","type":"backend","label":"Releases","sublabel":"08","pos":[100,1980],"size":[240,100]},
|
||||
{"id":"code-scope","type":"frontend","label":"Code agent","sublabel":"Human-controlled","pos":[400,440],"size":[240,100]},
|
||||
{"id":"code-architecture","type":"frontend","label":"Code agent","sublabel":"Human-controlled","pos":[400,660],"size":[240,100]},
|
||||
{"id":"code-ui-ux","type":"frontend","label":"Code agent","sublabel":"Human-controlled","pos":[400,880],"size":[240,100]},
|
||||
{"id":"code-planning","type":"frontend","label":"Code agent","sublabel":"Human-controlled","pos":[400,1100],"size":[240,100]},
|
||||
{"id":"code-delivery","type":"frontend","label":"Code agent","sublabel":"Human-controlled","pos":[400,1320],"size":[240,100]},
|
||||
{"id":"code-uat","type":"frontend","label":"Code agent","sublabel":"Human-controlled","pos":[400,1540],"size":[240,100]},
|
||||
{"id":"code-security","type":"frontend","label":"Code agent","sublabel":"Human-controlled","pos":[400,1760],"size":[240,100]},
|
||||
{"id":"code-releases","type":"frontend","label":"Code agent","sublabel":"Human-controlled","pos":[400,1980],"size":[240,100]}
|
||||
{"id":"code-scope","type":"frontend","label":"AI Agent","sublabel":"Human-controlled","pos":[400,440],"size":[240,100]},
|
||||
{"id":"code-architecture","type":"frontend","label":"AI Agent","sublabel":"Human-controlled","pos":[400,660],"size":[240,100]},
|
||||
{"id":"code-ui-ux","type":"frontend","label":"AI Agent","sublabel":"Human-controlled","pos":[400,880],"size":[240,100]},
|
||||
{"id":"code-planning","type":"frontend","label":"AI Agent","sublabel":"Human-controlled","pos":[400,1100],"size":[240,100]},
|
||||
{"id":"code-delivery","type":"frontend","label":"AI Agent","sublabel":"Human-controlled","pos":[400,1320],"size":[240,100]},
|
||||
{"id":"code-uat","type":"frontend","label":"AI Agent","sublabel":"Human-controlled","pos":[400,1540],"size":[240,100]},
|
||||
{"id":"code-security","type":"frontend","label":"AI Agent","sublabel":"Human-controlled","pos":[400,1760],"size":[240,100]},
|
||||
{"id":"code-releases","type":"frontend","label":"AI Agent","sublabel":"Human-controlled","pos":[400,1980],"size":[240,100]}
|
||||
],
|
||||
"connections": [
|
||||
|
||||
|
||||
@@ -12,25 +12,25 @@
|
||||
{"id":"uat","type":"backend","label":"UAT","sublabel":"06","pos":[240,727.5],"size":[180,75]},
|
||||
{"id":"security","type":"backend","label":"Security","sublabel":"07","pos":[240,457.5],"size":[180,75]},
|
||||
{"id":"releases","type":"backend","label":"Releases","sublabel":"08","pos":[240,187.5],"size":[180,75]},
|
||||
{"id":"code-scope","type":"frontend","label":"Code agent","sublabel":"Human-controlled","pos":[510,37.5],"size":[180,75]},
|
||||
{"id":"code-architecture","type":"frontend","label":"Code agent","sublabel":"Human-controlled","pos":[780,37.5],"size":[180,75]},
|
||||
{"id":"code-ui-ux","type":"frontend","label":"Code agent","sublabel":"Human-controlled","pos":[1005,457.5],"size":[180,75]},
|
||||
{"id":"code-planning","type":"frontend","label":"Code agent","sublabel":"Human-controlled","pos":[780,877.5],"size":[180,75]},
|
||||
{"id":"code-delivery","type":"frontend","label":"Code agent","sublabel":"Human-controlled","pos":[510,877.5],"size":[180,75]},
|
||||
{"id":"code-uat","type":"frontend","label":"Code agent","sublabel":"Human-controlled","pos":[240,877.5],"size":[180,75]},
|
||||
{"id":"code-security","type":"frontend","label":"Code agent","sublabel":"Human-controlled","pos":[15,457.5],"size":[180,75]},
|
||||
{"id":"code-releases","type":"frontend","label":"Code agent","sublabel":"Human-controlled","pos":[240,37.5],"size":[180,75]}
|
||||
{"id":"code-scope","type":"frontend","label":"AI Agent","sublabel":"Human-controlled","pos":[510,37.5],"size":[180,75]},
|
||||
{"id":"code-architecture","type":"frontend","label":"AI Agent","sublabel":"Human-controlled","pos":[780,37.5],"size":[180,75]},
|
||||
{"id":"code-ui-ux","type":"frontend","label":"AI Agent","sublabel":"Human-controlled","pos":[1005,457.5],"size":[180,75]},
|
||||
{"id":"code-planning","type":"frontend","label":"AI Agent","sublabel":"Human-controlled","pos":[780,877.5],"size":[180,75]},
|
||||
{"id":"code-delivery","type":"frontend","label":"AI Agent","sublabel":"Human-controlled","pos":[510,877.5],"size":[180,75]},
|
||||
{"id":"code-uat","type":"frontend","label":"AI Agent","sublabel":"Human-controlled","pos":[240,877.5],"size":[180,75]},
|
||||
{"id":"code-security","type":"frontend","label":"AI Agent","sublabel":"Human-controlled","pos":[15,457.5],"size":[180,75]},
|
||||
{"id":"code-releases","type":"frontend","label":"AI Agent","sublabel":"Human-controlled","pos":[240,37.5],"size":[180,75]}
|
||||
],
|
||||
"connections": [
|
||||
|
||||
{"id":"govern-scope","from":"agent","to":"scope","label":"","variant":"security","fromSide":"right","toSide":"bottom","via":[[750,495],[750,292.5],[600,292.5]]},
|
||||
{"id":"govern-architecture","from":"agent","to":"architecture","label":"","variant":"security","fromSide":"right","toSide":"bottom","via":[[765,495],[765,345],[870,345]]},
|
||||
{"id":"govern-ui-ux","from":"agent","to":"ui-ux","label":"","variant":"security","fromSide":"right","toSide":"left"},
|
||||
{"id":"govern-planning","from":"agent","to":"planning","label":"","variant":"security","fromSide":"right","toSide":"top","via":[[765,495],[765,690],[870,690]]},
|
||||
{"id":"govern-delivery","from":"agent","to":"delivery","label":"","variant":"security","fromSide":"bottom","toSide":"top"},
|
||||
{"id":"govern-uat","from":"agent","to":"uat","label":"","variant":"security","fromSide":"left","toSide":"top","via":[[435,495],[435,690],[330,690]]},
|
||||
{"id":"govern-security","from":"agent","to":"security","label":"","variant":"security","fromSide":"left","toSide":"right"},
|
||||
{"id":"govern-releases","from":"agent","to":"releases","label":"","variant":"security","fromSide":"left","toSide":"bottom","via":[[435,495],[435,345],[330,345]]},
|
||||
{"id":"govern-scope","from":"agent","to":"scope","label":"","variant":"security","fromSide":"top","toSide":"bottom","route":"straight"},
|
||||
{"id":"govern-architecture","from":"agent","to":"architecture","label":"","variant":"security","fromSide":"top","toSide":"bottom","via":[[600,345],[870,345]]},
|
||||
{"id":"govern-ui-ux","from":"agent","to":"ui-ux","label":"","variant":"security","fromSide":"right","toSide":"left","route":"straight"},
|
||||
{"id":"govern-planning","from":"agent","to":"planning","label":"","variant":"security","fromSide":"bottom","toSide":"top","via":[[600,645],[870,645]]},
|
||||
{"id":"govern-delivery","from":"agent","to":"delivery","label":"","variant":"security","fromSide":"bottom","toSide":"top","route":"straight"},
|
||||
{"id":"govern-uat","from":"agent","to":"uat","label":"","variant":"security","fromSide":"bottom","toSide":"top","via":[[600,645],[330,645]]},
|
||||
{"id":"govern-security","from":"agent","to":"security","label":"","variant":"security","fromSide":"left","toSide":"right","route":"straight"},
|
||||
{"id":"govern-releases","from":"agent","to":"releases","label":"","variant":"security","fromSide":"top","toSide":"bottom","via":[[600,345],[330,345]]},
|
||||
{"id":"stage-1","from":"scope","to":"architecture","label":"Then","variant":"emphasis","fromSide":"right","toSide":"left"},
|
||||
{"id":"stage-2","from":"architecture","to":"ui-ux","label":"Then","variant":"emphasis","fromSide":"bottom","toSide":"top"},
|
||||
{"id":"stage-3","from":"ui-ux","to":"planning","label":"Then","variant":"emphasis","fromSide":"bottom","toSide":"top"},
|
||||
|
||||
@@ -15,7 +15,7 @@ description: Author typed JSON diagrams and embed their local interactive viewer
|
||||
| Dataflow | Sources, processing and destinations |
|
||||
| Lifecycle | States and transitions |
|
||||
|
||||
The standalone viewer provides pan/zoom, node inspection, search/focus, relationship tracing, light/dark themes, and an export menu. Motion is opt-in. The Organization views exercise architecture mode; other diagram types use the same build interface but do not yet have portal-specific examples. Browser-dependent exports such as video are not acceptance-tested by this integration.
|
||||
The standalone viewer provides pan/zoom, node inspection, search/focus, relationship tracing, light/dark themes, and an export menu. Motion is opt-in. The Organization views exercise architecture mode; Roadmap uses native Workflow v2 with a horizontal desktop path and the same stages stacked on mobile. Other diagram types use the same build interface but do not yet have portal-specific examples. Browser-dependent exports such as video are not acceptance-tested by this integration.
|
||||
|
||||
## Author a diagram
|
||||
|
||||
@@ -23,6 +23,8 @@ Create `diagrams/<name>.<type>.json` using the matching schema and authoring gui
|
||||
|
||||
Set `meta.output` to `static/diagrams/<name>/index.html`. The build validates the typed source with the upstream showcase profile, renders locally, checks the artifact, and publishes the standalone HTML. Editable JSON stays in the repository; the portal does not publish source-download files.
|
||||
|
||||
Roadmap has a scoped multiline typography adapter in `scripts/roadmap-viewer.mjs`. Its two `.workflow.json` sources use the native v2 schema, one lane, `mainPath`, logical columns and native routes. The native renderer validates the schema and solves geometry; the adapter wraps the existing action/output/exit copy, removes the redundant lane frame and trims empty canvas. The final artifact then passes the upstream showcase composition checker. This path records source, adapter and final artifact hashes in private `.cache/archify/*.portal.json` receipts, not upstream `deliver` provenance. Keep the vendor unchanged and run the Roadmap browser check at 1440, 390 and 320 pixels after any copy or sizing change. Typography is embedded in the SVG so exports retain it.
|
||||
|
||||
```sh
|
||||
pnpm diagrams:build
|
||||
pnpm test
|
||||
|
||||
@@ -28,7 +28,10 @@ Include `title` and `description` frontmatter. Place each page in its owning sec
|
||||
| Contribution | `docs/contribution/` | `sidebars/contribution.ts` |
|
||||
| Portal maintenance and reference | `docs/core/` | `sidebars.ts` |
|
||||
|
||||
Keep these content roots disjoint. Preserve existing URLs when moving pages. Specific AI initiatives and organizational reporting lines remain subject to agreement.
|
||||
Keep these content roots disjoint. Preserve existing URLs unless a URL migration is explicitly approved; provide precise redirects for approved moves. Metric details live on individual canonical pages directly under Measurement, alongside shared collection safeguards and the synthetic example. Specific AI initiatives and organizational reporting lines remain subject to agreement.
|
||||
Every published documentation page must have a navigable sidebar entry. Nested references are welcome; hidden documentation is not. Linked category overviews count as entries, but an in-page anchor is not a separate document. Portal-maintenance pages keep their existing `/docs/` routes and dedicated sidebar, reachable from Contribution → Portal maintenance.
|
||||
|
||||
`pnpm verify:build` compares all Docusaurus-generated document IDs/routes with resolved sidebar trees (including linked category overviews), checks reachability from the navbar, rejects missing/duplicate entries and unclassified HTML routes, and checks every document’s local links and anchors. The inventory is written to `.cache/sidebar-coverage.json`. Only the homepage, not-found page, search-results UI, legacy Strategy redirect, exact legacy measurement-contracts hash-aware redirect and standalone diagram viewers are non-document HTML routes; no documentation page is exempt. The metric migration manifest in `research/ai-adoption/measurement-migration.json` records old anchors, canonical IDs/URLs, implementation status and preserved-contract hashes.
|
||||
|
||||
## Validate the change
|
||||
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
---
|
||||
id: baseline
|
||||
title: Baseline
|
||||
sidebar_label: Baseline
|
||||
description: Understand a workflow, select relevant candidate metrics and establish feasible starting evidence for later comparison.
|
||||
pagination_prev: measurement/index
|
||||
pagination_next: skills-governance
|
||||
hide_table_of_contents: true
|
||||
---
|
||||
|
||||
import ArchifyDiagram from '@site/src/components/ArchifyDiagram';
|
||||
|
||||
<div className="strategy-content">
|
||||
|
||||
Establish a starting position for one workflow as adoption reaches it. This is not a mandatory company-wide baseline of every metric in the [Measurement registry](./measurement/index.mdx).
|
||||
|
||||
<ArchifyDiagram name="strategy-baseline" title="From current workflow through relevant selection and feasible evidence to a starting position and later comparison" story />
|
||||
|
||||
**Target operating model — no actual baseline values or approved thresholds are established here.** Missing evidence remains an explicit gap, not an invented starting value.
|
||||
|
||||
## Delivery example: know what must improve
|
||||
|
||||
In the [illustrative Delivery workflow](./stage-01-skills-adoption.mdx), Product Engineering maps a bounded code change through regression tests, independent review and existing release controls. Suppose the concern is repeated rework because regression evidence is incomplete: first verify the cause from actual changes, rather than assuming a skill will fix it.
|
||||
|
||||
Consider accepted-task outcomes, escaped-quality follow-up and review/rework inputs to cost if their contracts fit. Select only evidence that can inform that concern; deployment frequency need not help. The output is a workflow map and comparison record, not a pass/fail score. The owning team's designated workflow owner confirms scope with the independent Quality Engineering reviewer; unresolved source or acceptance gaps limit later conclusions, not authorize a pilot.
|
||||
|
||||
## Understand the current workflow
|
||||
|
||||
Describe the task, team or service, intended outcome, current tools, handoffs, controls and known friction. Bound what is in and out of scope. For Delivery, start with codebase structure and existing principles, system-logic sources, tests, builds and packaging, then deployments. Record current practice, including any existing AI use; do not label it “no-skill” unless that is true.
|
||||
|
||||
## Select relevant metrics, with reasons
|
||||
|
||||
Start with **Workflow effectiveness**: select relevant current-workflow outcomes before standardized skills adoption—accepted work, delivery time, failures/rework, cost, human effort/experience or business acceptance where the contracts apply. Choose the registry entries that answer this workflow's questions. Record why each selected metric applies, what decision it can inform, and why other candidates are irrelevant or deferred. There is no required universal subset. A service-level DORA metric, a qualification test and a people survey have different populations; they are not interchangeable.
|
||||
|
||||
Keep **Skills effectiveness & health** separate. If no applicable skills exist, selection, bundle, adoption and review measures may be N/A, not zero; they are not prerequisites for baselining current work. If skills already exist, record that starting context and qualify named revisions separately. Do not mix sandbox skill evaluations into validated workflow task success or live policy-effect rates.
|
||||
|
||||
Agree what counts as a started task, independent acceptance and completed follow-up before counting outcomes. Freeze eligibility and acceptance rules and verify event joins. Select a complete comparable workflow cycle and a predeclared precision/sample requirement appropriate to the decision. Do not select a convenient end date after seeing results. Where those requirements cannot be met, record the resulting evidence limitation.
|
||||
|
||||
## Agree feasible evidence
|
||||
|
||||
Confirm collection feasibility, period, sources, owner, independent reviewer, access, lawful basis, privacy and retention before collecting. Use the [shared safeguards](./measurement/collection-and-safeguards.mdx) and each selected contract's input requirements. Proposed owner/cadence entries are not already assigned responsibilities.
|
||||
|
||||
Start with a controlled worksheet or export if automation is unavailable. Join task IDs to acceptance records, PR/commit IDs, CI results and later defects where relevant; test source coverage and permissions. Repository and CI evidence support verification, but a green build alone is not task acceptance. Record exact skill revisions and client/model configurations when present; keep missing versions unknown.
|
||||
|
||||
## Record the starting position
|
||||
|
||||
Collect prospective current-practice evidence over the agreed period. Record actual starting values only when supported by traceable evidence. Include units, population, observation period, counts, exclusions, source coverage, calculation version, uncertainty and limitations. Zero denominators mean “not available,” not zero performance.
|
||||
|
||||
For each selected metric, keep one of these explicit records:
|
||||
|
||||
- **Available:** evidenced starting value, source links, calculation, owner and limits.
|
||||
- **Unavailable:** missing input or permission, affected comparison, responsible owner and proposed next action or review point. Never fill the gap with the synthetic example or an assumed industry value.
|
||||
|
||||
Record deferred and non-applicable candidates separately from selected-but-unavailable metrics. This page is the recording method, not an Eldorado baseline report or a set of approved targets.
|
||||
|
||||
## Keep later evaluation comparable
|
||||
|
||||
Retain task class, service, skill, client/model configuration and concurrent changes. In [Adoption](./skills-adoption.mdx), use the same agreed eligibility, acceptance and observation rules; in [Maintenance](./skills-maintenance.mdx), record any changes and breaks in comparability rather than silently replacing the starting position.
|
||||
|
||||
A matched or randomized comparison may be used when practical and ethical. Label observational trends as descriptive, not causal ROI; report confounding, selection and uncertainty. Missing or small samples limit conclusions. Baseline values describe current practice; they do not establish acceptable risk or authorize expansion.
|
||||
|
||||
**Next:** [Govern skill ownership and authority →](./skills-governance.mdx)
|
||||
|
||||
Carry the map, selected definitions and evidence limits into candidate design. Return here from [Adoption](./skills-adoption.mdx) when scope changes, or from [Maintenance](./skills-maintenance.mdx) when the current workflow no longer matches the comparison. See the [whole Stage 01 journey](./stage-01-skills-adoption.mdx).
|
||||
|
||||
</div>
|
||||
@@ -1,71 +0,0 @@
|
||||
---
|
||||
id: measurement
|
||||
title: Skills Measurement
|
||||
sidebar_label: Skills Measurement
|
||||
description: Which KPIs to collect during skills adoption, where the evidence comes from, how to calculate them and when to report.
|
||||
hide_table_of_contents: true
|
||||
---
|
||||
|
||||
import ArchifyDiagram from '@site/src/components/ArchifyDiagram';
|
||||
|
||||
<div className="strategy-content">
|
||||
|
||||
Measure adoption in stages: first establish today’s performance, then follow the pilot, extend coverage and keep skills current. Count use separately from outcomes—more use does not by itself mean better work.
|
||||
|
||||
<ArchifyDiagram name="strategy-measurement" title="Skills adoption measurement: baseline, pilot, broader adoption and monitoring" story />
|
||||
|
||||
**Recommended collection plan · Target operating model, not installed telemetry.** Confirm the proposed roles and reporting cadence below before collecting data.
|
||||
|
||||
## 1. Establish the baseline
|
||||
|
||||
Choose one workflow, such as reviewing a code change with a review skill. Agree what counts as a started task, independent acceptance and the follow-up period before counting outcomes. Collect current-practice evidence over a complete comparable workflow cycle and until the agreed sample requirement is met; use the same rules in the pilot.
|
||||
|
||||
Start with a controlled worksheet or export. Join task IDs to acceptance records, PR/commit IDs, CI results and later defects. Record the exact skill revision and client configuration for pilot work; keep missing versions unknown. Repository and CI evidence support verification, but a green build alone is not task acceptance.
|
||||
|
||||
## 2. Measure the pilot
|
||||
|
||||
Start with these four questions. Capture inputs as work happens; do not reconstruct review effort from elapsed PR time.
|
||||
|
||||
### Are tasks reaching acceptance?
|
||||
|
||||
**Collect:** task starts and independent acceptance, failure or abandonment records from the work tracker. **Calculate:** accepted tasks / all eligible starts whose observation period has ended × 100. Failed, abandoned and unresolved tasks stay in the denominator; show unknown outcomes and coverage separately. This is [validated task success](./reference/measurement-contracts.mdx#validated-task-success), not a count of agent completions. **Weekly:** Quality Engineering reviews the pilot cohort.
|
||||
|
||||
### Is quality holding up?
|
||||
|
||||
**Collect:** accepted change IDs, linked confirmed defects, severity and follow-up dates from review and defect records; retain PR/CI evidence. **Calculate:** changes with at least one confirmed defect / accepted changes with completed follow-up × 100. Count each affected change once, not each defect. Missing links do not mean clean work. **Monthly:** Quality Engineering reviews [escaped quality](./reference/measurement-contracts.mdx#changes-with-escaped-quality-issues) after follow-up, alongside severe incident counts.
|
||||
|
||||
### What does an accepted outcome cost?
|
||||
|
||||
**Collect:** invoices and usage costs plus sampled human review/rework minutes at approved rates, including unsuccessful attempts and allocated licenses/tooling. **Calculate:** total allocated workflow cost / independently accepted tasks in the same matured start cohort. Keep effort separate from waiting time. Missing buckets make this a partial estimate, not total cost. **Monthly:** Finance & Accounting reconciles [cost per accepted outcome](./reference/measurement-contracts.mdx#cost-per-accepted-outcome), restating late invoices.
|
||||
|
||||
### Can people confidently verify the work?
|
||||
|
||||
**Collect:** an anonymous 1–5 survey after a pilot workflow cycle: verification confidence, manageable workload and usefulness as separate items. **Calculate:** sum of valid confidence scores / valid responses; also show the distribution and responses / invitations × 100. This guides enablement, not claims of saved time. **After each pilot cycle:** People & Administration reviews [confidence and cognitive load](./reference/measurement-contracts.mdx#verification-confidence-and-cognitive-load); protect small groups.
|
||||
|
||||
### What a pilot report looks like
|
||||
|
||||
**Illustrative arithmetic, not company results or targets.** The bundled synthetic fixture shows four matured starts: one accepted, one failed, one abandoned and one unresolved. Confirmed success is **1 / 4 × 100 = 25%**, with **75%** known-outcome coverage. A newer start has not finished its observation period and is shown separately.
|
||||
|
||||
Recorded compute spend is **EUR 60 / 1 = EUR 60** per accepted outcome—a **partial estimate** because licenses, tooling, review and rework are missing. Five survey responses total 20 points: **20 / 5 = 4** out of 5; response rate is **5 / 10 × 100 = 50%**. The report calls for reconciling the unknown task and missing costs, not claiming a skills benefit. Reproduce it with `node scripts/ai-kpi.mjs`; [fixture and limits](./reference/measurement-contracts.mdx#run-the-synthetic-measurement-example).
|
||||
|
||||
## 3. Extend collection as adoption grows
|
||||
|
||||
Keep those outcome measures, then add reach. An adoption percentage is meaningless without a known eligible population.
|
||||
|
||||
**Are supported skills available?** Freeze the expected active installation inventory; compare observed bundle/adapter revisions with the approved support and revocation records. [Supported bundle coverage](./reference/measurement-contracts.mdx#supported-bundle-coverage) = fresh, verified supported installations / all expected active installations × 100. Offline or stale entries stay in the denominator. **Weekly and at revocation:** Platform & IT reconciles coverage.
|
||||
|
||||
**Are approved workflows being used?** Freeze the lawfully enrolled participant cohort; collect workflow-linked use of an approved revision through a qualified adapter or a separately labeled declaration. [Approved-workflow adoption](./reference/measurement-contracts.mdx#approved-workflow-adoption) = eligible participants with at least one observed approved use / eligible invited participants × 100. Report this as an observed lower bound with source coverage: missing use is unknown. Installation and loading are not use. **Monthly:** Data & AI reviews reach without invocation quotas or employee rankings.
|
||||
|
||||
## 4. Keep the collection running
|
||||
|
||||
**Are skills still maintained?** From the versioned catalog, join each active approved revision to its owner, substantive review evidence and due date. [Review coverage](./reference/measurement-contracts.mdx#skills-within-substantive-review-window) = revisions with all three current / all active approved revisions × 100. **Monthly and each release:** Data & AI reports overdue/ownerless revisions and deprecated or revoked versions still in use—not just a percentage.
|
||||
|
||||
At each report, compare like workflows with the baseline and publish the period, counts, exclusions and source coverage. Zero denominators mean “not available.” Trends are descriptive, not causal ROI. Act on critical policy effects immediately; add selection precision/recall at qualification and service-level delivery or departmental outcome measures when their source links are ready.
|
||||
|
||||
Agree purpose, lawful basis, access and retention first. No raw prompts, code or secrets by default; suppress people cohorts below five and prevent identifying drill-downs.
|
||||
|
||||
[Full KPI reference →](./reference/measurement-contracts.mdx) preserves all definitions, collection safeguards and the distinction between synthetic calculations and unimplemented metrics.
|
||||
|
||||
**Next:** [Maintain skills using the evidence →](./skills-maintenance.mdx)
|
||||
|
||||
</div>
|
||||
@@ -0,0 +1,38 @@
|
||||
---
|
||||
id: approved-workflow-adoption
|
||||
slug: /measurement/approved-workflow-adoption
|
||||
title: Approved-workflow adoption
|
||||
description: Definition, collection evidence and limitations for approved-workflow adoption.
|
||||
---
|
||||
|
||||
<div className="strategy-content">
|
||||
|
||||
**Target operating model — recommended contracts, not installed collection.** All owner and cadence entries below are proposals to confirm before the pilot, not assigned responsibilities or approved schedules.
|
||||
|
||||
**Unimplemented metric — no live telemetry.** This is a prospective contract, not an implemented calculation or collector.
|
||||
|
||||
{/* contract:start */}
|
||||
Eligible participants with at least one approved-skill workflow use; usefulness assessed separately through accepted outcomes and feedback.
|
||||
|
||||
| Contract | Definition |
|
||||
| --- | --- |
|
||||
| Numerator | Distinct eligible pseudonymous participants with workflow-linked skill.used on approved revision |
|
||||
| Denominator | Distinct eligible participants in frozen invited cohort |
|
||||
| Expression | N / D * 100 |
|
||||
| Aggregation | percent |
|
||||
| Unit | % |
|
||||
| Eligible population | Consented or otherwise lawfully enrolled pilot cohort for the period; supported workflow available. |
|
||||
| Exclusions | Outside pilot and formally recorded leave before period; nonresponders remain eligible, not excluded. |
|
||||
| Events and source | skill.used; cohort.snapshot; optional qualified client adapter or declaration |
|
||||
| Owner / cadence | Data & AI / Monthly |
|
||||
| Missing evidence | Show observed lower bound and telemetry/response coverage; missing usage unknown rather than non-use. |
|
||||
| Gaming and limits | Invocation quotas and coercion; no target usage count, split server/client/self-report origins. Descriptive signal, not causal AI productivity attribution. Source completeness, task mix and sampling limit inference; report uncertainty. Self-report is not verified use; installation/loading is not use or benefit. Suppress small groups. |
|
||||
{/* contract:end */}
|
||||
|
||||
Read the shared [collection and safeguards](./collection-and-safeguards.mdx) before collecting data; see the [synthetic example and limits](./synthetic-example.mdx).
|
||||
|
||||
Return to [Skills Measurement](./index.mdx).
|
||||
|
||||
In [Stage 01](../stage-01-skills-adoption.mdx), authorization to test an experimental revision is not general approved status. This contract counts approved-revision use only; do not relabel experimental pilot use to raise its numerator. [Adoption](../skills-adoption.mdx) still evaluates that pilot through independent work outcomes and [Quality's fitness evidence](../skills-quality.mdx). Use this reach measure only where its approved-revision population applies.
|
||||
|
||||
</div>
|
||||
@@ -0,0 +1,36 @@
|
||||
---
|
||||
id: change-fail-rate
|
||||
slug: /measurement/change-fail-rate
|
||||
title: Change fail rate
|
||||
description: Definition, collection evidence and limitations for change fail rate.
|
||||
---
|
||||
|
||||
<div className="strategy-content">
|
||||
|
||||
**Target operating model — recommended contracts, not installed collection.** All owner and cadence entries below are proposals to confirm before the pilot, not assigned responsibilities or approved schedules.
|
||||
|
||||
**Prototype calculation — no live telemetry.** The synthetic example calculates this metric; it has no network collectors.
|
||||
|
||||
{/* contract:start */}
|
||||
Production deployment effects requiring unplanned remediation, rollback or hotfix, not solely outage declarations.
|
||||
|
||||
| Contract | Definition |
|
||||
| --- | --- |
|
||||
| Numerator | Distinct matured production deployment_ids linked to qualifying immediate intervention |
|
||||
| Denominator | All distinct production deployment_ids that reached production in the matured deployment cohort |
|
||||
| Expression | N / D * 100 |
|
||||
| Aggregation | percent |
|
||||
| Unit | % |
|
||||
| Eligible population | Deployments with production effect during window and approved intervention follow-up horizon elapsed. |
|
||||
| Exclusions | Failed preproduction attempts, duplicate callbacks and no-effect retries; failures after production effect stay included. |
|
||||
| Events and source | deployment.completed; deployment.failed; incident.linked; release and incident records |
|
||||
| Owner / cadence | Quality Engineering / Weekly; finalized after horizon |
|
||||
| Missing evidence | Known failures / all eligible deployments is a lower bound where incident linkage incomplete; label provisional and report unknown links. |
|
||||
| Gaming and limits | Avoid incident links or relabel intervention planned; reconcile rollbacks/hotfixes independently. Descriptive signal, not causal AI productivity attribution. Source completeness, task mix and sampling limit inference; report uncertainty. Define immediate intervention and follow-up horizon before pilot; no universal incident-to-AI attribution. |
|
||||
{/* contract:end */}
|
||||
|
||||
Read the shared [collection and safeguards](./collection-and-safeguards.mdx) before collecting data; see the [synthetic example and limits](./synthetic-example.mdx).
|
||||
|
||||
Return to [Skills Measurement](./index.mdx).
|
||||
|
||||
</div>
|
||||
@@ -0,0 +1,36 @@
|
||||
---
|
||||
id: change-lead-time
|
||||
slug: /measurement/change-lead-time
|
||||
title: Change lead time
|
||||
description: Definition, collection evidence and limitations for change lead time.
|
||||
---
|
||||
|
||||
<div className="strategy-content">
|
||||
|
||||
**Target operating model — recommended contracts, not installed collection.** All owner and cadence entries below are proposals to confirm before the pilot, not assigned responsibilities or approved schedules.
|
||||
|
||||
**Unimplemented metric — no live telemetry.** This is a prospective contract, not an implemented calculation or collector.
|
||||
|
||||
{/* contract:start */}
|
||||
Arithmetic mean commit-to-first-successful-production-deployment duration; also publish median/p90 and sample count.
|
||||
|
||||
| Contract | Definition |
|
||||
| --- | --- |
|
||||
| Numerator | Sum of elapsed hours from committed_at to first successful production deployment for each service+commit |
|
||||
| Denominator | Count of eligible service+commit pairs with valid mappings |
|
||||
| Expression | N / D |
|
||||
| Aggregation | mean |
|
||||
| Unit | hours/change |
|
||||
| Eligible population | Changes first successfully deployed to a service in reporting window; rollout retries collapse to same logical deployment. |
|
||||
| Exclusions | Nonproduction, duplicates, no-op deployment with no new commits; missing mappings shown as coverage loss. |
|
||||
| Events and source | change.committed; deployment.completed; VCS immutable commit timestamps and release manifest |
|
||||
| Owner / cadence | Platform & IT / Weekly per service |
|
||||
| Missing evidence | Missing commit mapping or negative/skewed duration excluded from numeric sample, reported explicitly; no zero substitution. |
|
||||
| Gaming and limits | Timestamp rewriting and cherry-picking fast work; lock change mapping and show undeployed backlog age. Descriptive signal, not causal AI productivity attribution. Source completeness, task mix and sampling limit inference; report uncertainty. Not PR cycle time, effort saved, or a complete view of unfinished changes. p90 uses nearest-rank sorted sample. |
|
||||
{/* contract:end */}
|
||||
|
||||
Read the shared [collection and safeguards](./collection-and-safeguards.mdx) before collecting data; see the [synthetic example and limits](./synthetic-example.mdx).
|
||||
|
||||
Return to [Skills Measurement](./index.mdx).
|
||||
|
||||
</div>
|
||||
@@ -0,0 +1,36 @@
|
||||
---
|
||||
id: changes-with-escaped-quality-issues
|
||||
slug: /measurement/changes-with-escaped-quality-issues
|
||||
title: Changes with escaped quality issues
|
||||
description: Definition, collection evidence and limitations for changes with escaped quality issues.
|
||||
---
|
||||
|
||||
<div className="strategy-content">
|
||||
|
||||
**Target operating model — recommended contracts, not installed collection.** All owner and cadence entries below are proposals to confirm before the pilot, not assigned responsibilities or approved schedules.
|
||||
|
||||
**Prototype calculation — no live telemetry.** The synthetic example calculates this metric; it has no network collectors.
|
||||
|
||||
{/* contract:start */}
|
||||
Accepted changes with at least one confirmed post-acceptance defect during approved follow-up, split by severity.
|
||||
|
||||
| Contract | Definition |
|
||||
| --- | --- |
|
||||
| Numerator | Distinct eligible change_ids with one or more linked confirmed defects in follow-up |
|
||||
| Denominator | Accepted change_ids with completed predeclared follow-up horizon |
|
||||
| Expression | N / D * 100 |
|
||||
| Aggregation | percent |
|
||||
| Unit | % |
|
||||
| Eligible population | Accepted changes in acceptance window whose follow-up is complete by as_of. |
|
||||
| Exclusions | Immature changes shown separately; duplicates/unconfirmed reports excluded but counted as pending triage. |
|
||||
| Events and source | change.accepted; defect.confirmed; defect tracking and acceptance evidence |
|
||||
| Owner / cadence | Quality Engineering / Monthly mature cohorts |
|
||||
| Missing evidence | Unknown linkage is a coverage warning; no fabricated clean outcome. Show absolute defect and severe incident counts as well. |
|
||||
| Gaming and limits | Shorten follow-up or downgrade severity; freeze horizon and rubric and independently sample defects. Descriptive signal, not causal AI productivity attribution. Source completeness, task mix and sampling limit inference; report uncertainty. Counts affected changes, not raw defects per change; no presumption defects are AI-caused. |
|
||||
{/* contract:end */}
|
||||
|
||||
Read the shared [collection and safeguards](./collection-and-safeguards.mdx) before collecting data; see the [synthetic example and limits](./synthetic-example.mdx).
|
||||
|
||||
Return to [Skills Measurement](./index.mdx).
|
||||
|
||||
</div>
|
||||
@@ -0,0 +1,44 @@
|
||||
---
|
||||
id: collection-and-safeguards
|
||||
slug: /measurement/collection-and-safeguards
|
||||
title: Collection and safeguards
|
||||
description: Shared interpretation rules, event contracts and privacy safeguards for selected metrics.
|
||||
---
|
||||
|
||||
<div className="strategy-content">
|
||||
|
||||
**Target operating model — recommended contracts, not installed collection.** Registry inclusion does not require use, collection or baselining. All owner and cadence entries are proposals to confirm for selected metrics, not assigned responsibilities or approved schedules.
|
||||
|
||||
{/* preserved:start */}
|
||||
Use these safeguards throughout the [Stage 01 journey](../stage-01-skills-adoption.mdx); these pages do not describe installed controls or measured company results.
|
||||
|
||||
### Decide what counts before counting
|
||||
|
||||
Use the [metric definitions](./index.mdx#metric-definitions) for exact definitions. Every report states its eligible population, observation window, numerator and denominator or distribution sample count, source coverage, exclusions and calculation version. Zero denominators return “not available.” Missing telemetry is unknown, not inactivity, compliance or success. Examples are explicitly synthetic and illustrative.
|
||||
|
||||
Begin with task acceptance, repository, CI, deployment and incident systems because they can independently establish outcomes. Add catalog/version inventory and task-level declarations. Client telemetry is supplementary and version-dependent; enabling rich tool details may collect sensitive commands and identifiers. Do not enable it merely to count skills. A normalized adapter may report approved skill identifiers without forwarding raw arguments.
|
||||
|
||||
Validated success uses all eligible initiated tasks whose predeclared observation window has matured. Failed and abandoned tasks remain nonsuccess. Unresolved or unobserved outcomes remain in the denominator, with known-outcome coverage shown alongside the conservative confirmed-success share. They are not relabeled as observed failure. A task cancelled before start is excluded; cancellation after start remains visible. Count a task once across retries and multiple skills. For timeliness, also show unfinished work and age; accepted-only lead-time distributions have survivorship limitations.
|
||||
|
||||
The registry includes five service-level DORA measures: commit-to-production lead time, deployment frequency, change fail rate, failed deployment recovery time and deployment rework rate. Select them only where applicable; do not substitute PR-open-to-merge time or all-incident MTTR. Where relevant, interpret them alongside selected quality, policy, cost, support, adoption, experience or maintenance evidence. Keep customer/business outcomes linked to their departmental hypotheses; do not infer conversion, trust or revenue improvement from delivery telemetry.
|
||||
|
||||
### Interpretation limits {#baseline-and-interpretation}
|
||||
|
||||
See [Baseline](../baseline.mdx) for selecting relevant metrics and establishing comparable current-practice evidence. Pilot application belongs to [Adoption](../skills-adoption.mdx); ongoing reporting belongs to [Maintenance](../skills-maintenance.mdx).
|
||||
|
||||
Elapsed time and human effort are different quantities. Parallel agents may reduce waiting while increasing review or compute. Include failed attempts and human review/rework in cost, do not multiply a multi-skill task's value across every invocation, and do not convert survey perceptions into proven time savings. Small or incomplete populations yield evidence limits, not an ROI percentage.
|
||||
|
||||
### Event and privacy contract
|
||||
|
||||
Use a versioned event envelope and required fields per event. Source producer plus event ID deduplicates transport retries. Conflicting payloads under the same key are quarantined. Attempts have distinct IDs under one task. Domain IDs deduplicate deployments, defects and approvals even when multiple feeds describe them. Late arrivals produce versioned aggregate corrections; never silently overwrite a published result. Preserve occurrence and receipt times, reject impossible orderings and flag clock skew. Missing terminal events remain unresolved until the work owner reconciles them.
|
||||
|
||||
Many-to-many task/attempt/skill/client associations preserve exact immutable versions. Unknown version stays null with a reason; never assign the latest revision retroactively. Client declarations, server facts and self-reports remain separately labeled. A skill-loaded event is evidence of loading only. The minimal prototype can operate without actor identity except where a lawful, necessary adoption denominator requires pseudonymous cohort membership.
|
||||
|
||||
The privacy starting proposal is 30 days for raw structured analytics events and 12 months for aggregated trends, subject to the responsible owners' review. Keep the approved catalog/approval record for the supported revision's lifetime and its required audit period, which must be decided separately. Incident evidence uses a restricted, explicitly authorized hold and deletion schedule, not an indefinite analytics exception. Suppress reports below five people and prohibit drill-down or overlapping cohort slices that reconstruct identities. Five is a proposed minimum, not a guarantee against re-identification. No raw prompts, code, screens, customer cases or secrets are collected by default. Publish the purpose, lawful collection basis, access/deletion route and retention before collecting. Consent is not presumed to be an appropriate employment-law basis.
|
||||
{/* preserved:end */}
|
||||
|
||||
Return to the [Skills Measurement index](./index.mdx) for every metric definition.
|
||||
|
||||
For the illustrative Delivery comparison, agree sources, permissions and independent acceptance before collection. Carry the population and gap record from [Baseline](../baseline.mdx) into [Adoption](../skills-adoption.mdx). Keep [Quality's qualification trials](../skills-quality.mdx) separate from live workflow starts; revised reports must preserve that boundary.
|
||||
|
||||
</div>
|
||||
@@ -0,0 +1,36 @@
|
||||
---
|
||||
id: confirmed-policy-effects
|
||||
slug: /measurement/confirmed-policy-effects
|
||||
title: Confirmed policy effects
|
||||
description: Definition, collection evidence and limitations for confirmed policy effects.
|
||||
---
|
||||
|
||||
<div className="strategy-content">
|
||||
|
||||
**Target operating model — recommended contracts, not installed collection.** All owner and cadence entries below are proposals to confirm before the pilot, not assigned responsibilities or approved schedules.
|
||||
|
||||
**Prototype calculation — no live telemetry.** The synthetic example calculates this metric; it has no network collectors.
|
||||
|
||||
{/* contract:start */}
|
||||
Eligible evaluated attempts with an actual confirmed prohibited effect; report attempts, blocked attempts and effects separately.
|
||||
|
||||
| Contract | Definition |
|
||||
| --- | --- |
|
||||
| Numerator | Distinct attempt_ids with confirmed prohibited action effect |
|
||||
| Denominator | All evaluated eligible attempt_ids including failed and abandoned runs |
|
||||
| Expression | N / D * 100 |
|
||||
| Aggregation | percent |
|
||||
| Unit | % |
|
||||
| Eligible population | Governed skill trials or supported workflow attempts, reported separately for eval and live populations. |
|
||||
| Exclusions | Out-of-scope runs; detection gaps remain coverage issues, not exclusions from known initiated population. |
|
||||
| Events and source | attempt.started; policy.violation; gate.blocked; security audit and incident triage |
|
||||
| Owner / cadence | Architecture & Security / Immediate incident action; weekly aggregates |
|
||||
| Missing evidence | Unknown outcomes remain visible; zero detected effects never proves safety. Missing audits make rate provisional. |
|
||||
| Gaming and limits | Hide incidents or inflate harmless trials; absolute severity counts and fixed task mix accompany rate. Descriptive signal, not causal AI productivity attribution. Source completeness, task mix and sampling limit inference; report uncertainty. Blocked attempts are not actual effects; any critical effect blocks promotion regardless of aggregate rate. |
|
||||
{/* contract:end */}
|
||||
|
||||
Read the shared [collection and safeguards](./collection-and-safeguards.mdx) before collecting data; see the [synthetic example and limits](./synthetic-example.mdx).
|
||||
|
||||
Return to [Skills Measurement](./index.mdx).
|
||||
|
||||
</div>
|
||||
@@ -0,0 +1,36 @@
|
||||
---
|
||||
id: cost-per-accepted-outcome
|
||||
slug: /measurement/cost-per-accepted-outcome
|
||||
title: Cost per accepted outcome
|
||||
description: Definition, collection evidence and limitations for cost per accepted outcome.
|
||||
---
|
||||
|
||||
<div className="strategy-content">
|
||||
|
||||
**Target operating model — recommended contracts, not installed collection.** All owner and cadence entries below are proposals to confirm before the pilot, not assigned responsibilities or approved schedules.
|
||||
|
||||
**Prototype calculation — no live telemetry.** The synthetic example calculates this metric; it has no network collectors.
|
||||
|
||||
{/* contract:start */}
|
||||
Allocated total workflow cost including unsuccessful attempts, licenses, compute, tooling and human review/rework divided by accepted outcomes.
|
||||
|
||||
| Contract | Definition |
|
||||
| --- | --- |
|
||||
| Numerator | Sum allocated costs in one approved reporting currency for all tasks/attempts in matured start cohort |
|
||||
| Denominator | Distinct independently accepted tasks in same cohort |
|
||||
| Expression | N / D |
|
||||
| Aggregation | ratio |
|
||||
| Unit | currency/accepted outcome |
|
||||
| Eligible population | Matured eligible started-task cohort, with all attempt costs through as_of and allocated shared period costs. |
|
||||
| Exclusions | Unrelated projects and documented taxes/transfers outside chosen accounting basis; never failed/abandoned attempts. |
|
||||
| Events and source | cost.recorded; task.accepted; finance invoices, usage ledger, sampled effort with approved rates |
|
||||
| Owner / cadence | Finance & Accounting Squad / Monthly with late invoice restatement |
|
||||
| Missing evidence | Missing cost buckets produce partial estimate plus coverage, not a total. Mixed currency requires dated approved conversion; zero accepted outcomes = null with full cost shown. |
|
||||
| Gaming and limits | Count tokens only or hide labor/failures; reconcile invoice and allocation totals without double counting. Descriptive signal, not causal AI productivity attribution. Source completeness, task mix and sampling limit inference; report uncertainty. Allocation and sampled labor carry uncertainty; no ROI without independently measured business benefit. |
|
||||
{/* contract:end */}
|
||||
|
||||
Read the shared [collection and safeguards](./collection-and-safeguards.mdx) before collecting data; see the [synthetic example and limits](./synthetic-example.mdx).
|
||||
|
||||
Return to [Skills Measurement](./index.mdx).
|
||||
|
||||
</div>
|
||||
@@ -0,0 +1,36 @@
|
||||
---
|
||||
id: deployment-frequency
|
||||
slug: /measurement/deployment-frequency
|
||||
title: Deployment frequency
|
||||
description: Definition, collection evidence and limitations for deployment frequency.
|
||||
---
|
||||
|
||||
<div className="strategy-content">
|
||||
|
||||
**Target operating model — recommended contracts, not installed collection.** All owner and cadence entries below are proposals to confirm before the pilot, not assigned responsibilities or approved schedules.
|
||||
|
||||
**Unimplemented metric — no live telemetry.** This is a prospective contract, not an implemented calculation or collector.
|
||||
|
||||
{/* contract:start */}
|
||||
Distinct successful logical production deployments per complete service-day of observation.
|
||||
|
||||
| Contract | Definition |
|
||||
| --- | --- |
|
||||
| Numerator | Distinct service_id+deployment_id successful production deployments in window |
|
||||
| Denominator | Observed service-days in window |
|
||||
| Expression | N / D |
|
||||
| Aggregation | ratio |
|
||||
| Unit | deployments/service-day |
|
||||
| Eligible population | Declared production services and complete UTC observation days; report each service before pooled views. |
|
||||
| Exclusions | Test/staging, failed attempts without production effect, duplicate callbacks and retries of the same rollout. |
|
||||
| Events and source | deployment.completed; authoritative deployment service |
|
||||
| Owner / cadence | Platform & IT / Weekly per service |
|
||||
| Missing evidence | Missing feed periods not zero; report coverage and no unqualified overall rate when period incomplete. |
|
||||
| Gaming and limits | Split deployments without value; pair with success, rework and failure measures. Descriptive signal, not causal AI productivity attribution. Source completeness, task mix and sampling limit inference; report uncertainty. More deployments alone do not establish better performance; affected unsuccessful changes remain in change-fail population. |
|
||||
{/* contract:end */}
|
||||
|
||||
Read the shared [collection and safeguards](./collection-and-safeguards.mdx) before collecting data; see the [synthetic example and limits](./synthetic-example.mdx).
|
||||
|
||||
Return to [Skills Measurement](./index.mdx).
|
||||
|
||||
</div>
|
||||
@@ -0,0 +1,36 @@
|
||||
---
|
||||
id: deployment-rework-rate
|
||||
slug: /measurement/deployment-rework-rate
|
||||
title: Deployment rework rate
|
||||
description: Definition, collection evidence and limitations for deployment rework rate.
|
||||
---
|
||||
|
||||
<div className="strategy-content">
|
||||
|
||||
**Target operating model — recommended contracts, not installed collection.** All owner and cadence entries below are proposals to confirm before the pilot, not assigned responsibilities or approved schedules.
|
||||
|
||||
**Prototype calculation — no live telemetry.** The synthetic example calculates this metric; it has no network collectors.
|
||||
|
||||
{/* contract:start */}
|
||||
Unplanned production deployment effects triggered by a production incident as a share of deployment effects.
|
||||
|
||||
| Contract | Definition |
|
||||
| --- | --- |
|
||||
| Numerator | Distinct incident-linked deployment_ids classified unplanned remediation |
|
||||
| Denominator | All distinct production deployment_ids with production effect in window |
|
||||
| Expression | N / D * 100 |
|
||||
| Aggregation | percent |
|
||||
| Unit | % |
|
||||
| Eligible population | Production deployment effects in window with immutable planned/unplanned classification and incident linkage. |
|
||||
| Exclusions | Nonproduction, no-effect retries and duplicates; do not exclude unclassified changes silently. |
|
||||
| Events and source | deployment.completed; incident.linked; release intent classification |
|
||||
| Owner / cadence | Platform & IT / Weekly |
|
||||
| Missing evidence | Unknown classification stays denominator; observed numerator is lower bound until reconciliation; show classification coverage. |
|
||||
| Gaming and limits | Call hotfixes planned; freeze reason and independently reconcile incident/deployment links. Descriptive signal, not causal AI productivity attribution. Source completeness, task mix and sampling limit inference; report uncertainty. Distinct from failure rate: one failed deployment can lead to multiple separate rework deployments. |
|
||||
{/* contract:end */}
|
||||
|
||||
Read the shared [collection and safeguards](./collection-and-safeguards.mdx) before collecting data; see the [synthetic example and limits](./synthetic-example.mdx).
|
||||
|
||||
Return to [Skills Measurement](./index.mdx).
|
||||
|
||||
</div>
|
||||
@@ -0,0 +1,36 @@
|
||||
---
|
||||
id: failed-deployment-recovery-time
|
||||
slug: /measurement/failed-deployment-recovery-time
|
||||
title: Failed deployment recovery time
|
||||
description: Definition, collection evidence and limitations for failed deployment recovery time.
|
||||
---
|
||||
|
||||
<div className="strategy-content">
|
||||
|
||||
**Target operating model — recommended contracts, not installed collection.** All owner and cadence entries below are proposals to confirm before the pilot, not assigned responsibilities or approved schedules.
|
||||
|
||||
**Unimplemented metric — no live telemetry.** This is a prospective contract, not an implemented calculation or collector.
|
||||
|
||||
{/* contract:start */}
|
||||
Mean elapsed time from production deployment failure onset to service restoration, with median/p90 and unresolved count/age.
|
||||
|
||||
| Contract | Definition |
|
||||
| --- | --- |
|
||||
| Numerator | Sum of recovery_at minus failure_started_at in hours for recovered eligible deployment failures |
|
||||
| Denominator | Count of recovered eligible deployment failures with valid timestamps |
|
||||
| Expression | N / D |
|
||||
| Aggregation | mean |
|
||||
| Unit | hours/failure |
|
||||
| Eligible population | Production deployment failures beginning in window; latest verified restoration if a recovery is rescinded. |
|
||||
| Exclusions | Nondeployment incidents; invalid timestamp pairs reported missing, not treated as instantaneous recovery. |
|
||||
| Events and source | deployment.failed; service.restored; incident service |
|
||||
| Owner / cadence | Platform & IT / Weekly with unresolved failures |
|
||||
| Missing evidence | Unresolved failures reported separately and excluded only from recovered-duration distribution; prevent declaring improvement without their visibility. |
|
||||
| Gaming and limits | Premature recovery declarations or omit hard cases; require operational readback and carry unresolved ages. Descriptive signal, not causal AI productivity attribution. Source completeness, task mix and sampling limit inference; report uncertainty. Not all-incident MTTR; recovered-only sample has survivorship bias. p90 nearest rank. |
|
||||
{/* contract:end */}
|
||||
|
||||
Read the shared [collection and safeguards](./collection-and-safeguards.mdx) before collecting data; see the [synthetic example and limits](./synthetic-example.mdx).
|
||||
|
||||
Return to [Skills Measurement](./index.mdx).
|
||||
|
||||
</div>
|
||||
@@ -0,0 +1,81 @@
|
||||
---
|
||||
id: index
|
||||
slug: /measurement
|
||||
title: Skills Measurement
|
||||
sidebar_label: Measurement
|
||||
description: Optional contracts for workflow effectiveness and skills effectiveness and health, with distinct populations and honest implementation limits.
|
||||
pagination_prev: stage-01-skills-adoption
|
||||
pagination_next: baseline
|
||||
hide_table_of_contents: true
|
||||
---
|
||||
|
||||
import ArchifyDiagram from '@site/src/components/ArchifyDiagram';
|
||||
|
||||
<div className="strategy-content">
|
||||
|
||||
Start with how work performs today; compare relevant outcomes after introducing skills. Separately assess whether the skills are effective, supported, used and maintained. Registry inclusion does not require a metric to be used, collected or baselined. More adoption does not prove improved work.
|
||||
|
||||
<ArchifyDiagram name="strategy-measurement" title="Workflow effectiveness / Skills effectiveness & health" story />
|
||||
|
||||
**Target operating model — candidate definitions, not installed telemetry or a collection plan.** Proposed owners and cadences in the contracts apply only if selected and agreed for a workflow.
|
||||
|
||||
## Read a candidate contract
|
||||
|
||||
Each entry explains meaning and applicability, calculation, required inputs and evidence, exclusions, missing-evidence behavior, limitations and implementation status. The two groups below classify every contract by its primary question; conditional reuse never merges populations. A delivery metric need not fit a non-delivery workflow.
|
||||
|
||||
To select a relevant subset and establish actual starting evidence, use [Baseline](../baseline.mdx). Pilot application belongs to [Adoption](../skills-adoption.mdx); ongoing interpretation belongs to [Maintenance](../skills-maintenance.mdx).
|
||||
|
||||
In the **illustrative Delivery workflow** from [Stage 01](../stage-01-skills-adoption.mdx), incomplete regression evidence is the improvement hypothesis. The workflow owner and independent Quality Engineering reviewer select contracts that can test it, then carry the same definitions into the baseline and pilot comparison. They can leave unrelated metrics unselected. This reference capability supports the whole journey; opening this page is not an execution gate.
|
||||
|
||||
## Metric definitions
|
||||
|
||||
Each contract is a prospective definition, not a rollout obligation. No live source or observed baseline is established. N and D refer to the numerator and denominator shown for that metric.
|
||||
|
||||
<details>
|
||||
<summary>Implementation status—not live telemetry</summary>
|
||||
|
||||
There are **16 contracts: 9 prototype calculations and 7 unimplemented metrics**. The prototype has no network collectors. None of these counts establishes live telemetry.
|
||||
|
||||
The nine calculations cover task success, selection precision and recall, change fail rate, deployment rework, escaped quality, policy effects, cost and the primary human-experience item. The seven omissions are supported bundle coverage, approved-workflow adoption, change lead time, deployment frequency, failed deployment recovery time, substantive-review coverage and workflow-specific business acceptance.
|
||||
|
||||
</details>
|
||||
|
||||
### Workflow effectiveness
|
||||
|
||||
**Is the work getting better?** Baseline relevant current-workflow outcomes even before standardized skills exist, then compare the same outcomes during adoption and maintenance. Use comparable task mix, acceptance rules, follow-up periods and source coverage. Before/after trends alone are not causal evidence of a skills benefit.
|
||||
|
||||
1. [Validated task success](./validated-task-success.mdx) — **Prototype calculation.** Independently accepted outcomes among matured workflow starts; failures, abandonment and unresolved outcomes remain in the denominator.
|
||||
2. [Change lead time](./change-lead-time.mdx) — **Unimplemented metric.** Delivery time for production changes in one service, not general task duration.
|
||||
3. [Deployment frequency](./deployment-frequency.mdx) — **Unimplemented metric.** Production delivery frequency for one service; frequency alone is not value.
|
||||
4. [Change fail rate](./change-fail-rate.mdx) — **Prototype calculation.** Production deployments causing failures; requires joined change/incident evidence.
|
||||
5. [Failed deployment recovery time](./failed-deployment-recovery-time.mdx) — **Unimplemented metric.** Recovery from failed production deployments; conditional on eligible incidents.
|
||||
6. [Deployment rework rate](./deployment-rework-rate.mdx) — **Prototype calculation.** Unplanned corrective production deployments, not all forms of task rework.
|
||||
7. [Changes with escaped quality issues](./changes-with-escaped-quality-issues.mdx) — **Prototype calculation.** Accepted changes with confirmed downstream issues after follow-up.
|
||||
8. [Confirmed policy effects](./confirmed-policy-effects.mdx) — **Prototype calculation.** Safety of supported workflow attempts; governed skill trials are a separate evaluation population, never pooled with live work.
|
||||
9. [Cost per accepted outcome](./cost-per-accepted-outcome.mdx) — **Prototype calculation.** Cost of the matured workflow cohort, including unsuccessful attempts and recorded review/rework effort. Missing cost buckets remain partial.
|
||||
10. [Verification confidence and cognitive load](./verification-confidence-and-cognitive-load.mdx) — **Prototype calculation.** Anonymous cohort experience: confidence, workload and usefulness separately, not measured time savings.
|
||||
11. [Workflow-specific business acceptance](./workflow-specific-business-acceptance.mdx) — **Unimplemented metric.** Acceptance against an agreed departmental rubric; requires a defined workflow and independent evidence.
|
||||
|
||||
Human effort is recorded as review/rework inputs where the cost contract supports it; the experience survey describes perception. Neither elapsed delivery time nor token counts establish effort saved. If the current workflow lacks the event semantics required by a contract (for example, governed attempts), record it as not applicable or unavailable with a reason; do not relabel unrelated records to manufacture a baseline.
|
||||
|
||||
### Skills effectiveness & health
|
||||
|
||||
**Are the skills fit for use and kept fit?** Qualify named skills and versions, observe supported use during adoption, and review or retire them in maintenance. Without applicable skills, bundles or enrolled use, skill-specific measures may be **N/A, not zero**. Once a population exists, missing observations are unknown, not evidence of non-use or good health.
|
||||
|
||||
**Fitness comes from [Quality's evaluation evidence](../skills-quality.mdx), not health proxies.** Compare named candidate and approved revisions against declared cases, independent artifact acceptance and mandatory safety checks. Retain regression results, failed trials and coverage limits. The five registry contracts below complement that report: selection tests relevance; support, use and review measures describe operating health. None replaces evidence that a skill produces useful, safe artifacts. Maintenance sends real failures and revision changes back to Quality for requalification.
|
||||
|
||||
1. [Skill selection precision](./skill-selection-precision.mdx) — **Prototype calculation.** Did the evaluated selection choose an applicable skill? Requires labeled qualification cases.
|
||||
2. [Skill selection recall](./skill-selection-recall.mdx) — **Prototype calculation.** Were expected skills selected? Requires the same labeled qualification population.
|
||||
3. [Supported bundle coverage](./supported-bundle-coverage.mdx) — **Unimplemented metric.** Are expected active installations on supported, non-revoked bundles/adapters?
|
||||
4. [Approved-workflow adoption](./approved-workflow-adoption.mdx) — **Unimplemented metric.** Is the enrolled cohort using approved skills in eligible workflows? Installation/loading is not use.
|
||||
5. [Skills within substantive review window](./skills-within-substantive-review-window.mdx) — **Unimplemented metric.** Do active approved revisions have current owners and substantive review evidence?
|
||||
|
||||
**Task-success population matters.** The canonical validated-task-success contract above measures workflow outcomes, not an evaluation benchmark. A named skill/version can be examined as a predeclared live-workflow slice under that same contract, without counting retries or multiple skills as extra tasks or attributing causality. Sandbox/evaluation cases remain excluded: a named skill/version evaluation must be reported separately with its own declared cases, acceptance evidence and limits. It is not an additional implemented calculation or a second conflicting task-success formula. The canonical page explains this boundary. Likewise, keep policy-effect evaluation trials separate from live attempts.
|
||||
|
||||
Use both tracks together to decide whether to improve, retain or retire a skill. Higher selection scores, wider adoption or current reviews cannot substitute for accepted work, safety, cost and human experience.
|
||||
|
||||
Read [Collection and safeguards](./collection-and-safeguards.mdx) for shared interpretation, event and privacy rules. [Run the synthetic measurement example](./synthetic-example.mdx) for reproducible arithmetic and limits.
|
||||
|
||||
**Next:** [Establish a relevant workflow baseline →](../baseline.mdx)
|
||||
|
||||
</div>
|
||||
@@ -0,0 +1,38 @@
|
||||
---
|
||||
id: skill-selection-precision
|
||||
slug: /measurement/skill-selection-precision
|
||||
title: Skill selection precision
|
||||
description: Definition, collection evidence and limitations for skill selection precision.
|
||||
---
|
||||
|
||||
<div className="strategy-content">
|
||||
|
||||
**Target operating model — recommended contracts, not installed collection.** All owner and cadence entries below are proposals to confirm before the pilot, not assigned responsibilities or approved schedules.
|
||||
|
||||
**Prototype calculation — no live telemetry.** The synthetic example calculates this metric; it has no network collectors.
|
||||
|
||||
{/* contract:start */}
|
||||
Correct activations among activations on an independently labeled evaluation corpus.
|
||||
|
||||
| Contract | Definition |
|
||||
| --- | --- |
|
||||
| Numerator | True-positive activations for the requested workflow |
|
||||
| Denominator | True-positive plus false-positive activations |
|
||||
| Expression | N / D * 100 |
|
||||
| Aggregation | percent |
|
||||
| Unit | % |
|
||||
| Eligible population | All candidate/client labeled evaluation task-trials with known activation and relevance. |
|
||||
| Exclusions | Unlabeled/unknown activations excluded with coverage; no cherry-picked failed trials. |
|
||||
| Events and source | eval.selection; versioned labeled corpus and runner |
|
||||
| Owner / cadence | Data & AI / Each skill/client qualification |
|
||||
| Missing evidence | Unknown activation/relevance is unscorable; publish missing count and deny qualification if planned coverage incomplete. |
|
||||
| Gaming and limits | Choose easy labels or hide negative cases; freeze corpus and independently review labels. Descriptive signal, not causal AI productivity attribution. Source completeness, task mix and sampling limit inference; report uncertainty. Does not show execution success; precision depends on corpus prevalence. |
|
||||
{/* contract:end */}
|
||||
|
||||
Read the shared [collection and safeguards](./collection-and-safeguards.mdx) before collecting data; see the [synthetic example and limits](./synthetic-example.mdx).
|
||||
|
||||
Return to [Skills Measurement](./index.mdx).
|
||||
|
||||
Use this labeled-case result in [Quality's candidate evaluation](../skills-quality.mdx). Selecting the right skill is only one input: independently test artifact fitness, safe execution and revision regression before the owning approver considers a bounded pilot. It is not the live Delivery workflow's accepted-task rate.
|
||||
|
||||
</div>
|
||||
@@ -0,0 +1,38 @@
|
||||
---
|
||||
id: skill-selection-recall
|
||||
slug: /measurement/skill-selection-recall
|
||||
title: Skill selection recall
|
||||
description: Definition, collection evidence and limitations for skill selection recall.
|
||||
---
|
||||
|
||||
<div className="strategy-content">
|
||||
|
||||
**Target operating model — recommended contracts, not installed collection.** All owner and cadence entries below are proposals to confirm before the pilot, not assigned responsibilities or approved schedules.
|
||||
|
||||
**Prototype calculation — no live telemetry.** The synthetic example calculates this metric; it has no network collectors.
|
||||
|
||||
{/* contract:start */}
|
||||
Relevant task-trials in which the intended skill activates.
|
||||
|
||||
| Contract | Definition |
|
||||
| --- | --- |
|
||||
| Numerator | True-positive activations |
|
||||
| Denominator | True-positive plus false-negative task-trials |
|
||||
| Expression | N / D * 100 |
|
||||
| Aggregation | percent |
|
||||
| Unit | % |
|
||||
| Eligible population | Independently labeled relevant evaluation task-trials for a skill/client tuple. |
|
||||
| Exclusions | Irrelevant tasks; missing relevance or activation reported as unscorable, not negative. |
|
||||
| Events and source | eval.selection; versioned labeled corpus and runner |
|
||||
| Owner / cadence | Data & AI / Each skill/client qualification |
|
||||
| Missing evidence | Report evaluation coverage; null if no relevant labeled tasks. |
|
||||
| Gaming and limits | Overtrigger to maximize recall; always pair with precision and negative cases. Descriptive signal, not causal AI productivity attribution. Source completeness, task mix and sampling limit inference; report uncertainty. Loading the right skill is not adherence. |
|
||||
{/* contract:end */}
|
||||
|
||||
Read the shared [collection and safeguards](./collection-and-safeguards.mdx) before collecting data; see the [synthetic example and limits](./synthetic-example.mdx).
|
||||
|
||||
Return to [Skills Measurement](./index.mdx).
|
||||
|
||||
Use this labeled-case result alongside precision in [Quality's candidate evaluation](../skills-quality.mdx). Finding expected skills does not establish useful artifacts or safe execution. Preserve missing-case coverage and revision-regression evidence before a bounded pilot; do not pool evaluation cases with live Delivery tasks.
|
||||
|
||||
</div>
|
||||
@@ -0,0 +1,38 @@
|
||||
---
|
||||
id: skills-within-substantive-review-window
|
||||
slug: /measurement/skills-within-substantive-review-window
|
||||
title: Skills within substantive review window
|
||||
description: Definition, collection evidence and limitations for skills within substantive review window.
|
||||
---
|
||||
|
||||
<div className="strategy-content">
|
||||
|
||||
**Target operating model — recommended contracts, not installed collection.** All owner and cadence entries below are proposals to confirm before the pilot, not assigned responsibilities or approved schedules.
|
||||
|
||||
**Unimplemented metric — no live telemetry.** This is a prospective contract, not an implemented calculation or collector.
|
||||
|
||||
{/* contract:start */}
|
||||
Active approved skill revisions with an accountable owner and completed substantive review not past due.
|
||||
|
||||
| Contract | Definition |
|
||||
| --- | --- |
|
||||
| Numerator | Distinct active approved skill revisions with current owner, review evidence and review_due_at >= as_of |
|
||||
| Denominator | All active approved skill revisions in catalog snapshot |
|
||||
| Expression | N / D * 100 |
|
||||
| Aggregation | percent |
|
||||
| Unit | % |
|
||||
| Eligible population | Approved revisions currently supported for use at as_of. |
|
||||
| Exclusions | Experimental and retired revisions; deprecated/revoked in-use counts reported independently, not hidden. |
|
||||
| Events and source | catalog.published; catalog.reviewed; catalog.deprecated; catalog.revoked; version inventory |
|
||||
| Owner / cadence | Data & AI / Monthly and each release |
|
||||
| Missing evidence | Missing owner/date/evidence outside numerator; show ownerless, deprecated-in-use and revoked-in-use absolute counts. |
|
||||
| Gaming and limits | Rubber-stamp review dates; require linked regression/security/usefulness evidence. Descriptive signal, not causal AI productivity attribution. Source completeness, task mix and sampling limit inference; report uncertainty. A current review is not proof of effectiveness; consumer inventory may miss shadow copies. |
|
||||
{/* contract:end */}
|
||||
|
||||
Read the shared [collection and safeguards](./collection-and-safeguards.mdx) before collecting data; see the [synthetic example and limits](./synthetic-example.mdx).
|
||||
|
||||
Return to [Skills Measurement](./index.mdx).
|
||||
|
||||
[Maintenance](../skills-maintenance.mdx) uses this coverage signal to find overdue or ownerless revisions. A current date is not proof of effectiveness: substantive review must consider [Quality's fitness and regression evidence](../skills-quality.mdx), supported-client changes and live-workflow outcomes. Gaps trigger review or requalification, not a favorable health assumption.
|
||||
|
||||
</div>
|
||||
@@ -0,0 +1,36 @@
|
||||
---
|
||||
id: supported-bundle-coverage
|
||||
slug: /measurement/supported-bundle-coverage
|
||||
title: Supported bundle coverage
|
||||
description: Definition, collection evidence and limitations for supported bundle coverage.
|
||||
---
|
||||
|
||||
<div className="strategy-content">
|
||||
|
||||
**Target operating model — recommended contracts, not installed collection.** All owner and cadence entries below are proposals to confirm before the pilot, not assigned responsibilities or approved schedules.
|
||||
|
||||
**Unimplemented metric — no live telemetry.** This is a prospective contract, not an implemented calculation or collector.
|
||||
|
||||
{/* contract:start */}
|
||||
Inventoried active installations with verified effective approved, supported and nonrevoked bundle/adapter tuple.
|
||||
|
||||
| Contract | Definition |
|
||||
| --- | --- |
|
||||
| Numerator | Eligible installation_ids with valid inventory evidence within approved freshness window and matching support matrix |
|
||||
| Denominator | All expected active installation_ids in the managed pilot inventory |
|
||||
| Expression | N / D * 100 |
|
||||
| Aggregation | percent |
|
||||
| Unit | % |
|
||||
| Eligible population | Active installation inventory frozen for report, including invisible/offline entries until authoritative offboarding. |
|
||||
| Exclusions | Verified decommissioned installations and nonpilot assets; lack of telemetry alone never excludes. |
|
||||
| Events and source | inventory.observed; catalog.published; catalog.revoked; device inventory |
|
||||
| Owner / cadence | Platform & IT / Weekly and at revocation |
|
||||
| Missing evidence | Unknown/stale versions count outside numerator, inside denominator. Show inventory discovery coverage versus eligible device roster; if roster unknown metric is provisional. |
|
||||
| Gaming and limits | Remove silent devices or trust declared versions; reconcile managed inventory and separately label attestation trust. Descriptive signal, not causal AI productivity attribution. Source completeness, task mix and sampling limit inference; report uncertainty. Even verified file digests do not prove a private model followed the content. |
|
||||
{/* contract:end */}
|
||||
|
||||
Read the shared [collection and safeguards](./collection-and-safeguards.mdx) before collecting data; see the [synthetic example and limits](./synthetic-example.mdx).
|
||||
|
||||
Return to [Skills Measurement](./index.mdx).
|
||||
|
||||
</div>
|
||||
@@ -0,0 +1,24 @@
|
||||
---
|
||||
id: synthetic-example
|
||||
slug: /measurement/synthetic-example
|
||||
title: Run the synthetic measurement example
|
||||
description: Reproduce the synthetic KPI calculations and understand their limits.
|
||||
---
|
||||
|
||||
<div className="strategy-content">
|
||||
|
||||
**Target operating model — recommended contracts, not installed collection.** All owner and cadence entries below are proposals to confirm before the pilot, not assigned responsibilities or approved schedules.
|
||||
|
||||
{/* preserved:start */}
|
||||
**Executed synthetic example — not Eldorado results.** The bundled fixture produces 1 independently accepted task from 4 matured starts: 25% confirmed success. One unresolved task remains in that denominator; known-outcome coverage is 75%. Selection precision and recall are each 1 / 2 = 50%. Recorded synthetic compute cost is EUR 60 / 1 accepted outcome = EUR 60 per accepted outcome, a partial estimate: licenses, tooling, review and rework are missing. These deliberately small samples demonstrate arithmetic and missingness, not a baseline, target or ROI claim.
|
||||
|
||||
From the private documentation checkout, run `node scripts/ai-kpi.mjs` and `node --test scripts/ai-kpi.test.mjs`. The fixture `scripts/fixtures/ai-kpi-synthetic.json` is labeled synthetic; every result carries the same label and calculation version. This prototype has no network collectors and does not enable employee telemetry.
|
||||
|
||||
The executable covers validated success, selection precision/recall, change fail and rework rates, escaped quality, policy effects, cost and human experience. Other catalog metrics remain contracts rather than implemented collectors; output lists the omissions. Snapshot inputs are simplified, pre-reconciled records, not a production ingestion system. Conflicting duplicates reject the calculation rather than silently choosing a value.
|
||||
{/* preserved:end */}
|
||||
|
||||
Return to the [Skills Measurement index](./index.mdx) for every metric definition.
|
||||
|
||||
Use this fixture to check calculation and missing-evidence behavior before applying selected contracts in [Baseline](../baseline.mdx) or [Adoption](../skills-adoption.mdx). It is not the illustrative Delivery workflow's baseline and does not qualify a skill: [Quality](../skills-quality.mdx) requires independent, versioned artifact and safety evidence on declared evaluation cases.
|
||||
|
||||
</div>
|
||||
@@ -0,0 +1,44 @@
|
||||
---
|
||||
id: validated-task-success
|
||||
slug: /measurement/validated-task-success
|
||||
title: Validated task success
|
||||
description: Definition, collection evidence and limitations for validated task success.
|
||||
---
|
||||
|
||||
<div className="strategy-content">
|
||||
|
||||
**Target operating model — recommended contracts, not installed collection.** All owner and cadence entries below are proposals to confirm before the pilot, not assigned responsibilities or approved schedules.
|
||||
|
||||
**Prototype calculation — no live telemetry.** The synthetic example calculates this metric; it has no network collectors.
|
||||
|
||||
{/* contract:start */}
|
||||
Confirmed independently accepted tasks as a share of all eligible initiated tasks in a matured start cohort; a conservative confirmed-success share, not observed failure rate.
|
||||
|
||||
| Contract | Definition |
|
||||
| --- | --- |
|
||||
| Numerator | Distinct matured task_ids with valid independent task.accepted evidence by as_of |
|
||||
| Denominator | All distinct eligible task_ids started in window with started_at + preregistered task_observation_hours <= as_of |
|
||||
| Expression | N / D * 100 |
|
||||
| Aggregation | percent |
|
||||
| Unit | % |
|
||||
| Eligible population | Tasks in a preregistered workflow cohort, started in window; each counted once across retries, skills and clients. |
|
||||
| Exclusions | Cancelled before start, sandbox/evaluation tasks and out-of-scope workflows; never post-start failures/abandonments. |
|
||||
| Events and source | task.started; task.accepted; task.failed; task.abandoned; task.cancelled; work-management acceptance record |
|
||||
| Owner / cadence | Quality Engineering / Weekly pilot; monthly departmental outcome review |
|
||||
| Missing evidence | Unresolved/missing terminal outcomes remain in denominator with unknown count and known-outcome coverage; do not label them failed. Invalid/missing start excluded from calculation but flagged as orphan evidence. |
|
||||
| Gaming and limits | Split easy tasks or omit starts; reconcile starts to approved backlog and audit acceptance rubrics. Descriptive signal, not causal AI productivity attribution. Source completeness, task mix and sampling limit inference; report uncertainty. Maturation horizon is workflow-specific and must be approved; no automatic abandonment on timeout. |
|
||||
{/* contract:end */}
|
||||
|
||||
## Workflow outcomes versus skill/version evaluation
|
||||
|
||||
This contract belongs to **Workflow effectiveness**. Use the same matured-start population and independent acceptance rules before and after introducing skills; skills are not required for a workflow outcome to exist. Do not narrow the later denominator to successful skill invocations.
|
||||
|
||||
For **Skills effectiveness & health**, a predeclared slice of live workflow tasks using a named skill/version may reuse this contract unchanged. Keep the parent cohort visible, report exact versions and selection limits, and count each task once across retries, skills and clients. Overlapping skill slices must not be summed. This is descriptive evidence, not proof that the skill caused success.
|
||||
|
||||
A sandbox or qualification evaluation of a named skill/version is a different population and remains excluded by this contract. [Quality](../skills-quality.mdx) defines artifact-success and revision-regression evidence: declare cases, skill/version, client/model configuration, acceptance rubric and observed results separately; never combine those cases with live workflow starts or present their results as this prototype's workflow rate. This page does not introduce an implemented skill-evaluation metric or an alternative formula. No applicable skill means that skill-specific evaluation is N/A, not a zero workflow success rate.
|
||||
|
||||
Read the shared [collection and safeguards](./collection-and-safeguards.mdx) before collecting data; see the [synthetic example and limits](./synthetic-example.mdx).
|
||||
|
||||
Return to [Skills Measurement](./index.mdx).
|
||||
|
||||
</div>
|
||||
@@ -0,0 +1,36 @@
|
||||
---
|
||||
id: verification-confidence-and-cognitive-load
|
||||
slug: /measurement/verification-confidence-and-cognitive-load
|
||||
title: Verification confidence and cognitive load
|
||||
description: Definition, collection evidence and limitations for verification confidence and cognitive load.
|
||||
---
|
||||
|
||||
<div className="strategy-content">
|
||||
|
||||
**Target operating model — recommended contracts, not installed collection.** All owner and cadence entries below are proposals to confirm before the pilot, not assigned responsibilities or approved schedules.
|
||||
|
||||
**Prototype calculation — no live telemetry.** The synthetic example calculates this metric; it has no network collectors.
|
||||
|
||||
{/* contract:start */}
|
||||
Three separate anonymous 1–5 item distributions: confidence in verifying output, manageable workload, usefulness. Primary item: verification confidence mean; report full distributions and response rate.
|
||||
|
||||
| Contract | Definition |
|
||||
| --- | --- |
|
||||
| Numerator | Sum valid 1–5 verification-confidence responses, one per participant per survey wave |
|
||||
| Denominator | Count valid responses to that item |
|
||||
| Expression | N / D |
|
||||
| Aggregation | mean |
|
||||
| Unit | points (1–5) |
|
||||
| Eligible population | Invited eligible cohort at fixed survey wave; voluntary responses. |
|
||||
| Exclusions | Invalid/out-of-range answers and superseded duplicate submission; nonresponders stay in response-rate denominator. |
|
||||
| Events and source | survey.response; anonymous survey with single-use token and aggregate invitation count |
|
||||
| Owner / cadence | People & Administration Squad / After pilot workflow cycle; periodic follow-up |
|
||||
| Missing evidence | Report valid response count / invited count and item nonresponse; no imputation. Suppress people cohorts below five. |
|
||||
| Gaming and limits | Pressure to respond positively; no manager access to individual responses, avoid identifying free text. Descriptive signal, not causal AI productivity attribution. Source completeness, task mix and sampling limit inference; report uncertainty. Perception and selection bias; not measured time savings. No composite productivity index. |
|
||||
{/* contract:end */}
|
||||
|
||||
Read the shared [collection and safeguards](./collection-and-safeguards.mdx) before collecting data; see the [synthetic example and limits](./synthetic-example.mdx).
|
||||
|
||||
Return to [Skills Measurement](./index.mdx).
|
||||
|
||||
</div>
|
||||
@@ -0,0 +1,36 @@
|
||||
---
|
||||
id: workflow-specific-business-acceptance
|
||||
slug: /measurement/workflow-specific-business-acceptance
|
||||
title: Workflow-specific business acceptance
|
||||
description: Definition, collection evidence and limitations for workflow-specific business acceptance.
|
||||
---
|
||||
|
||||
<div className="strategy-content">
|
||||
|
||||
**Target operating model — recommended contracts, not installed collection.** All owner and cadence entries below are proposals to confirm before the pilot, not assigned responsibilities or approved schedules.
|
||||
|
||||
**Unimplemented metric — no live telemetry.** This is a prospective contract, not an implemented calculation or collector.
|
||||
|
||||
{/* contract:start */}
|
||||
Independently accepted domain outcomes against a predeclared business rubric, separate from technical completion.
|
||||
|
||||
| Contract | Definition |
|
||||
| --- | --- |
|
||||
| Numerator | Eligible completed-observation task_ids meeting the department-specific outcome rubric |
|
||||
| Denominator | All eligible initiated workflow task_ids with matured business-outcome horizon |
|
||||
| Expression | N / D * 100 |
|
||||
| Aggregation | percent |
|
||||
| Unit | % |
|
||||
| Eligible population | One named departmental workflow and predeclared start cohort; never pool unlike rubrics. |
|
||||
| Exclusions | Cancelled-before-start and unrelated workflows; unsuccessful or abandoned eligible work remains. |
|
||||
| Events and source | task.started; business.accepted; departmental case/content/reconciliation/onboarding review record |
|
||||
| Owner / cadence | Product Management / Each pilot cycle with owning department |
|
||||
| Missing evidence | Unknown follow-up stays denominator with unresolved count; no claim actual business outcome changed without source evidence. |
|
||||
| Gaming and limits | Weaken rubric or count drafts as customer benefit; lock rubric and independently audit acceptance. Descriptive signal, not causal AI productivity attribution. Source completeness, task mix and sampling limit inference; report uncertainty. Domain owner signs acceptance: Operations service accuracy; Marketing claims/rights; Finance reconciliation accuracy; HR policy correctness; Product usability/value. Not revenue uplift. |
|
||||
{/* contract:end */}
|
||||
|
||||
Read the shared [collection and safeguards](./collection-and-safeguards.mdx) before collecting data; see the [synthetic example and limits](./synthetic-example.mdx).
|
||||
|
||||
Return to [Skills Measurement](./index.mdx).
|
||||
|
||||
</div>
|
||||
@@ -1,363 +0,0 @@
|
||||
---
|
||||
id: measurement-contracts
|
||||
title: Skills KPI reference
|
||||
description: Full KPI contracts, minimal events, illustrative calculations, privacy and limits.
|
||||
---
|
||||
|
||||
<div className="strategy-content">
|
||||
|
||||
Return to the [Skills Measurement collection plan](../measurement.mdx).
|
||||
|
||||
**Target operating model — recommended contracts, not installed collection.** All owner and cadence entries below are proposals to confirm before the pilot, not assigned responsibilities or approved schedules.
|
||||
|
||||
There are **16 contracts: 9 prototype calculations and 7 unimplemented metrics**. The prototype has no network collectors. None of these counts establishes live telemetry.
|
||||
|
||||
The nine calculations cover task success, selection precision and recall, change fail rate, deployment rework, escaped quality, policy effects, cost and the primary human-experience item. The seven omissions are supported bundle coverage, approved-workflow adoption, change lead time, deployment frequency, failed deployment recovery time, substantive-review coverage and workflow-specific business acceptance.
|
||||
|
||||
## Collection and safeguards
|
||||
|
||||
Introduction depends on the [roadmap gates](../roadmap.mdx); these pages do not describe installed controls or measured company results.
|
||||
|
||||
### Decide what counts before counting
|
||||
|
||||
Use the metric contracts below for exact definitions. Every report states its eligible population, observation window, numerator and denominator or distribution sample count, source coverage, exclusions and calculation version. Zero denominators return “not available.” Missing telemetry is unknown, not inactivity, compliance or success. Examples are explicitly synthetic and illustrative.
|
||||
|
||||
Begin with task acceptance, repository, CI, deployment and incident systems because they can independently establish outcomes. Add catalog/version inventory and task-level declarations. Client telemetry is supplementary and version-dependent; enabling rich tool details may collect sensitive commands and identifiers. Do not enable it merely to count skills. A normalized adapter may report approved skill identifiers without forwarding raw arguments.
|
||||
|
||||
Validated success uses all eligible initiated tasks whose predeclared observation window has matured. Failed and abandoned tasks remain nonsuccess. Unresolved or unobserved outcomes remain in the denominator, with known-outcome coverage shown alongside the conservative confirmed-success share. They are not relabeled as observed failure. A task cancelled before start is excluded; cancellation after start remains visible. Count a task once across retries and multiple skills. For timeliness, also show unfinished work and age; accepted-only lead-time distributions have survivorship limitations.
|
||||
|
||||
Track all five service-level DORA measures: commit-to-production lead time, deployment frequency, change fail rate, failed deployment recovery time and deployment rework rate. Do not substitute PR-open-to-merge time or all-incident MTTR. Pair them with matured escaped-quality rates, policy effects, total cost per accepted outcome, support coverage, adoption, human experience and catalog maintenance. Keep customer/business outcomes linked to their departmental hypotheses; do not infer conversion, trust or revenue improvement from delivery telemetry.
|
||||
|
||||
### Baseline and interpretation
|
||||
|
||||
Before a pilot, freeze eligibility and acceptance rules and verify event joins. Collect prospective no-skill/current-practice evidence over a complete comparable workflow cycle and until the preregistered precision/sample requirement is met. Do not select a convenient end date after seeing results. Retain task class, service, skill, client/model configuration and concurrent changes. A matched or randomized comparison may be used when practical and ethical; label observational trends as descriptive and report confounding, selection and uncertainty.
|
||||
|
||||
Elapsed time and human effort are different quantities. Parallel agents may reduce waiting while increasing review or compute. Include failed attempts and human review/rework in cost, do not multiply a multi-skill task's value across every invocation, and do not convert survey perceptions into proven time savings. Small or incomplete populations yield evidence limits, not an ROI percentage.
|
||||
|
||||
### Event and privacy contract
|
||||
|
||||
Use a versioned event envelope and required fields per event. Source producer plus event ID deduplicates transport retries. Conflicting payloads under the same key are quarantined. Attempts have distinct IDs under one task. Domain IDs deduplicate deployments, defects and approvals even when multiple feeds describe them. Late arrivals produce versioned aggregate corrections; never silently overwrite a published result. Preserve occurrence and receipt times, reject impossible orderings and flag clock skew. Missing terminal events remain unresolved until the work owner reconciles them.
|
||||
|
||||
Many-to-many task/attempt/skill/client associations preserve exact immutable versions. Unknown version stays null with a reason; never assign the latest revision retroactively. Client declarations, server facts and self-reports remain separately labeled. A skill-loaded event is evidence of loading only. The minimal prototype can operate without actor identity except where a lawful, necessary adoption denominator requires pseudonymous cohort membership.
|
||||
|
||||
The privacy starting proposal is 30 days for raw structured analytics events and 12 months for aggregated trends, subject to the responsible owners' review. Keep the approved catalog/approval record for the supported revision's lifetime and its required audit period, which must be decided separately. Incident evidence uses a restricted, explicitly authorized hold and deletion schedule, not an indefinite analytics exception. Suppress reports below five people and prohibit drill-down or overlapping cohort slices that reconstruct identities. Five is a proposed minimum, not a guarantee against re-identification. No raw prompts, code, screens, customer cases or secrets are collected by default. Publish the purpose, lawful collection basis, access/deletion route and retention before collecting. Consent is not presumed to be an appropriate employment-law basis.
|
||||
|
||||
## Metric contracts
|
||||
|
||||
Each contract is a prospective collection design. No live source or observed baseline is established. N and D refer to the numerator and denominator shown for that metric.
|
||||
|
||||
### Validated task success
|
||||
|
||||
Confirmed independently accepted tasks as a share of all eligible initiated tasks in a matured start cohort; a conservative confirmed-success share, not observed failure rate.
|
||||
|
||||
| Contract | Definition |
|
||||
| --- | --- |
|
||||
| Numerator | Distinct matured task_ids with valid independent task.accepted evidence by as_of |
|
||||
| Denominator | All distinct eligible task_ids started in window with started_at + preregistered task_observation_hours <= as_of |
|
||||
| Expression | N / D * 100 |
|
||||
| Aggregation | percent |
|
||||
| Unit | % |
|
||||
| Eligible population | Tasks in a preregistered workflow cohort, started in window; each counted once across retries, skills and clients. |
|
||||
| Exclusions | Cancelled before start, sandbox/evaluation tasks and out-of-scope workflows; never post-start failures/abandonments. |
|
||||
| Events and source | task.started; task.accepted; task.failed; task.abandoned; task.cancelled; work-management acceptance record |
|
||||
| Owner / cadence | Quality Engineering / Weekly pilot; monthly departmental outcome review |
|
||||
| Missing evidence | Unresolved/missing terminal outcomes remain in denominator with unknown count and known-outcome coverage; do not label them failed. Invalid/missing start excluded from calculation but flagged as orphan evidence. |
|
||||
| Gaming and limits | Split easy tasks or omit starts; reconcile starts to approved backlog and audit acceptance rubrics. Descriptive signal, not causal AI productivity attribution. Source completeness, task mix and sampling limit inference; report uncertainty. Maturation horizon is workflow-specific and must be approved; no automatic abandonment on timeout. |
|
||||
|
||||
|
||||
### Skill selection precision
|
||||
|
||||
Correct activations among activations on an independently labeled evaluation corpus.
|
||||
|
||||
| Contract | Definition |
|
||||
| --- | --- |
|
||||
| Numerator | True-positive activations for the requested workflow |
|
||||
| Denominator | True-positive plus false-positive activations |
|
||||
| Expression | N / D * 100 |
|
||||
| Aggregation | percent |
|
||||
| Unit | % |
|
||||
| Eligible population | All candidate/client labeled evaluation task-trials with known activation and relevance. |
|
||||
| Exclusions | Unlabeled/unknown activations excluded with coverage; no cherry-picked failed trials. |
|
||||
| Events and source | eval.selection; versioned labeled corpus and runner |
|
||||
| Owner / cadence | Data & AI / Each skill/client qualification |
|
||||
| Missing evidence | Unknown activation/relevance is unscorable; publish missing count and deny qualification if planned coverage incomplete. |
|
||||
| Gaming and limits | Choose easy labels or hide negative cases; freeze corpus and independently review labels. Descriptive signal, not causal AI productivity attribution. Source completeness, task mix and sampling limit inference; report uncertainty. Does not show execution success; precision depends on corpus prevalence. |
|
||||
|
||||
|
||||
### Skill selection recall
|
||||
|
||||
Relevant task-trials in which the intended skill activates.
|
||||
|
||||
| Contract | Definition |
|
||||
| --- | --- |
|
||||
| Numerator | True-positive activations |
|
||||
| Denominator | True-positive plus false-negative task-trials |
|
||||
| Expression | N / D * 100 |
|
||||
| Aggregation | percent |
|
||||
| Unit | % |
|
||||
| Eligible population | Independently labeled relevant evaluation task-trials for a skill/client tuple. |
|
||||
| Exclusions | Irrelevant tasks; missing relevance or activation reported as unscorable, not negative. |
|
||||
| Events and source | eval.selection; versioned labeled corpus and runner |
|
||||
| Owner / cadence | Data & AI / Each skill/client qualification |
|
||||
| Missing evidence | Report evaluation coverage; null if no relevant labeled tasks. |
|
||||
| Gaming and limits | Overtrigger to maximize recall; always pair with precision and negative cases. Descriptive signal, not causal AI productivity attribution. Source completeness, task mix and sampling limit inference; report uncertainty. Loading the right skill is not adherence. |
|
||||
|
||||
|
||||
### Supported bundle coverage
|
||||
|
||||
Inventoried active installations with verified effective approved, supported and nonrevoked bundle/adapter tuple.
|
||||
|
||||
| Contract | Definition |
|
||||
| --- | --- |
|
||||
| Numerator | Eligible installation_ids with valid inventory evidence within approved freshness window and matching support matrix |
|
||||
| Denominator | All expected active installation_ids in the managed pilot inventory |
|
||||
| Expression | N / D * 100 |
|
||||
| Aggregation | percent |
|
||||
| Unit | % |
|
||||
| Eligible population | Active installation inventory frozen for report, including invisible/offline entries until authoritative offboarding. |
|
||||
| Exclusions | Verified decommissioned installations and nonpilot assets; lack of telemetry alone never excludes. |
|
||||
| Events and source | inventory.observed; catalog.published; catalog.revoked; device inventory |
|
||||
| Owner / cadence | Platform & IT / Weekly and at revocation |
|
||||
| Missing evidence | Unknown/stale versions count outside numerator, inside denominator. Show inventory discovery coverage versus eligible device roster; if roster unknown metric is provisional. |
|
||||
| Gaming and limits | Remove silent devices or trust declared versions; reconcile managed inventory and separately label attestation trust. Descriptive signal, not causal AI productivity attribution. Source completeness, task mix and sampling limit inference; report uncertainty. Even verified file digests do not prove a private model followed the content. |
|
||||
|
||||
|
||||
### Approved-workflow adoption
|
||||
|
||||
Eligible participants with at least one approved-skill workflow use; usefulness assessed separately through accepted outcomes and feedback.
|
||||
|
||||
| Contract | Definition |
|
||||
| --- | --- |
|
||||
| Numerator | Distinct eligible pseudonymous participants with workflow-linked skill.used on approved revision |
|
||||
| Denominator | Distinct eligible participants in frozen invited cohort |
|
||||
| Expression | N / D * 100 |
|
||||
| Aggregation | percent |
|
||||
| Unit | % |
|
||||
| Eligible population | Consented or otherwise lawfully enrolled pilot cohort for the period; supported workflow available. |
|
||||
| Exclusions | Outside pilot and formally recorded leave before period; nonresponders remain eligible, not excluded. |
|
||||
| Events and source | skill.used; cohort.snapshot; optional qualified client adapter or declaration |
|
||||
| Owner / cadence | Data & AI / Monthly |
|
||||
| Missing evidence | Show observed lower bound and telemetry/response coverage; missing usage unknown rather than non-use. |
|
||||
| Gaming and limits | Invocation quotas and coercion; no target usage count, split server/client/self-report origins. Descriptive signal, not causal AI productivity attribution. Source completeness, task mix and sampling limit inference; report uncertainty. Self-report is not verified use; installation/loading is not use or benefit. Suppress small groups. |
|
||||
|
||||
|
||||
### Change lead time
|
||||
|
||||
Arithmetic mean commit-to-first-successful-production-deployment duration; also publish median/p90 and sample count.
|
||||
|
||||
| Contract | Definition |
|
||||
| --- | --- |
|
||||
| Numerator | Sum of elapsed hours from committed_at to first successful production deployment for each service+commit |
|
||||
| Denominator | Count of eligible service+commit pairs with valid mappings |
|
||||
| Expression | N / D |
|
||||
| Aggregation | mean |
|
||||
| Unit | hours/change |
|
||||
| Eligible population | Changes first successfully deployed to a service in reporting window; rollout retries collapse to same logical deployment. |
|
||||
| Exclusions | Nonproduction, duplicates, no-op deployment with no new commits; missing mappings shown as coverage loss. |
|
||||
| Events and source | change.committed; deployment.completed; VCS immutable commit timestamps and release manifest |
|
||||
| Owner / cadence | Platform & IT / Weekly per service |
|
||||
| Missing evidence | Missing commit mapping or negative/skewed duration excluded from numeric sample, reported explicitly; no zero substitution. |
|
||||
| Gaming and limits | Timestamp rewriting and cherry-picking fast work; lock change mapping and show undeployed backlog age. Descriptive signal, not causal AI productivity attribution. Source completeness, task mix and sampling limit inference; report uncertainty. Not PR cycle time, effort saved, or a complete view of unfinished changes. p90 uses nearest-rank sorted sample. |
|
||||
|
||||
|
||||
### Deployment frequency
|
||||
|
||||
Distinct successful logical production deployments per complete service-day of observation.
|
||||
|
||||
| Contract | Definition |
|
||||
| --- | --- |
|
||||
| Numerator | Distinct service_id+deployment_id successful production deployments in window |
|
||||
| Denominator | Observed service-days in window |
|
||||
| Expression | N / D |
|
||||
| Aggregation | ratio |
|
||||
| Unit | deployments/service-day |
|
||||
| Eligible population | Declared production services and complete UTC observation days; report each service before pooled views. |
|
||||
| Exclusions | Test/staging, failed attempts without production effect, duplicate callbacks and retries of the same rollout. |
|
||||
| Events and source | deployment.completed; authoritative deployment service |
|
||||
| Owner / cadence | Platform & IT / Weekly per service |
|
||||
| Missing evidence | Missing feed periods not zero; report coverage and no unqualified overall rate when period incomplete. |
|
||||
| Gaming and limits | Split deployments without value; pair with success, rework and failure measures. Descriptive signal, not causal AI productivity attribution. Source completeness, task mix and sampling limit inference; report uncertainty. More deployments alone do not establish better performance; affected unsuccessful changes remain in change-fail population. |
|
||||
|
||||
|
||||
### Change fail rate
|
||||
|
||||
Production deployment effects requiring unplanned remediation, rollback or hotfix, not solely outage declarations.
|
||||
|
||||
| Contract | Definition |
|
||||
| --- | --- |
|
||||
| Numerator | Distinct matured production deployment_ids linked to qualifying immediate intervention |
|
||||
| Denominator | All distinct production deployment_ids that reached production in the matured deployment cohort |
|
||||
| Expression | N / D * 100 |
|
||||
| Aggregation | percent |
|
||||
| Unit | % |
|
||||
| Eligible population | Deployments with production effect during window and approved intervention follow-up horizon elapsed. |
|
||||
| Exclusions | Failed preproduction attempts, duplicate callbacks and no-effect retries; failures after production effect stay included. |
|
||||
| Events and source | deployment.completed; deployment.failed; incident.linked; release and incident records |
|
||||
| Owner / cadence | Quality Engineering / Weekly; finalized after horizon |
|
||||
| Missing evidence | Known failures / all eligible deployments is a lower bound where incident linkage incomplete; label provisional and report unknown links. |
|
||||
| Gaming and limits | Avoid incident links or relabel intervention planned; reconcile rollbacks/hotfixes independently. Descriptive signal, not causal AI productivity attribution. Source completeness, task mix and sampling limit inference; report uncertainty. Define immediate intervention and follow-up horizon before pilot; no universal incident-to-AI attribution. |
|
||||
|
||||
|
||||
### Failed deployment recovery time
|
||||
|
||||
Mean elapsed time from production deployment failure onset to service restoration, with median/p90 and unresolved count/age.
|
||||
|
||||
| Contract | Definition |
|
||||
| --- | --- |
|
||||
| Numerator | Sum of recovery_at minus failure_started_at in hours for recovered eligible deployment failures |
|
||||
| Denominator | Count of recovered eligible deployment failures with valid timestamps |
|
||||
| Expression | N / D |
|
||||
| Aggregation | mean |
|
||||
| Unit | hours/failure |
|
||||
| Eligible population | Production deployment failures beginning in window; latest verified restoration if a recovery is rescinded. |
|
||||
| Exclusions | Nondeployment incidents; invalid timestamp pairs reported missing, not treated as instantaneous recovery. |
|
||||
| Events and source | deployment.failed; service.restored; incident service |
|
||||
| Owner / cadence | Platform & IT / Weekly with unresolved failures |
|
||||
| Missing evidence | Unresolved failures reported separately and excluded only from recovered-duration distribution; prevent declaring improvement without their visibility. |
|
||||
| Gaming and limits | Premature recovery declarations or omit hard cases; require operational readback and carry unresolved ages. Descriptive signal, not causal AI productivity attribution. Source completeness, task mix and sampling limit inference; report uncertainty. Not all-incident MTTR; recovered-only sample has survivorship bias. p90 nearest rank. |
|
||||
|
||||
|
||||
### Deployment rework rate
|
||||
|
||||
Unplanned production deployment effects triggered by a production incident as a share of deployment effects.
|
||||
|
||||
| Contract | Definition |
|
||||
| --- | --- |
|
||||
| Numerator | Distinct incident-linked deployment_ids classified unplanned remediation |
|
||||
| Denominator | All distinct production deployment_ids with production effect in window |
|
||||
| Expression | N / D * 100 |
|
||||
| Aggregation | percent |
|
||||
| Unit | % |
|
||||
| Eligible population | Production deployment effects in window with immutable planned/unplanned classification and incident linkage. |
|
||||
| Exclusions | Nonproduction, no-effect retries and duplicates; do not exclude unclassified changes silently. |
|
||||
| Events and source | deployment.completed; incident.linked; release intent classification |
|
||||
| Owner / cadence | Platform & IT / Weekly |
|
||||
| Missing evidence | Unknown classification stays denominator; observed numerator is lower bound until reconciliation; show classification coverage. |
|
||||
| Gaming and limits | Call hotfixes planned; freeze reason and independently reconcile incident/deployment links. Descriptive signal, not causal AI productivity attribution. Source completeness, task mix and sampling limit inference; report uncertainty. Distinct from failure rate: one failed deployment can lead to multiple separate rework deployments. |
|
||||
|
||||
|
||||
### Changes with escaped quality issues
|
||||
|
||||
Accepted changes with at least one confirmed post-acceptance defect during approved follow-up, split by severity.
|
||||
|
||||
| Contract | Definition |
|
||||
| --- | --- |
|
||||
| Numerator | Distinct eligible change_ids with one or more linked confirmed defects in follow-up |
|
||||
| Denominator | Accepted change_ids with completed predeclared follow-up horizon |
|
||||
| Expression | N / D * 100 |
|
||||
| Aggregation | percent |
|
||||
| Unit | % |
|
||||
| Eligible population | Accepted changes in acceptance window whose follow-up is complete by as_of. |
|
||||
| Exclusions | Immature changes shown separately; duplicates/unconfirmed reports excluded but counted as pending triage. |
|
||||
| Events and source | change.accepted; defect.confirmed; defect tracking and acceptance evidence |
|
||||
| Owner / cadence | Quality Engineering / Monthly mature cohorts |
|
||||
| Missing evidence | Unknown linkage is a coverage warning; no fabricated clean outcome. Show absolute defect and severe incident counts as well. |
|
||||
| Gaming and limits | Shorten follow-up or downgrade severity; freeze horizon and rubric and independently sample defects. Descriptive signal, not causal AI productivity attribution. Source completeness, task mix and sampling limit inference; report uncertainty. Counts affected changes, not raw defects per change; no presumption defects are AI-caused. |
|
||||
|
||||
|
||||
### Confirmed policy effects
|
||||
|
||||
Eligible evaluated attempts with an actual confirmed prohibited effect; report attempts, blocked attempts and effects separately.
|
||||
|
||||
| Contract | Definition |
|
||||
| --- | --- |
|
||||
| Numerator | Distinct attempt_ids with confirmed prohibited action effect |
|
||||
| Denominator | All evaluated eligible attempt_ids including failed and abandoned runs |
|
||||
| Expression | N / D * 100 |
|
||||
| Aggregation | percent |
|
||||
| Unit | % |
|
||||
| Eligible population | Governed skill trials or supported workflow attempts, reported separately for eval and live populations. |
|
||||
| Exclusions | Out-of-scope runs; detection gaps remain coverage issues, not exclusions from known initiated population. |
|
||||
| Events and source | attempt.started; policy.violation; gate.blocked; security audit and incident triage |
|
||||
| Owner / cadence | Architecture & Security / Immediate incident action; weekly aggregates |
|
||||
| Missing evidence | Unknown outcomes remain visible; zero detected effects never proves safety. Missing audits make rate provisional. |
|
||||
| Gaming and limits | Hide incidents or inflate harmless trials; absolute severity counts and fixed task mix accompany rate. Descriptive signal, not causal AI productivity attribution. Source completeness, task mix and sampling limit inference; report uncertainty. Blocked attempts are not actual effects; any critical effect blocks promotion regardless of aggregate rate. |
|
||||
|
||||
|
||||
### Cost per accepted outcome
|
||||
|
||||
Allocated total workflow cost including unsuccessful attempts, licenses, compute, tooling and human review/rework divided by accepted outcomes.
|
||||
|
||||
| Contract | Definition |
|
||||
| --- | --- |
|
||||
| Numerator | Sum allocated costs in one approved reporting currency for all tasks/attempts in matured start cohort |
|
||||
| Denominator | Distinct independently accepted tasks in same cohort |
|
||||
| Expression | N / D |
|
||||
| Aggregation | ratio |
|
||||
| Unit | currency/accepted outcome |
|
||||
| Eligible population | Matured eligible started-task cohort, with all attempt costs through as_of and allocated shared period costs. |
|
||||
| Exclusions | Unrelated projects and documented taxes/transfers outside chosen accounting basis; never failed/abandoned attempts. |
|
||||
| Events and source | cost.recorded; task.accepted; finance invoices, usage ledger, sampled effort with approved rates |
|
||||
| Owner / cadence | Finance & Accounting Squad / Monthly with late invoice restatement |
|
||||
| Missing evidence | Missing cost buckets produce partial estimate plus coverage, not a total. Mixed currency requires dated approved conversion; zero accepted outcomes = null with full cost shown. |
|
||||
| Gaming and limits | Count tokens only or hide labor/failures; reconcile invoice and allocation totals without double counting. Descriptive signal, not causal AI productivity attribution. Source completeness, task mix and sampling limit inference; report uncertainty. Allocation and sampled labor carry uncertainty; no ROI without independently measured business benefit. |
|
||||
|
||||
|
||||
### Verification confidence and cognitive load
|
||||
|
||||
Three separate anonymous 1–5 item distributions: confidence in verifying output, manageable workload, usefulness. Primary item: verification confidence mean; report full distributions and response rate.
|
||||
|
||||
| Contract | Definition |
|
||||
| --- | --- |
|
||||
| Numerator | Sum valid 1–5 verification-confidence responses, one per participant per survey wave |
|
||||
| Denominator | Count valid responses to that item |
|
||||
| Expression | N / D |
|
||||
| Aggregation | mean |
|
||||
| Unit | points (1–5) |
|
||||
| Eligible population | Invited eligible cohort at fixed survey wave; voluntary responses. |
|
||||
| Exclusions | Invalid/out-of-range answers and superseded duplicate submission; nonresponders stay in response-rate denominator. |
|
||||
| Events and source | survey.response; anonymous survey with single-use token and aggregate invitation count |
|
||||
| Owner / cadence | People & Administration Squad / After pilot workflow cycle; periodic follow-up |
|
||||
| Missing evidence | Report valid response count / invited count and item nonresponse; no imputation. Suppress people cohorts below five. |
|
||||
| Gaming and limits | Pressure to respond positively; no manager access to individual responses, avoid identifying free text. Descriptive signal, not causal AI productivity attribution. Source completeness, task mix and sampling limit inference; report uncertainty. Perception and selection bias; not measured time savings. No composite productivity index. |
|
||||
|
||||
|
||||
### Skills within substantive review window
|
||||
|
||||
Active approved skill revisions with an accountable owner and completed substantive review not past due.
|
||||
|
||||
| Contract | Definition |
|
||||
| --- | --- |
|
||||
| Numerator | Distinct active approved skill revisions with current owner, review evidence and review_due_at >= as_of |
|
||||
| Denominator | All active approved skill revisions in catalog snapshot |
|
||||
| Expression | N / D * 100 |
|
||||
| Aggregation | percent |
|
||||
| Unit | % |
|
||||
| Eligible population | Approved revisions currently supported for use at as_of. |
|
||||
| Exclusions | Experimental and retired revisions; deprecated/revoked in-use counts reported independently, not hidden. |
|
||||
| Events and source | catalog.published; catalog.reviewed; catalog.deprecated; catalog.revoked; version inventory |
|
||||
| Owner / cadence | Data & AI / Monthly and each release |
|
||||
| Missing evidence | Missing owner/date/evidence outside numerator; show ownerless, deprecated-in-use and revoked-in-use absolute counts. |
|
||||
| Gaming and limits | Rubber-stamp review dates; require linked regression/security/usefulness evidence. Descriptive signal, not causal AI productivity attribution. Source completeness, task mix and sampling limit inference; report uncertainty. A current review is not proof of effectiveness; consumer inventory may miss shadow copies. |
|
||||
|
||||
|
||||
### Workflow-specific business acceptance
|
||||
|
||||
Independently accepted domain outcomes against a predeclared business rubric, separate from technical completion.
|
||||
|
||||
| Contract | Definition |
|
||||
| --- | --- |
|
||||
| Numerator | Eligible completed-observation task_ids meeting the department-specific outcome rubric |
|
||||
| Denominator | All eligible initiated workflow task_ids with matured business-outcome horizon |
|
||||
| Expression | N / D * 100 |
|
||||
| Aggregation | percent |
|
||||
| Unit | % |
|
||||
| Eligible population | One named departmental workflow and predeclared start cohort; never pool unlike rubrics. |
|
||||
| Exclusions | Cancelled-before-start and unrelated workflows; unsuccessful or abandoned eligible work remains. |
|
||||
| Events and source | task.started; business.accepted; departmental case/content/reconciliation/onboarding review record |
|
||||
| Owner / cadence | Product Management / Each pilot cycle with owning department |
|
||||
| Missing evidence | Unknown follow-up stays denominator with unresolved count; no claim actual business outcome changed without source evidence. |
|
||||
| Gaming and limits | Weaken rubric or count drafts as customer benefit; lock rubric and independently audit acceptance. Descriptive signal, not causal AI productivity attribution. Source completeness, task mix and sampling limit inference; report uncertainty. Domain owner signs acceptance: Operations service accuracy; Marketing claims/rights; Finance reconciliation accuracy; HR policy correctness; Product usability/value. Not revenue uplift. |
|
||||
|
||||
|
||||
## Run the synthetic measurement example
|
||||
|
||||
**Executed synthetic example — not Eldorado results.** The bundled fixture produces 1 independently accepted task from 4 matured starts: 25% confirmed success. One unresolved task remains in that denominator; known-outcome coverage is 75%. Selection precision and recall are each 1 / 2 = 50%. Recorded synthetic compute cost is EUR 60 / 1 accepted outcome = EUR 60 per accepted outcome, a partial estimate: licenses, tooling, review and rework are missing. These deliberately small samples demonstrate arithmetic and missingness, not a baseline, target or ROI claim.
|
||||
|
||||
From the private documentation checkout, run `node scripts/ai-kpi.mjs` and `node --test scripts/ai-kpi.test.mjs`. The fixture `scripts/fixtures/ai-kpi-synthetic.json` is labeled synthetic; every result carries the same label and calculation version. This prototype has no network collectors and does not enable employee telemetry.
|
||||
|
||||
The executable covers validated success, selection precision/recall, change fail and rework rates, escaped quality, policy effects, cost and human experience. Other catalog metrics remain contracts rather than implemented collectors; output lists the omissions. Snapshot inputs are simplified, pre-reconciled records, not a production ingestion system. Conflicting duplicates reject the calculation rather than silently choosing a value.
|
||||
|
||||
**Next:** [Use findings to maintain, quarantine or replace skills →](../skills-maintenance.mdx)
|
||||
|
||||
</div>
|
||||
+29
-33
@@ -1,7 +1,7 @@
|
||||
---
|
||||
id: roadmap
|
||||
title: Roadmap
|
||||
description: Assess current code quality and delivery processes, close critical gaps, then pilot, expand and sustain AI adoption.
|
||||
description: Build proven skills in human and AI Agent work, starting with Delivery, as the foundation for the future autonomous SDLC.
|
||||
hide_table_of_contents: true
|
||||
---
|
||||
|
||||
@@ -9,71 +9,67 @@ import ArchifyDiagram from '@site/src/components/ArchifyDiagram';
|
||||
|
||||
<div className="strategy-content">
|
||||
|
||||
Understand today’s code and how work really reaches production before introducing AI into the workflow. Fix what would make a pilot unsafe or impossible to evaluate—not every item of technical debt.
|
||||
## Two stages toward Target
|
||||
|
||||
<ArchifyDiagram name="strategy-roadmap" title="Assess code and delivery, improve readiness, pilot, expand on evidence, then sustain" story />
|
||||
<ArchifyDiagram name="strategy-roadmap" title="Adopt skills → Future Autonomous Agent" story />
|
||||
|
||||
**Recommended sequence · Target operating model, not an approved schedule or deployed governance.**
|
||||
**Humans direct, guide and review throughout.** Stage 1 standardizes skills in human + AI Agent work across the SDLC. Proven skills, measurements and working practices become the foundation for Stage 2: the future Autonomous Agent in [Target](./target-operating-model.mdx).
|
||||
|
||||
## 1. Understand code quality and delivery
|
||||
Target operating model—not deployed autonomy, an agreed schedule or approved KPI thresholds. Stage 1 is useful in its own right; Stage 2 requires a separately justified change in authority, not graduation for using enough skills.
|
||||
|
||||
Inspect representative repositories across important services and change types: tests and CI reliability, maintainability, technical debt and security findings. Trace recent changes through the actual SDLC with the people doing the work—from request to production and feedback. Check ownership, review and release practices, handoffs, rework and bottlenecks; do not assume the documented process is the real one.
|
||||
## Stage 1: Delivery first
|
||||
|
||||
**Output:** baseline findings, a process map and prioritized gaps. Use these to identify a low-risk, repeatable workflow with observable acceptance—not simply the easiest repository.
|
||||
<ArchifyDiagram name="strategy-roadmap-adoption" title="Delivery first → Other SDLC phases, order undecided" story />
|
||||
|
||||
## 2. Fix critical readiness gaps
|
||||
Start with Delivery, then extend skills adoption to the remaining SDLC phases. Their order is not yet decided. **Delivery keeps improving as adoption expands.**
|
||||
|
||||
Resolve gaps that threaten safe execution or a trustworthy comparison: for example, exposed secrets, unclear approval authority or unreliable checks needed to accept the pilot’s changes. Establish accountable people, data boundaries and recovery for the selected scope. Broader refactoring and non-critical debt can run alongside the pilot with a separate improvement backlog.
|
||||
## Improve within each phase
|
||||
|
||||
**Output:** a readiness decision and bounded pilot charter. Proceed only when the critical gaps for that workflow are closed; otherwise narrow the scope or hold.
|
||||
<ArchifyDiagram name="strategy-roadmap-loop" title="Each phase: understand → baseline → topology → use → collect → reassess → repeat" story />
|
||||
|
||||
## 3. Run a bounded pilot
|
||||
Repeat this loop within every phase—not as six global roadmap stages. Skills topology defines **what skills exist, how they relate, when they are used and how they work together**, including handoffs—not just a catalogue.
|
||||
|
||||
Try a small set of reviewed skills in the selected workflow, with human review and no new privileged autonomous actions. Compare equivalent work with the baseline: accepted outcomes, escaped defects, full cost and verification effort. [Skills Measurement](./measurement.mdx) explains what to collect, calculate and report; agree the comparison rules before starting.
|
||||
## Delivery in practice
|
||||
|
||||
**Output:** a pilot report and a continue, adjust or stop decision. Missing evidence is a reason to investigate, not proof of improvement.
|
||||
**Understand the engineering path first:** codebase structure and existing principles → system-logic source → tests → builds and packaging → deployments. Inspect actual practices, tooling, controls and problems with the people doing the work, rather than assuming the documented process is the real one.
|
||||
|
||||
## 4. Expand only on evidence
|
||||
**Establish the comparison, then engineer skills.** Select relevant metrics/KPIs and a baseline for comparable work before changing it. [Measurement](./measurement/index.mdx) supplies optional definitions; [Baseline](./baseline.mdx) records the actual starting position or gaps. Connect skills to the engineering path, with clear triggers, dependencies and acceptance checks; [Quality](./skills-quality.mdx) qualifies the candidate before bounded real use.
|
||||
|
||||
Extend to another workflow or team only when quality, usefulness, cost and support capacity justify it. Prove reliable skill distribution, revocation and recovery before expanding authority. Introduce autonomous SDLC execution progressively under human direction; new departmental workflows need their own data boundaries and acceptance evidence.
|
||||
**Use, collect, compare, repeat.** A human works with an AI Agent on real changes. Collect results, friction and feedback alongside quality, cost and verification effort. Compare with the baseline to understand the new current situation; retain, improve, stop or propose expansion. Changed revisions return to qualification; changed workflows need a fresh comparison.
|
||||
|
||||
**Output:** an evidenced expansion decision with verified controls for the next scope—not organization-wide rollout by default.
|
||||
|
||||
## 5. Sustain and improve
|
||||
|
||||
Review outcomes, drift, incidents and maintenance effort. Retire ineffective skills, revisit process bottlenecks and repeat assessment when repositories, clients, data or authority change. Work toward [Target](./target-operating-model.mdx): an autonomous agent executes and governs the repeating SDLC while humans direct, guide and review.
|
||||
|
||||
**Output:** maintained skills, a refreshed improvement backlog and evidence for the next cycle. Keep human takeover available; narrow or stop workflows when evidence no longer supports them.
|
||||
Follow the **illustrative Delivery workflow** in [Stage 01](./stage-01-skills-adoption.mdx): prepare a bounded code change and regression tests, then hand the exact artifact to independent review. Its dependency diagram shows what passes between activities and who decides whether work can progress. Governance and Measurement support the whole loop; they are not one-time gates.
|
||||
|
||||
<details>
|
||||
<summary>Supporting gate evidence and hold conditions</summary>
|
||||
<summary>Readiness questions behind the roadmap</summary>
|
||||
|
||||
These are recommended implementation gates, not assigned human owners, approved thresholds or installed integrations. Agree acceptance criteria for each selected workflow before evaluating it.
|
||||
These are readiness questions, not additional roadmap stages. Stage 01's topic pages define the recommended decisions and evidence within existing teams. Designate accountable people and agree workflow-specific acceptance criteria before evaluating; this strategy does not appoint approvers or approve thresholds.
|
||||
|
||||
### Assessment → readiness
|
||||
### Understand the current situation
|
||||
|
||||
Retain the sampled repository revisions, test/CI results, debt and security findings, and traced changes behind the process map. Record coverage and unknowns. Distinguish critical pilot blockers from parallel improvements; hold selection if the sample cannot explain how the candidate workflow is delivered and accepted.
|
||||
Sample representative repositories and changes. Retain repository revisions, tests and CI reliability, maintainability, technical debt and security findings. Trace ownership, review and release practices, handoffs, rework and bottlenecks. Keep baseline findings, a process map and prioritized gaps; hold selection if the sample cannot explain how work is delivered and accepted.
|
||||
|
||||
### Readiness → pilot
|
||||
### Prepare safe, measurable human + AI work
|
||||
|
||||
Inventory actual client hosts/builds, provider/data terms, authority and event availability. Confirm accountable people and independent reviewers, forbidden actions, data/retention decisions, recovery and a reproducible baseline. Hold if accountability, lawful collection or critical acceptance checks remain unresolved.
|
||||
|
||||
### Pilot → expansion
|
||||
Close critical gaps such as exposed secrets, unclear approval authority or unreliable acceptance checks. Broader refactoring and non-critical debt can run alongside the selected work. Stage 1 introduces no new privileged autonomous actions.
|
||||
|
||||
### Engineer and evaluate connected skills
|
||||
|
||||
Use a small registry, immutable skill contracts, qualified client adapters, evaluations and coaching. Verify the measurement calculations with synthetic fixtures before interpreting real outcomes. Require mandatory safety checks, independent task acceptance, reconciled source coverage and user feedback. Hold or narrow scope if quality or coverage is inadequate; usage alone does not justify expansion.
|
||||
|
||||
### Expansion → wider authority
|
||||
### Extend adoption without stopping improvement
|
||||
|
||||
Prove canary updates, effective-version readback, version locking, exception expiry, stale/offline handling, rollback and revocation. Hold if effective versions or controls cannot be verified or the catalog cannot be supported.
|
||||
|
||||
For autonomous execution, begin with observation and evidence assembly, then proposing and routing work, before granting scoped execution authority. Recommended controls include exact-artifact approvals, idempotency, duplicate/outage recovery, separation of duties, audit and kill-switch drills. Prove human takeover; never infer permission from missing evidence. The agent ultimately executes and governs the cycle, not only routes tasks.
|
||||
Use evidence to choose the next SDLC phase; no second or third phase is assigned here. Continue the improvement loop in Delivery and every phase already using skills.
|
||||
|
||||
### Sustained operation
|
||||
### Prepare for the future Autonomous Agent
|
||||
|
||||
Operations, Marketing, Finance & Accounting and HR & Administration workflows each need a workflow owner, outcome, data boundary, capacity and domain-specific review; Product and Technology continue quality improvement. Keep sensitive decisions human. Use accepted outcomes, guardrails, total cost and experience to continue, narrow, stop or roll back. Changed client, provider, data or authority boundaries reopen the relevant gates.
|
||||
Stage 2 builds on proven skills, measurements and working practices—not permission inferred from adoption alone. [Stage 02](./stage-02-autonomous-agent.mdx) owns the separate authority/readiness decision. Recommended controls include exact-artifact approvals, idempotency, duplicate/outage recovery, separation of duties, audit and kill-switch drills. Prove human takeover; never infer permission from missing evidence. Keep sensitive decisions human. Changed client, provider, data or authority boundaries reopen the relevant checks.
|
||||
|
||||
</details>
|
||||
|
||||
**Next:** [Return to the strategy destination →](./target-operating-model.mdx)
|
||||
**Next:** [Stage - 01 - Skills Adoption →](./stage-01-skills-adoption.mdx)
|
||||
|
||||
</div>
|
||||
@@ -13,7 +13,7 @@ import ArchifyDiagram from '@site/src/components/ArchifyDiagram';
|
||||
|
||||
## When should a pilot become a team workflow?
|
||||
|
||||
Expand only when a bounded canary produces independently accepted work and useful feedback. Teach people to verify artifacts and recover without AI, not merely invoke a skill.
|
||||
Expand only when a bounded canary produces independently accepted work and useful feedback. Teach people to verify artifacts and recover without AI, not merely invoke a skill. Compare **Workflow effectiveness** with the current-workflow baseline; observe **Skills effectiveness & health** separately as skills enter use. More adoption does not prove improved work, and before/after trends alone are not causal evidence.
|
||||
|
||||
<ArchifyDiagram name="strategy-adoption" title="Choose a workflow, coach a canary, verify outcomes and improve before expansion" story />
|
||||
|
||||
@@ -21,10 +21,23 @@ Expand only when a bounded canary produces independently accepted work and usefu
|
||||
- **Choice within support:** qualify the client path instead of promising identical agent behavior.
|
||||
- **No adoption quotas:** retain a manual path; rejected suggestions and non-use are feedback, not poor performance.
|
||||
|
||||
## Run one bounded comparison, then make a decision
|
||||
|
||||
Bring the [Baseline](./baseline.mdx) comparison record, [Quality](./skills-quality.mdx) qualification report and [Governance](./skills-governance.mdx) pilot authorization—not merely an installed bundle. In the **illustrative Delivery workflow**, the developer and AI Agent prepare a bounded patch and regression tests on the qualified client; an independent reviewer accepts or rejects the exact work. Existing release controls still apply. Record failed and abandoned work as well as accepted changes, and use the manual path if the skill adds risk or effort.
|
||||
|
||||
At the agreed review point, the designated Product Engineering workflow owner considers the comparable outcomes and feedback, Quality Engineering's independent acceptance/quality evidence and any boundary or support findings from Architecture & Security and Platform & IT. These are proposed responsibilities; appoint actual people and agree criteria before the pilot.
|
||||
|
||||
- **Retain:** useful within the tested scope and supported controls; the designated owning approver records exact-revision approval after independent review and required boundary/support checks, then hands that revision and evidence to [Maintenance](./skills-maintenance.mdx). The pilot decision alone is not general approval.
|
||||
- **Improve:** return failure cases and friction to the author and [Quality](./skills-quality.mdx); a changed candidate needs new evidence.
|
||||
- **Expand:** propose a new bounded workflow/cohort, revisit [Baseline](./baseline.mdx) and obtain the relevant approval—not automatic organization-wide rollout.
|
||||
- **Stop or hold:** unsafe behavior triggers containment; insufficient evidence means no benefit claim and no justified expansion. Preserve a manual path.
|
||||
|
||||
The output is a decision record with evidence, scope and remaining uncertainties. Qualification fitness and live outcomes inform it separately; apparent before/after improvement does not establish causality.
|
||||
|
||||
<details>
|
||||
<summary>Onboarding responsibilities, coaching and feedback safeguards</summary>
|
||||
|
||||
**TO-BE · Target operating model.** Introduction depends on the [roadmap gates](./roadmap.mdx); these pages do not describe installed controls or measured company results.
|
||||
**TO-BE · Target operating model.** This bounded comparison belongs to the [Stage 01 journey](./stage-01-skills-adoption.mdx); these pages do not describe installed controls or measured company results.
|
||||
|
||||
Start with a small set of useful workflows chosen by the existing teams. Product Management and the departmental owner identify the outcome; Data & AI helps turn it into a skill; Quality Engineering establishes acceptance; Platform & IT qualifies the client path; Architecture & Security clears the data boundary. People & Administration Squad coordinates learning and accessible feedback.
|
||||
|
||||
@@ -36,6 +49,38 @@ No developer rankings, individual productivity scores, minimum invocation quotas
|
||||
|
||||
</details>
|
||||
|
||||
**Next:** [Measure accepted outcomes, not activity →](./measurement.mdx)
|
||||
<details>
|
||||
<summary>Pilot evidence, illustrative report and expansion</summary>
|
||||
|
||||
## Apply the selected measures in the pilot
|
||||
|
||||
Use the relevant subset agreed in [Baseline](./baseline.mdx), not every entry in the [Measurement registry](./measurement/index.mdx). Keep its eligibility, independent acceptance and follow-up rules. Capture inputs as work happens; record exact skill revision and client configuration, leaving missing versions unknown. Do not reconstruct review effort from elapsed PR time.
|
||||
|
||||
The following questions are candidates, not a mandatory pilot bundle. Proposed owners and cadences need agreement before collection:
|
||||
|
||||
| If this question is selected | Evidence and pilot review |
|
||||
| --- | --- |
|
||||
| Are tasks reaching acceptance? | Join tracker starts to independent acceptance, failure and abandonment. Apply [validated task success](./measurement/validated-task-success.mdx) to matured starts; retain failed, abandoned and unresolved tasks in the denominator and show unknown outcomes and coverage. Proposed weekly reviewer: Quality Engineering. |
|
||||
| Is quality holding up? | Link accepted changes to confirmed defects, severity and follow-up dates; retain PR/CI evidence. Apply [escaped quality](./measurement/changes-with-escaped-quality-issues.mdx) after follow-up, counting each affected change once, alongside severe incidents. Missing links are not clean work. Proposed monthly reviewer: Quality Engineering. |
|
||||
| What does an accepted outcome cost? | Reconcile invoices and usage, sampled review/rework minutes at approved rates, unsuccessful attempts and allocated licenses/tooling. Apply [cost per accepted outcome](./measurement/cost-per-accepted-outcome.mdx) to the same matured start cohort; distinguish effort from waiting. Missing buckets make the estimate partial. Proposed monthly reviewer: Finance & Accounting; restate late invoices. |
|
||||
| Can people confidently verify the work? | Use the anonymous 1–5 survey for confidence, manageable workload and usefulness as separate items. Report the [confidence measure](./measurement/verification-confidence-and-cognitive-load.mdx), distribution and response rate; protect small groups. Proposed reviewer after each pilot cycle: People & Administration. This is enablement evidence, not proven saved time. |
|
||||
|
||||
### What a pilot report looks like
|
||||
|
||||
**Illustrative arithmetic, not company results or targets.** The bundled synthetic fixture shows four matured starts: one accepted, one failed, one abandoned and one unresolved. Confirmed success is **1 / 4 × 100 = 25%**, with **75%** known-outcome coverage. A newer start has not finished its observation period and is shown separately.
|
||||
|
||||
Recorded compute spend is **EUR 60 / 1 = EUR 60** per accepted outcome—a **partial estimate** because licenses, tooling, review and rework are missing. Five survey responses total 20 points: **20 / 5 = 4** out of 5; response rate is **5 / 10 × 100 = 50%**. Reconcile the unknown task and missing costs instead of claiming a skills benefit. Reproduce it with `node scripts/ai-kpi.mjs`; [fixture and limits](./measurement/synthetic-example.mdx).
|
||||
|
||||
### Revisit selection as adoption expands
|
||||
|
||||
Selection precision/recall qualify named skill versions against labeled cases; they do not measure real-workflow acceptance. Keep any skill/version evaluation separate from the live task-success cohort. Skill-specific measures with no applicable population are N/A, not zero; missing evidence for an existing population remains unknown.
|
||||
|
||||
Keep relevant outcome evidence comparable; add reach measures only if they answer the expanded workflow's questions. For [supported bundle coverage](./measurement/supported-bundle-coverage.mdx), freeze the expected active installation inventory and compare observed bundle/adapter revisions to support and revocation records. Offline or stale entries stay in the denominator. Platform & IT is the proposed weekly and at-revocation reviewer.
|
||||
|
||||
For [approved-workflow adoption](./measurement/approved-workflow-adoption.mdx), freeze the lawfully enrolled participant cohort and distinguish qualified-adapter observations from labeled declarations. Report the observed lower bound with source coverage: missing use is unknown; installation and loading are not use. Data & AI is the proposed monthly reviewer. No invocation quotas or employee rankings. Return to Baseline for a new workflow rather than treating rollout as company-wide metric collection.
|
||||
|
||||
</details>
|
||||
|
||||
**Next:** [Maintain skills using the agreed evidence →](./skills-maintenance.mdx)
|
||||
|
||||
</div>
|
||||
@@ -21,10 +21,18 @@ The owning team authors the skill; independent reviewers assess it before exact-
|
||||
- **Pin the whole bundle:** content, adapters and executable dependencies travel together.
|
||||
- **Keep controls authoritative:** exceptions expire and cannot bypass protected release, payment or identity controls.
|
||||
|
||||
## Connect knowledge without expanding authority
|
||||
|
||||
Use the workflow map from [Baseline](./baseline.mdx) to engineer a connected skills topology. In the **illustrative Delivery workflow**, repository understanding produces a source-and-constraints map; change/test preparation consumes it and produces a patch plus regression evidence; independent verification consumes that exact artifact and returns findings. Each handoff specifies its trigger, expected output and what happens when evidence is missing. The agent cannot mark its own work approved or acquire deployment credentials through a skill.
|
||||
|
||||
Governance spans design, qualification, the pilot and maintenance—not just entry to a catalogue. The owning Product Engineering team's designated accountable person records scope and permitted effects; an independent Quality Engineering reviewer accepts [evaluation evidence](./skills-quality.mdx); Architecture & Security reviews higher-risk boundaries; Platform & IT verifies the qualified distribution path. These are recommended assignments within existing teams: name the actual people before relying on a decision.
|
||||
|
||||
**Two different permissions:** qualification may justify a bounded experimental pilot. Wider approved use requires the pilot comparison and canary evidence too. Record exact revisions, audience, expiry/stop conditions and approvers for each; neither a baseline nor a passing test grants permission by itself. Failed review returns the candidate to its author; unsafe use enters [Maintenance containment](./skills-maintenance.mdx).
|
||||
|
||||
<details>
|
||||
<summary>Ownership, client qualification, exceptions and rollback</summary>
|
||||
|
||||
**TO-BE · Target operating model.** Introduction depends on the [roadmap gates](./roadmap.mdx); these pages do not describe installed controls or measured company results.
|
||||
**TO-BE · Target operating model.** Use these contracts throughout the [Stage 01 journey](./stage-01-skills-adoption.mdx); they are not installed controls or measured company results.
|
||||
|
||||
### A contract that travels, controls that stay authoritative
|
||||
|
||||
@@ -36,7 +44,7 @@ Adapters place content in the qualified client's discovery paths and implement o
|
||||
|
||||
### Lifecycle and decision rights
|
||||
|
||||
A proposal names the problem, owner, data scope and testable outcome. Experimental revisions run only in approved disposable environments. Promotion requires independent review, static and executable dependency checks, per-client behavioral evaluations and a bounded canary. Approval records bind the exact artifact and permitted uses. Deprecated revisions carry a migration path and deadline; retired revisions are unavailable for new work. Any active revision can be quarantined immediately.
|
||||
A proposal names the problem, owner, data scope and testable outcome. Initial experimental qualification runs only in approved disposable environments. Real work requires a separate bounded-pilot authorization after qualification; that authorization permits only its recorded cohort, data and effects, not general approved use. Promotion from the bounded pilot requires independent review, static and executable dependency checks, per-client evaluations, pilot outcomes and canary evidence. Approval records bind the exact artifact and permitted uses. Deprecated revisions carry a migration path and deadline; retired revisions are unavailable for new work. Any active revision can be quarantined immediately.
|
||||
|
||||
The author never supplies the only approval. Data & AI maintains catalog state; the owning team is accountable for content; Quality Engineering approves evaluation evidence; Architecture & Security approves higher-risk boundaries; Platform & IT verifies distribution and revocation. A business owner accepts workflow outcomes. These functions can be covered by existing staff, but incompatible author/approver duties must remain separate for the same release.
|
||||
|
||||
@@ -91,7 +99,8 @@ Rollback restores the approved manifest and dependencies, invalidates affected s
|
||||
| Transition | Required evidence |
|
||||
| --- | --- |
|
||||
| proposed → experimental | Owner, purpose, risk/data scope, disposable environment and preregistered test plan |
|
||||
| experimental → approved | Independent review, all mandatory tests, qualified clients, canary, exact-digest approval |
|
||||
| experimental → bounded pilot | Independent qualification evidence, named pilot approver, exact revision, bounded cohort/data/effects and manual recovery; remains experimental outside that envelope |
|
||||
| bounded pilot → approved | Independent review, all mandatory tests, qualified clients, pilot comparison and canary evidence; owning approver records exact-digest authorization for retained scope |
|
||||
| approved → deprecated | Owner gives migration/replacement and retirement conditions |
|
||||
| deprecated → retired | Consumers reconciled or explicit risk-approved cutover; no new invocation |
|
||||
| any active state → quarantined | Incident or unsafe/unknown provenance; central deny immediately |
|
||||
|
||||
@@ -13,7 +13,7 @@ import ArchifyDiagram from '@site/src/components/ArchifyDiagram';
|
||||
|
||||
## What happens when a skill drifts or causes harm?
|
||||
|
||||
Monitor usefulness and safety throughout a revision's life. Unsafe behavior triggers containment; a correction returns through independent tests and approval, never automatic reinstatement.
|
||||
Monitor both **Workflow effectiveness** (comparable outcomes, safety, cost and human experience) and **Skills effectiveness & health** (fitness/regression evidence, selection, supported use and substantive review) throughout a revision's life. Use the evidence to improve, retain or retire skills; adoption or current review dates alone do not prove better work. Unsafe behavior triggers containment; a correction returns through independent tests and approval, never automatic reinstatement.
|
||||
|
||||
<ArchifyDiagram name="strategy-maintenance" title="Monitor, triage and test corrections; promote safely or contain and roll back" story />
|
||||
|
||||
@@ -21,10 +21,18 @@ Monitor usefulness and safety throughout a revision's life. Unsafe behavior trig
|
||||
- **Early triggers:** incidents and client, model or dependency changes override the calendar.
|
||||
- **Recovery is verified:** rollback restores a known-good bundle; it cannot undo disclosure or past effects.
|
||||
|
||||
## Close the loop on the retained workflow
|
||||
|
||||
Start from [Adoption's decision](./skills-adoption.mdx), the approved manifest and its evidence limits. In the **illustrative Delivery workflow**, a missed regression case becomes a sanitized evaluation case. Product Engineering owns the correction; an independent Quality Engineering reviewer reruns [Quality's fitness and regression evaluation](./skills-quality.mdx) against the approved revision. Keep the live defect and task records in their original populations; do not erase a failure because the replacement passes.
|
||||
|
||||
The owning team's designated approver decides whether the corrected exact revision can re-enter a bounded canary, using independent results and Platform & IT's recovery/effective-version evidence; Architecture & Security reviews changed risk boundaries. Missing evidence means hold. Safe unchanged use may continue only within its existing authorization; harmful behavior is contained immediately. These recommended functions require named people before use.
|
||||
|
||||
Retain a supported revision, requalify a change or retire it with a reconciled consumer/migration record. A materially changed workflow returns to [Baseline](./baseline.mdx); the [Measurement registry](./measurement/index.mdx) helps revise relevant evidence without silently resetting history. That feedback closes [Stage 01](./stage-01-skills-adoption.mdx)—it does not automatically advance to autonomy.
|
||||
|
||||
<details>
|
||||
<summary>Review responsibilities, incident handling and proposed review intervals</summary>
|
||||
|
||||
**TO-BE · Target operating model.** Introduction depends on the [roadmap gates](./roadmap.mdx); these pages do not describe installed controls or measured company results.
|
||||
**TO-BE · Target operating model.** Maintenance sustains the [Stage 01 journey](./stage-01-skills-adoption.mdx); these pages do not describe installed controls or measured company results.
|
||||
|
||||
Every approved skill has an accountable owning team, independent reviewer, review due date, supported client matrix and rollback bundle. Review both usefulness and safety, not just metadata freshness. Proposed maximum review intervals are recorded by risk tier; incidents, dependency changes, model/client drift or repeated failures trigger earlier review.
|
||||
|
||||
@@ -44,6 +52,21 @@ Owner ratification is required before adoption. Review earlier after incidents o
|
||||
|
||||
</details>
|
||||
|
||||
**Next:** [Use exit evidence to choose the next rollout stage →](./roadmap.mdx)
|
||||
<details>
|
||||
<summary>Ongoing reporting and comparison</summary>
|
||||
|
||||
## Keep selected evidence useful
|
||||
|
||||
Continue the measures agreed for the workflow in [Baseline](./baseline.mdx) and applied during [Adoption](./skills-adoption.mdx). Revisit relevance when scope changes; the [registry](./measurement/index.mdx) is a source of choices, not a requirement to collect every metric. Preserve current-workflow comparisons separately from named skill/version evaluations. No applicable skill population is N/A, not zero; missing evidence for existing revisions is unknown and must not improve reported health.
|
||||
|
||||
If substantive-review coverage is selected, join each active approved catalog revision to its owner, substantive review evidence and due date. Apply [review coverage](./measurement/skills-within-substantive-review-window.mdx): revisions with all three current / all active approved revisions × 100. The proposed Data & AI review is monthly and at each release, subject to agreement. Report overdue/ownerless revisions and deprecated or revoked versions still in use—not just a percentage.
|
||||
|
||||
At each agreed report, compare like workflows with their recorded starting position. Publish period, counts, exclusions, source coverage and changes in calculation or scope. Zero denominators mean “not available”; unresolved gaps remain visible. Trends are descriptive, not causal ROI. Reconcile late evidence using versioned corrections and distinguish changed practice from changed measurement.
|
||||
|
||||
Act on critical policy effects immediately; do not wait for a reporting cycle. Use selection precision/recall at qualification, or service-level delivery and departmental outcome measures, only where relevant and their source links are feasible. Confirm purpose, lawful basis, access and retention before changing collection, following the [shared safeguards](./measurement/collection-and-safeguards.mdx).
|
||||
|
||||
</details>
|
||||
|
||||
**Continue the loop:** [Requalify changed skills →](./skills-quality.mdx). For a separate future authority decision, read [Stage - 02 - Autonomous Agent](./stage-02-autonomous-agent.mdx).
|
||||
|
||||
</div>
|
||||
@@ -21,10 +21,20 @@ Risk determines the evaluation depth, not whether safety checks apply. Independe
|
||||
- **No averaging away harm:** a critical unauthorized effect blocks promotion.
|
||||
- **Proposed floors need owner ratification:** missing coverage or acceptance rules means qualification is incomplete.
|
||||
|
||||
## Prove the candidate fits the workflow
|
||||
|
||||
Bring the workflow/acceptance map from [Baseline](./baseline.mdx) and the pinned candidate, client tuple and authority envelope from [Governance](./skills-governance.mdx). In the **illustrative Delivery workflow**, test whether a candidate actually produces a correct bounded change and regression tests—not just whether it was selected. Compare candidate, current-approved and no-skill paths on the same starting artifacts. Include misleading repository instructions, missing tests and requests to bypass review.
|
||||
|
||||
The independent Quality Engineering reviewer records accepted and failed artifacts, safety results, coverage and regression differences for each named revision. The owning team's designated approver then decides whether that evidence supports a bounded pilot; Architecture & Security must accept any higher-risk boundary. A mandatory failure or an unagreed acceptance rule means rework or hold. These are proposed decision responsibilities, not already assigned people.
|
||||
|
||||
**Qualification artifact success is not live task success.** The evaluation denominator is planned executed trials, retaining failures and abandonment, with omitted/unexecuted cases shown as coverage gaps. [Validated task success](./measurement/validated-task-success.mdx) instead uses matured real-workflow starts. Never pool them. [Measurement](./measurement/index.mdx) links selection and health signals to this fitness evidence; neither usage nor a fresh review date proves effectiveness.
|
||||
|
||||
The output is a versioned qualification report and explicit limitations for [Adoption](./skills-adoption.mdx), not approval of every future task. [Maintenance](./skills-maintenance.mdx) feeds real failures and material client/model/dependency changes back into this same evaluation, including regression against the currently approved revision.
|
||||
|
||||
<details>
|
||||
<summary>Evaluation design, adversarial cases and interpretation</summary>
|
||||
|
||||
**TO-BE · Target operating model.** Introduction depends on the [roadmap gates](./roadmap.mdx); these pages do not describe installed controls or measured company results.
|
||||
**TO-BE · Target operating model.** Qualification supports the [Stage 01 journey](./stage-01-skills-adoption.mdx); these pages do not describe installed controls or measured company results.
|
||||
|
||||
Quality has four separate questions: was the right skill selected, was the procedure executed safely, did the artifact pass independent checks, and did the workflow produce useful outcomes? A successful invocation answers none of the remaining questions by itself.
|
||||
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
---
|
||||
id: stage-01-skills-adoption
|
||||
title: Stage - 01 - Skills Adoption
|
||||
description: Build proven skills and measurable working practices through human and AI Agent collaboration, starting with Delivery.
|
||||
hide_table_of_contents: true
|
||||
---
|
||||
|
||||
import ArchifyDiagram from '@site/src/components/ArchifyDiagram';
|
||||
|
||||
<div className="strategy-content">
|
||||
|
||||
Improve one workflow through human + AI Agent work, then repeat with evidence. This is the practical first stage of the [Roadmap](./roadmap.mdx), not permission to deploy the autonomous [Target](./target-operating-model.mdx).
|
||||
|
||||
<ArchifyDiagram name="strategy-stage01" title="One workflow: establish the starting point, engineer and qualify, pilot, decide, maintain and learn" story />
|
||||
|
||||
**Read the arrows as handoffs, not a checklist of page approvals.** Governance bounds every activity. Measurement supplies selected definitions throughout. Quality establishes candidate fitness; Adoption tests usefulness in real work; Maintenance returns failures and changed conditions to qualification.
|
||||
|
||||
## Delivery first: one change, from intent to accepted work
|
||||
|
||||
**Illustrative Delivery workflow throughout these pages — not an Eldorado pilot or measured result:** a Product Engineering developer uses an AI Agent to prepare a bounded code change and regression tests. An independent reviewer checks the exact change and evidence. Existing release authority remains unchanged; the skill cannot approve or deploy its own output.
|
||||
|
||||
First trace codebase structure and existing principles → system-logic source → tests → builds and packaging → deployments. Identify the friction to improve—for example, incomplete regression evidence that sends changes back for rework. Verify that this is the actual problem before choosing a skill.
|
||||
|
||||
Adoption can extend to other SDLC phases; their order is not yet decided. Delivery keeps improving as adoption expands.
|
||||
|
||||
## Carry evidence forward, not assumptions
|
||||
|
||||
1. **Understand and baseline.** Product Engineering maps the selected workflow and desired improvement. Select relevant KPIs from [Measurement](./measurement/index.mdx); [Baseline](./baseline.mdx) records current outcomes, acceptance rules and explicit gaps. A baseline describes work; it grants no approval.
|
||||
2. **Engineer a connected candidate.** Under [Governance](./skills-governance.mdx), connect repository understanding → change/test preparation → independent verification. Specify triggers, inputs, outputs, handoffs, pinned dependencies and forbidden actions. This skills topology is more than a catalogue.
|
||||
3. **Qualify before exposing real work.** [Quality](./skills-quality.mdx) compares candidate, current-approved and no-skill paths on declared cases. The independent Quality Engineering reviewer accepts evaluation evidence; the owning team's designated approver authorizes only the tested pilot envelope, with Architecture & Security review where risk requires it. Failed checks or missing authority mean rework or hold, not an automatic pilot.
|
||||
4. **Pilot and compare.** [Adoption](./skills-adoption.mdx) applies that revision to a bounded real-work cohort, retaining the manual path. Compare accepted outcomes, quality, review/rework cost and feedback with the starting position. Live tasks and qualification trials remain separate populations.
|
||||
5. **Decide and maintain.** The owning team's designated workflow owner decides retain, improve, stop or propose expansion from the comparison and independent evidence. [Maintenance](./skills-maintenance.mdx) keeps retained revisions supported and feeds defects into requalification. A new scope returns to Baseline; a changed revision returns to Quality. The new current situation starts the next loop.
|
||||
|
||||
These are recommended responsibilities within existing teams, not appointed people or already approved controls. Before work starts, record the actual accountable person, independent reviewer, acceptance rules and permitted effects. Missing assignments keep the affected decision on hold.
|
||||
|
||||
<details>
|
||||
<summary>Where each topic helps—and what it gives the next activity</summary>
|
||||
|
||||
| Topic | Use it when | Carry forward |
|
||||
| --- | --- | --- |
|
||||
| [Measurement](./measurement/index.mdx) | Choosing or interpreting evidence at any point | Relevant contracts for Workflow effectiveness and Skills effectiveness & health; no mandatory full catalogue |
|
||||
| [Baseline](./baseline.mdx) | Understanding a workflow or a material scope change | Workflow map, selected definitions, evidenced starting position or gaps |
|
||||
| [Governance](./skills-governance.mdx) | Designing, approving, distributing or withdrawing any revision | Named accountability, authority envelope and exact-revision decision record |
|
||||
| [Quality](./skills-quality.mdx) | Introducing or changing skills, clients, models or dependencies | Versioned evaluation results, failures, limits and independent recommendation |
|
||||
| [Adoption](./skills-adoption.mdx) | Introducing a qualified candidate into bounded work | Comparable outcome report, user feedback and retain/improve/expand/stop decision |
|
||||
| [Maintenance](./skills-maintenance.mdx) | Keeping a supported workflow dependable | Reviewed revision, regression cases, recovery evidence or retirement |
|
||||
|
||||
The six topics are connected lifecycle activities, not six rigid sequential approval gates. The sidebar is a reading map: you can consult Measurement before, during or after any activity.
|
||||
|
||||
</details>
|
||||
|
||||
Proven skills and working practices may support [Stage - 02 - Autonomous Agent](./stage-02-autonomous-agent.mdx). Stage 01 can remain valuable indefinitely; progression requires a separate case for authority and readiness.
|
||||
|
||||
**Start here:** [Understand and baseline one workflow →](./baseline.mdx). Consult the [Measurement registry](./measurement/index.mdx) when selecting evidence.
|
||||
|
||||
</div>
|
||||
@@ -0,0 +1,36 @@
|
||||
---
|
||||
id: stage-02-autonomous-agent
|
||||
title: Stage - 02 - Autonomous Agent
|
||||
description: Introduce the future Autonomous Agent on proven skills and measured practices while humans retain direction and review.
|
||||
hide_table_of_contents: true
|
||||
---
|
||||
|
||||
import ArchifyDiagram from '@site/src/components/ArchifyDiagram';
|
||||
|
||||
<div className="strategy-content">
|
||||
|
||||
**A separate authority decision, not the reward for skills adoption.**
|
||||
|
||||
This future stage of the [Roadmap](./roadmap.mdx) builds on [Stage - 01 - Skills Adoption](./stage-01-skills-adoption.mdx). The destination is [Target](./target-operating-model.mdx): an Autonomous Agent that executes and governs the SDLC cycle, with humans retaining direction and review.
|
||||
|
||||
<ArchifyDiagram name="strategy-stage02" title="Future authority: evidence and human decision before bounded execution, with independent stop and takeover" story />
|
||||
|
||||
## Build on what has been proven
|
||||
|
||||
Carry forward proven skills, measurements and working practices from real human + AI Agent work. The skills foundation provides [governance](./skills-governance.mdx), [quality checks](./skills-quality.mdx), [adoption feedback](./skills-adoption.mdx), [measurement](./measurement/index.mdx) and [maintenance](./skills-maintenance.mdx); it is not permission to expand authority automatically.
|
||||
|
||||
## Introduce authority deliberately
|
||||
|
||||
Establish reliable observation and evidence assembly, then proposing and routing work, before granting scoped execution authority. In the **illustrative Delivery workflow**, preparing a patch under human supervision does not authorize the central agent to merge or deploy it. A proposal must explain which extra operation is needed, why Stage 01 is insufficient, the exact resources/data it may touch and how humans can stop it.
|
||||
|
||||
The owning department's designated accountable approver decides the proposed workflow scope, with Architecture & Security accepting the authority/data boundary, Quality Engineering independently assessing behavior and Platform & IT verifying enforcement and recovery. These are recommended functions within existing teams—not appointed approvers or granted permissions. Unresolved release approval roles remain a hold condition; the agent cannot appoint its own authority.
|
||||
|
||||
Require exact-artifact approvals, separated credentials, independent checks, idempotency and duplicate/outage recovery, an auditable task ledger, and a tested stop/human-takeover path outside the model. Sensitive decisions remain human; missing evidence never means permission. A readiness failure returns to [Stage 01](./stage-01-skills-adoption.mdx) or redesign; it does not justify a larger experiment.
|
||||
|
||||
The output is either a recorded hold or a narrowly scoped authorization with conditions and invalidation rules. Monitor outcomes and authority violations separately. A material boundary change reopens the decision; harmful behavior revokes mutation authority and activates takeover, feeding evidence back into [Quality](./skills-quality.mdx) and [Maintenance](./skills-maintenance.mdx).
|
||||
|
||||
This is future direction, not deployed autonomy, agreed delivery dates or approved KPI thresholds. The transition depends on reviewed evidence and explicit authority decisions, not adoption volume alone.
|
||||
|
||||
**Return to dependable work:** [Continue the Stage 01 improvement loop →](./stage-01-skills-adoption.mdx).
|
||||
|
||||
</div>
|
||||
@@ -16,13 +16,15 @@ import ArchifyDiagram from '@site/src/components/ArchifyDiagram';
|
||||
|
||||
<ArchifyDiagram name="strategy-target" title="Autonomous agent executes and governs the SDLC; humans direct, guide and review" story />
|
||||
|
||||
An autonomous agent executes and governs every phase. Humans direct, guide and review it; a separate human-controlled code agent contributes to each phase from outside the cycle.
|
||||
An autonomous agent executes and governs every phase. Humans direct, guide and review it; a separate human-controlled AI Agent contributes to each phase from outside the cycle.
|
||||
|
||||
**Solid arrows:** lifecycle · **Dotted spokes:** execution and governance · **Dashed arrows:** contributions.
|
||||
|
||||
**Scope → Architecture → UI/UX → Planning → Delivery → UAT → Security → Releases → Scope**
|
||||
|
||||
Each stage follows the previous one. Releases returns to Scope; the cycle repeats indefinitely, with human direction informing the next iteration.
|
||||
The arrows show the intended SDLC cycle, not the order of skills rollout. Releases returns evidence to Scope; human direction informs the next iteration. The [Roadmap](./roadmap.mdx) starts with human + AI Agent work in Delivery before considering wider autonomous authority.
|
||||
|
||||
**Illustrative Delivery thread:** an agent prepares a bounded code change and regression evidence, an independent human reviews the exact artifact, and existing release controls decide whether it can advance. Stage 01 makes this working practice dependable; Stage 02 separately considers what the central agent may execute. Skills supply knowledge and verification steps, never permission.
|
||||
|
||||
<details>
|
||||
<summary>Supporting implementation options: trust boundaries and recovery</summary>
|
||||
@@ -39,7 +41,7 @@ The lifecycle above is the strategic direction. The earlier control design below
|
||||
|
||||
<ArchifyDiagram name="ai-adoption-target" title="Supporting control option, not agreed approval policy: isolated release authority" />
|
||||
|
||||
**TO-BE · Target operating model.** Introduction depends on the [roadmap gates](./roadmap.mdx); these pages do not describe installed controls or measured company results.
|
||||
**TO-BE · Target operating model.** The [Roadmap](./roadmap.mdx) separates skills adoption from the future authority decision; these pages do not describe installed controls or measured company results.
|
||||
|
||||
### One coordination function, distributed contributions
|
||||
|
||||
@@ -153,15 +155,18 @@ Success means accepted outcomes with maintained quality, controlled risk and und
|
||||
|
||||
### Navigate the strategy
|
||||
|
||||
- [Roadmap](./roadmap.mdx) — Evidence-gated phases, no promised dates or budgets.
|
||||
- [Roadmap](./roadmap.mdx) — Skills adoption first; future autonomy separately justified, no promised dates or budgets.
|
||||
- [Stage 01](./stage-01-skills-adoption.mdx) — Follow one workflow through evidence, decisions and feedback.
|
||||
- [Baseline](./baseline.mdx) — Understand current work and record the starting position before changing it.
|
||||
- [Skills governance](./skills-governance.mdx) — Contract, lifecycle, decision rights, adapters, locking, exceptions.
|
||||
- [Skills quality](./skills-quality.mdx) — Risk tiers, independent evaluation, repeated trials, adversarial conformance.
|
||||
- [Skills adoption](./skills-adoption.mdx) — Workflow-led coaching, client choice, feedback, manual path.
|
||||
- [Measurement](./measurement.mdx) — Full KPI contracts, minimal events, illustrative calculations, privacy and limits.
|
||||
- [Measurement](./measurement/index.mdx) — Full KPI contracts, minimal events, illustrative calculations, privacy and limits.
|
||||
- [Skills maintenance](./skills-maintenance.mdx) — Review, drift, deprecation, rollback and incident handling.
|
||||
- [Stage 02](./stage-02-autonomous-agent.mdx) — Decide whether bounded autonomous authority is justified and recoverable.
|
||||
|
||||
</details>
|
||||
|
||||
**Next:** [Decide who owns and approves each skill →](./skills-governance.mdx)
|
||||
**Next:** [Follow the Roadmap toward Target →](./roadmap.mdx)
|
||||
|
||||
</div>
|
||||
+1
-1
@@ -15,7 +15,7 @@
|
||||
"verify:build": "node scripts/verify.mjs --build",
|
||||
"diagrams:build": "node scripts/build-diagrams.mjs",
|
||||
"test": "node --test scripts/*.test.mjs",
|
||||
"test:browser": "node scripts/browser/strategy-story.cjs && node scripts/browser/inline-controls.cjs && node scripts/browser/sdlc-cycle.cjs && node scripts/browser/skills-measurement.cjs && node scripts/browser/roadmap.cjs",
|
||||
"test:browser": "node scripts/browser/measurement-pages.cjs && node scripts/browser/sidebar-coverage.cjs && node scripts/browser/skills-stories.cjs && node scripts/browser/strategy-navigation.cjs && node scripts/browser/strategy-story.cjs && node scripts/browser/inline-controls.cjs && node scripts/browser/sdlc-cycle.cjs && node scripts/browser/target-midpoints.cjs && node scripts/browser/skills-measurement.cjs && node scripts/browser/roadmap.cjs && node scripts/browser/roadmap-timeline.cjs",
|
||||
"kpi:example": "node scripts/ai-kpi.mjs"
|
||||
},
|
||||
"dependencies": {
|
||||
|
||||
@@ -0,0 +1,162 @@
|
||||
{
|
||||
"sourceCommit": "b9c2047c614dd4e825fa746815104d35d9500739",
|
||||
"sourcePath": "docs/strategy/reference/measurement-contracts.mdx",
|
||||
"metrics": [
|
||||
{
|
||||
"oldAnchor": "validated-task-success",
|
||||
"title": "Validated task success",
|
||||
"docId": "measurement/validated-task-success",
|
||||
"url": "/strategy/measurement/validated-task-success/",
|
||||
"calculationId": "validated-task-success",
|
||||
"status": "prototype",
|
||||
"contractSha256": "925100f4c84f43e2cfdca4a89d6b4a984c808dae2d2ec5e57202318f70b9c544"
|
||||
},
|
||||
{
|
||||
"oldAnchor": "skill-selection-precision",
|
||||
"title": "Skill selection precision",
|
||||
"docId": "measurement/skill-selection-precision",
|
||||
"url": "/strategy/measurement/skill-selection-precision/",
|
||||
"calculationId": "selection-precision",
|
||||
"status": "prototype",
|
||||
"contractSha256": "189e93e4e5f52a7e70e2045c6b824a9da621382f39ba8ce9a59c0c04812f0ce3"
|
||||
},
|
||||
{
|
||||
"oldAnchor": "skill-selection-recall",
|
||||
"title": "Skill selection recall",
|
||||
"docId": "measurement/skill-selection-recall",
|
||||
"url": "/strategy/measurement/skill-selection-recall/",
|
||||
"calculationId": "selection-recall",
|
||||
"status": "prototype",
|
||||
"contractSha256": "847b5ba6094585eb88b8eb2b55b42e0f3c6822dcaa1629256ad0501a13eb7f18"
|
||||
},
|
||||
{
|
||||
"oldAnchor": "supported-bundle-coverage",
|
||||
"title": "Supported bundle coverage",
|
||||
"docId": "measurement/supported-bundle-coverage",
|
||||
"url": "/strategy/measurement/supported-bundle-coverage/",
|
||||
"calculationId": "supported-bundle-coverage",
|
||||
"status": "unimplemented",
|
||||
"contractSha256": "8b4dc2dbdfb6999fac283814f518645d0830d515125910d79dd7dc8763f0521c"
|
||||
},
|
||||
{
|
||||
"oldAnchor": "approved-workflow-adoption",
|
||||
"title": "Approved-workflow adoption",
|
||||
"docId": "measurement/approved-workflow-adoption",
|
||||
"url": "/strategy/measurement/approved-workflow-adoption/",
|
||||
"calculationId": "useful-adoption",
|
||||
"status": "unimplemented",
|
||||
"contractSha256": "355996d5adb603021ba22f9e1f7f08f2fbea017dac9ee0a4bd42cc00bf7adea3"
|
||||
},
|
||||
{
|
||||
"oldAnchor": "change-lead-time",
|
||||
"title": "Change lead time",
|
||||
"docId": "measurement/change-lead-time",
|
||||
"url": "/strategy/measurement/change-lead-time/",
|
||||
"calculationId": "change-lead-time",
|
||||
"status": "unimplemented",
|
||||
"contractSha256": "96fd0edd5eba139a7c5905b606bcc96e608c5294acd2ef0c962fdb7d339d8251"
|
||||
},
|
||||
{
|
||||
"oldAnchor": "deployment-frequency",
|
||||
"title": "Deployment frequency",
|
||||
"docId": "measurement/deployment-frequency",
|
||||
"url": "/strategy/measurement/deployment-frequency/",
|
||||
"calculationId": "deployment-frequency",
|
||||
"status": "unimplemented",
|
||||
"contractSha256": "5a34ba52e5c2768e29a1a7574274e07a65509f75063e89ccc7ce1b035aeff4c5"
|
||||
},
|
||||
{
|
||||
"oldAnchor": "change-fail-rate",
|
||||
"title": "Change fail rate",
|
||||
"docId": "measurement/change-fail-rate",
|
||||
"url": "/strategy/measurement/change-fail-rate/",
|
||||
"calculationId": "change-fail-rate",
|
||||
"status": "prototype",
|
||||
"contractSha256": "d2a4ecaddd468f42db5824f9bfab8a8c8fcdf9157b33b4e4f047269a83c8567b"
|
||||
},
|
||||
{
|
||||
"oldAnchor": "failed-deployment-recovery-time",
|
||||
"title": "Failed deployment recovery time",
|
||||
"docId": "measurement/failed-deployment-recovery-time",
|
||||
"url": "/strategy/measurement/failed-deployment-recovery-time/",
|
||||
"calculationId": "failed-deployment-recovery-time",
|
||||
"status": "unimplemented",
|
||||
"contractSha256": "489fd756883d4ccee1769fcfaa0b67725420463df2b1f6faf3e7faa7002f7a80"
|
||||
},
|
||||
{
|
||||
"oldAnchor": "deployment-rework-rate",
|
||||
"title": "Deployment rework rate",
|
||||
"docId": "measurement/deployment-rework-rate",
|
||||
"url": "/strategy/measurement/deployment-rework-rate/",
|
||||
"calculationId": "deployment-rework-rate",
|
||||
"status": "prototype",
|
||||
"contractSha256": "e8ade457136feac3ad39e9eba2a9d67142bc605727d9f4f038a7df6d5a0707fd"
|
||||
},
|
||||
{
|
||||
"oldAnchor": "changes-with-escaped-quality-issues",
|
||||
"title": "Changes with escaped quality issues",
|
||||
"docId": "measurement/changes-with-escaped-quality-issues",
|
||||
"url": "/strategy/measurement/changes-with-escaped-quality-issues/",
|
||||
"calculationId": "escaped-quality-rate",
|
||||
"status": "prototype",
|
||||
"contractSha256": "c436d504c8b3a9f655de18b2ca00fa8a0ab47ea1cf37637ff21561f81ecc77c9"
|
||||
},
|
||||
{
|
||||
"oldAnchor": "confirmed-policy-effects",
|
||||
"title": "Confirmed policy effects",
|
||||
"docId": "measurement/confirmed-policy-effects",
|
||||
"url": "/strategy/measurement/confirmed-policy-effects/",
|
||||
"calculationId": "policy-effects",
|
||||
"status": "prototype",
|
||||
"contractSha256": "b64c02f5516b08421fa8b816f0f490571afd05baf5ad6e9d92cb6a7b711ac82a"
|
||||
},
|
||||
{
|
||||
"oldAnchor": "cost-per-accepted-outcome",
|
||||
"title": "Cost per accepted outcome",
|
||||
"docId": "measurement/cost-per-accepted-outcome",
|
||||
"url": "/strategy/measurement/cost-per-accepted-outcome/",
|
||||
"calculationId": "cost-per-accepted-outcome",
|
||||
"status": "prototype",
|
||||
"contractSha256": "d8865ec31315d3c8398ec58cdb6665cb506a7d6309ebec3da0ca7dea84a5f406"
|
||||
},
|
||||
{
|
||||
"oldAnchor": "verification-confidence-and-cognitive-load",
|
||||
"title": "Verification confidence and cognitive load",
|
||||
"docId": "measurement/verification-confidence-and-cognitive-load",
|
||||
"url": "/strategy/measurement/verification-confidence-and-cognitive-load/",
|
||||
"calculationId": "human-experience",
|
||||
"status": "prototype",
|
||||
"contractSha256": "01e017471004c5f780fd0c2671a4d4449d392956cb4c5f0bd7791959d6a9af9a"
|
||||
},
|
||||
{
|
||||
"oldAnchor": "skills-within-substantive-review-window",
|
||||
"title": "Skills within substantive review window",
|
||||
"docId": "measurement/skills-within-substantive-review-window",
|
||||
"url": "/strategy/measurement/skills-within-substantive-review-window/",
|
||||
"calculationId": "maintenance-health",
|
||||
"status": "unimplemented",
|
||||
"contractSha256": "339fe0da6b382a34c52b5ec6005ce08a7293a2b07ccd88540a6df03a02d96ad4"
|
||||
},
|
||||
{
|
||||
"oldAnchor": "workflow-specific-business-acceptance",
|
||||
"title": "Workflow-specific business acceptance",
|
||||
"docId": "measurement/workflow-specific-business-acceptance",
|
||||
"url": "/strategy/measurement/workflow-specific-business-acceptance/",
|
||||
"calculationId": "department-outcome",
|
||||
"status": "unimplemented",
|
||||
"contractSha256": "55fce8843409a1bc1383fef3cee5b9a616b44fa8d45ba84c6e4ed490a25f2de4"
|
||||
}
|
||||
],
|
||||
"shared": [
|
||||
{
|
||||
"slug": "collection-and-safeguards",
|
||||
"sha256": "37709cf9978a698026492b29f2095996c462e098a74f082a6b3c3a3a7b38ecab",
|
||||
"previousSha256": "8610ed8df6a24cf138f9e6e2c09060db2aab4c0b1259ca0168e581e3fb964e52",
|
||||
"revisionNote": "Stage 01 separation: baseline establishment moved to baseline.mdx; DORA candidates are optional. Event/privacy and outcome safeguards retained."
|
||||
},
|
||||
{
|
||||
"slug": "synthetic-example",
|
||||
"sha256": "24af68ff4fd61159d1c0557ed0f8f8462470d56c6c83816eb93b47fb04149fde"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,317 @@
|
||||
{
|
||||
"purpose": "Route-level editorial and verification contract for connected Strategy; no deployed-result claims",
|
||||
"routes": [
|
||||
{
|
||||
"source": "docs/strategy/baseline.mdx",
|
||||
"route": "/strategy/baseline/",
|
||||
"question": "What is the actual starting position of this workflow?",
|
||||
"inputs": "Current-practice map, desired improvement and candidate contracts",
|
||||
"action_or_decision": "Select feasible relevant evidence; confirm eligibility and gaps",
|
||||
"output": "Traceable comparison record, not approval",
|
||||
"next_or_feedback": "/strategy/skills-governance/",
|
||||
"review": "Illustrative Delivery evidence handoff and return paths"
|
||||
},
|
||||
{
|
||||
"source": "docs/strategy/measurement/approved-workflow-adoption.mdx",
|
||||
"route": "/strategy/measurement/approved-workflow-adoption/",
|
||||
"question": "Is the enrolled cohort using approved revisions in eligible work?",
|
||||
"inputs": "skill.used; cohort.snapshot; optional qualified client adapter or declaration",
|
||||
"action_or_decision": "Apply only if selected; preserve Consented or otherwise lawfully enrolled pilot cohort for the period; supported workflow available.",
|
||||
"output": "percent; Show observed lower bound and telemetry/response coverage; missing usage unknown rather than non-use.",
|
||||
"next_or_feedback": "/strategy/skills-adoption/",
|
||||
"review": "Canonical contract and URL preserved; populations, exclusions, missingness and crosslinks reviewed",
|
||||
"contract_sha256": "355996d5adb603021ba22f9e1f7f08f2fbea017dac9ee0a4bd42cc00bf7adea3",
|
||||
"implementation": "unimplemented"
|
||||
},
|
||||
{
|
||||
"source": "docs/strategy/measurement/change-fail-rate.mdx",
|
||||
"route": "/strategy/measurement/change-fail-rate/",
|
||||
"question": "How often do production deployments require immediate intervention?",
|
||||
"inputs": "deployment.completed; deployment.failed; incident.linked; release and incident records",
|
||||
"action_or_decision": "Apply only if selected; preserve Deployments with production effect during window and approved intervention follow-up horizon elapsed.",
|
||||
"output": "percent; Known failures / all eligible deployments is a lower bound where incident linkage incomplete; label provisional and report unknown links.",
|
||||
"next_or_feedback": "/strategy/skills-adoption/",
|
||||
"review": "Canonical contract and URL preserved; populations, exclusions, missingness and crosslinks reviewed",
|
||||
"contract_sha256": "d2a4ecaddd468f42db5824f9bfab8a8c8fcdf9157b33b4e4f047269a83c8567b",
|
||||
"implementation": "prototype"
|
||||
},
|
||||
{
|
||||
"source": "docs/strategy/measurement/change-lead-time.mdx",
|
||||
"route": "/strategy/measurement/change-lead-time/",
|
||||
"question": "How long does a service change take from commit to production?",
|
||||
"inputs": "change.committed; deployment.completed; VCS immutable commit timestamps and release manifest",
|
||||
"action_or_decision": "Apply only if selected; preserve Changes first successfully deployed to a service in reporting window; rollout retries collapse to same logical deployment.",
|
||||
"output": "mean; Missing commit mapping or negative/skewed duration excluded from numeric sample, reported explicitly; no zero substitution.",
|
||||
"next_or_feedback": "/strategy/skills-adoption/",
|
||||
"review": "Canonical contract and URL preserved; populations, exclusions, missingness and crosslinks reviewed",
|
||||
"contract_sha256": "96fd0edd5eba139a7c5905b606bcc96e608c5294acd2ef0c962fdb7d339d8251",
|
||||
"implementation": "unimplemented"
|
||||
},
|
||||
{
|
||||
"source": "docs/strategy/measurement/changes-with-escaped-quality-issues.mdx",
|
||||
"route": "/strategy/measurement/changes-with-escaped-quality-issues/",
|
||||
"question": "Which accepted changes have confirmed downstream defects?",
|
||||
"inputs": "change.accepted; defect.confirmed; defect tracking and acceptance evidence",
|
||||
"action_or_decision": "Apply only if selected; preserve Accepted changes in acceptance window whose follow-up is complete by as_of.",
|
||||
"output": "percent; Unknown linkage is a coverage warning; no fabricated clean outcome. Show absolute defect and severe incident counts as well.",
|
||||
"next_or_feedback": "/strategy/skills-adoption/",
|
||||
"review": "Canonical contract and URL preserved; populations, exclusions, missingness and crosslinks reviewed",
|
||||
"contract_sha256": "c436d504c8b3a9f655de18b2ca00fa8a0ab47ea1cf37637ff21561f81ecc77c9",
|
||||
"implementation": "prototype"
|
||||
},
|
||||
{
|
||||
"source": "docs/strategy/measurement/collection-and-safeguards.mdx",
|
||||
"route": "/strategy/measurement/collection-and-safeguards/",
|
||||
"question": "How can I collect and interpret selected evidence safely?",
|
||||
"inputs": "Selected contracts, source inventory and approved collection purpose",
|
||||
"action_or_decision": "Agree populations, deduplication, permissions and retention before collection",
|
||||
"output": "Traceable lawful collection and interpretation contract",
|
||||
"next_or_feedback": "/strategy/baseline/",
|
||||
"review": "Linked to full journey; obsolete roadmap-gates link replaced only in safeguards; preserved arithmetic/privacy substance"
|
||||
},
|
||||
{
|
||||
"source": "docs/strategy/measurement/confirmed-policy-effects.mdx",
|
||||
"route": "/strategy/measurement/confirmed-policy-effects/",
|
||||
"question": "Did eligible attempts produce prohibited effects?",
|
||||
"inputs": "attempt.started; policy.violation; gate.blocked; security audit and incident triage",
|
||||
"action_or_decision": "Apply only if selected; preserve Governed skill trials or supported workflow attempts, reported separately for eval and live populations.",
|
||||
"output": "percent; Unknown outcomes remain visible; zero detected effects never proves safety. Missing audits make rate provisional.",
|
||||
"next_or_feedback": "/strategy/skills-adoption/",
|
||||
"review": "Canonical contract and URL preserved; populations, exclusions, missingness and crosslinks reviewed",
|
||||
"contract_sha256": "b64c02f5516b08421fa8b816f0f490571afd05baf5ad6e9d92cb6a7b711ac82a",
|
||||
"implementation": "prototype"
|
||||
},
|
||||
{
|
||||
"source": "docs/strategy/measurement/cost-per-accepted-outcome.mdx",
|
||||
"route": "/strategy/measurement/cost-per-accepted-outcome/",
|
||||
"question": "What recorded total or partial cost supports each accepted outcome?",
|
||||
"inputs": "cost.recorded; task.accepted; finance invoices, usage ledger, sampled effort with approved rates",
|
||||
"action_or_decision": "Apply only if selected; preserve Matured eligible started-task cohort, with all attempt costs through as_of and allocated shared period costs.",
|
||||
"output": "ratio; Missing cost buckets produce partial estimate plus coverage, not a total. Mixed currency requires dated approved conversion; zero accepted outcomes = null with full cost shown.",
|
||||
"next_or_feedback": "/strategy/skills-adoption/",
|
||||
"review": "Canonical contract and URL preserved; populations, exclusions, missingness and crosslinks reviewed",
|
||||
"contract_sha256": "d8865ec31315d3c8398ec58cdb6665cb506a7d6309ebec3da0ca7dea84a5f406",
|
||||
"implementation": "prototype"
|
||||
},
|
||||
{
|
||||
"source": "docs/strategy/measurement/deployment-frequency.mdx",
|
||||
"route": "/strategy/measurement/deployment-frequency/",
|
||||
"question": "How frequently does this service deploy successfully?",
|
||||
"inputs": "deployment.completed; authoritative deployment service",
|
||||
"action_or_decision": "Apply only if selected; preserve Declared production services and complete UTC observation days; report each service before pooled views.",
|
||||
"output": "ratio; Missing feed periods not zero; report coverage and no unqualified overall rate when period incomplete.",
|
||||
"next_or_feedback": "/strategy/skills-adoption/",
|
||||
"review": "Canonical contract and URL preserved; populations, exclusions, missingness and crosslinks reviewed",
|
||||
"contract_sha256": "5a34ba52e5c2768e29a1a7574274e07a65509f75063e89ccc7ce1b035aeff4c5",
|
||||
"implementation": "unimplemented"
|
||||
},
|
||||
{
|
||||
"source": "docs/strategy/measurement/deployment-rework-rate.mdx",
|
||||
"route": "/strategy/measurement/deployment-rework-rate/",
|
||||
"question": "How much production deployment activity is corrective?",
|
||||
"inputs": "deployment.completed; incident.linked; release intent classification",
|
||||
"action_or_decision": "Apply only if selected; preserve Production deployment effects in window with immutable planned/unplanned classification and incident linkage.",
|
||||
"output": "percent; Unknown classification stays denominator; observed numerator is lower bound until reconciliation; show classification coverage.",
|
||||
"next_or_feedback": "/strategy/skills-adoption/",
|
||||
"review": "Canonical contract and URL preserved; populations, exclusions, missingness and crosslinks reviewed",
|
||||
"contract_sha256": "e8ade457136feac3ad39e9eba2a9d67142bc605727d9f4f038a7df6d5a0707fd",
|
||||
"implementation": "prototype"
|
||||
},
|
||||
{
|
||||
"source": "docs/strategy/measurement/failed-deployment-recovery-time.mdx",
|
||||
"route": "/strategy/measurement/failed-deployment-recovery-time/",
|
||||
"question": "How long did recovered deployment failures take to restore?",
|
||||
"inputs": "deployment.failed; service.restored; incident service",
|
||||
"action_or_decision": "Apply only if selected; preserve Production deployment failures beginning in window; latest verified restoration if a recovery is rescinded.",
|
||||
"output": "mean; Unresolved failures reported separately and excluded only from recovered-duration distribution; prevent declaring improvement without their visibility.",
|
||||
"next_or_feedback": "/strategy/skills-adoption/",
|
||||
"review": "Canonical contract and URL preserved; populations, exclusions, missingness and crosslinks reviewed",
|
||||
"contract_sha256": "489fd756883d4ccee1769fcfaa0b67725420463df2b1f6faf3e7faa7002f7a80",
|
||||
"implementation": "unimplemented"
|
||||
},
|
||||
{
|
||||
"source": "docs/strategy/measurement/index.mdx",
|
||||
"route": "/strategy/measurement/",
|
||||
"question": "Which evidence can support this workflow decision?",
|
||||
"inputs": "Workflow question and available populations",
|
||||
"action_or_decision": "Choose applicable contracts and connect fitness to Quality",
|
||||
"output": "Selected definitions and limits, never mandatory full collection",
|
||||
"next_or_feedback": "/strategy/baseline/",
|
||||
"review": "Two tracks retained; fitness not reduced to health proxies"
|
||||
},
|
||||
{
|
||||
"source": "docs/strategy/measurement/skill-selection-precision.mdx",
|
||||
"route": "/strategy/measurement/skill-selection-precision/",
|
||||
"question": "Were selected skills relevant to the labeled cases?",
|
||||
"inputs": "eval.selection; versioned labeled corpus and runner",
|
||||
"action_or_decision": "Apply only if selected; preserve All candidate/client labeled evaluation task-trials with known activation and relevance.",
|
||||
"output": "percent; Unknown activation/relevance is unscorable; publish missing count and deny qualification if planned coverage incomplete.",
|
||||
"next_or_feedback": "/strategy/skills-quality/",
|
||||
"review": "Canonical contract and URL preserved; populations, exclusions, missingness and crosslinks reviewed",
|
||||
"contract_sha256": "189e93e4e5f52a7e70e2045c6b824a9da621382f39ba8ce9a59c0c04812f0ce3",
|
||||
"implementation": "prototype"
|
||||
},
|
||||
{
|
||||
"source": "docs/strategy/measurement/skill-selection-recall.mdx",
|
||||
"route": "/strategy/measurement/skill-selection-recall/",
|
||||
"question": "Were expected skills found in relevant labeled cases?",
|
||||
"inputs": "eval.selection; versioned labeled corpus and runner",
|
||||
"action_or_decision": "Apply only if selected; preserve Independently labeled relevant evaluation task-trials for a skill/client tuple.",
|
||||
"output": "percent; Report evaluation coverage; null if no relevant labeled tasks.",
|
||||
"next_or_feedback": "/strategy/skills-quality/",
|
||||
"review": "Canonical contract and URL preserved; populations, exclusions, missingness and crosslinks reviewed",
|
||||
"contract_sha256": "847b5ba6094585eb88b8eb2b55b42e0f3c6822dcaa1629256ad0501a13eb7f18",
|
||||
"implementation": "prototype"
|
||||
},
|
||||
{
|
||||
"source": "docs/strategy/measurement/skills-within-substantive-review-window.mdx",
|
||||
"route": "/strategy/measurement/skills-within-substantive-review-window/",
|
||||
"question": "Which approved revisions have current ownership and substantive review?",
|
||||
"inputs": "catalog.published; catalog.reviewed; catalog.deprecated; catalog.revoked; version inventory",
|
||||
"action_or_decision": "Apply only if selected; preserve Approved revisions currently supported for use at as_of.",
|
||||
"output": "percent; Missing owner/date/evidence outside numerator; show ownerless, deprecated-in-use and revoked-in-use absolute counts.",
|
||||
"next_or_feedback": "/strategy/skills-maintenance/",
|
||||
"review": "Canonical contract and URL preserved; populations, exclusions, missingness and crosslinks reviewed",
|
||||
"contract_sha256": "339fe0da6b382a34c52b5ec6005ce08a7293a2b07ccd88540a6df03a02d96ad4",
|
||||
"implementation": "unimplemented"
|
||||
},
|
||||
{
|
||||
"source": "docs/strategy/measurement/supported-bundle-coverage.mdx",
|
||||
"route": "/strategy/measurement/supported-bundle-coverage/",
|
||||
"question": "Which expected installations have verified supported revisions?",
|
||||
"inputs": "inventory.observed; catalog.published; catalog.revoked; device inventory",
|
||||
"action_or_decision": "Apply only if selected; preserve Active installation inventory frozen for report, including invisible/offline entries until authoritative offboarding.",
|
||||
"output": "percent; Unknown/stale versions count outside numerator, inside denominator. Show inventory discovery coverage versus eligible device roster; if roster unknown metric is provisional.",
|
||||
"next_or_feedback": "/strategy/skills-maintenance/",
|
||||
"review": "Canonical contract and URL preserved; populations, exclusions, missingness and crosslinks reviewed",
|
||||
"contract_sha256": "8b4dc2dbdfb6999fac283814f518645d0830d515125910d79dd7dc8763f0521c",
|
||||
"implementation": "unimplemented"
|
||||
},
|
||||
{
|
||||
"source": "docs/strategy/measurement/synthetic-example.mdx",
|
||||
"route": "/strategy/measurement/synthetic-example/",
|
||||
"question": "How can I reproduce the arithmetic without claiming real results?",
|
||||
"inputs": "Labeled synthetic fixture",
|
||||
"action_or_decision": "Run the prototype and verify missingness",
|
||||
"output": "Synthetic calculations with omissions, not baseline values",
|
||||
"next_or_feedback": "/strategy/baseline/",
|
||||
"review": "Linked to full journey; obsolete roadmap-gates link replaced only in safeguards; preserved arithmetic/privacy substance"
|
||||
},
|
||||
{
|
||||
"source": "docs/strategy/measurement/validated-task-success.mdx",
|
||||
"route": "/strategy/measurement/validated-task-success/",
|
||||
"question": "Which matured workflow starts reached independent acceptance?",
|
||||
"inputs": "task.started; task.accepted; task.failed; task.abandoned; task.cancelled; work-management acceptance record",
|
||||
"action_or_decision": "Apply only if selected; preserve Tasks in a preregistered workflow cohort, started in window; each counted once across retries, skills and clients.",
|
||||
"output": "percent; Unresolved/missing terminal outcomes remain in denominator with unknown count and known-outcome coverage; do not label them failed. Invalid/missing start excluded from calculation but flagged as orphan evidence.",
|
||||
"next_or_feedback": "/strategy/skills-adoption/",
|
||||
"review": "Canonical contract and URL preserved; populations, exclusions, missingness and crosslinks reviewed",
|
||||
"contract_sha256": "925100f4c84f43e2cfdca4a89d6b4a984c808dae2d2ec5e57202318f70b9c544",
|
||||
"implementation": "prototype"
|
||||
},
|
||||
{
|
||||
"source": "docs/strategy/measurement/verification-confidence-and-cognitive-load.mdx",
|
||||
"route": "/strategy/measurement/verification-confidence-and-cognitive-load/",
|
||||
"question": "Can the cohort confidently verify work without excessive perceived load?",
|
||||
"inputs": "survey.response; anonymous survey with single-use token and aggregate invitation count",
|
||||
"action_or_decision": "Apply only if selected; preserve Invited eligible cohort at fixed survey wave; voluntary responses.",
|
||||
"output": "mean; Report valid response count / invited count and item nonresponse; no imputation. Suppress people cohorts below five.",
|
||||
"next_or_feedback": "/strategy/skills-adoption/",
|
||||
"review": "Canonical contract and URL preserved; populations, exclusions, missingness and crosslinks reviewed",
|
||||
"contract_sha256": "01e017471004c5f780fd0c2671a4d4449d392956cb4c5f0bd7791959d6a9af9a",
|
||||
"implementation": "prototype"
|
||||
},
|
||||
{
|
||||
"source": "docs/strategy/measurement/workflow-specific-business-acceptance.mdx",
|
||||
"route": "/strategy/measurement/workflow-specific-business-acceptance/",
|
||||
"question": "Did a named workflow meet its departmental acceptance rubric?",
|
||||
"inputs": "task.started; business.accepted; departmental case/content/reconciliation/onboarding review record",
|
||||
"action_or_decision": "Apply only if selected; preserve One named departmental workflow and predeclared start cohort; never pool unlike rubrics.",
|
||||
"output": "percent; Unknown follow-up stays denominator with unresolved count; no claim actual business outcome changed without source evidence.",
|
||||
"next_or_feedback": "/strategy/skills-adoption/",
|
||||
"review": "Canonical contract and URL preserved; populations, exclusions, missingness and crosslinks reviewed",
|
||||
"contract_sha256": "55fce8843409a1bc1383fef3cee5b9a616b44fa8d45ba84c6e4ed490a25f2de4",
|
||||
"implementation": "unimplemented"
|
||||
},
|
||||
{
|
||||
"source": "docs/strategy/roadmap.mdx",
|
||||
"route": "/strategy/roadmap/",
|
||||
"question": "How do we move toward Target without assuming autonomy?",
|
||||
"inputs": "Target and current working practices",
|
||||
"action_or_decision": "Start skills adoption in Delivery; leave later phase order undecided",
|
||||
"output": "Two-stage direction and within-phase learning loop",
|
||||
"next_or_feedback": "/strategy/stage-01-skills-adoption/",
|
||||
"review": "Qualified pilot and separate Stage02 authority now explicit"
|
||||
},
|
||||
{
|
||||
"source": "docs/strategy/skills-adoption.mdx",
|
||||
"route": "/strategy/skills-adoption/",
|
||||
"question": "Should a qualified skill become a retained workflow?",
|
||||
"inputs": "Baseline, qualification and explicit bounded-pilot authorization",
|
||||
"action_or_decision": "Run comparable real work; owner decides retain/improve/expand/stop",
|
||||
"output": "Decision record; retained revision requires exact-scope approval",
|
||||
"next_or_feedback": "/strategy/skills-maintenance/",
|
||||
"review": "Manual path and feedback to author/Quality/Baseline"
|
||||
},
|
||||
{
|
||||
"source": "docs/strategy/skills-governance.mdx",
|
||||
"route": "/strategy/skills-governance/",
|
||||
"question": "Who may authorize which revision for which use?",
|
||||
"inputs": "Workflow map, candidate topology and risk boundary",
|
||||
"action_or_decision": "Name people, independent reviewers and staged permissions",
|
||||
"output": "Pinned candidate, bounded-pilot authorization then exact-scope approval",
|
||||
"next_or_feedback": "/strategy/skills-quality/",
|
||||
"review": "Reconciled disposable qualification, authorized pilot and wider use"
|
||||
},
|
||||
{
|
||||
"source": "docs/strategy/skills-maintenance.mdx",
|
||||
"route": "/strategy/skills-maintenance/",
|
||||
"question": "How do retained skills remain useful and safe?",
|
||||
"inputs": "Approved manifest, outcomes, failures and client/model drift",
|
||||
"action_or_decision": "Continue authorized use, requalify, contain or retire",
|
||||
"output": "Support/recovery evidence, regression cases or migration record",
|
||||
"next_or_feedback": "/strategy/skills-quality/",
|
||||
"review": "Fitness/regression beyond metadata health; no automatic autonomy"
|
||||
},
|
||||
{
|
||||
"source": "docs/strategy/skills-quality.mdx",
|
||||
"route": "/strategy/skills-quality/",
|
||||
"question": "Is the named candidate fit and non-regressing?",
|
||||
"inputs": "Pinned revision/client, declared cases and acceptance rules",
|
||||
"action_or_decision": "Independent fitness/safety/regression evaluation; recommend pilot or hold",
|
||||
"output": "Versioned qualification report with failures and limits",
|
||||
"next_or_feedback": "/strategy/skills-adoption/",
|
||||
"review": "Separates artifact trial population from matured live tasks"
|
||||
},
|
||||
{
|
||||
"source": "docs/strategy/stage-01-skills-adoption.mdx",
|
||||
"route": "/strategy/stage-01-skills-adoption/",
|
||||
"question": "How do I begin one repeatable adoption journey?",
|
||||
"inputs": "Workflow problem, people and current evidence",
|
||||
"action_or_decision": "Baseline, engineer, qualify, authorize pilot, compare and decide",
|
||||
"output": "Supported workflow or explicit hold/stop; feedback to baseline/quality",
|
||||
"next_or_feedback": "/strategy/baseline/",
|
||||
"review": "New native dependency story plus evidence handoffs"
|
||||
},
|
||||
{
|
||||
"source": "docs/strategy/stage-02-autonomous-agent.mdx",
|
||||
"route": "/strategy/stage-02-autonomous-agent/",
|
||||
"question": "Is additional autonomous authority justified and recoverable?",
|
||||
"inputs": "Proven Stage01 practices, limits and explicit operation proposal",
|
||||
"action_or_decision": "Existing designated functions assess scope, enforcement and takeover",
|
||||
"output": "Recorded hold or conditional bounded authority",
|
||||
"next_or_feedback": "/strategy/stage-01-skills-adoption/",
|
||||
"review": "New authority boundary diagram and return-to-Stage01 path"
|
||||
},
|
||||
{
|
||||
"source": "docs/strategy/target-operating-model.mdx",
|
||||
"route": "/strategy/target-operating-model/",
|
||||
"question": "What operating model are we aiming for?",
|
||||
"inputs": "Human-directed SDLC target and existing team boundaries",
|
||||
"action_or_decision": "Distinguish intended execution from current authority",
|
||||
"output": "Shared destination, no deployed-autonomy claim",
|
||||
"next_or_feedback": "/strategy/roadmap/",
|
||||
"review": "Preserved central-agent topology; connected Delivery thread"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
import test from 'node:test';
|
||||
import assert from 'node:assert/strict';
|
||||
import {readFileSync} from 'node:fs';
|
||||
const read = path => readFileSync(path, 'utf8');
|
||||
|
||||
test('Baseline is workflow-scoped, evidence-bound and distinct from the optional registry', () => {
|
||||
const page = read('docs/strategy/baseline.mdx');
|
||||
for (const heading of ['Understand the current workflow','Select relevant metrics, with reasons','Agree feasible evidence','Record the starting position','Keep later evaluation comparable']) assert(page.includes(`## ${heading}`));
|
||||
for (const text of ['not a mandatory company-wide baseline','no actual baseline values or approved thresholds','lawful basis','privacy','retention','source coverage','**Available:**','**Unavailable:**','not causal ROI','selected-but-unavailable']) assert(page.includes(text), text);
|
||||
assert(page.indexOf('<ArchifyDiagram') < page.indexOf('## Understand'));
|
||||
assert(!page.includes('25%'));
|
||||
for (const doc of ['measurement/index','measurement/collection-and-safeguards','skills-adoption','skills-maintenance','skills-governance']) assert(page.includes(`./${doc}.mdx`));
|
||||
const registry = read('docs/strategy/measurement/index.mdx');
|
||||
assert(registry.includes('pagination_next: baseline'));
|
||||
assert(page.includes('pagination_prev: measurement/index'));
|
||||
assert(page.includes('pagination_next: skills-governance'));
|
||||
});
|
||||
|
||||
test('workflow application has one home and shared safety remains explicit', () => {
|
||||
const registry = read('docs/strategy/measurement/index.mdx');
|
||||
const shared = read('docs/strategy/measurement/collection-and-safeguards.mdx');
|
||||
const adoption = read('docs/strategy/skills-adoption.mdx');
|
||||
const maintenance = read('docs/strategy/skills-maintenance.mdx');
|
||||
assert(!registry.includes('Measure the pilot'));
|
||||
assert(!shared.includes('Track all five'));
|
||||
assert(!shared.includes('Before a pilot, freeze'));
|
||||
assert(shared.includes('id') && shared.includes('{#baseline-and-interpretation}')); // Existing inbound anchor survives relocation.
|
||||
for (const marker of ['transport retries','quarantined','Late arrivals','Unknown version stays null','30 days','12 months','below five people','No raw prompts','Consent is not presumed']) assert(shared.includes(marker),marker);
|
||||
assert(adoption.includes('not a mandatory pilot bundle'));
|
||||
assert(adoption.includes('What a pilot report looks like'));
|
||||
assert(maintenance.includes('Keep selected evidence useful'));
|
||||
assert(maintenance.includes('versioned corrections'));
|
||||
assert(adoption.includes('**Next:** [Maintain skills using the agreed evidence →](./skills-maintenance.mdx)'));
|
||||
});
|
||||
@@ -0,0 +1,8 @@
|
||||
const {chromium}=require('playwright');
|
||||
const fs=require('node:fs');const assert=require('node:assert/strict');
|
||||
(async()=>{
|
||||
const base=process.argv[2]||'http://127.0.0.1:4173';const out=`.cache/journey-${process.argv[3]||'candidate'}`;fs.mkdirSync(out,{recursive:true});
|
||||
const b=await chromium.launch({executablePath:process.env.PLAYWRIGHT_CHROMIUM_EXECUTABLE,args:['--no-sandbox']});const results=[];
|
||||
const steps=[['target-operating-model','roadmap'],['roadmap','stage-01-skills-adoption'],['stage-01-skills-adoption','baseline'],['baseline','measurement'],['measurement','skills-quality'],['skills-quality','skills-governance'],['skills-governance','skills-quality'],['skills-quality','skills-adoption'],['skills-adoption','skills-maintenance'],['skills-maintenance','skills-quality'],['skills-quality','measurement/validated-task-success'],['measurement/validated-task-success','skills-quality'],['skills-maintenance','stage-02-autonomous-agent'],['stage-02-autonomous-agent','stage-01-skills-adoption']];
|
||||
try{for(const width of [1440,390]){const p=await b.newPage({viewport:{width,height:900}});for(const [from,to]of steps){await p.goto(`${base}/eldorado-v1/documentation/strategy/${from}/`,{waitUntil:'networkidle'});const href=`/eldorado-v1/documentation/strategy/${to}/`;const link=p.locator(`article a[href="${href}"]`).filter({visible:true}).first();assert(await link.count(),`${from} → ${to}`);await link.scrollIntoViewIfNeeded();await p.waitForLoadState('networkidle');await link.click();await p.waitForURL(`${base}${href}`);await p.locator('article h1').waitFor();results.push({width,from,to,clicked:true});fs.writeFileSync(`${out}/results.json`,JSON.stringify(results,null,2))}await p.close()}console.log(`PASS ${results.length} real reader handoffs and feedback links`)}finally{await b.close()}
|
||||
})().catch(e=>{console.error(e);process.exitCode=1});
|
||||
@@ -125,9 +125,9 @@ const fs = require('node:fs');
|
||||
await page.screenshot({path:`${output}/${width}.png`, fullPage:true});
|
||||
await frame.locator('#btn-theme').click(); await theme('dark');
|
||||
// Exercise keyboard navigation without racing the portal's smooth scroll.
|
||||
await page.locator('.strategy-content a[href$="/strategy/skills-governance/"]').filter({visible:true}).focus();
|
||||
await page.locator('.strategy-content a[href$="/strategy/roadmap/"]').filter({visible:true}).first().focus();
|
||||
await page.keyboard.press('Enter');
|
||||
await page.waitForURL('**/strategy/skills-governance/');
|
||||
await page.waitForURL('**/strategy/roadmap/');
|
||||
await page.goBack({waitUntil:'domcontentloaded'});
|
||||
await page.waitForURL('**/strategy/target-operating-model/');
|
||||
await page.getByRole('heading', {name:'Target operating model', exact:true, level:1}).waitFor();
|
||||
|
||||
@@ -0,0 +1,79 @@
|
||||
const {chromium} = require('playwright');
|
||||
const assert = require('node:assert/strict');
|
||||
const fs = require('node:fs');
|
||||
(async () => {
|
||||
const base = process.argv[2] || 'http://127.0.0.1:4173';
|
||||
const prefix = '/eldorado-v1/documentation';
|
||||
const manifest = JSON.parse(fs.readFileSync('research/ai-adoption/measurement-migration.json','utf8'));
|
||||
const output = `.cache/metric-pages-${process.argv[3] || 'local'}`;
|
||||
fs.mkdirSync(output,{recursive:true});
|
||||
const browser = await chromium.launch({headless:true,executablePath:process.env.PLAYWRIGHT_CHROMIUM_EXECUTABLE,args:['--no-sandbox']});
|
||||
const results = [];
|
||||
try {
|
||||
for (const width of [1440,390]) {
|
||||
const context = await browser.newContext({viewport:{width,height:900}});
|
||||
try {
|
||||
const page = await context.newPage();
|
||||
const errors = [];
|
||||
page.on('pageerror',e => errors.push(e.message));
|
||||
for (const m of manifest.metrics) {
|
||||
const url = `${base}${prefix}${m.url}`;
|
||||
assert.equal((await page.goto(url,{waitUntil:'networkidle'})).status(),200);
|
||||
assert.equal(await page.locator('article h1').innerText(),m.title);
|
||||
assert.equal(await page.locator('link[rel="canonical"]').getAttribute('href'),`https://pages.apps.lego-cloud.eu${prefix}${m.url}`);
|
||||
const table = page.locator('article table');
|
||||
assert.equal(await table.count(),1);
|
||||
assert.equal(await table.locator('tbody tr').count(),11);
|
||||
const article = await page.locator('article').innerText();
|
||||
assert(article.includes(m.status === 'prototype' ? 'Prototype calculation' : 'Unimplemented metric'));
|
||||
assert(article.includes('no live telemetry'));
|
||||
assert.equal(await page.locator('.breadcrumbs a').filter({hasText:'Measurement'}).getAttribute('href'),`${prefix}/strategy/measurement/`);
|
||||
assert(!await page.evaluate(() => document.documentElement.scrollWidth > innerWidth));
|
||||
await page.goto(`${base}${prefix}/strategy/reference/measurement-contracts/#${m.oldAnchor}`,{waitUntil:'networkidle'});
|
||||
await page.waitForURL(url);
|
||||
await page.locator('article h1').waitFor();
|
||||
results.push({width,metric:m.oldAnchor,canonical:true,redirect:true,fields:11});
|
||||
}
|
||||
for (const suffix of ['', '#unknown-anchor', '#__proto__']) {
|
||||
await page.goto(`${base}${prefix}/strategy/reference/measurement-contracts/${suffix}`,{waitUntil:'networkidle'});
|
||||
await page.waitForURL(`${base}${prefix}/strategy/measurement/`);
|
||||
}
|
||||
for (const [anchor,target] of [
|
||||
['collection-and-safeguards','collection-and-safeguards/'],
|
||||
['decide-what-counts-before-counting','collection-and-safeguards/#decide-what-counts-before-counting'],
|
||||
['baseline-and-interpretation','collection-and-safeguards/#baseline-and-interpretation'],
|
||||
['event-and-privacy-contract','collection-and-safeguards/#event-and-privacy-contract'],
|
||||
['run-the-synthetic-measurement-example','synthetic-example/'],
|
||||
['metric-contracts','#metric-definitions'],
|
||||
]) {
|
||||
await page.goto(`${base}${prefix}/strategy/reference/measurement-contracts/#${anchor}`,{waitUntil:'networkidle'});
|
||||
await page.waitForURL(`${base}${prefix}/strategy/measurement/${target}`);
|
||||
if (target.includes('#')) await page.locator(`#${target.split('#')[1]}`).waitFor();
|
||||
}
|
||||
await page.goto(`${base}${prefix}/strategy/measurement/supported-bundle-coverage/`,{waitUntil:'networkidle'});
|
||||
await page.locator('.breadcrumbs a').filter({hasText:'Measurement'}).click();
|
||||
await page.waitForURL(`${base}${prefix}/strategy/measurement/`);
|
||||
if (width < 997) await page.getByRole('button',{name:'Toggle navigation bar'}).click();
|
||||
const menu = page.locator('.theme-doc-sidebar-menu').filter({visible:true});
|
||||
const category = menu.locator('.theme-doc-sidebar-item-category').filter({has:page.getByRole('link',{name:'Measurement',exact:true})}).last();
|
||||
const caret = category.locator(':scope > .menu__list-item-collapsible > button.menu__caret');
|
||||
await caret.click();
|
||||
await category.getByRole('link',{name:'Validated task success',exact:true}).waitFor({state:'hidden'});
|
||||
await caret.focus(); await page.keyboard.press('Enter');
|
||||
await category.getByRole('link',{name:'Validated task success',exact:true}).waitFor({state:'visible'});
|
||||
await menu.getByRole('link',{name:'Measurement',exact:true}).click();
|
||||
await page.waitForURL(`${base}${prefix}/strategy/measurement/`);
|
||||
await page.locator('article h1').waitFor();
|
||||
if (width < 997) await page.getByRole('button',{name:'Close navigation bar'}).waitFor({state:'hidden'});
|
||||
await page.locator('#metric-definitions').scrollIntoViewIfNeeded();
|
||||
await page.screenshot({path:`${output}/${width}-index.png`});
|
||||
await page.goto(`${base}${prefix}/strategy/measurement/supported-bundle-coverage/`,{waitUntil:'networkidle'});
|
||||
await page.screenshot({path:`${output}/${width}-metric.png`,fullPage:true});
|
||||
assert.deepEqual(errors,[]);
|
||||
} finally {await context.close();}
|
||||
}
|
||||
assert.equal(results.length,32);
|
||||
fs.writeFileSync(`${output}/results.json`,JSON.stringify(results,null,2));
|
||||
console.log('PASS: 16 metric pages × 2 widths; canonical metadata, contract fields, status, all legacy metric/shared/fallback redirects and linked Measurement keyboard navigation');
|
||||
} finally {await browser.close();}
|
||||
})().catch(e => {console.error(e);process.exitCode=1;});
|
||||
@@ -0,0 +1,136 @@
|
||||
const {chromium} = require('playwright');
|
||||
const assert = require('node:assert/strict');
|
||||
const fs = require('node:fs');
|
||||
const views = {
|
||||
'strategy-roadmap': ['skills','autonomy'],
|
||||
'strategy-roadmap-adoption': ['delivery','remaining'],
|
||||
'strategy-roadmap-loop': ['understand','baseline','topology','use','collect','reassess'],
|
||||
};
|
||||
(async () => {
|
||||
const base = process.argv[2] || 'http://127.0.0.1:4173';
|
||||
const output = `.cache/roadmap-timeline-${process.argv[3] || 'local'}`;
|
||||
fs.mkdirSync(output, {recursive:true});
|
||||
const browser = await chromium.launch({headless:true, executablePath:process.env.PLAYWRIGHT_CHROMIUM_EXECUTABLE, args:['--no-sandbox']});
|
||||
const results = [];
|
||||
const inspect = async (frame, name, vertical) => {
|
||||
await frame.locator('svg[role="img"]').waitFor();
|
||||
const geometry = await frame.locator('svg[role="img"]').evaluate(svg => ({
|
||||
width:innerWidth, height:innerHeight,
|
||||
edges:[...svg.querySelectorAll('path[data-edge-id]')].map(p => ({id:p.dataset.edgeId,box:p.getBoundingClientRect().toJSON()})),
|
||||
cards:[...svg.querySelectorAll('[data-node-id]')].map(node => ({
|
||||
id:node.dataset.nodeId, box:node.querySelector('rect').getBoundingClientRect().toJSON(),
|
||||
number:node.querySelector('[data-stage-number]').textContent,
|
||||
text:[...node.querySelectorAll('text')].map(text => ({value:text.textContent, box:text.getBoundingClientRect().toJSON(), size:parseFloat(getComputedStyle(text).fontSize)*text.getScreenCTM().a}))
|
||||
}))
|
||||
}));
|
||||
const ids=views[name];
|
||||
geometry.cards.sort((a,b)=>ids.indexOf(a.id)-ids.indexOf(b.id));
|
||||
assert.deepEqual(geometry.cards.map(n => n.id), ids);
|
||||
assert.deepEqual(geometry.cards.map(n => n.number), ids.length === 6 ? ids.map((_,i)=>`Step ${i+1}`) : name === 'strategy-roadmap' ? ['Stage 1','Stage 2'] : ['First','Then']);
|
||||
assert.equal(geometry.edges.length,ids.length===6?6:1);
|
||||
if(ids.length===6) assert(geometry.edges.some(e=>e.id==='repeat'));
|
||||
for(const edge of geometry.edges) assert(edge.box.left>=0 && edge.box.right<=geometry.width+1 && edge.box.top>=0 && edge.box.bottom<=geometry.height+1, `clipped edge ${name} ${edge.id}`);
|
||||
for (const [index, card] of geometry.cards.entries()) {
|
||||
assert.equal(card.text.length,3);
|
||||
assert(card.box.left >= 0 && card.box.top >= 0 && card.box.right <= geometry.width+1 && card.box.bottom <= geometry.height+1, `outside iframe ${name} ${card.id}`);
|
||||
for(const text of card.text) {
|
||||
assert(text.size>=13, `small text ${name} ${card.id}: ${text.size}`);
|
||||
assert(text.box.left>=card.box.left && text.box.right<=card.box.right+1 && text.box.top>=card.box.top && text.box.bottom<=card.box.bottom+1, `clipped text ${name} ${card.id}`);
|
||||
}
|
||||
for(let t=1;t<card.text.length;t++) assert(card.text[t-1].box.bottom<card.text[t].box.top,`text overlap ${card.id}`);
|
||||
if(index && vertical) {assert.equal(geometry.cards[index-1].box.x,card.box.x);assert(geometry.cards[index-1].box.bottom<card.box.top);}
|
||||
}
|
||||
return geometry;
|
||||
};
|
||||
try {
|
||||
for(const width of [1440,1024,390,320]) {
|
||||
const context=await browser.newContext({viewport:{width,height:1000},colorScheme:'light'});
|
||||
try {
|
||||
const page=await context.newPage(); const errors=[]; page.on('pageerror',e=>errors.push(e.message));
|
||||
assert.equal((await page.goto(`${base}/eldorado-v1/documentation/strategy/roadmap/`,{waitUntil:'networkidle'})).status(),200);
|
||||
await page.addStyleTag({content:'html {scroll-behavior:auto !important;}'});
|
||||
assert.equal(await page.locator('.archify-panel--story').count(),3);
|
||||
for(const name of Object.keys(views)) {
|
||||
const panel=page.locator(`[data-diagram="${name}"]`);
|
||||
const iframe=panel.locator(width<1100?'.story-mobile':'.story-desktop');
|
||||
await iframe.scrollIntoViewIfNeeded();
|
||||
const frame=await (await iframe.elementHandle()).contentFrame();
|
||||
await frame.locator('svg[role="img"]').waitFor();
|
||||
const opener=panel.getByRole('button',{name:/^Expand /});
|
||||
for(const theme of ['light','dark']) {
|
||||
const frameTop=await iframe.evaluate(n=>n.getBoundingClientRect().top+scrollY);
|
||||
await page.evaluate(y=>scrollTo({top:y-120,behavior:'instant'}),frameTop);
|
||||
if(await frame.locator('html').getAttribute('data-theme')!==theme) await frame.locator('#btn-theme').click();
|
||||
await page.waitForFunction(t=>document.documentElement.dataset.theme===t,theme);
|
||||
const inline=await inspect(frame,name,width<1100);
|
||||
await frame.locator('#btn-preset').focus();await page.keyboard.press('Enter');
|
||||
await frame.locator('[data-preset-value="blueprint"]').focus();await page.keyboard.press('Enter');
|
||||
await frame.waitForFunction(()=>document.documentElement.dataset.preset==='blueprint');
|
||||
await inspect(frame,name,width<1100);
|
||||
await frame.locator('#btn-preset').focus();await page.keyboard.press('Enter');
|
||||
await frame.locator('[data-preset-value="classic"]').focus();await page.keyboard.press('Enter');
|
||||
await frame.waitForFunction(()=>document.documentElement.dataset.preset==='classic');
|
||||
await frame.locator('#btn-export').focus();await page.keyboard.press('Enter');
|
||||
await frame.locator('[data-format="svg"]').focus();
|
||||
const [download]=await Promise.all([page.waitForEvent('download'),page.keyboard.press('Enter')]);
|
||||
assert.equal(await download.failure(),null);
|
||||
const exported=`${output}/${width}-${theme}-${name}.svg`;
|
||||
await download.saveAs(exported);
|
||||
const svg=fs.readFileSync(exported,'utf8');
|
||||
for(const id of views[name]) assert(svg.includes(`data-node-id="${id}"`));
|
||||
assert(svg.includes('eldorado-roadmap-typography'));
|
||||
await panel.screenshot({path:`${output}/${width}-${theme}-${name}-inline.png`});
|
||||
// Scroll each card into the real viewport: tall iframe captures alone
|
||||
// may contain compositor blanks even when DOM geometry is correct.
|
||||
for(const card of inline.cards) {
|
||||
const top=await iframe.evaluate(n=>n.getBoundingClientRect().top+scrollY);
|
||||
await page.evaluate(y=>scrollTo({top:y,behavior:'instant'}),top+card.box.top-100);
|
||||
await page.screenshot({path:`${output}/${width}-${theme}-${name}-${card.id}.png`});
|
||||
}
|
||||
await opener.focus();await page.keyboard.press('Enter');
|
||||
const close=panel.getByRole('button',{name:'Close full-screen diagram',exact:true});await close.waitFor({state:'visible'});
|
||||
const fullIframe=panel.locator('dialog iframe');
|
||||
const fullscreen=await (await fullIframe.elementHandle()).contentFrame();
|
||||
await fullscreen.waitForFunction(t=>document.documentElement.dataset.theme===t,theme);
|
||||
const expanded=await inspect(fullscreen,name,width<1000);
|
||||
await page.screenshot({path:`${output}/${width}-${theme}-${name}-fullscreen.png`});
|
||||
await close.focus();await page.keyboard.press('Escape');
|
||||
await fullIframe.waitFor({state:'detached'});assert(await opener.evaluate(n=>n===document.activeElement));
|
||||
results.push({width,theme,name,inline,expanded});fs.writeFileSync(`${output}/results.json`,JSON.stringify(results,null,2));
|
||||
}
|
||||
}
|
||||
assert(!await page.evaluate(()=>document.documentElement.scrollWidth>innerWidth));assert.deepEqual(errors,[]);
|
||||
} finally {await context.close();}
|
||||
}
|
||||
assert.equal(results.length,24);
|
||||
for(const viewport of [{width:390,height:667},{width:320,height:568}]) {
|
||||
const context=await browser.newContext({viewport});
|
||||
try {
|
||||
const page=await context.newPage();await page.goto(`${base}/eldorado-v1/documentation/strategy/roadmap/`,{waitUntil:'networkidle'});
|
||||
await page.addStyleTag({content:'html {scroll-behavior:auto !important;}'});
|
||||
for(const name of Object.keys(views)) {
|
||||
const panel=page.locator(`[data-diagram="${name}"]`), opener=panel.getByRole('button',{name:/^Expand /});
|
||||
await opener.focus();await page.keyboard.press('Enter');const modal=panel.locator('dialog'), close=modal.getByRole('button',{name:'Close full-screen diagram',exact:true});await close.waitFor({state:'visible'});
|
||||
const iframe=modal.locator('iframe'), frame=await (await iframe.elementHandle()).contentFrame();
|
||||
const geometry=await inspect(frame,name,true);
|
||||
assert(await modal.evaluate(n=>n.scrollHeight>n.clientHeight),'short fullscreen must scroll');
|
||||
for(const card of geometry.cards) {
|
||||
await modal.evaluate((n,y)=>{n.scrollTop=y;},card.box.top);
|
||||
const b=await iframe.boundingBox(), t=await modal.locator('.archify-modal-toolbar').boundingBox(), c=await close.boundingBox();
|
||||
assert(c.y>=0 && c.y+c.height<=viewport.height);
|
||||
assert(b.y+card.box.top>=t.y+t.height-1 && b.y+card.box.bottom<=viewport.height+1,`unreachable ${name} ${card.id}`);
|
||||
}
|
||||
await modal.evaluate(n=>{n.scrollTop=0;});
|
||||
for(const selector of ['#btn-theme','#btn-preset','#btn-export']) {
|
||||
const control=frame.locator(selector), b=await control.boundingBox();assert(b.x>=0 && b.x+b.width<=viewport.width && b.y>=0 && b.y+b.height<=viewport.height);await control.click();if(selector!=='#btn-theme')await control.click();
|
||||
}
|
||||
await close.focus();await page.keyboard.press('Escape');await iframe.waitFor({state:'detached'});assert(await opener.evaluate(n=>n===document.activeElement));
|
||||
await page.keyboard.press('Enter');await close.waitFor({state:'visible'});await close.click();await iframe.waitFor({state:'detached'});assert(await opener.evaluate(n=>n===document.activeElement));
|
||||
results.push({viewport,name,scrollable:geometry});fs.writeFileSync(`${output}/results.json`,JSON.stringify(results,null,2));
|
||||
}
|
||||
} finally {await context.close();}
|
||||
}
|
||||
assert.equal(results.length,30);
|
||||
console.log('PASS 48 diagram contexts: three views × four widths × light/dark × inline/fullscreen; plus six short-phone scrolling/keyboard contexts.');
|
||||
} finally {await browser.close();}
|
||||
})().catch(error=>{console.error(error);process.exitCode=1;});
|
||||
@@ -8,6 +8,50 @@ const fs = require('node:fs');
|
||||
const browser = await chromium.launch({headless:true, executablePath:process.env.PLAYWRIGHT_CHROMIUM_EXECUTABLE, args:['--no-sandbox']});
|
||||
const results = [];
|
||||
try {
|
||||
// Intermediate widths must use the readable vertical Roadmap, not shrink the loop.
|
||||
for (const width of [768, 1024]) {
|
||||
const context = await browser.newContext({viewport:{width,height:1000}, colorScheme:'light'});
|
||||
try {
|
||||
const page = await context.newPage();
|
||||
const errors = [];
|
||||
page.on('pageerror', error => errors.push(error.message));
|
||||
const response = await page.goto(`${base}/eldorado-v1/documentation/strategy/roadmap/`, {waitUntil:'networkidle'});
|
||||
assert.equal(response.status(), 200);
|
||||
const panel = page.locator('.archify-panel--story[data-diagram="strategy-roadmap"]');
|
||||
const iframe = panel.locator('.story-mobile');
|
||||
assert(await iframe.isVisible(), `${width}: vertical Roadmap iframe must be visible`);
|
||||
assert(!await panel.locator('.story-desktop').isVisible(), `${width}: horizontal Roadmap must be hidden`);
|
||||
const frame = await (await iframe.elementHandle()).contentFrame();
|
||||
await frame.locator('svg[role="img"]').waitFor();
|
||||
const geometry = await frame.locator('svg[role="img"]').evaluate(svg => ({
|
||||
width:innerWidth, height:innerHeight,
|
||||
overflow:document.documentElement.scrollWidth > innerWidth || document.documentElement.scrollHeight > innerHeight,
|
||||
nodes:[...svg.querySelectorAll('[data-node-id]')].map(node => ({
|
||||
id:node.dataset.nodeId, box:node.querySelector('rect').getBoundingClientRect().toJSON(),
|
||||
text:[...node.querySelectorAll('text')].map(t => ({text:t.textContent, box:t.getBoundingClientRect().toJSON(), size:parseFloat(getComputedStyle(t).fontSize)*t.getScreenCTM().a}))
|
||||
})).sort((a,b) => a.box.y-b.box.y || a.box.x-b.box.x)
|
||||
}));
|
||||
assert.deepEqual(geometry.nodes.map(n => n.id), ['skills','autonomy']);
|
||||
for (const [index, card] of geometry.nodes.entries()) {
|
||||
assert(card.text.length > 0, `${width}: missing text in ${card.id}`);
|
||||
assert(card.box.left >= 0 && card.box.top >= 0 && card.box.right <= geometry.width + 1 && card.box.bottom <= geometry.height + 1, `${width}: card outside iframe: ${card.id}`);
|
||||
for (const t of card.text) {
|
||||
assert(t.box.left >= card.box.left && t.box.right <= card.box.right + 1 && t.box.top >= card.box.top && t.box.bottom <= card.box.bottom + 1, `${width}: clipped ${card.id} ${t.text}`);
|
||||
assert(t.size >= 11, `${width}: small ${card.id} ${t.text}: ${t.size}`);
|
||||
}
|
||||
if (index) {
|
||||
const previous = geometry.nodes[index - 1].box;
|
||||
assert.equal(previous.x, card.box.x);
|
||||
assert(previous.bottom < card.box.top, `${width}: stages must flow vertically`);
|
||||
}
|
||||
}
|
||||
assert(!geometry.overflow, `${width}: iframe overflow`);
|
||||
assert(!await page.evaluate(() => document.documentElement.scrollWidth > innerWidth), `${width}: page overflow`);
|
||||
assert.deepEqual(errors, []);
|
||||
results.push({width, geometry, responsiveReadability:true});
|
||||
fs.writeFileSync(`${output}/results.json`, JSON.stringify(results,null,2));
|
||||
} finally {await context.close();}
|
||||
}
|
||||
for (const width of [1440, 390, 320]) {
|
||||
const context = await browser.newContext({viewport:{width,height:1000}, colorScheme:'light'});
|
||||
const page = await context.newPage();
|
||||
@@ -17,42 +61,75 @@ const fs = require('node:fs');
|
||||
assert.equal(response.status(), 200);
|
||||
assert.equal(await page.locator('h1').innerText(), 'Roadmap');
|
||||
const headings = page.locator('.strategy-content > h2');
|
||||
assert.deepEqual((await headings.allTextContents()).map(s => s.replace(/\u200b/g, '')), ['1. Understand code quality and delivery','2. Fix critical readiness gaps','3. Run a bounded pilot','4. Expand only on evidence','5. Sustain and improve']);
|
||||
assert.deepEqual((await headings.allTextContents()).map(s => s.replace(/\u200b/g, '')), ['Two stages toward Target','Stage 1: Delivery first','Improve within each phase','Delivery in practice']);
|
||||
const text = await page.locator('.strategy-content').innerText();
|
||||
for (const marker of ['baseline findings', 'process map', 'prioritized gaps', 'alongside the pilot', 'Recommended sequence']) assert(text.includes(marker), marker);
|
||||
for (const marker of ['Humans direct, guide and review throughout', 'Delivery keeps improving', 'system-logic source', 'baseline', 'Target operating model']) assert(text.includes(marker), marker);
|
||||
assert(!text.includes('Supporting gate evidence and hold conditions\n\nThese are'));
|
||||
if (width < 700) await page.getByRole('button', {name:'Toggle navigation bar'}).click();
|
||||
const menu = page.locator('.theme-doc-sidebar-menu .menu__link').filter({visible:true});
|
||||
await menu.first().waitFor({state:'visible'});
|
||||
assert.deepEqual((await menu.allTextContents()).slice(0,2), ['Target','Roadmap']);
|
||||
if (width < 700) await page.getByRole('button', {name:'Close navigation bar'}).click();
|
||||
const panel = page.locator('.archify-panel--story');
|
||||
const panel = page.locator('.archify-panel--story').first();
|
||||
const iframe = panel.locator(width > 700 ? '.story-desktop' : '.story-mobile');
|
||||
await iframe.scrollIntoViewIfNeeded();
|
||||
const frame = await (await iframe.elementHandle()).contentFrame();
|
||||
await frame.locator('svg[role="img"]').waitFor();
|
||||
const checkCards = async () => {
|
||||
const cards = await frame.locator('svg[role="img"] [data-node-id]').evaluateAll(nodes => nodes.map(node => {
|
||||
const box = node.querySelector('rect').getBoundingClientRect();
|
||||
return {id:node.dataset.nodeId, box:box.toJSON(), text:[...node.querySelectorAll('text')].map(t => ({text:t.textContent, box:t.getBoundingClientRect().toJSON(), size:parseFloat(getComputedStyle(t).fontSize)*t.getScreenCTM().a}))};
|
||||
}));
|
||||
for (const card of cards) for (const t of card.text) {
|
||||
assert(t.box.left >= card.box.left && t.box.right <= card.box.right + 1 && t.box.top >= card.box.top && t.box.bottom <= card.box.bottom + 1, `${width}: clipped ${card.id} ${t.text}`);
|
||||
assert(t.size >= 11, `${width}: small ${card.id} ${t.text}: ${t.size}`);
|
||||
}
|
||||
return cards;
|
||||
};
|
||||
await checkCards();
|
||||
const geometry = await frame.locator('svg[role="img"]').evaluate(svg => ({
|
||||
nodes:[...svg.querySelectorAll('[data-node-id]')].map(n => ({id:n.dataset.nodeId,...n.getBoundingClientRect().toJSON()})),
|
||||
nodes:[...svg.querySelectorAll('[data-node-id]')].map(n => ({id:n.dataset.nodeId,...n.getBoundingClientRect().toJSON()})).sort((a,b) => a.y-b.y || a.x-b.x),
|
||||
width:innerWidth, height:innerHeight,
|
||||
minLabel:Math.min(...[...svg.querySelectorAll('text[data-node-label]')].map(n => parseFloat(getComputedStyle(n).fontSize)*n.getScreenCTM().a))
|
||||
}));
|
||||
assert.deepEqual(geometry.nodes.map(n => n.id), ['assessment','readiness','pilot','expansion','sustain']);
|
||||
assert.deepEqual(geometry.nodes.map(n => n.id), ['skills','autonomy']);
|
||||
for (const n of geometry.nodes) assert(n.x >= 0 && n.y >= 0 && n.right <= geometry.width + 1 && n.bottom <= geometry.height + 1);
|
||||
assert(geometry.minLabel >= 10, `readable node labels: ${geometry.minLabel}`);
|
||||
for (let i=1; i<geometry.nodes.length; i++) {
|
||||
const a=geometry.nodes[i-1], b=geometry.nodes[i];
|
||||
if(width > 700) {assert.equal(a.y,b.y); assert(a.right < b.x);}
|
||||
else {assert.equal(a.x,b.x); assert(a.bottom < b.y);}
|
||||
}
|
||||
// Portal -> diagram and diagram -> portal are both part of the contract.
|
||||
if (width <= 700) await page.getByRole('button', {name:'Toggle navigation bar'}).click();
|
||||
for (let attempt=0; attempt<3; attempt++) {
|
||||
await page.getByRole('button', {name:/Switch between dark and light mode/}).filter({visible:true}).click();
|
||||
if (await page.locator('html').getAttribute('data-theme') === 'dark') break;
|
||||
}
|
||||
if (width <= 700) await page.getByRole('button', {name:'Close navigation bar'}).click();
|
||||
await frame.waitForFunction(() => document.documentElement.dataset.theme === 'dark');
|
||||
await frame.locator('#btn-theme').click();
|
||||
await page.waitForFunction(() => document.documentElement.dataset.theme === 'light');
|
||||
await frame.locator('#btn-theme').click();
|
||||
await page.waitForFunction(() => document.documentElement.dataset.theme === 'dark');
|
||||
await checkCards();
|
||||
await frame.locator('#btn-theme').click();
|
||||
await page.waitForFunction(() => document.documentElement.dataset.theme === 'light');
|
||||
for (const preset of ['blueprint','classic']) {
|
||||
await frame.locator('#btn-preset').click();
|
||||
await frame.locator(`[data-preset-value="${preset}"]`).click();
|
||||
assert.equal(await frame.locator('html').getAttribute('data-preset'), preset);
|
||||
await checkCards();
|
||||
}
|
||||
await frame.locator('#btn-export').click();
|
||||
const [download] = await Promise.all([page.waitForEvent('download'), frame.locator('[data-format="svg"]').click()]);
|
||||
assert.equal(await download.failure(), null);
|
||||
await download.saveAs(`${output}/${width}.svg`);
|
||||
assert(fs.readFileSync(`${output}/${width}.svg`, 'utf8').includes('Assess current state'));
|
||||
assert(fs.readFileSync(`${output}/${width}.svg`, 'utf8').includes('Adopt skills'));
|
||||
assert(fs.readFileSync(`${output}/${width}.svg`, 'utf8').includes('eldorado-roadmap-typography'));
|
||||
for (const id of ['skills','autonomy']) {
|
||||
await frame.locator(`svg[role="img"] [data-node-id="${id}"]`).screenshot({path:`${output}/${width}-${id}-card.png`});
|
||||
}
|
||||
const opener = panel.getByRole('button', {name:/^Expand /});
|
||||
await opener.click();
|
||||
const close = panel.getByRole('button', {name:'Close full-screen diagram', exact:true});
|
||||
@@ -67,8 +144,9 @@ const fs = require('node:fs');
|
||||
await headings.first().scrollIntoViewIfNeeded();
|
||||
await page.screenshot({path:`${output}/${width}-assessment.png`});
|
||||
await page.screenshot({path:`${output}/${width}-full.png`, fullPage:true});
|
||||
await page.locator('.strategy-content summary').click();
|
||||
assert(await page.locator('.strategy-content details').evaluate(n => n.open));
|
||||
await page.locator('.strategy-content summary').focus();
|
||||
await page.keyboard.press('Enter');
|
||||
await page.waitForFunction(() => document.querySelector('.strategy-content details').open);
|
||||
await page.locator('.strategy-content details p').last().waitFor({state:'visible'});
|
||||
assert((await page.locator('.strategy-content details').innerText()).includes('exact-artifact approvals'));
|
||||
const links = await page.locator('.strategy-content a').evaluateAll(nodes => nodes.filter(n => !n.classList.contains('hash-link')).map(n => n.href));
|
||||
@@ -81,6 +159,6 @@ const fs = require('node:fs');
|
||||
fs.writeFileSync(`${output}/results.json`, JSON.stringify(results,null,2));
|
||||
await context.close();
|
||||
}
|
||||
console.log(`PASS ${results.length} Roadmap viewports: visible stages/outputs, sidebar, diagram geometry, controls, export and links`);
|
||||
console.log(`PASS ${results.length} Roadmap viewports: three-level story, sidebar, diagram geometry, controls, export and links`);
|
||||
} finally {await browser.close();}
|
||||
})().catch(error => {console.error(error); process.exitCode = 1;});
|
||||
@@ -23,7 +23,7 @@ const fs = require('node:fs');
|
||||
if (width < 700) await page.getByRole('button', {name:'Toggle navigation bar'}).click();
|
||||
const menu = page.locator('.theme-doc-sidebar-menu .menu__link').filter({visible:true});
|
||||
await menu.first().waitFor({state:'visible'});
|
||||
assert.deepEqual(await menu.allTextContents(), ['Target', 'Roadmap', 'Skills governance', 'Skills quality', 'Skills adoption', 'Skills Measurement', 'Skills maintenance']);
|
||||
assert.deepEqual(await menu.allTextContents(), ['Target', 'Roadmap', 'Stage - 01 - Skills Adoption', 'Stage - 02 - Autonomous Agent']);
|
||||
assert((await menu.nth(0).getAttribute('href')).endsWith('/strategy/target-operating-model/'));
|
||||
assert((await menu.nth(1).getAttribute('href')).endsWith('/strategy/roadmap/'));
|
||||
assert.equal(await menu.filter({hasText:/^Target$/}).count(), 1);
|
||||
@@ -53,6 +53,9 @@ const fs = require('node:fs');
|
||||
assert.deepEqual(metrics.edges.map(e=>e.slice(0,2)), ids.map((id,i)=>[id,ids[(i+1)%ids.length]]));
|
||||
assert(metrics.edges.every(e=>e[2]?.startsWith('url(')), 'all stages must have arrowheads');
|
||||
assert.equal(metrics.nodes.length, 17);
|
||||
assert.equal(metrics.labels.filter(n => n.text === 'AI Agent').length, 8);
|
||||
assert(!metrics.labels.some(n => /code[ -]agent/i.test(n.text)));
|
||||
assert((await page.locator('.strategy-content').innerText()).includes('human-controlled AI Agent'));
|
||||
assert(!metrics.nodes.some(n=>n.id==='humans'));
|
||||
assert.equal(await frame.locator('[data-node-id="agent"] text').allTextContents().then(texts=>texts.includes('Human Controlled')), true);
|
||||
assert.equal(metrics.relationships.length, 24);
|
||||
@@ -74,6 +77,15 @@ const fs = require('node:fs');
|
||||
}
|
||||
assert(metrics.labels.every(n=>n.px>=14), JSON.stringify(metrics.labels));
|
||||
assert.deepEqual(metrics.overflow, []);
|
||||
await frame.locator('#btn-export').click();
|
||||
const [download] = await Promise.all([page.waitForEvent('download'), frame.locator('[data-format="svg"]').click()]);
|
||||
assert.equal(await download.failure(), null);
|
||||
const exportPath = `${output}/${width}-${route ? 'target' : 'landing'}.svg`;
|
||||
await download.saveAs(exportPath);
|
||||
const exported = fs.readFileSync(exportPath, 'utf8');
|
||||
assert.equal((exported.match(/>AI Agent<\/text>/g) || []).length, 8);
|
||||
assert(!/code[ -]agent/i.test(exported));
|
||||
assert(exported.includes('Autonomous agent') && exported.includes('Human Controlled'));
|
||||
assert(!await page.evaluate(()=>document.documentElement.scrollWidth>innerWidth));
|
||||
await page.evaluate(()=>scrollTo({top:0,behavior:'instant'}));
|
||||
await page.waitForFunction(()=>scrollY===0);
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
const {chromium} = require('playwright');
|
||||
const assert = require('node:assert/strict');
|
||||
const fs = require('node:fs');
|
||||
(async () => {
|
||||
const base = process.argv[2] || 'http://127.0.0.1:4173';
|
||||
const output = `.cache/sidebar-browser-${process.argv[3] || 'local'}`;
|
||||
const {documents} = JSON.parse(fs.readFileSync('.cache/sidebar-coverage.json', 'utf8'));
|
||||
assert(documents.length > 0);
|
||||
fs.mkdirSync(output, {recursive:true});
|
||||
const browser = await chromium.launch({headless:true, executablePath:process.env.PLAYWRIGHT_CHROMIUM_EXECUTABLE, args:['--no-sandbox']});
|
||||
const results = [];
|
||||
try {
|
||||
for (const width of [1440,390,320]) {
|
||||
const context = await browser.newContext({viewport:{width,height:900}});
|
||||
try {
|
||||
const page = await context.newPage();
|
||||
const errors = [];
|
||||
page.on('pageerror', e => errors.push(e.message));
|
||||
const menu = page.locator('.theme-doc-sidebar-menu').filter({visible:true});
|
||||
const open = async () => {
|
||||
if (width < 997) await page.getByRole('button', {name:'Toggle navigation bar'}).click();
|
||||
await menu.waitFor();
|
||||
};
|
||||
for (const doc of documents) {
|
||||
assert.equal((await page.goto(`${base}${doc.route}/`, {waitUntil:'networkidle'})).status(), 200);
|
||||
await page.locator('article h1').waitFor();
|
||||
await open();
|
||||
const links = menu.locator('a[href]:not([role="button"])').filter({visible:true});
|
||||
const active = await links.evaluateAll((nodes, route) => nodes.filter(n => n.pathname.replace(/\/$/,'') === route).map(n => n.textContent), doc.route);
|
||||
assert.equal(active.length, 1, `${width}: visible unique owning-sidebar entry for ${doc.route}`);
|
||||
results.push({width, route:doc.route, visibleEntry:active[0]});
|
||||
}
|
||||
// Contribution exposes all legacy maintenance pages without changing routes.
|
||||
for (const [label, route] of [['Starting point','overview'],['Update and publish','maintain'],['Site configuration','reference']]) {
|
||||
await page.goto(`${base}/eldorado-v1/documentation/contribution/`, {waitUntil:'networkidle'});
|
||||
await open();
|
||||
const toggle = menu.getByRole('button', {name:'Portal maintenance', exact:true});
|
||||
await toggle.focus();
|
||||
await page.keyboard.press('Enter');
|
||||
await menu.getByRole('link', {name:label, exact:true}).click();
|
||||
await page.waitForURL(`${base}/eldorado-v1/documentation/docs/${route}/`);
|
||||
await page.locator('article h1').waitFor();
|
||||
}
|
||||
const reference = '/eldorado-v1/documentation/strategy/reference/measurement-contracts/';
|
||||
await page.goto(`${base}${reference}#supported-bundle-coverage`, {waitUntil:'networkidle'});
|
||||
await page.waitForURL(`${base}/eldorado-v1/documentation/strategy/measurement/supported-bundle-coverage/`);
|
||||
await page.getByRole('heading', {level:1, name:'Supported bundle coverage', exact:true}).waitFor();
|
||||
assert((await page.locator('article').innerText()).includes('Supported bundle coverage'));
|
||||
assert.equal(await page.locator('.breadcrumbs a').filter({hasText:'Stage - 01 - Skills Adoption'}).getAttribute('href'), '/eldorado-v1/documentation/strategy/stage-01-skills-adoption/');
|
||||
assert((await page.locator('.breadcrumbs').innerText()).includes('Measurement'));
|
||||
await open();
|
||||
await menu.getByRole('link', {name:'Supported bundle coverage', exact:true}).waitFor({state:'visible'});
|
||||
await page.screenshot({path:`${output}/${width}-reference.png`, animations:'disabled'});
|
||||
assert.deepEqual(errors, []);
|
||||
} finally {await context.close();}
|
||||
}
|
||||
assert.equal(results.length, documents.length * 3);
|
||||
fs.writeFileSync(`${output}/results.json`, JSON.stringify(results,null,2));
|
||||
console.log(`PASS: all ${documents.length} docs have visible unique sidebar entries at 3 viewports; Contribution links, Measurement breadcrumbs and reported anchor redirect work`);
|
||||
} finally {await browser.close();}
|
||||
})().catch(e => {console.error(e); process.exitCode = 1;});
|
||||
@@ -0,0 +1,51 @@
|
||||
const {chromium}=require('playwright');
|
||||
const fs=require('node:fs');
|
||||
const path=require('node:path');
|
||||
const assert=require('node:assert/strict');
|
||||
(async()=>{
|
||||
const dir=process.argv[2]||'.cache/skills-candidate';
|
||||
const browser=await chromium.launch({executablePath:process.env.PLAYWRIGHT_CHROMIUM_EXECUTABLE,args:['--no-sandbox']});
|
||||
const results=[];
|
||||
try {
|
||||
for(const topic of ['measurement','baseline','governance','quality','adoption','maintenance','stage01','stage02']) for(const width of [1440,1024,390,320]){
|
||||
const spec=JSON.parse(fs.readFileSync(`diagrams/strategy-${topic}${width<=1100?'-mobile':''}.architecture.json`));
|
||||
const page=await browser.newPage({viewport:{width:1200,height:1000}});
|
||||
await page.goto('file://'+path.resolve(`${dir}/${topic}-${width}.svg`));
|
||||
const measured=await page.locator('svg').evaluate(svg=>{
|
||||
const v=svg.viewBox.baseVal;const issues=[];
|
||||
for(const el of svg.querySelectorAll('[data-node-id],path[data-edge-id],g[data-edge-id]')){
|
||||
const b=el.getBBox();if(b.x<v.x-1||b.y<v.y-1||b.x+b.width>v.x+v.width+1||b.y+b.height>v.y+v.height+1)issues.push(el.getAttribute('data-node-id')||el.getAttribute('data-edge-id'));
|
||||
}
|
||||
// Measure the whole rendered label group, including its opaque mask:
|
||||
// text presence alone cannot detect one label hiding another.
|
||||
const labels=[...svg.querySelectorAll('g[data-edge-id]')].filter(el=>el.querySelector('text')).map(el=>({id:el.dataset.edgeId,box:el.getBoundingClientRect()}));
|
||||
const labelOverlaps=[];
|
||||
const nodes=[...svg.querySelectorAll('[data-node-id]')].map(el=>({id:el.dataset.nodeId,box:el.getBoundingClientRect()}));
|
||||
const labelNodeOverlaps=[];
|
||||
for(const a of labels)for(const b of nodes){
|
||||
if(Math.min(a.box.right,b.box.right)>Math.max(a.box.left,b.box.left)&&Math.min(a.box.bottom,b.box.bottom)>Math.max(a.box.top,b.box.top))labelNodeOverlaps.push([a.id,b.id]);
|
||||
}
|
||||
for(let i=0;i<labels.length;i++)for(let j=i+1;j<labels.length;j++){
|
||||
const a=labels[i],b=labels[j];
|
||||
if(Math.min(a.box.right,b.box.right)>Math.max(a.box.left,b.box.left)&&Math.min(a.box.bottom,b.box.bottom)>Math.max(a.box.top,b.box.top))labelOverlaps.push([a.id,b.id]);
|
||||
}
|
||||
return {labelOverlaps,labelNodeOverlaps,viewBox:[v.width,v.height],nodes:[...svg.querySelectorAll('[data-node-id]')].map(n=>n.dataset.nodeId),edges:[...svg.querySelectorAll('path[data-edge-id]')].map(n=>n.dataset.edgeId),text:svg.textContent,issues};
|
||||
});
|
||||
assert.deepEqual(measured.viewBox,spec.meta.viewBox);
|
||||
assert.deepEqual(measured.nodes.sort(),spec.components.map(n=>n.id).sort());
|
||||
assert.deepEqual(measured.edges.sort(),spec.connections.map(e=>e.id).sort());
|
||||
assert.deepEqual(measured.issues,[]);
|
||||
assert.deepEqual(measured.labelOverlaps,[],`${topic}-${width}: rendered edge labels overlap`);
|
||||
assert.deepEqual(measured.labelNodeOverlaps,[],`${topic}-${width}: edge label obscures a node`);
|
||||
for(const n of spec.components){assert(measured.text.includes(n.label));assert(measured.text.includes(n.tag));for(const line of n.sublabel.split('\n'))assert(measured.text.includes(line));}
|
||||
for(const e of spec.connections)if(e.label)assert(measured.text.includes(e.label));
|
||||
if(width===1440){
|
||||
await page.setViewportSize({width:spec.meta.viewBox[0],height:spec.meta.viewBox[1]});
|
||||
await page.screenshot({path:`${dir}/${topic}-standalone-export.png`});
|
||||
}
|
||||
results.push({topic,width,nodes:measured.nodes.length,edges:measured.edges.length,complete:true});await page.close();
|
||||
}
|
||||
fs.writeFileSync(`${dir}/export-results.json`,JSON.stringify(results,null,2));
|
||||
console.log(`PASS ${results.length} standalone SVGs: exact graph, text, full-canvas containment and non-overlapping edge labels`);
|
||||
}finally{await browser.close();}
|
||||
})().catch(e=>{console.error(e);process.exitCode=1});
|
||||
@@ -17,12 +17,18 @@ const fs = require('node:fs');
|
||||
assert.equal(response.status(), 200);
|
||||
assert.equal(await page.locator('h1').innerText(), 'Skills Measurement');
|
||||
assert((await page.title()).startsWith('Skills Measurement |'));
|
||||
assert.equal(await page.locator('.strategy-content details').count(), 0);
|
||||
assert.equal(await page.locator('.strategy-content h2').count(), 4);
|
||||
assert.equal(await page.locator('.strategy-content details').count(), 1);
|
||||
assert.equal(await page.locator('.strategy-content details[open]').count(), 0);
|
||||
assert((await page.locator('.strategy-content details summary').innerText()).includes('Implementation status'));
|
||||
assert.equal(await page.locator('.strategy-content h2').count(), 2);
|
||||
assert.deepEqual((await page.locator('.strategy-content h3').allTextContents()).map(text => text.replaceAll('\u200b', '')), ['Workflow effectiveness', 'Skills effectiveness & health']);
|
||||
assert.equal(await page.locator('.strategy-content ol').count(), 2);
|
||||
assert.equal(await page.locator('.strategy-content ol > li').count(), 16);
|
||||
if (width < 700) await page.getByRole('button', {name:'Toggle navigation bar'}).click();
|
||||
const menu = page.locator('.theme-doc-sidebar-menu .menu__link').filter({visible:true});
|
||||
await menu.first().waitFor({state:'visible'});
|
||||
assert.deepEqual(await menu.allTextContents(), ['Target','Roadmap','Skills governance','Skills quality','Skills adoption','Skills Measurement','Skills maintenance']);
|
||||
const metrics = JSON.parse(fs.readFileSync('research/ai-adoption/measurement-migration.json','utf8')).metrics;
|
||||
assert.deepEqual(await menu.allTextContents(), ['Target','Roadmap','Stage - 01 - Skills Adoption','Measurement',...metrics.map(m => m.title),'Collection and safeguards','Run the synthetic measurement example','Baseline','Governance','Quality','Adoption','Maintenance','Stage - 02 - Autonomous Agent']);
|
||||
if (width < 700) await page.getByRole('button', {name:'Close navigation bar'}).click();
|
||||
const panel = page.locator('.archify-panel--story');
|
||||
const iframe = panel.locator(width > 700 ? '.story-desktop' : '.story-mobile');
|
||||
@@ -33,14 +39,14 @@ const fs = require('node:fs');
|
||||
const nodes = [...svg.querySelectorAll('[data-node-id]')].map(n => n.getBoundingClientRect().toJSON());
|
||||
return {nodes, width:innerWidth, height:innerHeight, minLabel:Math.min(...[...svg.querySelectorAll('text[data-node-label]')].map(n => parseFloat(getComputedStyle(n).fontSize)*n.getScreenCTM().a))};
|
||||
});
|
||||
assert.equal(geometry.nodes.length, 6);
|
||||
assert.equal(geometry.nodes.length, JSON.parse(fs.readFileSync('diagrams/strategy-measurement.architecture.json')).components.length);
|
||||
for (const n of geometry.nodes) assert(n.x >= 0 && n.y >= 0 && n.right <= geometry.width + 1 && n.bottom <= geometry.height + 1);
|
||||
assert(geometry.minLabel >= 10, `readable node labels: ${geometry.minLabel}`);
|
||||
await frame.locator('#btn-theme').click();
|
||||
await page.waitForFunction(() => document.documentElement.dataset.theme === 'dark');
|
||||
await frame.locator('#btn-theme').click();
|
||||
await page.waitForFunction(() => document.documentElement.dataset.theme === 'light');
|
||||
for (const preset of ['blueprint','classic']) {
|
||||
for (const preset of ['signal-flow','blueprint','editorial','classic']) {
|
||||
await frame.locator('#btn-preset').click();
|
||||
await frame.locator(`[data-preset-value="${preset}"]`).click();
|
||||
assert.equal(await frame.locator('html').getAttribute('data-preset'), preset);
|
||||
@@ -50,7 +56,30 @@ const fs = require('node:fs');
|
||||
assert.equal(await download.failure(), null);
|
||||
const path = `${output}/${width}.svg`; await download.saveAs(path);
|
||||
const svg = fs.readFileSync(path, 'utf8');
|
||||
assert(svg.includes('Establish baseline') && svg.includes('Ongoing monitoring'));
|
||||
assert(svg.includes('Workflow effectiveness') && svg.includes('Skills effectiveness & health') && svg.includes('No mandatory collection'));
|
||||
const exports = ['svg'];
|
||||
for (const format of ['png','jpeg','webp','svg-light','svg-dark','webm']) {
|
||||
await frame.locator('#btn-export').click();
|
||||
const option = frame.locator(`[data-format="${format}"]`);
|
||||
if (await option.isDisabled()) { exports.push(`${format}:unsupported`); await frame.locator('#btn-export').click(); continue; }
|
||||
const [file] = await Promise.all([page.waitForEvent('download', {timeout:60000}), option.click()]);
|
||||
assert.equal(await file.failure(), null);
|
||||
const target = `${output}/${width}-${format}-${file.suggestedFilename()}`;
|
||||
await file.saveAs(target);
|
||||
const bytes = fs.readFileSync(target); assert(bytes.length > 1000);
|
||||
if (format.startsWith('svg')) assert(bytes.toString().includes('eldorado-skills-typography'));
|
||||
else {
|
||||
const mime = {png:'image/png', jpeg:'image/jpeg', webp:'image/webp', webm:'video/webm'}[format];
|
||||
const dimensions = await page.evaluate(async ({mime,data}) => {
|
||||
const media = document.createElement(mime.startsWith('video') ? 'video' : 'img');
|
||||
const ready = new Promise((resolve,reject) => {media[mime.startsWith('video') ? 'onloadedmetadata' : 'onload'] = resolve; media.onerror = reject;});
|
||||
media.src = `data:${mime};base64,${data}`; await ready;
|
||||
return [media.videoWidth || media.naturalWidth, media.videoHeight || media.naturalHeight];
|
||||
}, {mime, data:bytes.toString('base64')});
|
||||
assert(dimensions.every(n => n > 0));
|
||||
}
|
||||
exports.push(format);
|
||||
}
|
||||
const opener = panel.getByRole('button', {name:/^Expand /});
|
||||
await opener.click();
|
||||
const close = panel.getByRole('button', {name:'Close full-screen diagram', exact:true});
|
||||
@@ -65,21 +94,20 @@ const fs = require('node:fs');
|
||||
await page.locator('.strategy-content h2').nth(1).scrollIntoViewIfNeeded();
|
||||
await page.screenshot({path:`${output}/${width}-pilot.png`});
|
||||
await page.screenshot({path:`${output}/${width}-full.png`, fullPage:true});
|
||||
const links = await page.locator('.strategy-content a[href*="measurement-contracts"]').evaluateAll(nodes => nodes.map(n => n.href));
|
||||
const links = await page.locator('.strategy-content a[href*="/measurement/"]').evaluateAll(nodes => nodes.map(n => n.href));
|
||||
for (const href of [...new Set(links)]) {
|
||||
const navigation = await page.goto(href, {waitUntil:'networkidle'});
|
||||
if (navigation) assert.equal(navigation.status(), 200);
|
||||
assert.equal(page.url(), href);
|
||||
if (new URL(href).hash) await page.locator(new URL(href).hash).waitFor({state:'visible'});
|
||||
}
|
||||
assert.equal(await page.locator('.strategy-content h3').count(), 19);
|
||||
assert((await page.locator('.strategy-content').innerText()).includes('9 prototype calculations and 7 unimplemented metrics'));
|
||||
assert.equal(new Set(links.map(h => new URL(h).pathname)).size, 18);
|
||||
assert(!await page.evaluate(() => document.documentElement.scrollWidth > innerWidth));
|
||||
assert.deepEqual(errors, []);
|
||||
results.push({width, geometry, links:links.length, title:true, sidebar:true, controls:true, export:true, reference:true});
|
||||
results.push({width, geometry, links:links.length, title:true, sidebar:true, controls:true, exports, reference:true});
|
||||
fs.writeFileSync(`${output}/results.json`, JSON.stringify(results,null,2));
|
||||
await context.close();
|
||||
}
|
||||
console.log(`PASS ${results.length} Skills Measurement viewports: title/sidebar, open plan, diagram geometry/controls/export, all reference links and no page errors`);
|
||||
console.log(`PASS ${results.length} Skills Measurement viewports: title/sidebar, optional registry, diagram geometry/controls/export, all reference links and no page errors`);
|
||||
} finally {await browser.close();}
|
||||
})().catch(error => {console.error(error); process.exitCode = 1;});
|
||||
@@ -0,0 +1,60 @@
|
||||
const {chromium}=require('playwright');
|
||||
const fs=require('node:fs');
|
||||
const assert=require('node:assert/strict');
|
||||
(async()=>{
|
||||
const base=process.argv[2]||'http://127.0.0.1:4173';
|
||||
const out=`.cache/skills-${process.argv[3]||'candidate'}`;fs.mkdirSync(out,{recursive:true});
|
||||
const browser=await chromium.launch({executablePath:process.env.PLAYWRIGHT_CHROMIUM_EXECUTABLE,args:['--no-sandbox']}); const results=[];
|
||||
try {
|
||||
for(const topic of ['measurement','baseline','governance','quality','adoption','maintenance','stage01','stage02']) for(const width of [1440,1024,390,320]) {
|
||||
console.log(`Checking ${topic} at ${width}px`);
|
||||
const page=await browser.newPage({viewport:{width,height:900},colorScheme:'light'});const errors=[];page.on('pageerror',e=>errors.push(e.message));
|
||||
const route=topic==='stage01'?'stage-01-skills-adoption':topic==='stage02'?'stage-02-autonomous-agent':['measurement','baseline'].includes(topic)?topic:`skills-${topic}`;
|
||||
assert.equal((await page.goto(`${base}/eldorado-v1/documentation/strategy/${route}/`,{waitUntil:'networkidle'})).status(),200);
|
||||
const panel=page.locator('.archify-panel--skills');assert.equal(await panel.count(),1);
|
||||
const iframe=panel.locator(width>1100?'.story-desktop':'.story-mobile');await iframe.scrollIntoViewIfNeeded();
|
||||
const frame=await(await iframe.elementHandle()).contentFrame();await frame.locator('svg[role="img"]').waitFor();
|
||||
// Keep iframe controls below the fixed portal header. Frame-local click
|
||||
// actionability cannot detect an overlay in the parent document.
|
||||
const showControls=async()=>{
|
||||
await panel.locator('dialog iframe').waitFor({state:'detached'});
|
||||
await panel.evaluate(n=>{
|
||||
scrollTo({top:n.getBoundingClientRect().top+scrollY-100,behavior:'instant'});
|
||||
return new Promise(resolve=>requestAnimationFrame(()=>requestAnimationFrame(resolve)));
|
||||
});
|
||||
};
|
||||
const geometry=await frame.locator('svg[role="img"]').evaluate(svg=>{
|
||||
const nodes=[...svg.querySelectorAll('g[data-node-id]')];const issues=[];let min=Infinity;
|
||||
for(const n of nodes){const rect=n.querySelector('rect').getBBox();for(const t of n.querySelectorAll('text')){
|
||||
const b=t.getBBox();min=Math.min(min,parseFloat(getComputedStyle(t).fontSize)*t.getScreenCTM().a);
|
||||
if(b.x<rect.x||b.y<rect.y||b.x+b.width>rect.x+rect.width||b.y+b.height>rect.y+rect.height)issues.push(n.id+':'+t.textContent);
|
||||
}}
|
||||
return {nodes:nodes.length,min,issues,width:innerWidth,svgWidth:svg.getBoundingClientRect().width};
|
||||
});
|
||||
const source=JSON.parse(fs.readFileSync(`diagrams/strategy-${topic}.architecture.json`));
|
||||
assert.equal(geometry.nodes,source.components.length);assert.deepEqual(geometry.issues,[]);assert(geometry.min>=10,JSON.stringify(geometry));
|
||||
for(const theme of ['light','dark']){
|
||||
await showControls();
|
||||
if(await frame.locator('html').getAttribute('data-theme')!==theme)await frame.locator('#btn-theme').click();
|
||||
await page.waitForFunction(t=>document.documentElement.dataset.theme===t,theme).catch(error=>{throw new Error(`${topic}/${width}/${theme}: theme synchronization failed`,{cause:error});});
|
||||
await panel.scrollIntoViewIfNeeded();await page.screenshot({path:`${out}/${topic}-${width}-${theme}-inline.png`});
|
||||
const open=panel.getByRole('button',{name:/^Expand /});await open.click();const close=panel.getByRole('button',{name:'Close full-screen diagram',exact:true});await close.waitFor({state:'visible'});
|
||||
const expanded=await(await panel.locator('dialog iframe').elementHandle()).contentFrame();await expanded.locator('svg[role="img"]').waitFor();
|
||||
await expanded.waitForFunction(t=>document.documentElement.dataset.theme===t,theme);
|
||||
await panel.locator('dialog').evaluate(n=>n.scrollTop=0);
|
||||
assert((await expanded.url()).includes(width<=1100?`${topic}-mobile/`:`${topic}/`));
|
||||
await page.screenshot({path:`${out}/${topic}-${width}-${theme}-fullscreen.png`});
|
||||
if(width<=700){await page.setViewportSize({width,height:480});assert(await panel.locator('dialog').evaluate(n=>n.scrollHeight>n.clientHeight));await panel.locator('dialog').evaluate(n=>n.scrollTop=n.scrollHeight);await page.screenshot({path:`${out}/${topic}-${width}-${theme}-short-bottom.png`});await page.setViewportSize({width,height:900});}
|
||||
await close.focus();await page.keyboard.press('Escape');assert(await open.evaluate(n=>n===document.activeElement));
|
||||
}
|
||||
await showControls();
|
||||
await frame.locator('#btn-preset').click();await frame.locator('[data-preset-value="blueprint"]').click();
|
||||
await frame.locator('#btn-preset').click();await frame.locator('[data-preset-value="classic"]').click();
|
||||
await frame.locator('#btn-export').click();const [download]=await Promise.all([page.waitForEvent('download'),frame.locator('[data-format="svg"]').click()]);assert.equal(await download.failure(),null);
|
||||
await download.saveAs(`${out}/${topic}-${width}.svg`);assert(fs.readFileSync(`${out}/${topic}-${width}.svg`,'utf8').includes('eldorado-skills-typography'));
|
||||
assert(!await page.evaluate(()=>document.documentElement.scrollWidth>innerWidth));assert.deepEqual(errors,[]);
|
||||
results.push({topic,width,geometry,controls:true,export:true,themes:true,fullscreen:true});fs.writeFileSync(`${out}/results.json`,JSON.stringify(results,null,2));await page.close();
|
||||
}
|
||||
console.log(`PASS ${results.length} Skills story contexts: geometry, themes, controls, exports, fullscreen and short-phone scrolling`);
|
||||
}finally{await browser.close();}
|
||||
})().catch(e=>{console.error(e);process.exitCode=1});
|
||||
@@ -0,0 +1,105 @@
|
||||
const {chromium} = require('playwright');
|
||||
const assert = require('node:assert/strict');
|
||||
const fs = require('node:fs');
|
||||
(async () => {
|
||||
const base = process.argv[2] || 'http://127.0.0.1:4173';
|
||||
const output = `.cache/strategy-navigation-${process.argv[3] || 'local'}`;
|
||||
fs.mkdirSync(output, {recursive:true});
|
||||
const prefix = '/eldorado-v1/documentation/strategy/';
|
||||
const first = 'Stage - 01 - Skills Adoption';
|
||||
const second = 'Stage - 02 - Autonomous Agent';
|
||||
const topics = ['Measurement','Baseline','Governance','Quality','Adoption','Maintenance'];
|
||||
const metrics = JSON.parse(fs.readFileSync('research/ai-adoption/measurement-migration.json','utf8')).metrics;
|
||||
const childIds = [...metrics.map(m => m.docId),'measurement/collection-and-safeguards','measurement/synthetic-example'];
|
||||
const childTitles = [...metrics.map(m => m.title),'Collection and safeguards','Run the synthetic measurement example'];
|
||||
const ids = ['target-operating-model','roadmap','stage-01-skills-adoption','measurement',...childIds,'baseline','skills-governance','skills-quality','skills-adoption','skills-maintenance','stage-02-autonomous-agent'];
|
||||
const titles = ['Target','Roadmap',first,'Skills Measurement',...childTitles,'Baseline','Skills governance','Skills quality','Skills adoption','Skills maintenance',second];
|
||||
const browser = await chromium.launch({headless:true, executablePath:process.env.PLAYWRIGHT_CHROMIUM_EXECUTABLE, args:['--no-sandbox']});
|
||||
const results = [];
|
||||
try {
|
||||
for (const width of [1440,1024,390,320]) {
|
||||
const context = await browser.newContext({viewport:{width,height:900}, colorScheme:'light'});
|
||||
try {
|
||||
const page = await context.newPage();
|
||||
const errors = [];
|
||||
page.on('pageerror', error => errors.push(error.message));
|
||||
const openMenu = async () => {
|
||||
if (width < 997) await page.getByRole('button', {name:'Toggle navigation bar'}).click();
|
||||
const menu = page.locator('.theme-doc-sidebar-menu').filter({visible:true});
|
||||
await menu.locator('.menu__link').first().waitFor({state:'visible'});
|
||||
return menu;
|
||||
};
|
||||
const closeMenu = async () => {
|
||||
if (width < 997) await page.getByRole('button', {name:'Close navigation bar'}).click();
|
||||
};
|
||||
assert.equal((await page.goto(`${base}${prefix}roadmap/`, {waitUntil:'networkidle'})).status(), 200);
|
||||
let menu = await openMenu();
|
||||
const visibleLabels = () => menu.locator('.menu__link').filter({visible:true}).allTextContents();
|
||||
assert.deepEqual(await visibleLabels(), ['Target','Roadmap',first,second]);
|
||||
const category = menu.locator('.theme-doc-sidebar-item-category').filter({has:page.getByRole('link', {name:first, exact:true})});
|
||||
const caret = category.locator(':scope > .menu__list-item-collapsible > button.menu__caret');
|
||||
await caret.click();
|
||||
await category.getByRole('link', {name:'Governance', exact:true}).waitFor({state:'visible'});
|
||||
assert.deepEqual(await visibleLabels(), ['Target','Roadmap',first,...topics,second]);
|
||||
assert.deepEqual(await category.locator('ul .menu__link').filter({visible:true}).allTextContents(), topics);
|
||||
const measurement = category.locator('.theme-doc-sidebar-item-category').filter({has:page.getByRole('link', {name:'Measurement', exact:true})});
|
||||
const reference = measurement.locator(':scope > .menu__list-item-collapsible > button.menu__caret');
|
||||
await reference.focus();
|
||||
await page.keyboard.press('Enter');
|
||||
await category.getByRole('link', {name:'Validated task success', exact:true}).waitFor({state:'visible'});
|
||||
assert.deepEqual(await visibleLabels(), ['Target','Roadmap',first,topics[0],...childTitles,...topics.slice(1),second]);
|
||||
await reference.click();
|
||||
await page.screenshot({path:`${output}/${width}-expanded.png`, animations:'disabled'});
|
||||
await caret.click();
|
||||
await category.getByRole('link', {name:'Governance', exact:true}).waitFor({state:'hidden'});
|
||||
assert.deepEqual(await visibleLabels(), ['Target','Roadmap',first,second]);
|
||||
await menu.getByRole('link', {name:first, exact:true}).click();
|
||||
await page.waitForURL(`${base}${prefix}stage-01-skills-adoption/`);
|
||||
await page.getByRole('heading', {level:1, name:first, exact:true}).waitFor();
|
||||
assert.equal(await page.locator('h1').innerText(), first);
|
||||
assert((await page.locator('article').innerText()).includes('Delivery first'));
|
||||
assert(!await page.evaluate(() => document.documentElement.scrollWidth > innerWidth));
|
||||
await page.screenshot({path:`${output}/${width}-stage-01.png`, fullPage:true, animations:'disabled'});
|
||||
for (const [index, id] of ids.entries()) {
|
||||
assert.equal((await page.goto(`${base}${prefix}${id}/`, {waitUntil:'networkidle'})).status(), 200);
|
||||
assert.equal(new URL(page.url()).pathname, `${prefix}${id}/`);
|
||||
// Target has a longer canonical page heading but keeps its short navigation label.
|
||||
if (index) assert.equal(await page.locator('h1').innerText(), titles[index]);
|
||||
else assert((await page.locator('h1').innerText()).includes('Target'));
|
||||
const prev = page.locator('.pagination-nav__link--prev');
|
||||
const next = page.locator('.pagination-nav__link--next');
|
||||
if (index) assert.equal(await prev.getAttribute('href'), `${prefix}${id === 'baseline' ? 'measurement' : ids[index-1]}/`);
|
||||
else assert.equal(await prev.count(), 0);
|
||||
if (index < ids.length-1) assert.equal(await next.getAttribute('href'), `${prefix}${id === 'measurement' ? 'baseline' : ids[index+1]}/`);
|
||||
else assert.equal(await next.count(), 0);
|
||||
if (index >= 3 && index < ids.length - 1) {
|
||||
assert.equal(await page.locator('.breadcrumbs a').filter({hasText:first}).getAttribute('href'), `${prefix}stage-01-skills-adoption/`);
|
||||
menu = await openMenu();
|
||||
const expectedTopics = id === 'measurement' || id.startsWith('measurement/') ? [topics[0],...childTitles,...topics.slice(1)] : topics;
|
||||
assert.deepEqual(await visibleLabels(), ['Target','Roadmap',first,...expectedTopics,second]);
|
||||
if (id.startsWith('measurement/')) assert.equal(await page.locator('.breadcrumbs a').filter({hasText:'Measurement'}).getAttribute('href'), `${prefix}measurement/`);
|
||||
await closeMenu();
|
||||
}
|
||||
assert(!await page.evaluate(() => document.documentElement.scrollWidth > innerWidth), `${width}: overflow on ${id}`);
|
||||
if(width===1440 || width===390) {
|
||||
// Full-page capture does not trigger below-fold lazy iframes.
|
||||
for(const iframe of await page.locator('.archify-panel--story > iframe').filter({visible:true}).all()) {
|
||||
await iframe.scrollIntoViewIfNeeded();
|
||||
const frame=await (await iframe.elementHandle()).contentFrame();
|
||||
await frame.locator('.diagram-container > svg').waitFor();
|
||||
}
|
||||
await page.evaluate(()=>scrollTo({top:0,behavior:'instant'}));
|
||||
await page.screenshot({path:`${output}/${width}-${id.replaceAll('/','-')}.png`,fullPage:true,animations:'disabled'});
|
||||
}
|
||||
}
|
||||
assert((await page.locator('article').innerText()).includes('not deployed autonomy'));
|
||||
await page.screenshot({path:`${output}/${width}-stage-02.png`, fullPage:true, animations:'disabled'});
|
||||
assert.deepEqual(errors, []);
|
||||
results.push({width, routes:ids.length, linkedCategory:true, expandCollapse:true, nesting:true, breadcrumbs:true, pagination:true, overflow:false, errors});
|
||||
fs.writeFileSync(`${output}/results.json`, JSON.stringify(results,null,2));
|
||||
} finally {await context.close();}
|
||||
}
|
||||
assert.equal(results.length, 4);
|
||||
console.log(`PASS: 4 desktop/mobile viewports; all ${ids.length} routes; linked Measurement category, keyboard expansion, breadcrumbs, next/previous and no overflow/errors`);
|
||||
} finally {await browser.close();}
|
||||
})().catch(error => {console.error(error); process.exitCode = 1;});
|
||||
@@ -12,25 +12,30 @@ const fs=require('node:fs');
|
||||
const page=await context.newPage();
|
||||
for(const id of ['index','target-operating-model','skills-governance','skills-quality','skills-adoption','measurement','skills-maintenance','roadmap']){
|
||||
const response=await page.goto(`${base}/eldorado-v1/documentation/strategy/${id==='index'?'':id+'/'}`,{waitUntil:'networkidle'});assert.equal(response.status(),200);
|
||||
const panel=page.locator('.archify-panel--story');
|
||||
const panel=page.locator('.archify-panel--story').first();
|
||||
const iframe=panel.locator(width===390?'.story-mobile':'.story-desktop');await iframe.scrollIntoViewIfNeeded();
|
||||
const frame=await (await iframe.elementHandle()).contentFrame();await frame.locator('svg[role="img"]').waitFor();
|
||||
const geometry=await frame.locator('svg[role="img"]').evaluate(svg=>{
|
||||
const nodes=[...svg.querySelectorAll('[data-node-id]')].map(n=>{const r=n.getBoundingClientRect();return {id:n.id,x:r.x,y:r.y,right:r.right,bottom:r.bottom};});
|
||||
return {width:innerWidth,height:innerHeight,nodes,svg:svg.getBoundingClientRect().toJSON(),minLabel:Math.min(...[...svg.querySelectorAll('text[data-node-label]')].map(n=>parseFloat(getComputedStyle(n).fontSize)*n.getScreenCTM().a))};
|
||||
});
|
||||
assert(geometry.nodes.length>=5 && geometry.nodes.length<=(['index','target-operating-model'].includes(id)?18:7),id);
|
||||
const name=await panel.getAttribute('data-diagram');
|
||||
const source=JSON.parse(fs.readFileSync(`diagrams/${name}.${name==='strategy-roadmap'?'workflow':'architecture'}.json`));
|
||||
assert.equal(geometry.nodes.length,(source.components||source.nodes).length,id);
|
||||
for(const n of geometry.nodes) assert(n.x>=0 && n.y>=0 && n.right<=geometry.width+1 && n.bottom<=geometry.height+1,`${id} ${width} clipped ${JSON.stringify(n)} / ${geometry.height}`);
|
||||
const data=await page.locator('.strategy-content').evaluate(el=>({words:el.innerText.trim().split(/\s+/).length,overflow:document.documentElement.scrollWidth>innerWidth,openDetails:el.querySelectorAll('details[open]').length}));
|
||||
assert(data.words<=(id==='measurement'?1100:id==='roadmap'?600:200),id);assert(!data.overflow,id);assert.equal(data.openDetails,0,id);
|
||||
assert(data.words<=(id==='measurement'?1600:id==='roadmap'?600:550),id);assert(!data.overflow,id);assert.equal(data.openDetails,0,id);
|
||||
await page.evaluate(()=>scrollTo({top:0,behavior:'instant'}));await page.screenshot({path:`.cache/story-${label}/${width}-${id}.png`,fullPage:true});
|
||||
const opener=panel.getByRole('button',{name:/^Expand /});await opener.click();
|
||||
const close=panel.getByRole('button',{name:'Close full-screen diagram',exact:true});await close.waitFor({state:'visible'});
|
||||
assert.equal(await close.innerText(),'×');assert(await close.evaluate(n=>n===document.activeElement));
|
||||
const box=await close.boundingBox();assert.equal(box.width,44);assert.equal(box.height,44);
|
||||
await close.click();assert(await opener.evaluate(n=>n===document.activeElement));
|
||||
await opener.click();await close.waitFor({state:'visible'});await page.keyboard.press('Escape');await page.waitForFunction(()=>!document.querySelector('.archify-panel--story dialog').open);assert(await opener.evaluate(n=>n===document.activeElement));
|
||||
if(id !== 'measurement') {
|
||||
await close.click();await panel.locator('dialog iframe').waitFor({state:'detached'});assert(await opener.evaluate(n=>n===document.activeElement));
|
||||
await opener.click();await close.waitFor({state:'visible'});await page.keyboard.press('Escape');await page.waitForFunction(()=>!document.querySelector('.archify-panel--story dialog').open);
|
||||
// Native close clears open before the queued React onClose restores focus.
|
||||
// Wait for its unmount before focusing the next keyboard interaction target.
|
||||
await panel.locator('dialog iframe').waitFor({state:'detached'});assert(await opener.evaluate(n=>n===document.activeElement));
|
||||
if(await page.locator('.strategy-content > details > summary').count()) {
|
||||
const summary=page.locator('.strategy-content > details > summary').first();
|
||||
await summary.focus();await page.keyboard.press('Enter');
|
||||
await page.waitForFunction(()=>document.querySelector('.strategy-content > details').open);
|
||||
@@ -39,7 +44,8 @@ const fs=require('node:fs');
|
||||
results.push({id,width,...data,geometry,modalClick:true,modalEscape:true,focusRestored:true,details:id!=='measurement'});fs.writeFileSync(`.cache/story-${label}/results.json`,JSON.stringify(results,null,2));
|
||||
}
|
||||
await page.goto(`${base}/eldorado-v1/documentation/strategy/reference/measurement-contracts/#validated-task-success`,{waitUntil:'networkidle'});
|
||||
const heading=page.locator('#validated-task-success');await heading.waitFor({state:'visible'});
|
||||
await page.waitForURL(`${base}/eldorado-v1/documentation/strategy/measurement/validated-task-success/`);
|
||||
await page.getByRole('heading',{level:1,name:'Validated task success',exact:true}).waitFor();
|
||||
assert.equal(await page.locator('.strategy-content details').count(),0,'reference is directly readable');
|
||||
await context.close();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,185 @@
|
||||
const {chromium} = require('playwright');
|
||||
const assert = require('node:assert/strict');
|
||||
const fs = require('node:fs');
|
||||
const {pathToFileURL} = require('node:url');
|
||||
const {resolve} = require('node:path');
|
||||
|
||||
// Inspect the rendered paths, not just the authored JSON. Also runs on downloaded SVGs.
|
||||
function inspect({mobile}) {
|
||||
const svg = document.querySelector('svg[role="img"]');
|
||||
const point = (element, p) => new DOMPoint(p.x, p.y).matrixTransform(element.getCTM());
|
||||
const boxes = [...svg.querySelectorAll('[data-node-id]')].map(node => {
|
||||
const rect = node.querySelector('rect'), box = rect.getBBox();
|
||||
const a = point(rect, box), b = point(rect, {x:box.x + box.width, y:box.y + box.height});
|
||||
return {id:node.dataset.nodeId, x:a.x, y:a.y, right:b.x, bottom:b.y, cx:(a.x+b.x)/2, cy:(a.y+b.y)/2};
|
||||
});
|
||||
const agent = boxes.find(n => n.id === 'agent');
|
||||
const errors = [], endpoints = {};
|
||||
const phases = ['scope','architecture','ui-ux','planning','delivery','uat','security','releases'];
|
||||
const edges = [...svg.querySelectorAll('path[data-edge-id]')];
|
||||
if (edges.length !== 24) errors.push(`expected 24 graph edges, got ${edges.length}`);
|
||||
phases.forEach((phase, index) => {
|
||||
for (const [id, from, to] of [
|
||||
[`govern-${phase}`,'agent',phase],
|
||||
[`stage-${index+1}`,phase,phases[(index+1)%phases.length]],
|
||||
[`contribute-${phase}`,`code-${phase}`,phase],
|
||||
]) {
|
||||
const matches = edges.filter(p => p.dataset.edgeId === id);
|
||||
if (matches.length !== 1 || matches[0].dataset.edgeFrom !== from || matches[0].dataset.edgeTo !== to || !matches[0].getAttribute('marker-end') || matches[0].getAttribute('marker-start')) errors.push(`${id}: graph or direction changed`);
|
||||
}
|
||||
});
|
||||
// CTMs put boxes and paths in the same viewport coordinate system.
|
||||
// 0.01 covers floating-point error against bounds, NOT source spreading:
|
||||
// shared endpoints below must be exactly identical.
|
||||
const paths = [...svg.querySelectorAll('path[data-edge-id^="govern-"]')];
|
||||
if (paths.length !== 8) errors.push(`expected eight governance paths, got ${paths.length}`);
|
||||
for (const path of paths) {
|
||||
const id = path.dataset.edgeTo;
|
||||
const side = mobile ? 'left' : ['scope','architecture','releases'].includes(id) ? 'top'
|
||||
: ['planning','delivery','uat'].includes(id) ? 'bottom' : id === 'security' ? 'left' : 'right';
|
||||
const expected = {top:[agent.cx,agent.y],bottom:[agent.cx,agent.bottom],left:[agent.x,agent.cy],right:[agent.right,agent.cy]}[side];
|
||||
const start = point(path,path.getPointAtLength(0));
|
||||
endpoints[id] = [start.x,start.y];
|
||||
if (Math.hypot(start.x-expected[0],start.y-expected[1]) > 0.01) errors.push(`${id}: wrong ${side} midpoint`);
|
||||
const length = path.getTotalLength();
|
||||
const target = boxes.find(n => n.id === id);
|
||||
const destination = mobile ? [target.x,target.cy]
|
||||
: side === 'top' ? [target.cx,target.bottom] : side === 'bottom' ? [target.cx,target.y]
|
||||
: side === 'left' ? [target.right,target.cy] : [target.x,target.cy];
|
||||
const end = point(path,path.getPointAtLength(length));
|
||||
if (Math.hypot(end.x-destination[0],end.y-destination[1]) > 0.01) errors.push(`${id}: destination midpoint changed`);
|
||||
for (let distance = 1; distance < length; distance += 2) {
|
||||
const p = point(path,path.getPointAtLength(distance));
|
||||
for (const box of boxes) {
|
||||
if (box.id === id) continue;
|
||||
if (p.x > box.x+0.1 && p.x < box.right-0.1 && p.y > box.y+0.1 && p.y < box.bottom-0.1) {
|
||||
errors.push(`${id}: crosses ${box.id}`); break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for (const group of mobile ? [phases] : [['scope','architecture','releases'],['planning','delivery','uat']]) {
|
||||
const first = endpoints[group[0]];
|
||||
if (group.some(id => !endpoints[id] || endpoints[id][0] !== first?.[0] || endpoints[id][1] !== first?.[1])) errors.push(`source-port spreading: ${group.join(',')}`);
|
||||
}
|
||||
const lifecycle = [];
|
||||
if (!mobile) {
|
||||
for (const [id, x, y1, y2, peer] of [
|
||||
['stage-2',850,262.5,457.5,'architecture'], ['stage-3',850,532.5,727.5,'planning'],
|
||||
['stage-6',350,727.5,532.5,'uat'], ['stage-7',350,457.5,262.5,'releases'],
|
||||
]) {
|
||||
const path = svg.querySelector(`path[data-edge-id="${id}"]`);
|
||||
if (!path) {errors.push(`${id}: missing lifecycle path`); continue;}
|
||||
const length = path.getTotalLength();
|
||||
const a = path.getPointAtLength(0), b = path.getPointAtLength(length);
|
||||
// Local SVG coordinates test exact offsets; transformed coordinates test
|
||||
// node clearance at any inline/fullscreen/export scale.
|
||||
if (Math.hypot(a.x-x,a.y-y1) > 0.01 || Math.hypot(b.x-x,b.y-y2) > 0.01) errors.push(`${id}: wrong shifted endpoints`);
|
||||
if (!path.getAttribute('marker-end')) errors.push(`${id}: missing direction`);
|
||||
const governance = paths.find(p => p.dataset.edgeTo === peer);
|
||||
if (!governance) {errors.push(`${id}: missing governance peer ${peer}`); continue;}
|
||||
const end = governance.getPointAtLength(governance.getTotalLength());
|
||||
if (Math.abs(Math.abs(a.x-end.x)-20) > 0.01) errors.push(`${id}: wrong attachment clearance`);
|
||||
for (let distance = 1; distance < length; distance += 2) {
|
||||
const local = path.getPointAtLength(distance), p = point(path,local);
|
||||
if (Math.abs(local.x-x) > 0.01) errors.push(`${id}: channel not straight`);
|
||||
for (const box of boxes) {
|
||||
if (p.x > box.x+0.1 && p.x < box.right-0.1 && p.y > box.y+0.1 && p.y < box.bottom-0.1) errors.push(`${id}: crosses ${box.id}`);
|
||||
}
|
||||
}
|
||||
// No positive-length collinear overlap with ANY governance segment.
|
||||
// Perpendicular crossings remain legitimate in this fixed radial layout.
|
||||
for (const govern of paths) {
|
||||
const total = govern.getTotalLength();
|
||||
for (let d = 0; d < total - 1; d += 1) {
|
||||
const p = govern.getPointAtLength(d), q = govern.getPointAtLength(d+1);
|
||||
if (Math.abs(p.x-x) < 0.01 && Math.abs(q.x-x) < 0.01 && Math.min(Math.max(p.y,q.y),Math.max(y1,y2)) - Math.max(Math.min(p.y,q.y),Math.min(y1,y2)) > 0.01) errors.push(`${id}: overlaps ${govern.dataset.edgeId}`);
|
||||
}
|
||||
}
|
||||
lifecycle.push({id,start:[a.x,a.y],end:[b.x,b.y],attachmentClearance:Math.abs(a.x-end.x)});
|
||||
}
|
||||
}
|
||||
return {errors:[...new Set(errors)],endpoints,lifecycle};
|
||||
}
|
||||
|
||||
function inspectTypography({mobile}) {
|
||||
const errors = [];
|
||||
const nodes = [...document.querySelectorAll('[data-node-id]')].map(node => {
|
||||
const box = node.querySelector('rect').getBoundingClientRect();
|
||||
const texts = [...node.querySelectorAll(':scope > text')];
|
||||
const bounds = texts.map(text => text.getBoundingClientRect());
|
||||
texts.forEach((text, index) => {
|
||||
const expected = text.hasAttribute('data-node-label') ? (mobile ? 38 : 27) : (mobile ? 28 : 21);
|
||||
if (parseFloat(getComputedStyle(text).fontSize) !== expected) errors.push(`${node.id}: wrong text size`);
|
||||
const b = bounds[index];
|
||||
if (b.width <= 0 || b.height <= 0 || b.x < box.x - 1 || b.right > box.right + 1 || b.y < box.y - 1 || b.bottom > box.bottom + 1) errors.push(`${node.id}: text outside node`);
|
||||
});
|
||||
if (bounds.length === 2 && bounds[0].bottom > bounds[1].top) errors.push(`${node.id}: title/subtitle overlap`);
|
||||
return {id:node.id, text:texts.map(t => t.textContent), sizes:texts.map(t => getComputedStyle(t).fontSize)};
|
||||
});
|
||||
if (nodes.length !== 17) errors.push(`expected 17 nodes, got ${nodes.length}`);
|
||||
return {errors, nodes};
|
||||
}
|
||||
|
||||
(async () => {
|
||||
const base = process.argv[2] || 'http://127.0.0.1:4173';
|
||||
const output = `.cache/midpoints-${process.argv[3] || 'local'}`;
|
||||
fs.mkdirSync(output,{recursive:true});
|
||||
const browser = await chromium.launch({headless:true, executablePath:process.env.PLAYWRIGHT_CHROMIUM_EXECUTABLE,args:['--no-sandbox']});
|
||||
const results = [];
|
||||
try {
|
||||
for (const width of [1440,390,320]) {
|
||||
const page = await browser.newPage({viewport:{width,height:1000}});
|
||||
await page.goto(`${base}/eldorado-v1/documentation/strategy/target-operating-model/`,{waitUntil:'networkidle'});
|
||||
const panel = page.locator('[data-diagram="strategy-target"]');
|
||||
const iframe = panel.locator(`:scope > .story-${width > 700 ? 'desktop' : 'mobile'}`);
|
||||
await iframe.scrollIntoViewIfNeeded();
|
||||
const frame = await (await iframe.elementHandle()).contentFrame();
|
||||
await frame.locator('svg[role="img"]').waitFor();
|
||||
const inline = await frame.evaluate(inspect,{mobile:width < 700});
|
||||
assert.deepEqual(inline.errors,[]);
|
||||
await page.screenshot({path:`${output}/${width}-inline.png`,fullPage:true});
|
||||
const exported = [];
|
||||
for (const theme of ['light','dark']) {
|
||||
if (await frame.locator('html').getAttribute('data-theme') !== theme) await frame.locator('#btn-theme').click();
|
||||
await frame.waitForFunction(t => document.documentElement.dataset.theme === t, theme);
|
||||
await frame.locator('#btn-export').click();
|
||||
const [download] = await Promise.all([page.waitForEvent('download'),frame.locator('[data-format="svg"]').click()]);
|
||||
assert.equal(await download.failure(),null);
|
||||
const path = `${output}/${width}-${theme}.svg`;
|
||||
await download.saveAs(path);
|
||||
// A separate SVG document has no viewer CSS to hide export regressions.
|
||||
const standalone = await browser.newPage({viewport:{width:1440,height:1100},colorScheme:theme});
|
||||
await standalone.goto(pathToFileURL(resolve(path)).href);
|
||||
assert.equal(await standalone.evaluate(() => document.contentType),'image/svg+xml');
|
||||
await standalone.evaluate(() => document.fonts.ready);
|
||||
const geometry = await standalone.evaluate(inspect,{mobile:width < 700});
|
||||
const typography = await standalone.evaluate(inspectTypography,{mobile:width < 700});
|
||||
assert.deepEqual(geometry.errors,[]);
|
||||
assert.deepEqual(typography.errors,[]);
|
||||
const background = await standalone.locator('rect.c-bg-rect').evaluate(n => getComputedStyle(n).fill);
|
||||
if (exported.length) assert.notEqual(background,exported[0].background,'standalone theme must change');
|
||||
// CDP captures SVG documents without Playwright's HTML-body screenshot wait.
|
||||
const client = await standalone.context().newCDPSession(standalone);
|
||||
const size = await standalone.evaluate(() => ({width:document.documentElement.width.baseVal.value,height:document.documentElement.height.baseVal.value}));
|
||||
const image = await client.send('Page.captureScreenshot',{format:'png',captureBeyondViewport:true,clip:{x:0,y:0,...size,scale:1}});
|
||||
fs.writeFileSync(`${output}/${width}-${theme}-standalone.png`,Buffer.from(image.data,'base64'));
|
||||
exported.push({theme,background,geometry,typography});
|
||||
await standalone.close();
|
||||
}
|
||||
await panel.getByRole('button',{name:/^Expand /}).click();
|
||||
const full = await (await panel.locator('dialog iframe').elementHandle()).contentFrame();
|
||||
await full.locator('svg[role="img"]').waitFor();
|
||||
// The existing fullscreen viewer always opens the radial desktop source.
|
||||
const fullscreen = await full.evaluate(inspect,{mobile:false});
|
||||
assert.deepEqual(fullscreen.errors,[]);
|
||||
await page.screenshot({path:`${output}/${width}-fullscreen.png`});
|
||||
await panel.getByRole('button',{name:'Close full-screen diagram'}).click();
|
||||
results.push({width,inline,exported,fullscreen});
|
||||
fs.writeFileSync(`${output}/results.json`,JSON.stringify(results,null,2));
|
||||
await page.close();
|
||||
}
|
||||
assert.equal(results.length,3);
|
||||
console.log('PASS midpoint geometry: 3 viewports × inline/fullscreen; standalone SVG geometry and typography in light/dark');
|
||||
} finally {await browser.close();}
|
||||
})().catch(error => {console.error(error);process.exitCode=1;});
|
||||
@@ -1,6 +1,10 @@
|
||||
import {readdirSync, readFileSync, writeFileSync, mkdirSync, copyFileSync, renameSync, rmSync} from 'node:fs';
|
||||
import {join} from 'node:path';
|
||||
import {execFileSync} from 'node:child_process';
|
||||
import {skillsViewer, isSkillsStory} from './skills-viewer.mjs';
|
||||
import {roadmapViewer} from './roadmap-viewer.mjs';
|
||||
import {targetRouting} from './target-routing.mjs';
|
||||
import {createHash} from 'node:crypto';
|
||||
const cli = 'vendor/archify/bin/archify.mjs';
|
||||
const types = new Set(['architecture','workflow','sequence','dataflow','lifecycle']);
|
||||
const inlineStyles = readFileSync(new URL('./inline-viewer.css', import.meta.url), 'utf8');
|
||||
@@ -23,11 +27,22 @@ for (const file of readdirSync('diagrams').sort()) {
|
||||
mkdirSync(`static/diagrams/${name}`, {recursive: true});
|
||||
if (spec.diagram_type !== type || spec.meta.output !== output) throw new Error(`Diagram type/output mismatch: ${file}`);
|
||||
const run = args => execFileSync(process.execPath,[cli,...args],{stdio:'inherit',env:{...process.env,ARCHIFY_UPDATE_CHECK_DISABLED:'1'}});
|
||||
const roadmap = /^strategy-roadmap(?:-(?:adoption|loop))?(?:-mobile)?$/.test(name);
|
||||
const skills = isSkillsStory(name);
|
||||
if (roadmap || skills) {
|
||||
// Native renderer validates schema and compiles layout. Check readability
|
||||
// after multiline typography, not upstream's single-line preview.
|
||||
execFileSync(process.execPath, [`vendor/archify/renderers/${type}/render-${type}.mjs`, input, output], {stdio:'inherit', env:{...process.env, ARCHIFY_UPDATE_CHECK_DISABLED:'1'}});
|
||||
writeFileSync(output, (skills ? skillsViewer : roadmapViewer)(readFileSync(output, 'utf8'), spec));
|
||||
run(['check',output,'--json']);
|
||||
} else {
|
||||
run(['validate',type,input,'--quality','showcase','--json']);
|
||||
run(['deliver',type,input,output,'--quality','showcase','--json']);
|
||||
run(['check',output,'--json','--require-provenance']);
|
||||
}
|
||||
// Verify the upstream artifact first, then add the scoped portal integration.
|
||||
let viewer = readFileSync(output, 'utf8');
|
||||
if (name === 'strategy-target') viewer = targetRouting(viewer);
|
||||
// Upstream intentionally disables preset selection in gallery embeds. Enable
|
||||
// only those two guards; fail closed if a future vendor update changes them.
|
||||
const start = viewer.indexOf('Archify.preset = (function () {');
|
||||
@@ -48,7 +63,23 @@ for (const file of readdirSync('diagrams').sort()) {
|
||||
}
|
||||
writeFileSync(output, viewer.replace('</head>', `<style id="eldorado-inline-controls">${inlineStyles}</style><style id="eldorado-cycle-labels">${storyStyles}</style></head>`)
|
||||
.replace('</body>', `<script>${themeBridge}</script></body>`));
|
||||
if (roadmap || skills) {
|
||||
// This is a portal receipt, not upstream deliver provenance: formatting
|
||||
// happens between the native schema/layout compiler and artifact checker.
|
||||
const hash = path => createHash('sha256').update(readFileSync(path)).digest('hex');
|
||||
const checked = JSON.parse(execFileSync(process.execPath, [cli,'check',output,'--json'], {encoding:'utf8', env:{...process.env, ARCHIFY_UPDATE_CHECK_DISABLED:'1'}}));
|
||||
if (!checked.ok || checked.composition?.status !== 'pass') throw new Error('Story final artifact failed');
|
||||
writeFileSync(`.cache/archify/${name}.portal.json`, JSON.stringify({source:input, sourceSha256:hash(input), adapterSha256:hash(skills ? 'scripts/skills-viewer.mjs' : 'scripts/roadmap-viewer.mjs'), artifactSha256:hash(output), checker:checked}, null, 2));
|
||||
} else {
|
||||
renameSync(`static/diagrams/${name}/index.delivery.json`, `.cache/archify/${name}.delivery.json`);
|
||||
if (name === 'strategy-target') {
|
||||
// The native receipt describes the PRE-integration artifact only.
|
||||
const hash = path => createHash('sha256').update(readFileSync(path)).digest('hex');
|
||||
const checked = JSON.parse(execFileSync(process.execPath, [cli,'check',output,'--json'], {encoding:'utf8', env:{...process.env, ARCHIFY_UPDATE_CHECK_DISABLED:'1'}}));
|
||||
if (!checked.ok || checked.composition?.status !== 'pass') throw new Error('Target final artifact failed');
|
||||
writeFileSync(`.cache/archify/${name}.portal.json`, JSON.stringify({source:input, sourceSha256:hash(input), adapterSha256:hash('scripts/target-routing.mjs'), artifactSha256:hash(output), nativeReceiptScope:'before portal integration', checker:checked}, null, 2));
|
||||
}
|
||||
}
|
||||
}
|
||||
copyFileSync('vendor/archify/LICENSE','static/diagrams/ARCHIFY-LICENSE.txt');
|
||||
copyFileSync('vendor/archify/THIRD_PARTY_NOTICES.md','static/diagrams/THIRD-PARTY-NOTICES.md');
|
||||
@@ -0,0 +1,58 @@
|
||||
import test from 'node:test';
|
||||
import assert from 'node:assert/strict';
|
||||
import {readFileSync,readdirSync} from 'node:fs';
|
||||
import {createHash} from 'node:crypto';
|
||||
const read=p=>readFileSync(p,'utf8');
|
||||
const coverage=JSON.parse(read('research/ai-adoption/strategy-coverage.json')).routes;
|
||||
|
||||
test('connected Strategy covers every canonical route and reader handoff',()=>{
|
||||
const files=readdirSync('docs/strategy',{recursive:true}).filter(p=>p.endsWith('.mdx')).map(p=>'docs/strategy/'+p).sort();
|
||||
assert.equal(coverage.length,28);
|
||||
assert.deepEqual(coverage.map(r=>r.source).sort(),files);
|
||||
assert.equal(new Set(coverage.map(r=>r.route)).size,28);
|
||||
for(const r of coverage){
|
||||
for(const k of ['question','inputs','action_or_decision','output','next_or_feedback','review'])assert(r[k],`${r.source}: ${k}`);
|
||||
const page=read(r.source);assert(!/roadmap gates|Evidence-gated phases/.test(page),r.source);
|
||||
assert(coverage.some(n=>n.route===r.next_or_feedback),r.next_or_feedback);
|
||||
if(r.contract_sha256){
|
||||
const body=page.split('{/* contract:start */}\n')[1].split('\n{/* contract:end */}')[0];
|
||||
assert.equal(createHash('sha256').update(body).digest('hex'),r.contract_sha256,r.source);
|
||||
}
|
||||
}
|
||||
assert.equal(coverage.filter(r=>r.implementation==='prototype').length,9);
|
||||
assert.equal(coverage.filter(r=>r.implementation==='unimplemented').length,7);
|
||||
});
|
||||
|
||||
test('the parent journey connects qualification, pilot authority and feedback without automatic autonomy',()=>{
|
||||
const parent=read('docs/strategy/stage-01-skills-adoption.mdx');
|
||||
for(const marker of ['illustrative Delivery','independent Quality Engineering reviewer','baseline describes work; it grants no approval','not six rigid sequential approval gates','Governance bounds every activity','separate case for authority and readiness'])assert(parent.toLowerCase().includes(marker.toLowerCase()),marker);
|
||||
const governance=read('docs/strategy/skills-governance.mdx');
|
||||
for(const marker of ['experimental → bounded pilot','bounded pilot → approved','Initial experimental qualification runs only in approved disposable environments','Real work requires a separate bounded-pilot authorization'])assert(governance.includes(marker),marker);
|
||||
assert(!governance.includes('| experimental → approved |'));
|
||||
assert(read('docs/strategy/skills-adoption.mdx').includes('pilot decision alone is not general approval'));
|
||||
const quality=read('docs/strategy/skills-quality.mdx');
|
||||
for(const marker of ['Qualification artifact success is not live task success','planned executed trials','matured real-workflow starts','regression against the currently approved revision'])assert(quality.includes(marker),marker);
|
||||
for(const id of ['measurement/index','skills-maintenance'])assert(read(`docs/strategy/${id}.mdx`).includes('skills-quality.mdx'));
|
||||
const future=read('docs/strategy/stage-02-autonomous-agent.mdx');
|
||||
for(const marker of ['separate authority decision','Unresolved release approval roles remain a hold condition','not deployed autonomy','stop/human-takeover','recorded hold'])assert(future.includes(marker),marker);
|
||||
});
|
||||
|
||||
for(const stage of ['stage01','stage02'])test(`${stage}: native paired views preserve handoffs, decisions and containment`,()=>{
|
||||
const pair=['','-mobile'].map(s=>JSON.parse(read(`diagrams/strategy-${stage}${s}.architecture.json`)));
|
||||
const nodes=d=>d.components.map(({pos,size,...n})=>n);
|
||||
const relationships=d=>d.connections.map(({id,from,to,variant})=>({id,from,to,variant}));
|
||||
assert.deepEqual(nodes(pair[0]),nodes(pair[1]));
|
||||
assert.deepEqual(relationships(pair[0]),relationships(pair[1]));
|
||||
const expected=stage==='stage01'?[['baseline','engineer'],['engineer','qualify'],['qualify','pilot'],['pilot','decide'],['decide','maintain'],['maintain','engineer'],['decide','baseline']]:[['proven','case'],['case','decision'],['decision','execute'],['decision','hold'],['execute','stop'],['stop','hold']];
|
||||
assert.deepEqual(pair[0].connections.map(e=>[e.from,e.to]).sort(),expected.sort());
|
||||
const by=Object.fromEntries(pair[0].components.map(n=>[n.id,n]));
|
||||
if(stage==='stage01'){
|
||||
assert(by.qualify.sublabel.includes('Fail / incomplete: hold or rework'));
|
||||
assert(by.reference.tag.includes('Throughout'));
|
||||
assert(by.decide.sublabel.includes('Compare with baseline, not trials'));
|
||||
}else{
|
||||
assert(by.decision.sublabel.includes('Owning approver'));
|
||||
assert(by.stop.sublabel.includes('Revoke mutations'));
|
||||
assert(by.hold.sublabel.includes('No automatic progression'));
|
||||
}
|
||||
});
|
||||
@@ -8,7 +8,8 @@
|
||||
font-size: var(--cycle-label);
|
||||
transform: translateY(-6px);
|
||||
}
|
||||
.diagram-container > svg text[data-detail="context"] {
|
||||
/* Export strips data-detail; node ownership and the muted class survive. */
|
||||
.diagram-container > svg [data-node-id] > text.t-muted {
|
||||
font-size: var(--cycle-detail);
|
||||
transform: translateY(16px);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
import assert from 'node:assert/strict';
|
||||
import {readFileSync, readdirSync} from 'node:fs';
|
||||
import {runInNewContext} from 'node:vm';
|
||||
const read = p => readFileSync(p, 'utf8');
|
||||
|
||||
export function verifyMeasurementPages() {
|
||||
const manifest = JSON.parse(read('research/ai-adoption/measurement-migration.json'));
|
||||
const {documents, exclusions} = JSON.parse(read('.cache/sidebar-coverage.json'));
|
||||
const prefix = '/eldorado-v1/documentation';
|
||||
const legacy = 'strategy/reference/measurement-contracts/index.html';
|
||||
assert.equal(exclusions.filter(e => e.file === legacy).length, 1);
|
||||
assert(!documents.some(d => d.id === 'reference/measurement-contracts'));
|
||||
const search = readdirSync('build').filter(f => /^search-index.*\.json$/.test(f)).map(f => read(`build/${f}`)).join('\n');
|
||||
assert(!search.includes('/strategy/reference/measurement-contracts/'));
|
||||
const children = [...manifest.metrics.map(m => ({...m,slug:m.oldAnchor})),
|
||||
{slug:'collection-and-safeguards',title:'Collection and safeguards'},
|
||||
{slug:'synthetic-example',title:'Run the synthetic measurement example'},
|
||||
];
|
||||
for (const child of children) {
|
||||
const route = `${prefix}/strategy/measurement/${child.slug}/`;
|
||||
const doc = documents.filter(d => `${d.route}/` === route);
|
||||
assert.equal(doc.length,1);
|
||||
assert.equal(doc[0].id, `measurement/${child.slug}`);
|
||||
const page = read(`build/strategy/measurement/${child.slug}/index.html`);
|
||||
const canonical = [...page.matchAll(/<link\b[^>]*rel="canonical"[^>]*>/g)];
|
||||
assert.equal(canonical.length,1);
|
||||
assert(canonical[0][0].includes(`href="https://pages.apps.lego-cloud.eu${route}"`));
|
||||
assert(search.includes(route), `Missing search route: ${route}`);
|
||||
assert(!page.includes(`${prefix}/strategy/reference/measurement-contracts/`));
|
||||
}
|
||||
const script = read(`build/${legacy}`).match(/<script>([\s\S]*?)<\/script>/)[1];
|
||||
for (const m of manifest.metrics) {
|
||||
let destination;
|
||||
runInNewContext(script,{window:{location:{hash:`#${m.oldAnchor}`,replace:url => {destination=url;}}}});
|
||||
assert.equal(destination,`${prefix}${m.url}`);
|
||||
}
|
||||
console.log('PASS: 18 canonical Measurement children, exact IDs, search membership and 16 hash redirects; no legacy document/index duplication');
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
import test from 'node:test';
|
||||
import assert from 'node:assert/strict';
|
||||
import {readFileSync, existsSync, readdirSync} from 'node:fs';
|
||||
import {createHash} from 'node:crypto';
|
||||
import {calculate} from './ai-kpi.mjs';
|
||||
const read = p => readFileSync(p, 'utf8');
|
||||
|
||||
test('each original metric survives exactly once on its own canonical Measurement page', () => {
|
||||
const manifest = JSON.parse(read('research/ai-adoption/measurement-migration.json'));
|
||||
const model = JSON.parse(read('research/ai-adoption/strategy-model.json'));
|
||||
const report = calculate(JSON.parse(read('scripts/fixtures/ai-kpi-synthetic.json')));
|
||||
assert.equal(manifest.metrics.length, 16);
|
||||
assert.deepEqual(manifest.metrics.map(m => m.title), model.kpis.map(k => k.name));
|
||||
assert.equal(new Set(manifest.metrics.map(m => m.docId)).size, 16);
|
||||
assert.equal(manifest.metrics.filter(m => m.status === 'prototype').length, 9);
|
||||
assert.equal(manifest.metrics.filter(m => m.status === 'unimplemented').length, 7);
|
||||
const overview = read('docs/strategy/measurement/index.mdx');
|
||||
for (const metric of manifest.metrics) {
|
||||
const page = read(`docs/strategy/${metric.docId}.mdx`);
|
||||
assert.equal(metric.url, `/strategy/${metric.docId}/`);
|
||||
assert.equal(metric.oldAnchor, metric.docId.split('/').at(-1));
|
||||
assert(page.includes(`slug: /${metric.docId}`));
|
||||
assert(overview.includes(`./${metric.oldAnchor}.mdx`));
|
||||
assert(page.includes('./collection-and-safeguards.mdx'));
|
||||
assert(page.includes('not installed collection'));
|
||||
assert(page.includes(metric.status === 'prototype' ? 'Prototype calculation' : 'Unimplemented metric'));
|
||||
assert.equal(Object.hasOwn(report.kpis, metric.calculationId), metric.status === 'prototype');
|
||||
const contract = page.split('{/* contract:start */}\n')[1]?.split('\n{/* contract:end */}')[0];
|
||||
assert(contract, metric.title);
|
||||
assert.equal(createHash('sha256').update(contract).digest('hex'), metric.contractSha256, metric.title);
|
||||
for (const field of ['Numerator','Denominator','Expression','Aggregation','Unit','Eligible population','Exclusions','Events and source','Owner / cadence','Missing evidence','Gaming and limits']) assert.equal(contract.split(`| ${field} |`).length, 2, `${metric.title}: ${field}`);
|
||||
}
|
||||
assert.equal(readdirSync('docs/strategy/measurement').filter(p => p.endsWith('.mdx')).length, 19);
|
||||
assert(!existsSync('docs/strategy/reference/measurement-contracts.mdx'));
|
||||
for (const part of manifest.shared) {
|
||||
const page = read(`docs/strategy/measurement/${part.slug}.mdx`);
|
||||
const body = page.split('{/* preserved:start */}\n')[1]?.split('\n{/* preserved:end */}')[0];
|
||||
// Only the cross-page navigation wording changes; hash all original substance.
|
||||
const original = body.replace('Use the [metric definitions](./index.mdx#metric-definitions)', 'Use the metric contracts below')
|
||||
// The old navigation named nonexistent roadmap gates. Restore only that
|
||||
// historical sentence for the migration hash; metric substance stays exact.
|
||||
.replace('Use these safeguards throughout the [Stage 01 journey](../stage-01-skills-adoption.mdx)', 'Introduction depends on the [roadmap gates](../roadmap.mdx)');
|
||||
assert.equal(createHash('sha256').update(original).digest('hex'), part.sha256);
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,65 @@
|
||||
// Native Workflow v2 owns node geometry, mainPath and routing. The portal adds
|
||||
// multiline typography: upstream's three single-line labels are too small for
|
||||
// a Roadmap reading view. Do not change the pinned vendor or graph semantics.
|
||||
const escape = text => text.replaceAll('&', '&').replaceAll('<', '<').replaceAll('>', '>').replaceAll('"', '"');
|
||||
const wrap = (text, limit = 21) => {
|
||||
const lines = [];
|
||||
for (const word of text.split(/\s+/)) {
|
||||
if (!lines.length || `${lines.at(-1)} ${word}`.length > limit) lines.push(word);
|
||||
else lines[lines.length - 1] += ` ${word}`;
|
||||
}
|
||||
return lines;
|
||||
};
|
||||
export function roadmapViewer(html, spec) {
|
||||
if (spec.diagram_type !== 'workflow' || spec.schema_version !== 2 || ![2, 6].includes(spec.nodes.length)) throw new Error('Roadmap workflow contract drift');
|
||||
const boxes = [];
|
||||
for (const [index, node] of spec.nodes.entries()) {
|
||||
const start = html.indexOf(`<g id="node-${node.id}"`);
|
||||
const next = html.indexOf('<text data-node-label=', start);
|
||||
const end = html.indexOf('</g>', next) + 4;
|
||||
if (start < 0 || next < start || end < next) throw new Error(`Roadmap node drift: ${node.id}`);
|
||||
const original = html.slice(start, end);
|
||||
const rect = /<rect x="([\d.-]+)" y="([\d.-]+)" width="([\d.]+)" height="([\d.]+)"/.exec(original);
|
||||
if (!rect || (original.match(/<text /g) || []).length !== 2) throw new Error(`Roadmap text contract drift: ${node.id}`);
|
||||
const [x,y,w,h] = rect.slice(1).map(Number);
|
||||
boxes.push({x,y,w,h});
|
||||
const text = (value, top, size, cls, attrs = 'data-detail="context"') => {
|
||||
const lines = wrap(value, size === 30 ? 18 : 21);
|
||||
const maxLines = top === 160 ? 3 : 2;
|
||||
if (lines.length > maxLines || lines.some(line => line.length > 21)) throw new Error(`Roadmap copy exceeds card capacity: ${node.id}`);
|
||||
return `<text x="${x+24}" y="${y+top}" font-size="${size}" class="${cls}" ${attrs}>${lines.map((line,i) => `<tspan x="${x+24}" dy="${i ? 34 : 0}">${escape(line)}</tspan>`).join('')}</text>`;
|
||||
};
|
||||
if (!node.sublabel || node.tag || /Output:|Exit:|\n/.test(node.sublabel)) throw new Error(`Roadmap content contract drift: ${node.id}`);
|
||||
const number = spec.nodes.length === 6 ? `Step ${index+1}` : spec.nodes[0].id === 'skills' ? `Stage ${index+1}` : index === 0 ? 'First' : 'Then';
|
||||
const content = text(number, 40, 26, 't-primary', 'data-stage-number="" font-weight="700"')
|
||||
+ text(node.label, 88, 30, 't-primary', 'data-node-label="" font-weight="700"')
|
||||
+ text(node.sublabel, 160, 26, 't-muted');
|
||||
// Preserve native node title/metadata and rectangles; replace sigil/text only.
|
||||
// Sigils are nested SVG groups. Anchor on the two native node rectangles.
|
||||
const rectangles = [...original.matchAll(/<rect\b[^>]*\/>/g)];
|
||||
if (rectangles.length !== 2) throw new Error('Roadmap shape contract drift');
|
||||
const prefixEnd = rectangles[1].index + rectangles[1][0].length;
|
||||
const replacement = original.slice(0,prefixEnd).replaceAll('rx="6"', 'rx="0"') + content + '</g>';
|
||||
html = html.slice(0,start) + replacement + html.slice(end);
|
||||
}
|
||||
// The native mobile return channel sits outside the card column.
|
||||
const left = Math.min(...boxes.map(b => b.x)) - (spec.edges.some(e => e.route === 'return-left') ? 80 : 12);
|
||||
const top = Math.min(...boxes.map(b => b.y)) - 12;
|
||||
const width = Math.max(...boxes.map(b => b.x+b.w)) - left + 12;
|
||||
const height = Math.max(...boxes.map(b => b.y+b.h)) - top + 12;
|
||||
// One editorial lane; its title/frame would repeat the page's framing.
|
||||
html = html.replace(/<rect\b[^>]*data-composition-frame-kind="lane"[^>]*\/>\s*<text\b[^>]*>[\s\S]*?<\/text>/g, '');
|
||||
const roots = [...html.matchAll(/<svg\b[^>]*role="img"[^>]*>/g)];
|
||||
if (roots.length !== 1) throw new Error('Roadmap SVG contract drift');
|
||||
const root = roots[0][0].replace(/viewBox="[^"]*"/, `viewBox="${left} ${top} ${width} ${height}"`);
|
||||
const styles = `<style id="eldorado-roadmap-typography">
|
||||
html[data-embed="true"] .diagram-container > svg {max-height:calc(100vh - 84px);}
|
||||
[data-node-id] text {font-family: Arial, sans-serif;}
|
||||
svg[data-preset="classic"] [data-node-id] > rect.c-backend,
|
||||
svg[data-preset="editorial"] [data-node-id] > rect.c-backend {fill:var(--panel); stroke:var(--border);}
|
||||
.c-grid {opacity:0;}
|
||||
|
||||
</style>`;
|
||||
html = html.replace(roots[0][0], root + styles);
|
||||
return html;
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
import {test} from 'node:test';
|
||||
import assert from 'node:assert/strict';
|
||||
import {readFileSync, writeFileSync, mkdtempSync, rmSync, mkdirSync} from 'node:fs';
|
||||
import {execFileSync} from 'node:child_process';
|
||||
import {roadmapViewer} from './roadmap-viewer.mjs';
|
||||
|
||||
for (const name of ['strategy-roadmap', 'strategy-roadmap-adoption', 'strategy-roadmap-loop']) for (const suffix of ['', '-mobile']) test(`${name}${suffix} retains graph and passes final composition`, () => {
|
||||
mkdirSync('.cache', {recursive:true});
|
||||
const dir = mkdtempSync('.cache/roadmap-test-');
|
||||
try {
|
||||
const source = `diagrams/${name}${suffix}.workflow.json`;
|
||||
const spec = JSON.parse(readFileSync(source, 'utf8'));
|
||||
const output = `${dir}/index.html`;
|
||||
execFileSync(process.execPath, ['vendor/archify/renderers/workflow/render-workflow.mjs', source, output], {env:{...process.env, ARCHIFY_UPDATE_CHECK_DISABLED:'1'}});
|
||||
const native = readFileSync(output, 'utf8');
|
||||
const styled = roadmapViewer(native, spec);
|
||||
const graph = html => [...html.matchAll(/<path\b[^>]*data-edge-id="[^"]+"[^>]*>/g)].map(m => m[0]);
|
||||
assert.equal(graph(native).length, spec.edges.length);
|
||||
assert.deepEqual(graph(styled), graph(native), 'native paths must not be rewritten');
|
||||
for (const node of spec.nodes) assert(styled.includes(`data-node-id="${node.id}"`));
|
||||
assert.equal((styled.match(/<text data-node-label=/g) || []).length, 0, 'single-line preview replaced');
|
||||
assert(styled.includes('eldorado-roadmap-typography'));
|
||||
writeFileSync(output, styled);
|
||||
const checked = JSON.parse(execFileSync(process.execPath, ['vendor/archify/bin/archify.mjs','check',output,'--json'], {encoding:'utf8', env:{...process.env, ARCHIFY_UPDATE_CHECK_DISABLED:'1'}}));
|
||||
assert(checked.ok);
|
||||
assert.equal(checked.composition.status, 'pass');
|
||||
assert.equal(checked.composition.metrics.properCrossings, 0);
|
||||
assert.equal(checked.composition.metrics.labelCanvasOverflowIssues, 0);
|
||||
assert.throws(() => roadmapViewer('', spec), /drift/);
|
||||
const oversized = structuredClone(spec);
|
||||
oversized.nodes[0].sublabel = 'Too much copy '.repeat(20);
|
||||
assert.throws(() => roadmapViewer(native, oversized), /capacity/);
|
||||
assert.throws(() => roadmapViewer(native, {...spec,diagram_type:'architecture'}), /contract drift/);
|
||||
} finally {rmSync(dir, {recursive:true, force:true});}
|
||||
});
|
||||
+24
-19
@@ -3,27 +3,32 @@ import assert from 'node:assert/strict';
|
||||
import {readFileSync} from 'node:fs';
|
||||
const read = path => readFileSync(path, 'utf8');
|
||||
|
||||
test('Roadmap visibly assesses code and real delivery before adoption', () => {
|
||||
export const views = {
|
||||
'strategy-roadmap': ['skills', 'autonomy'],
|
||||
'strategy-roadmap-adoption': ['delivery', 'remaining'],
|
||||
'strategy-roadmap-loop': ['understand', 'baseline', 'topology', 'use', 'collect', 'reassess'],
|
||||
};
|
||||
test('Roadmap has three visual levels and preserves human direction and Delivery discovery', () => {
|
||||
const page = read('docs/strategy/roadmap.mdx');
|
||||
const visible = page.split('<details>')[0];
|
||||
const headings = [...visible.matchAll(/^## (.+)$/gm)].map(match => match[1]);
|
||||
assert.deepEqual(headings, ['1. Understand code quality and delivery', '2. Fix critical readiness gaps', '3. Run a bounded pilot', '4. Expand only on evidence', '5. Sustain and improve']);
|
||||
assert(visible.indexOf(' story />') < visible.indexOf('## 1.'));
|
||||
for (const marker of ['representative repositories', 'tests and CI', 'maintainability', 'technical debt', 'security findings', 'actual SDLC', 'ownership', 'review and release', 'bottlenecks', 'baseline findings', 'process map', 'prioritized gaps', 'alongside the pilot', './measurement.mdx', './target-operating-model.mdx']) assert(visible.includes(marker), marker);
|
||||
assert.equal((visible.match(/\*\*Output:/g) || []).length, 5);
|
||||
assert.match(visible, /Recommended sequence/);
|
||||
assert(!page.includes('### Foundation'));
|
||||
for (const marker of ['revocation', 'exact-artifact approvals', 'idempotency', 'human takeover', 'sensitive decisions']) assert(page.includes(marker), marker);
|
||||
assert.deepEqual([...visible.matchAll(/<ArchifyDiagram name="([^"]+)"/g)].map(m => m[1]), Object.keys(views));
|
||||
assert.deepEqual([...visible.matchAll(/^## (.+)$/gm)].map(m => m[1]), ['Two stages toward Target', 'Stage 1: Delivery first', 'Improve within each phase', 'Delivery in practice']);
|
||||
for (const marker of ['Humans direct, guide and review throughout', 'standardizes skills', 'foundation for Stage 2', 'future Autonomous Agent', 'not deployed autonomy', 'order is not yet decided', 'Delivery keeps improving', 'not as six global roadmap stages', 'what skills exist, how they relate, when they are used and how they work together', 'codebase structure', 'existing principles', 'system-logic source', 'tests', 'builds and packaging', 'deployments', 'practices, tooling, controls and problems', 'metrics/KPIs and a baseline', 'friction and feedback', './measurement/index.mdx', './target-operating-model.mdx']) assert(visible.includes(marker), marker);
|
||||
for (const marker of ['revocation','exact-artifact approvals','idempotency','human takeover','sensitive decisions','security findings','reproducible baseline']) assert(page.includes(marker), marker);
|
||||
assert(!/## [1-5]\.|Prepare foundations|Sustain and improve/.test(page));
|
||||
});
|
||||
|
||||
test('both roadmap diagrams make assessment and readiness prerequisites to the pilot', () => {
|
||||
const ids = ['assessment', 'readiness', 'pilot', 'expansion', 'sustain'];
|
||||
for (const suffix of ['', '-mobile']) {
|
||||
const diagram = JSON.parse(read(`diagrams/strategy-roadmap${suffix}.architecture.json`));
|
||||
assert.deepEqual(diagram.components.map(n => n.id), ids);
|
||||
assert.deepEqual(diagram.connections.map(e => [e.from,e.to]), ids.slice(1).map((id, i) => [ids[i],id]));
|
||||
assert.match(diagram.components[0].sublabel, /Code quality \+ delivery flow/);
|
||||
assert.match(diagram.components[1].sublabel, /Critical gaps/);
|
||||
assert.match(diagram.components[4].label, /Sustain/);
|
||||
for (const [name, ids] of Object.entries(views)) test(`${name}: native graph, mobile parity and loop semantics`, () => {
|
||||
const variants = ['', '-mobile'].map(suffix => JSON.parse(read(`diagrams/${name}${suffix}.workflow.json`)));
|
||||
for (const [index, d] of variants.entries()) {
|
||||
assert.equal(d.schema_version, 2);
|
||||
assert.equal(d.diagram_type, 'workflow');
|
||||
assert.deepEqual(d.mainPath, ids.length === 6 ? ids.slice(0,3) : ids);
|
||||
assert.deepEqual(d.nodes.map(n => n.id), ids);
|
||||
assert.deepEqual(d.edges.filter(e => e.role === 'main').map(e => [e.from,e.to]), ids.slice(1).map((id,i) => [ids[i],id]));
|
||||
assert.deepEqual(d.edges.filter(e => e.role === 'return').map(e => [e.from,e.to]), ids.length === 6 ? [['reassess','understand']] : []);
|
||||
if (index) assert(d.nodes.every(n => n.col === 0));
|
||||
assert(d.nodes.every(n => n.sublabel && !n.tag && n.height === 240));
|
||||
}
|
||||
const semantics = d => ({nodes:d.nodes.map(({col,yOffset,...n}) => n), edges:d.edges.map(({fromSide,toSide,route,...e}) => e)});
|
||||
assert.deepEqual(semantics(variants[0]),semantics(variants[1]));
|
||||
});
|
||||
@@ -5,7 +5,7 @@ const read = p => readFileSync(p, 'utf8');
|
||||
const stages = ['Scope', 'Architecture', 'UI/UX', 'Planning', 'Delivery', 'UAT', 'Security', 'Releases'];
|
||||
|
||||
test('Strategy opens at the canonical autonomous lifecycle', () => {
|
||||
assert.match(read('sidebars/strategy.ts'), /strategySidebar: \['target-operating-model', 'roadmap'/);
|
||||
assert.match(read('sidebars/strategy.ts'), /strategySidebar:\s*\[\s*'target-operating-model',\s*'roadmap'/);
|
||||
assert.match(read('docs/strategy/target-operating-model.mdx'), /^sidebar_label: Target$/m);
|
||||
for (const id of ['target-operating-model']) {
|
||||
const page = read(`docs/strategy/${id}.mdx`);
|
||||
@@ -14,7 +14,8 @@ test('Strategy opens at the canonical autonomous lifecycle', () => {
|
||||
assert(primary.includes('autonomous agent'));
|
||||
assert(primary.includes('direct, guide and review'));
|
||||
assert(primary.includes('Scope → Architecture → UI/UX → Planning → Delivery → UAT → Security → Releases → Scope'));
|
||||
assert(primary.includes('human-controlled code agent'));
|
||||
assert(primary.includes('human-controlled AI Agent'));
|
||||
assert(!/code[ -]agent/i.test(page));
|
||||
assert(primary.includes('TO-BE'));
|
||||
assert(!/only routes|People authorize|independent gates protect release/.test(primary));
|
||||
}
|
||||
@@ -37,7 +38,7 @@ test('both target diagrams have eight stages, eight governed phases and eight hu
|
||||
assert.deepEqual(d.connections.filter(e => e.from === 'agent').map(e => e.to), ids);
|
||||
const contributors = d.components.filter(n => n.id.startsWith('code-'));
|
||||
assert.equal(contributors.length, 8);
|
||||
assert(contributors.every(n => n.label === 'Code agent' && n.sublabel === 'Human-controlled'));
|
||||
assert(contributors.every(n => n.label === 'AI Agent' && n.sublabel === 'Human-controlled'));
|
||||
for (const id of ids) {
|
||||
assert(d.connections.some(e => e.from === `code-${id}` && e.to === id && e.variant === 'dashed'));
|
||||
assert(d.connections.some(e => e.from === 'agent' && e.to === id && e.variant === 'security'));
|
||||
|
||||
@@ -0,0 +1,116 @@
|
||||
import assert from 'node:assert/strict';
|
||||
import {readFileSync, readdirSync, mkdirSync, writeFileSync} from 'node:fs';
|
||||
import {join} from 'node:path';
|
||||
|
||||
const normalize = path => path.replace(/\/$/, '');
|
||||
const read = path => JSON.parse(readFileSync(path, 'utf8'));
|
||||
|
||||
// Use Docusaurus's resolved IDs/routes and sidebar trees, not filename guesses.
|
||||
export function auditSidebars(instances, entrySidebars) {
|
||||
const docs = new Map();
|
||||
const menus = new Map();
|
||||
for (const {plugin, version, documents, sidebars} of instances) {
|
||||
const ids = new Set();
|
||||
for (const doc of documents) {
|
||||
assert(!ids.has(doc.id), `Duplicate document ID: ${plugin}:${version}:${doc.id}`);
|
||||
ids.add(doc.id);
|
||||
const route = normalize(doc.path);
|
||||
assert(!docs.has(route), `Duplicate document route: ${route}`);
|
||||
docs.set(route, {...doc, plugin, version, menu: `${plugin}:${version}:${doc.sidebar}`});
|
||||
}
|
||||
for (const [name, items] of Object.entries(sidebars)) menus.set(`${plugin}:${version}:${name}`, items);
|
||||
}
|
||||
const links = new Map();
|
||||
for (const [menu, items] of menus) {
|
||||
const found = new Set();
|
||||
const walk = items => {
|
||||
for (const item of items) {
|
||||
assert(['category', 'link', 'html'].includes(item.type), `Unresolved sidebar type: ${item.type}`);
|
||||
assert(!item.unlisted, `Hidden sidebar item: ${item.label}`);
|
||||
if (item.href && !/^(https?:|mailto:)/.test(item.href)) {
|
||||
const route = normalize(item.href);
|
||||
if (item.docId) assert.equal(docs.get(route)?.id, item.docId, `Sidebar ID/route mismatch: ${item.docId}`);
|
||||
assert(!found.has(route), `Duplicate sidebar route in ${menu}: ${route}`);
|
||||
found.add(route);
|
||||
}
|
||||
if (item.type === 'category') walk(item.items);
|
||||
}
|
||||
};
|
||||
walk(items);
|
||||
links.set(menu, found);
|
||||
}
|
||||
const reachable = new Set(entrySidebars);
|
||||
for (const menu of reachable) {
|
||||
assert(menus.has(menu), `Unknown navigation sidebar: ${menu}`);
|
||||
for (const route of links.get(menu)) {
|
||||
const doc = docs.get(route);
|
||||
if (doc) reachable.add(doc.menu);
|
||||
}
|
||||
}
|
||||
for (const [route, doc] of docs) {
|
||||
assert(reachable.has(doc.menu), `Unreachable sidebar for ${doc.plugin}:${doc.id}`);
|
||||
assert(links.get(doc.menu)?.has(route), `Missing sidebar document: ${doc.plugin}:${doc.id}`);
|
||||
}
|
||||
return [...docs.entries()].map(([route, doc]) => ({route, id:doc.id, plugin:doc.plugin, sidebar:doc.sidebar}));
|
||||
}
|
||||
|
||||
export async function verifySidebarCoverage() {
|
||||
const global = read('.docusaurus/globalData.json')['docusaurus-plugin-content-docs'];
|
||||
assert(global && Object.keys(global).length, 'No generated document inventory');
|
||||
const instances = [];
|
||||
for (const [plugin, data] of Object.entries(global)) {
|
||||
const folder = `.docusaurus/docusaurus-plugin-content-docs/${plugin}/p`;
|
||||
const resolved = readdirSync(folder).filter(f => f.endsWith('.json')).map(f => read(join(folder, f)).version);
|
||||
for (const version of data.versions) {
|
||||
const matches = resolved.filter(v => v.version === version.name);
|
||||
assert.equal(matches.length, 1, `Missing/duplicate resolved version: ${plugin}:${version.name}`);
|
||||
instances.push({plugin, version:version.name, documents:version.docs, sidebars:matches[0].docsSidebars});
|
||||
}
|
||||
}
|
||||
const {default:config} = await import('../.docusaurus/docusaurus.config.mjs');
|
||||
const entries = config.themeConfig.navbar.items.filter(i => i.type === 'docSidebar').map(i => `${i.docsPluginId || 'default'}:current:${i.sidebarId}`);
|
||||
const documents = auditSidebars(instances, entries);
|
||||
const routes = new Set(documents.map(d => `${d.route.replace(config.baseUrl, '')}/index.html`));
|
||||
const exclusions = [];
|
||||
const html = readdirSync('build', {recursive:true}).filter(f => f.endsWith('.html')).sort();
|
||||
for (const file of html) {
|
||||
if (routes.delete(file)) continue;
|
||||
let reason;
|
||||
if (file === 'index.html') reason = 'Dedicated React homepage, not a documentation page';
|
||||
else if (file === '404.html') reason = 'Docusaurus not-found system page';
|
||||
else if (file === 'search/index.html') reason = 'Local-search results UI, not a documentation page';
|
||||
else if (file === 'strategy/index.html') {
|
||||
assert(readFileSync(join('build',file),'utf8').includes('http-equiv="refresh"'), 'Strategy alias must remain a redirect');
|
||||
reason = 'Legacy Strategy redirect alias to Target';
|
||||
} else if (file === 'strategy/reference/measurement-contracts/index.html') {
|
||||
const body = readFileSync(join('build',file),'utf8');
|
||||
assert(body.includes('window.location.replace') && body.includes('name="robots" content="noindex"') && !body.includes('<article'), 'Metric alias must remain a non-indexed redirect');
|
||||
assert.equal(body, readFileSync(join('static',file),'utf8'));
|
||||
reason = 'Legacy measurement-contracts hash-aware redirect to canonical Measurement pages';
|
||||
} else if (file.startsWith('diagrams/') && readFileSync(join('build',file),'utf8').includes('<svg')) {
|
||||
assert.equal(readFileSync(join('build',file),'utf8'), readFileSync(join('static',file),'utf8'), `Viewer must match generated static asset: ${file}`);
|
||||
reason = 'Standalone diagram viewer asset, not documentation';
|
||||
}
|
||||
assert(reason, `Unclassified published HTML route: ${file}`);
|
||||
exclusions.push({file, reason});
|
||||
}
|
||||
assert.equal(routes.size, 0, `Missing published docs: ${[...routes]}`);
|
||||
// Check all local links and anchors on every document, not only selected Strategy pages.
|
||||
for (const {route} of documents) {
|
||||
const file = `build/${route.replace(config.baseUrl, '')}/index.html`;
|
||||
const body = readFileSync(file, 'utf8');
|
||||
for (const [, href] of body.matchAll(/href="([^" ]+)"/g)) {
|
||||
if (!href.startsWith(config.baseUrl) && !href.startsWith('#')) continue;
|
||||
const url = new URL(href, `https://docs.invalid${route}/`);
|
||||
let target = url.pathname.slice(config.baseUrl.length);
|
||||
if (!target || target.endsWith('/')) target += 'index.html';
|
||||
else if (!target.split('/').at(-1).includes('.')) target += '/index.html';
|
||||
const targetBody = readFileSync(join('build', decodeURIComponent(target)), 'utf8');
|
||||
if (url.hash) assert(targetBody.includes(`id="${decodeURIComponent(url.hash.slice(1))}"`), `Broken anchor: ${route} -> ${href}`);
|
||||
}
|
||||
}
|
||||
mkdirSync('.cache', {recursive:true});
|
||||
writeFileSync('.cache/sidebar-coverage.json', JSON.stringify({documents, exclusions}, null, 2));
|
||||
console.log(`PASS: ${documents.length} published docs reachable in resolved sidebars; ${exclusions.length} classified non-doc HTML routes; all doc links/anchors checked`);
|
||||
return {documents, exclusions};
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
import {test} from 'node:test';
|
||||
import assert from 'node:assert/strict';
|
||||
import {auditSidebars} from './sidebar-coverage.mjs';
|
||||
|
||||
const fixture = () => [{plugin:'strategy', version:'current', documents:[
|
||||
{id:'overview', path:'/strategy/overview/', sidebar:'main'},
|
||||
{id:'nested/reference', path:'/strategy/reference/', sidebar:'main'},
|
||||
], sidebars:{main:[{type:'category', label:'Stage', href:'/strategy/overview', items:[
|
||||
{type:'category', label:'Reference', items:[{type:'link', docId:'nested/reference', href:'/strategy/reference'}]},
|
||||
]}]}}];
|
||||
const entries = ['strategy:current:main'];
|
||||
test('resolved nested entries and linked category overviews both count', () => {
|
||||
assert.equal(auditSidebars(fixture(), entries).length, 2);
|
||||
});
|
||||
test('missing docs fail even if Docusaurus assigns a displayed sidebar', () => {
|
||||
const data = fixture();
|
||||
data[0].sidebars.main[0].items = [];
|
||||
assert.throws(() => auditSidebars(data, entries), /Missing sidebar document/);
|
||||
});
|
||||
test('new publishable docs and absent category overview links fail closed', () => {
|
||||
const data = fixture();
|
||||
data[0].documents.push({id:'new', path:'/new'});
|
||||
assert.throws(() => auditSidebars(data, entries), /Unreachable sidebar/);
|
||||
const withoutLink = fixture();
|
||||
delete withoutLink[0].sidebars.main[0].href;
|
||||
assert.throws(() => auditSidebars(withoutLink, entries), /Missing sidebar document/);
|
||||
});
|
||||
test('duplicate normalized routes and duplicate sidebar entries fail', () => {
|
||||
const data = fixture();
|
||||
data[0].documents.push({...data[0].documents[0], path:'/strategy/overview'});
|
||||
assert.throws(() => auditSidebars(data, entries), /Duplicate document ID/);
|
||||
data[0].documents.at(-1).id = 'different';
|
||||
assert.throws(() => auditSidebars(data, entries), /Duplicate document route/);
|
||||
const duplicate = fixture();
|
||||
duplicate[0].sidebars.main.push({type:'link', href:'/strategy/overview/'});
|
||||
assert.throws(() => auditSidebars(duplicate, entries), /Duplicate sidebar route/);
|
||||
});
|
||||
test('unlisted entries and unresolved sidebar types fail', () => {
|
||||
const data = fixture();
|
||||
data[0].sidebars.main[0].unlisted = true;
|
||||
assert.throws(() => auditSidebars(data, entries), /Hidden sidebar item/);
|
||||
data[0].sidebars.main[0] = {type:'autogenerated'};
|
||||
assert.throws(() => auditSidebars(data, entries), /Unresolved sidebar type/);
|
||||
});
|
||||
test('disconnected plugin menus fail, cross-plugin sidebar links make them reachable', () => {
|
||||
const data = fixture();
|
||||
data.push({plugin:'default', version:'current', documents:[{id:'help', path:'/docs/help', sidebar:'docs'}], sidebars:{docs:[{type:'link', href:'/docs/help'}]}});
|
||||
assert.throws(() => auditSidebars(data, entries), /Unreachable sidebar/);
|
||||
data[0].sidebars.main.push({type:'link', href:'/docs/help/'});
|
||||
assert.equal(auditSidebars(data, entries).length, 3);
|
||||
});
|
||||
@@ -4,29 +4,62 @@ import {readFileSync} from 'node:fs';
|
||||
import {calculate} from './ai-kpi.mjs';
|
||||
const read = path => readFileSync(path, 'utf8');
|
||||
|
||||
test('Skills Measurement is an open adoption collection plan, not a hidden catalogue', () => {
|
||||
const page = read('docs/strategy/measurement.mdx');
|
||||
assert.match(page, /title: Skills Measurement\nsidebar_label: Skills Measurement/);
|
||||
for (const heading of ['Establish the baseline', 'Measure the pilot', 'Extend collection as adoption grows', 'Keep the collection running']) assert(page.includes(heading), heading);
|
||||
assert(!page.includes('<details>'));
|
||||
assert(page.includes('./reference/measurement-contracts.mdx'));
|
||||
test('Skills Measurement is a visible optional registry, separate from workflow application', () => {
|
||||
const page = read('docs/strategy/measurement/index.mdx');
|
||||
assert.match(page, /title: Skills Measurement\nsidebar_label: Measurement/);
|
||||
for (const heading of ['Establish the baseline', 'Measure the pilot', 'Extend collection as adoption grows', 'Keep the collection running']) assert(!page.includes(heading), heading);
|
||||
assert(page.includes('Registry inclusion does not require a metric to be used, collected or baselined'));
|
||||
assert(page.includes('../baseline.mdx'));
|
||||
assert(page.includes('<summary>Implementation status—not live telemetry</summary>'));
|
||||
const visible = page.replace(/<details>[\s\S]*?<\/details>/g, '');
|
||||
assert.equal([...visible.matchAll(/^\d+\. \[/gm)].length,16,'All contract links remain visible');
|
||||
assert(page.includes('./collection-and-safeguards.mdx'));
|
||||
assert(!page.includes('Is AI-assisted work worth continuing?'));
|
||||
for (const word of ['Recommended', 'not installed', 'unknown', 'review', 'CI', 'revision', 'Monthly', 'Weekly']) assert(page.includes(word), word);
|
||||
for (const word of ['candidate', 'not installed', 'applicability', 'calculation', 'inputs', 'limitations', 'implementation status']) assert(page.includes(word), word);
|
||||
});
|
||||
|
||||
test('all sixteen metric definitions remain in the reference with explicit implementation limits', () => {
|
||||
const page = read('docs/strategy/reference/measurement-contracts.mdx');
|
||||
const manifest = JSON.parse(read('research/ai-adoption/measurement-migration.json'));
|
||||
const page = read('docs/strategy/measurement/index.mdx') + read('docs/strategy/measurement/collection-and-safeguards.mdx');
|
||||
const model = JSON.parse(read('research/ai-adoption/strategy-model.json'));
|
||||
for (const k of model.kpis) {
|
||||
const section = page.split(`### ${k.name}\n`)[1]?.split('\n### ')[0];
|
||||
const section = read(`docs/strategy/${manifest.metrics.find(m => m.title === k.name).docId}.mdx`);
|
||||
assert(section, k.name);
|
||||
for (const field of ['Numerator','Denominator','Expression','Aggregation','Unit','Eligible population','Exclusions','Events and source','Owner / cadence','Missing evidence','Gaming and limits']) assert(section.includes(`| ${field} |`));
|
||||
}
|
||||
for (const text of ['9 prototype calculations', '7 unimplemented metrics', 'no network collectors', '30 days', '12 months', 'below five people', 'Missing telemetry is unknown']) assert(page.includes(text), text);
|
||||
});
|
||||
|
||||
test('two groups exhaustively classify the sixteen canonical contracts without duplication', () => {
|
||||
const page = read('docs/strategy/measurement/index.mdx');
|
||||
const manifest = JSON.parse(read('research/ai-adoption/measurement-migration.json'));
|
||||
assert.deepEqual([...page.matchAll(/^### (.+)$/gm)].map(m => m[1]), ['Workflow effectiveness', 'Skills effectiveness & health']);
|
||||
const rows = [...page.matchAll(/^\d+\. \[([^\]]+)\]\(\.\/([^/]+)\.mdx\) — \*\*(Prototype calculation|Unimplemented metric)\.\*\*/gm)];
|
||||
assert.equal(rows.length, 16);
|
||||
assert.equal(new Set(rows.map(m => m[2])).size, 16);
|
||||
assert.deepEqual(rows.map(m => m[1]).sort(), manifest.metrics.map(m => m.title).sort());
|
||||
assert.equal(rows.filter(m => m[3] === 'Prototype calculation').length, 9);
|
||||
assert.equal(rows.filter(m => m[3] === 'Unimplemented metric').length, 7);
|
||||
const [workflow, skills] = page.split('### Workflow effectiveness')[1].split('### Skills effectiveness & health');
|
||||
assert.equal([...workflow.matchAll(/^\d+\. /gm)].length, 11);
|
||||
assert.equal([...skills.matchAll(/^\d+\. /gm)].length, 5);
|
||||
for (const slug of ['validated-task-success', 'confirmed-policy-effects', 'cost-per-accepted-outcome', 'workflow-specific-business-acceptance']) assert(workflow.includes(`./${slug}.mdx`));
|
||||
for (const slug of ['skill-selection-precision', 'skill-selection-recall', 'supported-bundle-coverage', 'approved-workflow-adoption', 'skills-within-substantive-review-window']) assert(skills.includes(`./${slug}.mdx`));
|
||||
for (const marker of ['N/A, not zero', 'More adoption does not prove improved work', 'Before/after trends alone are not causal evidence', 'Sandbox/evaluation cases remain excluded']) assert(page.includes(marker), marker);
|
||||
});
|
||||
|
||||
test('workflow task-success contract retains evaluation exclusions and explains conditional skill slices', () => {
|
||||
const page = read('docs/strategy/measurement/validated-task-success.mdx');
|
||||
assert.equal((page.match(/\| Expression \|/g) || []).length, 1);
|
||||
for (const marker of ['sandbox/evaluation tasks', 'Overlapping skill slices must not be summed', 'remains excluded by this contract', 'does not introduce an implemented skill-evaluation metric', 'N/A, not a zero workflow success rate']) assert(page.includes(marker), marker);
|
||||
for (const name of ['baseline', 'skills-adoption', 'skills-maintenance', 'stage-01-skills-adoption']) {
|
||||
const text = read(`docs/strategy/${name}.mdx`);
|
||||
if (name !== 'stage-01-skills-adoption') for (const group of ['Workflow effectiveness', 'Skills effectiveness & health']) assert(text.includes(group), name);
|
||||
}
|
||||
});
|
||||
|
||||
test('published pilot arithmetic matches the executable fixture, including partial cost', () => {
|
||||
const page = read('docs/strategy/measurement.mdx');
|
||||
const page = read('docs/strategy/skills-adoption.mdx');
|
||||
const fixture = JSON.parse(read('scripts/fixtures/ai-kpi-synthetic.json'));
|
||||
const report = calculate(fixture);
|
||||
const success = report.kpis['validated-task-success'];
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
import {test} from 'node:test';
|
||||
import assert from 'node:assert/strict';
|
||||
import {readFileSync, mkdtempSync, rmSync} from 'node:fs';
|
||||
import {tmpdir} from 'node:os';
|
||||
import {join} from 'node:path';
|
||||
import {execFileSync} from 'node:child_process';
|
||||
import {skillsViewer,isSkillsStory} from './skills-viewer.mjs';
|
||||
const read = p => readFileSync(p,'utf8');
|
||||
const topics = ['measurement','baseline','governance','quality','adoption','maintenance'];
|
||||
test('all seven Skills Adoption pages include their own native diagram story',()=>{
|
||||
let count=0;
|
||||
for(const route of ['stage-01-skills-adoption',...topics.map(t=>['measurement','baseline'].includes(t)?t:`skills-${t}`)]){
|
||||
const diagrams=[...read(`docs/strategy/${route === 'measurement' ? 'measurement/index' : route}.mdx`).matchAll(/<ArchifyDiagram name="([^"]+)"/g)];
|
||||
assert.equal(diagrams.length,1);
|
||||
for(const [,name] of diagrams){assert(isSkillsStory(name));for(const suffix of ['','-mobile'])JSON.parse(read(`diagrams/${name}${suffix}.architecture.json`));count++;}
|
||||
}
|
||||
assert.equal(count,7);assert(!isSkillsStory('strategy-target'));assert(!isSkillsStory('strategy-roadmap'));
|
||||
});
|
||||
for(const topic of topics) test(`${topic}: rich native source, wide desktop, mobile parity and checked adapter`,()=>{
|
||||
const name=`strategy-${topic}`;const desktop=JSON.parse(read(`diagrams/${name}.architecture.json`));
|
||||
const mobile=JSON.parse(read(`diagrams/${name}-mobile.architecture.json`));
|
||||
const semantic = d=>d.components.map(({pos,size,...n})=>n);
|
||||
assert.deepEqual(semantic(desktop),semantic(mobile));
|
||||
assert(new Set(desktop.components.map(n=>n.pos[0])).size>1);
|
||||
assert.equal(new Set(mobile.components.map(n=>n.pos[0])).size,1);
|
||||
for(const n of desktop.components){assert(n.tag);assert(n.sublabel);assert(n.sublabel.split('\n').length<=4);}
|
||||
const dir=mkdtempSync(join(tmpdir(),'skills-viewer-'));
|
||||
try{
|
||||
const path=join(dir,'native.html');
|
||||
execFileSync(process.execPath,['vendor/archify/renderers/architecture/render-architecture.mjs',`diagrams/${name}.architecture.json`,path]);
|
||||
const native=read(path);const html=skillsViewer(native,desktop);
|
||||
assert.equal((html.match(/<g\b[^>]*data-node-id=/g)||[]).length,desktop.components.length);
|
||||
assert.equal((html.match(/<text data-node-label=/g)||[]).length,0); // Adapter uses explicit position before semantic attributes.
|
||||
assert.equal((html.match(/data-node-label=""/g)||[]).length,desktop.components.length);
|
||||
assert(html.includes('eldorado-skills-typography'));
|
||||
assert.throws(()=>skillsViewer(native.replace('data-node-id="'+desktop.components[0].id+'"','data-node-id="missing"'),desktop));
|
||||
const bad=structuredClone(desktop);bad.components[0].sublabel='';assert.throws(()=>skillsViewer(native,bad));
|
||||
}finally{rmSync(dir,{recursive:true,force:true});}
|
||||
});
|
||||
test('domain contracts retain human authority, honest measures and Delivery-first rollout',()=>{
|
||||
const text=t=>JSON.stringify(JSON.parse(read(`diagrams/strategy-${t}.architecture.json`)));
|
||||
assert(text('governance').includes('Author is not sole approver'));
|
||||
assert(text('quality').includes('Critical effect blocks'));
|
||||
assert(text('adoption').includes('Delivery first')&&text('adoption').includes('Later order undecided'));
|
||||
assert(text('adoption').includes('No quotas or rankings'));
|
||||
for(const marker of ['Workflow effectiveness','Skills effectiveness & health','Quality: artifact fitness + safety','No mandatory collection','Before / after is not causality','Candidate / approved regression'])assert(text('measurement').includes(marker),marker);
|
||||
assert(text('maintenance').includes('No automatic reinstatement'));
|
||||
});
|
||||
test('topic compositions explain distinct relationships rather than a fixed card count',()=>{
|
||||
const spec=t=>JSON.parse(read(`diagrams/strategy-${t}.architecture.json`));
|
||||
const has=(d,a,b)=>assert(d.connections.some(e=>e.from===a&&e.to===b),`${a} → ${b}`);
|
||||
const g=spec('governance');const steps=g.components.filter(n=>/^0[1-6]/.test(n.label));
|
||||
assert.equal(steps.length,6);
|
||||
for(let i=1;i<steps.length;i++){assert(steps[i].pos[0]>steps[i-1].pos[0]);assert(steps[i].pos[1]>steps[i-1].pos[1]);has(g,steps[i-1].id,steps[i].id);}
|
||||
has(g,'approve','owner');has(g,'distribute','withdraw');
|
||||
const q=spec('quality');for(const id of ['selection','safety','artifact','outcome'])has(q,id,'gate');has(q,'gate','accept');has(q,'gate','rework');
|
||||
const a=spec('adoption');for(const [x,y] of [['human','agent'],['agent','human'],['agent','learn'],['learn','delivery'],['learn','expand'],['human','expand']])has(a,x,y);
|
||||
const m=spec('measurement');for(const [x,y] of [['workflow','compare'],['compare','interpret'],['skills','observe'],['observe','improve'],['interpret','improve']])has(m,x,y);
|
||||
const b=spec('baseline');for(const [x,y] of [['workflow','selection'],['selection','evidence'],['evidence','position'],['position','comparison']])has(b,x,y);
|
||||
const c=spec('maintenance');for(const [x,y] of [['observe','triage'],['triage','change'],['change','validate'],['validate','release'],['release','observe'],['triage','safe'],['safe','observe'],['triage','retire'],['triage','contain'],['contain','change']])has(c,x,y);
|
||||
});
|
||||
@@ -0,0 +1,45 @@
|
||||
// Native editable geometry and edges; scoped editorial typography for Stage 01.
|
||||
export const isSkillsStory = name => /^strategy-(governance|quality|adoption|measurement|baseline|maintenance|stage01|stage02)(-mobile)?$/.test(name);
|
||||
const escape = text => text.replaceAll('&', '&').replaceAll('<', '<').replaceAll('>', '>').replaceAll('"', '"');
|
||||
export function skillsViewer(html, spec) {
|
||||
if (spec.diagram_type !== 'architecture' || !spec.components.length) throw new Error('Skills story contract drift');
|
||||
const stageMobile = /strategy-stage0[12]-mobile\//.test(spec.meta.output);
|
||||
const detailSize = stageMobile ? 38 : spec.meta.output.includes('-mobile/') ? 34 : 32;
|
||||
for (const node of spec.components) {
|
||||
const pattern = new RegExp(`<g\\b[^>]*data-node-id="${node.id}"[^>]*>[\\s\\S]*?<text data-node-label=[\\s\\S]*?</g>`);
|
||||
const match = html.match(pattern);
|
||||
if (!match) throw new Error(`Missing Skills node: ${node.id}`);
|
||||
const original = match[0];
|
||||
const rectangles = [...original.matchAll(/<rect\b[^>]*class="c-[^"]+"[^>]*\/>/g)];
|
||||
if (rectangles.length !== 2) throw new Error('Skills shape contract drift');
|
||||
const [x,y] = node.pos;
|
||||
const lines = node.sublabel.split('\n');
|
||||
if (!node.tag || !node.sublabel || lines.length > 4) throw new Error(`Skills copy exceeds capacity: ${node.id}`);
|
||||
const text = (value, top, size, attrs) => `<text x="${x+28}" y="${y+top}" font-size="${size}" ${attrs}>${escape(value)}</text>`;
|
||||
const content = text(node.tag, 40, detailSize, 'class="t-muted" data-detail="context"')
|
||||
+ text(node.label, 89, stageMobile ? 40 : 36, 'class="t-primary" data-node-label="" font-weight="700"')
|
||||
+ lines.map((line,i) => text(line, 138+i*42, detailSize, 'class="t-primary" data-detail="context"')).join('');
|
||||
const prefix = original.slice(0,rectangles[1].index+rectangles[1][0].length).replaceAll('rx="6"','rx="0"');
|
||||
html = html.replace(original,prefix+content+'</g>');
|
||||
}
|
||||
const roots = [...html.matchAll(/<svg\b[^>]*role="img"[^>]*>/g)];
|
||||
if (roots.length !== 1) throw new Error('Skills SVG contract drift');
|
||||
const [width,height] = spec.meta.viewBox;
|
||||
const root = roots[0][0].replace(/viewBox="[^"]*"/,`viewBox="0 0 ${width} ${height}"`);
|
||||
// Embedded in SVG so downloaded files retain typography without the viewer.
|
||||
html = html.replace(roots[0][0],root+`<style id="eldorado-skills-typography">
|
||||
[data-node-id] text {font-family:Arial,sans-serif;}
|
||||
rect[fill="url(#grid)"] {opacity:0;}
|
||||
[data-node-id] > rect:not(.c-mask) {stroke-width:3;}
|
||||
[data-edge-id] {opacity:1;}
|
||||
</style>`);
|
||||
// Native labels use tiny technical annotations. Enlarge both text and mask,
|
||||
// retaining the native edge identity, routing and explicit label position.
|
||||
html = html.replace(/(<g data-detail="context"[^>]*data-edge-id[^>]*>)([\s\S]*?)(<\/g>)/g, (all,open,body,close) => {
|
||||
const text = body.match(/<text x="([^"]+)" y="([^"]+)"([^>]*)>([\s\S]*?)<\/text>/);
|
||||
if (!text) throw new Error('Skills edge label contract drift');
|
||||
const x=Number(text[1]), y=Number(text[2]), width=text[4].replace(/&[^;]+;/g,'x').length*17+24;
|
||||
return open+`<rect x="${x-width/2}" y="${y-34}" width="${width}" height="44" class="c-mask"/>`+text[0].replace('font-size="8"',`font-size="${detailSize}"`)+close;
|
||||
});
|
||||
return html;
|
||||
}
|
||||
@@ -1,17 +1,51 @@
|
||||
import {test} from 'node:test';
|
||||
import assert from 'node:assert/strict';
|
||||
import {readFileSync, existsSync} from 'node:fs';
|
||||
import {runInNewContext} from 'node:vm';
|
||||
import ts from 'typescript';
|
||||
const read = p => readFileSync(p, 'utf8');
|
||||
|
||||
test('Strategy has one canonical Target, then Roadmap, without a landing menu duplicate', () => {
|
||||
const sidebar = read('sidebars/strategy.ts').split('strategySidebar: [')[1].split(']')[0];
|
||||
const ids = [...sidebar.matchAll(/'([^']+)'/g)].map(match => match[1]);
|
||||
assert.deepEqual(ids, ['target-operating-model', 'roadmap', 'skills-governance', 'skills-quality', 'skills-adoption', 'measurement', 'skills-maintenance']);
|
||||
assert.equal(ids.filter(id => id === 'target-operating-model').length, 1);
|
||||
test('Strategy has Target, Roadmap, a linked Skills Adoption category and Autonomous Agent', () => {
|
||||
const compiled = ts.transpileModule(read('sidebars/strategy.ts'), {compilerOptions:{module:ts.ModuleKind.CommonJS}}).outputText;
|
||||
const sandbox = {exports:{}};
|
||||
runInNewContext(compiled, sandbox);
|
||||
const sidebar = JSON.parse(JSON.stringify(sandbox.exports.default.strategySidebar));
|
||||
assert.deepEqual(sidebar, ['target-operating-model', 'roadmap', {
|
||||
type:'category', label:'Stage - 01 - Skills Adoption',
|
||||
link:{type:'doc', id:'stage-01-skills-adoption'}, collapsed:true,
|
||||
items:[
|
||||
{type:'category', label:'Measurement', collapsed:true, link:{type:'doc', id:'measurement/index'}, items:[
|
||||
...JSON.parse(read('research/ai-adoption/measurement-migration.json')).metrics.map(m => m.docId),
|
||||
'measurement/collection-and-safeguards','measurement/synthetic-example',
|
||||
]},
|
||||
{type:'doc', id:'baseline', label:'Baseline'},
|
||||
{type:'doc', id:'skills-governance', label:'Governance'},
|
||||
{type:'doc', id:'skills-quality', label:'Quality'},
|
||||
{type:'doc', id:'skills-adoption', label:'Adoption'},
|
||||
{type:'doc', id:'skills-maintenance', label:'Maintenance'},
|
||||
|
||||
],
|
||||
}, 'stage-02-autonomous-agent']);
|
||||
assert.match(read('docs/strategy/target-operating-model.mdx'), /^sidebar_label: Target$/m);
|
||||
assert.match(read('docusaurus.config.ts'), /type: 'docSidebar', docsPluginId: 'strategy', sidebarId: 'strategySidebar', label: 'Strategy'/);
|
||||
});
|
||||
|
||||
test('stage overviews explain the foundation and future without replacing topic content', () => {
|
||||
const first = read('docs/strategy/stage-01-skills-adoption.mdx');
|
||||
const second = read('docs/strategy/stage-02-autonomous-agent.mdx');
|
||||
for (const [id, title, page] of [
|
||||
['stage-01-skills-adoption', 'Stage - 01 - Skills Adoption', first],
|
||||
['stage-02-autonomous-agent', 'Stage - 02 - Autonomous Agent', second],
|
||||
]) {
|
||||
assert(page.includes(`id: ${id}\ntitle: ${title}`));
|
||||
for (const link of ['./roadmap.mdx', './target-operating-model.mdx']) assert(page.includes(link));
|
||||
}
|
||||
for (const id of ['measurement/index','baseline','skills-governance','skills-quality','skills-adoption','skills-maintenance']) assert(first.includes(`./${id}.mdx`));
|
||||
for (const marker of ['human + AI Agent','Delivery first','order is not yet decided','KPIs','baseline','topology','feedback','new current situation']) assert(first.includes(marker), marker);
|
||||
for (const marker of ['future','proven skills','measurements','working practices','direction and review','not deployed autonomy','approved KPI thresholds']) assert(second.includes(marker), marker);
|
||||
assert.match(read('docs/strategy/measurement/index.mdx'), /^title: Skills Measurement\nsidebar_label: Measurement$/m);
|
||||
});
|
||||
|
||||
test('old Strategy entry redirects to Target instead of maintaining a second document', () => {
|
||||
assert(!existsSync('docs/strategy/index.mdx'));
|
||||
assert.match(read('docusaurus.config.ts'), /'@docusaurus\/plugin-client-redirects'/);
|
||||
|
||||
@@ -6,43 +6,50 @@ const model = JSON.parse(read('research/ai-adoption/strategy-model.json'));
|
||||
|
||||
test('every strategy page leads with a compact diagram story and closes its references', () => {
|
||||
for (const {id} of model.pages) {
|
||||
const page = read(`docs/strategy/${id}.mdx`);
|
||||
const page = read(`docs/strategy/${id === 'measurement' ? 'measurement/index' : id}.mdx`);
|
||||
const narrative = page.split('<div className="strategy-content">')[1].replace(/<details>[\s\S]*?<\/details>/g, '');
|
||||
assert.equal((narrative.match(/<ArchifyDiagram /g) || []).length, 1, id);
|
||||
assert.equal((narrative.match(/<ArchifyDiagram /g) || []).length, id === 'roadmap' ? 3 : 1, id);
|
||||
assert(narrative.includes(' story />'), id);
|
||||
assert(!page.includes('<details>') || page.indexOf(' story />') < page.indexOf('<details>'), id);
|
||||
assert(!/<details\s+open/.test(page), id);
|
||||
assert.equal((page.match(/<details>/g) || []).length, (page.match(/<\/details>/g) || []).length, id);
|
||||
assert.equal((narrative.match(/^## /gm) || []).length, id === 'measurement' ? 4 : id === 'roadmap' ? 5 : 1, id);
|
||||
assert((narrative.match(/^- /gm) || []).length <= 3, id);
|
||||
assert(narrative.includes('**Next:**'), id);
|
||||
assert((narrative.match(/^## /gm) || []).length <= 4, id);
|
||||
assert((narrative.match(/^- /gm) || []).length <= 7, id);
|
||||
assert(/\*\*(Next|Continue the loop):\*\*/.test(narrative), id);
|
||||
assert(!narrative.includes('| ---'), id);
|
||||
const words = narrative.replace(/<[^>]*>/g, '').trim().split(/\s+/).length;
|
||||
assert(words <= (id === 'measurement' ? 1100 : id === 'roadmap' ? 600 : 200), `${id}: ${words} default narrative words`);
|
||||
assert(words <= (id === 'measurement' ? 1600 : id === 'roadmap' ? 600 : 500), `${id}: ${words} default narrative words`);
|
||||
}
|
||||
});
|
||||
|
||||
test('mobile story diagrams preserve the same nodes and directed relationships', () => {
|
||||
for (const {id} of model.pages) {
|
||||
const page = read(`docs/strategy/${id}.mdx`);
|
||||
const page = read(`docs/strategy/${id === 'measurement' ? 'measurement/index' : id}.mdx`);
|
||||
const name = /<ArchifyDiagram name="([^"]+)"[^>]+ story/.exec(page)[1];
|
||||
if (name === 'strategy-roadmap') {
|
||||
const desktop = JSON.parse(read(`diagrams/${name}.workflow.json`));
|
||||
const mobile = JSON.parse(read(`diagrams/${name}-mobile.workflow.json`));
|
||||
const semantic = d => ({nodes:d.nodes.map(({col,yOffset,...n}) => n), edges:d.edges.map(({fromSide,toSide,...e}) => e)});
|
||||
assert.deepEqual(semantic(desktop), semantic(mobile));
|
||||
continue;
|
||||
}
|
||||
const desktop = JSON.parse(read(`diagrams/${name}.architecture.json`));
|
||||
const mobile = JSON.parse(read(`diagrams/${name}-mobile.architecture.json`));
|
||||
assert(desktop.components.length >= 5 && desktop.components.length <= (name === 'strategy-target' ? 18 : 7), name);
|
||||
const semantic = d => ({nodes:d.components.map(({pos,size,...n})=>n),edges:d.connections.map(({fromSide,toSide,via,labelAt,...e})=>e)});
|
||||
assert(desktop.components.length >= 5, name);
|
||||
const semantic = d => ({nodes:d.components.map(({pos,size,...n})=>n),edges:d.connections.map(({fromSide,toSide,route,via,labelAt,...e})=>e)});
|
||||
assert.deepEqual(semantic(desktop), semantic(mobile), name);
|
||||
assert(desktop.connections.every(e => (e.label || e.id.startsWith('govern-')) && e.from !== e.to), name);
|
||||
assert(desktop.connections.every(e => (e.label || e.id.startsWith('govern-') || /^strategy-(governance|quality|adoption|measurement|maintenance)$/.test(name)) && e.from !== e.to), name);
|
||||
assert.equal(desktop.meta.legend.mode, 'hidden');
|
||||
}
|
||||
});
|
||||
|
||||
test('all sixteen exact KPI formulas remain reachable in the linked reference', () => {
|
||||
assert(read('docs/strategy/measurement.mdx').includes('./reference/measurement-contracts.mdx'));
|
||||
const page = read('docs/strategy/reference/measurement-contracts.mdx');
|
||||
const contracts = page.split('## Metric contracts')[1].split('## Run the synthetic')[0];
|
||||
assert.equal((contracts.match(/^### /gm) || []).length, 16);
|
||||
const manifest = JSON.parse(read('research/ai-adoption/measurement-migration.json'));
|
||||
assert.equal(manifest.metrics.length, 16);
|
||||
for (const metric of model.kpis) {
|
||||
const section = contracts.split(`### ${metric.name}\n`)[1]?.split('\n### ')[0];
|
||||
const entry = manifest.metrics.find(m => m.title === metric.name);
|
||||
assert(read('docs/strategy/measurement/index.mdx').includes(`./${entry.oldAnchor}.mdx`));
|
||||
const section = read(`docs/strategy/${entry.docId}.mdx`);
|
||||
assert(section, metric.name);
|
||||
for (const label of ['Numerator','Denominator','Expression','Aggregation','Unit','Eligible population','Exclusions','Events and source','Owner / cadence','Missing evidence','Gaming and limits']) assert(section.includes(`| ${label} |`), `${metric.name}: ${label}`);
|
||||
}
|
||||
|
||||
@@ -3,15 +3,16 @@ import assert from 'node:assert/strict';
|
||||
import {readFileSync, readdirSync} from 'node:fs';
|
||||
const read = p => readFileSync(p, 'utf8');
|
||||
const model = JSON.parse(read('research/ai-adoption/strategy-model.json'));
|
||||
test('seven canonical strategy pages preserve target boundary and separate evidence', () => {
|
||||
test('seven existing strategy pages and two stage overviews preserve canonical routes', () => {
|
||||
assert.equal(model.pages.length, 7);
|
||||
assert.equal(readdirSync('docs/strategy').filter(p => p.endsWith('.mdx')).length, 7);
|
||||
assert.deepEqual(readdirSync('docs/strategy').filter(p => p.endsWith('.mdx')).sort(),
|
||||
[...model.pages.filter(p => p.id !== 'measurement').map(({id}) => `${id}.mdx`), 'stage-01-skills-adoption.mdx', 'stage-02-autonomous-agent.mdx', 'baseline.mdx'].sort());
|
||||
for (const {id} of model.pages) {
|
||||
const page = read(`docs/strategy/${id}.mdx`);
|
||||
assert(page.includes(`id: ${id}`));
|
||||
const page = read(`docs/strategy/${id === 'measurement' ? 'measurement/index' : id}.mdx`);
|
||||
assert(page.includes(`id: ${id === 'measurement' ? 'index' : id}`));
|
||||
assert(page.includes('Target operating model'));
|
||||
assert(!/## Sources|\[\d+\]|Internal evidence mapping/.test(page));
|
||||
assert(read('sidebars/strategy.ts').includes(`'${id}'`));
|
||||
assert(read('sidebars/strategy.ts').includes(`'${id === 'measurement' ? 'measurement/index' : id}'`));
|
||||
}
|
||||
for (const teams of Object.values(model.organization)) for (const name of teams) {
|
||||
assert(read('docs/organization/structure.mdx').includes(name));
|
||||
@@ -19,15 +20,15 @@ test('seven canonical strategy pages preserve target boundary and separate evide
|
||||
}
|
||||
});
|
||||
test('every metric has an actionable reader-facing contract', () => {
|
||||
const page = read('docs/strategy/reference/measurement-contracts.mdx');
|
||||
const manifest = JSON.parse(read('research/ai-adoption/measurement-migration.json'));
|
||||
assert.equal(model.kpis.length,16);
|
||||
for (const k of model.kpis) {
|
||||
const section=page.split(`### ${k.name}\n`)[1]?.split('\n### ')[0];
|
||||
const section=read(`docs/strategy/${manifest.metrics.find(m => m.title === k.name).docId}.mdx`);
|
||||
assert(section,k.name);
|
||||
for (const field of ['Eligible population','Exclusions','Events and source','Owner / cadence','Missing evidence','Gaming and limits']) assert(section.includes(`| ${field} |`));
|
||||
assert(section.includes(k.owner));
|
||||
}
|
||||
assert(page.includes('synthetic') && page.includes('not a production ingestion system'));
|
||||
assert(read('docs/strategy/measurement/synthetic-example.mdx').includes('not a production ingestion system'));
|
||||
});
|
||||
test('diagram preserves independent release approval and no agent production authority', () => {
|
||||
const d=JSON.parse(read('diagrams/ai-adoption-target.architecture.json'));
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
import {test} from 'node:test';
|
||||
import assert from 'node:assert/strict';
|
||||
import {readFileSync} from 'node:fs';
|
||||
import {createRouter} from '../vendor/archify/renderers/architecture/routing.mjs';
|
||||
import {segmentIntersectsRect} from '../vendor/archify/renderers/shared/geometry.mjs';
|
||||
|
||||
for (const suffix of ['', '-mobile']) {
|
||||
test(`Target${suffix} uses shared native midpoint ports without node crossings`, () => {
|
||||
const diagram = JSON.parse(readFileSync(`diagrams/strategy-target${suffix}.architecture.json`, 'utf8'));
|
||||
const boxes = new Map(diagram.components.map(({id, pos: [x, y], size: [width, height]}) =>
|
||||
[id, {id, x, y, width, height, cx: x + width / 2, cy: y + height / 2}]));
|
||||
const router = createRouter(boxes, diagram.connections, {distinctAutomaticPorts: true});
|
||||
const agent = boxes.get('agent');
|
||||
for (const edge of diagram.connections.filter(edge => edge.from === 'agent')) {
|
||||
const side = suffix ? 'left' : ['scope', 'architecture', 'releases'].includes(edge.to) ? 'top'
|
||||
: ['planning', 'delivery', 'uat'].includes(edge.to) ? 'bottom' : edge.to === 'security' ? 'left' : 'right';
|
||||
assert.equal(edge.fromSide, side, edge.id);
|
||||
assert(edge.via || (edge.route && edge.route !== 'auto'), `${edge.id} must opt out of automatic port spreading`);
|
||||
const expected = {top: [agent.cx, agent.y], bottom: [agent.cx, agent.y + agent.height],
|
||||
left: [agent.x, agent.cy], right: [agent.x + agent.width, agent.cy]}[side];
|
||||
const points = router.pathFor(edge).points;
|
||||
assert.deepEqual(points[0], expected, edge.id);
|
||||
for (let i = 1; i < points.length; i++) {
|
||||
for (const box of boxes.values()) {
|
||||
if ([edge.from, edge.to].includes(box.id)) continue;
|
||||
assert(!segmentIntersectsRect({start: points[i - 1], end: points[i]}, box), `${edge.id} crosses ${box.id}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
// Owned desktop-only integration, applied AFTER native artifact verification.
|
||||
// Native architecture JSON has no per-edge attachment offset. Keep the central
|
||||
// governance ports native; shift only these lifecycle channels on the same sides.
|
||||
export const targetLifecycleOffsets = [
|
||||
{id:'stage-2', from:'architecture', to:'ui-ux', x:870, shiftedX:850, y1:262.5, y2:457.5},
|
||||
{id:'stage-3', from:'ui-ux', to:'planning', x:870, shiftedX:850, y1:532.5, y2:727.5},
|
||||
{id:'stage-6', from:'uat', to:'security', x:330, shiftedX:350, y1:727.5, y2:532.5},
|
||||
{id:'stage-7', from:'security', to:'releases', x:330, shiftedX:350, y1:457.5, y2:262.5},
|
||||
];
|
||||
|
||||
export function targetRouting(viewer) {
|
||||
for (const {id, from, to, x, shiftedX, y1, y2} of targetLifecycleOffsets) {
|
||||
const oldPath = `M ${x} ${y1} L ${x} ${y2}`;
|
||||
const newPath = `M ${shiftedX} ${y1} L ${shiftedX} ${y2}`;
|
||||
const oldPoints = `${x},${y1};${x},${y2}`;
|
||||
const newPoints = `${shiftedX},${y1};${shiftedX},${y2}`;
|
||||
// Match the whole native crossover group: its mask must move with the edge.
|
||||
// Trace/export use this actual path; composition checks use its point list.
|
||||
const groups = [...viewer.matchAll(/<g data-graph-role="automatic-crossover"[^>]*>\s*<path\b[^>]*\/>\s*<path\b[^>]*\/>\s*<\/g>/g)]
|
||||
.filter(([group]) => group.includes(`data-edge-id="${id}"`));
|
||||
if (groups.length !== 1) throw new Error(`Target routing drift: ${id} group`);
|
||||
const group = groups[0][0];
|
||||
for (const attribute of [`data-edge-from="${from}"`, `data-edge-to="${to}"`, `data-composition-points="${oldPoints}"`, 'data-graph-role="automatic-crossover-underlay"']) {
|
||||
if (!group.includes(attribute)) throw new Error(`Target routing drift: ${id} ${attribute}`);
|
||||
}
|
||||
if (group.split(`d="${oldPath}"`).length !== 3) throw new Error(`Target routing drift: ${id} paths`);
|
||||
const shifted = group.replaceAll(`d="${oldPath}"`, `d="${newPath}"`)
|
||||
.replace(`data-composition-points="${oldPoints}"`, `data-composition-points="${newPoints}"`);
|
||||
viewer = viewer.replace(group, shifted);
|
||||
}
|
||||
return viewer;
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
import {test} from 'node:test';
|
||||
import assert from 'node:assert/strict';
|
||||
import {targetRouting, targetLifecycleOffsets} from './target-routing.mjs';
|
||||
|
||||
const fixture = targetLifecycleOffsets.map(({id, from, to, x, y1, y2}) => `<g data-graph-role="automatic-crossover" style="--step:9">
|
||||
<path data-graph-role="automatic-crossover-underlay" d="M ${x} ${y1} L ${x} ${y2}"/>
|
||||
<path data-edge-from="${from}" data-edge-to="${to}" data-edge-id="${id}" data-composition-points="${x},${y1};${x},${y2}" d="M ${x} ${y1} L ${x} ${y2}" marker-end="url(#arrowhead-emphasis)"/>
|
||||
</g>`).join('\n');
|
||||
|
||||
test('Target adapter shifts precisely four paths, masks and composition points', () => {
|
||||
const unrelated = '<path data-edge-id="govern-architecture" d="M 600 450 L 870 262.5"/><g data-node-id="agent"/>';
|
||||
const output = targetRouting(fixture + unrelated);
|
||||
assert(output.endsWith(unrelated));
|
||||
let restored = output;
|
||||
for (const {x, shiftedX, y1, y2} of targetLifecycleOffsets) {
|
||||
assert.equal(output.split(`d="M ${shiftedX} ${y1} L ${shiftedX} ${y2}"`).length, 3);
|
||||
assert(output.includes(`data-composition-points="${shiftedX},${y1};${shiftedX},${y2}"`));
|
||||
restored = restored.replaceAll(`d="M ${shiftedX} ${y1} L ${shiftedX} ${y2}"`, `d="M ${x} ${y1} L ${x} ${y2}"`)
|
||||
.replace(`data-composition-points="${shiftedX},${y1};${shiftedX},${y2}"`, `data-composition-points="${x},${y1};${x},${y2}"`);
|
||||
}
|
||||
assert.equal(restored, fixture + unrelated, 'all other bytes preserved');
|
||||
});
|
||||
|
||||
test('Target adapter fails closed on missing, duplicate, moved or changed native edges', () => {
|
||||
for (const changed of [fixture.replace('stage-2', 'missing'), fixture + fixture,
|
||||
fixture.replace('870 262.5', '871 262.5'), fixture.replace('870,262.5', '871,262.5'),
|
||||
fixture.replace('data-edge-from="architecture"', 'data-edge-from="scope"'),
|
||||
fixture.replace('automatic-crossover-underlay', 'unknown')]) {
|
||||
assert.throws(() => targetRouting(changed), /Target routing drift/);
|
||||
}
|
||||
assert.throws(() => targetRouting(targetRouting(fixture)), /Target routing drift/);
|
||||
});
|
||||
+13
-2
@@ -1,6 +1,8 @@
|
||||
import assert from 'node:assert/strict';
|
||||
import {readFileSync, readdirSync, existsSync} from 'node:fs';
|
||||
import {join} from 'node:path';
|
||||
import {verifySidebarCoverage} from './sidebar-coverage.mjs';
|
||||
import {verifyMeasurementPages} from './measurement-pages.mjs';
|
||||
const read = p => readFileSync(p, 'utf8');
|
||||
const config = read('docusaurus.config.ts');
|
||||
assert(config.includes("baseUrl: '/eldorado-v1/documentation/'"));
|
||||
@@ -16,15 +18,24 @@ const workflow = read('.gitea/workflows/pages.yml');
|
||||
assert(workflow.includes('mountpoint -q'));
|
||||
assert(workflow.includes("gitea.event_name == 'push' && gitea.ref == 'refs/heads/main'"));
|
||||
if (process.argv.includes('--build')) {
|
||||
await verifySidebarCoverage();
|
||||
verifyMeasurementPages();
|
||||
const model = JSON.parse(read('research/ai-adoption/strategy-model.json'));
|
||||
const indexes = readdirSync('build').filter(f => /^search-index.*\.json$/.test(f)).map(f => read(join('build',f))).join('\n');
|
||||
assert(indexes.includes('/eldorado-v1/documentation/strategy/baseline/'), 'Missing indexed Baseline route');
|
||||
const redirect = read('build/strategy/index.html');
|
||||
assert(redirect.includes('/eldorado-v1/documentation/strategy/target-operating-model/'));
|
||||
assert(redirect.includes('window.location.href') && redirect.includes('http-equiv="refresh"') && !redirect.includes('archify-panel'), 'Landing must redirect, not duplicate Target');
|
||||
for (const {id, title} of model.pages) {
|
||||
const strategyPages = [...model.pages,
|
||||
{id:'stage-01-skills-adoption', title:'Stage - 01 - Skills Adoption'},
|
||||
{id:'baseline', title:'Baseline'},
|
||||
{id:'stage-02-autonomous-agent', title:'Stage - 02 - Autonomous Agent'},
|
||||
];
|
||||
for (const {id, title} of strategyPages) {
|
||||
const route = `strategy/${id === 'index' ? '' : `${id}/`}index.html`;
|
||||
const page = read(join('build',route));
|
||||
assert(page.includes(title) && page.includes('Target operating model'), route);
|
||||
assert(page.includes(title), route);
|
||||
if (!id.startsWith('stage-')) assert(page.includes('Target operating model'), route);
|
||||
assert(indexes.includes(title), `Missing indexed Strategy page: ${id}`);
|
||||
for (const match of page.matchAll(/href="(\/eldorado-v1\/documentation\/[^"?#]*)/g)) {
|
||||
const local = decodeURIComponent(match[1].replace('/eldorado-v1/documentation/',''));
|
||||
|
||||
@@ -1,2 +1,11 @@
|
||||
import type {SidebarsConfig} from '@docusaurus/plugin-content-docs';
|
||||
export default {contributionSidebar: ['contribute', 'diagrams']} satisfies SidebarsConfig;
|
||||
export default {
|
||||
contributionSidebar: ['contribute', 'diagrams', {
|
||||
type: 'category', label: 'Portal maintenance', collapsed: true,
|
||||
items: [
|
||||
{type: 'link', label: 'Starting point', href: '/eldorado-v1/documentation/docs/overview/'},
|
||||
{type: 'link', label: 'Update and publish', href: '/eldorado-v1/documentation/docs/maintain/'},
|
||||
{type: 'link', label: 'Site configuration', href: '/eldorado-v1/documentation/docs/reference/'},
|
||||
],
|
||||
}],
|
||||
} satisfies SidebarsConfig;
|
||||
+44
-1
@@ -1,2 +1,45 @@
|
||||
import type {SidebarsConfig} from '@docusaurus/plugin-content-docs';
|
||||
export default {strategySidebar: ['target-operating-model', 'roadmap', 'skills-governance', 'skills-quality', 'skills-adoption', 'measurement', 'skills-maintenance']} satisfies SidebarsConfig;
|
||||
export default {
|
||||
strategySidebar: [
|
||||
'target-operating-model',
|
||||
'roadmap',
|
||||
{
|
||||
type: 'category',
|
||||
label: 'Stage - 01 - Skills Adoption',
|
||||
link: {type: 'doc', id: 'stage-01-skills-adoption'},
|
||||
collapsed: true,
|
||||
items: [
|
||||
{
|
||||
type: 'category', label: 'Measurement', collapsed: true,
|
||||
link: {type: 'doc', id: 'measurement/index'},
|
||||
items: [
|
||||
'measurement/validated-task-success',
|
||||
'measurement/skill-selection-precision',
|
||||
'measurement/skill-selection-recall',
|
||||
'measurement/supported-bundle-coverage',
|
||||
'measurement/approved-workflow-adoption',
|
||||
'measurement/change-lead-time',
|
||||
'measurement/deployment-frequency',
|
||||
'measurement/change-fail-rate',
|
||||
'measurement/failed-deployment-recovery-time',
|
||||
'measurement/deployment-rework-rate',
|
||||
'measurement/changes-with-escaped-quality-issues',
|
||||
'measurement/confirmed-policy-effects',
|
||||
'measurement/cost-per-accepted-outcome',
|
||||
'measurement/verification-confidence-and-cognitive-load',
|
||||
'measurement/skills-within-substantive-review-window',
|
||||
'measurement/workflow-specific-business-acceptance',
|
||||
'measurement/collection-and-safeguards',
|
||||
'measurement/synthetic-example',
|
||||
],
|
||||
},
|
||||
{type: 'doc', id: 'baseline', label: 'Baseline'},
|
||||
{type: 'doc', id: 'skills-governance', label: 'Governance'},
|
||||
{type: 'doc', id: 'skills-quality', label: 'Quality'},
|
||||
{type: 'doc', id: 'skills-adoption', label: 'Adoption'},
|
||||
{type: 'doc', id: 'skills-maintenance', label: 'Maintenance'},
|
||||
],
|
||||
},
|
||||
'stage-02-autonomous-agent',
|
||||
],
|
||||
} satisfies SidebarsConfig;
|
||||
@@ -11,6 +11,16 @@ export default function ArchifyDiagram({name, title, compact = false, story = fa
|
||||
const opener = useRef<HTMLButtonElement>(null);
|
||||
const headingId = useId();
|
||||
const [expanded, setExpanded] = useState(false);
|
||||
const [narrowRoadmap, setNarrowRoadmap] = useState(false);
|
||||
const skillsStory = /^strategy-(governance|quality|adoption|measurement|baseline|maintenance|stage01|stage02)$/.test(name);
|
||||
useEffect(() => {
|
||||
if (!name.startsWith('strategy-roadmap') && !skillsStory) return;
|
||||
const media = window.matchMedia(skillsStory ? '(max-width: 1100px)' : '(max-width: 999px)');
|
||||
const update = () => setNarrowRoadmap(media.matches);
|
||||
update();
|
||||
media.addEventListener('change', update);
|
||||
return () => media.removeEventListener('change', update);
|
||||
}, [name, skillsStory]);
|
||||
const {colorMode, setColorMode} = useColorMode();
|
||||
const initialTheme = useRef(colorMode);
|
||||
const desktop = useRef<HTMLIFrameElement>(null);
|
||||
@@ -57,7 +67,7 @@ export default function ArchifyDiagram({name, title, compact = false, story = fa
|
||||
return () => {document.body.style.overflow = previousOverflow;};
|
||||
}, [expanded]);
|
||||
const close = () => {dialog.current?.close();};
|
||||
return <section className={`archify-panel${compact ? ' archify-panel--compact' : ''}${story ? ' archify-panel--story' : ''}`} data-diagram={name} aria-label={title}>
|
||||
return <section className={`archify-panel${compact ? ' archify-panel--compact' : ''}${story ? ' archify-panel--story' : ''}${skillsStory ? ' archify-panel--skills' : ''}`} data-diagram={name} aria-label={title}>
|
||||
<div className="archify-toolbar"><button ref={opener} type="button" className="archify-expand" aria-label={`Expand ${title}`} title="Expand diagram" onClick={() => setExpanded(true)}><svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" aria-hidden="true"><path d="M8 3H3v5M16 3h5v5M21 16v5h-5M8 21H3v-5" /></svg></button></div>
|
||||
{story ? <>
|
||||
<iframe className="story-desktop" ref={desktop} onLoad={() => syncTheme(desktop.current)} src={`${source}?embed=1&theme=${initialTheme.current}`} title={title} sandbox="allow-scripts allow-downloads" loading="lazy" referrerPolicy="no-referrer" />
|
||||
@@ -65,7 +75,7 @@ export default function ArchifyDiagram({name, title, compact = false, story = fa
|
||||
</> : <iframe ref={desktop} onLoad={() => syncTheme(desktop.current)} src={`${source}?theme=${initialTheme.current}`} title={title} sandbox="allow-scripts allow-downloads" loading="lazy" referrerPolicy="no-referrer" />}
|
||||
<dialog ref={dialog} className="archify-modal" aria-labelledby={headingId} onClose={() => {setExpanded(false); opener.current?.focus();}}>
|
||||
<div className="archify-modal-toolbar"><strong id={headingId}>{title}</strong><button type="button" onClick={close} autoFocus aria-label="Close full-screen diagram"><span aria-hidden="true">×</span></button></div>
|
||||
{expanded && <iframe ref={fullscreen} onLoad={() => syncTheme(fullscreen.current)} src={`${source}?theme=${initialTheme.current}`} title={`${title} — expanded`} sandbox="allow-scripts allow-downloads" referrerPolicy="no-referrer" />}
|
||||
{expanded && <iframe ref={fullscreen} onLoad={() => syncTheme(fullscreen.current)} src={`${narrowRoadmap ? mobileSource : source}?${name.startsWith('strategy-roadmap') || skillsStory ? 'embed=1&' : ''}theme=${initialTheme.current}`} title={`${title} — expanded`} sandbox="allow-scripts allow-downloads" referrerPolicy="no-referrer" />}
|
||||
</dialog>
|
||||
</section>;
|
||||
}
|
||||
+38
-5
@@ -110,9 +110,13 @@ a:focus-visible, button:focus-visible {outline: 3px solid #b88719; outline-offse
|
||||
.archify-panel--story {max-width: 740px;}
|
||||
.archify-panel--story > iframe {height: auto; aspect-ratio: 480 / 408;}
|
||||
.archify-panel--story > .story-mobile {display: none;}
|
||||
.theme-doc-markdown:has([data-diagram="strategy-roadmap"]) {max-width: none;}
|
||||
.archify-panel--story[data-diagram^="strategy-roadmap"] {max-width: none; --roadmap-height: 640px;}
|
||||
.archify-panel--story[data-diagram^="strategy-roadmap"] > .story-desktop {aspect-ratio: auto; height: 300px;}
|
||||
.archify-panel--story[data-diagram="strategy-roadmap-loop"] {--roadmap-height: 1840px;}
|
||||
.archify-panel--story[data-diagram="strategy-roadmap-loop"] > .story-desktop {height: 460px;}
|
||||
.archify-panel--story[data-diagram="strategy-target"] > iframe {aspect-ratio: 1620 / 1430;}
|
||||
.archify-panel--story[data-diagram="strategy-adoption"] > iframe {aspect-ratio: 545 / 408;}
|
||||
.archify-panel--story[data-diagram="strategy-maintenance"] > iframe {aspect-ratio: 524 / 408;}
|
||||
|
||||
.strategy-content > details {margin: .65rem 0; border: 1px solid var(--line); padding: .8rem 1rem; background: var(--surface);}
|
||||
.strategy-content summary {cursor: pointer; font-weight: 700;}
|
||||
.strategy-content summary:focus-visible {outline: 3px solid #b88719; outline-offset: 4px;}
|
||||
@@ -121,11 +125,15 @@ a:focus-visible, button:focus-visible {outline: 3px solid #b88719; outline-offse
|
||||
@media (max-width: 700px) {
|
||||
.archify-panel--story > .story-desktop {display: none;}
|
||||
.archify-panel--story > .story-mobile {display: block; height: auto; aspect-ratio: 240 / 748;}
|
||||
.archify-panel--story[data-diagram="strategy-roadmap"] > .story-mobile {aspect-ratio: 240 / 628;}
|
||||
.archify-panel--story[data-diagram="strategy-adoption"] > .story-mobile {aspect-ratio: 305 / 748;}
|
||||
.archify-panel--story[data-diagram="strategy-maintenance"] > .story-mobile {aspect-ratio: 284 / 748;}
|
||||
|
||||
|
||||
.archify-panel--story[data-diagram="strategy-target"] > .story-mobile {aspect-ratio: 680 / 2340;}
|
||||
}
|
||||
/* Keep the three-card loop readable beside the documentation sidebar. */
|
||||
@media (width < 1100px) {
|
||||
.archify-panel--story[data-diagram^="strategy-roadmap"] > .story-desktop {display: none;}
|
||||
.archify-panel--story[data-diagram^="strategy-roadmap"] > .story-mobile {display: block; height: var(--roadmap-height); width: 100%; max-width: 432px; margin-inline: auto; aspect-ratio: auto;}
|
||||
}
|
||||
.archify-expand {display: grid; place-items: center; width: 44px; height: 44px; border: 0; padding: 0; background: transparent; color: var(--ifm-link-color); cursor: pointer;}
|
||||
.archify-expand:hover {background: var(--ifm-hover-overlay);}
|
||||
.archify-modal {position: fixed; inset: 0; margin: 0; padding: 0; width: 100vw; height: 100dvh; max-width: none; max-height: none; border: 0; background: var(--surface); color: var(--ifm-color-content);}
|
||||
@@ -134,4 +142,29 @@ a:focus-visible, button:focus-visible {outline: 3px solid #b88719; outline-offse
|
||||
.archify-modal-toolbar {display: flex; align-items: center; justify-content: space-between; gap: 16px; padding: 12px 20px; border-bottom: 1px solid var(--line);}
|
||||
.archify-modal-toolbar button {display: inline-flex; align-items: center; justify-content: center; flex-shrink: 0; width: 44px; height: 44px; padding: 0; background: var(--gold); color: #14131a; font: inherit; font-size: 24px; font-weight: 700; border: 0; cursor: pointer;}
|
||||
.archify-panel .archify-modal iframe {flex: 1; min-height: 0; height: 100%; width: 100%;}
|
||||
/* Read narrow Roadmap views by scrolling, never by fitting their
|
||||
entire height into a short phone screen. Other diagram viewers are unchanged. */
|
||||
@media (max-width: 999px) {
|
||||
[data-diagram^="strategy-roadmap"] .archify-modal {overflow-y: auto; overscroll-behavior: contain;}
|
||||
[data-diagram^="strategy-roadmap"] .archify-modal-toolbar {position: sticky; top: 0; z-index: 1; flex-shrink: 0; background: var(--surface);}
|
||||
[data-diagram^="strategy-roadmap"] .archify-modal iframe {flex: none; height: var(--roadmap-height); min-height: var(--roadmap-height);}
|
||||
}
|
||||
@media (prefers-reduced-motion: reduce) {.start-card {transition: none;} .start-card:hover {transform: none;}}
|
||||
|
||||
/* Skills Adoption alone uses the full reading column, not a narrow preview. */
|
||||
.theme-doc-markdown:has(.archify-panel--skills) {max-width: none;}
|
||||
.archify-panel--story.archify-panel--skills {max-width: none;}
|
||||
.archify-panel--skills {--skills-wide: 2000 / 1200; --skills-narrow: 880 / 2900;}
|
||||
.archify-panel--skills[data-diagram="strategy-governance"] {--skills-wide: 1760 / 1550;}
|
||||
.archify-panel--skills[data-diagram="strategy-adoption"] {--skills-wide: 2040 / 1300; --skills-narrow: 880 / 2200;}
|
||||
.archify-panel--skills[data-diagram="strategy-measurement"] {--skills-wide: 2400 / 1280; --skills-narrow: 880 / 2600;}
|
||||
.archify-panel--skills[data-diagram="strategy-baseline"] {--skills-wide: 2400 / 1280; --skills-narrow: 880 / 2200;}
|
||||
.archify-panel--skills[data-diagram="strategy-maintenance"] {--skills-wide: 2630 / 1480; --skills-narrow: 880 / 3250;}
|
||||
.archify-panel--story.archify-panel--skills > .story-desktop {aspect-ratio: var(--skills-wide); height: auto;}
|
||||
@media (max-width: 1100px) {
|
||||
.archify-panel--story.archify-panel--skills > .story-desktop {display: none;}
|
||||
.archify-panel--story.archify-panel--skills > .story-mobile {display: block; aspect-ratio: var(--skills-narrow); height: auto; max-width: 440px; margin-inline: auto;}
|
||||
.archify-panel--skills .archify-modal {overflow-y: auto; overscroll-behavior: contain;}
|
||||
.archify-panel--skills .archify-modal-toolbar {position: sticky; top: 0; z-index: 1; flex-shrink: 0; background: var(--surface);}
|
||||
.archify-panel--skills .archify-modal iframe {flex: none; height: auto; min-height: 0; aspect-ratio: var(--skills-narrow); max-width: 600px; margin-inline: auto;}
|
||||
}
|
||||
Loaded 100 of 101 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user