Compare commits

...
Author SHA1 Message Date
jarvis-at-skic 9ac6e2bc6f Merge pull request 'docs: concrete workflow and skill metrics on slide 14' (#46) from docs/slide14-concrete-metrics into main
Build and publish Eldorado documentation / build (push) Successful in 44s
2026-10-09 00:13:50 -07:00
jarvis-at-skic 946b6f1cbb docs: give slide 14 concrete workflow and skill metrics
Build and publish Eldorado documentation / build (pull_request) Successful in 46s
2026-10-09 07:08:51 +00:00
jarvis-at-skic accca0cb1f Merge pull request 'fix: clarify slide 13 weekly allocation' (#45) from fix/slide13-weekly-allocation into main
Build and publish Eldorado documentation / build (push) Successful in 48s
2026-10-08 23:54:18 -07:00
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
jarvis-at-skic c88f4dbc25 fix: align presentation with complete Strategy narrative
Build and publish Eldorado documentation / build (pull_request) Successful in 48s
2026-10-08 19:21:27 +00:00
jarvis-at-skic eea14bf00f Merge pull request 'feat: playable homepage presentation under Understand In Speed' (#42) from feat/homepage-presentation-embed into main
Build and publish Eldorado documentation / build (push) Successful in 52s
2026-10-08 11:41:35 -07:00
9 changed files with 601 additions and 73 deletions

No files matched your search

@@ -1,39 +1,63 @@
# Less Prompting, More Shipping — v1.0.1 # Less Prompting, More Shipping — v1.1.0
An explanation for the CTO and engineering leads: decide how a solo AI Architect should invest the first six months. The original `AI_Architect_Test_Task.pdf` governs the assignment content. Read with the same-build Strategy: **Target → Roadmap → 6 Months Target → 6 Months Roadmap → Beyond 6 Months**. The six-month contribution does not replace the long-term human-controlled autonomous SDLC destination or authorize its execution. The source map records exact source-document hashes, the historical long-term/assignment origins and correction authority; it does not mislabel a historical revision as current. This is not a second Strategy landing page. An explanation for the CTO and engineering leads: understand the intended destination and decide how a solo AI Architect should contribute in the first six months. The original `AI_Architect_Test_Task.pdf` supplies the assumed context, four questions and 50-minute total. The same-build Strategy supplies the connected narrative: **Target → Roadmap → 6 Months Target → 6 Months Roadmap → Beyond 6 Months**. The six-month contribution neither replaces the long-term human-controlled autonomous SDLC nor authorizes it.
## Story and timing
23 slides: 21 main slides / **35 minutes**, one **15-minute Q&A**, one **zero-minute reference appendix**. EXP-01 is now one two-minute illustration, not the spine of the strategy. Its detailed fictional sample, extension caps and stop ledger remain in speaker notes and the canonical linked Strategy packet.
The table is the revised presentation allocation. The PDF prescribes 50 minutes total, not this split. The six-month Strategy page still contains an earlier proposed outline; its exact subsection timings are not claimed to match this destination-first deck. No Strategy page was rewritten to accommodate the presentation.
| Slide | Minutes / elapsed | Main message | Strategy evidence (canonical slug) |
| --- | --- | --- | --- |
| 1 | 1 / 0–1 | Destination and first contribution | target-operating-model; roadmap; six-months-target; PDF |
| 2 | 2 / 1–3 | Existing uneven AI; solo CTO-reporting role; unknowns | six-months-target; PDF Context/Q1/assumptions |
| 3 | 1 / 3–4 | Accepted output, not faster drafts | six-months-target; baseline; measurement |
| 4 | 3 / 4–7 | Intended SDLC cycle and central human-controlled agent | target-operating-model |
| 5 | 1 / 7–8 | Eight outside human-controlled contributors | target-operating-model |
| 6 | 2 / 8–10 | Delivery-first adoption, then other phases, then separate autonomy | roadmap; target-operating-model |
| 7 | 2 / 10–12 | Connected skills and repeating within-phase learning | roadmap; stage-01-skills-adoption |
| 8 | 1 / 12–13 | First-six-month building block toward Target | six-months-target; target-operating-model |
| 9 | 1 / 13–14 | Influence beside work, no team authority | six-months-roadmap |
| 10 | 2 / 14–16 | Months 1–2: discover, baseline, agree | six-months-roadmap; baseline |
| 11 | 2 / 16–18 | Months 3–4: qualify, test, compare | six-months-roadmap |
| 12 | 2 / 18–20 | Months 5–6: conditional transfer and handover | six-months-roadmap; six-months-target |
| 13 | 1 / 20–21 | Solo capacity, one live pilot, funded support | six-months-roadmap |
| 14 | 2 / 21–23 | Acceptance, burden, quality and total costs | measurement; six-months-roadmap |
| 15 | 2 / 23–25 | Misleading signals and causal limits | measurement; six-months-roadmap |
| 16 | 2 / 25–27 | Qualification is not pilot permission | skills-quality; six-months-roadmap |
| 17 | 2 / 27–29 | Fictional EXP-01: cheapest fit, hold, then stop | six-months-roadmap |
| 18 | 1 / 29–30 | Realistic month-six evidence portfolio | six-months-target; six-months-roadmap |
| 19 | 2 / 30–32 | Evidence-led investment toward established destination | stage-02-autonomous-agent; target-operating-model; roadmap; six-months-target |
| 20 | 2 / 32–34 | Separate bounded authority, stop and human takeover | stage-02-autonomous-agent; target-operating-model |
| 21 | 1 / 34–35 | First CTO alignment and four answers | six-months-roadmap; PDF Q1–4 |
| 22 | 15 / 35–50 | Q&A | PDF Format; six-months-target |
| 23 | 0 / optional | Linked references, outside the main talk | PDF; all five Strategy pages plus measurement |
PDF Q1 **What you do** → slides 2, 9–13. Q2 **How you measure it** → 14–17. Q3 **What you achieve** → 8 and 18. Q4 **What comes next** → 4–7 establish the destination; 19–20 explain evidence-led progression. Scale/growth/uneven AI use are assignment facts, not independently measured company facts. Stack, providers, data policy, task supply, partner capacity and bottlenecks remain unknown or hypotheses, explained on slide 2 and in discovery notes.
## Source and build ## Source and build
- `slides.mjs`: 17 talk slides (35 minutes), one 15-minute discussion slide, one zero-minute reference appendix. Every slide has narration, timing and source references. EXP-01 remains fictional throughout. - `slides.mjs` is the single editorial source for standalone and homepage. Every slide has section, track, timing, narration and source references. Notes are public HTML, never confidential.
- `theme.css`: Lato, gold #ffc950, charcoal #14131a/#1f1f29 and light surfaces, derived from `src/css/custom.css`. Separate standalone document prevents Reveal/global CSS leaking into the portal. Portrait re-composes the same content, landscape retains the room presentation. - `target-figure.mjs` provides two presentation-sized views of the original topology. Slide 4 preserves the eight ordered cycle edges and eight governance spokes, including Releases → Scope. Slide 5 preserves all eight external `code-* → phase` contribution edges. There is one central autonomous agent, not a separate Humans node or a reporting hierarchy. Tests compare all three edge sets with the original diagram JSON; desktop and phone are recomposed, not shrunk documentation screenshots.
- `runtime.js`: Reveal initialization, reduced motion, portrait/orientation adaptation and accessible toolbar. - `theme.css` preserves portal Lato/gold/charcoal/light surfaces and isolated standalone styles. Distinct cycle, contribution layer, staged progression, learning loop and horizon compositions support the story.
- `scripts/build-presentations.mjs`: generates `static/presentations/less-prompting-more-shipping/`, including source-map.json and locally copied, exact-pinned Reveal.js 5.2.1 + notes plugin, Lato fonts and licenses. Generated output is ignored, rebuilt before both start and production build. No production CDN. The existing pipeline runs content tests and verifies the generated route and homepage entry. - `runtime.js` is unchanged: Reveal, reduced motion, responsive portrait layout, toolbar, isolated embedded focus/URL and no autoplay.
- `scripts/build-presentations.mjs` generates the same canonical route, exact-pinned local Reveal.js 5.2.1, notes plugin, Lato assets/licenses and `source-map.json`. The map includes slide IDs/sections/tracks/minutes/sources, four-question coverage, exact Strategy and topology source hashes, and provenance without claiming historical revisions are current. No runtime CDN.
From repository root: `pnpm install --frozen-lockfile`, `pnpm build`, `pnpm verify:build`. Serve `build/` under `/eldorado-v1/documentation/` with a static server. The dedicated route is `/eldorado-v1/documentation/presentations/less-prompting-more-shipping/`. Relative links/assets also work if the site base path changes. Homepage entry uses a normal document navigation, not a React-router handoff. From repository root: `pnpm install --frozen-lockfile`, `pnpm test`, `pnpm typecheck`, `pnpm build`, `pnpm verify:build`. Serve `build/` under `/eldorado-v1/documentation/` with a static server. The canonical route remains `/eldorado-v1/documentation/presentations/less-prompting-more-shipping/`. The homepage's **Understand In Speed** embeds that generated document, not a duplicated slide source. Existing Organization, Strategy, homepage component and runtime sources are preserved.
## Present ## Present and verify
Use arrows or touch swipes. Esc/Overview shows the slide grid. F/Fullscreen enters fullscreen. S/Notes opens Reveal's speaker window (allow popups); notes require HTTP(S), not file://. Notes are not confidential: they ship in HTML. Named deep links, e.g. `#/qualification`, survive refresh. Autoplay is off. Reduced-motion preference disables transitions. Arrows/touch navigate. Esc/Overview shows the grid. F/Fullscreen and S/Notes work standalone; embedded focus stays within its own document and parent URL is unchanged. Notes need HTTP(S) and popups. Named deep links such as `#/target` and `#/qualification` survive refresh. Print uses `?print-pdf`: Chromium, landscape, no margins, background graphics. Export has **23 pages**, without notes. No unsolicited PDF/PPTX/ZIP is published.
Print opens `?print-pdf`: use Chromium, landscape, no margins and background graphics. The default export has 19 slides without speaker notes. No PDF/PPTX/ZIP is added to the public site. Printing is secondary to the interactive presentation. `pnpm test:presentation <base>` covers 23 slides at desktop, portrait and landscape (69 views), bounds, errors, links, hash/refresh, keyboard, touch, overview, notes popup, fullscreen, homepage handoff and 23-page print layout. `pnpm test:homepage-embed <base>` covers 23 slides at four widths (92 views), focus/scroll/URL isolation, touch, fullscreen, unsupported-fullscreen escape, Tab exit, themes and reduced motion. Outputs are ordered individual PNGs and JSON in `.cache/presentation/` and `.cache/homepage-embed/`; inspect real pixels, not just geometry. Set `PLAYWRIGHT_CHROMIUM_EXECUTABLE` for an installed browser.
## Verify Local Docusaurus serve on Node 26 redirects WOFF2 paths with a trailing slash in this environment. Use a regular prefix-correct static server for production-equivalent font verification; missing-font screenshots are not acceptable evidence.
`pnpm test:presentation http://127.0.0.1:4180` against a prefix-correct static server runs 19 slides at desktop, portrait and landscape, checks bounds/errors/local links, refresh/hash, keyboard, touch, overview, notes popup, fullscreen, homepage integration and 19-page print layout. It writes ordered, individual PNGs plus JSON and a print diagnostic to `.cache/presentation/`. Set `PLAYWRIGHT_CHROMIUM_EXECUTABLE` if using an installed Chromium rather than Playwright's default binary. Inspect every slide individually after the final build. Local Docusaurus serve on Node26 incorrectly redirects WOFF2 paths with a trailing slash in this environment; use a regular static server for production-equivalent font verification, not missing-font screenshots. Official runtime references: https://revealjs.com/installation/, https://revealjs.com/speaker-view/, https://revealjs.com/pdf-export/. The pinned package is intentional; runtime API compatibility is judged against 5.2.1, not latest-version assumptions.
Official implementation references: https://revealjs.com/installation/, https://revealjs.com/speaker-view/, https://revealjs.com/pdf-export/. The pinned 5.2.1 package is intentional; consult its runtime for API compatibility rather than assuming the current documentation's latest-version distribution paths. License is MIT; notes is bundled from `plugin/notes/notes.js`.
## Content traceability
PDF Q1 → slides 2–8 (context, influence, months and capacity).
PDF Q2 → slides 9–14 (balanced measures, misleading signals, one example and two decision states).
PDF Q3 → slide 15 (realistic observable change and evidence).
PDF Q4 → slide 16 (conditional choices beyond six months).
Opening/alignment → slides 1 and 17; discussion → 18; references → 19.
The generated source-map.json gives each slide's exact Strategy page and PDF section. Slides 5–7 simplify the six-month/roadmap diagrams; slides 3, 11–14 simplify Stage01 handoff/qualification/feedback without changing human approval or recovery semantics. No screenshots of documentation diagrams are used.
## Boundaries ## Boundaries
No company gains, approved thresholds, staffing commitments, tool inventory or deployed autonomy are claimed. The numerical example reproduces EXP-01 rather than inventing a second example. The title is mild self-aware humor, not a claim that fewer prompts intrinsically improve output. No guaranteed benefits, approved thresholds, staffing commitments or deployed autonomy. The intended long-term destination is explicit, while its timing and authority remain unapproved. First-six-month failure or a cheaper deterministic intervention is compatible with that direction. Human product, risk and release authority is retained. Skills carry knowledge and verification, not permission.
Initial production audit after adding Reveal: 2 critical, 2 high, 2 moderate (uuid, http-cache-semantics, braces, postcss-selector-parser, tinypool). Same inherited counts as the parent; Reveal itself has no runtime dependencies. This is not risk acceptance or a clean security audit. This branch is a review candidate, not a publication. The dependent reviewer owns merge, exact-main CI and deployed verification. Dependency manifests are unchanged. Previously recorded production audit: 2 critical, 2 high, 2 moderate; this presentation revision is neither remediation nor security-risk acceptance. Chromium viewport testing is not Safari/Firefox, physical-device or full assistive-technology certification. This branch is a review candidate; the dependent reviewer owns merge, exact-main CI and deployed verification.
@@ -1,23 +1,334 @@
// Editorial source: concise visible story + spoken argument + traceable references. // Single editorial source for standalone and homepage. Planned narration: 35 + 15 minutes.
const s = (id, title, minutes, body, notes, sources, kind='') => ({id,title,minutes,body,notes,sources,kind}); import {cycleFigure,contributionsFigure} from './target-figure.mjs';
export const slides = [ export const slides = [
s('opening','Less Prompting,<br>More Shipping',1,`<p class="subtitle">The AI Architect’s First Six Months</p><p class="thesis">Improve accepted engineering work.<br>Not the number of times we ask AI.</p><p class="small">Proposed strategy · 35 minutes + 15 minutes Q&amp;A</p>`, 'Open with the outcome, not a tool purchase. The title is a reminder to measure useful work, not an instruction to minimize prompts. More careful prompting may be exactly what good work needs. My proposal is to earn one evidence-backed improvement, make its costs visible, and stop what does not help. Walk through what I do, how I measure, what month six looks like and what comes next.', ['PDF: Format; Context; questions 1–4','six-months-target'], 'dark'), {
s('starting-point','We are not starting from “no AI”.',2,`<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>`, '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.', ['PDF: Context; question 1; final assumptions instruction','six-months-target']), "id": "opening",
s('north-star','A faster draft is not a shipped outcome.',2,`<div class="flow"><span>Intent</span><i>→</i><span>Change + tests</span><i>→</i><span>Independent acceptance</span></div><div class="rail">Existing release authority stays with people.</div><p class="statement">Less rework. Sound quality.<br>Understand the total burden.</p><p class="small">If the bottleneck is CI or review capacity, fix that—not the prompt count.</p>`, 'Trace a change through acceptance and its existing release route. An agent can shorten drafting and still make reviewers work harder. The outcome must survive independent acceptance, defect follow-up and total-cost accounting. Observe why work comes back rather than assume more output from the model means more output from engineering. Flaky tests, unclear scope or scarce reviewers may make a non-AI intervention the right investment.', ['six-months-target','baseline','measurement']), "title": "Less Prompting,<br>More Shipping",
s('influence','Influence is earned beside the work.',2,`<div class="roles"><div><b>CTO</b><span>Sponsor access<br>Resolve priority trade-offs</span></div><div class="gold"><b>Architect</b><span>Pair, build, evaluate<br>Bring evidence—not mandates</span></div><div><b>Willing team</b><span>Agree contribution<br>Own acceptance and upkeep</span></div></div><p class="statement">An invitation with an exit.<br>Not a rollout disguised as a favor.</p>`, 'Meet leads, developers and reviewers across contrasting workflows before recruiting one willing team. Show a concrete example to a skeptic and invite them to judge it without requiring enrollment. Agree a short weekly team check-in and a monthly CTO decision review. Record participant and reviewer effort: it is not free labor. If priorities conflict, ask the CTO to choose a trade-off rather than use sponsorship as a compliance escalation. Actual approvers must be named before a pilot.', ['six-months-roadmap','six-months-roadmap']), "minutes": 1,
s('months-one-two','Months 1–2 / Earn the right to test.',3,`<div class="timeline"><div><b>01 · Discover</b><p>Trace real changes.<br>Rank friction and evidence gaps.</p><span>Output: current-work map</span></div><div><b>02 · Agree</b><p>One willing team.<br>Baseline + smallest intervention.</p><span>Output: bounded experiment packet</span></div></div><div class="gate">Decision 1 → Fund one experiment—or hold.</div><p class="small">No partner, reliable checks or lawful evidence → no live pilot.</p>`, 'In month one agree expectations and access with the CTO, pair on contrasting workflows and trace repository principles, system logic, tests, builds and deployments. Rank bottlenecks, not teams. Month two observes a prospective baseline and compares context, coaching, test feedback, deterministic automation and skills. Agree task eligibility, acceptance, evidence, people, spend/effort limits and a stop date. The experiment packet can be one worksheet plus existing records. Discovery may need to continue; the calendar does not waive prerequisites.', ['six-months-roadmap','baseline']), "body": "<p class=\"subtitle\">The destination—and the first six months toward it</p><p class=\"thesis\">Improve accepted engineering work.<br>Not the number of times we ask AI.</p><p class=\"small\">Proposed strategy · 35 minutes + 15 minutes Q&amp;A</p>",
s('months-three-four','Months 3–4 / Test, then decide.',3,`<div class="timeline"><div><b>03 · Work alongside</b><p>Build and independently qualify.<br>Pair on bounded real work.</p><span>Output: failures + reproducible examples</span></div><div><b>04 · Compare</b><p>Reconcile outcomes and burden.<br>Include pending and abandoned work.</p><span>Output: retain / change / hold / stop</span></div></div><div class="gate">Decision 2 → Keep only what the evidence supports.</div><p class="small">Missing follow-up is “unknown”, not “all clear”.</p>`, 'Qualification precedes exposure to real work; actual pilot permission is a separate human decision. During month three I pair and collect both benefits and transferred work. Month four compares matured cohorts with the reviewer, records task mix and concurrent changes, and gives the owner and CTO a recommendation. Unsafe work stops immediately. Sparse tasks or missing follow-up make the result inconclusive. Only an explicitly approved bounded extension can continue; otherwise narrow or stop. Do not silently convert a feasibility exercise into a rollout.', ['six-months-roadmap','six-months-roadmap']), "notes": "Open with the outcome, not a tool purchase. The title is a reminder to measure useful work, not an instruction to minimize prompts. More careful prompting may be exactly what good work needs. My proposal is to earn one evidence-backed improvement, make its costs visible, and stop what does not help. Walk through what I do, how I measure, what month six looks like and what comes next. Start with the long-term Target and broad Roadmap, then bound the first-six-month contribution. The five Strategy pages organize this story; the assignment supplies the four questions and total time.",
s('months-five-six','Months 5–6 / Transfer only if earned.',2,`<div class="timeline"><div><b>05 · Selective transfer</b><p>Champion + backup.<br>Check a second team’s fit.</p><span>Only with capacity and funded upkeep</span></div><div><b>06 · Evidence review</b><p>Team operates without daily help.<br>CTO chooses the next investment.</p><span>Owned workflow—or documented stop</span></div></div><p class="statement">New scope → new baseline.<br>No automatic company-wide rollout.</p>`, 'A second team is conditional: willingness, different task mix and support capacity can all change the answer. Keep improving the first workflow if transfer is premature. Hand over a reproducible example, support and recovery instructions to an actual owner and backup. Test operation without my daily assistance rather than treating training attendance as handover. Month six must show limits and stopped work as well as retained value. The CTO decides what is worth funding next.', ['six-months-roadmap','six-months-target']), "sources": [
s('capacity','One architect. One active live pilot.',2,`<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>`, '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.', ['six-months-roadmap']), "PDF: Format; Context; questions 1–4",
s('measures','Three measures. One decision.',3,`<div class="measure-list"><div><b>Accepted work</b><span>Accepted / all matured eligible starts</span></div><div><b>Review + rework</b><span>Comparable effort, including shifted burden</span></div><div><b>Escaped defects</b><span>Severity and complete follow-up</span></div></div><div class="rail">Alongside: setup, support, upkeep and tool cost. Critical effects stop work.</div><p class="small">Task / PR / CI / defect links + a small effort record; no individual league tables.</p>`, 'Use a small balanced set matched to the mechanism, not all sixteen optional metric contracts. Predeclare eligibility, maturity horizons, denominator and follow-up. Register every eligible task start, including failures, abandoned work and unresolved matured starts; pending tasks stay separate. Link tasks to exact PR/CI acceptance and defect records, with a minimal effort log. Record checked reasons for returns, such as missing regression evidence. Agree access, purpose and retention; avoid raw prompt collection and individual performance ranking. Show total setup and recurring cost beside outcomes. If linkage is incomplete, hold the claim.', ['measurement','six-months-roadmap']), "six-months-target",
s('misleading','A dashboard can be confidently wrong.',2,`<div class="contrast traps"><p><b>Tempting signal</b><br>More PRs or generated lines<br>Shorter PR elapsed time<br>Higher acceptance rate<br>No defects recorded</p><p><b>Question before believing it</b><br>Useful work—or smaller slices?<br>Less effort—or less waiting?<br>Same task mix and denominator?<br>Enough follow-up and linkage?</p></div><p class="statement">AI usage is diagnostic.<br>It is not the score.</p>`, 'Invocation counts, licenses and positive sentiment can help diagnose reach or friction, but are not productivity outcomes. Acceptance changes may reflect selection and learning; stratify by complexity and reviewer availability and record concurrent model/tool/CI changes. Elapsed time is not engineer hours. Missing quality records are not zero defects. Small descriptive samples cannot establish causal ROI; agree uncertainty and precision rules before collecting evidence for a promotion claim. Do not annualize a tiny difference into cash savings.', ['measurement','six-months-roadmap']), "target-operating-model",
s('experiment','EXP-01 / Start cheaper than a platform.',2,`<p class="fiction">Fictional teaching example · not Eldorado data or approval</p><div class="flow"><span>Review returns:<br>missing test evidence</span><i>→</i><span>Test map +<br>checklist first</span><i>→</i><span>Skill only if<br>context loss persists</span></div><p class="statement">Small bug fixes. One repository.<br>Current AI practice is the comparator.</p><p class="small">Exclude secrets, personal data, migrations and production permissions.</p>`, 'Keep one example from baseline to decision. Suppose changes repeatedly lack regression evidence. Compare a repository test map plus review checklist against packaging the same guidance as a skill; the cheaper checklist wins if it performs as well. A skill carries reusable instructions and verification, not authority. Freeze a small non-urgent bug-fix scope, one willing team and one qualified client/model tuple. The full fictional packet includes explicit real-use blanks for people, dates, immutable references, sources and data approval. Those blanks are not permission.', ['six-months-roadmap']), "roadmap"
s('qualification','“It worked once” is not a release gate.',2,`<div class="flow"><span>Pin candidate<br>and environment</span><i>→</i><span>Independent<br>qualification</span><i>→</i><span>Separate<br>pilot permission</span></div><div class="contrast"><p><b>Try to break it</b><br>Wrong task · injected instruction<br>Missing tests · recovery</p><p><b>First revision</b><br>No approved prior skill = N/A<br>Remove + reload → current practice</p></div><div class="rail">Failed mandatory safety checks → HOLD. An average cannot override them.</div>`, 'The author cannot approve their own evidence or deployment. Test representative work, unrelated-task decline, injected instructions to bypass review, missing-test escalation, and removal/reload recovery. These examples are not a complete risk-tier evaluation suite. A real independent reviewer approves a risk-appropriate design and inspects all results. First-revision regression against an approved skill is N/A, not a fake pass; prove recovery to declared existing AI-assisted practice. The actual workflow approver separately authorizes the exact revision/client, cohort, window, expiry and effects. Security/data boundaries need their actual owners. Later revision changes return to qualification.', ['six-months-roadmap','skills-quality']), ],
s('inconclusive','First review / Do not promote this result.',2,`<p class="fiction">EXP-01 · fictional observations · not company performance</p><table><thead><tr><th>Evidence</th><th>Baseline</th><th>Pilot, first review</th></tr></thead><tbody><tr><td>Accepted / matured starts</td><td>8 / 12</td><td>9 / 12</td></tr><tr><td>Effort records</td><td>12 / 12</td><td>9 / 12 only</td></tr><tr><td>Mature defect follow-up</td><td>8 / 8 accepted</td><td>6 / 9 accepted</td></tr></tbody></table><div class="gate">INCONCLUSIVE → Hold expansion. Finish evidence—or stop.</div><p class="small">Three later starts remain pending. Missing evidence is not zero cost.</p>`, 'The apparent nine versus eight accepted is not a demonstrated gain. Baseline has two failed, one abandoned and one unresolved; pilot has one of each. Three later starts have not matured and stay out of the matured denominator. At first review pilot effort median is 35 minutes among observed rows only, not the whole cohort. One non-severe baseline defect is known; pilot defect follow-up is incomplete. A tiny sample, different mix and learning also limit inference. The fictional owner may authorize one two-week evidence-only extension with no new starts, at most four architect hours, two reviewer hours and EUR25 additional spend. If reconciliation cannot finish, stop rather than keep extending.', ['six-months-roadmap']), "kind": "dark",
s('stop','A useful answer can be “stop this one”.',2,`<p class="fiction">EXP-01 · fictional reconciled burden · not a causal productivity estimate</p><div class="comparison"><div><strong>30 min</strong><span>Baseline median review / rework</span></div><span class="versus">→</span><div><strong>40 min</strong><span>Pilot median, all 12 records</span></div></div><p class="statement">The predeclared burden guardrail is breached.</p><div class="rail">Stop candidate → verify recovery → keep useful checklist → requalify any revision</div>`, 'Assume reconciliation finds a 40-minute median against 30 baseline for comparable work, with reviewers tracing extra effort to checking generated tests. This breaches the fictional no-increase burden guardrail even with nine accepted tasks. It is sufficient for a local stop decision, not statistical proof the intervention fails everywhere. Remove/reload and verify current-practice recovery; preserve evidence and useful test map/checklist. Return failure cases to the author. Retain would require different evidence: complete comparable outcomes and costs, acceptable quality/burden, agreed precision, independent acceptance and funded upkeep. A new revision must requalify. Critical unauthorized effects stop immediately, not at the scheduled review.', ['six-months-roadmap']), "section": "Why change",
s('month-six','Month six / An evidence portfolio, not a victory lap.',2,`<div class="ledger"><div><b>Visible change</b><b>Evidence to ask for</b></div><div><span>One workflow understood</span><span>Map + baseline + explicit gaps</span></div><div><span>Retained practice—or justified stop</span><span>Comparable outcomes + costs + limits</span></div><div><span>Less dependence on the architect</span><span>Owner + backup + recovery rehearsal</span></div></div><p class="small">Proposed achievable picture. No guaranteed savings, headcount reduction or org-wide uplift.</p>`, 'Commit to activities I can drive: discovery, agreement, hands-on support, reproducible evidence and clear decisions. Do not promise a positive effect outside my control. A realistic month-six organization has one bounded workflow learned from, transparent limitations, some reusable examples and an owner if anything is retained. A second willing team may have a new baseline, not a blanket rollout. If experiments stop, explain what was ruled out, what remains useful and why the next investment changes. Independent source-linked evidence, not a polished demo or attendance count, backs the picture.', ['six-months-target','six-months-roadmap']), "track": "main"
s('beyond','Beyond six months / Choose, do not graduate.',2,`<div class="choices"><div><b>Deepen</b><p>Coaching, context or deterministic tooling where friction remains.</p></div><div><b>Transfer</b><p>Only with repeatable value, local fit and supported ownership.</p></div><div><b>Toward autonomy</b><p>Separate authority case, containment and human takeover.</p></div></div><p class="statement">Long-term vision. Separate authority.<br>Not a month-six promise.</p>`, 'The next quarter may deepen the existing workflow or stop expansion entirely. Skills remain optional; no catalog or central control platform is a prerequisite. Transfer needs new-scope baseline and local capacity. Consider bounded autonomy only if it solves an evidenced bottleneck and controls are proven: exact-artifact approvals, scoped identity, idempotency, audit, independent stop and takeover. People retain product, risk and release decisions. The long-term destination remains human-directed, guided and reviewed autonomous SDLC. These six months contribute toward that vision, not replace it; they do not promise its timing or authorize its execution. The CTO chooses investment based on the evidence, not an inevitable maturity staircase.', ['stage-02-autonomous-agent','target-operating-model','roadmap','six-months-target']), },
s('alignment','The first CTO conversation',1,`<ol class="asks"><li>Which outcome is worth improving first?</li><li>Who can volunteer time—and independent review?</li><li>What data, risk and effort limits apply?</li><li>When will we decide to continue or stop?</li></ol><p class="statement">Sponsor the learning.<br>Do not pre-approve the answer.</p>`, 'Close with concrete alignment, not a shopping list. Ask the CTO to agree an outcome, access to willing teams, independent review capacity, risk/data boundary and decision cadence. Agree success and stop criteria before collecting favorable anecdotes. We have covered the four assignment questions: action, measurement, realistic six-month evidence and conditional next investment. Transition to the fifteen-minute discussion. If time runs short, skip detail in narration rather than the decision and its limits.', ['PDF: questions 1–4','six-months-roadmap'], 'dark'), {
s('discussion','Q&A / What would change your mind?',15,`<p class="subtitle">15 minutes for the hard questions.</p><div class="discussion"><p>No willing team?</p><p>Too little evidence?</p><p>A cheaper non-AI fix?</p></div><p class="small">The proposed plan can change. The evidence standard should not.</p>`, 'Reserve the full fifteen minutes. If no team volunteers, revisit the problem and sponsor trade-offs rather than conscript people. If evidence is sparse, narrow the question, explicitly authorize a bounded evidence-completion window or stop. If deterministic tooling is better, choose it. Discuss the company’s real constraints rather than pretend the fictional example estimates company benefit. The next slide provides linked sources for follow-up, not additional spoken content.', ['PDF: Format','six-months-target'], 'dark'), "id": "starting-point",
s('references','References / Follow the evidence.',0,`<ul class="references"><li>AI Architect Test Task · Eldorado.gg<br><span>Context, four questions, assumptions, 50-minute format</span></li><li><a href="../../strategy/target-operating-model/">Long-term Target</a> · <a href="../../strategy/roadmap/">Roadmap →</a></li><li><a href="../../strategy/six-months-target/">6 Months Target →</a></li><li><a href="../../strategy/six-months-roadmap/">6 Months Roadmap →</a></li><li><a href="../../strategy/six-months-roadmap/#exp-01-a-small-decision-ready-example">EXP-01 packet and decision limits →</a></li><li><a href="../../strategy/measurement/">Measurement definitions and safeguards →</a></li><li><a href="../../strategy/stage-02-autonomous-agent/">Beyond 6 Months →</a></li></ul>`, 'Appendix, zero planned talk time. The original assignment is the supplied AI_Architect_Test_Task.pdf. The source-reference map in this presentation directory records every slide against the PDF and reviewed Strategy. The deck does not reproduce the assignment file publicly. EXP-01 remains entirely fictional; its budget, medians, samples and outcomes are teaching devices. Official Reveal documentation consulted: installation, speaker-view and pdf-export on revealjs.com. All runtime assets are pinned and bundled locally.', ['PDF: complete assignment','six-months-target','six-months-roadmap','six-months-roadmap','measurement','stage-02-autonomous-agent']) "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>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",
"six-months-target"
],
"kind": "",
"section": "Why change",
"track": "main"
},
{
"id": "north-star",
"title": "A faster draft is not a shipped outcome.",
"minutes": 1,
"body": "<div class=\"flow\"><span>Intent</span><i>→</i><span>Change + tests</span><i>→</i><span>Independent acceptance</span></div><div class=\"rail\">Existing release authority stays with people.</div><p class=\"statement\">Less rework. Sound quality.<br>Understand the total burden.</p><p class=\"small\">If the bottleneck is CI or review capacity, fix that—not the prompt count.</p>",
"notes": "Trace a change through acceptance and its existing release route. An agent can shorten drafting and still make reviewers work harder. The outcome must survive independent acceptance, defect follow-up and total-cost accounting. Observe why work comes back rather than assume more output from the model means more output from engineering. Flaky tests, unclear scope or scarce reviewers may make a non-AI intervention the right investment.",
"sources": [
"six-months-target",
"baseline",
"measurement"
],
"kind": "",
"section": "Why change",
"track": "main"
},
{
"id": "target",
"title": "Target / Autonomous SDLC.",
"minutes": 3,
"body": cycleFigure + `<p class="diagram-legend">Solid → lifecycle · Dotted ⇢ executes and governs</p><p class="small">Humans direct, guide and review. Not deployed or promised in six months.</p>`,
"notes": "This is the intended destination, not deployed software, an agreed date or a six-month promise. Read the solid cycle clockwise from Scope: Architecture, UI/UX, Planning, Delivery, UAT, Security, Releases, then evidence returns to Scope. The single central autonomous agent executes and governs every phase, not merely routing tickets. Dotted spokes connect it to all eight phases; people direct, guide and review throughout. There is deliberately no separate Humans node or organizational reporting hierarchy. This view isolates the lifecycle and governance relationships for readability; the next slide restores all eight outside human-controlled contributors. Neither diagram assigns approval roles or grants permissions.",
"sources": [
"target-operating-model"
],
"kind": "",
"section": "Target",
"track": "main"
},
{
"id": "contributors",
"title": "People contribute throughout the cycle.",
"minutes": 1,
"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"
],
"kind": "",
"section": "Target",
"track": "main"
},
{
"id": "roadmap",
"title": "Roadmap / Build dependable work first.",
"minutes": 2,
"body": "<div class=\"journey\"><div><small>STAGE 1 · HUMAN + AI</small><b>Delivery first</b><span>Standardize connected skills<br>and working practices</span></div><i>→</i><div><small>STAGE 1 · EXPAND</small><b>Other SDLC phases</b><span>Order undecided<br>Delivery keeps improving</span></div><i>⇢</i><div><small>STAGE 2 · SEPARATE AUTHORITY</small><b>Autonomous capabilities</b><span>Proven practices + controls<br>toward the Target</span></div></div><div class=\"rail\">Humans direct, guide and review throughout.</div><p class=\"small\">A strategic progression—not a six-month schedule or automatic graduation.</p>",
"notes": "The Roadmap has two broad stages. First standardize skills and practices in human plus AI Agent work, starting with Delivery. Then expand across other SDLC phases, with their remaining order explicitly undecided. This adoption order is different from the Target lifecycle sequence. Delivery continues improving while other phases join. Proven skills, measurements and working practices provide a foundation for the future autonomous agent, but adoption volume never grants authority. Stage one is useful in its own right. Evidence may support coaching, context or deterministic tooling rather than a skill for a particular bottleneck; that practical choice contributes to dependable work rather than cancelling the long-term destination.",
"sources": [
"roadmap",
"target-operating-model"
],
"kind": "",
"section": "Roadmap",
"track": "main"
},
{
"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>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",
"stage-01-skills-adoption"
],
"kind": "",
"section": "Roadmap",
"track": "main"
},
{
"id": "six-month-target",
"title": "6 Months Target / One credible contribution.",
"minutes": 1,
"body": "<div class=\"horizon\"><div><small>LONG-TERM DESTINATION</small><b>Human-controlled autonomous SDLC</b></div><div class=\"near\"><small>FIRST SIX MONTHS</small><b>One workflow understood and improved—or stopped with evidence</b><span>One willing partner · reusable practice · owned upkeep</span></div></div><p class=\"statement\">Earn a dependable building block.<br>Do not promise the entire destination.</p>",
"notes": "Separate the horizons without making them opposing stories. A credible six-month contribution is a current-work map, an agreed comparison, a bounded intervention and transparent evidence, with a team owner if useful practice is retained. One workflow with one willing team is already meaningful for a solo architect; a second team is conditional on fit and support. These are proposed outcomes, not known company results or guaranteed gains. If an intervention fails, the useful result is an explained stop, retained learning and a better next investment. The autonomous SDLC remains the destination, with no claim that it can or should be delivered in six months.",
"sources": [
"six-months-target",
"target-operating-model"
],
"kind": "",
"section": "6 Months Target",
"track": "main"
},
{
"id": "influence",
"title": "Influence is earned beside the work.",
"minutes": 1,
"body": "<div class=\"roles\"><div><b>CTO</b><span>Sponsor access<br>Resolve priority trade-offs</span></div><div class=\"gold\"><b>Architect</b><span>Pair, build, evaluate<br>Bring evidence—not mandates</span></div><div><b>Willing team</b><span>Agree contribution<br>Own acceptance and upkeep</span></div></div><p class=\"statement\">An invitation with an exit.<br>Not a rollout disguised as a favor.</p>",
"notes": "Meet leads, developers and reviewers across contrasting workflows before recruiting one willing team. Show a concrete example to a skeptic and invite them to judge it without requiring enrollment. Agree a short weekly team check-in and a monthly CTO decision review. Record participant and reviewer effort: it is not free labor. If priorities conflict, ask the CTO to choose a trade-off rather than use sponsorship as a compliance escalation. Actual approvers must be named before a pilot.",
"sources": [
"six-months-roadmap"
],
"kind": "",
"section": "6 Months Roadmap",
"track": "main"
},
{
"id": "months-one-two",
"title": "Months 1–2 / Earn the right to test.",
"minutes": 2,
"body": "<div class=\"timeline\"><div><b>01 · Discover</b><p>Trace real changes.<br>Rank friction and evidence gaps.</p><span>Output: current-work map</span></div><div><b>02 · Agree</b><p>One willing team.<br>Baseline + smallest intervention.</p><span>Output: bounded experiment packet</span></div></div><div class=\"gate\">Decision 1 → Fund one experiment—or hold.</div><p class=\"small\">No partner, reliable checks or lawful evidence → no live pilot.</p>",
"notes": "In month one agree expectations and access with the CTO, pair on contrasting workflows and trace repository principles, system logic, tests, builds and deployments. Rank bottlenecks, not teams. Month two observes a prospective baseline and compares context, coaching, test feedback, deterministic automation and skills. Agree task eligibility, acceptance, evidence, people, spend/effort limits and a stop date. The experiment packet can be one worksheet plus existing records. Discovery may need to continue; the calendar does not waive prerequisites.",
"sources": [
"six-months-roadmap",
"baseline"
],
"kind": "",
"section": "6 Months Roadmap",
"track": "main"
},
{
"id": "months-three-four",
"title": "Months 3–4 / Test, then decide.",
"minutes": 2,
"body": "<div class=\"timeline\"><div><b>03 · Work alongside</b><p>Build and independently qualify.<br>Pair on bounded real work.</p><span>Output: failures + reproducible examples</span></div><div><b>04 · Compare</b><p>Reconcile outcomes and burden.<br>Include pending and abandoned work.</p><span>Output: retain / change / hold / stop</span></div></div><div class=\"gate\">Decision 2 → Keep only what the evidence supports.</div><p class=\"small\">Missing follow-up is “unknown”, not “all clear”.</p>",
"notes": "Qualification precedes exposure to real work; actual pilot permission is a separate human decision. During month three I pair and collect both benefits and transferred work. Month four compares matured cohorts with the reviewer, records task mix and concurrent changes, and gives the owner and CTO a recommendation. Unsafe work stops immediately. Sparse tasks or missing follow-up make the result inconclusive. Only an explicitly approved bounded extension can continue; otherwise narrow or stop. Do not silently convert a feasibility exercise into a rollout.",
"sources": [
"six-months-roadmap"
],
"kind": "",
"section": "6 Months Roadmap",
"track": "main"
},
{
"id": "months-five-six",
"title": "Months 5–6 / Transfer only if earned.",
"minutes": 2,
"body": "<div class=\"timeline\"><div><b>05 · Selective transfer</b><p>Champion + backup.<br>Check a second team’s fit.</p><span>Only with capacity and funded upkeep</span></div><div><b>06 · Evidence review</b><p>Team operates without daily help.<br>CTO chooses the next investment.</p><span>Owned workflow—or documented stop</span></div></div><p class=\"statement\">New scope → new baseline.<br>No automatic company-wide rollout.</p>",
"notes": "A second team is conditional: willingness, different task mix and support capacity can all change the answer. Keep improving the first workflow if transfer is premature. Hand over a reproducible example, support and recovery instructions to an actual owner and backup. Test operation without my daily assistance rather than treating training attendance as handover. Month six must show limits and stopped work as well as retained value. The CTO decides what is worth funding next.",
"sources": [
"six-months-roadmap",
"six-months-target"
],
"kind": "",
"section": "6 Months Roadmap",
"track": "main"
},
{
"id": "capacity",
"title": "One architect. One active live pilot.",
"minutes": 1,
"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"
],
"kind": "",
"section": "6 Months Roadmap",
"track": "main"
},
{
"id": "measures",
"title": "Measure better work—and skill health",
"minutes": 2,
"body": "<div class=\"measurement-panels\"><div class=\"workflow-panel\"><h3>Is the work improving?</h3><p class=\"metric-context\">Baseline → pilot · like-for-like cohorts</p><div class=\"metric\"><b>Validated task success (%)</b><span>Independently accepted tasks ÷ all matured eligible starts.</span></div><div class=\"metric\"><b>Changes with escaped quality issues (%)</b><span>Changes with confirmed defects ÷ accepted changes with completed follow-up.</span></div><div class=\"metric\"><b>Cost per accepted outcome <em>(currency/outcome)</em></b><span>Allocated cohort cost, including failures and review/rework ÷ independently accepted tasks.</span></div></div><div class=\"skill-panel\"><h3>Are skills fit and maintained?</h3><p class=\"metric-context\">Separate qualification + catalog populations</p><div class=\"metric\"><b>Skill selection precision (%)</b><span>Correct activations ÷ all scored activations in labeled evaluation.</span></div><div class=\"metric\"><b>Skills within substantive review window (%)</b><span>Owned, reviewed, not-overdue revisions ÷ all active approved revisions.</span></div><p class=\"qualification-note\">Independent quality qualification still required.</p></div></div><p class=\"measurement-caution\">Choose relevant measures · Unknown is not zero<br>Skill health is not productivity proof.</p>",
"notes": "Choose a small relevant subset from the sixteen optional contracts, not a requirement to collect all five shown here or all sixteen. These are candidate definitions, not actual company values or installed telemetry: task success, escaped quality, cost and precision have prototype calculations without network collectors; substantive-review coverage is unimplemented. Workflow only: compare like-for-like periods/cohorts with the same eligibility, task mix, observation and follow-up horizons, acceptance rubric and source coverage; record staffing, model/client and concurrent process changes. Before/after differences are not causal ROI. Validated task success is 100 times distinct independently accepted tasks by as_of divided by all eligible starts whose preregistered observation horizon has matured. Count each task once across retries, clients and skills. Failures, abandonment and unresolved matured starts remain in the denominator; unknown outcomes are not labeled failures. Exclude pre-start cancellations, sandbox/evaluation and out-of-scope tasks; flag invalid/missing starts and show unknown counts and coverage. Escaped quality is 100 times accepted changes with at least one linked confirmed post-acceptance defect during approved follow-up divided by accepted changes whose predeclared follow-up is complete. Count affected changes, not raw defects; separate severity and absolute defect/severe-incident counts. Show immature changes and pending triage separately; missing linkage or incomplete follow-up is not a clean result. Cost divides allocated costs for every task/attempt in the matured start cohort through as_of, including failed and abandoned attempts and shared period costs, by distinct independently accepted tasks in that same cohort. Include licenses, compute, tooling, setup, qualification, onboarding, support, upkeep and human quality review/rework effort at approved rates without double counting; exclude unrelated projects and documented accounting-basis exclusions. Use one approved reporting currency or dated approved conversion. Missing cost buckets mean a partial estimate with coverage, not total cost; zero accepted outcomes means null with full cost shown. Restate late invoices. Skill selection precision is 100 times true-positive activations divided by true-positive plus false-positive activations in candidate/client evaluation trials with independently labeled relevance and known activation. Freeze the corpus, retain negative/failed trials; unknown activation/relevance is unscorable, reported with coverage and blocks qualification if planned coverage is incomplete. This does not measure artifact success or live workflow acceptance. Substantive-review coverage is 100 times active approved revisions with current owner, linked substantive review evidence and review_due_at at or after as_of divided by all active approved revisions in the catalog snapshot. Experimental/retired revisions are excluded; report deprecated/revoked-in-use and ownerless counts separately. Missing owner/date/evidence stays outside the numerator. Review evidence includes regression, security and usefulness, not a rubber-stamped date. Independent Quality qualification still tests artifact fitness, safe execution and revision regression. Keep qualification trials and live workflow starts separate; never pool their denominators. No applicable skill population is N/A, not a baseline zero; missing evidence for an existing population is unknown, not good health. Predeclared live skill/version slices may reuse the workflow contract unchanged, without summing overlapping slices. Agree access, purpose and retention; link tracker, PR/CI, defect, cost and minimal effort evidence without individual rankings. If evidence is incomplete, limit or hold the claim; critical policy effects stop work regardless of averages.",
"sources": [
"measurement",
"six-months-roadmap",
"measurement/validated-task-success",
"measurement/changes-with-escaped-quality-issues",
"measurement/cost-per-accepted-outcome",
"measurement/skill-selection-precision",
"measurement/skills-within-substantive-review-window",
"skills-quality"
],
"kind": "",
"section": "6 Months Roadmap",
"track": "main"
},
{
"id": "misleading",
"title": "A dashboard can be confidently wrong.",
"minutes": 2,
"body": "<div class=\"contrast traps\"><p><b>Tempting signal</b><br>More PRs or generated lines<br>Shorter PR elapsed time<br>Higher acceptance rate<br>No defects recorded</p><p><b>Question before believing it</b><br>Useful work—or smaller slices?<br>Less effort—or less waiting?<br>Same task mix and denominator?<br>Enough follow-up and linkage?</p></div><p class=\"statement\">AI usage is diagnostic.<br>It is not the score.</p>",
"notes": "Invocation counts, licenses and positive sentiment can help diagnose reach or friction, but are not productivity outcomes. Acceptance changes may reflect selection and learning; stratify by complexity and reviewer availability and record concurrent model/tool/CI changes. Elapsed time is not engineer hours. Missing quality records are not zero defects. Small descriptive samples cannot establish causal ROI; agree uncertainty and precision rules before collecting evidence for a promotion claim. Do not annualize a tiny difference into cash savings.",
"sources": [
"measurement",
"six-months-roadmap"
],
"kind": "",
"section": "6 Months Roadmap",
"track": "main"
},
{
"id": "qualification",
"title": "“It worked once” is not a release gate.",
"minutes": 2,
"body": "<div class=\"flow\"><span>Pin candidate<br>and environment</span><i>→</i><span>Independent<br>qualification</span><i>→</i><span>Separate<br>pilot permission</span></div><div class=\"contrast\"><p><b>Try to break it</b><br>Wrong task · injected instruction<br>Missing tests · recovery</p><p><b>First revision</b><br>No approved prior skill = N/A<br>Remove + reload → current practice</p></div><div class=\"rail\">Failed mandatory safety checks → HOLD. An average cannot override them.</div>",
"notes": "The author cannot approve their own evidence or deployment. Test representative work, unrelated-task decline, injected instructions to bypass review, missing-test escalation, and removal/reload recovery. These examples are not a complete risk-tier evaluation suite. A real independent reviewer approves a risk-appropriate design and inspects all results. First-revision regression against an approved skill is N/A, not a fake pass; prove recovery to declared existing AI-assisted practice. The actual workflow approver separately authorizes the exact revision/client, cohort, window, expiry and effects. Security/data boundaries need their actual owners. Later revision changes return to qualification.",
"sources": [
"six-months-roadmap",
"skills-quality"
],
"kind": "",
"section": "6 Months Roadmap",
"track": "main"
},
{
"id": "experiment",
"title": "EXP-01 / Better acceptance is not enough.",
"minutes": 2,
"body": "<p class=\"fiction\">Fictional teaching example · not Eldorado results or approval</p><div class=\"flow\"><span>Missing test evidence<br>→ checklist first</span><i>→</i><span>Incomplete follow-up<br>→ hold expansion</span><i>→</i><span>Higher review burden<br>→ stop candidate</span></div><p class=\"statement\">Keep the useful practice.<br>Reject the unsupported benefit claim.</p><p class=\"small\">Existing AI practice is the comparator. A skill is tested only if needed.</p>",
"notes": "Keep one example from baseline to decision. Suppose changes repeatedly lack regression evidence. Compare a repository test map plus review checklist against packaging the same guidance as a skill; the cheaper checklist wins if it performs as well. A skill carries reusable instructions and verification, not authority. Freeze a small non-urgent bug-fix scope, one willing team and one qualified client/model tuple. The full fictional packet includes explicit real-use blanks for people, dates, immutable references, sources and data approval. Those blanks are not permission. The apparent nine versus eight accepted is not a demonstrated gain. Baseline has two failed, one abandoned and one unresolved; pilot has one of each. Three later starts have not matured and stay out of the matured denominator. At first review pilot effort median is 35 minutes among observed rows only, not the whole cohort. One non-severe baseline defect is known; pilot defect follow-up is incomplete. A tiny sample, different mix and learning also limit inference. The fictional owner may authorize one two-week evidence-only extension with no new starts, at most four architect hours, two reviewer hours and EUR25 additional spend. If reconciliation cannot finish, stop rather than keep extending. Assume reconciliation finds a 40-minute median against 30 baseline for comparable work, with reviewers tracing extra effort to checking generated tests. This breaches the fictional no-increase burden guardrail even with nine accepted tasks. It is sufficient for a local stop decision, not statistical proof the intervention fails everywhere. Remove/reload and verify current-practice recovery; preserve evidence and useful test map/checklist. Return failure cases to the author. Retain would require different evidence: complete comparable outcomes and costs, acceptable quality/burden, agreed precision, independent acceptance and funded upkeep. A new revision must requalify. Critical unauthorized effects stop immediately, not at the scheduled review. The sample table and extension caps are speaker-reference detail, not the main strategy story. Use only the three visible decisions in the planned narration; expand into these numbers only if asked.",
"sources": [
"six-months-roadmap"
],
"kind": "",
"section": "6 Months Roadmap",
"track": "main"
},
{
"id": "month-six",
"title": "Month six / An evidence portfolio, not a victory lap.",
"minutes": 1,
"body": "<div class=\"ledger\"><div><b>Visible change</b><b>Evidence to ask for</b></div><div><span>One workflow understood</span><span>Map + baseline + explicit gaps</span></div><div><span>Retained practice—or justified stop</span><span>Comparable outcomes + costs + limits</span></div><div><span>Less dependence on the architect</span><span>Owner + backup + recovery rehearsal</span></div></div><p class=\"small\">Proposed achievable picture. No guaranteed savings, headcount reduction or org-wide uplift.</p>",
"notes": "Commit to activities I can drive: discovery, agreement, hands-on support, reproducible evidence and clear decisions. Do not promise a positive effect outside my control. A realistic month-six organization has one bounded workflow learned from, transparent limitations, some reusable examples and an owner if anything is retained. A second willing team may have a new baseline, not a blanket rollout. If experiments stop, explain what was ruled out, what remains useful and why the next investment changes. Independent source-linked evidence, not a polished demo or attendance count, backs the picture.",
"sources": [
"six-months-target",
"six-months-roadmap"
],
"kind": "",
"section": "6 Months Target",
"track": "main"
},
{
"id": "beyond",
"title": "Beyond 6 Months / Progress toward the Target.",
"minutes": 2,
"body": "<div class=\"choices\"><div><b>Deepen</b><p>Coaching, context or deterministic tooling where friction remains.</p></div><div><b>Transfer</b><p>Only with repeatable value, local fit and supported ownership.</p></div><div><b>Toward autonomy</b><p>Separate authority case, containment and human takeover.</p></div></div><p class=\"statement\">Established destination. Evidence-led steps.<br>Separate authority—not automatic graduation.</p>",
"notes": "The next quarter may deepen the existing workflow or stop expansion entirely. Skills remain optional; no catalog or central control platform is a prerequisite. Transfer needs new-scope baseline and local capacity. Consider bounded autonomy only if it solves an evidenced bottleneck and controls are proven: exact-artifact approvals, scoped identity, idempotency, audit, independent stop and takeover. People retain product, risk and release decisions. The long-term destination remains human-directed, guided and reviewed autonomous SDLC. These six months contribute toward that vision, not replace it; they do not promise its timing or authorize its execution. The CTO chooses investment based on the evidence, not an inevitable maturity staircase.",
"sources": [
"stage-02-autonomous-agent",
"target-operating-model",
"roadmap",
"six-months-target"
],
"kind": "",
"section": "Beyond 6 Months",
"track": "main"
},
{
"id": "authority",
"title": "Toward autonomy / Change authority deliberately.",
"minutes": 2,
"body": "<div class=\"flow\"><span>Observe +<br>assemble evidence</span><i>→</i><span>Propose +<br>route work</span><i>⇢</i><span>Separately authorize<br>scoped execution</span></div><div class=\"rail\">Exact-artifact approval · scoped identity · audit + recovery</div><p class=\"statement\">Independent stop. Human takeover.</p><p class=\"small\">Readiness failure → hold or redesign. Missing evidence is never permission.</p>",
"notes": "Progress toward the established Target by granting only the extra operation that an evidenced business case needs. Reliable observation and evidence assembly come before proposing and routing; neither permits mutation, merge or deployment. A separate human decision names the exact resources, data, artifact and scope. Prove identity separation, checks outside candidate control, idempotency, duplicate/outage recovery and audit. Test a kill switch and human takeover outside the model before trusting scoped execution. The agent cannot appoint approvers or edit its own gates. Changed boundaries reopen review; harmful behavior revokes authority and feeds learning back to Quality and Maintenance. This is the bridge toward the autonomous Target, not an installed system or a dated commitment.",
"sources": [
"stage-02-autonomous-agent",
"target-operating-model"
],
"kind": "",
"section": "Beyond 6 Months",
"track": "main"
},
{
"id": "alignment",
"title": "The first CTO conversation",
"minutes": 1,
"body": "<ol class=\"asks\"><li>Which outcome is worth improving first?</li><li>Who can volunteer time—and independent review?</li><li>What data, risk and effort limits apply?</li><li>When will we decide to continue or stop?</li></ol><p class=\"statement\">Sponsor the learning.<br>Do not pre-approve the answer.</p>",
"notes": "Close with concrete alignment, not a shopping list. Ask the CTO to agree an outcome, access to willing teams, independent review capacity, risk/data boundary and decision cadence. Agree success and stop criteria before collecting favorable anecdotes. The long-term Target and Roadmap establish the destination; the six-month plan is a realistic contribution toward it. We have covered the four assignment questions: action, measurement, realistic six-month evidence and conditional next investment. Transition to the fifteen-minute discussion. If time runs short, skip detail in narration rather than the decision and its limits.",
"sources": [
"PDF: questions 1–4",
"six-months-roadmap"
],
"kind": "dark",
"section": "Discussion",
"track": "main"
},
{
"id": "discussion",
"title": "Q&A / What would change your mind?",
"minutes": 15,
"body": "<p class=\"subtitle\">15 minutes for the hard questions.</p><div class=\"discussion\"><p>No willing team?</p><p>Too little evidence?</p><p>A cheaper non-AI fix?</p></div><p class=\"small\">The proposed plan can change. The evidence standard should not.</p>",
"notes": "Reserve the full fifteen minutes. If no team volunteers, revisit the problem and sponsor trade-offs rather than conscript people. If evidence is sparse, narrow the question, explicitly authorize a bounded evidence-completion window or stop. If deterministic tooling is better, choose it. Discuss the company’s real constraints rather than pretend the fictional example estimates company benefit. The next slide provides linked sources for follow-up, not additional spoken content.",
"sources": [
"PDF: Format",
"six-months-target"
],
"kind": "dark",
"section": "Discussion",
"track": "discussion"
},
{
"id": "references",
"title": "References / Follow the evidence.",
"minutes": 0,
"body": "<ul class=\"references\"><li>AI Architect Test Task · Eldorado.gg<br><span>Context, four questions, assumptions, 50-minute format</span></li><li><a href=\"../../strategy/target-operating-model/\">Long-term Target</a> · <a href=\"../../strategy/roadmap/\">Roadmap →</a></li><li><a href=\"../../strategy/six-months-target/\">6 Months Target →</a></li><li><a href=\"../../strategy/six-months-roadmap/\">6 Months Roadmap →</a></li><li><a href=\"../../strategy/six-months-roadmap/#exp-01-a-small-decision-ready-example\">EXP-01 packet and decision limits →</a></li><li><a href=\"../../strategy/measurement/\">Measurement definitions and safeguards →</a></li><li><a href=\"../../strategy/stage-02-autonomous-agent/\">Beyond 6 Months →</a></li></ul>",
"notes": "Appendix, zero planned talk time. The original assignment is the supplied AI_Architect_Test_Task.pdf. The source-reference map in this presentation directory records every slide against the PDF and reviewed Strategy. The deck does not reproduce the assignment file publicly. EXP-01 remains entirely fictional; its budget, medians, samples and outcomes are teaching devices. Official Reveal documentation consulted: installation, speaker-view and pdf-export on revealjs.com. All runtime assets are pinned and bundled locally.",
"sources": [
"PDF: complete assignment",
"six-months-target",
"six-months-roadmap",
"measurement",
"stage-02-autonomous-agent"
],
"kind": "",
"section": "Reference",
"track": "appendix"
}
]; ];
@@ -0,0 +1,25 @@
// Presentation-sized views of the canonical topology, not a new operating model.
export const phases=['scope','architecture','ui-ux','planning','delivery','uat','security','releases'];
export const labels=['Scope','Architecture','UI/UX','Planning','Delivery','UAT','Security','Releases'];
export const topology={
lifecycle:phases.map((id,i)=>[id,phases[(i+1)%phases.length]]),
governance:phases.map(id=>['agent',id]),
contributions:phases.map(id=>[`code-${id}`,id]),
};
function cycle(portrait){
const key=portrait?'phone':'wide';
const w=portrait?540:1096,h=portrait?540:350;
const xs=portrait?[100,270,440]:[200,548,896],ys=portrait?[65,270,475]:[40,175,310];
const pos=[[xs[1],ys[0]],[xs[2],ys[0]],[xs[2],ys[1]],[xs[2],ys[2]],[xs[1],ys[2]],[xs[0],ys[2]],[xs[0],ys[1]],[xs[0],ys[0]]];
const bw=portrait?154:202,bh=52,cx=xs[1],cy=ys[1],cw=portrait?164:270,ch=portrait?112:94;
const edge=(a,b)=>{const dx=b[0]-a[0],dy=b[1]-a[1],t=Math.min(dx?bw/2/Math.abs(dx):Infinity,dy?bh/2/Math.abs(dy):Infinity);return [a[0]+dx*t,a[1]+dy*t]};
const path=(d,type,from,to)=>`<path d="${d}" class="${type}" data-from="${from}" data-to="${to}" marker-end="url(#${key}-${type})"/>`;
let lines=pos.map((a,i)=>{const b=pos[(i+1)%8],p=edge(a,b),q=edge(b,a);return path(`M${p} L${q}`,'cycle-edge',...topology.lifecycle[i])}).join('');
// Top and bottom share a center exit; side spokes enter the side phases.
lines+=pos.map(([x,y],i)=>{let d;if(y<cy)d=`M${cx},${cy-ch/2} V${(cy-ch/2+y+bh/2)/2} H${x+(x<cx?30:x>cx?-30:0)} V${y+bh/2}`;else if(y>cy)d=`M${cx},${cy+ch/2} V${(cy+ch/2+y-bh/2)/2} H${x+(x<cx?30:x>cx?-30:0)} V${y-bh/2}`;else d=`M${cx+(x>cx?cw/2:-cw/2)},${cy} H${x+(x>cx?-bw/2:bw/2)}`;return path(d,'govern-edge',...topology.governance[i])}).join('');
const nodes=pos.map(([x,y],i)=>`<g data-node="${phases[i]}"><rect x="${x-bw/2}" y="${y-bh/2}" width="${bw}" height="${bh}"/><text x="${x}" y="${y+8}">${labels[i]}</text></g>`).join('');
const center=portrait?['Autonomous','agent','Human-controlled']:['Autonomous agent','Human-controlled'];
return `<svg class="target-cycle ${key}" viewBox="0 0 ${w} ${h}" role="img" aria-label="Intended SDLC: Scope, Architecture, UI/UX, Planning, Delivery, UAT, Security, Releases and back to Scope. One human-controlled autonomous agent executes and governs all eight phases."><defs>${['cycle-edge','govern-edge'].map(t=>`<marker id="${key}-${t}" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="5" markerHeight="5" orient="auto-start-reverse"><path d="M0 0 L10 5 L0 10z" fill="${t==='cycle-edge'?'#14131a':'#936500'}"/></marker>`).join('')}</defs>${lines}${nodes}<g data-node="agent" class="central"><rect x="${cx-cw/2}" y="${cy-ch/2}" width="${cw}" height="${ch}"/>${center.map((t,i)=>`<text x="${cx}" y="${cy-(center.length-1)*14+i*28+8}" class="${i===center.length-1?'control-label':''}">${t}</text>`).join('')}</g></svg>`;
}
export const cycleFigure=cycle(false)+cycle(true);
export const contributionsFigure=`<div class="contribution-grid">${phases.map((id,i)=>`<div data-from="code-${id}" data-to="${id}"><span>AI Agent</span><i aria-label="contributes to">⇢</i><b>${labels[i]}</b></div>`).join('')}</div>`;
@@ -64,3 +64,78 @@ a:focus-visible,button:focus-visible{outline:3px solid #b88719;outline-offset:3p
.embedded .deck .progress{position:fixed;bottom:0} .embedded .deck .progress{position:fixed;bottom:0}
@media print{.toolbar{display:none}.reveal.deck{top:0;height:100%}} @media print{.toolbar{display:none}.reveal.deck{top:0;height:100%}}
html.print-pdf .toolbar{display:none}html.print-pdf .reveal.deck{top:0;height:100%} html.print-pdf .toolbar{display:none}html.print-pdf .reveal.deck{top:0;height:100%}
/* Distinct strategy views: paired topology, progression and learning loop. */
.deck .target-cycle{width:100%;height:350px;display:block;margin:0 auto}
.deck .target-cycle.phone{display:none}
.target-cycle rect{fill:#f6f6f6;stroke:#14131a;stroke-width:2}
.target-cycle text{text-anchor:middle;font:700 24px Lato,sans-serif;fill:#14131a}
.target-cycle .central rect{fill:#ffc950}
.target-cycle .control-label{font-size:20px;font-weight:400}
.target-cycle .cycle-edge{fill:none;stroke:#14131a;stroke-width:2.5}
.target-cycle .govern-edge{fill:none;stroke:#936500;stroke-width:2.5;stroke-dasharray:3 5}
.deck .diagram-legend{font-size:23px;margin:12px 0}
.deck #target .small{font-size:21px;margin:12px 0}
.deck .diagram-intro{font-size:30px}
.deck .contribution-grid{display:grid;grid-template-columns:repeat(4,1fr);gap:12px 20px;margin:22px 0}
.deck .contribution-grid>div{border-top:4px solid #ffc950;padding:10px 8px;display:flex;flex-direction:column;align-items:center;font-size:26px}
.deck .contribution-grid i{font-style:normal;transform:rotate(90deg);color:#805b00;font-size:32px;line-height:1.2}
.deck .journey{display:flex;gap:16px;align-items:center;margin:36px 0}
.deck .journey>div{flex:1;border-top:6px solid #ffc950;padding:18px 6px;align-self:stretch}
.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 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}
.portrait .deck .journey{flex-direction:column;gap:4px;margin:18px 0}
.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 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}
/* Slide 14: outcomes lead; skill indicators remain a separate population. */
.deck .slides #measures{padding-top:32px}
.deck #measures h2{font-size:48px;margin-bottom:20px}
#measures .measurement-panels{display:grid;grid-template-columns:1.3fr 1fr;gap:24px}
#measures .workflow-panel,#measures .skill-panel{padding:16px 22px;font-size:21px;line-height:1.3;background:#e9e9ec;border-top:6px solid var(--gold)}
#measures .skill-panel{background:#eeedf0;border-top-color:#8b8994}
#measures h3{font-size:28px;line-height:1.15;letter-spacing:-.025em;font-weight:900;margin:0;text-transform:none;color:var(--ink)}
.deck #measures .metric-context{font-size:19px;line-height:1.3;margin:8px 0 12px;color:#62616b}
#measures .metric{border-top:1px solid #bbb9c2;padding:10px 0 0;margin-top:10px}
#measures .metric b{display:block;font-size:25px;line-height:1.2}
#measures .metric em{font-style:normal;font-size:20px;white-space:nowrap}
#measures .metric span{display:block;font-size:21px;line-height:1.3;margin-top:7px}
.deck #measures .qualification-note{border-left:4px solid var(--gold);padding-left:12px;font-size:21px;font-weight:700;line-height:1.25;margin:22px 0 0}
.deck #measures .measurement-caution{font-size:20px;line-height:1.4;color:#62616b;margin:16px 0 0}
.portrait .deck .slides #measures{padding-top:20px}
.portrait .deck #measures h2{font-size:38px;margin:12px 0 14px}
.portrait #measures .measurement-panels{grid-template-columns:1fr;gap:12px}
.portrait #measures .workflow-panel,.portrait #measures .skill-panel{padding:12px 16px}
.portrait #measures h3{font-size:29px}
.portrait .deck #measures .metric-context{font-size:20px;margin:6px 0 8px}
.portrait #measures .metric{padding-top:4px;margin-top:4px}
.portrait #measures .metric b{font-size:26px}
.portrait #measures .metric span{font-size:22px;line-height:1.2;margin-top:5px}
.portrait .deck #measures .qualification-note{font-size:22px;margin-top:12px}
.portrait .deck #measures .measurement-caution{font-size:21px;margin-top:12px}
+10 -7
View File
@@ -1,4 +1,5 @@
const {chromium}=require('playwright'); const {chromium}=require('playwright');
const staircaseFits=require('./presentation-staircase.cjs');
const assert=require('node:assert/strict');const fs=require('node:fs'); const assert=require('node:assert/strict');const fs=require('node:fs');
(async()=>{ (async()=>{
const base=process.argv[2]||'http://127.0.0.1:43853';const root=base+'/eldorado-v1/documentation/'; const base=process.argv[2]||'http://127.0.0.1:43853';const root=base+'/eldorado-v1/documentation/';
@@ -11,7 +12,7 @@ const assert=require('node:assert/strict');const fs=require('node:fs');
await p.goto(root,{waitUntil:'networkidle'});const section=p.locator('section[aria-labelledby="presentation-title"]');await section.scrollIntoViewIfNeeded(); await p.goto(root,{waitUntil:'networkidle'});const section=p.locator('section[aria-labelledby="presentation-title"]');await section.scrollIntoViewIfNeeded();
const iframe=p.locator('iframe[title="Less Prompting, More Shipping — interactive presentation"]');const f=await iframe.elementHandle().then(e=>e.contentFrame());await f.waitForFunction(()=>window.Reveal?.isReady());await f.evaluate(()=>document.fonts.ready); const iframe=p.locator('iframe[title="Less Prompting, More Shipping — interactive presentation"]');const f=await iframe.elementHandle().then(e=>e.contentFrame());await f.waitForFunction(()=>window.Reveal?.isReady());await f.evaluate(()=>document.fonts.ready);
assert.deepEqual(await p.locator('#start-title,#presentation-title').evaluateAll(es=>es.map(e=>{const s=getComputedStyle(e);return [s.fontFamily,s.fontSize,s.fontWeight,s.letterSpacing,s.lineHeight]})).then(a=>a[0]),await p.locator('#presentation-title').evaluate(e=>{const s=getComputedStyle(e);return [s.fontFamily,s.fontSize,s.fontWeight,s.letterSpacing,s.lineHeight]})); assert.deepEqual(await p.locator('#start-title,#presentation-title').evaluateAll(es=>es.map(e=>{const s=getComputedStyle(e);return [s.fontFamily,s.fontSize,s.fontWeight,s.letterSpacing,s.lineHeight]})).then(a=>a[0]),await p.locator('#presentation-title').evaluate(e=>{const s=getComputedStyle(e);return [s.fontFamily,s.fontSize,s.fontWeight,s.letterSpacing,s.lineHeight]}));
assert.equal(await f.locator('.toolbar').isVisible(),false);assert.equal(await f.evaluate(()=>Reveal.getConfig().hash),false);assert.equal(await f.evaluate(()=>Reveal.getConfig().transition),'none');assert.equal(await f.evaluate(()=>Reveal.getTotalSlides()),19); assert.equal(await f.locator('.toolbar').isVisible(),false);assert.equal(await f.evaluate(()=>Reveal.getConfig().hash),false);assert.equal(await f.evaluate(()=>Reveal.getConfig().transition),'none');assert.equal(await f.evaluate(()=>Reveal.getTotalSlides()),23);
assert(await p.evaluate(()=>document.documentElement.scrollWidth<=innerWidth)); assert(await p.evaluate(()=>document.documentElement.scrollWidth<=innerWidth));
if(viewport.width<=390)assert(await iframe.evaluate(e=>e.clientHeight>e.clientWidth),'phone stage must recompose rather than shrink landscape text'); if(viewport.width<=390)assert(await iframe.evaluate(e=>e.clientHeight>e.clientWidth),'phone stage must recompose rather than shrink landscape text');
await p.getByRole('button',{name:'Fullscreen',exact:true}).focus();await p.keyboard.press('ArrowRight');assert.equal(await f.evaluate(()=>Reveal.getIndices().h),0); await p.getByRole('button',{name:'Fullscreen',exact:true}).focus();await p.keyboard.press('ArrowRight');assert.equal(await f.evaluate(()=>Reveal.getIndices().h),0);
@@ -19,13 +20,15 @@ const assert=require('node:assert/strict');const fs=require('node:fs');
const scroll=await p.evaluate(()=>scrollY);await p.keyboard.press('ArrowRight');assert.equal(await f.evaluate(()=>Reveal.getIndices().h),2);assert.equal(await p.evaluate(()=>scrollY),scroll);assert.equal(p.url(),root); const scroll=await p.evaluate(()=>scrollY);await p.keyboard.press('ArrowRight');assert.equal(await f.evaluate(()=>Reveal.getIndices().h),2);assert.equal(await p.evaluate(()=>scrollY),scroll);assert.equal(p.url(),root);
await f.evaluate(()=>Reveal.slide(0)); await f.evaluate(()=>Reveal.slide(0));
const visited=[]; const visited=[];
for(let i=0;i<19;i++){ for(let i=0;i<23;i++){
assert.equal(await f.evaluate(()=>Reveal.getIndices().h),i);visited.push(await f.evaluate(()=>Reveal.getCurrentSlide().id)); 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('h1,h2,p,li,table,.flow,.roles,.timeline')].filter(e=>!e.closest('.notes')).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,[]); const bad=await f.evaluate(()=>{const r=Reveal.getCurrentSlide().getBoundingClientRect();return [...Reveal.getCurrentSlide().querySelectorAll('.measurement-panels,.metric,.metric b,.metric span,.qualification-note,h3,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,[]);
await iframe.screenshot({path:`${out}/${viewport.width}-${i+1}.png`}); if(i===6)assert(await f.evaluate(staircaseFits),'staircase aligns each arrow with its intended steps');
if(i<18)await p.keyboard.press('ArrowRight'); 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');
} }
assert.equal(new Set(visited).size,19);assert.equal(p.url(),root);assert.equal(new URL(f.url()).hash,''); assert.equal(new Set(visited).size,23);assert.equal(p.url(),root);assert.equal(new URL(f.url()).hash,'');
await f.evaluate(()=>Reveal.slide(0));await section.screenshot({path:`${out}/${viewport.width}-light.png`}); await f.evaluate(()=>Reveal.slide(0));await section.screenshot({path:`${out}/${viewport.width}-light.png`});
await p.evaluate(()=>document.documentElement.setAttribute('data-theme','dark'));await section.screenshot({path:`${out}/${viewport.width}-dark.png`}); await p.evaluate(()=>document.documentElement.setAttribute('data-theme','dark'));await section.screenshot({path:`${out}/${viewport.width}-dark.png`});
await p.getByRole('button',{name:'Fullscreen',exact:true}).click();await p.waitForFunction(()=>!!document.fullscreenElement);await f.waitForTimeout(100); await p.getByRole('button',{name:'Fullscreen',exact:true}).click();await p.waitForFunction(()=>!!document.fullscreenElement);await f.waitForTimeout(100);
@@ -52,6 +55,6 @@ const assert=require('node:assert/strict');const fs=require('node:fs');
await p.getByRole('link',{name:/Open presentation/}).click();await p.waitForFunction(()=>window.Reveal?.isReady());assert(!p.url().includes('embed'));assert(await p.locator('.toolbar').isVisible()); await p.getByRole('link',{name:/Open presentation/}).click();await p.waitForFunction(()=>window.Reveal?.isReady());assert(!p.url().includes('embed'));assert(await p.locator('.toolbar').isVisible());
assert.deepEqual(errors,[]);results.push({viewport,visited,headingParity:true,keyboardIsolation:true,scrollIsolation:true,touch:true,fullscreen:true,tabExit:true,errors});await context.close(); assert.deepEqual(errors,[]);results.push({viewport,visited,headingParity:true,keyboardIsolation:true,scrollIsolation:true,touch:true,fullscreen:true,tabExit:true,errors});await context.close();
} }
fs.writeFileSync(`${out}/results.json`,JSON.stringify(results,null,2));console.log('PASS: 76 inline slides, heading parity, URLs, focus/scroll isolation, touch, fullscreen, Tab exit, themes, reduced motion and standalone handoff'); fs.writeFileSync(`${out}/results.json`,JSON.stringify(results,null,2));console.log('PASS: 92 inline slides, heading parity, URLs, focus/scroll isolation, touch, fullscreen, Tab exit, themes, reduced motion and standalone handoff');
}finally{await browser.close()} }finally{await browser.close()}
})().catch(e=>{console.error(e);process.exitCode=1}); })().catch(e=>{console.error(e);process.exitCode=1});
@@ -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);
};
+12 -9
View File
@@ -1,4 +1,5 @@
const {chromium}=require('playwright'); const {chromium}=require('playwright');
const staircaseFits=require('./presentation-staircase.cjs');
const fs=require('node:fs'); const assert=require('node:assert/strict'); const fs=require('node:fs'); const assert=require('node:assert/strict');
(async()=>{ (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/'; 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/';
@@ -11,22 +12,24 @@ const fs=require('node:fs'); const assert=require('node:assert/strict');
const page=await context.newPage();const errors=[];page.on('pageerror',e=>errors.push(e.message));page.on('response',r=>{if(r.status()>=400)errors.push(`${r.status()} ${r.url()}`)});page.on('console',m=>{if(m.type()==='error')errors.push(m.text())}); const page=await context.newPage();const errors=[];page.on('pageerror',e=>errors.push(e.message));page.on('response',r=>{if(r.status()>=400)errors.push(`${r.status()} ${r.url()}`)});page.on('console',m=>{if(m.type()==='error')errors.push(m.text())});
assert.equal((await page.goto(url,{waitUntil:'networkidle'})).status(),200); assert.equal((await page.goto(url,{waitUntil:'networkidle'})).status(),200);
await page.waitForFunction(()=>window.Reveal?.isReady());await page.evaluate(()=>document.fonts.ready); await page.waitForFunction(()=>window.Reveal?.isReady());await page.evaluate(()=>document.fonts.ready);
assert.equal(await page.evaluate(()=>Reveal.getTotalSlides()),19); assert.equal(await page.evaluate(()=>Reveal.getTotalSlides()),23);
assert.equal(await page.evaluate(()=>Reveal.getConfig().transition),'none'); assert.equal(await page.evaluate(()=>Reveal.getConfig().transition),'none');
const bounds=[]; const bounds=[];
for(let i=0;i<19;i++){ for(let i=0;i<23;i++){
await page.evaluate(i=>Reveal.slide(i),i);await page.waitForTimeout(60); await page.evaluate(i=>Reveal.slide(i),i);await page.waitForTimeout(60);
const bad=await page.evaluate(()=>{ const bad=await page.evaluate(()=>{
const slide=Reveal.getCurrentSlide(),r=slide.getBoundingClientRect(); const slide=Reveal.getCurrentSlide(),r=slide.getBoundingClientRect();
return [...slide.querySelectorAll('h1,h2,p,li,td,th,.rail,.gate,.facts,.flow,.roles,.timeline,.capacity,.measure-list,.contrast,.comparison,.choices,.ledger')].filter(e=>!e.closest('.notes')).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)); return [...slide.querySelectorAll('.measurement-panels,.metric,.metric b,.metric span,.qualification-note,h3,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));
}); });
bounds.push({slide:i+1,overflow:bad}); 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`}); await page.screenshot({path:`${out}/${viewport.width}-slide-${String(i+1).padStart(2,'0')}.png`});
} }
fs.writeFileSync(`${out}/${viewport.width}-bounds.json`,JSON.stringify(bounds,null,2)); fs.writeFileSync(`${out}/${viewport.width}-bounds.json`,JSON.stringify(bounds,null,2));
assert.deepEqual(bounds.filter(b=>b.overflow.length),[],'slide overflow'); assert.deepEqual(bounds.filter(b=>b.overflow.length),[],'slide overflow');
await page.goto(url+'#/qualification');await page.reload();await page.waitForFunction(()=>Reveal.isReady());assert.equal(await page.evaluate(()=>Reveal.getCurrentSlide().id),'qualification'); await page.goto(url+'#/qualification');await page.reload();await page.waitForFunction(()=>Reveal.isReady());assert.equal(await page.evaluate(()=>Reveal.getCurrentSlide().id),'qualification');
await page.keyboard.press('ArrowRight');assert.equal(await page.evaluate(()=>Reveal.getCurrentSlide().id),'inconclusive');await page.keyboard.press('ArrowLeft'); await page.keyboard.press('ArrowRight');assert.equal(await page.evaluate(()=>Reveal.getCurrentSlide().id),'experiment');await page.keyboard.press('ArrowLeft');
await page.getByRole('button',{name:'Overview',exact:true}).click();assert(await page.evaluate(()=>Reveal.isOverview()));await page.keyboard.press('Escape');assert(!await page.evaluate(()=>Reveal.isOverview())); await page.getByRole('button',{name:'Overview',exact:true}).click();assert(await page.evaluate(()=>Reveal.isOverview()));await page.keyboard.press('Escape');assert(!await page.evaluate(()=>Reveal.isOverview()));
if(viewport.width===1440){ if(viewport.width===1440){
await page.getByRole('button',{name:'Fullscreen',exact:true}).click();await page.waitForFunction(()=>!!document.fullscreenElement);await page.getByRole('button',{name:'Fullscreen',exact:true}).click();await page.waitForFunction(()=>!document.fullscreenElement); await page.getByRole('button',{name:'Fullscreen',exact:true}).click();await page.waitForFunction(()=>!!document.fullscreenElement);await page.getByRole('button',{name:'Fullscreen',exact:true}).click();await page.waitForFunction(()=>!document.fullscreenElement);
@@ -42,11 +45,11 @@ const fs=require('node:fs'); const assert=require('node:assert/strict');
const links=await page.locator('a').evaluateAll(els=>els.map(e=>e.href).filter(h=>!h.includes('?'))); const links=await page.locator('a').evaluateAll(els=>els.map(e=>e.href).filter(h=>!h.includes('?')));
for(const link of new Set(links))assert.equal((await page.request.get(link)).status(),200,link); for(const link of new Set(links))assert.equal((await page.request.get(link)).status(),200,link);
await page.getByRole('link',{name:'Portal',exact:true}).click();await page.waitForURL(base+root);await page.getByRole('link',{name:/Open presentation/}).scrollIntoViewIfNeeded();await page.screenshot({path:`${out}/${viewport.width}-homepage.png`});await page.getByRole('link',{name:/Open presentation/}).click();await page.waitForFunction(()=>window.Reveal?.isReady()); await page.getByRole('link',{name:'Portal',exact:true}).click();await page.waitForURL(base+root);await page.getByRole('link',{name:/Open presentation/}).scrollIntoViewIfNeeded();await page.screenshot({path:`${out}/${viewport.width}-homepage.png`});await page.getByRole('link',{name:/Open presentation/}).click();await page.waitForFunction(()=>window.Reveal?.isReady());
assert.deepEqual(errors,[]);results.push({viewport,slides:19,overflow:false,errors,deepLinkRefresh:true,keyboard:true,overview:true,links:true,touch:viewport.width!==1440});await context.close(); assert.deepEqual(errors,[]);results.push({viewport,slides:23,overflow:false,errors,deepLinkRefresh:true,keyboard:true,overview:true,links:true,touch:viewport.width!==1440});await context.close();
} }
const narrow=await browser.newPage({viewport:{width:320,height:720}});await narrow.goto(url,{waitUntil:'networkidle'});await narrow.evaluate(()=>document.fonts.ready);assert(await narrow.evaluate(()=>document.querySelector('.toolbar').scrollWidth<=innerWidth),'320px toolbar must not clip Print');await narrow.screenshot({path:out+'/320-toolbar.png'});await narrow.close(); const narrow=await browser.newPage({viewport:{width:320,height:720}});await narrow.goto(url,{waitUntil:'networkidle'});await narrow.evaluate(()=>document.fonts.ready);assert(await narrow.evaluate(()=>document.querySelector('.toolbar').scrollWidth<=innerWidth),'320px toolbar must not clip Print');await narrow.screenshot({path:out+'/320-toolbar.png'});await narrow.close();
const page=await browser.newPage({viewport:{width:1440,height:900}});await page.goto(url+'?print-pdf',{waitUntil:'networkidle'});await page.waitForFunction(()=>document.querySelectorAll('.pdf-page').length===19);await page.pdf({path:out+'/print.pdf',preferCSSPageSize:true,printBackground:true}); const page=await browser.newPage({viewport:{width:1440,height:900}});await page.goto(url+'?print-pdf',{waitUntil:'networkidle'});await page.waitForFunction(()=>document.querySelectorAll('.pdf-page').length===23);await page.pdf({path:out+'/print.pdf',preferCSSPageSize:true,printBackground:true});
assert.equal(await page.locator('.pdf-page').count(),19); assert.equal(await page.locator('.pdf-page').count(),23);
fs.writeFileSync(`${out}/results.json`,JSON.stringify({results,printPages:19},null,2));console.log('PASS: 57 slide views, bounds, refresh/hash, keyboard, overview, touch, fullscreen, notes, all links, homepage, print'); fs.writeFileSync(`${out}/results.json`,JSON.stringify({results,printPages:23},null,2));console.log('PASS: 69 slide views, bounds, refresh/hash, keyboard, overview, touch, fullscreen, notes, all links, homepage, print');
}finally{await browser.close()} }finally{await browser.close()}
})().catch(e=>{console.error(e);process.exitCode=1}); })().catch(e=>{console.error(e);process.exitCode=1});
+10 -3
View File
@@ -9,14 +9,21 @@ for(const weight of [400,700,900]) await copyFile(`node_modules/@fontsource/lato
await copyFile('node_modules/@fontsource/lato/LICENSE',`${out}/assets/LATO-LICENSE`); await copyFile('node_modules/@fontsource/lato/LICENSE',`${out}/assets/LATO-LICENSE`);
await copyFile(`${root}/theme.css`,`${out}/theme.css`); await copyFile(`${root}/theme.css`,`${out}/theme.css`);
const esc=s=>s.replaceAll('&','&amp;').replaceAll('<','&lt;').replaceAll('>','&gt;').replaceAll('"','&quot;'); const esc=s=>s.replaceAll('&','&amp;').replaceAll('<','&lt;').replaceAll('>','&gt;').replaceAll('"','&quot;');
await writeFile(`${out}/index.html`,`<!doctype html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><meta name="description" content="The AI Architect’s First Six Months: a proposed, evidence-led strategy."><title>Less Prompting, More Shipping | Eldorado</title><link rel="icon" href="data:,"><link rel="stylesheet" href="./assets/reveal.css"><link rel="stylesheet" href="./theme.css"></head><body> await writeFile(`${out}/index.html`,`<!doctype html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><meta name="description" content="The autonomous SDLC destination and an evidence-led first-six-month contribution."><title>Less Prompting, More Shipping | Eldorado</title><link rel="icon" href="data:,"><link rel="stylesheet" href="./assets/reveal.css"><link rel="stylesheet" href="./theme.css"></head><body>
<nav class="toolbar" aria-label="Presentation tools"><a href="../../">Portal</a><a href="../../strategy/target-operating-model/">Strategy</a><button id="overview" type="button">Overview</button><button id="notes" type="button">Notes</button><button id="fullscreen" type="button">Fullscreen</button><a href="?print-pdf">Print</a><span class="help">← → navigate · Esc overview · S notes · F fullscreen</span></nav> <nav class="toolbar" aria-label="Presentation tools"><a href="../../">Portal</a><a href="../../strategy/target-operating-model/">Strategy</a><button id="overview" type="button">Overview</button><button id="notes" type="button">Notes</button><button id="fullscreen" type="button">Fullscreen</button><a href="?print-pdf">Print</a><span class="help">← → navigate · Esc overview · S notes · F fullscreen</span></nav>
<div class="reveal deck"><div class="slides">${slides.map((s,i)=>`<section id="${s.id}" class="${s.kind}" data-timing="${s.minutes*60}" ${s.kind==='dark'?'data-background-color="#1f1f29"':''}><p class="eyebrow">ELDORADO / ${i===17?'DISCUSSION':i===18?'REFERENCE':'AI STRATEGY'}</p><${i?'h2':'h1'}>${s.title}</${i?'h2':'h1'}>${s.body}<aside class="notes"><p><strong>${s.minutes} minutes.</strong> ${esc(s.notes)}</p><p>Sources: ${esc(s.sources.join('; '))}.</p></aside></section>`).join('\n')}</div></div> <div class="reveal deck"><div class="slides">${slides.map((s,i)=>`<section id="${s.id}" class="${s.kind}" data-timing="${s.minutes*60}" ${s.kind==='dark'?'data-background-color="#1f1f29"':''}><p class="eyebrow">ELDORADO / ${esc(s.section.toUpperCase())}</p><${i?'h2':'h1'}>${s.title}</${i?'h2':'h1'}>${s.body}<aside class="notes"><p><strong>${s.minutes} minutes.</strong> ${esc(s.notes)}</p><p>Sources: ${esc(s.sources.join('; '))}.</p></aside></section>`).join('\n')}</div></div>
<script src="./assets/reveal.js"></script><script src="./assets/notes.js"></script><script src="./runtime.js"></script></body></html>`); <script src="./assets/reveal.js"></script><script src="./assets/notes.js"></script><script src="./runtime.js"></script></body></html>`);
await copyFile(`${root}/runtime.js`,`${out}/runtime.js`); await copyFile(`${root}/runtime.js`,`${out}/runtime.js`);
const sourceDocuments = await Promise.all([...new Set(slides.flatMap(s=>s.sources).filter(s=>!s.startsWith('PDF:')))].sort().map(async id=>{ const sourceDocuments = await Promise.all([...new Set(slides.flatMap(s=>s.sources).filter(s=>!s.startsWith('PDF:')))].sort().map(async id=>{
const path=`docs/strategy/${id==='measurement'?'measurement/index':id}.mdx`; const path=`docs/strategy/${id==='measurement'?'measurement/index':id}.mdx`;
return {id,path,route:`/strategy/${id}/`,sha256:createHash('sha256').update(await readFile(path)).digest('hex')}; return {id,path,route:`/strategy/${id}/`,sha256:createHash('sha256').update(await readFile(path)).digest('hex')};
})); }));
await writeFile(`${out}/source-map.json`,JSON.stringify({version:'1.0.1',strategyRevision:'same-build; exact source hashes below; deployed revision in ../../revision.txt',strategyOrigins:{longTerm:'88a43757762114a506f57ed4b44484306cae1aaa',assignment:'fcaa84f3bf9058f4ede0a097d16d0e3571590a6b',horizonCorrection:'1557813737941901572'},sourceDocuments,assignment:'AI_Architect_Test_Task.pdf',talkMinutes:slides.slice(0,17).reduce((a,s)=>a+s.minutes,0),discussionMinutes:15,slides:slides.map(({id,title,minutes,sources},i)=>({number:i+1,id,title,minutes,sources:[...new Set(sources)]}))},null,2)); const assignmentQuestions = [
{question:'1. What you do',slides:['starting-point','influence','months-one-two','months-three-four','months-five-six','capacity']},
{question:'2. How you measure it',slides:['measures','misleading','qualification','experiment']},
{question:'3. What you achieve',slides:['six-month-target','month-six']},
{question:'4. What comes next',slides:['target','contributors','roadmap','learning-loop','beyond','authority']},
];
const diagramSources = await Promise.all(['diagrams/strategy-target.architecture.json','diagrams/strategy-target-mobile.architecture.json'].map(async path=>({path,sha256:createHash('sha256').update(await readFile(path)).digest('hex')})));
await writeFile(`${out}/source-map.json`,JSON.stringify({version:'1.1.0',assignmentQuestions,diagramSources,strategyRevision:'same-build; exact source hashes below; deployed revision in ../../revision.txt',strategyOrigins:{longTerm:'88a43757762114a506f57ed4b44484306cae1aaa',assignment:'fcaa84f3bf9058f4ede0a097d16d0e3571590a6b',horizonCorrection:'1557813737941901572'},sourceDocuments,assignment:'AI_Architect_Test_Task.pdf',talkMinutes:slides.filter(s=>s.track==='main').reduce((a,s)=>a+s.minutes,0),discussionMinutes:slides.filter(s=>s.track==='discussion').reduce((a,s)=>a+s.minutes,0),appendixMinutes:0,timingNote:'Revised presentation allocation; PDF specifies 50 total, not the split. The six-month Strategy page retains its earlier proposed outline.',slides:slides.map(({id,title,minutes,sources,section,track},i)=>({number:i+1,id,title,minutes,section,track,sources:[...new Set(sources)]}))},null,2));
console.log(`Built ${slides.length} local Reveal.js slides at ${out}`); console.log(`Built ${slides.length} local Reveal.js slides at ${out}`);
+74 -8
View File
@@ -6,19 +6,56 @@ import {execFileSync} from 'node:child_process';
import {slides} from '../presentations/less-prompting-more-shipping/slides.mjs'; import {slides} from '../presentations/less-prompting-more-shipping/slides.mjs';
const read=p=>readFileSync(p,'utf8'); const read=p=>readFileSync(p,'utf8');
test('deck preserves assignment coverage, 35+15 timing and traceable notes',()=>{ test('deck preserves assignment coverage, 35+15 timing and traceable notes',()=>{
assert.equal(slides.length,19); assert.equal(new Set(slides.map(s=>s.id)).size,19); assert.equal(slides.length,23); assert.equal(new Set(slides.map(s=>s.id)).size,23);
assert.equal(slides.slice(0,17).reduce((n,s)=>n+s.minutes,0),35); assert.equal(slides.filter(s=>s.track==='main').reduce((n,s)=>n+s.minutes,0),35);
assert.equal(slides[17].minutes,15); assert.equal(slides[18].minutes,0); assert.equal(slides.find(s=>s.track==='discussion').minutes,15); assert.equal(slides.find(s=>s.track==='appendix').minutes,0);
for(const s of slides){assert(s.sources.length);assert(s.notes.length>250);assert(s.body.length);} for(const s of slides){assert(s.sources.length);assert(s.notes.length>250);assert(s.body.length);}
for(const id of ['months-one-two','months-three-four','months-five-six','measures','month-six','beyond']) assert(slides.some(s=>s.id===id)); for(const id of ['months-one-two','months-three-four','months-five-six','measures','month-six','beyond']) assert(slides.some(s=>s.id===id));
for(const id of ['experiment','inconclusive','stop']) assert.match(slides.find(s=>s.id===id).body,/fictional/i); 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/); 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('measurement names five numerical candidates and separates populations',()=>{
const s=slides.find(s=>s.id==='measures');
assert.equal(s.minutes,2);
assert.equal(s.title,'Measure better work—and skill health');
for(const label of ['Validated task success (%)','Changes with escaped quality issues (%)','Cost per accepted outcome','currency/outcome','Skill selection precision (%)','Skills within substantive review window (%)','Baseline → pilot','Independent quality qualification still required','Choose relevant measures','Unknown is not zero','Skill health is not productivity proof']) assert(s.body.includes(label),label);
assert.equal((s.body.match(/class="metric"/g)||[]).length,5);
for(const text of ['matured eligible starts','completed follow-up','labeled evaluation','active approved revisions'])assert(s.body.includes(text),text);
for(const name of ['validated-task-success','changes-with-escaped-quality-issues','cost-per-accepted-outcome','skill-selection-precision','skills-within-substantive-review-window'])assert(s.sources.includes('measurement/'+name));
for(const term of ['N/A','unknown','unimplemented','partial','review/rework','like-for-like','zero accepted'])assert(s.notes.includes(term),term);
assert.doesNotMatch(s.body,/Accepted work<|\d+%/);
});
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',()=>{ test('build emits local pinned Reveal assets, stable IDs and no production CDN',()=>{
execFileSync(process.execPath,['scripts/build-presentations.mjs']); execFileSync(process.execPath,['scripts/build-presentations.mjs']);
const dir='static/presentations/less-prompting-more-shipping'; const html=read(`${dir}/index.html`); const dir='static/presentations/less-prompting-more-shipping'; const html=read(`${dir}/index.html`);
assert.equal((html.match(/<section /g)||[]).length,19); assert.equal((html.match(/<section /g)||[]).length,23);
assert.equal((html.match(/class="notes"/g)||[]).length,19); assert.equal((html.match(/class="notes"/g)||[]).length,23);
assert(!/https?:\/\//.test(html)); assert(!/https?:\/\//.test(html));
assert.match(html,/href="\.\.\/\.\.\/strategy\/target-operating-model\/"/); assert.match(html,/href="\.\.\/\.\.\/strategy\/target-operating-model\/"/);
assert.match(read(`${dir}/assets/reveal.js`),/5\.2\.1/); assert.match(read(`${dir}/assets/reveal.js`),/5\.2\.1/);
@@ -26,10 +63,39 @@ test('build emits local pinned Reveal assets, stable IDs and no production CDN',
assert.equal(JSON.parse(read('package.json')).dependencies['reveal.js'],'5.2.1'); assert.equal(JSON.parse(read('package.json')).dependencies['reveal.js'],'5.2.1');
assert.match(read('src/components/PresentationEmbed/index.tsx'),/Open presentation/); assert.match(read('src/components/PresentationEmbed/index.tsx'),/Open presentation/);
const map=JSON.parse(read(`${dir}/source-map.json`)); const map=JSON.parse(read(`${dir}/source-map.json`));
assert.equal(map.version,'1.0.1'); assert.equal(map.version,'1.1.0');
assert.equal(map.assignmentQuestions.length,4);
for(const question of map.assignmentQuestions)for(const id of question.slides)assert(slides.some(s=>s.id===id));
for(const doc of map.diagramSources)assert.equal(doc.sha256,createHash('sha256').update(read(doc.path)).digest('hex'));
assert.match(map.strategyRevision,/same-build/); assert.match(map.strategyRevision,/same-build/);
for(const doc of map.sourceDocuments) assert.equal(doc.sha256,createHash('sha256').update(read(doc.path)).digest('hex'),doc.path); for(const doc of map.sourceDocuments) assert.equal(doc.sha256,createHash('sha256').update(read(doc.path)).digest('hex'),doc.path);
for(const id of ['target-operating-model','roadmap','six-months-target','six-months-roadmap','stage-02-autonomous-agent']) assert(map.sourceDocuments.some(d=>d.id===id),id); for(const id of ['target-operating-model','roadmap','six-months-target','six-months-roadmap','stage-02-autonomous-agent']) assert(map.sourceDocuments.some(d=>d.id===id),id);
assert(slides.find(s=>s.id==='beyond').notes.includes('long-term destination remains human-directed')); assert(slides.find(s=>s.id==='beyond').notes.includes('long-term destination remains human-directed'));
for(const id of ['months-one-two','months-three-four','months-five-six','capacity','experiment','inconclusive','stop']) assert(slides.find(s=>s.id===id).sources.includes('six-months-roadmap'),id); for(const id of ['months-one-two','months-three-four','months-five-six','capacity','experiment']) assert(slides.find(s=>s.id===id).sources.includes('six-months-roadmap'),id);
});
test('visible strategy narrative preserves five-page order and short experiment',()=>{
const index=id=>slides.findIndex(s=>s.id===id);
const sequence=['starting-point','target','contributors','roadmap','learning-loop','six-month-target','months-one-two','months-three-four','months-five-six','experiment','month-six','beyond','authority','discussion'];
for(let i=1;i<sequence.length;i++)assert(index(sequence[i])>index(sequence[i-1]),sequence[i]);
assert.match(slides[index('target')].body,/Autonomous agent/);
assert.match(slides[index('roadmap')].body,/Order undecided/);
assert.match(slides[index('roadmap')].body,/Delivery keeps improving/);
assert.match(slides[index('learning-loop')].body,/Triggers → skills → handoffs → acceptance/);
assert(!slides.some(s=>s.id==='inconclusive'||s.id==='stop'));
assert(!slides[index('experiment')].body.includes('<table>'));
assert.match(slides[index('experiment')].notes,/40-minute median against 30 baseline/);
assert.equal(slides[index('experiment')].minutes,2);
assert.equal(slides.filter(s=>s.track==='appendix').reduce((a,s)=>a+s.minutes,0),0);
});
test('presentation topology preserves all original relationships across two readable views',async()=>{
const {topology,cycleFigure,contributionsFigure}=await import('../presentations/less-prompting-more-shipping/target-figure.mjs');
const original=JSON.parse(read('diagrams/strategy-target.architecture.json'));
const pairs=prefix=>original.connections.filter(c=>c.id.startsWith(prefix)).map(c=>[c.from,c.to]).sort();
assert.deepEqual([...topology.lifecycle].sort(),pairs('stage-'));
assert.deepEqual([...topology.governance].sort(),pairs('govern-'));
assert.deepEqual([...topology.contributions].sort(),pairs('contribute-'));
for(const [from,to] of [...topology.lifecycle,...topology.governance])assert(cycleFigure.includes(`data-from="${from}" data-to="${to}"`));
for(const [from,to] of topology.contributions)assert(contributionsFigure.includes(`data-from="${from}" data-to="${to}"`));
assert.equal((cycleFigure.match(/data-node="agent"/g)||[]).length,2); // desktop + recomposed phone
}); });