Compare commits

...
Author SHA1 Message Date
jarvis-at-skic b33b59659c fix: label slide 13 as an example weekly allocation
Build and publish Eldorado documentation / build (pull_request) Successful in 47s
2026-10-09 06:49:30 +00:00
jarvis-at-skic 86b1c769a3 Merge pull request 'fix: refine presentation slides 2, 5 and 7' (#44) from fix/slide-2-headings into main
Build and publish Eldorado documentation / build (push) Successful in 46s
2026-10-08 23:37:45 -07:00
jarvis-at-skic 499049eff3 fix: refine presentation slides 2, 5 and 7
Build and publish Eldorado documentation / build (pull_request) Successful in 56s
2026-10-09 06:32:21 +00:00
jarvis-at-skic 46bb8b2b48 Merge pull request 'fix: restore complete Strategy narrative in presentation' (#43) from fix/full-strategy-presentation into main
Build and publish Eldorado documentation / build (push) Successful in 52s
2026-10-08 12:38:16 -07:00
6 changed files with 64 additions and 11 deletions

No files matched your search

@@ -21,7 +21,7 @@ export const slides = [
"id": "starting-point",
"title": "We are not starting from “no AI”.",
"minutes": 2,
"body": "<div class=\"facts\"><div><strong>≈80 → ≈100</strong><span>engineers, by year end</span></div><div><strong>&gt;10</strong><span>teams</span></div><div><strong>Already using AI</strong><span>uneven depth and quality</span></div></div><div class=\"contrast\"><p><b>Assignment facts</b><br>Solo architect → CTO<br>No formal authority over teams</p><p><b>Unknown until discovery</b><br>Stack, tools, process, baselines<br>Capacity and actual bottlenecks</p></div>",
"body": "<div class=\"facts\"><div><strong>≈80 → ≈100</strong><span>engineers, by year end</span></div><div><strong>&gt;10</strong><span>teams</span></div><div><strong>Already using AI</strong><span>uneven depth and quality</span></div></div><div class=\"contrast\"><p>Solo architect → CTO<br>No formal authority over teams</p><p>Stack, tools, process, baselines<br>Capacity and actual bottlenecks</p></div>",
"notes": "These headcount and usage facts are from the assignment, not independent research. The comparison is existing AI-assisted practice, never an invented no-AI baseline. Delivery is a starting hypothesis, not a finding. The documented departmental model is not evidence of actual assignment staffing. Ask about stack and tool/data restrictions in discovery; do not assume familiar clients are in use. Every timeline and proposed allocation in this deck remains subject to agreement.",
"sources": [
"PDF: Context; question 1; final assumptions instruction",
@@ -63,7 +63,7 @@ export const slides = [
"id": "contributors",
"title": "People contribute throughout the cycle.",
"minutes": 1,
"body": `<p class="diagram-intro">Eight separate AI Agents, each human-controlled.</p>` + contributionsFigure + `<div class="rail">Dashed ⇢ contribution from outside the cycle.</div>`,
"body": `<p class="diagram-intro">Eight separate AI Agents, each human-controlled.</p>` + contributionsFigure + `<p class="small">AI Agent = Claude, Cline, ChatGPT or a similar tool, used under human control.</p><div class="rail">Dashed ⇢ contribution from outside the cycle.</div>`,
"notes": "Keep the previous cycle in mind: these eight pairs are its contribution layer, not a second lifecycle or eight central coordinators. Each separate human-controlled AI Agent contributes to its corresponding phase from outside the cycle. The central autonomous agent remains connected to every phase, executing and governing under human direction. Splitting the original topology into two presentation-sized views preserves all eight lifecycle arrows, eight governance spokes and eight contribution arrows without miniaturizing seventeen nodes. Laptop client choice and adapters are implementation options, not a promise of installed support. Human review, product and risk decisions remain necessary.",
"sources": [
"target-operating-model"
@@ -90,7 +90,7 @@ export const slides = [
"id": "learning-loop",
"title": "Connected skills. A repeating learning loop.",
"minutes": 2,
"body": "<div class=\"learning-loop\"><span>Understand work</span><i>→</i><span>Measure + baseline</span><i>→</i><span>Engineer topology</span><i>↓</i><span>Reassess</span><i>←</i><span>Collect results</span><i>←</i><span>Use in real work</span></div><div class=\"rail\">↻ Repeat within each phase. Not six global rollout stages.</div><p class=\"statement\">Triggers → skills → handoffs → acceptance.</p><p class=\"small\">Relationships and cooperation—not merely a catalogue.</p>",
"body": "<div class=\"learning-loop\"><span>Understand work</span><i>→</i><span>Measure + baseline</span><i>↓</i><span>Engineer topology</span><i>→</i><span>Use in real work</span><i>↓</i><span>Collect results</span><i>→</i><span>Reassess</span></div><div class=\"rail\">↻ Repeat within each phase. Not six global rollout stages.</div><p class=\"statement\">Triggers → skills → handoffs → acceptance.</p><p class=\"small\">Relationships and cooperation—not merely a catalogue.</p>",
"notes": "Within every adopted phase repeat the loop: understand the current situation, select relevant metrics and baseline, engineer connected skills, use them in real work, collect outcomes/friction/feedback, then reassess and repeat. Topology defines what exists, how skills relate, when each triggers and how they cooperate. In Delivery trace codebase principles through system logic, tests, builds/packaging and deployment before designing that topology. A code-change skill may hand an exact patch and regression evidence to independent review; its trigger is an eligible change, not an ambient right to act. Governance and Measurement support the whole loop. Qualify revisions before use, and reconsider simpler interventions whenever the evidence says they fit better.",
"sources": [
"roadmap",
@@ -172,7 +172,7 @@ export const slides = [
"id": "capacity",
"title": "One architect. One active live pilot.",
"minutes": 1,
"body": "<div class=\"capacity\" aria-label=\"Proposed weekly allocation: two days hands-on, one evaluation, one relationships, one support and decisions\"><div class=\"pair\">2 days<br><b>Pair + build</b></div><div>1 day<br><b>Evaluate</b></div><div>1 day<br><b>Relationships</b></div><div>1 day<br><b>Decisions + buffer</b></div></div><p class=\"statement\">Support is work.<br>Put it in the budget.</p><p class=\"small\">Proposed capacity envelope—not known company availability.</p>",
"body": "<p>Example weekly allocation for the AI architect</p><div class=\"capacity\" aria-label=\"Proposed weekly allocation: two days hands-on, one evaluation, one relationships, one support and decisions\"><div class=\"pair\">2 days<br><b>Pair + build</b></div><div>1 day<br><b>Evaluate</b></div><div>1 day<br><b>Relationships</b></div><div>1 day<br><b>Decisions + buffer</b></div></div><p class=\"statement\">Support is work.<br>Put it in the budget.</p><p class=\"small\">Proposed capacity envelope—not known company availability.</p>",
"notes": "This five-day allocation is a planning envelope, not a claim about company staffing. Two days are hands-on, one evaluation, one coaching/relationships, one sponsor decisions, support and contingency. Team lead agreement must include review time. A second team begins only when the first is supportable. Offer reusable examples and bounded office hours, not a permanent help desk to more than ten teams. Excess support demand becomes a CTO investment decision or a smaller scope.",
"sources": [
"six-months-roadmap"
@@ -85,15 +85,24 @@ html.print-pdf .toolbar{display:none}html.print-pdf .reveal.deck{top:0;height:10
.deck .journey small,.deck .horizon small{display:block;font-size:17px;color:#805b00;font-weight:900;letter-spacing:.04em;margin-bottom:14px}
.deck .journey b{font-size:31px;display:block;margin-bottom:20px}
.deck .journey span{font-size:25px}.deck .journey i{font-style:normal}
.deck .learning-loop{display:grid;grid-template-columns:1fr 40px 1fr 40px 1fr;align-items:center;gap:12px;margin:32px 0 22px}
.deck .learning-loop span{border:2px solid #14131a;padding:22px 10px;font-size:27px;text-align:center}
.deck .learning-loop i{font-style:normal;text-align:center}.deck .learning-loop i:nth-child(6){grid-column:5}
.deck .learning-loop{display:grid;grid-template-columns:1fr 28px 1fr 28px 1fr 28px 1fr;align-items:center;gap:0 8px;margin:22px 0}
.deck #learning-loop .statement{margin:16px 0 0}.deck #learning-loop .small{margin-top:12px}
.deck .learning-loop span{border:2px solid #14131a;padding:8px;font-size:27px;text-align:center}
.deck .learning-loop i{font-style:normal;text-align:center;line-height:1}
.deck .learning-loop>:nth-child(1){grid-area:1/1}.deck .learning-loop>:nth-child(2){grid-area:1/2}.deck .learning-loop>:nth-child(3){grid-area:1/3}
.deck .learning-loop>:nth-child(4){grid-area:2/3}
.deck .learning-loop>:nth-child(5){grid-area:3/3}.deck .learning-loop>:nth-child(6){grid-area:3/4}.deck .learning-loop>:nth-child(7){grid-area:3/5}
.deck .learning-loop>:nth-child(8){grid-area:4/5}
.deck .learning-loop>:nth-child(9){grid-area:5/5}.deck .learning-loop>:nth-child(10){grid-area:5/6}.deck .learning-loop>:nth-child(11){grid-area:5/7}
.deck .horizon{margin:35px 0;border-left:5px solid #ffc950;padding-left:25px}
.deck .horizon b{font-size:32px;display:block}.deck .horizon .near{background:#e9e9ec;padding:22px;margin-top:28px}
.deck .horizon span{display:block;font-size:25px;margin-top:14px}
.portrait .deck .target-cycle.wide{display:none}.portrait .deck .target-cycle.phone{display:block;height:540px}
.portrait .deck #target h2{font-size:40px}
.portrait .deck #target .small{font-size:24px;margin-top:20px}
.portrait .deck #contributors .small{margin:12px 0}
.portrait .deck #contributors .contribution-grid{gap:6px;margin:14px 0}
.portrait .deck #contributors .contribution-grid>div{padding:4px 8px}
.portrait .deck .contribution-grid{grid-template-columns:1fr 1fr;gap:12px;margin:24px 0}
.portrait .deck .contribution-grid>div{padding:8px;flex-direction:column;justify-content:center;gap:0;font-size:27px}
.portrait .deck .contribution-grid i{transform:rotate(90deg)}.portrait .deck .contribution-grid b{text-align:center}
@@ -101,6 +110,6 @@ html.print-pdf .toolbar{display:none}html.print-pdf .reveal.deck{top:0;height:10
.portrait .deck .journey>div{width:100%;padding:12px 0;border-top-width:4px}
.portrait .deck .journey b{font-size:29px;margin-bottom:8px}.portrait .deck .journey small{margin-bottom:8px}
.portrait .deck .journey i{transform:rotate(90deg);line-height:1}
.portrait .deck .learning-loop{grid-template-columns:1fr 28px 1fr 28px 1fr;gap:6px;margin:30px 0}
.portrait .deck .learning-loop span{font-size:24px;padding:20px 4px}
.portrait .deck .learning-loop{grid-template-columns:1fr 16px 1fr 16px 1fr 16px 1fr;gap:0 3px;margin:30px 0}
.portrait .deck .learning-loop span{font-size:24px;padding:14px 2px}
.portrait .deck .horizon b{font-size:32px}
+3 -1
View File
@@ -1,4 +1,5 @@
const {chromium}=require('playwright');
const staircaseFits=require('./presentation-staircase.cjs');
const assert=require('node:assert/strict');const fs=require('node:fs');
(async()=>{
const base=process.argv[2]||'http://127.0.0.1:43853';const root=base+'/eldorado-v1/documentation/';
@@ -22,7 +23,8 @@ const assert=require('node:assert/strict');const fs=require('node:fs');
for(let i=0;i<23;i++){
assert.equal(await f.evaluate(()=>Reveal.getIndices().h),i);visited.push(await f.evaluate(()=>Reveal.getCurrentSlide().id));
const bad=await f.evaluate(()=>{const r=Reveal.getCurrentSlide().getBoundingClientRect();return [...Reveal.getCurrentSlide().querySelectorAll('svg,text,.journey,.learning-loop,.contribution-grid,h1,h2,p,li,table,.flow,.roles,.timeline')].filter(e=>!e.closest('.notes')&&e.getBoundingClientRect().width>0).filter(e=>{const b=e.getBoundingClientRect();return b.bottom>r.bottom+1||b.right>r.right+1||b.left<r.left-1}).map(e=>e.textContent)});assert.deepEqual(bad,[]);
if(i===4)assert(await f.evaluate(()=>[...document.querySelectorAll('#contributors .contribution-grid>div')].every(e=>{const a=e.querySelector('span').getBoundingClientRect(), arrow=e.querySelector('i').getBoundingClientRect(), b=e.querySelector('b').getBoundingClientRect();return a.bottom<=arrow.top+2&&arrow.bottom<=b.top+2&&Math.abs((a.left+a.right-b.left-b.right)/2)<2&&getComputedStyle(e.querySelector('i')).transform==='matrix(0, 1, -1, 0, 0, 0)'})),'contribution arrows must point down to their own phase');
if(i===6)assert(await f.evaluate(staircaseFits),'staircase aligns each arrow with its intended steps');
if(i===4)assert(await f.evaluate(()=>[...document.querySelectorAll('#contributors .contribution-grid>div')].every(e=>{const a=e.querySelector('span').getBoundingClientRect(), arrow=e.querySelector('i').getBoundingClientRect(), b=e.querySelector('b').getBoundingClientRect();return a.bottom<=arrow.top+2&&arrow.bottom<=b.top+2&&Math.abs((a.left+a.right-b.left-b.right)/2)<2&&getComputedStyle(e.querySelector('i')).transform==='matrix(0, 1, -1, 0, 0, 0)'})),'contribution arrows must point down to their own phase');
await iframe.screenshot({path:`${out}/${viewport.width}-${i+1}.png`});
if(i<22)await p.keyboard.press('ArrowRight');
}
@@ -0,0 +1,14 @@
// Browser-side geometry contract, shared by standalone and embedded acceptance.
module.exports = function staircaseFits() {
const els=[...document.querySelectorAll('#learning-loop .learning-loop>*')];
const b=els.map(e=>e.getBoundingClientRect());
const center=r=>({x:(r.left+r.right)/2,y:(r.top+r.bottom)/2});
const close=(a,b)=>Math.abs(a-b)<2;
return [[0,1,2],[4,5,6],[8,9,10]].every(([a,arrow,c])=>
close(center(b[a]).y,center(b[c]).y)&&close(center(b[a]).y,center(b[arrow]).y)&&
b[a].right<=b[arrow].left+2&&b[arrow].right<=b[c].left+2
)&&[[2,3,4],[6,7,8]].every(([a,arrow,c])=>
close(center(b[a]).x,center(b[c]).x)&&close(center(b[a]).x,center(b[arrow]).x)&&
b[a].bottom<=b[arrow].top+2&&b[arrow].bottom<=b[c].top+2
)&&els.filter(e=>e.tagName==='SPAN').every(e=>e.scrollWidth<=e.clientWidth+1);
};
+3 -1
View File
@@ -1,4 +1,5 @@
const {chromium}=require('playwright');
const staircaseFits=require('./presentation-staircase.cjs');
const fs=require('node:fs'); const assert=require('node:assert/strict');
(async()=>{
const base=process.argv[2]||'http://127.0.0.1:4179'; const root='/eldorado-v1/documentation/';const url=base+root+'presentations/less-prompting-more-shipping/';
@@ -20,7 +21,8 @@ const fs=require('node:fs'); const assert=require('node:assert/strict');
const slide=Reveal.getCurrentSlide(),r=slide.getBoundingClientRect();
return [...slide.querySelectorAll('svg,text,.journey,.learning-loop,.contribution-grid,h1,h2,p,li,td,th,.rail,.gate,.facts,.flow,.roles,.timeline,.capacity,.measure-list,.contrast,.comparison,.choices,.ledger')].filter(e=>!e.closest('.notes')&&e.getBoundingClientRect().width>0).filter(e=>{const b=e.getBoundingClientRect();return b.bottom>r.bottom+1||b.right>r.right+1||b.left<r.left-1||b.top<r.top-1}).map(e=>e.textContent.slice(0,60));
});
if(i===4)assert(await page.evaluate(()=>[...document.querySelectorAll('#contributors .contribution-grid>div')].every(e=>{const a=e.querySelector('span').getBoundingClientRect(), arrow=e.querySelector('i').getBoundingClientRect(), b=e.querySelector('b').getBoundingClientRect();return a.bottom<=arrow.top+2&&arrow.bottom<=b.top+2&&Math.abs((a.left+a.right-b.left-b.right)/2)<2&&getComputedStyle(e.querySelector('i')).transform==='matrix(0, 1, -1, 0, 0, 0)'})),'contribution arrows must point down to their own phase');
if(i===6)assert(await page.evaluate(staircaseFits),'staircase aligns each arrow with its intended steps');
if(i===4)assert(await page.evaluate(()=>[...document.querySelectorAll('#contributors .contribution-grid>div')].every(e=>{const a=e.querySelector('span').getBoundingClientRect(), arrow=e.querySelector('i').getBoundingClientRect(), b=e.querySelector('b').getBoundingClientRect();return a.bottom<=arrow.top+2&&arrow.bottom<=b.top+2&&Math.abs((a.left+a.right-b.left-b.right)/2)<2&&getComputedStyle(e.querySelector('i')).transform==='matrix(0, 1, -1, 0, 0, 0)'})),'contribution arrows must point down to their own phase');
bounds.push({slide:i+1,overflow:bad});
await page.screenshot({path:`${out}/${viewport.width}-slide-${String(i+1).padStart(2,'0')}.png`});
}
+26
View File
@@ -14,6 +14,32 @@ test('deck preserves assignment coverage, 35+15 timing and traceable notes',()=>
for(const id of ['experiment']) assert.match(slides.find(s=>s.id===id).body,/fictional/i);
assert.match(slides.find(s=>s.id==='qualification').notes,/separately authorizes/);
});
test('starting point keeps content without the two removed headings',()=>{
const body=slides.find(s=>s.id==='starting-point').body;
assert.doesNotMatch(body,/Assignment facts|Unknown until discovery/);
for(const text of ['Solo architect → CTO','No formal authority over teams','Stack, tools, process, baselines','Capacity and actual bottlenecks'])assert(body.includes(text));
assert.doesNotMatch(body,/<p><br>/);
});
test('contributors explains human-controlled AI tools below the diagram',()=>{
const body=slides.find(s=>s.id==='contributors').body;
const definition='AI Agent = Claude, Cline, ChatGPT or a similar tool, used under human control.';
assert(body.includes(definition));
assert(body.indexOf(definition)>body.indexOf('contribution-grid'));
assert(body.includes('Dashed ⇢ contribution from outside the cycle.'));
});
test('capacity visibly frames the days as an example weekly allocation',()=>{
const slide=slides.find(s=>s.id==='capacity');
assert.equal(slide.title,'One architect. One active live pilot.');
assert(slide.body.startsWith('<p>Example weekly allocation for the AI architect</p><div class="capacity"'));
for(const text of ['2 days','Pair + build','Evaluate','Relationships','Decisions + buffer','Proposed capacity envelope—not known company availability.']) assert(slide.body.includes(text));
});
test('learning loop staircase preserves the original semantic sequence',()=>{
const body=slides.find(s=>s.id==='learning-loop').body;
const loop=body.split('</div>')[0];
assert.deepEqual([...loop.matchAll(/<span>(.*?)<\/span>/g)].map(m=>m[1]),['Understand work','Measure + baseline','Engineer topology','Use in real work','Collect results','Reassess']);
assert.deepEqual([...loop.matchAll(/<i>(.*?)<\/i>/g)].map(m=>m[1]),['→','↓','→','↓','→']);
assert(body.includes('↻ Repeat within each phase.'));
});
test('build emits local pinned Reveal assets, stable IDs and no production CDN',()=>{
execFileSync(process.execPath,['scripts/build-presentations.mjs']);
const dir='static/presentations/less-prompting-more-shipping'; const html=read(`${dir}/index.html`);