feat: wider, richer Skills Adoption diagrams #31
No files matched your search
@@ -2,7 +2,7 @@
|
||||
"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": {
|
||||
@@ -11,129 +11,136 @@
|
||||
},
|
||||
"components": [
|
||||
{
|
||||
"id": "choose",
|
||||
"id": "delivery",
|
||||
"type": "backend",
|
||||
"label": "Choose workflow",
|
||||
"sublabel": "Department outcome",
|
||||
"label": "Delivery first",
|
||||
"tag": "Understand real work",
|
||||
"sublabel": "Codebase + principles\nSystem logic and tests\nBuilds and packaging\nDeployments + baseline",
|
||||
"pos": [
|
||||
20,
|
||||
20
|
||||
40,
|
||||
40
|
||||
],
|
||||
"size": [
|
||||
180,
|
||||
60
|
||||
560,
|
||||
440
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "workflow",
|
||||
"type": "security",
|
||||
"label": "Choose bounded work",
|
||||
"tag": "Team + Product owner",
|
||||
"sublabel": "Define accepted outcome\nData & AI shapes the skill\nQuality sets acceptance\nSecurity clears data",
|
||||
"pos": [
|
||||
40,
|
||||
610
|
||||
],
|
||||
"size": [
|
||||
560,
|
||||
440
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "coach",
|
||||
"type": "backend",
|
||||
"label": "Coach people",
|
||||
"sublabel": "Verify + recover",
|
||||
"type": "frontend",
|
||||
"label": "Practice together",
|
||||
"tag": "Human + AI Agent",
|
||||
"sublabel": "Platform qualifies client\nPeople supports learning\nSelect skill; inspect work\nKeep a manual path",
|
||||
"pos": [
|
||||
20,
|
||||
140
|
||||
40,
|
||||
1180
|
||||
],
|
||||
"size": [
|
||||
180,
|
||||
60
|
||||
560,
|
||||
440
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "canary",
|
||||
"type": "backend",
|
||||
"label": "Run bounded canary",
|
||||
"sublabel": "Qualified skill + client",
|
||||
"id": "verify",
|
||||
"type": "security",
|
||||
"label": "Accept actual work",
|
||||
"tag": "Independent reviewer",
|
||||
"sublabel": "Check artifacts, not calls\nRecognize unsafe inputs\nUse incident routes\nExplain limits + recovery",
|
||||
"pos": [
|
||||
20,
|
||||
260
|
||||
40,
|
||||
1750
|
||||
],
|
||||
"size": [
|
||||
180,
|
||||
60
|
||||
560,
|
||||
440
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "accept",
|
||||
"type": "backend",
|
||||
"label": "Accept real work",
|
||||
"sublabel": "Independent review",
|
||||
"id": "learn",
|
||||
"type": "database",
|
||||
"label": "Review the feedback",
|
||||
"tag": "Owning team",
|
||||
"sublabel": "Collect metrics + friction\nNon-use is useful feedback\nRevise through review\nNo quotas or rankings",
|
||||
"pos": [
|
||||
20,
|
||||
380
|
||||
40,
|
||||
2320
|
||||
],
|
||||
"size": [
|
||||
180,
|
||||
60
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "feedback",
|
||||
"type": "backend",
|
||||
"label": "Review feedback",
|
||||
"sublabel": "Usefulness + non-use",
|
||||
"pos": [
|
||||
20,
|
||||
500
|
||||
],
|
||||
"size": [
|
||||
180,
|
||||
60
|
||||
560,
|
||||
440
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "expand",
|
||||
"type": "backend",
|
||||
"label": "Expand or revise",
|
||||
"sublabel": "Keep a manual path",
|
||||
"type": "cloud",
|
||||
"label": "Expand with evidence",
|
||||
"tag": "Other SDLC phases",
|
||||
"sublabel": "Later order undecided\nRepeat baseline + topology\nDelivery keeps improving\nNot autonomous authority",
|
||||
"pos": [
|
||||
20,
|
||||
620
|
||||
40,
|
||||
2890
|
||||
],
|
||||
"size": [
|
||||
180,
|
||||
60
|
||||
560,
|
||||
440
|
||||
]
|
||||
}
|
||||
],
|
||||
"connections": [
|
||||
{
|
||||
"id": "flow-0",
|
||||
"from": "choose",
|
||||
"to": "coach",
|
||||
"label": "Prepare"
|
||||
"from": "delivery",
|
||||
"to": "workflow",
|
||||
"fromSide": "bottom",
|
||||
"toSide": "top",
|
||||
"route": "straight"
|
||||
},
|
||||
{
|
||||
"id": "flow-1",
|
||||
"from": "coach",
|
||||
"to": "canary",
|
||||
"label": "support pilot"
|
||||
"from": "workflow",
|
||||
"to": "coach",
|
||||
"fromSide": "bottom",
|
||||
"toSide": "top",
|
||||
"route": "straight"
|
||||
},
|
||||
{
|
||||
"id": "flow-2",
|
||||
"from": "canary",
|
||||
"to": "accept",
|
||||
"label": "Verify"
|
||||
"from": "coach",
|
||||
"to": "verify",
|
||||
"fromSide": "bottom",
|
||||
"toSide": "top",
|
||||
"route": "straight"
|
||||
},
|
||||
{
|
||||
"id": "flow-3",
|
||||
"from": "accept",
|
||||
"to": "feedback",
|
||||
"label": "learn"
|
||||
"from": "verify",
|
||||
"to": "learn",
|
||||
"fromSide": "bottom",
|
||||
"toSide": "top",
|
||||
"route": "straight"
|
||||
},
|
||||
{
|
||||
"id": "flow-4",
|
||||
"from": "feedback",
|
||||
"from": "learn",
|
||||
"to": "expand",
|
||||
"label": "decide"
|
||||
},
|
||||
{
|
||||
"id": "feedback-loop",
|
||||
"from": "expand",
|
||||
"to": "coach",
|
||||
"label": "Review revision",
|
||||
"variant": "dashed",
|
||||
"fromSide": "right",
|
||||
"toSide": "right"
|
||||
"fromSide": "bottom",
|
||||
"toSide": "top",
|
||||
"route": "straight"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
"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": {
|
||||
@@ -11,129 +11,136 @@
|
||||
},
|
||||
"components": [
|
||||
{
|
||||
"id": "choose",
|
||||
"id": "delivery",
|
||||
"type": "backend",
|
||||
"label": "Choose workflow",
|
||||
"sublabel": "Department outcome",
|
||||
"label": "Delivery first",
|
||||
"tag": "Understand real work",
|
||||
"sublabel": "Codebase + principles\nSystem logic and tests\nBuilds and packaging\nDeployments + baseline",
|
||||
"pos": [
|
||||
20,
|
||||
20
|
||||
40,
|
||||
40
|
||||
],
|
||||
"size": [
|
||||
180,
|
||||
60
|
||||
560,
|
||||
440
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "workflow",
|
||||
"type": "security",
|
||||
"label": "Choose bounded work",
|
||||
"tag": "Team + Product owner",
|
||||
"sublabel": "Define accepted outcome\nData & AI shapes the skill\nQuality sets acceptance\nSecurity clears data",
|
||||
"pos": [
|
||||
700,
|
||||
40
|
||||
],
|
||||
"size": [
|
||||
560,
|
||||
440
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "coach",
|
||||
"type": "backend",
|
||||
"label": "Coach people",
|
||||
"sublabel": "Verify + recover",
|
||||
"type": "frontend",
|
||||
"label": "Practice together",
|
||||
"tag": "Human + AI Agent",
|
||||
"sublabel": "Platform qualifies client\nPeople supports learning\nSelect skill; inspect work\nKeep a manual path",
|
||||
"pos": [
|
||||
260,
|
||||
20
|
||||
1360,
|
||||
40
|
||||
],
|
||||
"size": [
|
||||
180,
|
||||
60
|
||||
560,
|
||||
440
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "canary",
|
||||
"type": "backend",
|
||||
"label": "Run bounded canary",
|
||||
"sublabel": "Qualified skill + client",
|
||||
"id": "verify",
|
||||
"type": "security",
|
||||
"label": "Accept actual work",
|
||||
"tag": "Independent reviewer",
|
||||
"sublabel": "Check artifacts, not calls\nRecognize unsafe inputs\nUse incident routes\nExplain limits + recovery",
|
||||
"pos": [
|
||||
260,
|
||||
150
|
||||
1360,
|
||||
610
|
||||
],
|
||||
"size": [
|
||||
180,
|
||||
60
|
||||
560,
|
||||
440
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "accept",
|
||||
"type": "backend",
|
||||
"label": "Accept real work",
|
||||
"sublabel": "Independent review",
|
||||
"id": "learn",
|
||||
"type": "database",
|
||||
"label": "Review the feedback",
|
||||
"tag": "Owning team",
|
||||
"sublabel": "Collect metrics + friction\nNon-use is useful feedback\nRevise through review\nNo quotas or rankings",
|
||||
"pos": [
|
||||
20,
|
||||
150
|
||||
700,
|
||||
610
|
||||
],
|
||||
"size": [
|
||||
180,
|
||||
60
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "feedback",
|
||||
"type": "backend",
|
||||
"label": "Review feedback",
|
||||
"sublabel": "Usefulness + non-use",
|
||||
"pos": [
|
||||
20,
|
||||
280
|
||||
],
|
||||
"size": [
|
||||
180,
|
||||
60
|
||||
560,
|
||||
440
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "expand",
|
||||
"type": "backend",
|
||||
"label": "Expand or revise",
|
||||
"sublabel": "Keep a manual path",
|
||||
"type": "cloud",
|
||||
"label": "Expand with evidence",
|
||||
"tag": "Other SDLC phases",
|
||||
"sublabel": "Later order undecided\nRepeat baseline + topology\nDelivery keeps improving\nNot autonomous authority",
|
||||
"pos": [
|
||||
260,
|
||||
280
|
||||
40,
|
||||
610
|
||||
],
|
||||
"size": [
|
||||
180,
|
||||
60
|
||||
560,
|
||||
440
|
||||
]
|
||||
}
|
||||
],
|
||||
"connections": [
|
||||
{
|
||||
"id": "flow-0",
|
||||
"from": "choose",
|
||||
"to": "coach",
|
||||
"label": "Prepare"
|
||||
"from": "delivery",
|
||||
"to": "workflow",
|
||||
"fromSide": "right",
|
||||
"toSide": "left",
|
||||
"route": "straight"
|
||||
},
|
||||
{
|
||||
"id": "flow-1",
|
||||
"from": "coach",
|
||||
"to": "canary",
|
||||
"label": "support pilot"
|
||||
"from": "workflow",
|
||||
"to": "coach",
|
||||
"fromSide": "right",
|
||||
"toSide": "left",
|
||||
"route": "straight"
|
||||
},
|
||||
{
|
||||
"id": "flow-2",
|
||||
"from": "canary",
|
||||
"to": "accept",
|
||||
"label": "Verify"
|
||||
"from": "coach",
|
||||
"to": "verify",
|
||||
"fromSide": "bottom",
|
||||
"toSide": "top",
|
||||
"route": "straight"
|
||||
},
|
||||
{
|
||||
"id": "flow-3",
|
||||
"from": "accept",
|
||||
"to": "feedback",
|
||||
"label": "learn"
|
||||
"from": "verify",
|
||||
"to": "learn",
|
||||
"fromSide": "left",
|
||||
"toSide": "right",
|
||||
"route": "straight"
|
||||
},
|
||||
{
|
||||
"id": "flow-4",
|
||||
"from": "feedback",
|
||||
"from": "learn",
|
||||
"to": "expand",
|
||||
"label": "decide"
|
||||
},
|
||||
{
|
||||
"id": "feedback-loop",
|
||||
"from": "expand",
|
||||
"to": "coach",
|
||||
"label": "Review revision",
|
||||
"variant": "dashed",
|
||||
"fromSide": "right",
|
||||
"toSide": "right"
|
||||
"fromSide": "left",
|
||||
"toSide": "right",
|
||||
"route": "straight"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
"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": {
|
||||
@@ -12,86 +12,92 @@
|
||||
"components": [
|
||||
{
|
||||
"id": "owner",
|
||||
"type": "security",
|
||||
"label": "Owner proposes",
|
||||
"sublabel": "Existing accountable team",
|
||||
"type": "backend",
|
||||
"label": "Propose a skill",
|
||||
"tag": "Owning team",
|
||||
"sublabel": "Problem + intended users\nData and authority scope\nSKILL.md + dependencies\nTestable outcome",
|
||||
"pos": [
|
||||
20,
|
||||
20
|
||||
40,
|
||||
40
|
||||
],
|
||||
"size": [
|
||||
180,
|
||||
60
|
||||
560,
|
||||
440
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "review",
|
||||
"type": "security",
|
||||
"label": "Independent review",
|
||||
"sublabel": "Quality + risk evidence",
|
||||
"tag": "Quality + Security",
|
||||
"sublabel": "Evaluate useful outcomes\nCheck risk boundaries\nAuthor is not sole approver\nRecord revision evidence",
|
||||
"pos": [
|
||||
20,
|
||||
140
|
||||
40,
|
||||
610
|
||||
],
|
||||
"size": [
|
||||
180,
|
||||
60
|
||||
560,
|
||||
440
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "canary",
|
||||
"type": "security",
|
||||
"label": "Bounded canary",
|
||||
"sublabel": "Qualified client path",
|
||||
"type": "frontend",
|
||||
"label": "Qualify real use",
|
||||
"tag": "Human + AI Agent",
|
||||
"sublabel": "Test exact client build\nRun a bounded canary\nInspect work independently\nNo failed mandatory gate",
|
||||
"pos": [
|
||||
20,
|
||||
260
|
||||
40,
|
||||
1180
|
||||
],
|
||||
"size": [
|
||||
180,
|
||||
60
|
||||
560,
|
||||
440
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "approve",
|
||||
"type": "security",
|
||||
"label": "Approve revision",
|
||||
"sublabel": "Exact digest + scope",
|
||||
"label": "Approve exact scope",
|
||||
"tag": "Accountable approvers",
|
||||
"sublabel": "Bind approval to digest\nPermitted uses + expiry\nExceptions cannot bypass\nprotected controls",
|
||||
"pos": [
|
||||
20,
|
||||
380
|
||||
40,
|
||||
1750
|
||||
],
|
||||
"size": [
|
||||
180,
|
||||
60
|
||||
560,
|
||||
440
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "publish",
|
||||
"type": "security",
|
||||
"label": "Publish bundle",
|
||||
"sublabel": "Data & AI catalog",
|
||||
"type": "database",
|
||||
"label": "Version the bundle",
|
||||
"tag": "Data & AI catalog",
|
||||
"sublabel": "Pin skill + adapter\nand dependency revisions\nRecord approval evidence\nKeep last-known-good",
|
||||
"pos": [
|
||||
20,
|
||||
500
|
||||
40,
|
||||
2320
|
||||
],
|
||||
"size": [
|
||||
180,
|
||||
60
|
||||
560,
|
||||
440
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "distribute",
|
||||
"type": "security",
|
||||
"label": "Verify effective state",
|
||||
"sublabel": "Platform & IT",
|
||||
"type": "cloud",
|
||||
"label": "Verify loaded state",
|
||||
"tag": "Platform & IT",
|
||||
"sublabel": "Stage and check digest\nRead effective revision\nTest open-session reload\nRevoke unsafe revisions",
|
||||
"pos": [
|
||||
20,
|
||||
620
|
||||
40,
|
||||
2890
|
||||
],
|
||||
"size": [
|
||||
180,
|
||||
60
|
||||
560,
|
||||
440
|
||||
]
|
||||
}
|
||||
],
|
||||
@@ -100,31 +106,41 @@
|
||||
"id": "flow-0",
|
||||
"from": "owner",
|
||||
"to": "review",
|
||||
"label": "submit"
|
||||
"fromSide": "bottom",
|
||||
"toSide": "top",
|
||||
"route": "straight"
|
||||
},
|
||||
{
|
||||
"id": "flow-1",
|
||||
"from": "review",
|
||||
"to": "canary",
|
||||
"label": "qualify"
|
||||
"fromSide": "bottom",
|
||||
"toSide": "top",
|
||||
"route": "straight"
|
||||
},
|
||||
{
|
||||
"id": "flow-2",
|
||||
"from": "canary",
|
||||
"to": "approve",
|
||||
"label": "Accept"
|
||||
"fromSide": "bottom",
|
||||
"toSide": "top",
|
||||
"route": "straight"
|
||||
},
|
||||
{
|
||||
"id": "flow-3",
|
||||
"from": "approve",
|
||||
"to": "publish",
|
||||
"label": "record approval"
|
||||
"fromSide": "bottom",
|
||||
"toSide": "top",
|
||||
"route": "straight"
|
||||
},
|
||||
{
|
||||
"id": "flow-4",
|
||||
"from": "publish",
|
||||
"to": "distribute",
|
||||
"label": "Deliver"
|
||||
"fromSide": "bottom",
|
||||
"toSide": "top",
|
||||
"route": "straight"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
"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": {
|
||||
@@ -12,86 +12,92 @@
|
||||
"components": [
|
||||
{
|
||||
"id": "owner",
|
||||
"type": "security",
|
||||
"label": "Owner proposes",
|
||||
"sublabel": "Existing accountable team",
|
||||
"type": "backend",
|
||||
"label": "Propose a skill",
|
||||
"tag": "Owning team",
|
||||
"sublabel": "Problem + intended users\nData and authority scope\nSKILL.md + dependencies\nTestable outcome",
|
||||
"pos": [
|
||||
20,
|
||||
20
|
||||
40,
|
||||
40
|
||||
],
|
||||
"size": [
|
||||
180,
|
||||
60
|
||||
560,
|
||||
440
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "review",
|
||||
"type": "security",
|
||||
"label": "Independent review",
|
||||
"sublabel": "Quality + risk evidence",
|
||||
"tag": "Quality + Security",
|
||||
"sublabel": "Evaluate useful outcomes\nCheck risk boundaries\nAuthor is not sole approver\nRecord revision evidence",
|
||||
"pos": [
|
||||
260,
|
||||
20
|
||||
700,
|
||||
40
|
||||
],
|
||||
"size": [
|
||||
180,
|
||||
60
|
||||
560,
|
||||
440
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "canary",
|
||||
"type": "security",
|
||||
"label": "Bounded canary",
|
||||
"sublabel": "Qualified client path",
|
||||
"type": "frontend",
|
||||
"label": "Qualify real use",
|
||||
"tag": "Human + AI Agent",
|
||||
"sublabel": "Test exact client build\nRun a bounded canary\nInspect work independently\nNo failed mandatory gate",
|
||||
"pos": [
|
||||
260,
|
||||
150
|
||||
1360,
|
||||
40
|
||||
],
|
||||
"size": [
|
||||
180,
|
||||
60
|
||||
560,
|
||||
440
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "approve",
|
||||
"type": "security",
|
||||
"label": "Approve revision",
|
||||
"sublabel": "Exact digest + scope",
|
||||
"label": "Approve exact scope",
|
||||
"tag": "Accountable approvers",
|
||||
"sublabel": "Bind approval to digest\nPermitted uses + expiry\nExceptions cannot bypass\nprotected controls",
|
||||
"pos": [
|
||||
20,
|
||||
150
|
||||
1360,
|
||||
610
|
||||
],
|
||||
"size": [
|
||||
180,
|
||||
60
|
||||
560,
|
||||
440
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "publish",
|
||||
"type": "security",
|
||||
"label": "Publish bundle",
|
||||
"sublabel": "Data & AI catalog",
|
||||
"type": "database",
|
||||
"label": "Version the bundle",
|
||||
"tag": "Data & AI catalog",
|
||||
"sublabel": "Pin skill + adapter\nand dependency revisions\nRecord approval evidence\nKeep last-known-good",
|
||||
"pos": [
|
||||
20,
|
||||
280
|
||||
700,
|
||||
610
|
||||
],
|
||||
"size": [
|
||||
180,
|
||||
60
|
||||
560,
|
||||
440
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "distribute",
|
||||
"type": "security",
|
||||
"label": "Verify effective state",
|
||||
"sublabel": "Platform & IT",
|
||||
"type": "cloud",
|
||||
"label": "Verify loaded state",
|
||||
"tag": "Platform & IT",
|
||||
"sublabel": "Stage and check digest\nRead effective revision\nTest open-session reload\nRevoke unsafe revisions",
|
||||
"pos": [
|
||||
260,
|
||||
280
|
||||
40,
|
||||
610
|
||||
],
|
||||
"size": [
|
||||
180,
|
||||
60
|
||||
560,
|
||||
440
|
||||
]
|
||||
}
|
||||
],
|
||||
@@ -100,31 +106,41 @@
|
||||
"id": "flow-0",
|
||||
"from": "owner",
|
||||
"to": "review",
|
||||
"label": "submit"
|
||||
"fromSide": "right",
|
||||
"toSide": "left",
|
||||
"route": "straight"
|
||||
},
|
||||
{
|
||||
"id": "flow-1",
|
||||
"from": "review",
|
||||
"to": "canary",
|
||||
"label": "qualify"
|
||||
"fromSide": "right",
|
||||
"toSide": "left",
|
||||
"route": "straight"
|
||||
},
|
||||
{
|
||||
"id": "flow-2",
|
||||
"from": "canary",
|
||||
"to": "approve",
|
||||
"label": "Accept"
|
||||
"fromSide": "bottom",
|
||||
"toSide": "top",
|
||||
"route": "straight"
|
||||
},
|
||||
{
|
||||
"id": "flow-3",
|
||||
"from": "approve",
|
||||
"to": "publish",
|
||||
"label": "record approval"
|
||||
"fromSide": "left",
|
||||
"toSide": "right",
|
||||
"route": "straight"
|
||||
},
|
||||
{
|
||||
"id": "flow-4",
|
||||
"from": "publish",
|
||||
"to": "distribute",
|
||||
"label": "Deliver"
|
||||
"fromSide": "left",
|
||||
"toSide": "right",
|
||||
"route": "straight"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
"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": {
|
||||
@@ -12,86 +12,92 @@
|
||||
"components": [
|
||||
{
|
||||
"id": "monitor",
|
||||
"type": "backend",
|
||||
"label": "Monitor skills",
|
||||
"sublabel": "Usefulness + safety",
|
||||
"type": "database",
|
||||
"label": "Watch for change",
|
||||
"tag": "Data & AI + owners",
|
||||
"sublabel": "Review usefulness + safety\nDue dates and feedback\nModel / client / tool drift\nFailures trigger early review",
|
||||
"pos": [
|
||||
20,
|
||||
20
|
||||
40,
|
||||
40
|
||||
],
|
||||
"size": [
|
||||
180,
|
||||
60
|
||||
560,
|
||||
440
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "triage",
|
||||
"type": "backend",
|
||||
"label": "Triage changes",
|
||||
"sublabel": "Owner + risk review",
|
||||
"label": "Triage the evidence",
|
||||
"tag": "Owner + Quality",
|
||||
"sublabel": "Reproduce the failure\nKeep artifact / client IDs\nAdd sanitized regressions\nAssess business effects",
|
||||
"pos": [
|
||||
20,
|
||||
140
|
||||
40,
|
||||
610
|
||||
],
|
||||
"size": [
|
||||
180,
|
||||
60
|
||||
560,
|
||||
440
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "contain",
|
||||
"type": "security",
|
||||
"label": "If unsafe: contain",
|
||||
"tag": "Security + Platform",
|
||||
"sublabel": "Revoke authority\nQuarantine revision\nRestore known-good bundle\nVerify effective state",
|
||||
"pos": [
|
||||
40,
|
||||
1180
|
||||
],
|
||||
"size": [
|
||||
560,
|
||||
440
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "correct",
|
||||
"type": "backend",
|
||||
"label": "Correct and test",
|
||||
"sublabel": "Independent regression",
|
||||
"label": "Create a new revision",
|
||||
"tag": "Owning team",
|
||||
"sublabel": "Correct skill + dependencies\nIndependent tests / review\nRequalify client + model\nNo automatic reinstatement",
|
||||
"pos": [
|
||||
20,
|
||||
260
|
||||
40,
|
||||
1750
|
||||
],
|
||||
"size": [
|
||||
180,
|
||||
60
|
||||
560,
|
||||
440
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "decision",
|
||||
"type": "backend",
|
||||
"label": "Approve or hold",
|
||||
"sublabel": "Exact revised bundle",
|
||||
"id": "approve",
|
||||
"type": "security",
|
||||
"label": "Authorize restart",
|
||||
"tag": "Accountable human",
|
||||
"sublabel": "Require regression evidence\nVerify rollback / revocation\nApprove exact new revision\nCanary before wider use",
|
||||
"pos": [
|
||||
20,
|
||||
380
|
||||
40,
|
||||
2320
|
||||
],
|
||||
"size": [
|
||||
180,
|
||||
60
|
||||
560,
|
||||
440
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "promote",
|
||||
"type": "backend",
|
||||
"label": "Promote safely",
|
||||
"sublabel": "Verify state + monitor",
|
||||
"id": "retire",
|
||||
"type": "cloud",
|
||||
"label": "Retire when obsolete",
|
||||
"tag": "Data & AI + Platform",
|
||||
"sublabel": "Deprecate with migration\nRetire: no new invocation\nTrack revoked versions\nHistory stays in metrics",
|
||||
"pos": [
|
||||
20,
|
||||
500
|
||||
40,
|
||||
2890
|
||||
],
|
||||
"size": [
|
||||
180,
|
||||
60
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "observe",
|
||||
"type": "backend",
|
||||
"label": "Quarantine / rollback",
|
||||
"sublabel": "Revoke unsafe revision",
|
||||
"pos": [
|
||||
20,
|
||||
620
|
||||
],
|
||||
"size": [
|
||||
180,
|
||||
60
|
||||
560,
|
||||
440
|
||||
]
|
||||
}
|
||||
],
|
||||
@@ -100,42 +106,41 @@
|
||||
"id": "flow-0",
|
||||
"from": "monitor",
|
||||
"to": "triage",
|
||||
"label": "Detect"
|
||||
"fromSide": "bottom",
|
||||
"toSide": "top",
|
||||
"route": "straight"
|
||||
},
|
||||
{
|
||||
"id": "flow-1",
|
||||
"from": "triage",
|
||||
"to": "correct",
|
||||
"label": "scope correction"
|
||||
"to": "contain",
|
||||
"fromSide": "bottom",
|
||||
"toSide": "top",
|
||||
"route": "straight"
|
||||
},
|
||||
{
|
||||
"id": "flow-2",
|
||||
"from": "correct",
|
||||
"to": "decision",
|
||||
"label": "Prove"
|
||||
"from": "contain",
|
||||
"to": "correct",
|
||||
"fromSide": "bottom",
|
||||
"toSide": "top",
|
||||
"route": "straight"
|
||||
},
|
||||
{
|
||||
"id": "flow-3",
|
||||
"from": "decision",
|
||||
"to": "promote",
|
||||
"label": "authorize"
|
||||
},
|
||||
|
||||
{
|
||||
"id": "unsafe",
|
||||
"from": "triage",
|
||||
"to": "observe",
|
||||
"label": "Unsafe",
|
||||
"variant": "security",
|
||||
"fromSide": "right",
|
||||
"toSide": "right"
|
||||
"from": "correct",
|
||||
"to": "approve",
|
||||
"fromSide": "bottom",
|
||||
"toSide": "top",
|
||||
"route": "straight"
|
||||
},
|
||||
{
|
||||
"id": "review-loop",
|
||||
"from": "observe",
|
||||
"to": "correct",
|
||||
"label": "Requalify",
|
||||
"variant": "dashed"
|
||||
"id": "flow-4",
|
||||
"from": "approve",
|
||||
"to": "retire",
|
||||
"fromSide": "bottom",
|
||||
"toSide": "top",
|
||||
"route": "straight"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
"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": {
|
||||
@@ -12,86 +12,92 @@
|
||||
"components": [
|
||||
{
|
||||
"id": "monitor",
|
||||
"type": "backend",
|
||||
"label": "Monitor skills",
|
||||
"sublabel": "Usefulness + safety",
|
||||
"type": "database",
|
||||
"label": "Watch for change",
|
||||
"tag": "Data & AI + owners",
|
||||
"sublabel": "Review usefulness + safety\nDue dates and feedback\nModel / client / tool drift\nFailures trigger early review",
|
||||
"pos": [
|
||||
20,
|
||||
20
|
||||
40,
|
||||
40
|
||||
],
|
||||
"size": [
|
||||
180,
|
||||
60
|
||||
560,
|
||||
440
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "triage",
|
||||
"type": "backend",
|
||||
"label": "Triage changes",
|
||||
"sublabel": "Owner + risk review",
|
||||
"label": "Triage the evidence",
|
||||
"tag": "Owner + Quality",
|
||||
"sublabel": "Reproduce the failure\nKeep artifact / client IDs\nAdd sanitized regressions\nAssess business effects",
|
||||
"pos": [
|
||||
260,
|
||||
20
|
||||
700,
|
||||
40
|
||||
],
|
||||
"size": [
|
||||
180,
|
||||
60
|
||||
560,
|
||||
440
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "contain",
|
||||
"type": "security",
|
||||
"label": "If unsafe: contain",
|
||||
"tag": "Security + Platform",
|
||||
"sublabel": "Revoke authority\nQuarantine revision\nRestore known-good bundle\nVerify effective state",
|
||||
"pos": [
|
||||
1360,
|
||||
40
|
||||
],
|
||||
"size": [
|
||||
560,
|
||||
440
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "correct",
|
||||
"type": "backend",
|
||||
"label": "Correct and test",
|
||||
"sublabel": "Independent regression",
|
||||
"label": "Create a new revision",
|
||||
"tag": "Owning team",
|
||||
"sublabel": "Correct skill + dependencies\nIndependent tests / review\nRequalify client + model\nNo automatic reinstatement",
|
||||
"pos": [
|
||||
260,
|
||||
150
|
||||
1360,
|
||||
610
|
||||
],
|
||||
"size": [
|
||||
180,
|
||||
60
|
||||
560,
|
||||
440
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "decision",
|
||||
"type": "backend",
|
||||
"label": "Approve or hold",
|
||||
"sublabel": "Exact revised bundle",
|
||||
"id": "approve",
|
||||
"type": "security",
|
||||
"label": "Authorize restart",
|
||||
"tag": "Accountable human",
|
||||
"sublabel": "Require regression evidence\nVerify rollback / revocation\nApprove exact new revision\nCanary before wider use",
|
||||
"pos": [
|
||||
20,
|
||||
150
|
||||
700,
|
||||
610
|
||||
],
|
||||
"size": [
|
||||
180,
|
||||
60
|
||||
560,
|
||||
440
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "promote",
|
||||
"type": "backend",
|
||||
"label": "Promote safely",
|
||||
"sublabel": "Verify state + monitor",
|
||||
"id": "retire",
|
||||
"type": "cloud",
|
||||
"label": "Retire when obsolete",
|
||||
"tag": "Data & AI + Platform",
|
||||
"sublabel": "Deprecate with migration\nRetire: no new invocation\nTrack revoked versions\nHistory stays in metrics",
|
||||
"pos": [
|
||||
20,
|
||||
280
|
||||
40,
|
||||
610
|
||||
],
|
||||
"size": [
|
||||
180,
|
||||
60
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "observe",
|
||||
"type": "backend",
|
||||
"label": "Quarantine / rollback",
|
||||
"sublabel": "Revoke unsafe revision",
|
||||
"pos": [
|
||||
260,
|
||||
280
|
||||
],
|
||||
"size": [
|
||||
180,
|
||||
60
|
||||
560,
|
||||
440
|
||||
]
|
||||
}
|
||||
],
|
||||
@@ -100,42 +106,41 @@
|
||||
"id": "flow-0",
|
||||
"from": "monitor",
|
||||
"to": "triage",
|
||||
"label": "Detect"
|
||||
"fromSide": "right",
|
||||
"toSide": "left",
|
||||
"route": "straight"
|
||||
},
|
||||
{
|
||||
"id": "flow-1",
|
||||
"from": "triage",
|
||||
"to": "correct",
|
||||
"label": "scope correction"
|
||||
"to": "contain",
|
||||
"fromSide": "right",
|
||||
"toSide": "left",
|
||||
"route": "straight"
|
||||
},
|
||||
{
|
||||
"id": "flow-2",
|
||||
"from": "correct",
|
||||
"to": "decision",
|
||||
"label": "Prove"
|
||||
"from": "contain",
|
||||
"to": "correct",
|
||||
"fromSide": "bottom",
|
||||
"toSide": "top",
|
||||
"route": "straight"
|
||||
},
|
||||
{
|
||||
"id": "flow-3",
|
||||
"from": "decision",
|
||||
"to": "promote",
|
||||
"label": "authorize"
|
||||
},
|
||||
|
||||
{
|
||||
"id": "unsafe",
|
||||
"from": "triage",
|
||||
"to": "observe",
|
||||
"label": "Unsafe",
|
||||
"variant": "security",
|
||||
"fromSide": "right",
|
||||
"toSide": "right"
|
||||
"from": "correct",
|
||||
"to": "approve",
|
||||
"fromSide": "left",
|
||||
"toSide": "right",
|
||||
"route": "straight"
|
||||
},
|
||||
{
|
||||
"id": "review-loop",
|
||||
"from": "observe",
|
||||
"to": "correct",
|
||||
"label": "Requalify",
|
||||
"variant": "dashed"
|
||||
"id": "flow-4",
|
||||
"from": "approve",
|
||||
"to": "retire",
|
||||
"fromSide": "left",
|
||||
"toSide": "right",
|
||||
"route": "straight"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
"schema_version": 1,
|
||||
"diagram_type": "architecture",
|
||||
"meta": {
|
||||
"title": "TO-BE: Measure skills adoption",
|
||||
"title": "Recommended collection plan: Measurement",
|
||||
"output": "static/diagrams/strategy-measurement-mobile/index.html",
|
||||
"quality_profile": "showcase",
|
||||
"legend": {
|
||||
@@ -11,120 +11,95 @@
|
||||
},
|
||||
"components": [
|
||||
{
|
||||
"id": "collect",
|
||||
"id": "baseline",
|
||||
"type": "backend",
|
||||
"label": "Establish baseline",
|
||||
"sublabel": "Current workflow",
|
||||
"tag": "Comparable workflow",
|
||||
"sublabel": "Join task / PR / CI IDs\nAgree acceptance + window\nRecord revision and client\nKeep unknowns visible",
|
||||
"pos": [
|
||||
20,
|
||||
20
|
||||
40,
|
||||
40
|
||||
],
|
||||
"size": [
|
||||
180,
|
||||
60
|
||||
560,
|
||||
440
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "validate",
|
||||
"type": "backend",
|
||||
"label": "Join evidence",
|
||||
"sublabel": "Tasks / versions / costs",
|
||||
"id": "success",
|
||||
"type": "frontend",
|
||||
"label": "Accepted outcomes",
|
||||
"tag": "Quality · weekly",
|
||||
"sublabel": "Tracker: starts + acceptance\nAccepted / eligible starts\nwith ended window × 100\nKeep failed, stopped, unknown\nShow outcome coverage",
|
||||
"pos": [
|
||||
20,
|
||||
140
|
||||
40,
|
||||
610
|
||||
],
|
||||
"size": [
|
||||
180,
|
||||
60
|
||||
560,
|
||||
440
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "calculate",
|
||||
"type": "backend",
|
||||
"label": "Measure the pilot",
|
||||
"sublabel": "Outcomes / quality",
|
||||
"id": "quality",
|
||||
"type": "security",
|
||||
"label": "Escaped quality",
|
||||
"tag": "Quality · monthly",
|
||||
"sublabel": "PRs + linked defect records\nAffected / followed-up\naccepted changes × 100\nCount each change once\nMissing links ≠ clean",
|
||||
"pos": [
|
||||
20,
|
||||
260
|
||||
40,
|
||||
1180
|
||||
],
|
||||
"size": [
|
||||
180,
|
||||
60
|
||||
560,
|
||||
440
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "balance",
|
||||
"type": "backend",
|
||||
"label": "Report together",
|
||||
"sublabel": "Cost / confidence / gaps",
|
||||
"id": "cost",
|
||||
"type": "cloud",
|
||||
"label": "Cost per outcome",
|
||||
"tag": "Finance · monthly",
|
||||
"sublabel": "Invoices + review minutes\nAll costs / accepted tasks\nSame matured start cohort\nFailed work + licenses too\nMissing buckets = partial",
|
||||
"pos": [
|
||||
20,
|
||||
380
|
||||
40,
|
||||
1750
|
||||
],
|
||||
"size": [
|
||||
180,
|
||||
60
|
||||
560,
|
||||
440
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "weigh",
|
||||
"type": "backend",
|
||||
"label": "Broader adoption",
|
||||
"sublabel": "Availability + use",
|
||||
"id": "confidence",
|
||||
"type": "frontend",
|
||||
"label": "Verification confidence",
|
||||
"tag": "People · each cycle",
|
||||
"sublabel": "Anonymous 1–5 survey\nSum of valid scores / replies\nShow spread; response rate:\nreplies / invitations × 100\nProtect small cohorts",
|
||||
"pos": [
|
||||
20,
|
||||
500
|
||||
40,
|
||||
2320
|
||||
],
|
||||
"size": [
|
||||
180,
|
||||
60
|
||||
560,
|
||||
440
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "decide",
|
||||
"type": "backend",
|
||||
"id": "monitor",
|
||||
"type": "database",
|
||||
"label": "Ongoing monitoring",
|
||||
"sublabel": "Review + maintenance",
|
||||
"tag": "Catalog + cohort report",
|
||||
"sublabel": "Catalog + cohort records\nTrack support, use, reviews\nCompare with baseline\nShow counts + coverage\nZero denominator = N/A",
|
||||
"pos": [
|
||||
20,
|
||||
620
|
||||
40,
|
||||
2890
|
||||
],
|
||||
"size": [
|
||||
180,
|
||||
60
|
||||
560,
|
||||
440
|
||||
]
|
||||
}
|
||||
],
|
||||
"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"
|
||||
}
|
||||
]
|
||||
"connections": []
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
"schema_version": 1,
|
||||
"diagram_type": "architecture",
|
||||
"meta": {
|
||||
"title": "TO-BE: Measure skills adoption",
|
||||
"title": "Recommended collection plan: Measurement",
|
||||
"output": "static/diagrams/strategy-measurement/index.html",
|
||||
"quality_profile": "showcase",
|
||||
"legend": {
|
||||
@@ -11,120 +11,95 @@
|
||||
},
|
||||
"components": [
|
||||
{
|
||||
"id": "collect",
|
||||
"id": "baseline",
|
||||
"type": "backend",
|
||||
"label": "Establish baseline",
|
||||
"sublabel": "Current workflow",
|
||||
"tag": "Comparable workflow",
|
||||
"sublabel": "Join task / PR / CI IDs\nAgree acceptance + window\nRecord revision and client\nKeep unknowns visible",
|
||||
"pos": [
|
||||
20,
|
||||
20
|
||||
40,
|
||||
40
|
||||
],
|
||||
"size": [
|
||||
180,
|
||||
60
|
||||
560,
|
||||
440
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "validate",
|
||||
"type": "backend",
|
||||
"label": "Join evidence",
|
||||
"sublabel": "Tasks / versions / costs",
|
||||
"id": "success",
|
||||
"type": "frontend",
|
||||
"label": "Accepted outcomes",
|
||||
"tag": "Quality · weekly",
|
||||
"sublabel": "Tracker: starts + acceptance\nAccepted / eligible starts\nwith ended window × 100\nKeep failed, stopped, unknown\nShow outcome coverage",
|
||||
"pos": [
|
||||
260,
|
||||
20
|
||||
700,
|
||||
40
|
||||
],
|
||||
"size": [
|
||||
180,
|
||||
60
|
||||
560,
|
||||
440
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "calculate",
|
||||
"type": "backend",
|
||||
"label": "Measure the pilot",
|
||||
"sublabel": "Outcomes / quality",
|
||||
"id": "quality",
|
||||
"type": "security",
|
||||
"label": "Escaped quality",
|
||||
"tag": "Quality · monthly",
|
||||
"sublabel": "PRs + linked defect records\nAffected / followed-up\naccepted changes × 100\nCount each change once\nMissing links ≠ clean",
|
||||
"pos": [
|
||||
260,
|
||||
150
|
||||
1360,
|
||||
40
|
||||
],
|
||||
"size": [
|
||||
180,
|
||||
60
|
||||
560,
|
||||
440
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "balance",
|
||||
"type": "backend",
|
||||
"label": "Report together",
|
||||
"sublabel": "Cost / confidence / gaps",
|
||||
"id": "cost",
|
||||
"type": "cloud",
|
||||
"label": "Cost per outcome",
|
||||
"tag": "Finance · monthly",
|
||||
"sublabel": "Invoices + review minutes\nAll costs / accepted tasks\nSame matured start cohort\nFailed work + licenses too\nMissing buckets = partial",
|
||||
"pos": [
|
||||
20,
|
||||
150
|
||||
1360,
|
||||
610
|
||||
],
|
||||
"size": [
|
||||
180,
|
||||
60
|
||||
560,
|
||||
440
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "weigh",
|
||||
"type": "backend",
|
||||
"label": "Broader adoption",
|
||||
"sublabel": "Availability + use",
|
||||
"id": "confidence",
|
||||
"type": "frontend",
|
||||
"label": "Verification confidence",
|
||||
"tag": "People · each cycle",
|
||||
"sublabel": "Anonymous 1–5 survey\nSum of valid scores / replies\nShow spread; response rate:\nreplies / invitations × 100\nProtect small cohorts",
|
||||
"pos": [
|
||||
20,
|
||||
280
|
||||
700,
|
||||
610
|
||||
],
|
||||
"size": [
|
||||
180,
|
||||
60
|
||||
560,
|
||||
440
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "decide",
|
||||
"type": "backend",
|
||||
"id": "monitor",
|
||||
"type": "database",
|
||||
"label": "Ongoing monitoring",
|
||||
"sublabel": "Review + maintenance",
|
||||
"tag": "Catalog + cohort report",
|
||||
"sublabel": "Catalog + cohort records\nTrack support, use, reviews\nCompare with baseline\nShow counts + coverage\nZero denominator = N/A",
|
||||
"pos": [
|
||||
260,
|
||||
280
|
||||
40,
|
||||
610
|
||||
],
|
||||
"size": [
|
||||
180,
|
||||
60
|
||||
560,
|
||||
440
|
||||
]
|
||||
}
|
||||
],
|
||||
"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"
|
||||
}
|
||||
]
|
||||
"connections": []
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
"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": {
|
||||
@@ -13,85 +13,91 @@
|
||||
{
|
||||
"id": "risk",
|
||||
"type": "security",
|
||||
"label": "Classify risk",
|
||||
"sublabel": "R1 / R2 / R3",
|
||||
"label": "Define the envelope",
|
||||
"tag": "Owner + reviewers",
|
||||
"sublabel": "R1: nonsensitive drafting\nR2: code / customer work\nR3: human-authorized\nAgree acceptance rules",
|
||||
"pos": [
|
||||
20,
|
||||
20
|
||||
40,
|
||||
40
|
||||
],
|
||||
"size": [
|
||||
180,
|
||||
60
|
||||
560,
|
||||
440
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "plan",
|
||||
"type": "security",
|
||||
"label": "Agree evaluation",
|
||||
"sublabel": "Task mix + thresholds",
|
||||
"id": "compare",
|
||||
"type": "backend",
|
||||
"label": "Compare three paths",
|
||||
"tag": "Same starting artifacts",
|
||||
"sublabel": "No skill / approved / new\nPositive + negative cases\nRepeat trials per client\nKeep failed attempts",
|
||||
"pos": [
|
||||
20,
|
||||
140
|
||||
40,
|
||||
610
|
||||
],
|
||||
"size": [
|
||||
180,
|
||||
60
|
||||
560,
|
||||
440
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "trial",
|
||||
"type": "security",
|
||||
"label": "Repeat trials",
|
||||
"sublabel": "Candidate vs approved",
|
||||
"id": "inspect",
|
||||
"type": "frontend",
|
||||
"label": "Inspect the outcome",
|
||||
"tag": "Independent evidence",
|
||||
"sublabel": "Right skill selected?\nProcedure safe?\nArtifact checks pass?\nUseful workflow result?",
|
||||
"pos": [
|
||||
20,
|
||||
260
|
||||
40,
|
||||
1180
|
||||
],
|
||||
"size": [
|
||||
180,
|
||||
60
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "verify",
|
||||
"type": "security",
|
||||
"label": "Verify artifacts",
|
||||
"sublabel": "Independent checks",
|
||||
"pos": [
|
||||
20,
|
||||
380
|
||||
],
|
||||
"size": [
|
||||
180,
|
||||
60
|
||||
560,
|
||||
440
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "gate",
|
||||
"type": "security",
|
||||
"label": "All gates pass?",
|
||||
"sublabel": "Safety cannot be traded",
|
||||
"label": "Every gate must pass",
|
||||
"tag": "Quality Engineering",
|
||||
"sublabel": "Safety + authorization\nSchema + provenance\nCritical effect blocks\nMissing coverage blocks",
|
||||
"pos": [
|
||||
20,
|
||||
500
|
||||
40,
|
||||
1750
|
||||
],
|
||||
"size": [
|
||||
180,
|
||||
60
|
||||
560,
|
||||
440
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "promote",
|
||||
"type": "security",
|
||||
"label": "Promote or hold",
|
||||
"sublabel": "Owner decision",
|
||||
"id": "canary",
|
||||
"type": "cloud",
|
||||
"label": "Test bounded work",
|
||||
"tag": "Human + AI Agent",
|
||||
"sublabel": "Qualified client + model\nHuman judges usefulness\nShow counts / uncertainty\nEvidence before promotion",
|
||||
"pos": [
|
||||
20,
|
||||
620
|
||||
40,
|
||||
2320
|
||||
],
|
||||
"size": [
|
||||
180,
|
||||
60
|
||||
560,
|
||||
440
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "improve",
|
||||
"type": "database",
|
||||
"label": "Feed the next revision",
|
||||
"tag": "Owning team",
|
||||
"sublabel": "Failures to regression set\nReview corrections\nMaterial client/model drift\ntriggers requalification",
|
||||
"pos": [
|
||||
40,
|
||||
2890
|
||||
],
|
||||
"size": [
|
||||
560,
|
||||
440
|
||||
]
|
||||
}
|
||||
],
|
||||
@@ -99,32 +105,42 @@
|
||||
{
|
||||
"id": "flow-0",
|
||||
"from": "risk",
|
||||
"to": "plan",
|
||||
"label": "Scope"
|
||||
"to": "compare",
|
||||
"fromSide": "bottom",
|
||||
"toSide": "top",
|
||||
"route": "straight"
|
||||
},
|
||||
{
|
||||
"id": "flow-1",
|
||||
"from": "plan",
|
||||
"to": "trial",
|
||||
"label": "freeze plan"
|
||||
"from": "compare",
|
||||
"to": "inspect",
|
||||
"fromSide": "bottom",
|
||||
"toSide": "top",
|
||||
"route": "straight"
|
||||
},
|
||||
{
|
||||
"id": "flow-2",
|
||||
"from": "trial",
|
||||
"to": "verify",
|
||||
"label": "Assess"
|
||||
"from": "inspect",
|
||||
"to": "gate",
|
||||
"fromSide": "bottom",
|
||||
"toSide": "top",
|
||||
"route": "straight"
|
||||
},
|
||||
{
|
||||
"id": "flow-3",
|
||||
"from": "verify",
|
||||
"to": "gate",
|
||||
"label": "review evidence"
|
||||
"from": "gate",
|
||||
"to": "canary",
|
||||
"fromSide": "bottom",
|
||||
"toSide": "top",
|
||||
"route": "straight"
|
||||
},
|
||||
{
|
||||
"id": "flow-4",
|
||||
"from": "gate",
|
||||
"to": "promote",
|
||||
"label": "decide"
|
||||
"from": "canary",
|
||||
"to": "improve",
|
||||
"fromSide": "bottom",
|
||||
"toSide": "top",
|
||||
"route": "straight"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
"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": {
|
||||
@@ -13,85 +13,91 @@
|
||||
{
|
||||
"id": "risk",
|
||||
"type": "security",
|
||||
"label": "Classify risk",
|
||||
"sublabel": "R1 / R2 / R3",
|
||||
"label": "Define the envelope",
|
||||
"tag": "Owner + reviewers",
|
||||
"sublabel": "R1: nonsensitive drafting\nR2: code / customer work\nR3: human-authorized\nAgree acceptance rules",
|
||||
"pos": [
|
||||
20,
|
||||
20
|
||||
40,
|
||||
40
|
||||
],
|
||||
"size": [
|
||||
180,
|
||||
60
|
||||
560,
|
||||
440
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "plan",
|
||||
"type": "security",
|
||||
"label": "Agree evaluation",
|
||||
"sublabel": "Task mix + thresholds",
|
||||
"id": "compare",
|
||||
"type": "backend",
|
||||
"label": "Compare three paths",
|
||||
"tag": "Same starting artifacts",
|
||||
"sublabel": "No skill / approved / new\nPositive + negative cases\nRepeat trials per client\nKeep failed attempts",
|
||||
"pos": [
|
||||
260,
|
||||
20
|
||||
700,
|
||||
40
|
||||
],
|
||||
"size": [
|
||||
180,
|
||||
60
|
||||
560,
|
||||
440
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "trial",
|
||||
"type": "security",
|
||||
"label": "Repeat trials",
|
||||
"sublabel": "Candidate vs approved",
|
||||
"id": "inspect",
|
||||
"type": "frontend",
|
||||
"label": "Inspect the outcome",
|
||||
"tag": "Independent evidence",
|
||||
"sublabel": "Right skill selected?\nProcedure safe?\nArtifact checks pass?\nUseful workflow result?",
|
||||
"pos": [
|
||||
260,
|
||||
150
|
||||
1360,
|
||||
40
|
||||
],
|
||||
"size": [
|
||||
180,
|
||||
60
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "verify",
|
||||
"type": "security",
|
||||
"label": "Verify artifacts",
|
||||
"sublabel": "Independent checks",
|
||||
"pos": [
|
||||
20,
|
||||
150
|
||||
],
|
||||
"size": [
|
||||
180,
|
||||
60
|
||||
560,
|
||||
440
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "gate",
|
||||
"type": "security",
|
||||
"label": "All gates pass?",
|
||||
"sublabel": "Safety cannot be traded",
|
||||
"label": "Every gate must pass",
|
||||
"tag": "Quality Engineering",
|
||||
"sublabel": "Safety + authorization\nSchema + provenance\nCritical effect blocks\nMissing coverage blocks",
|
||||
"pos": [
|
||||
20,
|
||||
280
|
||||
1360,
|
||||
610
|
||||
],
|
||||
"size": [
|
||||
180,
|
||||
60
|
||||
560,
|
||||
440
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "promote",
|
||||
"type": "security",
|
||||
"label": "Promote or hold",
|
||||
"sublabel": "Owner decision",
|
||||
"id": "canary",
|
||||
"type": "cloud",
|
||||
"label": "Test bounded work",
|
||||
"tag": "Human + AI Agent",
|
||||
"sublabel": "Qualified client + model\nHuman judges usefulness\nShow counts / uncertainty\nEvidence before promotion",
|
||||
"pos": [
|
||||
260,
|
||||
280
|
||||
700,
|
||||
610
|
||||
],
|
||||
"size": [
|
||||
180,
|
||||
60
|
||||
560,
|
||||
440
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "improve",
|
||||
"type": "database",
|
||||
"label": "Feed the next revision",
|
||||
"tag": "Owning team",
|
||||
"sublabel": "Failures to regression set\nReview corrections\nMaterial client/model drift\ntriggers requalification",
|
||||
"pos": [
|
||||
40,
|
||||
610
|
||||
],
|
||||
"size": [
|
||||
560,
|
||||
440
|
||||
]
|
||||
}
|
||||
],
|
||||
@@ -99,32 +105,42 @@
|
||||
{
|
||||
"id": "flow-0",
|
||||
"from": "risk",
|
||||
"to": "plan",
|
||||
"label": "Scope"
|
||||
"to": "compare",
|
||||
"fromSide": "right",
|
||||
"toSide": "left",
|
||||
"route": "straight"
|
||||
},
|
||||
{
|
||||
"id": "flow-1",
|
||||
"from": "plan",
|
||||
"to": "trial",
|
||||
"label": "freeze plan"
|
||||
"from": "compare",
|
||||
"to": "inspect",
|
||||
"fromSide": "right",
|
||||
"toSide": "left",
|
||||
"route": "straight"
|
||||
},
|
||||
{
|
||||
"id": "flow-2",
|
||||
"from": "trial",
|
||||
"to": "verify",
|
||||
"label": "Assess"
|
||||
"from": "inspect",
|
||||
"to": "gate",
|
||||
"fromSide": "bottom",
|
||||
"toSide": "top",
|
||||
"route": "straight"
|
||||
},
|
||||
{
|
||||
"id": "flow-3",
|
||||
"from": "verify",
|
||||
"to": "gate",
|
||||
"label": "review evidence"
|
||||
"from": "gate",
|
||||
"to": "canary",
|
||||
"fromSide": "left",
|
||||
"toSide": "right",
|
||||
"route": "straight"
|
||||
},
|
||||
{
|
||||
"id": "flow-4",
|
||||
"from": "gate",
|
||||
"to": "promote",
|
||||
"label": "decide"
|
||||
"from": "canary",
|
||||
"to": "improve",
|
||||
"fromSide": "left",
|
||||
"toSide": "right",
|
||||
"route": "straight"
|
||||
}
|
||||
]
|
||||
}
|
||||
+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-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",
|
||||
"test:browser": "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,45 @@
|
||||
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 ['governance','quality','adoption','measurement','maintenance']) for(const width of [1440,1024,390,320]) {
|
||||
const page=await browser.newPage({viewport:{width,height:900},colorScheme:'light'});const errors=[];page.on('pageerror',e=>errors.push(e.message));
|
||||
const route=topic==='measurement'?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>700?'.story-desktop':'.story-mobile');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('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};
|
||||
});
|
||||
assert.equal(geometry.nodes,6);assert.deepEqual(geometry.issues,[]);assert(geometry.min>=10,JSON.stringify(geometry));
|
||||
for(const theme of ['light','dark']){
|
||||
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);
|
||||
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();
|
||||
assert((await expanded.url()).includes(width<=700?`${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 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});
|
||||
@@ -1,6 +1,7 @@
|
||||
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';
|
||||
@@ -27,11 +28,12 @@ for (const file of readdirSync('diagrams').sort()) {
|
||||
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);
|
||||
if (roadmap) {
|
||||
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/workflow/render-workflow.mjs', input, output], {stdio:'inherit', env:{...process.env, ARCHIFY_UPDATE_CHECK_DISABLED:'1'}});
|
||||
writeFileSync(output, roadmapViewer(readFileSync(output, 'utf8'), spec));
|
||||
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']);
|
||||
@@ -61,13 +63,13 @@ 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) {
|
||||
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('Roadmap final artifact failed');
|
||||
writeFileSync(`.cache/archify/${name}.portal.json`, JSON.stringify({source:input, sourceSha256:hash(input), adapterSha256:hash('scripts/roadmap-viewer.mjs'), artifactSha256:hash(output), checker:checked}, null, 2));
|
||||
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') {
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
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 = ['governance','quality','adoption','measurement','maintenance'];
|
||||
test('all six Skills Adoption pages account for exactly five diagrams and ten sources',()=>{
|
||||
let count=0;
|
||||
for(const route of ['stage-01-skills-adoption',...topics.map(t=>t==='measurement'?t:`skills-${t}`)]){
|
||||
const diagrams=[...read(`docs/strategy/${route}.mdx`).matchAll(/<ArchifyDiagram name="([^"]+)"/g)];
|
||||
assert.equal(diagrams.length,route.startsWith('stage-')?0: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,5);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.equal(new Set(desktop.components.map(n=>n.pos[0])).size,3);
|
||||
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.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,6);
|
||||
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,6);
|
||||
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='not a full story';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=>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 ['Tracker:','Invoices + review minutes','linked defect records','Anonymous 1–5 survey','Missing buckets = partial','Zero denominator = N/A'])assert(text('measurement').includes(marker),marker);
|
||||
assert(text('maintenance').includes('No automatic reinstatement'));
|
||||
});
|
||||
@@ -0,0 +1,35 @@
|
||||
// Keep native geometry, metadata, routing and exports; enrich only typography.
|
||||
export const isSkillsStory = name => /^strategy-(governance|quality|adoption|measurement|maintenance)(-mobile)?$/.test(name);
|
||||
const escape = text => text.replaceAll('&', '&').replaceAll('<', '<').replaceAll('>', '>').replaceAll('"', '"');
|
||||
export function skillsViewer(html, spec) {
|
||||
if (spec.diagram_type !== 'architecture' || spec.components.length !== 6) throw new Error('Skills story contract drift');
|
||||
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 ((lines.length < 4 || lines.length > 5) || lines.some(line => line.length > 29) || node.label.length > 25) 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, 52, 36, 'class="t-muted" data-detail="context"')
|
||||
+ text(node.label, 118, 42, 'class="t-primary" data-node-label="" font-weight="700"')
|
||||
+ lines.map((line,i) => text(line, 190+i*46, 36, '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 = Math.max(...spec.components.map(n=>n.pos[0]+n.size[0]))+40;
|
||||
const height = Math.max(...spec.components.map(n=>n.pos[1]+n.size[1]))+40;
|
||||
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;}
|
||||
.c-grid {opacity:0;}
|
||||
[data-node-id] > rect:not(.c-mask) {stroke-width:3;}
|
||||
</style>`);
|
||||
return html;
|
||||
}
|
||||
@@ -38,7 +38,7 @@ test('mobile story diagrams preserve the same nodes and directed relationships',
|
||||
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,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|maintenance)$/.test(name)) && e.from !== e.to), name);
|
||||
assert.equal(desktop.meta.legend.mode, 'hidden');
|
||||
}
|
||||
});
|
||||
|
||||
@@ -12,14 +12,15 @@ export default function ArchifyDiagram({name, title, compact = false, story = fa
|
||||
const headingId = useId();
|
||||
const [expanded, setExpanded] = useState(false);
|
||||
const [narrowRoadmap, setNarrowRoadmap] = useState(false);
|
||||
const skillsStory = /^strategy-(governance|quality|adoption|measurement|maintenance)$/.test(name);
|
||||
useEffect(() => {
|
||||
if (!name.startsWith('strategy-roadmap')) return;
|
||||
const media = window.matchMedia('(max-width: 999px)');
|
||||
if (!name.startsWith('strategy-roadmap') && !skillsStory) return;
|
||||
const media = window.matchMedia(skillsStory ? '(max-width: 700px)' : '(max-width: 999px)');
|
||||
const update = () => setNarrowRoadmap(media.matches);
|
||||
update();
|
||||
media.addEventListener('change', update);
|
||||
return () => media.removeEventListener('change', update);
|
||||
}, [name]);
|
||||
}, [name, skillsStory]);
|
||||
const {colorMode, setColorMode} = useColorMode();
|
||||
const initialTheme = useRef(colorMode);
|
||||
const desktop = useRef<HTMLIFrameElement>(null);
|
||||
@@ -66,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" />
|
||||
@@ -74,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={`${narrowRoadmap ? mobileSource : source}?${name.startsWith('strategy-roadmap') ? 'embed=1&' : ''}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>;
|
||||
}
|
||||
@@ -152,3 +152,17 @@ a:focus-visible, button:focus-visible {outline: 3px solid #b88719; outline-offse
|
||||
[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--story.archify-panel--skills > .story-desktop {aspect-ratio: auto; min-height: 460px; height: calc((100vw - 364px) * .56 + 72px); max-height: 720px;}
|
||||
@media (max-width: 996px) and (min-width: 701px) {
|
||||
.archify-panel--story.archify-panel--skills > .story-desktop {height: calc(100vw * .56 + 72px);}
|
||||
}
|
||||
@media (max-width: 700px) {
|
||||
.archify-panel--story.archify-panel--skills > .story-mobile {aspect-ratio: auto; height: 1680px; max-width: 400px; 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: 1900px; min-height: 1900px;}
|
||||
}
|
||||
Reference in new issue
Block a user