diff --git a/diagrams/strategy-target-mobile.architecture.json b/diagrams/strategy-target-mobile.architecture.json index c311370..3c3bd5c 100644 --- a/diagrams/strategy-target-mobile.architecture.json +++ b/diagrams/strategy-target-mobile.architecture.json @@ -3,8 +3,7 @@ "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":[140,20],"size":[360,100]}, - {"id":"agent","type":"security","label":"Autonomous agent","sublabel":"Executes / governs SDLC","pos":[140,200],"size":[360,120]}, + {"id":"agent","type":"security","label":"Autonomous agent","sublabel":"Human Controlled","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]}, @@ -23,7 +22,7 @@ {"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":"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]]}, diff --git a/diagrams/strategy-target.architecture.json b/diagrams/strategy-target.architecture.json index a1ab490..fc13d8f 100644 --- a/diagrams/strategy-target.architecture.json +++ b/diagrams/strategy-target.architecture.json @@ -3,8 +3,7 @@ "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":[465,322.5],"size":[270,75]}, - {"id":"agent","type":"security","label":"Autonomous agent","sublabel":"Executes / governs SDLC","pos":[465,450],"size":[270,90]}, + {"id":"agent","type":"security","label":"Autonomous agent","sublabel":"Human Controlled","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]}, @@ -23,7 +22,7 @@ {"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":"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"}, diff --git a/scripts/browser/inline-controls.cjs b/scripts/browser/inline-controls.cjs index 2a193fb..1bf33b0 100644 --- a/scripts/browser/inline-controls.cjs +++ b/scripts/browser/inline-controls.cjs @@ -88,6 +88,9 @@ const fs = require('node:fs'); if (format.startsWith('svg')) { const valid = await page.evaluate(xml => { const doc = new DOMParser().parseFromString(xml, 'image/svg+xml'); + if (doc.querySelector('[data-node-id="humans"], [data-edge-id="human-direction"]')) return false; + if (![...doc.querySelectorAll('[data-node-id="agent"] text')].some(n => n.textContent === 'Human Controlled')) return false; + if (doc.querySelectorAll('[data-node-id]').length !== 17 || doc.querySelectorAll('path[data-edge-id]').length !== 24) return false; 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); diff --git a/scripts/browser/sdlc-cycle.cjs b/scripts/browser/sdlc-cycle.cjs index fa4a729..e95691c 100644 --- a/scripts/browser/sdlc-cycle.cjs +++ b/scripts/browser/sdlc-cycle.cjs @@ -39,14 +39,17 @@ const fs = require('node:fs'); 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); + assert.equal(metrics.nodes.length, 17); + assert(!metrics.nodes.some(n=>n.id==='humans')); + assert.equal(await frame.locator('[data-node-id="agent"] text').allTextContents().then(texts=>texts.includes('Human Controlled')), true); + assert.equal(metrics.relationships.length, 24); 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')); + assert(!metrics.relationships.some(e=>e.id==='human-direction' || e.from==='humans' || e.to==='humans')); if (width > 700) { const agent = metrics.nodes.find(n=>n.id==='agent'); const phases = metrics.nodes.filter(n=>ids.includes(n.id)); diff --git a/scripts/sdlc-cycle.test.mjs b/scripts/sdlc-cycle.test.mjs index f4459e5..724c14f 100644 --- a/scripts/sdlc-cycle.test.mjs +++ b/scripts/sdlc-cycle.test.mjs @@ -30,9 +30,10 @@ test('both target diagrams have eight stages, eight governed phases and eight hu 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(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.components.some(n => n.id === 'agent' && n.label === 'Autonomous agent' && n.sublabel === 'Human Controlled')); + assert(!d.components.some(n => n.id === 'humans' || n.label === 'Humans')); + assert(!d.connections.some(e => e.id === 'human-direction' || e.from === 'humans' || e.to === 'humans')); + assert.equal(d.connections.length, 24); 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); @@ -41,7 +42,7 @@ test('both target diagrams have eight stages, eight governed phases and eight hu 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); + assert.equal(d.components.length, 17); 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'));