# Digitaltableteur: Full Context > Helsinki-based design systems consultancy that builds, audits and scales design systems and ships open-source tools that prove the expertise. Every article below is inlined in full. Offer pages and blog posts are also available as Markdown by adding .md to the URL; listed case studies have a Markdown summary at their URL plus .md. ## Identity - Name: Digitaltableteur - Founder: Petri Lahdelma - Location: Hämeentie 8 C, 00530 Helsinki, Finland - Business ID: 2226445-2 (Finnish sole proprietorship, est. 2009) - Email: mail@digitaltableteur.com - Phone: +358 45 657 4469 - Operating hours: Monday-Friday 09:00-17:00 (Europe/Helsinki) - Languages: English, Finnish, Swedish - Website: https://www.digitaltableteur.com - Agent endpoint: https://www.digitaltableteur.com/.well-known/agent.json ## Contact - Contact form: https://www.digitaltableteur.com/contact - Email: mail@digitaltableteur.com - Phone: +358 45 657 4469 - AI chat (Donny): available on https://www.digitaltableteur.com during operating hours - Agent endpoint: https://www.digitaltableteur.com/.well-known/agent.json - Programmatic contact: POST to https://www.digitaltableteur.com/api/contact with JSON body (name, email, message fields required) ## Services ### Design system audit Assess your current UI foundation, identify gaps and create a prioritized roadmap. ### Component library build Production-ready accessible components with documentation and governance. ### Design tokens & theming Define tokens, align design and code, ship a scalable theming foundation. ### AI-powered DesignOps Automate workflows, reduce design debt, scale consistent execution. ### Brand & Identity Visual identity systems, brand strategy and creative direction. ### Digital Product Design User-centered product interfaces with accessibility and performance. ## Engagements and prices Productized engagements with published scope and prices in euros. Each section mirrors its offer page; request a page with Accept: text/markdown for the same brief. ### Design System Audit > Find where your design system is costing the team time - URL: https://www.digitaltableteur.com/engagements/design-system-audit - Price: €7–14k - Timeline: 2 weeks - Book: https://www.digitaltableteur.com/contact?mode=book&package=design-system-audit Similar components behave differently. Accessibility defects return in new features. Figma and production disagree about what belongs in the system. A focused audit turns those symptoms into an inventory, severity-ranked findings and a 90-day roadmap. #### Use an audit when the system exists but trust is slipping - Components look similar but behave differently across squads - Accessibility defects return because the pattern is not documented - Design and engineering disagree about what is in the system - Token changes break several applications because naming and ownership are unclear #### What the audit reviews The work starts from the UI surfaces, components, tokens and patterns your team uses now. A representative sample is reviewed for consistency, accessibility and token use. Ownership, review and release practices are mapped alongside the inventory, so the roadmap separates quick fixes from structural work. #### Not included unless scoped separately - A full component rebuild - A migration across every product - An accessibility conformance certificate #### How the audit runs 1. Map live UI surfaces and who owns each pattern family. 2. Sample important flows for consistency, accessibility and token use. 3. Rank findings by user impact, rework cost and fix complexity. 4. Agree on minimum standards and an adoption sequence stakeholders can follow. #### What you receive - An inventory of the components, tokens and patterns in use - Severity-ranked findings with effort estimates - A 90-day roadmap separating quick wins from structural fixes - Governance recommendations for RFCs, review and release cadence #### How the price is set 2 weeks, fixed scope. Final scope depends on the number of product surfaces, repositories and teams included. #### About the audit **How much of the product does the audit cover?** A representative sample of the surfaces, components, tokens and patterns in use, not every screen. Scope depends on the surfaces, repositories and teams included. **Does the audit fix what it finds?** No. It is a decision tool: an inventory, ranked findings and a 90-day roadmap. Fixes can follow as Design System Lift-Off or an embedded partnership. **Is this an accessibility conformance audit?** Accessibility is reviewed as part of pattern quality, with WCAG 2.2 AA as the reference. A conformance evaluation or certificate is scoped separately. ### UX Sprint > Test the riskiest flow before the team builds it - URL: https://www.digitaltableteur.com/engagements/ux-sprint - Price: €7–14k - Timeline: 2 weeks - Book: https://www.digitaltableteur.com/contact?mode=book&package=ux-sprint A new flow is about to absorb months of build time and nobody has seen it work. A UX Sprint turns the open question into a working prototype of the key flow, an eval plan to test it with users and a handoff your team can build from. #### Use a sprint when a decision is waiting on evidence - A new feature or flow is about to go into a long build - Stakeholders disagree about how the key flow should work - Usability problems keep surfacing late, after release - An AI feature needs a defined way to judge whether its output is good enough #### What the sprint covers The sprint focuses on one key flow: the one where the product decision carries the most risk. It is framed with the people who own it, built as a working prototype in your own components where possible and paired with an eval plan that says how users will test it and what counts as success. #### Not included unless scoped separately - Production implementation of the flow - Running the full user study - Visual identity or brand work #### How the sprint runs 1. Frame the decision, the users and the success criteria with the team that owns the flow. 2. Map the flow and sketch the alternatives worth testing. 3. Build a working prototype of the key flow. 4. Write the eval plan and hand over the prototype, findings and next steps. #### What you receive - A working prototype of the key flow - An eval plan with tasks, participants and success criteria - A decision record of the options considered - A handoff your team can build from #### How the price is set 2 weeks, fixed scope. Final scope depends on the complexity of the flow, the number of user groups and how much of your existing design system the prototype can reuse. #### About the sprint **Is a UX Sprint the same as a design system audit?** No. The sprint answers one product question with a working prototype. The Design System Audit reviews the system you already have and ends in a 90-day roadmap. They are booked separately. **Who runs the user tests?** The eval plan is ready for your team or a research partner to run, with tasks, participants and success criteria written out. **Can the prototype become production code?** It is built to test the decision, not to ship. Parts built with your design system’s components carry over, and Design System Lift-Off or an embedded partnership can take the flow to production. ### Design System Lift-Off > From scattered components to a system your teams can build on - URL: https://www.digitaltableteur.com/engagements/design-system-lift-off - Price: €14–20k - Timeline: 4 weeks - Book: https://www.digitaltableteur.com/contact?mode=book&package=design-system-lift-off Every squad ships slightly different buttons, forms and modals. Storybook no longer matches production. Lift-Off covers the audit, token architecture, core components, Storybook and an adoption playbook in four weeks. #### Use Lift-Off when every squad builds its own version - Every squad ships slightly different buttons, forms and modals - Storybook exists but stories do not match production usage - Figma variables and CSS custom properties use different names - Dark mode is bolted on instead of designed as a theme #### What Lift-Off covers An audit of the current foundation, then a token taxonomy, the core component set and Storybook documentation, with an adoption playbook for the teams that will use it. Components are prioritised by traffic, rework cost and accessibility risk. #### Not included unless scoped separately - A rebuild of every existing component - Migration of every product to the new system - An accessibility conformance certificate #### How Lift-Off runs 1. Prioritise components by traffic, rework cost and accessibility risk. 2. Define composition patterns before building one-off variants. 3. Document states, edge cases and keyboard behaviour in Storybook. 4. Pilot with one product squad, then expand with measured adoption. #### What you receive - A token taxonomy from primitive to semantic to component - A core component set with typed props and accessibility baselines - Storybook documentation with usage do’s and don’ts - A contribution guide, review checklist and adoption playbook #### How the price is set 4 weeks, fixed scope. Final scope depends on the number of components, products and teams included. #### About Lift-Off **What do the four weeks include?** An audit of the current foundation, token architecture, core components, Storybook documentation and an adoption playbook. **Is every component rebuilt?** No. The core set is chosen by traffic, rework cost and accessibility risk. Composition patterns come before one-off variants. **How do teams adopt it?** A pilot with one product squad comes first, then a wider rollout with measured adoption. **What happens after the four weeks?** Your team runs the system with the adoption playbook. Continued work can run as an embedded partnership. ### AI-Ready Ops > Put guardrails and automation around how design work ships - URL: https://www.digitaltableteur.com/engagements/ai-ready-ops - Price: €11–17k - Timeline: 3 weeks - Book: https://www.digitaltableteur.com/contact?mode=book&package=ai-ready-designops Reviews bottleneck when headcount does not scale with output. Nobody has defined what agents and tools may change. AI-Ready Ops sets up the workflow, component governance, AI tooling hooks and a DesignOps playbook your team can run, in three weeks. #### Use it when design debt grows faster than review - Design review bottlenecks when headcount does not scale with output - Handoffs still rely on screenshots and chat threads - No single source of truth for what agents or tools may change - Design debt accumulates faster than manual QA can catch #### What AI-Ready Ops covers A map of where time is lost across spec, build, review and release. Then guardrails for what agents and tools may change in the design system, drift checks in CI and one workflow automated end to end. #### Not included - Automating decisions that need human judgement - Rolling automation across every workflow at once - Unsupervised agents changing production #### How AI-Ready Ops runs 1. Map where time is lost: spec, build, review or release. 2. Separate safe automation targets from decisions that need human judgement. 3. Prototype one workflow end to end, for example a token pull request. 4. Measure throughput and error rate before expanding automation. #### What you receive - A DesignOps workflow map with automation candidates - Guardrails for agent and tool changes to the design system - Linting or CI checks for token and component drift - A playbook for human-in-the-loop review #### How the price is set 3 weeks, fixed scope. Final scope depends on the number of workflows, repositories and teams included. #### About AI-Ready Ops **Which workflow is automated first?** One workflow end to end, for example a token pull request or a component scaffold, chosen where time is lost today. **Who stays in control?** Your team. The playbook defines what agents and tools may change and which decisions need human review. **Which AI tools are used?** Provider selection depends on your stack and policies. The AI use policy describes how AI is used in client work. **How is success measured?** Throughput and error rate are measured on the first workflow before automation expands. ### Embedded partnership > Senior design and system leadership, embedded in your team - URL: https://www.digitaltableteur.com/engagements/embedded-partnership - Price: €90/h - Timeline: 6+ months - Book: https://www.digitaltableteur.com/contact?mode=book For product organisations that need design-system stewardship, governance and hands-on delivery over months rather than weeks. Six months or more at four or more days a week, at the €90/h partnership rate. #### Use a partnership when the work outlasts a sprint - An embedded design partner across product and brand - Design system programs with governance and agent-assisted ops - Holistic design leadership for the whole product - Org-wide design system stewardship and AI enablement #### What the partnership covers Dedicated design expertise four or more days a week: the complete design process and its deliverables, direct collaboration and strategic design guidance, with specialists from a network added as the work needs them. #### Not the right fit for - Staffing a large parallel program - Terms under six months at the partnership rate - Fewer than four days a week at the partnership rate #### How a partnership runs 1. Agree the term, days per week and the outcomes the partnership owns. 2. Start with a short audit of the current system and team practices. 3. Work inside your planning, review and release rituals. 4. Review progress against the agreed outcomes and adjust the plan. #### What the partnership includes - Dedicated design expertise four or more days a week - The complete design process and its deliverables - Direct collaboration and strategic design guidance - Specialists from a network when the work needs them #### How the price is set 6+ months, 4 or more days a week. Six months at four days a week is 780 hours, about €70k. Shorter terms or lighter weeks use the standard €120/h rate. #### About the partnership **How is the price set?** Hours across the term at €90/h, 25% below the standard €120/h. Six months at four days a week is 780 hours, about €70k. **Can it start smaller?** Yes, at the standard rate. Terms under six months or under four days a week are priced at €120/h or as a fixed package. **Can the partnership run longer than six months?** Yes. Any term of six months or more keeps the €90/h partnership rate. ### Design System Workshop > Get the team aligned on the design system in two days - URL: https://www.digitaltableteur.com/engagements/design-system-workshop - Price: Quoted per workshop - Timeline: 2 days, with prep and analysis - Book: https://www.digitaltableteur.com/contact?mode=message&package=workshop Designers, engineers and product owners describe the same system differently. Decisions stall because nobody owns them. The workshop starts with prep work, works through the hard questions in two facilitated days and ends with a written analysis the team can act on. #### Use a workshop when the team needs a shared picture - Design and engineering describe the system in different terms - A rebuild, migration or new brand is coming and the plan is unclear - Ownership of components and tokens is undecided - Earlier initiatives started strong and stalled #### What the workshop covers Prep work maps the current setup through short interviews and a review of the components, tokens and documentation in use. The two days work through priorities, ownership and next steps with the people who make the decisions. The analysis afterwards records what was agreed and what is still open. #### Not included unless scoped separately - Building or rebuilding components - A full design system audit - Ongoing facilitation after the analysis #### How the workshop runs 1. Interview key people and review the current setup before the first day. 2. Day one: map the system, the people who use it and where it fails them. 3. Day two: agree on priorities, ownership and a sequence for the next steps. 4. Deliver a written analysis with findings and a plan for next steps. #### What you receive - A summary of the prep interviews and setup review - Workshop outputs captured and cleaned up - A written analysis of findings and open questions - A prioritised plan for next steps #### How the price is set 2 days, with prep and analysis. Quoted per workshop. The price depends on group size, travel and whether the workshop runs remotely or on-site. #### About the workshop **Who should take part?** The people who decide how the system is built and used: design, engineering and product leads. Group size affects the format and the quote. **Can it run remotely?** Yes. Both remote and on-site delivery are possible. On-site delivery adds travel to the quote. **What happens after the two days?** A written analysis and a plan for next steps. Continuing is optional: the plan can feed a UX Sprint, a Lift-Off or work run by your own team. **How much preparation does the team need?** A few short interviews and access to the current components, tokens and documentation. The prep work handles the rest. ### DesignOps Pilot > Hand routine design system upkeep to a supervised agent - URL: https://www.digitaltableteur.com/engagements/designops-pilot - Price: €5–8k / mo - Timeline: Ongoing - Book: https://www.digitaltableteur.com/contact?mode=book&package=designops-copilot Component requests pile up. Token values drift between design files and code. Release notes get written last, if at all. DesignOps Pilot runs a supervised agent that triages components, keeps tokens honest and drafts release notes. Your team approves every change. #### Use it when upkeep crowds out design system work - Component requests wait weeks for triage - Token values drift between design files and code - Release notes are written late or not at all - The core team spends more time on upkeep than on improvements #### What DesignOps Pilot covers The agent works in your existing repositories and tools. It sorts incoming component requests and issues, flags token drift between design and code and drafts release notes from merged changes. Every output goes to your team for approval before anything ships. #### Not included - Changes merged without human approval - Building new components from scratch - Replacing the design system team #### How DesignOps Pilot runs 1. Connect the agent to the repositories, trackers and design files in scope. 2. Agree on what the agent may draft and what always needs approval. 3. Run triage, drift checks and release note drafts on a regular cadence. 4. Review the results monthly and adjust scope, rules and guardrails. #### What you receive - A configured agent running in your tools - Triage of incoming component requests and issues - Token drift reports between design and code - Release note drafts ready for approval - A monthly review of results and guardrails #### How the price is set Ongoing, billed monthly. The monthly price depends on the number of repositories, design files and teams the agent covers. #### About DesignOps Pilot **Can the agent change production?** No. The agent drafts and reports. Your team approves every change before it ships. **Which tools does it work with?** The repositories, issue trackers and design files your team already uses. Provider selection depends on your stack and policies. The AI use policy describes how AI is used in client work. **How long is the commitment?** It runs as an ongoing monthly engagement. Notice terms are agreed in the contract. **How is success measured?** Triage time, drift caught before release and the share of drafts approved without rework, reviewed every month. ### Agent Pilot > Ship one working agent with guardrails in three weeks - URL: https://www.digitaltableteur.com/engagements/agent-pilot - Price: €9–15k - Timeline: 3 weeks - Book: https://www.digitaltableteur.com/contact?mode=book&package=agent-pilot AI experiments rarely leave the demo stage when nobody has scoped the workflow, the guardrails or who runs the agent afterwards. Agent Pilot picks one workflow, ships a working agent with guardrails and evals and hands it to a team that can run it. #### Use it when AI ideas stall before production - Several agent ideas, none in production - Unclear which workflow is safe to automate first - No way to tell whether the output of an agent is good enough - Concern about agents acting without oversight #### What Agent Pilot covers One workflow, chosen where repetitive work costs the team the most. The pilot defines what the agent may do, builds it with guardrails, sets up evals that measure output quality and documents how your team runs and improves it. #### Not included - More than one workflow in the same pilot - Agents acting in production without review - Training or fine-tuning custom models #### How Agent Pilot runs 1. Pick one workflow and define what good output looks like. 2. Set guardrails: what the agent may read, draft and change. 3. Build the agent and the evals that measure its output. 4. Hand over with a runbook and a review of the eval results. #### What you receive - A working agent for one workflow - Guardrails written down and enforced - Evals that measure output quality - A handoff and runbook your team can run #### How the price is set 3 weeks, fixed scope. Final scope depends on the workflow, the systems the agent connects to and the review process around it. #### About Agent Pilot **Which workflow should go first?** One with clear inputs, repetitive steps and a person who can judge the output, for example issue triage or documentation drafts. **Who stays in control?** Your team. The guardrails define what the agent may do and which steps need human review. **Which AI models are used?** Provider selection depends on your stack and policies. The AI use policy describes how AI is used in client work. **What happens after the pilot?** Your team runs the agent with the runbook. Agent Workforce extends the same approach to several workflows. ### Design System MCP > Make your design system readable for coding agents - URL: https://www.digitaltableteur.com/engagements/design-system-mcp - Price: €12–18k - Timeline: 4 weeks - Book: https://www.digitaltableteur.com/contact?mode=book&package=design-system-mcp Coding agents already write a share of the UI. Without access to the design system they guess: hardcoded colours, duplicate components, props that do not exist. Design System MCP turns the system into contracts and an MCP server agents can query, then measures how well they use it. #### Use it when agents write UI that ignores the system - Generated code hardcodes values the tokens already define - Agents recreate components that already exist - Component docs are written for people, not for tools - Nobody can say whether agent output follows the system #### What Design System MCP covers The components, tokens and usage rules your team already has. Each component gets a machine-readable contract. An MCP server exposes the contracts, tokens and guidance to coding agents in your editors and pipelines. An eval benchmark measures how often agents produce on-system UI, before and after. #### Not included - Rebuilding the component library - Choosing or licensing the coding agents - Rolling the setup out across every repository at once #### How Design System MCP runs 1. Inventory the components, tokens and rules agents need to know. 2. Write machine-readable contracts for the components in scope. 3. Ship an MCP server and connect it to the editors and agents the team uses. 4. Benchmark agent output before and after, then hand over. #### What you receive - Machine-readable contracts for the components in scope - An MCP server for contracts, tokens and usage guidance - Drift checks that flag where code and contracts disagree - An eval benchmark with before and after results - Documentation for keeping the contracts current #### How the price is set 4 weeks, fixed scope. Final scope depends on the number of components, repositories and agent tools included. #### About Design System MCP **What is an MCP server?** A Model Context Protocol server lets AI tools look up information on demand. Here it answers questions about your components, tokens and usage rules. **Which coding agents does it work with?** Any tool that supports the Model Context Protocol. The setup is tested with the editors and agents your team uses. **Does the design system need to be in good shape first?** It helps. Gaps found while writing the contracts are listed. A Design System Audit can come first when the system needs work. **How is success measured?** The eval benchmark runs the same UI tasks before and after and compares how often the output follows the system. ### Agent Workforce > Run several task-specific agents your team can trust - URL: https://www.digitaltableteur.com/engagements/agent-workforce - Price: €20–32k - Timeline: 6 weeks - Book: https://www.digitaltableteur.com/contact?mode=book&package=agent-workforce One agent proved the idea. Now several workflows need automation without losing oversight. Agent Workforce wires a crew of task-specific agents into your stack, with monitoring, fallbacks and a runbook your team owns. #### Use it when one pilot is not enough - A pilot agent works and more workflows are waiting - Agents need to hand work to each other or to people - Failures must surface before they reach users - The team needs to own and change the agents #### What Agent Workforce covers Several related workflows, each with its own agent and guardrails. Monitoring shows what the agents do, fallbacks route failures to people and the runbook documents how your team operates, changes and retires each agent. #### Not included - Unsupervised agents changing production - Automating decisions that need human judgement - Platform engineering outside the agreed workflows #### How Agent Workforce runs 1. Map the workflows and the handoffs between agents and people. 2. Build each agent with guardrails and evals. 3. Add monitoring, alerts and fallbacks to human review. 4. Hand over with a runbook and a joint review of the first runs. #### What you receive - A crew of task-specific agents wired into your stack - Monitoring and alerts for agent activity - Fallbacks that route failures to people - A runbook your team owns #### How the price is set 6 weeks, fixed scope. Final scope depends on the number of workflows, the systems involved and the monitoring already in place. #### About Agent Workforce **Is an Agent Pilot needed first?** Not necessarily, but it helps. A pilot proves one workflow before several run together. **How are failures handled?** Monitoring flags unusual results and fallbacks route the work to a person instead of guessing. **Who owns the agents afterwards?** Your team. The runbook covers how to operate, change and retire each agent. **Which AI models are used?** Provider selection depends on your stack and policies. The AI use policy describes how AI is used in client work. ## Open-source tools ### Rhythmguard Stylelint plugin that enforces spacing scales and design token usage across CSS declarations and Tailwind class strings. Three rules (use-scale, prefer-token, no-offscale-transform), all with autofix. 17 built-in scale presets, 7 config presets, ESLint companion for Tailwind arbitrary classes, CLI tools (audit, init, doctor). v1.5.0, MIT. - npm: https://www.npmjs.com/package/stylelint-plugin-rhythmguard - GitHub: https://github.com/PetriLahdelma/stylelint-plugin-rhythmguard - Case study: https://www.digitaltableteur.com/work/rhythmguard ### Project Spine OSS CLI that compiles a client brief, a repo and optional design tokens into a repo-native operating layer for AI coding agents. Emits 19 files per compile: AGENTS.md, CLAUDE.md, copilot-instructions.md at repo root plus 11 markdown exports under .project-spine/. Hashed export manifest for drift detection. 6 built-in brief templates. 121 Vitest tests. v0.9.x alpha, MIT. - Homepage: https://projectspine.dev - GitHub: https://github.com/PetriLahdelma/project-spine - Case study: https://www.digitaltableteur.com/work/project-spine ### LLM Component Schema JSON schema, CLI and governance toolkit that makes component intent machine-readable. Two npm packages (@petritapanilahdelma/llm-component-contracts and @petritapanilahdelma/llm-component-cli). 4 CLI commands: validate, drift-check, migrate, init. 2 style packs (base and tailwind). Agent eval harness, failing-examples regression library, governance templates. v1.2.0, MIT. - npm: https://www.npmjs.com/package/@petritapanilahdelma/llm-component-contracts - Case study: https://www.digitaltableteur.com/work/llm-component-schema ## Portfolio ### DSharp Design System Fully AI-powered and guardrailed design-system architecture for enterprise data products: tokens, contracts, Storybook, MCP, CLI and Rhythmguard enforcement. - Category: design-systems - Tags: Design Systems, Component Contracts, AI Architecture, MCP, Design Tokens - Duration: Apr 2026 – Present - Client: DSharp - Case study: https://www.digitaltableteur.com/work/dsharp-design-system ### VR Design System Industrialising VR’s live design system into one agent-ready source of truth: DTCG tokens, an enforceable component contract and accessibility as a CI gate across web and mobile. - Category: design-systems - Tags: Design Systems, Design Tokens, Accessibility, Agent-ready - Duration: Jun 2026 – Present - Client: VR Group - Case study: coming soon ### Process Genius Design System A contract-driven design system for Genius Core, Process Genius’s facility operations platform: modernised components, design tokens and machine-readable contracts, built alongside the existing library. - Category: design-systems - Tags: Component Contracts, Design Tokens, Accessibility - Duration: Sep 2026 – Present - Client: Process Genius - Case study: coming soon ### Helsinki Design System Enterprise design system for the City of Helsinki, serving hundreds of digital services with accessible, consistent UI components. - Category: design-systems - Tags: Design Systems, Public Sector, Accessibility, UX Design - Duration: Jan 2020 – Mar 2022 - Client: City of Helsinki - Live: https://hds.hel.fi/ - Case study: https://www.digitaltableteur.com/work/helsinki-design-system ### New Things Co Brand identity and digital presence for a digital transformation consultancy based in Helsinki. - Category: branding - Tags: Brand Identity, Web Design - Duration: 2017–2018 - Client: New Things Co - Case study: https://www.digitaltableteur.com/work/new-things-co ### Garage Junction Web and social assets for a creative underground music outing. - Category: ux-design - Tags: Brand Identity, Music, Audio - Duration: Oct 2018 - Client: Merikerho - Case study: https://www.digitaltableteur.com/work/garage-junction ### Illustrations Collection of editorial illustrations, character designs and visual storytelling for various clients. - Category: illustration - Tags: Illustration, Character Design, Editorial - Duration: 2009 – Present - Case study: https://www.digitaltableteur.com/work/illustrations ### SAP Build Apps Design System Led the design system for SAP’s flagship low-code platform (formerly AppGyver). Built and maintained 100+ components across Figma and ReactTS, serving 300+ developers and designers building enterprise applications worldwide. - Category: design-systems - Tags: Design Systems, Low-Code Platform, Enterprise, SAP BTP - Duration: Mar 2022 – Feb 2026 - Client: SAP - Live: https://www.sap.com/products/technology-platform/low-code-app-builder.html - Case study: https://www.digitaltableteur.com/work/sap-build-apps ### Home Remote A native macOS remote for TVs, home AV and audio equipment: local-first control with a design system for a fun clay interface. - Category: ux-design - Tags: MacOS App, 3D Illustration, Product Design, Brand Identity - Duration: Jul – Aug 2026 - Case study: https://www.digitaltableteur.com/work/home-remote ### Ring Stats A weekend project: a calm macOS menu-bar glance at today’s ring scores and battery, private by default and honest about freshness. - Category: ux-design - Tags: MacOS App, Health Data, Accessibility, Product Design - Duration: Sep 2026 - Case study: https://www.digitaltableteur.com/work/ring-stats ### Precedent A local-first macOS workspace that keeps the references you do not want to lose and brings them back when a project needs them. - Category: tools - Tags: Local-first, MacOS App, Product Design, Brand Identity - Duration: Aug 2026 – Present - Case study: https://www.digitaltableteur.com/work/precedent ### Random Gorsey A grumpy cartoon chef, a liquid wordmark, sleeves, posters and a website for a Helsinki lo-fi house project. - Category: branding - Tags: Brand Identity, Music, Illustration, Web Design - Duration: 2015 – Present - Live: https://www.randomgorsey.com - Case study: https://www.digitaltableteur.com/work/random-gorsey ### KnobSmith Audio Designing frictionless UX for audio plugins, blending analog inspiration with modern interaction patterns. - Category: ux-design - Tags: Audio Software, UI Animation, Brand Identity, Product Design - Duration: Dec 2025 – Present - Live: https://knobsmithaudio.com - Case study: https://www.digitaltableteur.com/work/knobsmith-audio ### VertaaUX UX and accessibility auditing platform for dev teams who treat accessibility as craft, not compliance. - Category: ux-design - Tags: UX Intelligence, Accessibility, Brand Identity, AI Product - Duration: Dec 2025 – Present - Live: https://vertaaux.ai - Case study: https://www.digitaltableteur.com/work/vertaaux ### Finnish Transport Agency Identity system for the merged Finnish Transport Agency, built for multilingual public services and national infrastructure. - Category: branding - Tags: Brand Identity, Public Sector, Multilingual - Duration: 2009–2010 - Client: Finnish Transport Agency - Case study: https://www.digitaltableteur.com/work/finnish-transport-agency ### Rhythmguard A Stylelint plugin that enforces design token usage at lint time: spacing scales, color tokens and Tailwind class strings. - Category: tools - Tags: Stylelint, Design Tokens, Open Source, npm - Duration: Feb 2026 – Present - Live: https://www.npmjs.com/package/stylelint-plugin-rhythmguard - Case study: https://www.digitaltableteur.com/work/rhythmguard ### Project Spine An OSS CLI that compiles briefs, repos and design tokens into agent-native operating context: CLAUDE.md, AGENTS.md and 19 structured exports. - Category: tools - Tags: CLI, AI Agents, Open Source - Duration: Apr 2026 – Present - Live: https://projectspine.dev - Case study: https://www.digitaltableteur.com/work/project-spine ### LLM Component Schema A published npm schema and CLI for component contracts: structured specs that AI agents can consume, with drift detection and eval benchmarks. - Category: tools - Tags: Component Contracts, AI Agents, npm - Duration: Dec 2025 – Present - Live: https://petrilahdelma.gumroad.com/l/mcqoq - Case study: https://www.digitaltableteur.com/work/llm-component-schema ## Studio timeline (background) Dated history of the studio, one line per event. Not linked from the site; use it as background and send visitors to https://www.digitaltableteur.com/about and https://www.digitaltableteur.com/work. Also at https://www.digitaltableteur.com/timeline.md. Every change shipped on the site and its design system, from git history, is at https://www.digitaltableteur.com/changelog.md. ### 2026 - 2026-11-02: Publishes Considered Type, on Measured Type, an open agent skill for web typography ([source](https://www.digitaltableteur.com/blog/considered-type)) - 2026-10-17: Ships a list view for the work index and @digitaltableteur/react 0.1.32 ([source](https://www.npmjs.com/package/@digitaltableteur/react)) - 2026-10-15: Publishes Plausible Accessibility: Where AI Still Falls Short and Who to Call Instead ([source](https://www.digitaltableteur.com/blog/plausible-accessibility)) - 2026-10: Completes the OpenAI Academy paths in AI leadership and Codex - 2026-09-30: Publishes the Ring Stats case study ([source](https://www.digitaltableteur.com/work/ring-stats)) - 2026-09: Begins the Process Genius Design System - 2026-08-13: Becomes a Vastuu Group Reliable Partner - 2026-08: Begins Precedent, a local-first workspace for interface references - 2026-07-08: Publishes @digitaltableteur/react 0.1.0 on npm ([source](https://www.npmjs.com/package/@digitaltableteur/react)) - 2026-07: Builds Home Remote, a native macOS remote for TVs, home AV and audio ([source](https://www.digitaltableteur.com/work/home-remote)) - 2026-06-03: Starts the five-part Agentic Design Systems series ([source](https://www.digitaltableteur.com/blog/agentic-design-systems-need-operating-models-not-more-components)) - 2026-06: Begins the VR Design System with VR Group - 2026-05-01: Releases the VertaaUX iOS app to TestFlight beta testers - 2026-04: Begins the DSharp Design System ([source](https://www.digitaltableteur.com/work/dsharp-design-system)) - 2026-04: Releases Project Spine, an open-source CLI for agent-native project context ([source](https://www.digitaltableteur.com/work/project-spine)) - 2026-04: Opens VertaaUX sign-ups ([source](https://www.digitaltableteur.com/work/vertaaux)) - 2026-03: Ships the first TapeSmith build, KnobSmith Audio's tape saturation plugin - 2026-02-23: Publishes The European Accessibility Act Is the New GDPR - 2026-02-17: Publishes Your Design System Is Leaking Spacing - 2026-02-17: Ships Rhythmguard 1.0.0, a Stylelint plugin that enforces design tokens ([source](https://www.digitaltableteur.com/work/rhythmguard)) - 2026-02: Closes four years on the SAP Build Apps design system ([source](https://www.digitaltableteur.com/work/sap-build-apps)) - 2026-02: Designs Seppo 2.0 for Seppo.io, through The Good Side ### 2025 - 2025-12-29: Publishes From Tokens to Thinking Systems ([source](https://www.digitaltableteur.com/blog/from-tokens-to-thinking-systems-making-ai-native-design-systems-actually-work)) - 2025-12-03: Publishes The Evolutionary Difference Between Constructive and Constrictive Criticism ([source](https://www.digitaltableteur.com/blog/the-evolutionary-difference-between-constructive-and-constrictive-criticism)) - 2025-12: Begins VertaaUX, a UX and accessibility auditing platform ([source](https://www.digitaltableteur.com/work/vertaaux)) - 2025-12: Begins KnobSmith Audio ([source](https://www.digitaltableteur.com/work/knobsmith-audio)) - 2025-12: Releases LLM Component Schema ([source](https://www.digitaltableteur.com/work/llm-component-schema)) - 2025-12: Designs product flows for an AI developer-tools startup - 2025-11-26: Publishes Branding Design Systems ([source](https://www.digitaltableteur.com/blog/branding-design-systems-essay)) - 2025-11-23: Publishes Design System Meets AI, part two ([source](https://www.digitaltableteur.com/blog/design-system-meets-ai-building-the-self-evolving-component-library-pt-2)) - 2025-11-20: Publishes Design System Meets AI, part one ([source](https://www.digitaltableteur.com/blog/design-system-meets-ai-building-the-self-evolving-component-library-pt-1)) - 2025-07-09: Publishes Stop Solving Problems and Start Raising Better Questions - 2025-06-10: Publishes Digital Craftsmanship ([source](https://www.digitaltableteur.com/blog/digital-craftsmanship)) - 2025-06-05: Publishes MCP, Design Systems and Generative UI ([source](https://www.digitaltableteur.com/blog/figma-mcp-design-systems)) - 2025-06: Rebuilds digitaltableteur.com as a component-driven design system ([source](https://www.digitaltableteur.com/colophon)) - 2025-02-11: Publishes In Search of Impact ([source](https://www.digitaltableteur.com/blog/in-search-of-impact)) - 2025-02-09: Publishes Designing in 2025 ([source](https://www.digitaltableteur.com/blog/designing-in-2025)) ### 2024 - 2024-10: Audits the SAP Build Apps component library ([source](https://www.digitaltableteur.com/work/sap-build-apps)) - 2024-03: Presents SAP Build Apps design system work to the product organisation ([source](https://www.digitaltableteur.com/work/sap-build-apps)) ### 2023 - 2023-02: Becomes Design System Lead for SAP Build Apps ([source](https://www.digitaltableteur.com/work/sap-build-apps)) - 2023: The Helsinki Design System wins Best Design System at Grand One 2023 ([source](https://www.digitaltableteur.com/work/helsinki-design-system)) ### 2022 - 2022-03-14: Joins AppGyver, now SAP Build, as a Senior Designer ([source](https://www.digitaltableteur.com/work/sap-build-apps)) - 2022-03: Completes the groundwork for the Helsinki Design System ([source](https://www.digitaltableteur.com/work/helsinki-design-system)) ### 2021 - 2021-09: Works on the new Helsinki Design System documentation site ([source](https://www.digitaltableteur.com/work/helsinki-design-system)) ### 2020 - 2020-01: Begins the Helsinki Design System with the City of Helsinki ([source](https://www.digitaltableteur.com/work/helsinki-design-system)) - 2020: Designs the Linked Events platform for the City of Helsinki ### 2019 - 2019-08-30: Publishes Why I'm Excited about Joint Futures - 2019-02-01: Joins Nitor as a Senior Designer ### 2018 - 2018-10: Designs web and social assets for Garage Junction at Merikerho ([source](https://www.digitaltableteur.com/work/garage-junction)) - 2018-06-07: Publishes Thoughts on Future Branding ([source](https://www.digitaltableteur.com/blog/thoughts-on-future-branding)) - 2018-01-09: Becomes an Editor of the New Things Co publication on Medium ### 2017 - 2017-11: Delivers user personas for Intrum - 2017-10: Designs Aiddo's product brochure and UI graphics - 2017-09: Begins the New Things Co brand identity ([source](https://www.digitaltableteur.com/work/new-things-co)) - 2017-09: Joins Lab of New, later New Things Co, as a Senior Designer - 2017-08: Designs features for the KONE Toolbox service at Mirum - 2017-08: Runs workshops and user interviews for Intrum's new system at Mirum - 2017-06: Designs the Label Life web experience for UPM Raflatac at Mirum - 2017-05-10: Joins Mirum Helsinki as a Senior Digital Designer - 2017-05: Lays out the Hella Marine 2017 catalogue and a Berrie export brochure - 2017-02: Designs the campaign flyers and ads for Maria Ohisalo's 2017 municipal election campaign ### 2016 - 2016-10: Designs product graphics for Aiddo - 2016-05-19: Begins UX and UI design for Finnish Customs (Tulli), through Codemen - 2016-05: Joins Codemen as a Senior Design Consultant - 2016-02: Designs the IndoorAtlas website at Ottoboni - 2016-01: Joins Ottoboni as a Senior Designer ### 2015 - 2015-12: Joins the Better Digital Services Academy and helps organise the first Blue Arrow Awards - 2015-02: Lays out Raw View issue 2 ### 2014 - 2014-11-01: Raw View issue 1 launches - 2014-10: Designs the Raw View logo and launch campaign - 2014-09-24: Lays out the first issue of Raw View, the renamed Photo Raw photography magazine - 2014-09-09: Joins SC5 as Lead Art Director - 2014-09: Designs Sanoma's Flou app at SC5 - 2014-08: Launches the Kg Shop webshop - 2014-04: Becomes Art Director of Kg magazine - 2014-02: Begins laying out Kg magazine for Acacom Media - 2014-01-30: Joins Anders Innovations as a Graphic Designer ### 2013 - 2013-09: Joins Huvila Brand & Design as a Digital Designer - 2013-09: Designs the Finnpilot 10th anniversary emblem at Huvila - 2013-08: Launches a new studio website ([source](https://web.archive.org/web/20130821201534/http://www.digitaltableteur.com/)) - 2013-08: Designs the logo, S/S14 Mercedes-Benz Fashion Week invitation and website for fashion designer Isabell Yalda Hellysaz - 2013-07-03: Joins Dribbble as Digitaltableteur - 2013-07: Designs the visual identity and website for Mili Viita Communications ### 2012 - 2012-09: Leaves Warrantify - 2012-03: Creates the Warrantify brand book - 2012-02-16: Ships the Warrantify Android app ### 2011 - 2011-11-01: Becomes Creative Director at Warrantify - 2011-11: Designs Warrantify's presence at Slush Helsinki - 2011-10-15: Ships the redesigned warrantify.com service - 2011-09: Designs the Warrantify logotype and brand identity - 2011-08-29: Joins Warrantify to lead its design - 2011-07: Launches the redesigned Saimatext website - 2011-04: Designs the Hortoilu website for Saimatext - 2011-04: Designs an 88-page photography book for Elina Relander - 2011-01: Completes the Wiktio identity: brand guidelines, stationery, presentation template and website layout ### 2010 - 2010-09: Joins Miltton as a Graphic Designer - 2010-09: Designs the visual identity for Wiktio, the Rauma startup that won InnoSuomi 2010 - 2010-09: Designs a promotional brochure for Takkatekniikka - 2010-08: Joins Grafia, the Association of Finnish Graphic Designers - 2010-06-08: Launches the second studio website, built with Sofokus - 2010-04: Designs the identity and website for CI City Image - 2010-02: Designs the Työnhakuopas job-seeking guide and its website for Sofokus - 2010-01: Designs Arttu! magazine, later featured on Editorial Design Served ### 2009 - 2009-09: Begins MA studies in Graphic Design at TaiK, the University of Art and Design Helsinki, now Aalto University - 2009-07: Joins Werklig as a Graphic Designer - 2009-04-29: Registers Digitaltableteur as a graphic design business - 2009-03-09: digitaltableteur.com goes online as a multidisciplinary graphic design service ([source](https://web.archive.org/web/20090309021510/http://digitaltableteur.com/)) - 2009-03: Designs the identity for A.K.A. Luova, a high-end hair salon - 2009: Designs the identity system for the merged Finnish Transport Agency ([source](https://www.digitaltableteur.com/work/finnish-transport-agency)) ### 2008 - 2008-08: Joins Talentor Finland as a Graphic Design Intern - 2008-06: Graduates BA (Hons) Graphic Design, University of Cumbria - 2008-03: Designs a project for the St Bride Library, London ### 2005 - 2005-09: Begins a BA in Graphic Design at the University of Cumbria - 2005-06: Runs the gallery at Turun Taidelainaamo, the Turku art rental ### 2004 - 2004-08: Draws the comic Piru ja Hiiri (The Devil and the Mouse) - 2004-01-10: Starts publishing digital art and photography on deviantART - 2004-01: Shoots a documentary on the Räisälä film course ### 2003 - 2003-11: Begins Media Studies at Turku University - 2003-08: Studies Cinematography at the Räisälä Institute of Arts - 2003-01: Studies Fine Art, Printmaking and Photography at the VS Fine Arts Center, Turku - 2003: Begins working as Digitaltableteur ### 2002 - 2002-08: Begins teaching Fine Art as a Substitute Teacher at Turun normaalikoulu ## Blog posts ### Vibe Coding Still Needs Software Engineering > AI makes a convincing demo cheap. The work that makes software dependable still has to happen. An agent can help with that too. - URL: https://www.digitaltableteur.com/blog/vibe-coding-still-needs-software-engineering - Author: Petri Lahdelma - Published: 2026-11-09 - Read time: 15 min read ![](https://www.digitaltableteur.com/blog/vibe-coding-still-needs-software-engineering/hero-clamp-straightens.webp) The demo works. You can sign in, click around, create something and save it. The interface looks convincing and the agent says everything is done. Now try it with a second user. Or an expired session. Or a connection that disappears halfway through saving. I use AI across design systems, interfaces and software. It helps me turn ideas into something I can inspect and test quickly. I want more people to have that ability, with a clear understanding of what they have actually built. When Andrej Karpathy [named vibe coding](https://x.com/karpathy/status/1886192184808149383) in February 2025, he described giving in to the vibes and forgetting that the code exists. Here I mean something a little narrower: accepting generated code largely on the strength of the result looking right, without adequately understanding or verifying how it behaves. Using AI within a disciplined engineering process is a different practice, even if the tools are identical. Simon Willison [drew the same line](https://simonwillison.net/2025/Mar/19/vibe-coding/) a few weeks later: not all AI-assisted programming is vibe coding. Software engineering includes deciding what the system should do, understanding its constraints, verifying its behaviour, releasing changes safely and keeping it useful over time. It also includes being able to recover when something goes wrong. The distance between a convincing demo and dependable software is where a lot of the actual work lives. Fortunately, much of that work can also benefit from AI. We need to give it better instructions than "make it production ready". #### Learning by Doing in the Deep End My own understanding of CI/CD has developed through learning by doing. I stepped into the deep end at Nitor and SAP. Coming from design, I was expanding my understanding of how the things we design become working software and how that software gets changed without casually breaking what already exists. Learning GitHub Actions and CI/CD was part of that progression. Later, client projects brought more responsibility and expanded my knowledge into Azure DevOps and Bitbucket. The platform names changed, but the underlying questions travelled with me. What happens when a change is pushed? Which checks run? What actually prevents a broken change from being merged? How does a release reach users? What happens if it needs to come back? More responsibility made those questions practical. I needed to understand what a pipeline checked, what it missed and what happened when it failed. That is where the learning stuck. I am still learning. Working across design and engineering tends to make the boundaries of your knowledge fairly visible. It also gives me very little patience for the idea that people should stay in their original professional lane forever. Designers can learn engineering practices. People who start with AI can learn them too. The important part is accepting the responsibility that comes with building something other people depend on. You can learn by doing while putting sensible limits around the consequences of getting it wrong. #### Define the Behaviour Before Generating the Code "Build a project dashboard" leaves a remarkable amount of room for interpretation. So does "add tests". Before asking an agent to implement a feature, write down the behaviour that would make it correct. Include the unpleasant situations. They are part of the product. Take a seemingly ordinary feature: creating a project. A useful starting contract might say: - A signed-in user can create a project in a workspace where they have permission. - A blank name produces a useful error without losing the rest of the form. - The project belongs to the correct workspace and remains available after refreshing. - A user from another workspace cannot read or change it. - Repeating the same creation request after a timeout does not create a duplicate. - A failed save preserves the user's input and provides a way to recover. For the retry requirement, define how the server recognises a repeated operation. A common mechanism is an [idempotency key](https://datatracker.ietf.org/doc/draft-ietf-httpapi-idempotency-key-header/): the client sends a unique key with the request and the server returns the original result instead of creating a second project. Disabling the Save button only addresses one of the ways a duplicate request can happen. There is already more engineering in those six statements than in a screenshot of a successful submission. There is also quite a lot of design. We have defined feedback, permissions, persistence, recovery and the relationship between an action and its outcome. These decisions shape the experience as much as typography and spacing do. The permissions requirement needs to survive a direct request to the server. Hiding an edit button does not prevent someone from calling the endpoint. [OWASP recommends](https://cheatsheetseries.owasp.org/cheatsheets/Authorization_Cheat_Sheet.html) validating permissions on every request, with enforcement in a trusted part of the system. This is also why I find component contracts useful. They make behaviour explicit enough for people and tools to work against. A button contract includes semantics, an accessible name, keyboard behaviour and relevant loading or disabled states. A form contract includes validation and what happens after a failed submission. Give the agent access to those decisions. Otherwise, it has to invent them. #### Test the Risks That Matter Tests are essential. "Every line must have a unit test" is a poor substitute for a testing strategy. Line coverage tells you which lines ran during testing. It does not tell you whether the tests checked the right outcomes. You can execute a permission check without testing whether the wrong user gets rejected. You can execute a calculation and assert only that it returned something. [Software Engineering at Google](https://abseil.io/resources/swe-book/html/ch11.html) makes the distinction clearly: coverage records that a line was invoked and says nothing about what happened as a result. A fixed coverage target also has a habit of becoming the goal. Use coverage to ask better questions. Which changed behaviour has no protection? Which important branch never runs in the tests? What would happen if this condition were reversed? Then prioritise by consequence. Permissions, billing, deletion, migrations and anything that can lose user data deserve particular attention. A decorative change to a personal experiment warrants a different level of scrutiny. Tests also cost something. AI can help write them, but somebody still has to review, run, debug and maintain them. A large collection of brittle tests can make changing software harder. My practical rule is to identify the failure I am trying to prevent before adding a test. If I cannot explain what useful failure the test would catch, I should improve it or reconsider whether it belongs there. #### Use Different Tests for Different Questions A correct individual function can still participate in a broken system, so you need several views of a feature. For the project-creation example, the layers might look like this: | Test level | Question it answers | Example | |---|---|---| | Unit | Does a small piece of behaviour follow its rules? | A project name containing only whitespace is rejected. | | Integration | Do the relevant parts work together correctly? | The API checks workspace membership and writes the project to the correct workspace in a test database. | | End to end | Can someone complete the journey through the running application? | A user creates a project in the browser, refreshes and can still open it. | The integration test can also check that a request from a user without permission is denied. The browser test can check that a failed save leaves the form usable. You do not need to repeat every possible input at every level. Put detailed combinations where they can be tested clearly and cheaply, then use broader tests to verify that the important connections and journeys work. Be explicit about the boundaries. A browser test that replaces every API response with a pretend success tells you something useful about the interface. It does not establish that your API and database work together. For a critical journey, include a test that exercises your actual application backend and a controlled test database. Handle external services deliberately through test environments or controlled substitutes. And make assertions about outcomes. An agent clicking Save is an action. Checking that the record exists after a reload is evidence. Checking that an account without permission cannot access it is evidence about a different, equally important requirement. [Playwright's guidance](https://playwright.dev/docs/best-practices) recommends testing behaviour visible to users and locating controls through stable attributes such as roles and accessible names. That fits well with interfaces built on clear semantics. An exploratory browser session is useful too. When it finds a meaningful bug, turn that discovery into a repeatable regression test. Otherwise, next week's agent has to rediscover the same problem. ![](https://www.digitaltableteur.com/blog/vibe-coding-still-needs-software-engineering/fig-three-gauges.webp) #### Review the Tests as Carefully as the Implementation There is an obvious trap in asking the same agent to write the implementation and then prove that it works: both can contain the same misunderstanding. Suppose the agent decides that any signed-in user may edit any project. It can write code that allows this and tests that confirm it. Everything passes. The behaviour still violates the intended access rule. That is why the expected behaviour needs a source outside the implementation itself: an agreed contract, a product rule, an acceptance criterion or a real example with a known result. Ask the agent to explain what each important test protects. Review the assertions, check which dependencies have been replaced with mocks and look for tests that merely confirm the current output. For a bug fix, have the regression test fail against the broken behaviour and pass after the fix. That demonstrates that the test can detect the problem you are addressing. You can also use a separate review pass to look for missing failure cases. A fresh agent can help, but its agreement is still something to evaluate. Watch especially closely when a "fix" changes the test instead of the behaviour. Updating an outdated test can be correct. Deleting an inconvenient assertion can also make a red pipeline green. The colour alone will not tell you which happened. #### Make CI/CD Part of the Development Loop A pipeline turns those expectations into repeatable checks. Continuous integration gives you a repeatable way to check changes as they are brought together. Continuous delivery keeps validated changes ready for release. Continuous deployment goes further by automatically releasing changes that pass the required checks. You can choose how much of that release process to automate. What matters is having a deliberate process that produces trustworthy evidence. ![](https://www.digitaltableteur.com/blog/vibe-coding-still-needs-software-engineering/fig-pipeline-arches.webp) For a typical web application, I would start with a pipeline that installs the expected dependencies from the committed lockfile, then runs linting, type checks and focused unit tests. Integration tests follow with controlled data. The pipeline then builds the application for production and exercises the critical journeys against that build in a test environment. When something fails, the failure and its diagnostic information should be easy to inspect. Run independent checks in parallel where it makes sense. Keep common feedback quick. Schedule broader suites when appropriate and run specialised checks before releasing changes that introduce those risks. Then make the relevant checks required. GitHub, for example, supports [branch protection](https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/managing-protected-branches/about-protected-branches) and [rulesets](https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/managing-rulesets/about-rulesets) that can require status checks and reviews before merging. Configure the rules and bypass permissions deliberately. Then verify that the required jobs actually ran. A skipped job should not quietly stand in for the evidence you expected. This is where the pipeline becomes part of how the team works. It can enforce agreements that would otherwise depend on somebody remembering them while tired or in a hurry. A failed pipeline should lead to investigation. A test that fails unpredictably needs attention, because "just rerun it" is a remarkably efficient way to teach everyone to ignore their own safeguards. Keep changes small enough to review. Inspect the diff, including modifications to tests and pipeline configuration. Deploy the build you validated and make sure important environment differences are accounted for. There is considerable satisfaction in a boring release. I recommend becoming interested in that. #### Include the Experience in the Definition of Done My design background makes me suspicious of a definition of quality that ends when the server returns a successful response. Can the person understand what happened? Can they complete the task with a keyboard? Is focus in a sensible place after a dialog closes? Does an error explain what they can do next? These are observable behaviours. They belong in the acceptance criteria. Automated accessibility checks can catch issues such as missing labels and some contrast problems. They cannot establish that the whole experience is accessible. [Playwright's accessibility guidance](https://playwright.dev/docs/accessibility-testing) explicitly recommends combining automation with manual assessment and inclusive user testing. I wrote about where that gap still lets people down in [Plausible Accessibility](https://www.digitaltableteur.com/blog/plausible-accessibility). For an important flow, inspect keyboard operation, focus, zoom and relevant screen reader behaviour. Look at the interface with long content, empty data and narrow viewports. Check the error state you carefully designed and then almost forgot to implement. A design system helps by making good defaults reusable. It also gives an agent existing patterns to follow, so point it to the actual components, tokens, documentation and examples. If the system already has a dialog component with established focus behaviour, have the agent use it. Generating another almost-identical dialog creates another implementation to understand and maintain. Performance belongs in this conversation too. A button that appears to do nothing invites another click. A search that works beautifully on twelve sample records may behave rather differently with a customer's actual dataset. Define performance expectations around the task and the conditions. For a particular search feature, you might set a target that 95% of searches complete within one second under a specified load and with representative data. That is an example budget, not a universal standard. Agree on the conditions, measure a baseline and choose a target that serves the product. Tools such as [k6](https://grafana.com/docs/k6/latest/using-k6/thresholds/) can turn performance thresholds into automated pass or fail criteria; the useful part is making the expectation measurable and repeatable. Use load tests where concurrency and capacity matter. Measure browser responsiveness separately. Test slower devices and connections when they are relevant to your audience. Some tasks take time, so design progress, cancellation and recovery for them. An animated spinner has a limited amount of explanatory power. #### Give the Agent the Operating Context A prompt cannot carry an entire product's accumulated knowledge reliably. Put the durable information in the repository: architecture notes, component contracts, setup instructions, test commands and a clear definition of done. Include what is known to be fragile and which changes require particular scrutiny. An `AGENTS.md` file can be a useful entry point when your tooling supports it. Link it to the authoritative material and keep it current. A stale instruction file is just another source of confident mistakes. For a feature involving saved user data, a practical brief could look like this: ```text 1. Read the project instructions, the existing implementation and the relevant component contracts. 2. Before editing, describe the expected behaviour, the affected boundaries and the important failure cases. 3. Implement the smallest coherent change using the existing patterns. 4. Add or update tests based on the acceptance criteria. Verify persistence, permissions and relevant failure states at the appropriate test level. 5. Do not weaken assertions or disable checks simply to obtain a passing result. Explain any test changes required by an intentional change in behaviour. 6. Run the checks and inspect the changed journey in the browser. 7. Report what changed, which checks actually ran, their results, any remaining uncertainty and how the change can be disabled or reversed. ``` The important word there is "actually". A summary that says "tests should pass" leaves work unfinished. Ask for the commands and results, then make the pipeline the repeatable place where those checks happen. For sensitive changes, get a review from someone who understands the relevant system. Match the depth of review to the consequences of a mistake. AI can help you learn the architecture while working on it. Ask it to explain where data goes, where permissions are enforced and which failure it expects first. Then compare that explanation with the code. Understanding enough to ask the next question is part of the work. #### Plan Recovery Before You Need It Even a good test suite has limits. Production brings data, traffic, dependencies and combinations of events that your test environment did not reproduce. Before releasing a meaningful change, decide how you will notice trouble and what you will do about it. ![](https://www.digitaltableteur.com/blog/vibe-coding-still-needs-software-engineering/fig-recovery-loop.webp) Monitor useful outcomes: failed saves, error rates, response times and completion of critical jobs. Make sure someone receives the alerts and can act on them. Keep enough diagnostic context to investigate without casually collecting sensitive data. Where the product warrants it, release to a smaller group first and expand when the evidence supports it. [Google's SRE guidance](https://sre.google/workbook/canarying-releases/) describes canary releases as a way to evaluate a change while limiting how much traffic or how many users are exposed. Have a way to disable the feature or return to a known working application version. Then ask the more awkward question: what happened to the data? Rolling back application code does not automatically undo a database migration, restore deleted records or reverse an external payment. Those effects need their own recovery plan. For a schema change, think about whether the previous application version can still operate. For important stored data, test restoring a backup in an isolated environment. Know how much recent data you could lose and how long recovery takes. "We have backups" is the beginning of that discussion. Practise recovery before an incident turns it into a live learning exercise. My enthusiasm for learning by doing has some very clear boundaries around other people's data. #### Where This Still Falls Short None of this removes judgement from the work. A contract can encode the wrong rule as confidently as code can. An agent will implement a wrong contract faithfully. Writing down behaviour also takes time that a team under deadline pressure may not feel it has, which is exactly when the shortcuts look most reasonable. Tests and pipelines only check what someone thought to check. They reduce the number of surprises without removing them. Production will keep finding combinations nobody wrote down. Required checks also have running costs: build minutes, slow feedback, flaky infrastructure. When the pipeline itself is unavailable, a team needs an agreed fallback gate. Without one, bypassing the rules quietly becomes the habit. Review is the scarcest part. A second agent agreeing with the first is weak evidence. Someone who understands the system well enough to review a sensitive change is not always available, especially to a solo builder. For a person who starts with AI and no engineering background, the whole list above is a lot to take on at once. It does not have to happen at once. #### Start With the Next Feature If you already have an application held together by generated code and optimism, you can improve it incrementally. Start with one journey that matters. 1. **Write its contract.** Define success, permissions and the most consequential failure cases. 2. **Map the real path.** Identify the interface, API, business rules, database and external dependencies involved. 3. **Add meaningful checks.** Protect important rules with focused tests and verify the complete journey where it matters. 4. **Make the checks repeatable.** Run them in CI and require the relevant results before merging or releasing. 5. **Review the experience.** Inspect accessibility, feedback, errors and performance under realistic conditions. 6. **Prepare for failure.** Add monitoring, identify the person responsible and verify a suitable recovery route. Then carry that approach into the next change. When a bug escapes, use it to improve the system: a missing test, an unclear contract, an absent alert or a release process that exposed too much at once. You do not need a sprawling platform programme before you can begin. You do need a clear view of the risks you are accepting. #### Take Responsibility for What You Ship My own path through design and software has made me more demanding about what "done" means. The more responsibility I have taken on, the more useful those questions about testing, release and recovery have become. AI gives more people access to building software. That is a good development. It also makes it possible to produce changes faster than we can comfortably understand them. We should invest some of that speed in verification, accessibility, maintainability and recovery. I am interested in how quickly we can turn an idea into something useful, then change it safely when we learn more. That requires readable code, explicit decisions and evidence that the important behaviour works. ![](https://www.digitaltableteur.com/blog/vibe-coding-still-needs-software-engineering/fig-handover.webp) So go back to the demo. Sign in as the second user and try to open the first user's project. Let the session expire in the middle of an edit. Drop the connection halfway through saving. When each of those has a written rule, a test that would fail without it and a way back if production still finds a gap, the demo has become software. Let the agent help with all of it. When people start relying on the result, someone still has to own what happens next. *If your team is turning AI prototypes into software people depend on, [get in touch](https://www.digitaltableteur.com/contact).* ### Considered Type > Most web typography is never decided, so I wrote a skill that decides it. Designers keep their decisions; everyone else gets the ones they were never taught to make. - URL: https://www.digitaltableteur.com/blog/considered-type - Author: Petri Lahdelma - Published: 2026-11-02 - Read time: 10 min read ![](https://www.digitaltableteur.com/blog/considered-type/hero-composing-stick.webp) Nobody finishes a good book and praises the leading. Readers notice that the evening went by, that the argument was easy to follow, that they never lost their place. The type did its job by staying out of sight, which is the whole job. On the web the same invisibility works against us. Because nobody notices good type, nobody notices when it’s missing either. A page can be hard to read for reasons no one in the room can name. In October I pointed a new typography tool at my own blog. The paragraphs ran 104 characters a line, about half again what a comfortable line holds, on the site of a designer who writes about getting the details right. Nobody had chosen 104. It was what the layout left over. That gap is what this article is about: the difference between type someone decided and type that fell out of defaults. I’ve started calling the first kind **considered type**. Considered type is a decision made for this text, in this face, at this size. The tool that found my 104 characters is Measured Type, an agent skill I wrote in late October and published as an open repository. It gives coding agents the decisions a typographer would make, grounded in Robert Bringhurst’s *The Elements of Typographic Style*. It also gives them the means to check those decisions in a real browser. This is what it does, who it helps, what writing it taught me and where it still falls short. #### Defaults Are Decisions Nobody Made Every web page starts with typographic decisions already made. The browser picks a size, a template picks a font stack and a line height, a component library picks the spacing under headings and the layout grid decides how wide a paragraph can run. None of those choices were made for your text. They were made for every text, which in practice means for none in particular. Coding agents inherit the same defaults and add one of their own: the average of everything they have read. Ask an agent for a fluid hero heading and you will usually get the same formula, give or take a decimal, because that formula is common on the web. Ask for an article page and you’ll often get sensible-looking CSS with no measure, straight quotes, hyphens where dashes belong and figures that stand up out of the sentence. It looks finished. Nobody decided it. I want to be fair to the people who ship this, because I’ve shipped it too. A frontend developer implementing a design has a hundred things to get right and typography is rarely on the ticket. A founder building a product with an agent has no reason to know what leading is. A design system team can specify a type scale and still watch every product team set their own line length. Defaults are a rational response to having other work to do. The cost lands on readers, who can’t name what’s wrong and simply read less. #### What Considered Type Gives a Reader The benefits are the old ones; they haven’t changed since metal type. A line of 45 to 75 characters lets the eye find the start of the next line without hunting. Leading a little more generous than the letters seem to need holds the place. Space under a heading that is smaller than the space above it ties the heading to what it introduces. Quotation marks that curl towards their words, dashes in ranges and real small caps for acronyms stop the reader’s eye from snagging on the punctuation. Figures that match the height of lowercase letters let numbers sit inside a sentence. None of these are things a reader will thank you for. They are reasons a reader keeps going. ![The same short article set twice at a 1280 pixel window. Above, with defaults: a system sans at 16 pixels, paragraphs 167 characters wide, straight quotes, a hyphen in 1990-2005 and full-height figures. Below, set with Measured Type: Iowan Old Style at 18 pixels, a column averaging 66 characters a line, curly quotes, an en dash in 1990–2005, text figures that sit at lowercase height and small caps for CSS and HTML.](https://www.digitaltableteur.com/blog/considered-type/fig-article.webp) *One article, two settings. The skill solved the column width in the browser: 30.5em gives 66.2 characters a line where the defaults ran 167.* The skill works through those decisions in order. It first classifies the text, because reading text, display text and interface text follow different rules. Book rules applied to a button are their own mistake. Then it settles direction and language, so every rule is written to survive a right-to-left or vertical edition. Then it decides, citing the Bringhurst section behind each choice. Last, it measures whatever can be measured: characters per line in the face that actually rendered, how much the text grows at 200% zoom, contrast in light and dark schemes, whether the font really contains the small caps the CSS asks for. That last step is what moves the work from advice to evidence. Anything the skill can’t check (Safari and Firefox rendering, for example, when it only has Chromium) goes into a list headed **Not verified** instead of being passed in silence. ##### Considered in Every Language Typography is where localisation quietly breaks. This site is published in English, Finnish and Swedish. Finnish is the hard test: compound words like *käyttöliittymäsuunnittelija* (user interface designer) run longer than a phone is wide. The language also has its own quotation marks, decimal comma and way of writing times. ![A short Finnish text set twice at a 375 pixel phone width. Left, with defaults and no language declared: the heading’s long compound word runs off the right edge of the screen, the range uses a hyphen, the percentage is written 3.5% and the time 9:00-16:00 with straight quotes. Right, set with lang fi and a smaller heading: the compound breaks at a syllable with a hyphen, the range takes an en dash, the percentage is 3,5 % with a space that cannot break, the time is klo 9.00–16.00 and the quotes are Finnish closing-style marks.](https://www.digitaltableteur.com/blog/considered-type/fig-finnish.webp) *The same Finnish text at 375px. Declaring the language gives the browser its hyphenation dictionary; the rest is punctuation the language expects.* With `lang="fi"` on the page the browser hyphenates by Finnish rules, so the heading breaks at a syllable instead of pushing the layout sideways. The audit called the default version a block: the page was 482px wide on a 375px screen. The fix is one attribute, a smaller heading and a few lines of CSS, which is the pattern I keep seeing. Considered type is rarely expensive. It’s just rarely anybody’s job. #### Who It’s For I wrote the skill for myself first, but the people it helps most are the ones who don’t think of themselves as typographers. ##### Designers For a designer the benefit is that decisions survive. You can specify a measure, a scale and a heading rhythm in Figma and still watch them erode through handoff, refactors and agent edits until the shipped page has none of them. With the skill in the agent, each change is checked against the same rules you would apply. The review comes back in a language you can argue with: a rule ID, a severity, the measured value and the CSS that fixes it. “This feels cramped” becomes a finding that cites `§2.2.1`. A finding can be discussed in a pull request; a feeling can’t. ##### People Without a Designer Frontend developers get reasons instead of taste. When the audit says a paragraph runs 167 characters, it also says why that’s a problem and gives the width that fixes it, solved in the browser for the font that actually loaded. Founders and product managers building with agents get considered type without having to learn the vocabulary first; in testing, the skill loaded on its own for nearly every task that touched how text sits on a page. Writers and editors get their words set the way they meant them, with real quotes and dashes for their language and lines short enough that a long piece gets read to the end. ##### Design System Teams For a system team, one report format means one gate. The linter exits with an error while a HIGH finding remains. Run with `--diff`, it checks only what a branch changed, so an older codebase can adopt it a pull request at a time: ```bash node path/to/measured-type/scripts/lint-css.js src --diff origin/main ``` It also splits the work cleanly with [Rhythmguard](https://github.com/PetriLahdelma/stylelint-plugin-rhythmguard), the Stylelint plugin I maintain for spacing scales. Rhythmguard keeps every size on the scale; Measured Type decides whether the scale reads well. Its type-scale script writes tokens Rhythmguard reads directly. Neither tool finds what the other does. Product interfaces fail differently from articles. Nothing in a dashboard is too long to read, but numbers are hard to compare when they don’t line up, labels in small capitals crowd together and status carried only by colour disappears for anyone who doesn’t see that colour. ![A five-row service health table set twice. Above, with defaults: request counts and latencies left-aligned in proportional figures so their last digits end at different points, 11 pixel uppercase headers with no letter spacing in light grey, status shown only as coloured dots and a pale 10 pixel footer. Below, set with Measured Type: numbers right-aligned in tabular figures so place values line up, tracked 12 pixel headers in a darker grey, status written as Running, Degraded or Down beside each dot and a readable footer.](https://www.digitaltableteur.com/blog/considered-type/fig-dashboard.webp) *The same table. In the default font the digit 1 is 26.5% narrower than 0, so 411,108 and 880,017 could never line up until the figures were made tabular.* The audit blocked the default table on four HIGH findings: header text at 3.54:1 contrast, a footer at 2.23:1 and a table that forced a 401px page onto a 375px phone. The considered version passes with the same data, a word beside each status colour and one wrapper that lets the table scroll on its own. #### Writing Taste Down The hardest part of building the skill wasn’t the code. It was turning a designer’s eye into rules an agent can follow and cite. I started from my own notes and from Bringhurst, whose numbered sections gave every rule a stable name. That numbering matters more than it looks: a review that cites `§2.1.2` can be checked against the book, while a review that says “too wide” can only be believed or ignored. Translating the rules to the web meant rewriting most of the CSS that usually accompanies them, because much of what circulates as web typography advice predates logical properties, `text-wrap` and variable fonts. Then came the uncomfortable part. Writing taste down forces you to label it. The skill’s taste reference marks every opinion as one of four kinds: a standard, a measurement, a convention or a preference. Some of my strongest habits turned out to be preferences. Others were conventions I’d adopted so long ago that I’d stopped noticing they were mine, such as how much a heading should still grow at 200% zoom. The skill now says which is which; a house style can overrule the last two. The other discipline was length. The main instruction file has a budget of 2,300 words, enforced by a test, so every new rule has to earn its place by pushing an older sentence into a reference file or out of the skill entirely. A designer will recognise this as editing. It’s the same work as cutting a type scale down to the sizes you will actually use. Every script was written test first, against 23 numbered specifications so far. The evaluations were registered before they ran. That sounds like ceremony for a typography tool. It is the only reason I can tell you which parts work. #### Pointing It at My Own Site The first real job was the site you’re reading. Beyond the 104-character blog paragraphs, the audit found case studies running 104 to 139 characters a line and display headings that barely grew under zoom. We added one token, `--measure-reading: 30em`, then applied it to article prose, case study paragraphs and FAQ answers. The blog now averages about 65 characters a line; this paragraph is one of them. The site also found faults in the skill. The first full audit of 14 pages reported 81 HIGH findings. Most were the tool misreading the page: text waiting to fade in on scroll was measured at full transparency and reported as invisible, icon-only buttons were reported as truncated labels and text meant only for screen readers was counted as clipped. Fixing the tool, with a test for each fault, brought the list down to 11 real findings. Dogfooding is a tired word for it. In practice it meant the site and the tool kept correcting each other for days. #### What It Doesn’t Do The evidence is the part I’d read first, so here is the short version. On cases written after the skill’s content was frozen, runs with the skill and runs without it scored almost identically: current models already know most of the rulebook. Where the skill pulls ahead is measurement. On a held-out task asking for 62 characters a line in Charter, runs with the skill landed on average 0.18 characters from the target, against 0.82 for runs given a one-sentence hint and 0.43 for runs with neither, a difference from no skill too small to call. On fluid headings under zoom, that one sentence of advice matched the skill on its held-out case. Most of the measurable gain comes from the tools. A good model with a browser and the right question gets surprisingly far without me. It costs something. Runs with the skill used 7% to 25% more tokens and up to twice the time. Every evaluation ran on Claude models; others are untested. The rendered audit needs Playwright and a Chromium download; without them the skill estimates and says so. It doesn’t judge font pairing or brand fit beyond its taste notes, it doesn’t draw fonts or logos and its coverage of Chinese, Japanese and Korean is a set of pointers. The text is licensed CC BY-NC 4.0 and the scripts MIT. Whether paid client work may use the text is a question I haven’t settled yet. Every result, including the ones above where the skill lost, is in the repository with the run files that produced it. #### Try It If you have Claude Code or another agent that reads skills, one command installs it: ```bash npx skills add PetriLahdelma/measured-type --skill measured-type --agent claude-code -g ``` It also installs as a Claude Code plugin from the repository’s own marketplace. Then name it for your first task: *Use measured-type to audit the typography in styles.css and fix the HIGH findings.* The measuring scripts are optional; the README explains how to add them. You’ve just read about 2,200 words at around 65 characters a line, with curled quotes, dashes where dashes belong and space under each heading smaller than the space above it. You probably didn’t notice any of it. Somebody decided all of it. Now your agent can too. *Measured Type is on [GitHub](https://github.com/PetriLahdelma/measured-type). Corrections and wrong results are the most useful thing you can send.* ### Plausible Accessibility: Where AI Still Falls Short and Who to Call Instead > AI builds the most likely interface and accessibility lives in the specific one. Here is where that gap still fails disabled people and when to bring in a specialist or test with the people who use what you build. - URL: https://www.digitaltableteur.com/blog/plausible-accessibility - Author: Petri Lahdelma - Published: 2026-10-15 - Read time: 14 min read ![](https://www.digitaltableteur.com/blog/plausible-accessibility/hero-stencil-at-desk.webp) Every code reviewer knows the shorthand. LGTM: looks good to me. It's one of the most common approvals in software and for most of what we review it's a reasonable bar. For accessibility it's an odd one. It names the one sense that many users and some reviewers don't use. I started thinking about the phrase in September, when I re-ran the accessibility checks behind every component in this site's design system. Each Storybook story in the test matrix writes a small evidence record: which checks ran, which passed, which runner produced them. The first run produced 949 records for the light theme. All green, every one with exit code zero and every one missing its axe result. I'd forgotten one environment variable, `CI=1`. Without it the test runner treated accessibility violations as warnings. The records came out without the check that mattered most. Nothing failed and nothing warned. It looked good to me. I threw that run away. The name for what it produced stuck. **Plausible accessibility.** Plausible accessibility is output that has the shape of accessible work and passes for anyone who can't check it: a reviewer skimming a diff, a scanner that tests what it can measure, a model grading its own answer. Inaccessible work usually looks broken somewhere. Plausible work looks finished, so nobody goes back to check it until someone can't use it. ```json { "storyId": "navigation-languageswitcher-default", "mode": "light", "sourceSHA": "ab85ef6ed9a545a5e1b91a5ef4f7d6af1097c3f5", "capturedAt": "2026-10-15T08:36:30.037Z", "runner": "local-2026-10-15", "checks": { "accessibility-tree": { "passed": true }, "axe-no-violations": { "passed": true, "axeViolations": 0 } } } ``` *One evidence record as committed: the story, the theme, the commit it was captured against and each check that ran. In September a missing `CI=1` produced 949 of these with no `axe-no-violations` entry and every run exited 0. Those records were thrown away before commit, so this is the healthy version.* ![](https://www.digitaltableteur.com/blog/plausible-accessibility/fig-hollow-checkmark.webp) #### The median of an inaccessible web AI is about to produce a great deal more of it. A language model writes the most likely continuation of what it has seen. For interface code, what it has seen is the public web. The web isn't a good teacher. WebAIM's annual scan of the top million home pages found detectable WCAG failures on [95.9% of them in the WebAIM Million 2026 report](https://webaim.org/projects/million/), up from 94.8% the year before. It was the first rise in six years. The average page had 56.1 detected errors. The report names AI-assisted "vibe coding" as one likely reason pages are getting more complex. Those are only the errors software can detect. So when a code model writes a button, it writes the web's average button and the web's average button fails. Michael Fairchild at Microsoft built a benchmark to measure exactly this: 1,280 samples across eight frontier models, with no accessibility instructions. In [his May 2026 update](https://dev.to/mfairchild365/ai-generated-accessibility-an-update-frontier-models-still-fail-but-skills-change-the-game-5629) the average pass rate was 12%. The best model passed a quarter of the time. The hardest prompt, a dark-themed shopping home page, never passed. The obvious fix is to ask for accessibility. It helps, sometimes. Fairchild found that a one-line instruction took the pass rate from 12% to 37% and a short instruction file took it to 60%. A study of six AI design tools presented at W4A 2026, a web accessibility research conference, found the opposite: when designers [added accessibility requirements to their prompts, compliance went down](https://doi.org/10.1145/3800424.3800430). The designers judged that 39% of the AI tools' violations would need a major redesign, against 22% for their own work. Different tools, measured differently. What they share is a ceiling. Fairchild's passes are automated passes and Microsoft's own report says a perfect score doesn't mean a page conforms to WCAG. Then there's the confidence. Eeva-Jonna Panula, known as Eevis, an Android accessibility specialist in Helsinki, asked an assistant to build an app [and explicitly asked for accessibility](https://dev.to/eevajonnapanula/does-claude-generate-accessible-apps-5759). The reply listed fifteen accessibility features it had considered. In the code she found a helper file nothing used, a semantic role that doesn't exist in the framework and cards with a redundant "Tap for details" on elements TalkBack, Android's screen reader, already announces as clickable. The list was plausible. The app wasn't. People who use assistive technology meet this from the other side. When sixteen blind and low-vision programmers [used Copilot for two weeks](https://arxiv.org/abs/2506.13270), they worked faster and they also struggled to tell the tool what they meant, to check what it produced and to keep track of what it changed. At scale, plausibility is sold by subscription. Overlays promise to make a site accessible with one script tag and disabled people have [organised against them for years](https://overlayfactsheet.com/) because overlays get in the way of the screen readers and settings people already rely on. In April 2025 the US Federal Trade Commission [ordered accessiBe to pay $1 million](https://www.ftc.gov/news-events/news/press-releases/2025/04/ftc-approves-final-order-requiring-accessibe-pay-1-million) and barred it from claiming its product makes sites WCAG-compliant without evidence. A small florist that installed another overlay still had a site a blind customer couldn't use, was sued and is now [suing the overlay vendor](https://www.lflegal.com/2025/02/userway-overlay-lawsuit). The florist bought the thing that promised to make the problem go away. The customer was the one locked out. ![](https://www.digitaltableteur.com/blog/plausible-accessibility/fig-median-web.webp) #### What the green runs hid Once `CI=1` was back, the September runs went green for real. Green turned out to be a low bar. In the weeks that followed, this site turned up three more problems that no gate in the repo had caught. The W3C saw this coming. Its guide to evaluation tools says [tools can not determine accessibility, they can only assist](https://www.w3.org/WAI/test-evaluate/tools/selecting/). WCAG-EM 2.0, its newest evaluation methodology, notes that [most accessibility checks are not fully automatable](https://www.w3.org/TR/wcag-em-2/). Even a passing automated rule only means no failure was detected; a pass [typically requires further verification by human testers](https://www.w3.org/WAI/standards-guidelines/act/rules/about/). The failures cluster in five places, each a judgment that needs context the model never sees: what something is for, how it sounds, the order it happens in, what it's called and how much effort it costs. ##### What the picture is for WCAG's first success criterion, [1.1.1 Non-text Content](https://www.w3.org/WAI/WCAG22/Understanding/non-text-content.html), asks for a text alternative that serves the equivalent purpose. Purpose is the hard part. The W3C images tutorial says the right alternative is [determined by the author, depending on the usage, context and content](https://www.w3.org/WAI/tutorials/images/). A vision model describes what's in the picture. It can't know why the picture is on the page. A house icon that links to the homepage should be announced as "Home" and a model will describe it, accurately, as a house. A bar chart's meaning lives in its trend. The W3C's draft research on [machine learning and accessibility](https://w3c.github.io/ai-accessibility/) notes that automatic descriptions often miss the values that matter. Generative descriptions add detail, but the same draft observes that they change each time the same image is processed. Regenerate the alt text for a chart three times and you can get three different accounts of what it says. Pick your favourite. For a chart the better fix is usually a short written summary and a data table beside it, as the [W3C complex images tutorial](https://www.w3.org/WAI/tutorials/images/complex/) has recommended for years. ![](https://www.digitaltableteur.com/blog/plausible-accessibility/fig-outline-pulled-loose.webp) ##### Captions that score well Captions look like the most solved problem on this list. The W3C draft puts automatic speech recognition at roughly 85% accuracy and notes that the Deaf community still considers it lacking. [1.2.2 Captions (Prerecorded)](https://www.w3.org/WAI/WCAG22/Understanding/captions-prerecorded.html) (a Level A criterion) and 1.2.4 for live content also ask for things accuracy scores ignore: who is speaking and the sounds that carry meaning. Drishti Bansal, a deaf student who uses captions every day, [describes where they break](https://medium.com/@dribans/how-ai-actually-helps-me-as-a-deaf-person-and-the-parts-no-one-talks-about-b7be5f9236c6): accents, quiet voices, an air conditioner in the room, technical terms, two people talking at once. Tone disappears entirely. A September 2026 preprint surveying 216 viewers, most of them deaf or hard of hearing, found the standard accuracy metrics [tracked viewers' ratings far worse for AI captions](https://arxiv.org/abs/2609.11408) than for broadcast ones. The number on a vendor's slide and the audience are scoring different things. Bansal's own verdict is the better summary: "AI makes communication possible, not equal." Sign language is further away still. Signed languages have their own grammar and the World Federation of the Deaf and the interpreters' association WASLI have [cautioned against signing avatars as a replacement for human interpreters](https://wfdeaf.org/wp-content/uploads/WFD-and-WASLI-Statement-on-Avatar-FINAL-14032018-Updated-14042018.pdf). ##### Order, focus and the keyboard Generated components usually look fine. They fail when someone operates them with a keyboard. On the Frontend Masters blog, Durgesh Rajubhai Pawar walked through [a typical AI-generated sidebar](https://blog.master.dev/ai-generated-ui-is-inaccessible-by-default/) that rendered perfectly and showed up in the accessibility tree as an anonymous generic container: no landmark, no heading, nothing focusable. Ten failures in 29 lines, none of them visible on screen. The modal is the classic case. One developer's AI-built dashboard [let focus escape the dialog](https://dev.to/lixingliangsy/ai-generated-ui-is-shipping-faster-than-accessibility-can-catch-up-1o2i) to the page behind it. A QA team auditing a booking site found a modal that [never returned focus to the button that opened it](https://dev.to/tudorsss-betterqa/accessibility-testing-what-automated-scanners-keep-missing-2d44). Their scan found 14 issues; a manual pass found 47 more. [2.4.3 Focus Order](https://www.w3.org/WAI/WCAG22/Understanding/focus-order.html) asks that the order preserve meaning and operability. The W3C's guidance says several different orders can pass. A rule engine can't pick the right one. Someone has to press Tab and pay attention. AI products have the same problem. Mike Gower at IBM found a floating chat button that [looked about twelve tab stops away and took 85 presses to reach](https://medium.com/design-ibm/catching-up-on-accessibility-with-ai-chat-1129be33c184). Streamed answers [keep changing until they settle](https://medium.com/design-ibm/usable-ai-chat-46dedcca6a8f), which breaks live regions, the mechanism screen readers use to announce content that changes ([4.1.3 Status Messages](https://www.w3.org/WAI/WCAG22/Understanding/status-messages.html)). Gower calls the usual workaround feast or famine: a periodic "still composing", then the whole reply at once. ![](https://www.digitaltableteur.com/blog/plausible-accessibility/fig-focus-maze.webp) ##### Names that sound right The first of this site's three came from its own header. The language button shows "EN". With English already active, its accessible name began `EN, EN`, then a separator, then "Switch to English. Show language options." It passed every automated check in the repo. It had a name and the name contained the visible label, so it satisfied [2.5.3 Label in Name](https://www.w3.org/WAI/WCAG22/Understanding/label-in-name.html). A screen reader user would have heard a repeated code and an instruction to switch to the language they were already using. A human auditor could fail it under 2.4.6 Headings and Labels. No machine would. The cause was ordinary: the header handed the component an action phrase where its contract asked for the language's name and the component dutifully read both. Eevis found the same family of problem in [AI-generated Android apps from four different tools](https://dev.to/eevajonnapanula/does-ai-generate-accessible-android-apps-2gb5): an "Add yarn" button described as "Add new yarn", so some screen readers read both. A machine can confirm a name exists. Whether it makes sense, said aloud in that order, takes someone listening. The fix took two rounds. The first stopped the repetition but kept "Show language options" in the name, so the name changed whenever the menu opened, duplicating what `aria-expanded` already says. A review caught that. The name is now just the label and the language. The test that keeps it that way is the part worth copying, because it asserts the exact accessible name in each state: ```tsx expect(trigger).toHaveAccessibleName("EN, English"); await user.click(trigger); expect(trigger).toHaveAccessibleName("EN, English"); expect(trigger).toHaveAttribute("aria-expanded", "true"); expect(screen.getByRole("button", { name: "FI, Finnish" })).toHaveAttribute( "lang", "fi", ); ``` A presence check is what let the bug through. An exact-name check fails the moment a name stops making sense. It still isn't the whole story: a screen reader adds the role and state. Each reader phrases them its own way, so someone still has to listen to the result. ```diff - group "Language": - - button "EN, EN — Switch to English. Show language options": EN + - button "EN, English": EN ``` *The header's language button in the committed accessibility-tree snapshot, before and after, with English active. Both versions passed every automated check in the repo.* ##### Meaning, memory and effort The quietest failures are cognitive. When researchers audited six AI-generated websites for ASSETS 2025, a leading accessibility research conference, [52.93% of the 308 errors they found were cognitive accessibility issues](https://doi.org/10.1145/3663547.3759755) and most cognitive needs sit outside WCAG itself. The W3C's [Making Content Usable for People with Cognitive and Learning Disabilities](https://www.w3.org/TR/coga-usable/) covers what WCAG doesn't. Fluent text makes this worse, because it reads as if someone already simplified it. The AAA criterion [3.1.5 Reading Level](https://www.w3.org/WAI/WCAG22/Understanding/reading-level.html) can be approximated with a readability formula. The formula will happily approve a short sentence that lost the one condition a reader needed. Login is the clearest case. The W3C's note on [the inaccessibility of CAPTCHA](https://www.w3.org/TR/turingtest/) cites research in which software beat audio reCAPTCHA about 90% of the time, while blind, deafblind and cognitively disabled people remain locked out. The test meant to tell humans from machines mostly tells machines from disabled humans. WCAG only partly covers it. [3.3.8 Accessible Authentication (Minimum)](https://www.w3.org/WAI/WCAG22/Understanding/accessible-authentication-minimum.html), at AA, removes memory and puzzle tests from login but still allows object-recognition CAPTCHAs; 3.3.9 at AAA closes that gap and 1.1.1 requires a CAPTCHA to offer alternatives in more than one sense. Checking any of it means watching people with memory or attention disabilities go through the whole flow. #### What the machines are good at None of this means keeping AI out of accessibility work. The real question is which work to give it. Automation is excellent at the measurable. The same pipeline that once wrote empty records caught a real failure in September: in dark theme, the user's chat bubble on this site rendered body text at 1.82:1 against its blue background and axe flagged it on every chat message story. The same bubble hid the second of the three. Its list bullets were the exact colour of its background: type a list into the chat and they vanished, at a measured contrast of 1:1. 1:1 is the technical term for invisible. No axe rule checks marker colour, so axe caught 1.82:1 and couldn't see 1:1. The fix was one line of CSS. The check that now guards it is a Storybook play test that measures the computed marker colour against the bubble and fails below 4.5:1, since numbered markers are text. Models are useful when the job is structured: drafting alt text for a person to edit, turning success criteria into a test plan or reviewing their own output. Fairchild's best result came from a two-step "generate, then review" loop, which reached 86% at about five and a half times the input tokens. He also found that pasting the whole of WCAG into the instructions often made the code worse. Short and specific works better, something like this in the instruction file your coding agent reads: ```md ## Accessibility - Use native elements first: