docs: center Target lifecycle on autonomous agent #19
No files matched your search
@@ -3,25 +3,50 @@
|
||||
"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"}},
|
||||
"components": [
|
||||
{"id": "humans", "type": "backend", "label": "Humans", "sublabel": "Direct, guide and review", "pos": [20, 20], "size": [240, 80]},
|
||||
{"id": "agent", "type": "security", "label": "Autonomous agent", "sublabel": "Executes and governs SDLC", "pos": [20, 180], "size": [240, 80]},
|
||||
{"id": "scope", "type": "backend", "label": "Scope", "sublabel": "01", "pos": [20, 340], "size": [240, 80]},
|
||||
{"id": "architecture", "type": "backend", "label": "Architecture", "sublabel": "02", "pos": [20, 500], "size": [240, 80]},
|
||||
{"id": "ui-ux", "type": "backend", "label": "UI/UX", "sublabel": "03", "pos": [20, 660], "size": [240, 80]},
|
||||
{"id": "planning", "type": "backend", "label": "Planning", "sublabel": "04", "pos": [20, 820], "size": [240, 80]},
|
||||
{"id": "delivery", "type": "backend", "label": "Delivery", "sublabel": "05", "pos": [20, 980], "size": [240, 80]},
|
||||
{"id": "uat", "type": "backend", "label": "UAT", "sublabel": "06", "pos": [20, 1140], "size": [240, 80]},
|
||||
{"id": "releases", "type": "backend", "label": "Releases", "sublabel": "07", "pos": [20, 1300], "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 / governs SDLC","pos":[140,200],"size":[360,120]},
|
||||
{"id":"scope","type":"backend","label":"Scope","sublabel":"01","pos":[100,440],"size":[240,100]},
|
||||
{"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":[100,880],"size":[240,100]},
|
||||
{"id":"planning","type":"backend","label":"Planning","sublabel":"04","pos":[100,1100],"size":[240,100]},
|
||||
{"id":"delivery","type":"backend","label":"Delivery","sublabel":"05","pos":[100,1320],"size":[240,100]},
|
||||
{"id":"uat","type":"backend","label":"UAT","sublabel":"06","pos":[100,1540],"size":[240,100]},
|
||||
{"id":"security","type":"backend","label":"Security","sublabel":"07","pos":[100,1760],"size":[240,100]},
|
||||
{"id":"releases","type":"backend","label":"Releases","sublabel":"08","pos":[100,1980],"size":[240,100]},
|
||||
{"id":"code-scope","type":"frontend","label":"Code agent","sublabel":"Human-controlled","pos":[400,440],"size":[240,100]},
|
||||
{"id":"code-architecture","type":"frontend","label":"Code agent","sublabel":"Human-controlled","pos":[400,660],"size":[240,100]},
|
||||
{"id":"code-ui-ux","type":"frontend","label":"Code agent","sublabel":"Human-controlled","pos":[400,880],"size":[240,100]},
|
||||
{"id":"code-planning","type":"frontend","label":"Code agent","sublabel":"Human-controlled","pos":[400,1100],"size":[240,100]},
|
||||
{"id":"code-delivery","type":"frontend","label":"Code agent","sublabel":"Human-controlled","pos":[400,1320],"size":[240,100]},
|
||||
{"id":"code-uat","type":"frontend","label":"Code agent","sublabel":"Human-controlled","pos":[400,1540],"size":[240,100]},
|
||||
{"id":"code-security","type":"frontend","label":"Code agent","sublabel":"Human-controlled","pos":[400,1760],"size":[240,100]},
|
||||
{"id":"code-releases","type":"frontend","label":"Code agent","sublabel":"Human-controlled","pos":[400,1980],"size":[240,100]}
|
||||
],
|
||||
"connections": [
|
||||
{"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": "stage-1", "from": "scope", "to": "architecture", "label": "Then", "fromSide": "bottom", "toSide": "top"},
|
||||
{"id": "stage-2", "from": "architecture", "to": "ui-ux", "label": "Then", "fromSide": "bottom", "toSide": "top"},
|
||||
{"id": "stage-3", "from": "ui-ux", "to": "planning", "label": "Then", "fromSide": "bottom", "toSide": "top"},
|
||||
{"id": "stage-4", "from": "planning", "to": "delivery", "label": "Then", "fromSide": "bottom", "toSide": "top"},
|
||||
{"id": "stage-5", "from": "delivery", "to": "uat", "label": "Then", "fromSide": "bottom", "toSide": "top"},
|
||||
{"id": "stage-6", "from": "uat", "to": "releases", "label": "Then", "fromSide": "bottom", "toSide": "top"},
|
||||
{"id": "stage-7", "from": "releases", "to": "scope", "label": "Repeat indefinitely", "fromSide": "right", "toSide": "right", "via": [[300, 1340], [300, 380]], "labelAt": [180, 1430]}
|
||||
{"id":"human-direction","from":"humans","to":"agent","label":"Guide","fromSide":"bottom","toSide":"top"},
|
||||
{"id":"govern-scope","from":"agent","to":"scope","label":"","variant":"security","fromSide":"left","toSide":"left","via":[[60,260],[60,490]]},
|
||||
{"id":"govern-architecture","from":"agent","to":"architecture","label":"","variant":"security","fromSide":"left","toSide":"left","via":[[60,260],[60,710]]},
|
||||
{"id":"govern-ui-ux","from":"agent","to":"ui-ux","label":"","variant":"security","fromSide":"left","toSide":"left","via":[[60,260],[60,930]]},
|
||||
{"id":"govern-planning","from":"agent","to":"planning","label":"","variant":"security","fromSide":"left","toSide":"left","via":[[60,260],[60,1150]]},
|
||||
{"id":"govern-delivery","from":"agent","to":"delivery","label":"","variant":"security","fromSide":"left","toSide":"left","via":[[60,260],[60,1370]]},
|
||||
{"id":"govern-uat","from":"agent","to":"uat","label":"","variant":"security","fromSide":"left","toSide":"left","via":[[60,260],[60,1590]]},
|
||||
{"id":"govern-security","from":"agent","to":"security","label":"","variant":"security","fromSide":"left","toSide":"left","via":[[60,260],[60,1810]]},
|
||||
{"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"}
|
||||
]
|
||||
}
|
||||
@@ -3,25 +3,50 @@
|
||||
"diagram_type": "architecture",
|
||||
"meta": {"title": "TO-BE: autonomous SDLC, human direction", "output": "static/diagrams/strategy-target/index.html", "quality_profile": "showcase", "legend": {"mode": "hidden"}},
|
||||
"components": [
|
||||
{"id": "humans", "type": "backend", "label": "Humans", "sublabel": "Direct, guide and review", "pos": [40, 20], "size": [240, 80]},
|
||||
{"id": "agent", "type": "security", "label": "Autonomous agent", "sublabel": "Executes and governs SDLC", "pos": [360, 20], "size": [240, 80]},
|
||||
{"id": "scope", "type": "backend", "label": "Scope", "sublabel": "01", "pos": [40, 220], "size": [240, 80]},
|
||||
{"id": "architecture", "type": "backend", "label": "Architecture", "sublabel": "02", "pos": [360, 220], "size": [240, 80]},
|
||||
{"id": "ui-ux", "type": "backend", "label": "UI/UX", "sublabel": "03", "pos": [680, 220], "size": [240, 80]},
|
||||
{"id": "planning", "type": "backend", "label": "Planning", "sublabel": "04", "pos": [680, 380], "size": [240, 80]},
|
||||
{"id": "delivery", "type": "backend", "label": "Delivery", "sublabel": "05", "pos": [680, 540], "size": [240, 80]},
|
||||
{"id": "uat", "type": "backend", "label": "UAT", "sublabel": "06", "pos": [360, 540], "size": [240, 80]},
|
||||
{"id": "releases", "type": "backend", "label": "Releases", "sublabel": "07", "pos": [40, 540], "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 / governs SDLC","pos":[465,450],"size":[270,90]},
|
||||
{"id":"scope","type":"backend","label":"Scope","sublabel":"01","pos":[510,187.5],"size":[180,75]},
|
||||
{"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":[780,457.5],"size":[180,75]},
|
||||
{"id":"planning","type":"backend","label":"Planning","sublabel":"04","pos":[780,727.5],"size":[180,75]},
|
||||
{"id":"delivery","type":"backend","label":"Delivery","sublabel":"05","pos":[510,727.5],"size":[180,75]},
|
||||
{"id":"uat","type":"backend","label":"UAT","sublabel":"06","pos":[240,727.5],"size":[180,75]},
|
||||
{"id":"security","type":"backend","label":"Security","sublabel":"07","pos":[240,457.5],"size":[180,75]},
|
||||
{"id":"releases","type":"backend","label":"Releases","sublabel":"08","pos":[240,187.5],"size":[180,75]},
|
||||
{"id":"code-scope","type":"frontend","label":"Code agent","sublabel":"Human-controlled","pos":[510,37.5],"size":[180,75]},
|
||||
{"id":"code-architecture","type":"frontend","label":"Code agent","sublabel":"Human-controlled","pos":[780,37.5],"size":[180,75]},
|
||||
{"id":"code-ui-ux","type":"frontend","label":"Code agent","sublabel":"Human-controlled","pos":[1005,457.5],"size":[180,75]},
|
||||
{"id":"code-planning","type":"frontend","label":"Code agent","sublabel":"Human-controlled","pos":[780,877.5],"size":[180,75]},
|
||||
{"id":"code-delivery","type":"frontend","label":"Code agent","sublabel":"Human-controlled","pos":[510,877.5],"size":[180,75]},
|
||||
{"id":"code-uat","type":"frontend","label":"Code agent","sublabel":"Human-controlled","pos":[240,877.5],"size":[180,75]},
|
||||
{"id":"code-security","type":"frontend","label":"Code agent","sublabel":"Human-controlled","pos":[15,457.5],"size":[180,75]},
|
||||
{"id":"code-releases","type":"frontend","label":"Code agent","sublabel":"Human-controlled","pos":[240,37.5],"size":[180,75]}
|
||||
],
|
||||
"connections": [
|
||||
{"id": "human-direction", "from": "humans", "to": "agent", "label": "Guide", "fromSide": "right", "toSide": "left"},
|
||||
{"id": "agent-lifecycle", "from": "agent", "to": "scope", "label": "Entire cycle", "fromSide": "bottom", "toSide": "top", "via": [[480, 160], [160, 160]], "labelAt": [320, 145]},
|
||||
{"id": "stage-1", "from": "scope", "to": "architecture", "label": "Then", "fromSide": "right", "toSide": "left"},
|
||||
{"id": "stage-2", "from": "architecture", "to": "ui-ux", "label": "Then", "fromSide": "right", "toSide": "left"},
|
||||
{"id": "stage-3", "from": "ui-ux", "to": "planning", "label": "Then", "fromSide": "bottom", "toSide": "top"},
|
||||
{"id": "stage-4", "from": "planning", "to": "delivery", "label": "Then", "fromSide": "bottom", "toSide": "top"},
|
||||
{"id": "stage-5", "from": "delivery", "to": "uat", "label": "Then", "fromSide": "left", "toSide": "right"},
|
||||
{"id": "stage-6", "from": "uat", "to": "releases", "label": "Then", "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":"human-direction","from":"humans","to":"agent","label":"Guide","fromSide":"bottom","toSide":"top"},
|
||||
{"id":"govern-scope","from":"agent","to":"scope","label":"","variant":"security","fromSide":"right","toSide":"bottom","via":[[750,495],[750,292.5],[600,292.5]]},
|
||||
{"id":"govern-architecture","from":"agent","to":"architecture","label":"","variant":"security","fromSide":"right","toSide":"bottom","via":[[765,495],[765,345],[870,345]]},
|
||||
{"id":"govern-ui-ux","from":"agent","to":"ui-ux","label":"","variant":"security","fromSide":"right","toSide":"left"},
|
||||
{"id":"govern-planning","from":"agent","to":"planning","label":"","variant":"security","fromSide":"right","toSide":"top","via":[[765,495],[765,690],[870,690]]},
|
||||
{"id":"govern-delivery","from":"agent","to":"delivery","label":"","variant":"security","fromSide":"bottom","toSide":"top"},
|
||||
{"id":"govern-uat","from":"agent","to":"uat","label":"","variant":"security","fromSide":"left","toSide":"top","via":[[435,495],[435,690],[330,690]]},
|
||||
{"id":"govern-security","from":"agent","to":"security","label":"","variant":"security","fromSide":"left","toSide":"right"},
|
||||
{"id":"govern-releases","from":"agent","to":"releases","label":"","variant":"security","fromSide":"left","toSide":"bottom","via":[[435,495],[435,345],[330,345]]},
|
||||
{"id":"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"}
|
||||
]
|
||||
}
|
||||
@@ -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 />
|
||||
|
||||
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.
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
---
|
||||
id: 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.
|
||||
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 />
|
||||
|
||||
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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
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
|
||||
|
||||
|
||||
@@ -88,7 +88,7 @@ const fs = require('node:fs');
|
||||
if (format.startsWith('svg')) {
|
||||
const valid = await page.evaluate(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());
|
||||
assert(valid, format);
|
||||
} else {
|
||||
@@ -117,10 +117,13 @@ const fs = require('node:fs');
|
||||
await close.focus(); await page.keyboard.press('Escape');
|
||||
assert(await opener.evaluate(n => n === document.activeElement));
|
||||
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 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.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'}`);
|
||||
|
||||
@@ -19,7 +19,7 @@ const fs = require('node:fs');
|
||||
await page.waitForURL('**/strategy/target-operating-model/');
|
||||
for (const route of ['target-operating-model/', '']) {
|
||||
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'}`);
|
||||
await iframe.scrollIntoViewIfNeeded();
|
||||
const frame = await (await iframe.elementHandle()).contentFrame();
|
||||
@@ -32,15 +32,36 @@ const fs = require('node:fs');
|
||||
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 {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(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.deepEqual(metrics.overflow, []);
|
||||
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});
|
||||
results.push({width,route,...metrics});
|
||||
fs.writeFileSync(`${output}/results.json`,JSON.stringify(results,null,2));
|
||||
|
||||
@@ -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};});
|
||||
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}`);
|
||||
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);
|
||||
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 close=panel.getByRole('button',{name:'Close full-screen diagram',exact:true});await close.waitFor({state:'visible'});
|
||||
assert.equal(await close.innerText(),'×');assert(await close.evaluate(n=>n===document.activeElement));
|
||||
const box=await close.boundingBox();assert.equal(box.width,44);assert.equal(box.height,44);
|
||||
await close.click();assert(await opener.evaluate(n=>n===document.activeElement));
|
||||
await opener.click();await close.waitFor({state:'visible'});await page.keyboard.press('Escape');await page.waitForFunction(()=>!document.querySelector('.archify-panel--story dialog').open);assert(await opener.evaluate(n=>n===document.activeElement));
|
||||
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));
|
||||
}
|
||||
await page.goto(`${base}/eldorado-v1/documentation/strategy/measurement/#validated-task-success`,{waitUntil:'networkidle'});
|
||||
|
||||
@@ -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');
|
||||
viewer = viewer.slice(0, start) + preset.replaceAll(guard, '') + viewer.slice(end);
|
||||
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>`)
|
||||
.replace('</body>', `<script>${themeBridge}</script></body>`));
|
||||
renameSync(`static/diagrams/${name}/index.delivery.json`, `.cache/archify/${name}.delivery.json`);
|
||||
|
||||
@@ -2,13 +2,18 @@
|
||||
.diagram-container > svg text {
|
||||
font-family: Arial, sans-serif;
|
||||
letter-spacing: 0;
|
||||
font-size: 18px;
|
||||
font-size: 30px;
|
||||
}
|
||||
.diagram-container > svg text[data-node-label] {
|
||||
font-size: 24px;
|
||||
transform: translateY(-3px);
|
||||
font-size: var(--cycle-label);
|
||||
transform: translateY(-6px);
|
||||
}
|
||||
.diagram-container > svg text[data-detail="context"] {
|
||||
font-size: 18px;
|
||||
transform: translateY(7px);
|
||||
font-size: var(--cycle-detail);
|
||||
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;}
|
||||
@@ -2,35 +2,59 @@ import {test} from 'node:test';
|
||||
import assert from 'node:assert/strict';
|
||||
import {readFileSync} from 'node:fs';
|
||||
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', () => {
|
||||
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']) {
|
||||
const page = read(`docs/strategy/${id}.mdx`);
|
||||
const primary = page.split('<details>')[0];
|
||||
assert(primary.includes('name="strategy-target"'));
|
||||
assert(primary.includes('autonomous agent'));
|
||||
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(!/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']) {
|
||||
const d = JSON.parse(read(`diagrams/strategy-target${suffix}.architecture.json`));
|
||||
const ids = stages.map(label => d.components.find(n => n.label === label)?.id);
|
||||
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));
|
||||
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(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 === '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 === '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`);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -28,10 +28,10 @@ test('mobile story diagrams preserve the same nodes and directed relationships',
|
||||
const name = /<ArchifyDiagram name="([^"]+)"[^>]+ story/.exec(page)[1];
|
||||
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' ? 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)});
|
||||
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');
|
||||
}
|
||||
});
|
||||
|
||||
+2
-2
@@ -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 > iframe {height: auto; aspect-ratio: 480 / 408;}
|
||||
.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-maintenance"] > iframe {aspect-ratio: 524 / 408;}
|
||||
.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-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: 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:hover {background: var(--ifm-hover-overlay);}
|
||||
|
||||
Reference in new issue
Block a user