diff --git a/diagrams/strategy-adoption-mobile.architecture.json b/diagrams/strategy-adoption-mobile.architecture.json index 78a9456..f88e529 100644 --- a/diagrams/strategy-adoption-mobile.architecture.json +++ b/diagrams/strategy-adoption-mobile.architecture.json @@ -7,140 +7,239 @@ "quality_profile": "showcase", "legend": { "mode": "hidden" - } + }, + "viewBox": [ + 880, + 2040 + ] }, "components": [ { "id": "delivery", - "type": "backend", + "type": "external", "label": "Delivery first", - "tag": "Understand real work", - "sublabel": "Codebase + principles\nSystem logic and tests\nBuilds and packaging\nDeployments + baseline", + "tag": "Start with a real workflow", + "sublabel": "Baseline + bounded canary", "pos": [ - 40, - 40 + 60, + 120 ], "size": [ - 560, - 440 - ] + 740, + 220 + ], + "icon": "none" }, { - "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", + "id": "human", + "type": "backend", + "label": "Human", + "tag": "Direct + guide + review", + "sublabel": "Define outcome; inspect artifacts", "pos": [ - 40, - 610 + 60, + 1280 ], "size": [ - 560, - 440 - ] + 740, + 220 + ], + "icon": "none" }, { - "id": "coach", - "type": "frontend", - "label": "Practice together", - "tag": "Human + AI Agent", - "sublabel": "Platform qualifies client\nPeople supports learning\nSelect skill; inspect work\nKeep a manual path", + "id": "agent", + "type": "external", + "label": "AI Agent", + "tag": "Supported client + approved skills", + "sublabel": "Produce work within the boundary", "pos": [ - 40, - 1180 + 60, + 910 ], "size": [ - 560, - 440 - ] - }, - { - "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": [ - 40, - 1750 + 740, + 220 ], - "size": [ - 560, - 440 - ] + "icon": "none" }, { "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", + "type": "external", + "label": "Learn from real work", + "tag": "Ongoing, reviewed improvement", + "sublabel": "Feedback + friction + measures\nRetain a manual path\nNo quotas or rankings", "pos": [ - 40, - 2320 + 60, + 490 ], "size": [ - 560, - 440 - ] + 740, + 270 + ], + "icon": "none" }, { "id": "expand", - "type": "cloud", - "label": "Expand with evidence", + "type": "backend", + "label": "Expand on evidence", "tag": "Other SDLC phases", - "sublabel": "Later order undecided\nRepeat baseline + topology\nDelivery keeps improving\nNot autonomous authority", + "sublabel": "Later order undecided\nDelivery keeps improving", "pos": [ - 40, - 2890 + 60, + 1650 ], "size": [ - 560, - 440 - ] + 740, + 240 + ], + "icon": "none" } ], "connections": [ { - "id": "flow-0", + "id": "delivery-agent", "from": "delivery", - "to": "workflow", - "fromSide": "bottom", - "toSide": "top", - "route": "straight" + "to": "agent", + "label": "Practice", + "fromSide": "right", + "toSide": "right", + "route": "straight", + "width": 4, + "variant": "default", + "via": [ + [ + 850, + 230.0 + ], + [ + 850, + 1020.0 + ] + ], + "labelAt": [ + 780, + 870 + ] }, { - "id": "flow-1", - "from": "workflow", - "to": "coach", - "fromSide": "bottom", - "toSide": "top", - "route": "straight" + "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": "flow-2", - "from": "coach", - "to": "verify", + "id": "agent-human", + "from": "agent", + "to": "human", + "label": "Work to inspect", "fromSide": "bottom", "toSide": "top", - "route": "straight" + "route": "straight", + "width": 4, + "variant": "default", + "labelAt": [ + 610, + 1185 + ] }, { - "id": "flow-3", - "from": "verify", + "id": "agent-learn", + "from": "agent", "to": "learn", - "fromSide": "bottom", - "toSide": "top", - "route": "straight" + "label": "Observe", + "fromSide": "top", + "toSide": "bottom", + "route": "straight", + "width": 4, + "variant": "default", + "labelAt": [ + 610, + 815 + ] }, { - "id": "flow-4", + "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", - "fromSide": "bottom", - "toSide": "top", - "route": "straight" + "label": "Feedback", + "fromSide": "left", + "toSide": "left", + "route": "straight", + "width": 4, + "variant": "default", + "via": [ + [ + 20, + 625.0 + ], + [ + 20, + 1770.0 + ] + ], + "labelAt": [ + 620, + 1610 + ] } ] -} \ No newline at end of file +} diff --git a/diagrams/strategy-adoption.architecture.json b/diagrams/strategy-adoption.architecture.json index 9fe33da..2896ae7 100644 --- a/diagrams/strategy-adoption.architecture.json +++ b/diagrams/strategy-adoption.architecture.json @@ -7,140 +7,237 @@ "quality_profile": "showcase", "legend": { "mode": "hidden" - } + }, + "viewBox": [ + 2040, + 1160 + ] }, "components": [ { "id": "delivery", - "type": "backend", + "type": "external", "label": "Delivery first", - "tag": "Understand real work", - "sublabel": "Codebase + principles\nSystem logic and tests\nBuilds and packaging\nDeployments + baseline", + "tag": "Start with a real workflow", + "sublabel": "Baseline + bounded canary", "pos": [ - 40, - 40 + 60, + 350 ], "size": [ - 560, - 440 - ] + 470, + 210 + ], + "icon": "none" }, { - "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", + "id": "human", + "type": "backend", + "label": "Human", + "tag": "Direct + guide + review", + "sublabel": "Define outcome; inspect artifacts", "pos": [ 700, - 40 + 90 ], "size": [ - 560, - 440 - ] + 570, + 190 + ], + "icon": "none" }, { - "id": "coach", - "type": "frontend", - "label": "Practice together", - "tag": "Human + AI Agent", - "sublabel": "Platform qualifies client\nPeople supports learning\nSelect skill; inspect work\nKeep a manual path", + "id": "agent", + "type": "external", + "label": "AI Agent", + "tag": "Supported client + approved skills", + "sublabel": "Produce work within the boundary", "pos": [ - 1360, - 40 + 700, + 440 ], "size": [ - 560, - 440 - ] - }, - { - "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": [ - 1360, - 610 + 570, + 190 ], - "size": [ - 560, - 440 - ] + "icon": "none" }, { "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", + "type": "external", + "label": "Learn from real work", + "tag": "Ongoing, reviewed improvement", + "sublabel": "Feedback + friction + measures\nRetain a manual path\nNo quotas or rankings", "pos": [ 700, - 610 + 800 ], "size": [ - 560, - 440 - ] + 570, + 270 + ], + "icon": "none" }, { "id": "expand", - "type": "cloud", - "label": "Expand with evidence", + "type": "backend", + "label": "Expand on evidence", "tag": "Other SDLC phases", - "sublabel": "Later order undecided\nRepeat baseline + topology\nDelivery keeps improving\nNot autonomous authority", + "sublabel": "Later order undecided\nDelivery keeps improving", "pos": [ - 40, - 610 + 1460, + 360 ], "size": [ - 560, - 440 - ] + 520, + 240 + ], + "icon": "none" } ], "connections": [ { - "id": "flow-0", + "id": "delivery-agent", "from": "delivery", - "to": "workflow", + "to": "agent", + "label": "Practice", "fromSide": "right", "toSide": "left", - "route": "straight" + "route": "straight", + "width": 4, + "variant": "default", + "via": [ + [ + 585, + 455 + ], + [ + 585, + 535 + ] + ], + "labelAt": [ + 570, + 600 + ] }, { - "id": "flow-1", - "from": "workflow", - "to": "coach", - "fromSide": "right", - "toSide": "left", - "route": "straight" - }, - { - "id": "flow-2", - "from": "coach", - "to": "verify", + "id": "human-agent", + "from": "human", + "to": "agent", + "label": "Direction", "fromSide": "bottom", "toSide": "top", - "route": "straight" + "route": "straight", + "width": 4, + "variant": "default", + "labelAt": [ + 1100, + 360 + ] }, { - "id": "flow-3", - "from": "verify", - "to": "learn", + "id": "agent-human", + "from": "agent", + "to": "human", + "label": "Work to inspect", "fromSide": "left", - "toSide": "right", - "route": "straight" + "toSide": "left", + "route": "straight", + "width": 4, + "variant": "default", + "via": [ + [ + 630, + 535 + ], + [ + 630, + 185 + ] + ], + "labelAt": [ + 470, + 240 + ] }, { - "id": "flow-4", + "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", - "fromSide": "left", - "toSide": "right", - "route": "straight" + "label": "Feedback", + "fromSide": "right", + "toSide": "bottom", + "route": "straight", + "width": 4, + "variant": "default", + "via": [ + [ + 1720, + 935 + ] + ], + "labelAt": [ + 1480, + 895 + ] } ] -} \ No newline at end of file +} diff --git a/diagrams/strategy-governance-mobile.architecture.json b/diagrams/strategy-governance-mobile.architecture.json index a0bb588..857c1e7 100644 --- a/diagrams/strategy-governance-mobile.architecture.json +++ b/diagrams/strategy-governance-mobile.architecture.json @@ -7,140 +7,241 @@ "quality_profile": "showcase", "legend": { "mode": "hidden" - } + }, + "viewBox": [ + 880, + 2710 + ] }, "components": [ { "id": "owner", - "type": "backend", - "label": "Propose a skill", + "type": "external", + "label": "01 Propose", "tag": "Owning team", - "sublabel": "Problem + intended users\nData and authority scope\nSKILL.md + dependencies\nTestable outcome", + "sublabel": "Scope + testable outcome", "pos": [ - 40, - 40 + 60, + 120 ], "size": [ - 560, - 440 - ] + 740, + 220 + ], + "icon": "none" }, { "id": "review", - "type": "security", - "label": "Independent review", + "type": "external", + "label": "02 Review independently", "tag": "Quality + Security", - "sublabel": "Evaluate useful outcomes\nCheck risk boundaries\nAuthor is not sole approver\nRecord revision evidence", + "sublabel": "Author is not sole approver", "pos": [ - 40, - 610 + 60, + 490 ], "size": [ - 560, - 440 - ] + 740, + 220 + ], + "icon": "none" }, { "id": "canary", - "type": "frontend", - "label": "Qualify real use", + "type": "external", + "label": "03 Qualify real use", "tag": "Human + AI Agent", - "sublabel": "Test exact client build\nRun a bounded canary\nInspect work independently\nNo failed mandatory gate", + "sublabel": "Exact client + bounded canary", "pos": [ - 40, - 1180 + 60, + 860 ], "size": [ - 560, - 440 - ] + 740, + 220 + ], + "icon": "none" }, { "id": "approve", - "type": "security", - "label": "Approve exact scope", + "type": "backend", + "label": "04 Approve exact scope", "tag": "Accountable approvers", - "sublabel": "Bind approval to digest\nPermitted uses + expiry\nExceptions cannot bypass\nprotected controls", + "sublabel": "Digest + permitted uses + expiry", "pos": [ - 40, - 1750 + 60, + 1230 ], "size": [ - 560, - 440 - ] + 740, + 220 + ], + "icon": "none" }, { "id": "publish", - "type": "database", - "label": "Version the bundle", + "type": "backend", + "label": "05 Publish the bundle", "tag": "Data & AI catalog", - "sublabel": "Pin skill + adapter\nand dependency revisions\nRecord approval evidence\nKeep last-known-good", + "sublabel": "Pin skill, adapter + dependencies", "pos": [ - 40, - 2320 + 60, + 1600 ], "size": [ - 560, - 440 - ] + 740, + 220 + ], + "icon": "none" }, { "id": "distribute", - "type": "cloud", - "label": "Verify loaded state", + "type": "backend", + "label": "06 Verify loaded state", "tag": "Platform & IT", - "sublabel": "Stage and check digest\nRead effective revision\nTest open-session reload\nRevoke unsafe revisions", + "sublabel": "Read revision; verify reload", "pos": [ - 40, - 2890 + 60, + 1970 ], "size": [ - 560, - 440 - ] + 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": "", "fromSide": "bottom", "toSide": "top", - "route": "straight" + "route": "straight", + "width": 4, + "variant": "default", + "labelAt": [ + 610, + 395 + ] }, { - "id": "flow-1", + "id": "review-canary", "from": "review", "to": "canary", + "label": "", "fromSide": "bottom", "toSide": "top", - "route": "straight" + "route": "straight", + "width": 4, + "variant": "default", + "labelAt": [ + 610, + 765 + ] }, { - "id": "flow-2", + "id": "canary-approve", "from": "canary", "to": "approve", + "label": "", "fromSide": "bottom", "toSide": "top", - "route": "straight" + "route": "straight", + "width": 4, + "variant": "default", + "labelAt": [ + 610, + 1135 + ] }, { - "id": "flow-3", + "id": "approve-publish", "from": "approve", "to": "publish", + "label": "", "fromSide": "bottom", "toSide": "top", - "route": "straight" + "route": "straight", + "width": 4, + "variant": "default", + "labelAt": [ + 610, + 1505 + ] }, { - "id": "flow-4", + "id": "publish-distribute", "from": "publish", "to": "distribute", + "label": "", "fromSide": "bottom", "toSide": "top", - "route": "straight" + "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 + ] } ] -} \ No newline at end of file +} diff --git a/diagrams/strategy-governance.architecture.json b/diagrams/strategy-governance.architecture.json index e3a777f..e726e32 100644 --- a/diagrams/strategy-governance.architecture.json +++ b/diagrams/strategy-governance.architecture.json @@ -7,140 +7,271 @@ "quality_profile": "showcase", "legend": { "mode": "hidden" - } + }, + "viewBox": [ + 1760, + 1420 + ] }, "components": [ { "id": "owner", - "type": "backend", - "label": "Propose a skill", + "type": "external", + "label": "01 Propose", "tag": "Owning team", - "sublabel": "Problem + intended users\nData and authority scope\nSKILL.md + dependencies\nTestable outcome", + "sublabel": "Scope + testable outcome", "pos": [ - 40, - 40 + 80, + 60 ], "size": [ - 560, - 440 - ] + 500, + 170 + ], + "icon": "none" }, { "id": "review", - "type": "security", - "label": "Independent review", + "type": "external", + "label": "02 Review independently", "tag": "Quality + Security", - "sublabel": "Evaluate useful outcomes\nCheck risk boundaries\nAuthor is not sole approver\nRecord revision evidence", + "sublabel": "Author is not sole approver", "pos": [ - 700, - 40 + 300, + 280 ], "size": [ - 560, - 440 - ] + 500, + 170 + ], + "icon": "none" }, { "id": "canary", - "type": "frontend", - "label": "Qualify real use", + "type": "external", + "label": "03 Qualify real use", "tag": "Human + AI Agent", - "sublabel": "Test exact client build\nRun a bounded canary\nInspect work independently\nNo failed mandatory gate", + "sublabel": "Exact client + bounded canary", "pos": [ - 1360, - 40 + 520, + 500 ], "size": [ - 560, - 440 - ] + 500, + 170 + ], + "icon": "none" }, { "id": "approve", - "type": "security", - "label": "Approve exact scope", + "type": "backend", + "label": "04 Approve exact scope", "tag": "Accountable approvers", - "sublabel": "Bind approval to digest\nPermitted uses + expiry\nExceptions cannot bypass\nprotected controls", + "sublabel": "Digest + permitted uses + expiry", "pos": [ - 1360, - 610 + 740, + 720 ], "size": [ - 560, - 440 - ] + 500, + 170 + ], + "icon": "none" }, { "id": "publish", - "type": "database", - "label": "Version the bundle", + "type": "backend", + "label": "05 Publish the bundle", "tag": "Data & AI catalog", - "sublabel": "Pin skill + adapter\nand dependency revisions\nRecord approval evidence\nKeep last-known-good", + "sublabel": "Pin skill, adapter + dependencies", "pos": [ - 700, - 610 + 960, + 940 ], "size": [ - 560, - 440 - ] + 500, + 170 + ], + "icon": "none" }, { "id": "distribute", - "type": "cloud", - "label": "Verify loaded state", + "type": "backend", + "label": "06 Verify loaded state", "tag": "Platform & IT", - "sublabel": "Stage and check digest\nRead effective revision\nTest open-session reload\nRevoke unsafe revisions", + "sublabel": "Read revision; verify reload", "pos": [ - 40, - 610 + 1180, + 1160 ], "size": [ - 560, - 440 - ] + 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", - "fromSide": "right", - "toSide": "left", - "route": "straight" - }, - { - "id": "flow-1", - "from": "review", - "to": "canary", - "fromSide": "right", - "toSide": "left", - "route": "straight" - }, - { - "id": "flow-2", - "from": "canary", - "to": "approve", + "label": "", "fromSide": "bottom", "toSide": "top", - "route": "straight" + "route": "straight", + "width": 4, + "variant": "default", + "via": [ + [ + 330, + 255 + ], + [ + 550, + 255 + ] + ] }, { - "id": "flow-3", + "id": "review-canary", + "from": "review", + "to": "canary", + "label": "", + "fromSide": "bottom", + "toSide": "top", + "route": "straight", + "width": 4, + "variant": "default", + "via": [ + [ + 550, + 475 + ], + [ + 770, + 475 + ] + ] + }, + { + "id": "canary-approve", + "from": "canary", + "to": "approve", + "label": "", + "fromSide": "bottom", + "toSide": "top", + "route": "straight", + "width": 4, + "variant": "default", + "via": [ + [ + 770, + 695 + ], + [ + 990, + 695 + ] + ] + }, + { + "id": "approve-publish", "from": "approve", "to": "publish", - "fromSide": "left", - "toSide": "right", - "route": "straight" + "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": "", + "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" + "route": "straight", + "width": 4, + "variant": "security", + "labelAt": [ + 950, + 1220 + ] } ] -} \ No newline at end of file +} diff --git a/diagrams/strategy-maintenance-mobile.architecture.json b/diagrams/strategy-maintenance-mobile.architecture.json index dc6535e..5b74fa0 100644 --- a/diagrams/strategy-maintenance-mobile.architecture.json +++ b/diagrams/strategy-maintenance-mobile.architecture.json @@ -7,140 +7,332 @@ "quality_profile": "showcase", "legend": { "mode": "hidden" - } + }, + "viewBox": [ + 880, + 3080 + ] }, "components": [ { - "id": "monitor", - "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", + "id": "observe", + "type": "external", + "label": "Observe use", + "tag": "Owner + Data & AI", + "sublabel": "Feedback, drift + review due", "pos": [ - 40, - 40 + 60, + 120 ], "size": [ - 560, - 440 - ] + 740, + 220 + ], + "icon": "none" }, { "id": "triage", - "type": "backend", - "label": "Triage the evidence", - "tag": "Owner + Quality", - "sublabel": "Reproduce the failure\nKeep artifact / client IDs\nAdd sanitized regressions\nAssess business effects", + "type": "external", + "label": "Triage the signal", + "tag": "Owning team", + "sublabel": "Useful? Safe? Still needed?", "pos": [ - 40, - 610 + 60, + 1970 ], "size": [ - 560, - 440 - ] + 740, + 220 + ], + "icon": "none" + }, + { + "id": "change", + "type": "external", + "label": "Change the skill", + "tag": "Reviewed correction", + "sublabel": "New immutable revision", + "pos": [ + 60, + 1230 + ], + "size": [ + 740, + 220 + ], + "icon": "none" + }, + { + "id": "validate", + "type": "external", + "label": "Revalidate", + "tag": "Independent reviewers", + "sublabel": "Regression + client evidence", + "pos": [ + 60, + 860 + ], + "size": [ + 740, + 220 + ], + "icon": "none" + }, + { + "id": "release", + "type": "backend", + "label": "Approve + version", + "tag": "Accountable human authority", + "sublabel": "Verify distribution and recovery", + "pos": [ + 60, + 490 + ], + "size": [ + 740, + 220 + ], + "icon": "none" + }, + { + "id": "safe", + "type": "backend", + "label": "Continue safe use", + "tag": "Substantive review passes", + "sublabel": "Keep owner + next review date", + "pos": [ + 60, + 2710 + ], + "size": [ + 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": "If unsafe: contain", - "tag": "Security + Platform", - "sublabel": "Revoke authority\nQuarantine revision\nRestore known-good bundle\nVerify effective state", + "label": "Contain unsafe use", + "tag": "Security + Platform & IT", + "sublabel": "Revoke + quarantine + roll back\nNo automatic reinstatement", "pos": [ - 40, - 1180 + 60, + 1600 ], "size": [ - 560, - 440 - ] - }, - { - "id": "correct", - "type": "backend", - "label": "Create a new revision", - "tag": "Owning team", - "sublabel": "Correct skill + dependencies\nIndependent tests / review\nRequalify client + model\nNo automatic reinstatement", - "pos": [ - 40, - 1750 + 740, + 220 ], - "size": [ - 560, - 440 - ] - }, - { - "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": [ - 40, - 2320 - ], - "size": [ - 560, - 440 - ] - }, - { - "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": [ - 40, - 2890 - ], - "size": [ - 560, - 440 - ] + "icon": "none" } ], "connections": [ { - "id": "flow-0", - "from": "monitor", + "id": "observe-triage", + "from": "observe", "to": "triage", - "fromSide": "bottom", - "toSide": "top", - "route": "straight" + "label": "", + "fromSide": "left", + "toSide": "left", + "route": "straight", + "width": 4, + "variant": "default", + "via": [ + [ + 20, + 230.0 + ], + [ + 20, + 2080.0 + ] + ], + "labelAt": [ + 620, + 1930 + ] }, { - "id": "flow-1", + "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", - "fromSide": "bottom", - "toSide": "top", - "route": "straight" + "label": "Unsafe", + "fromSide": "top", + "toSide": "bottom", + "route": "straight", + "width": 4, + "variant": "security", + "labelAt": [ + 610, + 1875 + ] }, { - "id": "flow-2", + "id": "contain-change", "from": "contain", - "to": "correct", - "fromSide": "bottom", - "toSide": "top", - "route": "straight" + "to": "change", + "label": "Reviewed fix", + "fromSide": "top", + "toSide": "bottom", + "route": "straight", + "width": 4, + "variant": "security", + "labelAt": [ + 610, + 1505 + ] }, { - "id": "flow-3", - "from": "correct", - "to": "approve", - "fromSide": "bottom", - "toSide": "top", - "route": "straight" - }, - { - "id": "flow-4", - "from": "approve", - "to": "retire", - "fromSide": "bottom", - "toSide": "top", - "route": "straight" + "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 + ] } ] -} \ No newline at end of file +} diff --git a/diagrams/strategy-maintenance.architecture.json b/diagrams/strategy-maintenance.architecture.json index 2ec14d3..bd05b7a 100644 --- a/diagrams/strategy-maintenance.architecture.json +++ b/diagrams/strategy-maintenance.architecture.json @@ -7,140 +7,364 @@ "quality_profile": "showcase", "legend": { "mode": "hidden" - } + }, + "viewBox": [ + 2630, + 1300 + ] }, "components": [ { - "id": "monitor", - "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", + "id": "observe", + "type": "external", + "label": "Observe use", + "tag": "Owner + Data & AI", + "sublabel": "Feedback, drift + review due", "pos": [ - 40, - 40 + 670, + 60 ], "size": [ 560, - 440 - ] + 170 + ], + "icon": "none" }, { "id": "triage", - "type": "backend", - "label": "Triage the evidence", - "tag": "Owner + Quality", - "sublabel": "Reproduce the failure\nKeep artifact / client IDs\nAdd sanitized regressions\nAssess business effects", + "type": "external", + "label": "Triage the signal", + "tag": "Owning team", + "sublabel": "Useful? Safe? Still needed?", "pos": [ - 700, - 40 + 1340, + 330 + ], + "size": [ + 500, + 190 + ], + "icon": "none" + }, + { + "id": "change", + "type": "external", + "label": "Change the skill", + "tag": "Reviewed correction", + "sublabel": "New immutable revision", + "pos": [ + 1240, + 750 + ], + "size": [ + 520, + 180 + ], + "icon": "none" + }, + { + "id": "validate", + "type": "external", + "label": "Revalidate", + "tag": "Independent reviewers", + "sublabel": "Regression + client evidence", + "pos": [ + 560, + 970 ], "size": [ 560, - 440 - ] + 180 + ], + "icon": "none" + }, + { + "id": "release", + "type": "backend", + "label": "Approve + version", + "tag": "Accountable human authority", + "sublabel": "Verify distribution and recovery", + "pos": [ + 70, + 570 + ], + "size": [ + 540, + 180 + ], + "icon": "none" + }, + { + "id": "safe", + "type": "backend", + "label": "Continue safe use", + "tag": "Substantive review passes", + "sublabel": "Keep owner + next review date", + "pos": [ + 2010, + 80 + ], + "size": [ + 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": "If unsafe: contain", - "tag": "Security + Platform", - "sublabel": "Revoke authority\nQuarantine revision\nRestore known-good bundle\nVerify effective state", + "label": "Contain unsafe use", + "tag": "Security + Platform & IT", + "sublabel": "Revoke + quarantine + roll back\nNo automatic reinstatement", "pos": [ - 1360, - 40 + 2010, + 800 ], "size": [ - 560, - 440 - ] - }, - { - "id": "correct", - "type": "backend", - "label": "Create a new revision", - "tag": "Owning team", - "sublabel": "Correct skill + dependencies\nIndependent tests / review\nRequalify client + model\nNo automatic reinstatement", - "pos": [ - 1360, - 610 + 550, + 220 ], - "size": [ - 560, - 440 - ] - }, - { - "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": [ - 700, - 610 - ], - "size": [ - 560, - 440 - ] - }, - { - "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": [ - 40, - 610 - ], - "size": [ - 560, - 440 - ] + "icon": "none" } ], "connections": [ { - "id": "flow-0", - "from": "monitor", + "id": "observe-triage", + "from": "observe", "to": "triage", + "label": "", "fromSide": "right", - "toSide": "left", - "route": "straight" + "toSide": "top", + "route": "straight", + "width": 4, + "variant": "default", + "via": [ + [ + 1590, + 145 + ] + ] }, { - "id": "flow-1", + "id": "triage-change", "from": "triage", - "to": "contain", - "fromSide": "right", - "toSide": "left", - "route": "straight" - }, - { - "id": "flow-2", - "from": "contain", - "to": "correct", + "to": "change", + "label": "Correct", "fromSide": "bottom", "toSide": "top", - "route": "straight" + "route": "straight", + "width": 4, + "variant": "default", + "via": [ + [ + 1590, + 620 + ], + [ + 1500, + 620 + ] + ], + "labelAt": [ + 1450, + 680 + ] }, { - "id": "flow-3", - "from": "correct", - "to": "approve", - "fromSide": "left", + "id": "change-validate", + "from": "change", + "to": "validate", + "label": "", + "fromSide": "bottom", "toSide": "right", - "route": "straight" + "route": "straight", + "width": 4, + "variant": "default", + "via": [ + [ + 1500, + 1060 + ] + ] }, { - "id": "flow-4", - "from": "approve", + "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", - "fromSide": "left", - "toSide": "right", - "route": "straight" + "label": "Retire", + "fromSide": "right", + "toSide": "left", + "route": "straight", + "width": 4, + "variant": "default", + "via": [ + [ + 1950, + 425 + ], + [ + 1950, + 520 + ] + ], + "labelAt": [ + 1900, + 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 + ] } ] -} \ No newline at end of file +} diff --git a/diagrams/strategy-measurement-mobile.architecture.json b/diagrams/strategy-measurement-mobile.architecture.json index 30c2372..b9ac07a 100644 --- a/diagrams/strategy-measurement-mobile.architecture.json +++ b/diagrams/strategy-measurement-mobile.architecture.json @@ -2,104 +2,313 @@ "schema_version": 1, "diagram_type": "architecture", "meta": { - "title": "Recommended collection plan: Measurement", + "title": "TO-BE: Measurement", "output": "static/diagrams/strategy-measurement-mobile/index.html", "quality_profile": "showcase", "legend": { "mode": "hidden" - } + }, + "viewBox": [ + 880, + 3630 + ] }, "components": [ { - "id": "baseline", - "type": "backend", - "label": "Establish baseline", - "tag": "Comparable workflow", - "sublabel": "Join task / PR / CI IDs\nAgree acceptance + window\nRecord revision and client\nKeep unknowns visible", + "id": "success-source", + "type": "external", + "label": "Tracker + acceptance", + "tag": "Matured task starts", + "sublabel": "Join evidence to the workflow", "pos": [ - 40, - 40 + 60, + 120 ], "size": [ - 560, - 440 - ] + 740, + 220 + ], + "icon": "none" }, { "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", + "label": "Accepted / eligible starts \u00d7 100", + "tag": "Task success (%)", + "sublabel": "Failures + unresolved retained", "pos": [ - 40, - 610 + 60, + 490 ], "size": [ - 560, - 440 - ] + 740, + 220 + ], + "icon": "none" + }, + { + "id": "quality-source", + "type": "external", + "label": "Changes + defects", + "tag": "Completed follow-up", + "sublabel": "Join evidence to the workflow", + "pos": [ + 60, + 860 + ], + "size": [ + 740, + 220 + ], + "icon": "none" }, { "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", + "type": "frontend", + "label": "Affected / accepted changes \u00d7 100", + "tag": "Escaped quality (%)", + "sublabel": "Count each affected change once", "pos": [ - 40, - 1180 + 60, + 1230 ], "size": [ - 560, - 440 - ] + 740, + 220 + ], + "icon": "none" + }, + { + "id": "cost-source", + "type": "external", + "label": "Invoices + review minutes", + "tag": "Include failed attempts", + "sublabel": "Join evidence to the workflow", + "pos": [ + 60, + 1600 + ], + "size": [ + 740, + 220 + ], + "icon": "none" }, { "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", + "type": "frontend", + "label": "Allocated cost / accepted tasks", + "tag": "Cost per accepted outcome", + "sublabel": "Missing buckets = partial", "pos": [ - 40, - 1750 + 60, + 1970 ], "size": [ - 560, - 440 - ] + 740, + 220 + ], + "icon": "none" + }, + { + "id": "confidence-source", + "type": "external", + "label": "Anonymous 1\u20135 survey", + "tag": "Protect small groups", + "sublabel": "Join evidence to the workflow", + "pos": [ + 60, + 2340 + ], + "size": [ + 740, + 220 + ], + "icon": "none" }, { "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", + "label": "Confidence sum / valid responses", + "tag": "Verification confidence (1\u20135)", + "sublabel": "Show distribution + response rate", "pos": [ - 40, - 2320 + 60, + 2710 ], "size": [ - 560, - 440 + 740, + 220 + ], + "icon": "none" + }, + { + "id": "interpret", + "type": "backend", + "label": "Compare with baseline", + "tag": "Interpret, then act", + "sublabel": "Like workflows + source coverage\nZero denominator = N/A\nTrends are not causal ROI\nFix gaps; improve the workflow", + "pos": [ + 60, + 3080 + ], + "size": [ + 740, + 400 + ], + "icon": "none" + } + ], + "connections": [ + { + "id": "success-source-success", + "from": "success-source", + "to": "success", + "label": "", + "fromSide": "bottom", + "toSide": "top", + "route": "straight", + "width": 4, + "variant": "default", + "labelAt": [ + 610, + 395 ] }, { - "id": "monitor", - "type": "database", - "label": "Ongoing monitoring", - "tag": "Catalog + cohort report", - "sublabel": "Catalog + cohort records\nTrack support, use, reviews\nCompare with baseline\nShow counts + coverage\nZero denominator = N/A", - "pos": [ - 40, - 2890 + "id": "quality-source-quality", + "from": "quality-source", + "to": "quality", + "label": "", + "fromSide": "bottom", + "toSide": "top", + "route": "straight", + "width": 4, + "variant": "default", + "labelAt": [ + 610, + 1135 + ] + }, + { + "id": "cost-source-cost", + "from": "cost-source", + "to": "cost", + "label": "", + "fromSide": "bottom", + "toSide": "top", + "route": "straight", + "width": 4, + "variant": "default", + "labelAt": [ + 610, + 1875 + ] + }, + { + "id": "confidence-source-confidence", + "from": "confidence-source", + "to": "confidence", + "label": "", + "fromSide": "bottom", + "toSide": "top", + "route": "straight", + "width": 4, + "variant": "default", + "labelAt": [ + 610, + 2615 + ] + }, + { + "id": "success-interpret", + "from": "success", + "to": "interpret", + "label": "", + "fromSide": "right", + "toSide": "right", + "route": "straight", + "width": 4, + "variant": "default", + "via": [ + [ + 850, + 600.0 + ], + [ + 850, + 3280.0 + ] ], - "size": [ - 560, - 440 + "labelAt": [ + 620, + 3040 + ] + }, + { + "id": "quality-interpret", + "from": "quality", + "to": "interpret", + "label": "", + "fromSide": "right", + "toSide": "right", + "route": "straight", + "width": 4, + "variant": "default", + "via": [ + [ + 850, + 1340.0 + ], + [ + 850, + 3280.0 + ] + ], + "labelAt": [ + 620, + 3040 + ] + }, + { + "id": "cost-interpret", + "from": "cost", + "to": "interpret", + "label": "", + "fromSide": "right", + "toSide": "right", + "route": "straight", + "width": 4, + "variant": "default", + "via": [ + [ + 850, + 2080.0 + ], + [ + 850, + 3280.0 + ] + ], + "labelAt": [ + 620, + 3040 + ] + }, + { + "id": "confidence-interpret", + "from": "confidence", + "to": "interpret", + "label": "", + "fromSide": "bottom", + "toSide": "top", + "route": "straight", + "width": 4, + "variant": "default", + "labelAt": [ + 610, + 2985 ] } - ], - "connections": [] -} \ No newline at end of file + ] +} diff --git a/diagrams/strategy-measurement.architecture.json b/diagrams/strategy-measurement.architecture.json index 004ad65..94b227a 100644 --- a/diagrams/strategy-measurement.architecture.json +++ b/diagrams/strategy-measurement.architecture.json @@ -2,104 +2,291 @@ "schema_version": 1, "diagram_type": "architecture", "meta": { - "title": "Recommended collection plan: Measurement", + "title": "TO-BE: Measurement", "output": "static/diagrams/strategy-measurement/index.html", "quality_profile": "showcase", "legend": { "mode": "hidden" - } + }, + "viewBox": [ + 2400, + 1120 + ] }, "components": [ { - "id": "baseline", - "type": "backend", - "label": "Establish baseline", - "tag": "Comparable workflow", - "sublabel": "Join task / PR / CI IDs\nAgree acceptance + window\nRecord revision and client\nKeep unknowns visible", + "id": "success-source", + "type": "external", + "label": "Tracker + acceptance", + "tag": "Matured task starts", + "sublabel": "Join evidence to the workflow", "pos": [ - 40, - 40 + 50, + 70 ], "size": [ - 560, - 440 - ] + 580, + 180 + ], + "icon": "none" }, { "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", + "label": "Accepted / eligible starts \u00d7 100", + "tag": "Task success (%)", + "sublabel": "Failures + unresolved retained", "pos": [ - 700, - 40 + 770, + 70 ], "size": [ - 560, - 440 - ] + 700, + 180 + ], + "icon": "none" + }, + { + "id": "quality-source", + "type": "external", + "label": "Changes + defects", + "tag": "Completed follow-up", + "sublabel": "Join evidence to the workflow", + "pos": [ + 50, + 320 + ], + "size": [ + 580, + 180 + ], + "icon": "none" }, { "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", + "type": "frontend", + "label": "Affected / accepted changes \u00d7 100", + "tag": "Escaped quality (%)", + "sublabel": "Count each affected change once", "pos": [ - 1360, - 40 + 770, + 320 ], "size": [ - 560, - 440 - ] + 700, + 180 + ], + "icon": "none" + }, + { + "id": "cost-source", + "type": "external", + "label": "Invoices + review minutes", + "tag": "Include failed attempts", + "sublabel": "Join evidence to the workflow", + "pos": [ + 50, + 570 + ], + "size": [ + 580, + 180 + ], + "icon": "none" }, { "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", + "type": "frontend", + "label": "Allocated cost / accepted tasks", + "tag": "Cost per accepted outcome", + "sublabel": "Missing buckets = partial", "pos": [ - 1360, - 610 + 770, + 570 ], "size": [ - 560, - 440 - ] + 700, + 180 + ], + "icon": "none" + }, + { + "id": "confidence-source", + "type": "external", + "label": "Anonymous 1\u20135 survey", + "tag": "Protect small groups", + "sublabel": "Join evidence to the workflow", + "pos": [ + 50, + 820 + ], + "size": [ + 580, + 180 + ], + "icon": "none" }, { "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", + "label": "Confidence sum / valid responses", + "tag": "Verification confidence (1\u20135)", + "sublabel": "Show distribution + response rate", "pos": [ - 700, - 610 + 770, + 820 ], "size": [ - 560, - 440 + 700, + 180 + ], + "icon": "none" + }, + { + "id": "interpret", + "type": "backend", + "label": "Compare with baseline", + "tag": "Interpret, then act", + "sublabel": "Like workflows + source coverage\nZero denominator = N/A\nTrends are not causal ROI\nFix gaps; improve the workflow", + "pos": [ + 1650, + 325 + ], + "size": [ + 680, + 400 + ], + "icon": "none" + } + ], + "connections": [ + { + "id": "success-source-success", + "from": "success-source", + "to": "success", + "label": "", + "fromSide": "right", + "toSide": "left", + "route": "straight", + "width": 4, + "variant": "default" + }, + { + "id": "quality-source-quality", + "from": "quality-source", + "to": "quality", + "label": "", + "fromSide": "right", + "toSide": "left", + "route": "straight", + "width": 4, + "variant": "default" + }, + { + "id": "cost-source-cost", + "from": "cost-source", + "to": "cost", + "label": "", + "fromSide": "right", + "toSide": "left", + "route": "straight", + "width": 4, + "variant": "default" + }, + { + "id": "confidence-source-confidence", + "from": "confidence-source", + "to": "confidence", + "label": "", + "fromSide": "right", + "toSide": "left", + "route": "straight", + "width": 4, + "variant": "default" + }, + { + "id": "success-interpret", + "from": "success", + "to": "interpret", + "label": "", + "fromSide": "right", + "toSide": "left", + "route": "straight", + "width": 4, + "variant": "default", + "via": [ + [ + 1550, + 160 + ], + [ + 1550, + 525 + ] ] }, { - "id": "monitor", - "type": "database", - "label": "Ongoing monitoring", - "tag": "Catalog + cohort report", - "sublabel": "Catalog + cohort records\nTrack support, use, reviews\nCompare with baseline\nShow counts + coverage\nZero denominator = N/A", - "pos": [ - 40, - 610 - ], - "size": [ - 560, - 440 + "id": "quality-interpret", + "from": "quality", + "to": "interpret", + "label": "", + "fromSide": "right", + "toSide": "left", + "route": "straight", + "width": 4, + "variant": "default", + "via": [ + [ + 1550, + 410 + ], + [ + 1550, + 525 + ] + ] + }, + { + "id": "cost-interpret", + "from": "cost", + "to": "interpret", + "label": "", + "fromSide": "right", + "toSide": "left", + "route": "straight", + "width": 4, + "variant": "default", + "via": [ + [ + 1550, + 660 + ], + [ + 1550, + 525 + ] + ] + }, + { + "id": "confidence-interpret", + "from": "confidence", + "to": "interpret", + "label": "", + "fromSide": "right", + "toSide": "left", + "route": "straight", + "width": 4, + "variant": "default", + "via": [ + [ + 1550, + 910 + ], + [ + 1550, + 525 + ] ] } - ], - "connections": [] -} \ No newline at end of file + ] +} diff --git a/diagrams/strategy-quality-mobile.architecture.json b/diagrams/strategy-quality-mobile.architecture.json index d6c2cb9..a2a6d22 100644 --- a/diagrams/strategy-quality-mobile.architecture.json +++ b/diagrams/strategy-quality-mobile.architecture.json @@ -7,140 +7,256 @@ "quality_profile": "showcase", "legend": { "mode": "hidden" - } + }, + "viewBox": [ + 880, + 2800 + ] }, "components": [ { - "id": "risk", - "type": "security", - "label": "Define the envelope", - "tag": "Owner + reviewers", - "sublabel": "R1: nonsensitive drafting\nR2: code / customer work\nR3: human-authorized\nAgree acceptance rules", + "id": "selection", + "type": "external", + "label": "Right skill?", + "tag": "Selection evidence", + "sublabel": "Triggers, near misses, negatives", "pos": [ - 40, - 40 + 60, + 120 ], "size": [ - 560, - 440 - ] + 740, + 220 + ], + "icon": "none" }, { - "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", + "id": "safety", + "type": "external", + "label": "Safe execution?", + "tag": "Safety evidence", + "sublabel": "Permissions + adversarial trials", "pos": [ - 40, - 610 + 60, + 490 ], "size": [ - 560, - 440 - ] + 740, + 220 + ], + "icon": "none" }, { - "id": "inspect", - "type": "frontend", - "label": "Inspect the outcome", - "tag": "Independent evidence", - "sublabel": "Right skill selected?\nProcedure safe?\nArtifact checks pass?\nUseful workflow result?", + "id": "artifact", + "type": "external", + "label": "Valid artifact?", + "tag": "Independent inspection", + "sublabel": "Tests + human assessment", "pos": [ - 40, - 1180 + 60, + 860 ], "size": [ - 560, - 440 - ] + 740, + 220 + ], + "icon": "none" + }, + { + "id": "outcome", + "type": "external", + "label": "Useful outcome?", + "tag": "Workflow evidence", + "sublabel": "Baseline + repeated trials", + "pos": [ + 60, + 1230 + ], + "size": [ + 740, + 220 + ], + "icon": "none" }, { "id": "gate", "type": "security", "label": "Every gate must pass", - "tag": "Quality Engineering", - "sublabel": "Safety + authorization\nSchema + provenance\nCritical effect blocks\nMissing coverage blocks", + "tag": "Risk sets evaluation depth", + "sublabel": "No averaging away harm\nCritical effect blocks promotion\nMissing coverage = incomplete", "pos": [ - 40, - 1750 + 60, + 1600 ], "size": [ - 560, - 440 - ] + 740, + 310 + ], + "icon": "none" }, { - "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", + "id": "accept", + "type": "backend", + "label": "Accept evidence", + "tag": "All mandatory gates passed", + "sublabel": "Proceed to scoped approval", "pos": [ - 40, - 2320 + 60, + 2060 ], "size": [ - 560, - 440 - ] + 740, + 220 + ], + "icon": "none" }, { - "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", + "id": "rework", + "type": "security", + "label": "Rework / retest", + "tag": "Any failure or missing evidence", + "sublabel": "Keep failures in the record", "pos": [ - 40, - 2890 + 60, + 2430 ], "size": [ - 560, - 440 - ] + 740, + 220 + ], + "icon": "none" } ], "connections": [ { - "id": "flow-0", - "from": "risk", - "to": "compare", - "fromSide": "bottom", - "toSide": "top", - "route": "straight" - }, - { - "id": "flow-1", - "from": "compare", - "to": "inspect", - "fromSide": "bottom", - "toSide": "top", - "route": "straight" - }, - { - "id": "flow-2", - "from": "inspect", + "id": "selection-gate", + "from": "selection", "to": "gate", - "fromSide": "bottom", - "toSide": "top", - "route": "straight" + "label": "", + "fromSide": "right", + "toSide": "right", + "route": "straight", + "width": 4, + "variant": "default", + "via": [ + [ + 850, + 230.0 + ], + [ + 850, + 1755.0 + ] + ], + "labelAt": [ + 620, + 1560 + ] }, { - "id": "flow-3", + "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": "canary", + "to": "accept", + "label": "Pass", "fromSide": "bottom", "toSide": "top", - "route": "straight" + "route": "straight", + "width": 4, + "variant": "default", + "labelAt": [ + 610, + 1965 + ] }, { - "id": "flow-4", - "from": "canary", - "to": "improve", - "fromSide": "bottom", - "toSide": "top", - "route": "straight" + "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 + ] } ] -} \ No newline at end of file +} diff --git a/diagrams/strategy-quality.architecture.json b/diagrams/strategy-quality.architecture.json index 7084adc..29ffb4d 100644 --- a/diagrams/strategy-quality.architecture.json +++ b/diagrams/strategy-quality.architecture.json @@ -7,140 +7,260 @@ "quality_profile": "showcase", "legend": { "mode": "hidden" - } + }, + "viewBox": [ + 2000, + 1050 + ] }, "components": [ { - "id": "risk", - "type": "security", - "label": "Define the envelope", - "tag": "Owner + reviewers", - "sublabel": "R1: nonsensitive drafting\nR2: code / customer work\nR3: human-authorized\nAgree acceptance rules", + "id": "selection", + "type": "external", + "label": "Right skill?", + "tag": "Selection evidence", + "sublabel": "Triggers, near misses, negatives", "pos": [ - 40, - 40 + 60, + 70 ], "size": [ - 560, - 440 - ] + 510, + 170 + ], + "icon": "none" }, { - "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", + "id": "safety", + "type": "external", + "label": "Safe execution?", + "tag": "Safety evidence", + "sublabel": "Permissions + adversarial trials", "pos": [ - 700, - 40 + 60, + 310 ], "size": [ - 560, - 440 - ] + 510, + 170 + ], + "icon": "none" }, { - "id": "inspect", - "type": "frontend", - "label": "Inspect the outcome", - "tag": "Independent evidence", - "sublabel": "Right skill selected?\nProcedure safe?\nArtifact checks pass?\nUseful workflow result?", + "id": "artifact", + "type": "external", + "label": "Valid artifact?", + "tag": "Independent inspection", + "sublabel": "Tests + human assessment", "pos": [ - 1360, - 40 + 60, + 550 ], "size": [ - 560, - 440 - ] + 510, + 170 + ], + "icon": "none" + }, + { + "id": "outcome", + "type": "external", + "label": "Useful outcome?", + "tag": "Workflow evidence", + "sublabel": "Baseline + repeated trials", + "pos": [ + 60, + 790 + ], + "size": [ + 510, + 170 + ], + "icon": "none" }, { "id": "gate", "type": "security", "label": "Every gate must pass", - "tag": "Quality Engineering", - "sublabel": "Safety + authorization\nSchema + provenance\nCritical effect blocks\nMissing coverage blocks", + "tag": "Risk sets evaluation depth", + "sublabel": "No averaging away harm\nCritical effect blocks promotion\nMissing coverage = incomplete", "pos": [ - 1360, - 610 + 740, + 350 ], "size": [ - 560, - 440 - ] + 520, + 310 + ], + "icon": "none" }, { - "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", + "id": "accept", + "type": "backend", + "label": "Accept evidence", + "tag": "All mandatory gates passed", + "sublabel": "Proceed to scoped approval", "pos": [ - 700, - 610 + 1430, + 160 ], "size": [ - 560, - 440 - ] + 510, + 190 + ], + "icon": "none" }, { - "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", + "id": "rework", + "type": "security", + "label": "Rework / retest", + "tag": "Any failure or missing evidence", + "sublabel": "Keep failures in the record", "pos": [ - 40, - 610 + 1430, + 760 ], "size": [ - 560, - 440 - ] + 510, + 190 + ], + "icon": "none" } ], "connections": [ { - "id": "flow-0", - "from": "risk", - "to": "compare", - "fromSide": "right", - "toSide": "left", - "route": "straight" - }, - { - "id": "flow-1", - "from": "compare", - "to": "inspect", - "fromSide": "right", - "toSide": "left", - "route": "straight" - }, - { - "id": "flow-2", - "from": "inspect", + "id": "selection-gate", + "from": "selection", "to": "gate", - "fromSide": "bottom", - "toSide": "top", - "route": "straight" + "label": "", + "fromSide": "right", + "toSide": "left", + "route": "straight", + "width": 4, + "variant": "default", + "via": [ + [ + 650, + 155 + ], + [ + 650, + 505 + ] + ] }, { - "id": "flow-3", + "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": "canary", - "fromSide": "left", - "toSide": "right", - "route": "straight" + "to": "accept", + "label": "Pass", + "fromSide": "right", + "toSide": "left", + "route": "straight", + "width": 4, + "variant": "default", + "via": [ + [ + 1340, + 505 + ], + [ + 1340, + 255 + ] + ], + "labelAt": [ + 1330, + 210 + ] }, { - "id": "flow-4", - "from": "canary", - "to": "improve", - "fromSide": "left", - "toSide": "right", - "route": "straight" + "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 + ] } ] -} \ No newline at end of file +} diff --git a/scripts/browser/skills-exports.cjs b/scripts/browser/skills-exports.cjs new file mode 100644 index 0000000..4f34cc3 --- /dev/null +++ b/scripts/browser/skills-exports.cjs @@ -0,0 +1,42 @@ +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 ['governance','quality','adoption','measurement','maintenance']) 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.xv.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=[]; + for(let i=0;iMath.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,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`); + 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.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}); diff --git a/scripts/browser/skills-measurement.cjs b/scripts/browser/skills-measurement.cjs index 400e323..67ef003 100644 --- a/scripts/browser/skills-measurement.cjs +++ b/scripts/browser/skills-measurement.cjs @@ -33,7 +33,7 @@ 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(); @@ -50,7 +50,7 @@ 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('Compare with baseline') && svg.includes('Zero denominator = N/A')); const opener = panel.getByRole('button', {name:/^Expand /}); await opener.click(); const close = panel.getByRole('button', {name:'Close full-screen diagram', exact:true}); diff --git a/scripts/browser/skills-stories.cjs b/scripts/browser/skills-stories.cjs index 43d8355..3440212 100644 --- a/scripts/browser/skills-stories.cjs +++ b/scripts/browser/skills-stories.cjs @@ -11,7 +11,7 @@ const assert=require('node:assert/strict'); 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 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(); const geometry=await frame.locator('svg[role="img"]').evaluate(svg=>{ const nodes=[...svg.querySelectorAll('g[data-node-id]')];const issues=[];let min=Infinity; @@ -21,14 +21,15 @@ const assert=require('node:assert/strict'); }} 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)); + 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']){ 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}/`)); + 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)); diff --git a/scripts/browser/strategy-story.cjs b/scripts/browser/strategy-story.cjs index 1151540..57547da 100644 --- a/scripts/browser/strategy-story.cjs +++ b/scripts/browser/strategy-story.cjs @@ -19,7 +19,9 @@ const fs=require('node:fs'); 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>=(id==='roadmap'?2: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); diff --git a/scripts/skills-stories.test.mjs b/scripts/skills-stories.test.mjs index 6b672c9..b0f2109 100644 --- a/scripts/skills-stories.test.mjs +++ b/scripts/skills-stories.test.mjs @@ -21,28 +21,40 @@ for(const topic of topics) test(`${topic}: rich native source, wide desktop, mob 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(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.split('\n').length>=4);} + 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(/]*data-node-id=/g)||[]).length,6); + assert.equal((html.match(/]*data-node-id=/g)||[]).length,desktop.components.length); assert.equal((html.match(/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)); + 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=>read(`diagrams/strategy-${t}.architecture.json`); + 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 ['Tracker:','Invoices + review minutes','linked defect records','Anonymous 1–5 survey','Missing buckets = partial','Zero denominator = N/A'])assert(text('measurement').includes(marker),marker); + for(const marker of ['Tracker + acceptance','Invoices + review minutes','Changes + defects','Anonymous 1–5 survey','Missing buckets = partial','Zero denominator = N/A'])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;isteps[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 id of ['success','quality','cost','confidence']){has(m,id+'-source',id);has(m,id,'interpret');} + 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); +}); diff --git a/scripts/skills-viewer.mjs b/scripts/skills-viewer.mjs index 4af5978..6cec6c5 100644 --- a/scripts/skills-viewer.mjs +++ b/scripts/skills-viewer.mjs @@ -1,8 +1,9 @@ -// Keep native geometry, metadata, routing and exports; enrich only typography. +// Native editable geometry and edges; scoped editorial typography for Stage 01. 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'); + if (spec.diagram_type !== 'architecture' || !spec.components.length) throw new Error('Skills story contract drift'); + const detailSize = spec.meta.output.includes('-mobile/') ? 34 : 32; for (const node of spec.components) { const pattern = new RegExp(`]*data-node-id="${node.id}"[^>]*>[\\s\\S]*?`); const match = html.match(pattern); @@ -12,24 +13,32 @@ export function skillsViewer(html, spec) { 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}`); + if (!node.tag || !node.sublabel || lines.length > 4) throw new Error(`Skills copy exceeds capacity: ${node.id}`); const text = (value, top, size, attrs) => `${escape(value)}`; - 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 content = text(node.tag, 40, detailSize, 'class="t-muted" data-detail="context"') + + text(node.label, 89, 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+''); } const roots = [...html.matchAll(/]*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 [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+``); + // Native labels use tiny technical annotations. Enlarge both text and mask, + // retaining the native edge identity, routing and explicit label position. + html = html.replace(/(]*data-edge-id[^>]*>)([\s\S]*?)(<\/g>)/g, (all,open,body,close) => { + const text = body.match(/]*)>([\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+``+text[0].replace('font-size="8"',`font-size="${detailSize}"`)+close; + }); return html; } diff --git a/scripts/strategy-story.test.mjs b/scripts/strategy-story.test.mjs index 17875f8..4c17555 100644 --- a/scripts/strategy-story.test.mjs +++ b/scripts/strategy-story.test.mjs @@ -35,10 +35,10 @@ test('mobile story diagrams preserve the same nodes and directed relationships', } 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); + 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-') || /^strategy-(governance|quality|adoption|maintenance)$/.test(name)) && 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'); } }); diff --git a/src/components/ArchifyDiagram/index.tsx b/src/components/ArchifyDiagram/index.tsx index 3ae27f1..ff3600e 100644 --- a/src/components/ArchifyDiagram/index.tsx +++ b/src/components/ArchifyDiagram/index.tsx @@ -15,7 +15,7 @@ export default function ArchifyDiagram({name, title, compact = false, story = fa const skillsStory = /^strategy-(governance|quality|adoption|measurement|maintenance)$/.test(name); useEffect(() => { if (!name.startsWith('strategy-roadmap') && !skillsStory) return; - const media = window.matchMedia(skillsStory ? '(max-width: 700px)' : '(max-width: 999px)'); + const media = window.matchMedia(skillsStory ? '(max-width: 1100px)' : '(max-width: 999px)'); const update = () => setNarrowRoadmap(media.matches); update(); media.addEventListener('change', update); diff --git a/src/css/custom.css b/src/css/custom.css index 912c9b2..1f13bac 100644 --- a/src/css/custom.css +++ b/src/css/custom.css @@ -116,8 +116,7 @@ a:focus-visible, button:focus-visible {outline: 3px solid #b88719; outline-offse .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;} @@ -127,8 +126,7 @@ a:focus-visible, button:focus-visible {outline: 3px solid #b88719; outline-offse .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-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. */ @@ -156,13 +154,16 @@ a:focus-visible, button:focus-visible {outline: 3px solid #b88719; outline-offse /* 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 {--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 / 3900;} +.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: 1900px; min-height: 1900px;} + .archify-panel--skills .archify-modal iframe {flex: none; height: auto; min-height: 0; aspect-ratio: var(--skills-narrow); max-width: 600px; margin-inline: auto;} }