Compare commits

...
Author SHA1 Message Date
jarvis-at-skic 1057433c2a docs: center Target lifecycle on autonomous agent
Build and publish Eldorado documentation / build (pull_request) Successful in 41s
2026-10-05 17:23:56 +00:00
jarvis-at-skic 504d9f8845 Merge pull request 'docs: lead Strategy with autonomous SDLC cycle' (#18) from docs/autonomous-sdlc-cycle into main
Build and publish Eldorado documentation / build (push) Successful in 42s
2026-10-05 09:34:42 -07:00
12 changed files with 185 additions and 66 deletions

No files matched your search

@@ -3,25 +3,50 @@
"diagram_type": "architecture", "diagram_type": "architecture",
"meta": {"title": "TO-BE: autonomous SDLC, human direction", "output": "static/diagrams/strategy-target-mobile/index.html", "quality_profile": "showcase", "legend": {"mode": "hidden"}}, "meta": {"title": "TO-BE: autonomous SDLC, human direction", "output": "static/diagrams/strategy-target-mobile/index.html", "quality_profile": "showcase", "legend": {"mode": "hidden"}},
"components": [ "components": [
{"id": "humans", "type": "backend", "label": "Humans", "sublabel": "Direct, guide and review", "pos": [20, 20], "size": [240, 80]}, {"id":"humans","type":"backend","label":"Humans","sublabel":"Direct, guide and review","pos":[140,20],"size":[360,100]},
{"id": "agent", "type": "security", "label": "Autonomous agent", "sublabel": "Executes and governs SDLC", "pos": [20, 180], "size": [240, 80]}, {"id":"agent","type":"security","label":"Autonomous agent","sublabel":"Executes / governs SDLC","pos":[140,200],"size":[360,120]},
{"id": "scope", "type": "backend", "label": "Scope", "sublabel": "01", "pos": [20, 340], "size": [240, 80]}, {"id":"scope","type":"backend","label":"Scope","sublabel":"01","pos":[100,440],"size":[240,100]},
{"id": "architecture", "type": "backend", "label": "Architecture", "sublabel": "02", "pos": [20, 500], "size": [240, 80]}, {"id":"architecture","type":"backend","label":"Architecture","sublabel":"02","pos":[100,660],"size":[240,100]},
{"id": "ui-ux", "type": "backend", "label": "UI/UX", "sublabel": "03", "pos": [20, 660], "size": [240, 80]}, {"id":"ui-ux","type":"backend","label":"UI/UX","sublabel":"03","pos":[100,880],"size":[240,100]},
{"id": "planning", "type": "backend", "label": "Planning", "sublabel": "04", "pos": [20, 820], "size": [240, 80]}, {"id":"planning","type":"backend","label":"Planning","sublabel":"04","pos":[100,1100],"size":[240,100]},
{"id": "delivery", "type": "backend", "label": "Delivery", "sublabel": "05", "pos": [20, 980], "size": [240, 80]}, {"id":"delivery","type":"backend","label":"Delivery","sublabel":"05","pos":[100,1320],"size":[240,100]},
{"id": "uat", "type": "backend", "label": "UAT", "sublabel": "06", "pos": [20, 1140], "size": [240, 80]}, {"id":"uat","type":"backend","label":"UAT","sublabel":"06","pos":[100,1540],"size":[240,100]},
{"id": "releases", "type": "backend", "label": "Releases", "sublabel": "07", "pos": [20, 1300], "size": [240, 80]} {"id":"security","type":"backend","label":"Security","sublabel":"07","pos":[100,1760],"size":[240,100]},
{"id":"releases","type":"backend","label":"Releases","sublabel":"08","pos":[100,1980],"size":[240,100]},
{"id":"code-scope","type":"frontend","label":"Code agent","sublabel":"Human-controlled","pos":[400,440],"size":[240,100]},
{"id":"code-architecture","type":"frontend","label":"Code agent","sublabel":"Human-controlled","pos":[400,660],"size":[240,100]},
{"id":"code-ui-ux","type":"frontend","label":"Code agent","sublabel":"Human-controlled","pos":[400,880],"size":[240,100]},
{"id":"code-planning","type":"frontend","label":"Code agent","sublabel":"Human-controlled","pos":[400,1100],"size":[240,100]},
{"id":"code-delivery","type":"frontend","label":"Code agent","sublabel":"Human-controlled","pos":[400,1320],"size":[240,100]},
{"id":"code-uat","type":"frontend","label":"Code agent","sublabel":"Human-controlled","pos":[400,1540],"size":[240,100]},
{"id":"code-security","type":"frontend","label":"Code agent","sublabel":"Human-controlled","pos":[400,1760],"size":[240,100]},
{"id":"code-releases","type":"frontend","label":"Code agent","sublabel":"Human-controlled","pos":[400,1980],"size":[240,100]}
], ],
"connections": [ "connections": [
{"id":"human-direction","from":"humans","to":"agent","label":"Guide","fromSide":"bottom","toSide":"top"}, {"id":"human-direction","from":"humans","to":"agent","label":"Guide","fromSide":"bottom","toSide":"top"},
{"id": "agent-lifecycle", "from": "agent", "to": "scope", "label": "Entire cycle", "fromSide": "bottom", "toSide": "top"}, {"id":"govern-scope","from":"agent","to":"scope","label":"","variant":"security","fromSide":"left","toSide":"left","via":[[60,260],[60,490]]},
{"id": "stage-1", "from": "scope", "to": "architecture", "label": "Then", "fromSide": "bottom", "toSide": "top"}, {"id":"govern-architecture","from":"agent","to":"architecture","label":"","variant":"security","fromSide":"left","toSide":"left","via":[[60,260],[60,710]]},
{"id": "stage-2", "from": "architecture", "to": "ui-ux", "label": "Then", "fromSide": "bottom", "toSide": "top"}, {"id":"govern-ui-ux","from":"agent","to":"ui-ux","label":"","variant":"security","fromSide":"left","toSide":"left","via":[[60,260],[60,930]]},
{"id": "stage-3", "from": "ui-ux", "to": "planning", "label": "Then", "fromSide": "bottom", "toSide": "top"}, {"id":"govern-planning","from":"agent","to":"planning","label":"","variant":"security","fromSide":"left","toSide":"left","via":[[60,260],[60,1150]]},
{"id": "stage-4", "from": "planning", "to": "delivery", "label": "Then", "fromSide": "bottom", "toSide": "top"}, {"id":"govern-delivery","from":"agent","to":"delivery","label":"","variant":"security","fromSide":"left","toSide":"left","via":[[60,260],[60,1370]]},
{"id": "stage-5", "from": "delivery", "to": "uat", "label": "Then", "fromSide": "bottom", "toSide": "top"}, {"id":"govern-uat","from":"agent","to":"uat","label":"","variant":"security","fromSide":"left","toSide":"left","via":[[60,260],[60,1590]]},
{"id": "stage-6", "from": "uat", "to": "releases", "label": "Then", "fromSide": "bottom", "toSide": "top"}, {"id":"govern-security","from":"agent","to":"security","label":"","variant":"security","fromSide":"left","toSide":"left","via":[[60,260],[60,1810]]},
{"id": "stage-7", "from": "releases", "to": "scope", "label": "Repeat indefinitely", "fromSide": "right", "toSide": "right", "via": [[300, 1340], [300, 380]], "labelAt": [180, 1430]} {"id":"govern-releases","from":"agent","to":"releases","label":"","variant":"security","fromSide":"left","toSide":"left","via":[[60,260],[60,2030]]},
{"id":"stage-1","from":"scope","to":"architecture","label":"Then","variant":"emphasis","fromSide":"bottom","toSide":"top"},
{"id":"stage-2","from":"architecture","to":"ui-ux","label":"Then","variant":"emphasis","fromSide":"bottom","toSide":"top"},
{"id":"stage-3","from":"ui-ux","to":"planning","label":"Then","variant":"emphasis","fromSide":"bottom","toSide":"top"},
{"id":"stage-4","from":"planning","to":"delivery","label":"Then","variant":"emphasis","fromSide":"bottom","toSide":"top"},
{"id":"stage-5","from":"delivery","to":"uat","label":"Then","variant":"emphasis","fromSide":"bottom","toSide":"top"},
{"id":"stage-6","from":"uat","to":"security","label":"Then","variant":"emphasis","fromSide":"bottom","toSide":"top"},
{"id":"stage-7","from":"security","to":"releases","label":"Then","variant":"emphasis","fromSide":"bottom","toSide":"top"},
{"id":"stage-8","from":"releases","to":"scope","label":"Repeat indefinitely","variant":"emphasis","fromSide":"bottom","toSide":"top","via":[[220,2140],[680,2140],[680,380],[220,380]],"labelAt":[440,2180]},
{"id":"contribute-scope","from":"code-scope","to":"scope","label":"Contribute","variant":"dashed","fromSide":"left","toSide":"right"},
{"id":"contribute-architecture","from":"code-architecture","to":"architecture","label":"Contribute","variant":"dashed","fromSide":"left","toSide":"right"},
{"id":"contribute-ui-ux","from":"code-ui-ux","to":"ui-ux","label":"Contribute","variant":"dashed","fromSide":"left","toSide":"right"},
{"id":"contribute-planning","from":"code-planning","to":"planning","label":"Contribute","variant":"dashed","fromSide":"left","toSide":"right"},
{"id":"contribute-delivery","from":"code-delivery","to":"delivery","label":"Contribute","variant":"dashed","fromSide":"left","toSide":"right"},
{"id":"contribute-uat","from":"code-uat","to":"uat","label":"Contribute","variant":"dashed","fromSide":"left","toSide":"right"},
{"id":"contribute-security","from":"code-security","to":"security","label":"Contribute","variant":"dashed","fromSide":"left","toSide":"right"},
{"id":"contribute-releases","from":"code-releases","to":"releases","label":"Contribute","variant":"dashed","fromSide":"left","toSide":"right"}
] ]
} }
+43 -18
View File
@@ -3,25 +3,50 @@
"diagram_type": "architecture", "diagram_type": "architecture",
"meta": {"title": "TO-BE: autonomous SDLC, human direction", "output": "static/diagrams/strategy-target/index.html", "quality_profile": "showcase", "legend": {"mode": "hidden"}}, "meta": {"title": "TO-BE: autonomous SDLC, human direction", "output": "static/diagrams/strategy-target/index.html", "quality_profile": "showcase", "legend": {"mode": "hidden"}},
"components": [ "components": [
{"id": "humans", "type": "backend", "label": "Humans", "sublabel": "Direct, guide and review", "pos": [40, 20], "size": [240, 80]}, {"id":"humans","type":"backend","label":"Humans","sublabel":"Direct, guide and review","pos":[465,322.5],"size":[270,75]},
{"id": "agent", "type": "security", "label": "Autonomous agent", "sublabel": "Executes and governs SDLC", "pos": [360, 20], "size": [240, 80]}, {"id":"agent","type":"security","label":"Autonomous agent","sublabel":"Executes / governs SDLC","pos":[465,450],"size":[270,90]},
{"id": "scope", "type": "backend", "label": "Scope", "sublabel": "01", "pos": [40, 220], "size": [240, 80]}, {"id":"scope","type":"backend","label":"Scope","sublabel":"01","pos":[510,187.5],"size":[180,75]},
{"id": "architecture", "type": "backend", "label": "Architecture", "sublabel": "02", "pos": [360, 220], "size": [240, 80]}, {"id":"architecture","type":"backend","label":"Architecture","sublabel":"02","pos":[780,187.5],"size":[180,75]},
{"id": "ui-ux", "type": "backend", "label": "UI/UX", "sublabel": "03", "pos": [680, 220], "size": [240, 80]}, {"id":"ui-ux","type":"backend","label":"UI/UX","sublabel":"03","pos":[780,457.5],"size":[180,75]},
{"id": "planning", "type": "backend", "label": "Planning", "sublabel": "04", "pos": [680, 380], "size": [240, 80]}, {"id":"planning","type":"backend","label":"Planning","sublabel":"04","pos":[780,727.5],"size":[180,75]},
{"id": "delivery", "type": "backend", "label": "Delivery", "sublabel": "05", "pos": [680, 540], "size": [240, 80]}, {"id":"delivery","type":"backend","label":"Delivery","sublabel":"05","pos":[510,727.5],"size":[180,75]},
{"id": "uat", "type": "backend", "label": "UAT", "sublabel": "06", "pos": [360, 540], "size": [240, 80]}, {"id":"uat","type":"backend","label":"UAT","sublabel":"06","pos":[240,727.5],"size":[180,75]},
{"id": "releases", "type": "backend", "label": "Releases", "sublabel": "07", "pos": [40, 540], "size": [240, 80]} {"id":"security","type":"backend","label":"Security","sublabel":"07","pos":[240,457.5],"size":[180,75]},
{"id":"releases","type":"backend","label":"Releases","sublabel":"08","pos":[240,187.5],"size":[180,75]},
{"id":"code-scope","type":"frontend","label":"Code agent","sublabel":"Human-controlled","pos":[510,37.5],"size":[180,75]},
{"id":"code-architecture","type":"frontend","label":"Code agent","sublabel":"Human-controlled","pos":[780,37.5],"size":[180,75]},
{"id":"code-ui-ux","type":"frontend","label":"Code agent","sublabel":"Human-controlled","pos":[1005,457.5],"size":[180,75]},
{"id":"code-planning","type":"frontend","label":"Code agent","sublabel":"Human-controlled","pos":[780,877.5],"size":[180,75]},
{"id":"code-delivery","type":"frontend","label":"Code agent","sublabel":"Human-controlled","pos":[510,877.5],"size":[180,75]},
{"id":"code-uat","type":"frontend","label":"Code agent","sublabel":"Human-controlled","pos":[240,877.5],"size":[180,75]},
{"id":"code-security","type":"frontend","label":"Code agent","sublabel":"Human-controlled","pos":[15,457.5],"size":[180,75]},
{"id":"code-releases","type":"frontend","label":"Code agent","sublabel":"Human-controlled","pos":[240,37.5],"size":[180,75]}
], ],
"connections": [ "connections": [
{"id": "human-direction", "from": "humans", "to": "agent", "label": "Guide", "fromSide": "right", "toSide": "left"}, {"id":"human-direction","from":"humans","to":"agent","label":"Guide","fromSide":"bottom","toSide":"top"},
{"id": "agent-lifecycle", "from": "agent", "to": "scope", "label": "Entire cycle", "fromSide": "bottom", "toSide": "top", "via": [[480, 160], [160, 160]], "labelAt": [320, 145]}, {"id":"govern-scope","from":"agent","to":"scope","label":"","variant":"security","fromSide":"right","toSide":"bottom","via":[[750,495],[750,292.5],[600,292.5]]},
{"id": "stage-1", "from": "scope", "to": "architecture", "label": "Then", "fromSide": "right", "toSide": "left"}, {"id":"govern-architecture","from":"agent","to":"architecture","label":"","variant":"security","fromSide":"right","toSide":"bottom","via":[[765,495],[765,345],[870,345]]},
{"id": "stage-2", "from": "architecture", "to": "ui-ux", "label": "Then", "fromSide": "right", "toSide": "left"}, {"id":"govern-ui-ux","from":"agent","to":"ui-ux","label":"","variant":"security","fromSide":"right","toSide":"left"},
{"id": "stage-3", "from": "ui-ux", "to": "planning", "label": "Then", "fromSide": "bottom", "toSide": "top"}, {"id":"govern-planning","from":"agent","to":"planning","label":"","variant":"security","fromSide":"right","toSide":"top","via":[[765,495],[765,690],[870,690]]},
{"id": "stage-4", "from": "planning", "to": "delivery", "label": "Then", "fromSide": "bottom", "toSide": "top"}, {"id":"govern-delivery","from":"agent","to":"delivery","label":"","variant":"security","fromSide":"bottom","toSide":"top"},
{"id": "stage-5", "from": "delivery", "to": "uat", "label": "Then", "fromSide": "left", "toSide": "right"}, {"id":"govern-uat","from":"agent","to":"uat","label":"","variant":"security","fromSide":"left","toSide":"top","via":[[435,495],[435,690],[330,690]]},
{"id": "stage-6", "from": "uat", "to": "releases", "label": "Then", "fromSide": "left", "toSide": "right"}, {"id":"govern-security","from":"agent","to":"security","label":"","variant":"security","fromSide":"left","toSide":"right"},
{"id": "stage-7", "from": "releases", "to": "scope", "label": "Repeat indefinitely", "fromSide": "top", "toSide": "bottom", "via": [[160, 460], [160, 380]], "labelAt": [260, 420]} {"id":"govern-releases","from":"agent","to":"releases","label":"","variant":"security","fromSide":"left","toSide":"bottom","via":[[435,495],[435,345],[330,345]]},
{"id":"stage-1","from":"scope","to":"architecture","label":"Then","variant":"emphasis","fromSide":"right","toSide":"left"},
{"id":"stage-2","from":"architecture","to":"ui-ux","label":"Then","variant":"emphasis","fromSide":"bottom","toSide":"top"},
{"id":"stage-3","from":"ui-ux","to":"planning","label":"Then","variant":"emphasis","fromSide":"bottom","toSide":"top"},
{"id":"stage-4","from":"planning","to":"delivery","label":"Then","variant":"emphasis","fromSide":"left","toSide":"right"},
{"id":"stage-5","from":"delivery","to":"uat","label":"Then","variant":"emphasis","fromSide":"left","toSide":"right"},
{"id":"stage-6","from":"uat","to":"security","label":"Then","variant":"emphasis","fromSide":"top","toSide":"bottom"},
{"id":"stage-7","from":"security","to":"releases","label":"Then","variant":"emphasis","fromSide":"top","toSide":"bottom"},
{"id":"stage-8","from":"releases","to":"scope","label":"Repeat indefinitely","variant":"emphasis","fromSide":"right","toSide":"left","labelAt":[465,170]},
{"id":"contribute-scope","from":"code-scope","to":"scope","label":"Contribute","variant":"dashed","fromSide":"bottom","toSide":"top"},
{"id":"contribute-architecture","from":"code-architecture","to":"architecture","label":"Contribute","variant":"dashed","fromSide":"bottom","toSide":"top"},
{"id":"contribute-ui-ux","from":"code-ui-ux","to":"ui-ux","label":"Contribute","variant":"dashed","fromSide":"left","toSide":"right","labelAt":[990,570]},
{"id":"contribute-planning","from":"code-planning","to":"planning","label":"Contribute","variant":"dashed","fromSide":"top","toSide":"bottom"},
{"id":"contribute-delivery","from":"code-delivery","to":"delivery","label":"Contribute","variant":"dashed","fromSide":"top","toSide":"bottom"},
{"id":"contribute-uat","from":"code-uat","to":"uat","label":"Contribute","variant":"dashed","fromSide":"top","toSide":"bottom"},
{"id":"contribute-security","from":"code-security","to":"security","label":"Contribute","variant":"dashed","fromSide":"right","toSide":"left","labelAt":[220,570]},
{"id":"contribute-releases","from":"code-releases","to":"releases","label":"Contribute","variant":"dashed","fromSide":"bottom","toSide":"top"}
] ]
} }
+4 -2
View File
@@ -16,9 +16,11 @@ import ArchifyDiagram from '@site/src/components/ArchifyDiagram';
<ArchifyDiagram name="strategy-target" title="Autonomous agent executes and governs the SDLC; humans direct, guide and review" story /> <ArchifyDiagram name="strategy-target" title="Autonomous agent executes and governs the SDLC; humans direct, guide and review" story />
An autonomous agent executes and governs the SDLC. Humans direct, guide and review the work throughout the cycle. An autonomous agent executes and governs every phase. Humans direct, guide and review it; a separate human-controlled code agent contributes to each phase from outside the cycle.
**Scope → Architecture → UI/UX → Planning → Delivery → UAT → Releases → Scope** **Solid arrows:** lifecycle · **Dotted spokes:** execution and governance · **Dashed arrows:** contributions.
**Scope → Architecture → UI/UX → Planning → Delivery → UAT → Security → Releases → Scope**
Releases returns to Scope and the cycle repeats indefinitely. Governed skills and measured outcomes support the path toward this target; they are not a substitute for it. Releases returns to Scope and the cycle repeats indefinitely. Governed skills and measured outcomes support the path toward this target; they are not a substitute for it.
+6 -3
View File
@@ -1,6 +1,7 @@
--- ---
id: target-operating-model id: target-operating-model
title: Target operating model title: Target operating model
sidebar_label: Target
description: An autonomous agent executes and governs the SDLC; humans direct, guide and review the repeating cycle. description: An autonomous agent executes and governs the SDLC; humans direct, guide and review the repeating cycle.
hide_table_of_contents: true hide_table_of_contents: true
--- ---
@@ -15,9 +16,11 @@ import ArchifyDiagram from '@site/src/components/ArchifyDiagram';
<ArchifyDiagram name="strategy-target" title="Autonomous agent executes and governs the SDLC; humans direct, guide and review" story /> <ArchifyDiagram name="strategy-target" title="Autonomous agent executes and governs the SDLC; humans direct, guide and review" story />
An autonomous agent executes and governs the SDLC. Humans direct, guide and review the work throughout the cycle. An autonomous agent executes and governs every phase. Humans direct, guide and review it; a separate human-controlled code agent contributes to each phase from outside the cycle.
**Scope → Architecture → UI/UX → Planning → Delivery → UAT → Releases → Scope** **Solid arrows:** lifecycle · **Dotted spokes:** execution and governance · **Dashed arrows:** contributions.
**Scope → Architecture → UI/UX → Planning → Delivery → UAT → Security → Releases → Scope**
Each stage follows the previous one. Releases returns to Scope; the cycle repeats indefinitely, with human direction informing the next iteration. Each stage follows the previous one. Releases returns to Scope; the cycle repeats indefinitely, with human direction informing the next iteration.
@@ -44,7 +47,7 @@ The autonomous agent is more than a task router: it executes and governs the rep
One logical coordinator does not mean one fragile process. A durable task ledger, explicit state transitions, leases and idempotency keys allow recovery or multiple replicas without duplicate delivery. Inference outages stop new agent decisions, not the organization's ability to take over. People can resume work through the normal deterministic workflow. Evidence and authorization services fail closed for privileged actions; missing evidence never becomes permission. One logical coordinator does not mean one fragile process. A durable task ledger, explicit state transitions, leases and idempotency keys allow recovery or multiple replicas without duplicate delivery. Inference outages stop new agent decisions, not the organization's ability to take over. People can resume work through the normal deterministic workflow. Evidence and authorization services fail closed for privileged actions; missing evidence never becomes permission.
These controls support the sequence Scope → Architecture → UI/UX → Planning → Delivery → UAT → Releases → Scope; they do not replace it with a separate lifecycle. Product, engineering, design, quality, security and platform expertise inform human direction and review. Specific approval assignments and release permissions are implementation decisions still to be defined. These controls support the sequence Scope → Architecture → UI/UX → Planning → Delivery → UAT → Security → Releases → Scope; they do not replace it with a separate lifecycle. Product, engineering, design, quality, security and platform expertise inform human direction and review. Specific approval assignments and release permissions are implementation decisions still to be defined.
### Trust and authority boundaries ### Trust and authority boundaries
+6 -3
View File
@@ -88,7 +88,7 @@ const fs = require('node:fs');
if (format.startsWith('svg')) { if (format.startsWith('svg')) {
const valid = await page.evaluate(xml => { const valid = await page.evaluate(xml => {
const doc = new DOMParser().parseFromString(xml, 'image/svg+xml'); const doc = new DOMParser().parseFromString(xml, 'image/svg+xml');
return !doc.querySelector('parsererror') && doc.documentElement.localName === 'svg' && doc.querySelectorAll('text').length > 0; return !doc.querySelector('parsererror') && doc.documentElement.localName === 'svg' && doc.querySelectorAll('text').length > 0 && doc.querySelector('#eldorado-cycle-export')?.textContent.includes('stroke-dasharray: 3 9');
}, bytes.toString()); }, bytes.toString());
assert(valid, format); assert(valid, format);
} else { } else {
@@ -117,10 +117,13 @@ const fs = require('node:fs');
await close.focus(); await page.keyboard.press('Escape'); await close.focus(); await page.keyboard.press('Escape');
assert(await opener.evaluate(n => n === document.activeElement)); assert(await opener.evaluate(n => n === document.activeElement));
await iframe.scrollIntoViewIfNeeded(); await iframe.scrollIntoViewIfNeeded();
await page.evaluate(() => scrollTo(0, 0)); await page.evaluate(() => scrollTo({top: 0, behavior: 'instant'}));
await page.evaluate(() => new Promise(resolve => requestAnimationFrame(() => requestAnimationFrame(resolve))));
await page.screenshot({path:`${output}/${width}.png`, fullPage:true}); await page.screenshot({path:`${output}/${width}.png`, fullPage:true});
await frame.locator('#btn-theme').click(); await theme('dark'); await frame.locator('#btn-theme').click(); await theme('dark');
await page.locator('.strategy-content a[href$="/strategy/target-operating-model/"]').filter({visible:true}).click(); // Exercise keyboard navigation without racing the portal's smooth scroll.
await page.locator('.strategy-content a[href$="/strategy/target-operating-model/"]').filter({visible:true}).focus();
await page.keyboard.press('Enter');
await page.waitForURL('**/strategy/target-operating-model/'); await page.waitForURL('**/strategy/target-operating-model/');
await page.getByRole('heading', {name:'Target operating model', exact:true, level:1}).waitFor(); await page.getByRole('heading', {name:'Target operating model', exact:true, level:1}).waitFor();
const next = page.locator(`.archify-panel--story[data-diagram="strategy-target"] > .story-${width > 700 ? 'desktop' : 'mobile'}`); const next = page.locator(`.archify-panel--story[data-diagram="strategy-target"] > .story-${width > 700 ? 'desktop' : 'mobile'}`);
+25 -4
View File
@@ -19,7 +19,7 @@ const fs = require('node:fs');
await page.waitForURL('**/strategy/target-operating-model/'); await page.waitForURL('**/strategy/target-operating-model/');
for (const route of ['target-operating-model/', '']) { for (const route of ['target-operating-model/', '']) {
await page.goto(`${base}/eldorado-v1/documentation/strategy/${route}`, {waitUntil:'networkidle'}); await page.goto(`${base}/eldorado-v1/documentation/strategy/${route}`, {waitUntil:'networkidle'});
if (width === 1440) assert.equal(await page.locator('.theme-doc-sidebar-menu .menu__link').first().innerText(), 'Target operating model'); if (width === 1440) assert.equal(await page.locator('.theme-doc-sidebar-menu .menu__link').first().innerText(), 'Target');
const iframe = page.locator(`.archify-panel--story > .story-${width > 700 ? 'desktop' : 'mobile'}`); const iframe = page.locator(`.archify-panel--story > .story-${width > 700 ? 'desktop' : 'mobile'}`);
await iframe.scrollIntoViewIfNeeded(); await iframe.scrollIntoViewIfNeeded();
const frame = await (await iframe.elementHandle()).contentFrame(); const frame = await (await iframe.elementHandle()).contentFrame();
@@ -32,15 +32,36 @@ const fs = require('node:fs');
const box = n.querySelector('rect').getBoundingClientRect(); const box = n.querySelector('rect').getBoundingClientRect();
return [...n.querySelectorAll('text')].filter(t => {const b=t.getBoundingClientRect();return b.left<box.left||b.right>box.right||b.top<box.top||b.bottom>box.bottom;}).map(t=>t.textContent); return [...n.querySelectorAll('text')].filter(t => {const b=t.getBoundingClientRect();return b.left<box.left||b.right>box.right||b.top<box.top||b.bottom>box.bottom;}).map(t=>t.textContent);
}); });
return {labels,edges,overflow}; const relationships = [...svg.querySelectorAll('path[data-edge-id]')].map(n => ({id:n.dataset.edgeId,from:n.dataset.edgeFrom,to:n.dataset.edgeTo,dash:getComputedStyle(n).strokeDasharray,arrow:n.getAttribute('marker-end')}));
const nodes = [...svg.querySelectorAll('[data-node-id]')].map(n => {const r=n.querySelector('rect').getBoundingClientRect();return {id:n.dataset.nodeId,x:r.x+r.width/2,y:r.y+r.height/2};});
return {labels,edges,overflow,relationships,nodes};
}); });
const ids = ['scope','architecture','ui-ux','planning','delivery','uat','releases']; const ids = ['scope','architecture','ui-ux','planning','delivery','uat','security','releases'];
assert.deepEqual(metrics.edges.map(e=>e.slice(0,2)), ids.map((id,i)=>[id,ids[(i+1)%ids.length]])); assert.deepEqual(metrics.edges.map(e=>e.slice(0,2)), ids.map((id,i)=>[id,ids[(i+1)%ids.length]]));
assert(metrics.edges.every(e=>e[2]?.startsWith('url(')), 'all stages must have arrowheads'); assert(metrics.edges.every(e=>e[2]?.startsWith('url(')), 'all stages must have arrowheads');
assert.equal(metrics.nodes.length, 18);
const governs = metrics.relationships.filter(e=>e.id.startsWith('govern-'));
const contributions = metrics.relationships.filter(e=>e.id.startsWith('contribute-'));
assert.deepEqual(governs.map(e=>[e.from,e.to]), ids.map(id=>['agent',id]));
assert.deepEqual(contributions.map(e=>[e.from,e.to]), ids.map(id=>[`code-${id}`,id]));
assert(governs.every(e=>e.dash==='3px, 9px' && e.arrow?.startsWith('url(')));
assert(contributions.every(e=>e.dash==='12px, 8px' && e.arrow?.startsWith('url(')));
assert(metrics.relationships.some(e=>e.from==='humans' && e.to==='agent'));
if (width > 700) {
const agent = metrics.nodes.find(n=>n.id==='agent');
const phases = metrics.nodes.filter(n=>ids.includes(n.id));
for (const axis of ['x','y']) assert(Math.abs(agent[axis]-(Math.min(...phases.map(n=>n[axis]))+Math.max(...phases.map(n=>n[axis])))/2)<1);
for (const id of ids) {
const phase=phases.find(n=>n.id===id), code=metrics.nodes.find(n=>n.id===`code-${id}`);
assert(Math.hypot(code.x-agent.x,code.y-agent.y)>Math.hypot(phase.x-agent.x,phase.y-agent.y));
}
}
assert(metrics.labels.every(n=>n.px>=14), JSON.stringify(metrics.labels)); assert(metrics.labels.every(n=>n.px>=14), JSON.stringify(metrics.labels));
assert.deepEqual(metrics.overflow, []); assert.deepEqual(metrics.overflow, []);
assert(!await page.evaluate(()=>document.documentElement.scrollWidth>innerWidth)); assert(!await page.evaluate(()=>document.documentElement.scrollWidth>innerWidth));
await page.evaluate(()=>scrollTo(0,0)); await page.evaluate(()=>scrollTo({top:0,behavior:'instant'}));
await page.waitForFunction(()=>scrollY===0);
await page.evaluate(()=>new Promise(resolve=>requestAnimationFrame(()=>requestAnimationFrame(resolve))));
await page.screenshot({path:`${output}/${width}-${route ? 'target' : 'landing'}.png`,fullPage:true}); await page.screenshot({path:`${output}/${width}-${route ? 'target' : 'landing'}.png`,fullPage:true});
results.push({width,route,...metrics}); results.push({width,route,...metrics});
fs.writeFileSync(`${output}/results.json`,JSON.stringify(results,null,2)); fs.writeFileSync(`${output}/results.json`,JSON.stringify(results,null,2));
+6 -3
View File
@@ -19,18 +19,21 @@ 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};}); 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))}; return {width:innerWidth,height:innerHeight,nodes,svg:svg.getBoundingClientRect().toJSON(),minLabel:Math.min(...[...svg.querySelectorAll('text[data-node-label]')].map(n=>parseFloat(getComputedStyle(n).fontSize)*n.getScreenCTM().a))};
}); });
assert(geometry.nodes.length>=5 && geometry.nodes.length<=(['index','target-operating-model'].includes(id)?9:7),id); assert(geometry.nodes.length>=5 && geometry.nodes.length<=(['index','target-operating-model'].includes(id)?18:7),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}`); 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})); 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<=200,id);assert(!data.overflow,id);assert.equal(data.openDetails,0,id); assert(data.words<=200,id);assert(!data.overflow,id);assert.equal(data.openDetails,0,id);
await page.evaluate(()=>scrollTo(0,0));await page.screenshot({path:`.cache/story-${label}/${width}-${id}.png`,fullPage:true}); await page.evaluate(()=>scrollTo({top:0,behavior:'instant'}));await page.screenshot({path:`.cache/story-${label}/${width}-${id}.png`,fullPage:true});
const opener=panel.getByRole('button',{name:/^Expand /});await opener.click(); const opener=panel.getByRole('button',{name:/^Expand /});await opener.click();
const close=panel.getByRole('button',{name:'Close full-screen diagram',exact:true});await close.waitFor({state:'visible'}); const close=panel.getByRole('button',{name:'Close full-screen diagram',exact:true});await close.waitFor({state:'visible'});
assert.equal(await close.innerText(),'×');assert(await close.evaluate(n=>n===document.activeElement)); assert.equal(await close.innerText(),'×');assert(await close.evaluate(n=>n===document.activeElement));
const box=await close.boundingBox();assert.equal(box.width,44);assert.equal(box.height,44); const box=await close.boundingBox();assert.equal(box.width,44);assert.equal(box.height,44);
await close.click();assert(await opener.evaluate(n=>n===document.activeElement)); await close.click();assert(await opener.evaluate(n=>n===document.activeElement));
await opener.click();await close.waitFor({state:'visible'});await page.keyboard.press('Escape');await page.waitForFunction(()=>!document.querySelector('.archify-panel--story dialog').open);assert(await opener.evaluate(n=>n===document.activeElement)); await opener.click();await close.waitFor({state:'visible'});await page.keyboard.press('Escape');await page.waitForFunction(()=>!document.querySelector('.archify-panel--story dialog').open);assert(await opener.evaluate(n=>n===document.activeElement));
const summary=page.locator('.strategy-content > details > summary').first();await summary.click();assert(await summary.evaluate(n=>n.parentElement.open));await summary.click(); const summary=page.locator('.strategy-content > details > summary').first();
await summary.focus();await page.keyboard.press('Enter');
await page.waitForFunction(()=>document.querySelector('.strategy-content > details').open);
await page.keyboard.press('Enter');
results.push({id,width,...data,geometry,modalClick:true,modalEscape:true,focusRestored:true,details:true});fs.writeFileSync(`.cache/story-${label}/results.json`,JSON.stringify(results,null,2)); results.push({id,width,...data,geometry,modalClick:true,modalEscape:true,focusRestored:true,details:true});fs.writeFileSync(`.cache/story-${label}/results.json`,JSON.stringify(results,null,2));
} }
await page.goto(`${base}/eldorado-v1/documentation/strategy/measurement/#validated-task-success`,{waitUntil:'networkidle'}); await page.goto(`${base}/eldorado-v1/documentation/strategy/measurement/#validated-task-success`,{waitUntil:'networkidle'});
+9 -1
View File
@@ -37,7 +37,15 @@ for (const file of readdirSync('diagrams').sort()) {
if (start < 0 || end < start || preset.split(guard).length !== 3) throw new Error('Archify preset integration drift'); if (start < 0 || end < start || preset.split(guard).length !== 3) throw new Error('Archify preset integration drift');
viewer = viewer.slice(0, start) + preset.replaceAll(guard, '') + viewer.slice(end); viewer = viewer.slice(0, start) + preset.replaceAll(guard, '') + viewer.slice(end);
if (!viewer.includes('</head>') || !viewer.includes('</body>')) throw new Error(`Invalid viewer: ${output}`); if (!viewer.includes('</head>') || !viewer.includes('</body>')) throw new Error(`Invalid viewer: ${output}`);
const storyStyles = ['strategy-target', 'strategy-target-mobile'].includes(name) ? cycleStyles : ''; const storyStyles = ['strategy-target', 'strategy-target-mobile'].includes(name)
? `${name === 'strategy-target' ? ':root {--cycle-label: 27px; --cycle-detail: 21px;}' : ':root {--cycle-label: 38px; --cycle-detail: 28px;}'}${cycleStyles}` : '';
if (storyStyles) {
// Keep typography and relationship styles inside exported standalone SVGs.
const diagramRoot = /<svg\b[^>]*role="img"[^>]*>/g;
if ([...viewer.matchAll(diagramRoot)].length !== 1) throw new Error('Cycle SVG integration drift');
const exportStyles = storyStyles.replaceAll(':root', 'svg[role="img"]').replaceAll('.diagram-container > svg', 'svg[role="img"]');
viewer = viewer.replace(diagramRoot, root => `${root}<style id="eldorado-cycle-export">${exportStyles}</style>`);
}
writeFileSync(output, viewer.replace('</head>', `<style id="eldorado-inline-controls">${inlineStyles}</style><style id="eldorado-cycle-labels">${storyStyles}</style></head>`) 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>`)); .replace('</body>', `<script>${themeBridge}</script></body>`));
renameSync(`static/diagrams/${name}/index.delivery.json`, `.cache/archify/${name}.delivery.json`); renameSync(`static/diagrams/${name}/index.delivery.json`, `.cache/archify/${name}.delivery.json`);
+10 -5
View File
@@ -2,13 +2,18 @@
.diagram-container > svg text { .diagram-container > svg text {
font-family: Arial, sans-serif; font-family: Arial, sans-serif;
letter-spacing: 0; letter-spacing: 0;
font-size: 18px; font-size: 30px;
} }
.diagram-container > svg text[data-node-label] { .diagram-container > svg text[data-node-label] {
font-size: 24px; font-size: var(--cycle-label);
transform: translateY(-3px); transform: translateY(-6px);
} }
.diagram-container > svg text[data-detail="context"] { .diagram-container > svg text[data-detail="context"] {
font-size: 18px; font-size: var(--cycle-detail);
transform: translateY(7px); transform: translateY(16px);
} }
/* Edge semantics stay in SVG metadata; one page legend avoids repeated labels. */
.diagram-container > svg g[data-edge-id] {display: none;}
.diagram-container > svg path[data-edge-id^="stage-"] {stroke-width: 2.5;}
.diagram-container > svg path[data-edge-id^="govern-"] {stroke-dasharray: 3 9; stroke-width: 3;}
.diagram-container > svg path[data-edge-id^="contribute-"] {stroke-dasharray: 12 8; stroke-width: 3;}
+30 -6
View File
@@ -2,35 +2,59 @@ import {test} from 'node:test';
import assert from 'node:assert/strict'; import assert from 'node:assert/strict';
import {readFileSync} from 'node:fs'; import {readFileSync} from 'node:fs';
const read = p => readFileSync(p, 'utf8'); const read = p => readFileSync(p, 'utf8');
const stages = ['Scope', 'Architecture', 'UI/UX', 'Planning', 'Delivery', 'UAT', 'Releases']; const stages = ['Scope', 'Architecture', 'UI/UX', 'Planning', 'Delivery', 'UAT', 'Security', 'Releases'];
test('Strategy opens at the autonomous lifecycle, with a matching direct landing story', () => { test('Strategy opens at the autonomous lifecycle, with a matching direct landing story', () => {
assert.match(read('sidebars/strategy.ts'), /strategySidebar: \['target-operating-model', 'index'/); assert.match(read('sidebars/strategy.ts'), /strategySidebar: \['target-operating-model', 'index'/);
assert.match(read('docs/strategy/target-operating-model.mdx'), /^sidebar_label: Target$/m);
for (const id of ['index', 'target-operating-model']) { for (const id of ['index', 'target-operating-model']) {
const page = read(`docs/strategy/${id}.mdx`); const page = read(`docs/strategy/${id}.mdx`);
const primary = page.split('<details>')[0]; const primary = page.split('<details>')[0];
assert(primary.includes('name="strategy-target"')); assert(primary.includes('name="strategy-target"'));
assert(primary.includes('autonomous agent')); assert(primary.includes('autonomous agent'));
assert(primary.includes('direct, guide and review')); assert(primary.includes('direct, guide and review'));
assert(primary.includes('Scope → Architecture → UI/UX → Planning → Delivery → UAT → Releases → Scope')); assert(primary.includes('Scope → Architecture → UI/UX → Planning → Delivery → UAT → Security → Releases → Scope'));
assert(primary.includes('human-controlled code agent'));
assert(primary.includes('TO-BE')); assert(primary.includes('TO-BE'));
assert(!/only routes|People authorize|independent gates protect release/.test(primary)); assert(!/only routes|People authorize|independent gates protect release/.test(primary));
} }
}); });
test('both target diagrams have exactly seven sequential stages and a Releases to Scope return', () => { test('both target diagrams have eight stages, eight governed phases and eight human-controlled contributors', () => {
for (const suffix of ['', '-mobile']) { for (const suffix of ['', '-mobile']) {
const d = JSON.parse(read(`diagrams/strategy-target${suffix}.architecture.json`)); const d = JSON.parse(read(`diagrams/strategy-target${suffix}.architecture.json`));
const ids = stages.map(label => d.components.find(n => n.label === label)?.id); const ids = stages.map(label => d.components.find(n => n.label === label)?.id);
assert(ids.every(Boolean)); assert(ids.every(Boolean));
assert.equal(new Set(ids).size, 7); assert.equal(new Set(ids).size, 8);
const flow = d.connections.filter(e => ids.includes(e.from) && ids.includes(e.to)); const flow = d.connections.filter(e => ids.includes(e.from) && ids.includes(e.to));
assert.deepEqual(flow.map(e => [e.from, e.to]), ids.map((id, i) => [id, ids[(i + 1) % ids.length]])); assert.deepEqual(flow.map(e => [e.from, e.to]), ids.map((id, i) => [id, ids[(i + 1) % ids.length]]));
assert.match(flow.at(-1).label, /Repeat/); assert.match(flow.at(-1).label, /Repeat/);
assert(flow.at(-1).via.length >= 2, 'explicit outside return corridor');
assert(d.components.some(n => n.label === 'Autonomous agent' && /Executes.*governs/.test(n.sublabel))); assert(d.components.some(n => n.label === 'Autonomous agent' && /Executes.*governs/.test(n.sublabel)));
assert(d.components.some(n => n.label === 'Humans' && n.sublabel === 'Direct, guide and review')); assert(d.components.some(n => n.label === 'Humans' && n.sublabel === 'Direct, guide and review'));
assert(d.connections.some(e => e.from === 'humans' && e.to === 'agent')); assert(d.connections.some(e => e.from === 'humans' && e.to === 'agent'));
assert(d.connections.some(e => e.from === 'agent' && e.to === ids[0])); assert.deepEqual(d.connections.filter(e => e.from === 'agent').map(e => e.to), ids);
const contributors = d.components.filter(n => n.id.startsWith('code-'));
assert.equal(contributors.length, 8);
assert(contributors.every(n => n.label === 'Code agent' && n.sublabel === 'Human-controlled'));
for (const id of ids) {
assert(d.connections.some(e => e.from === `code-${id}` && e.to === id && e.variant === 'dashed'));
assert(d.connections.some(e => e.from === 'agent' && e.to === id && e.variant === 'security'));
}
assert.equal(d.components.length, 18);
if (!suffix) {
const center = n => n.pos.map((v, i) => v + n.size[i] / 2);
const agent = center(d.components.find(n => n.id === 'agent'));
const phaseCenters = ids.map(id => center(d.components.find(n => n.id === id)));
for (const axis of [0, 1]) {
const values = phaseCenters.map(c => c[axis]);
assert.equal(agent[axis], (Math.min(...values) + Math.max(...values)) / 2);
}
for (const code of contributors) {
const phase = d.components.find(n => n.id === code.id.slice(5));
const distance = n => Math.hypot(...center(n).map((v, i) => v - agent[i]));
assert(distance(code) > distance(phase), `${code.id} is exterior`);
}
}
} }
}); });
+2 -2
View File
@@ -28,10 +28,10 @@ test('mobile story diagrams preserve the same nodes and directed relationships',
const name = /<ArchifyDiagram name="([^"]+)"[^>]+ story/.exec(page)[1]; const name = /<ArchifyDiagram name="([^"]+)"[^>]+ story/.exec(page)[1];
const desktop = JSON.parse(read(`diagrams/${name}.architecture.json`)); const desktop = JSON.parse(read(`diagrams/${name}.architecture.json`));
const mobile = JSON.parse(read(`diagrams/${name}-mobile.architecture.json`)); const mobile = JSON.parse(read(`diagrams/${name}-mobile.architecture.json`));
assert(desktop.components.length >= 5 && desktop.components.length <= (name === 'strategy-target' ? 9 : 7), name); assert(desktop.components.length >= 5 && desktop.components.length <= (name === 'strategy-target' ? 18 : 7), name);
const semantic = d => ({nodes:d.components.map(({pos,size,...n})=>n),edges:d.connections.map(({fromSide,toSide,via,labelAt,...e})=>e)}); const semantic = d => ({nodes:d.components.map(({pos,size,...n})=>n),edges:d.connections.map(({fromSide,toSide,via,labelAt,...e})=>e)});
assert.deepEqual(semantic(desktop), semantic(mobile), name); assert.deepEqual(semantic(desktop), semantic(mobile), name);
assert(desktop.connections.every(e => e.label && e.from !== e.to), name); assert(desktop.connections.every(e => (e.label || e.id.startsWith('govern-')) && e.from !== e.to), name);
assert.equal(desktop.meta.legend.mode, 'hidden'); assert.equal(desktop.meta.legend.mode, 'hidden');
} }
}); });
+2 -2
View File
@@ -110,7 +110,7 @@ a:focus-visible, button:focus-visible {outline: 3px solid #b88719; outline-offse
.archify-panel--story {max-width: 740px;} .archify-panel--story {max-width: 740px;}
.archify-panel--story > iframe {height: auto; aspect-ratio: 480 / 408;} .archify-panel--story > iframe {height: auto; aspect-ratio: 480 / 408;}
.archify-panel--story > .story-mobile {display: none;} .archify-panel--story > .story-mobile {display: none;}
.archify-panel--story[data-diagram="strategy-target"] > iframe {aspect-ratio: 960 / 708;} .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-adoption"] > iframe {aspect-ratio: 545 / 408;}
.archify-panel--story[data-diagram="strategy-maintenance"] > iframe {aspect-ratio: 524 / 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 > details {margin: .65rem 0; border: 1px solid var(--line); padding: .8rem 1rem; background: var(--surface);}
@@ -124,7 +124,7 @@ a:focus-visible, button:focus-visible {outline: 3px solid #b88719; outline-offse
.archify-panel--story[data-diagram="strategy-roadmap"] > .story-mobile {aspect-ratio: 240 / 628;} .archify-panel--story[data-diagram="strategy-roadmap"] > .story-mobile {aspect-ratio: 240 / 628;}
.archify-panel--story[data-diagram="strategy-adoption"] > .story-mobile {aspect-ratio: 305 / 748;} .archify-panel--story[data-diagram="strategy-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-maintenance"] > .story-mobile {aspect-ratio: 284 / 748;}
.archify-panel--story[data-diagram="strategy-target"] > .story-mobile {aspect-ratio: 340 / 1520;} .archify-panel--story[data-diagram="strategy-target"] > .story-mobile {aspect-ratio: 680 / 2340;}
} }
.archify-expand {display: grid; place-items: center; width: 44px; height: 44px; border: 0; padding: 0; background: transparent; color: var(--ifm-link-color); cursor: pointer;} .archify-expand {display: grid; place-items: center; width: 44px; height: 44px; border: 0; padding: 0; background: transparent; color: var(--ifm-link-color); cursor: pointer;}
.archify-expand:hover {background: var(--ifm-hover-overlay);} .archify-expand:hover {background: var(--ifm-hover-overlay);}