diff --git a/.gitignore b/.gitignore index 126ad6f..0e4328b 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,4 @@ build/ .env.* !.env.example static/diagrams/ +static/presentations/ diff --git a/package.json b/package.json index 1e9691c..721dc3f 100644 --- a/package.json +++ b/package.json @@ -7,9 +7,11 @@ "node": ">=22" }, "scripts": { - "start": "pnpm diagrams:build && docusaurus start", - "build": "pnpm diagrams:build && docusaurus build", + "start": "pnpm diagrams:build && pnpm presentations:build && docusaurus start", + "build": "pnpm diagrams:build && pnpm presentations:build && docusaurus build", + "presentations:build": "node scripts/build-presentations.mjs", "serve": "docusaurus serve", + "test:presentation": "node scripts/browser/presentation.cjs", "typecheck": "tsc --noEmit", "verify": "pnpm test && node scripts/verify.mjs", "verify:build": "node scripts/verify.mjs --build", @@ -29,7 +31,8 @@ "clsx": "2.1.1", "prism-react-renderer": "2.4.1", "react": "19.1.1", - "react-dom": "19.1.1" + "react-dom": "19.1.1", + "reveal.js": "5.2.1" }, "devDependencies": { "@docusaurus/module-type-aliases": "3.10.2", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index e96ff24..2f67f05 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -44,6 +44,9 @@ importers: react-dom: specifier: 19.1.1 version: 19.1.1(react@19.1.1) + reveal.js: + specifier: 5.2.1 + version: 5.2.1 devDependencies: '@docusaurus/module-type-aliases': specifier: 3.10.2 @@ -4634,6 +4637,10 @@ packages: resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==} engines: {iojs: '>=1.0.0', node: '>=0.10.0'} + reveal.js@5.2.1: + resolution: {integrity: sha512-r7//6mIM5p34hFiDMvYfXgyjXqGRta+/psd9YtytsgRlrpRzFv4RbH76TXd2qD+7ZPZEbpBDhdRhJaFgfQ7zNQ==} + engines: {node: '>=18.0.0'} + rtlcss@4.3.0: resolution: {integrity: sha512-FI+pHEn7Wc4NqKXMXFM+VAYKEj/mRIcW4h24YVwVtyjI+EqGrLc2Hx/Ny0lrZ21cBWU2goLy36eqMcNj3AQJig==} engines: {node: '>=12.0.0'} @@ -11634,6 +11641,8 @@ snapshots: reusify@1.1.0: {} + reveal.js@5.2.1: {} + rtlcss@4.3.0: dependencies: escalade: 3.2.0 diff --git a/presentations/less-prompting-more-shipping/README.md b/presentations/less-prompting-more-shipping/README.md new file mode 100644 index 0000000..b76e031 --- /dev/null +++ b/presentations/less-prompting-more-shipping/README.md @@ -0,0 +1,39 @@ +# Less Prompting, More Shipping — v1.0.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 content. Read together with the reviewed Strategy at revision `fcaa84f3bf9058f4ede0a097d16d0e3571590a6b`; it is not a second Strategy landing page. + +## 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. +- `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. +- `runtime.js`: Reveal initialization, reduced motion, portrait/orientation adaptation and accessible toolbar. +- `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. + +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. + +## Present + +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. + +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. + +## Verify + +`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 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 + +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. + +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. diff --git a/presentations/less-prompting-more-shipping/runtime.js b/presentations/less-prompting-more-shipping/runtime.js new file mode 100644 index 0000000..b28f26f --- /dev/null +++ b/presentations/less-prompting-more-shipping/runtime.js @@ -0,0 +1,27 @@ +/* Reveal 5.2.1, fully local runtime; this document is isolated from Docusaurus CSS. */ +const reducedMotion = window.matchMedia('(prefers-reduced-motion: reduce)'); +const portrait = window.matchMedia('(max-width: 700px) and (orientation: portrait)'); +const printing = new URLSearchParams(location.search).has('print-pdf'); +function layoutSize(){ + const narrow=portrait.matches&&!printing; + document.documentElement.classList.toggle('portrait',narrow); + return narrow?{width:600,height:1000}:{width:1200,height:660}; +} +Reveal.initialize({ + ...layoutSize(), margin:0.04, minScale:0.1, maxScale:2, + hash:true, hashOneBasedIndex:false, controls:true, progress:true, + slideNumber:'c/t', showSlideNumber:'all', center:false, + transition:reducedMotion.matches?'none':'fade', transitionSpeed:'fast', + backgroundTransition:'none', autoSlide:0, touch:true, keyboard:true, + // Keep deliberate slides on phones rather than Reveal's automatic scroll view. + scrollActivationWidth:null, pdfMaxPagesPerSlide:1, pdfSeparateFragments:false, + plugins:[RevealNotes] +}); +portrait.addEventListener('change',()=>Reveal.configure(layoutSize())); +reducedMotion.addEventListener('change',event=>Reveal.configure({transition:event.matches?'none':'fade'})); +document.getElementById('overview').addEventListener('click',()=>Reveal.toggleOverview()); +document.getElementById('notes').addEventListener('click',()=>Reveal.getPlugin('notes').open()); +document.getElementById('fullscreen').addEventListener('click',()=>{ + if(document.fullscreenElement) document.exitFullscreen(); + else document.documentElement.requestFullscreen?.(); +}); diff --git a/presentations/less-prompting-more-shipping/slides.mjs b/presentations/less-prompting-more-shipping/slides.mjs new file mode 100644 index 0000000..877492d --- /dev/null +++ b/presentations/less-prompting-more-shipping/slides.mjs @@ -0,0 +1,23 @@ +// Editorial source: concise visible story + spoken argument + traceable references. +const s = (id, title, minutes, body, notes, sources, kind='') => ({id,title,minutes,body,notes,sources,kind}); +export const slides = [ + s('opening','Less Prompting,
More Shipping',1,`

The AI Architect’s First Six Months

Improve accepted engineering work.
Not the number of times we ask AI.

Proposed strategy · 35 minutes + 15 minutes Q&A

`, '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','target-operating-model'], 'dark'), + s('starting-point','We are not starting from “no AI”.',2,`
≈80 → ≈100engineers, by year end
>10teams
Already using AIuneven depth and quality

Assignment facts
Solo architect → CTO
No formal authority over teams

Unknown until discovery
Stack, tools, process, baselines
Capacity and actual bottlenecks

`, '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','target-operating-model']), + s('north-star','A faster draft is not a shipped outcome.',2,`
Intent→Change + tests→Independent acceptance
Existing release authority stays with people.

Less rework. Sound quality.
Understand the total burden.

If the bottleneck is CI or review capacity, fix that—not the prompt count.

`, '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.', ['target-operating-model','baseline','measurement']), + s('influence','Influence is earned beside the work.',2,`
CTOSponsor access
Resolve priority trade-offs
ArchitectPair, build, evaluate
Bring evidence—not mandates
Willing teamAgree contribution
Own acceptance and upkeep

An invitation with an exit.
Not a rollout disguised as a favor.

`, '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.', ['roadmap','stage-01-skills-adoption']), + s('months-one-two','Months 1–2 / Earn the right to test.',3,`
01 · Discover

Trace real changes.
Rank friction and evidence gaps.

Output: current-work map
02 · Agree

One willing team.
Baseline + smallest intervention.

Output: bounded experiment packet
Decision 1 → Fund one experiment—or hold.

No partner, reliable checks or lawful evidence → no live pilot.

`, '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.', ['roadmap','baseline']), + s('months-three-four','Months 3–4 / Test, then decide.',3,`
03 · Work alongside

Build and independently qualify.
Pair on bounded real work.

Output: failures + reproducible examples
04 · Compare

Reconcile outcomes and burden.
Include pending and abandoned work.

Output: retain / change / hold / stop
Decision 2 → Keep only what the evidence supports.

Missing follow-up is “unknown”, not “all clear”.

`, '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.', ['roadmap','stage-01-skills-adoption']), + s('months-five-six','Months 5–6 / Transfer only if earned.',2,`
05 · Selective transfer

Champion + backup.
Check a second team’s fit.

Only with capacity and funded upkeep
06 · Evidence review

Team operates without daily help.
CTO chooses the next investment.

Owned workflow—or documented stop

New scope → new baseline.
No automatic company-wide rollout.

`, '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.', ['roadmap','target-operating-model']), + s('capacity','One architect. One active live pilot.',2,`
2 days
Pair + build
1 day
Evaluate
1 day
Relationships
1 day
Decisions + buffer

Support is work.
Put it in the budget.

Proposed capacity envelope—not known company availability.

`, '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.', ['roadmap']), + s('measures','Three measures. One decision.',3,`
Accepted workAccepted / all matured eligible starts
Review + reworkComparable effort, including shifted burden
Escaped defectsSeverity and complete follow-up
Alongside: setup, support, upkeep and tool cost. Critical effects stop work.

Task / PR / CI / defect links + a small effort record; no individual league tables.

`, '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','stage-01-skills-adoption']), + s('misleading','A dashboard can be confidently wrong.',2,`

Tempting signal
More PRs or generated lines
Shorter PR elapsed time
Higher acceptance rate
No defects recorded

Question before believing it
Useful work—or smaller slices?
Less effort—or less waiting?
Same task mix and denominator?
Enough follow-up and linkage?

AI usage is diagnostic.
It is not the score.

`, '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','stage-01-skills-adoption']), + s('experiment','EXP-01 / Start cheaper than a platform.',2,`

Fictional teaching example · not Eldorado data or approval

Review returns:
missing test evidence
→Test map +
checklist first
→Skill only if
context loss persists

Small bug fixes. One repository.
Current AI practice is the comparator.

Exclude secrets, personal data, migrations and production permissions.

`, '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.', ['stage-01-skills-adoption']), + s('qualification','“It worked once” is not a release gate.',2,`
Pin candidate
and environment
→Independent
qualification
→Separate
pilot permission

Try to break it
Wrong task · injected instruction
Missing tests · recovery

First revision
No approved prior skill = N/A
Remove + reload → current practice

Failed mandatory safety checks → HOLD. An average cannot override them.
`, '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.', ['stage-01-skills-adoption','skills-quality']), + s('inconclusive','First review / Do not promote this result.',2,`

EXP-01 · fictional observations · not company performance

EvidenceBaselinePilot, first review
Accepted / matured starts8 / 129 / 12
Effort records12 / 129 / 12 only
Mature defect follow-up8 / 8 accepted6 / 9 accepted
INCONCLUSIVE → Hold expansion. Finish evidence—or stop.

Three later starts remain pending. Missing evidence is not zero cost.

`, '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.', ['stage-01-skills-adoption']), + s('stop','A useful answer can be “stop this one”.',2,`

EXP-01 · fictional reconciled burden · not a causal productivity estimate

30 minBaseline median review / rework
→
40 minPilot median, all 12 records

The predeclared burden guardrail is breached.

Stop candidate → verify recovery → keep useful checklist → requalify any revision
`, '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.', ['stage-01-skills-adoption']), + s('month-six','Month six / An evidence portfolio, not a victory lap.',2,`
Visible changeEvidence to ask for
One workflow understoodMap + baseline + explicit gaps
Retained practice—or justified stopComparable outcomes + costs + limits
Less dependence on the architectOwner + backup + recovery rehearsal

Proposed achievable picture. No guaranteed savings, headcount reduction or org-wide uplift.

`, '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.', ['target-operating-model','roadmap']), + s('beyond','Beyond six months / Choose, do not graduate.',2,`
Deepen

Coaching, context or deterministic tooling where friction remains.

Transfer

Only with repeatable value, local fit and supported ownership.

Bounded autonomy?

Separate authority case, containment and human takeover.

More authority is a new decision.
Not a reward for adoption.

`, '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 conditional long-term Target is a reference, not a month-six deliverable or deployed system. The CTO chooses investment based on the evidence, not an inevitable maturity staircase.', ['stage-02-autonomous-agent','target-operating-model']), + s('alignment','The first CTO conversation',1,`
  1. Which outcome is worth improving first?
  2. Who can volunteer time—and independent review?
  3. What data, risk and effort limits apply?
  4. When will we decide to continue or stop?

Sponsor the learning.
Do not pre-approve the answer.

`, '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','roadmap'], 'dark'), + s('discussion','Q&A / What would change your mind?',15,`

15 minutes for the hard questions.

No willing team?

Too little evidence?

A cheaper non-AI fix?

The proposed plan can change. The evidence standard should not.

`, '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','target-operating-model'], 'dark'), + s('references','References / Follow the evidence.',0,``, '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','target-operating-model','roadmap','stage-01-skills-adoption','measurement','stage-02-autonomous-agent']) +]; diff --git a/presentations/less-prompting-more-shipping/theme.css b/presentations/less-prompting-more-shipping/theme.css new file mode 100644 index 0000000..d6a9697 --- /dev/null +++ b/presentations/less-prompting-more-shipping/theme.css @@ -0,0 +1,58 @@ +@font-face{font-family:Lato;src:url(./assets/lato-latin-400-normal.woff2) format('woff2');font-weight:400;font-display:swap} +@font-face{font-family:Lato;src:url(./assets/lato-latin-700-normal.woff2) format('woff2');font-weight:700;font-display:swap} +@font-face{font-family:Lato;src:url(./assets/lato-latin-900-normal.woff2) format('woff2');font-weight:900;font-display:swap} +:root{--gold:#ffc950;--ink:#14131a;--paper:#f6f6f6} +body{margin:0;background:var(--paper);color:var(--ink)} +.deck{font:30px/1.35 Lato,sans-serif;color:var(--ink)} +.deck .slides{text-align:left} +.deck .slides section{box-sizing:border-box;padding:48px 52px;height:660px} +.deck h1,.deck h2{font-weight:900;letter-spacing:-.045em;line-height:1.07;margin:18px 0 30px;color:inherit;text-transform:none} +.deck h1{font-size:80px;max-width:960px}.deck h2{font-size:52px;max-width:1020px} +.deck p{margin:20px 0}.deck .eyebrow{font-size:17px;letter-spacing:.15em;font-weight:900;color:#805b00;margin:0} +.deck .subtitle{font-size:34px}.deck .thesis{font-size:37px;margin-top:52px;border-left:6px solid var(--gold);padding-left:24px} +.deck .small{font-size:21px;line-height:1.4;color:#62616b;margin-top:24px}.deck .statement{font-size:35px;font-weight:700;margin-top:32px} +.deck .dark{color:var(--paper)}.deck .dark .eyebrow,.deck .dark h1{color:var(--gold)}.deck .dark .small{color:#d5d4dc} +.deck .facts{display:flex;gap:40px;justify-content:space-between;margin:35px 0}.deck .facts strong{display:block;font-size:43px;line-height:1.12}.deck .facts span{display:block;font-size:24px;margin-top:12px} +.deck .contrast{display:grid;grid-template-columns:1fr 1fr;gap:44px;border-top:2px solid #dedee3;margin-top:28px;padding-top:8px}.deck .contrast p{font-size:27px;line-height:1.55}.deck .contrast b{color:#805b00;display:inline-block;margin-bottom:10px} +.deck .flow{display:flex;align-items:stretch;gap:18px;margin:40px 0 26px}.deck .flow span{flex:1;border:2px solid #14131a;padding:24px 18px;font-weight:700;font-size:27px;text-align:center;display:flex;align-items:center;justify-content:center}.deck .flow i{align-self:center;font-style:normal} +.deck .rail{border-left:6px solid var(--gold);padding:16px 24px;background:#e9e9ec;font-size:25px;font-weight:700} +.deck .roles{display:grid;grid-template-columns:1fr 1.2fr 1fr;gap:18px;margin:32px 0}.deck .roles div{padding:24px;border:2px solid #14131a}.deck .roles b{display:block;font-size:34px;margin-bottom:18px}.deck .roles span{font-size:26px;line-height:1.5}.deck .roles .gold{background:var(--gold)} +.deck .timeline{display:grid;grid-template-columns:1fr 1fr;gap:46px;margin:35px 0}.deck .timeline>div{border-top:8px solid var(--gold);padding-top:20px}.deck .timeline b{font-size:35px}.deck .timeline p{font-size:28px}.deck .timeline span{font-size:23px;color:#62616b} +.deck .gate{background:var(--ink);color:var(--gold);font-size:29px;font-weight:900;padding:20px 24px} +.deck .capacity{display:flex;margin:50px 0;gap:5px}.deck .capacity>div{flex:1;background:#e3e3e7;font-size:25px;padding:28px 16px;border-bottom:5px solid var(--ink)}.deck .capacity .pair{flex:2;background:var(--gold)}.deck .capacity b{display:block;margin-top:18px;font-size:24px} +.deck .measure-list>div{display:grid;grid-template-columns:310px 1fr;gap:24px;border-top:1px solid #b8b7c0;padding:20px 0}.deck .measure-list b{font-size:32px}.deck .measure-list span{font-size:27px}.deck .measure-list{margin-bottom:24px} +.deck .fiction{display:inline-block;background:#fff0cd;color:#594000;font-size:21px;padding:7px 12px;margin:0} +.deck table{width:100%;border-collapse:collapse;margin:22px 0;font-size:25px}.deck th,.deck td{text-align:left;border-bottom:1px solid #b8b7c0;padding:15px 10px}.deck th{font-weight:900;font-size:23px;background:#e9e9ec} +.deck .comparison{display:flex;align-items:center;gap:35px;margin:40px 0}.deck .comparison div{flex:1}.deck .comparison strong{display:block;font-size:80px;letter-spacing:-.05em}.deck .comparison span{font-size:23px}.deck .comparison .versus{font-size:50px} +.deck .ledger{margin:40px 0}.deck .ledger>div{display:grid;grid-template-columns:1fr 1fr;gap:32px;padding:21px 0;border-bottom:1px solid #b8b7c0;font-size:27px}.deck .ledger b{color:#805b00} +.deck .choices{display:grid;grid-template-columns:repeat(3,1fr);gap:28px;margin:40px 0}.deck .choices>div{border-top:6px solid var(--gold);padding-top:20px}.deck .choices b{font-size:33px}.deck .choices p{font-size:27px} +.deck .asks{font-size:33px;line-height:1.6;margin:35px 0 0;padding-left:38px}.deck .asks li{padding-left:12px} +.deck .discussion{display:flex;flex-direction:column;border-left:5px solid var(--gold);padding-left:28px;margin-top:40px}.deck .discussion p{font-size:36px;margin:10px 0} +.deck a{color:#805b00;text-decoration:underline}.deck .references{font-size:27px;line-height:1.5;padding-left:28px}.deck .references li{margin:12px 0}.deck .references span{font-size:22px;color:#62616b} +.deck .controls{color:#805b00}.deck .slide-number{font:16px Lato,sans-serif;background:#14131a;color:#fff;left:18px;right:auto;bottom:18px;padding:8px} +.deck .progress{color:#805b00;height:4px} +.toolbar{position:fixed;z-index:30;top:0;left:0;right:0;display:flex;align-items:center;gap:16px;background:#101014;color:#fff;padding:8px 18px;font:14px Lato,sans-serif;min-height:32px;box-sizing:content-box} +.toolbar a{color:var(--gold)}.toolbar button{font:inherit;color:white;border:1px solid #62616b;background:transparent;padding:6px 10px;cursor:pointer}.toolbar .help{margin-left:auto} +a:focus-visible,button:focus-visible{outline:3px solid #b88719;outline-offset:3px} +.reveal.deck{height:calc(100dvh - 48px);top:48px} +@media(max-width:600px){.toolbar{gap:9px;font-size:12px;padding:8px}.toolbar .help{display:none}.toolbar button{padding:6px}.deck .controls{bottom:18px}} +/* Portrait is re-composed, not a postage-stamp landscape slide. */ +.portrait .deck .slides section{height:1000px;padding:28px} +.portrait .deck h1{font-size:64px}.portrait .deck h2{font-size:43px;margin-bottom:24px} +.portrait .deck .facts{flex-wrap:wrap;gap:28px;margin:30px 0}.portrait .deck .facts strong{font-size:38px} +.portrait .deck .contrast{grid-template-columns:1fr;gap:0;margin-top:20px}.portrait .deck .contrast p{font-size:27px;margin:14px 0;line-height:1.4} +.portrait .deck .flow{flex-direction:column;gap:8px;margin:24px 0}.portrait .deck .flow span{padding:14px;font-size:27px}.portrait .deck .flow i{transform:rotate(90deg);line-height:1} +.portrait .deck .roles{grid-template-columns:1fr;gap:12px}.portrait .deck .roles div{padding:18px}.portrait .deck .roles b{font-size:30px;margin-bottom:8px}.portrait .deck .roles span{font-size:26px} +.portrait .deck .timeline{grid-template-columns:1fr;gap:24px;margin:25px 0}.portrait .deck .timeline>div{padding-top:14px}.portrait .deck .timeline p{margin:14px 0;font-size:28px} +.portrait .deck .statement{font-size:33px;margin-top:28px}.portrait .deck .rail{font-size:25px;padding:16px}.portrait .deck .gate{font-size:27px;padding:18px} +.portrait .deck .capacity{display:grid;grid-template-columns:1fr 1fr;gap:8px}.portrait .deck .capacity>div{padding:24px 16px} +.portrait .deck .measure-list>div{grid-template-columns:1fr;gap:10px}.portrait .deck .measure-list b{font-size:31px} +.portrait .deck .fiction{font-size:22px}.portrait .deck table{font-size:23px;table-layout:fixed}.portrait .deck th{font-size:22px}.portrait .deck th,.portrait .deck td{padding:15px 8px} +.portrait .deck .comparison{gap:20px}.portrait .deck .comparison strong{font-size:54px}.portrait .deck .comparison span{font-size:24px} +.portrait .deck .ledger>div{font-size:26px;gap:20px}.portrait .deck .choices{grid-template-columns:1fr;gap:20px}.portrait .deck .choices>div{padding-top:12px}.portrait .deck .choices p{margin:10px 0} +.portrait .deck .asks{font-size:31px;line-height:1.45}.portrait .deck .asks li{margin:22px 0}.portrait .deck .small{font-size:24px} +.portrait #qualification .contrast{grid-template-columns:1fr 1fr;gap:24px}.portrait #qualification .contrast p{font-size:24px} +.portrait .deck .references{font-size:29px}.portrait .deck .references li{margin:22px 0} +@media(prefers-reduced-motion:reduce){*{transition:none!important;animation:none!important}} +@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%} diff --git a/scripts/browser/presentation.cjs b/scripts/browser/presentation.cjs new file mode 100644 index 0000000..237fb6b --- /dev/null +++ b/scripts/browser/presentation.cjs @@ -0,0 +1,51 @@ +const {chromium}=require('playwright'); +const fs=require('node:fs'); const assert=require('node:assert/strict'); +(async()=>{ + const base=process.argv[2]||'http://127.0.0.1:4179'; const root='/eldorado-v1/documentation/';const url=base+root+'presentations/less-prompting-more-shipping/'; + const out='.cache/presentation';fs.mkdirSync(out,{recursive:true}); + const browser=await chromium.launch({headless:true,args:['--no-sandbox'],executablePath:process.env.PLAYWRIGHT_CHROMIUM_EXECUTABLE}); + const results=[]; + try{ + for(const viewport of [{width:1440,height:900},{width:390,height:844},{width:844,height:390}]){ + const context=await browser.newContext({viewport,hasTouch:viewport.width<1000,reducedMotion:'reduce'}); + 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); + 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.getConfig().transition),'none'); + const bounds=[]; + for(let i=0;i<19;i++){ + await page.evaluate(i=>Reveal.slide(i),i);await page.waitForTimeout(60); + const bad=await page.evaluate(()=>{ + 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.lefte.textContent.slice(0,60)); + }); + bounds.push({slide:i+1,overflow:bad}); + 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)); + 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.keyboard.press('ArrowRight');assert.equal(await page.evaluate(()=>Reveal.getCurrentSlide().id),'inconclusive');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())); + 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); + const popupPromise=context.waitForEvent('page');await page.getByRole('button',{name:'Notes',exact:true}).click();const popup=await popupPromise;await popup.waitForLoadState();await popup.waitForFunction(()=>document.body.innerText.includes('The author cannot approve'),{timeout:10000});await popup.screenshot({path:`${out}/speaker-view.png`});await popup.close(); + } else { + const client=await context.newCDPSession(page); + const before=await page.evaluate(()=>Reveal.getIndices().h); + await client.send('Input.dispatchTouchEvent',{type:'touchStart',touchPoints:[{x:viewport.width*.8,y:viewport.height*.5}]}); + await client.send('Input.dispatchTouchEvent',{type:'touchMove',touchPoints:[{x:viewport.width*.2,y:viewport.height*.5}]}); + await client.send('Input.dispatchTouchEvent',{type:'touchEnd',touchPoints:[]}); + assert.equal(await page.evaluate(()=>Reveal.getIndices().h),before+1); + } + 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); + 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(); + } + 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}); + assert.equal(await page.locator('.pdf-page').count(),19); + 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'); + }finally{await browser.close()} +})().catch(e=>{console.error(e);process.exitCode=1}); diff --git a/scripts/build-presentations.mjs b/scripts/build-presentations.mjs new file mode 100644 index 0000000..bfff6d9 --- /dev/null +++ b/scripts/build-presentations.mjs @@ -0,0 +1,17 @@ +import {mkdir,copyFile,writeFile} from 'node:fs/promises'; +import {slides} from '../presentations/less-prompting-more-shipping/slides.mjs'; +const root='presentations/less-prompting-more-shipping'; +const out=`static/${root}`; +await mkdir(`${out}/assets`,{recursive:true}); +for(const [src,dest] of [['dist/reveal.js','reveal.js'],['dist/reveal.css','reveal.css'],['plugin/notes/notes.js','notes.js'],['LICENSE','REVEAL-LICENSE']]) await copyFile(`node_modules/reveal.js/${src}`,`${out}/assets/${dest}`); +for(const weight of [400,700,900]) await copyFile(`node_modules/@fontsource/lato/files/lato-latin-${weight}-normal.woff2`,`${out}/assets/lato-latin-${weight}-normal.woff2`); +await copyFile('node_modules/@fontsource/lato/LICENSE',`${out}/assets/LATO-LICENSE`); +await copyFile(`${root}/theme.css`,`${out}/theme.css`); +const esc=s=>s.replaceAll('&','&').replaceAll('<','<').replaceAll('>','>').replaceAll('"','"'); +await writeFile(`${out}/index.html`,`Less Prompting, More Shipping | Eldorado + +
${slides.map((s,i)=>`

ELDORADO / ${i===17?'DISCUSSION':i===18?'REFERENCE':'AI STRATEGY'}

<${i?'h2':'h1'}>${s.title}${s.body}
`).join('\n')}
+`); +await copyFile(`${root}/runtime.js`,`${out}/runtime.js`); +await writeFile(`${out}/source-map.json`,JSON.stringify({version:'1.0.0',strategyRevision:'fcaa84f3bf9058f4ede0a097d16d0e3571590a6b',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}))},null,2)); +console.log(`Built ${slides.length} local Reveal.js slides at ${out}`); diff --git a/scripts/presentation.test.mjs b/scripts/presentation.test.mjs new file mode 100644 index 0000000..eaf6fcc --- /dev/null +++ b/scripts/presentation.test.mjs @@ -0,0 +1,27 @@ +import test from 'node:test'; +import assert from 'node:assert/strict'; +import {readFileSync} from 'node:fs'; +import {execFileSync} from 'node:child_process'; +import {slides} from '../presentations/less-prompting-more-shipping/slides.mjs'; +const read=p=>readFileSync(p,'utf8'); +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.slice(0,17).reduce((n,s)=>n+s.minutes,0),35); + assert.equal(slides[17].minutes,15); assert.equal(slides[18].minutes,0); + 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 ['experiment','inconclusive','stop']) assert.match(slides.find(s=>s.id===id).body,/fictional/i); + assert.match(slides.find(s=>s.id==='qualification').notes,/separately authorizes/); +}); +test('build emits local pinned Reveal assets, stable IDs and no production CDN',()=>{ + execFileSync(process.execPath,['scripts/build-presentations.mjs']); + const dir='static/presentations/less-prompting-more-shipping'; const html=read(`${dir}/index.html`); + assert.equal((html.match(/
+
+

THE AI ARCHITECT’S FIRST SIX MONTHS

+

Less Prompting, More Shipping

+

A practical conversation about improving accepted engineering work: one willing team, a bounded experiment, honest measurement and an evidence-led next step.

+

35-minute presentation · 15-minute discussion · proposed strategy, not company results.

+ Open presentation +
; }