Shift-Left Quality
Quality is part of done, not part of QA.
Quality is part of done, not part of QA. Accessibility, security, performance, observability: all in the gate, all run while the change is fresh, none deferred to a later sprint or a later team.
Opinion
The team that defers accessibility to a separate sprint is the team that releases an inaccessible product. Same shape with security: defer to a pen-test next quarter and the vulnerability releases. Same shape with performance: defer to a perf review and the regression goes out. The shift-left tradition has forty-five years of data behind it.2 The operational pattern in this repo is the same shape: a11y violations as build-failing in CI, security checks via Dependabot and CodeQL, perf budgets as Lighthouse thresholds.
I want to plant a flag on this: shift-left is the strategy and P4 Continuous Quality Feedback is the tactic. P5 says move the check earlier; P4 says give the engineer the loop to run the check at the keystroke. Neither row works alone: shift-left without the editor loop is a CI complaint waiting to happen. The editor loop without shift-left is a fast loop on the wrong thing.
For the agent, shift-left is what stops the model from generating accessible-looking but inaccessible markup, secure-looking but insecure code, performant-looking but slow code. The a11y MCP, the security MCP, the perf-budget script: the agent runs them as it writes, not after. CRITIC and the evaluator-optimizer pattern again: the model corrects against the tool signal, not against introspection.3 Shift-left is the principle that decides which signals belong in the loop.
Copy a note and link
Grab this short comment and drop it into a PR comment or an LLM chat to prompt the right change.
Quality is part of done, not part of QA. Move every check earlier: accessibility, security, performance, observability. From QA into PR, from PR into CI, from CI into the editor. The earlier a defect is found, the cheaper it is to fix; Boehm's cost-of-defect curve is the load-bearing source. /tenet/shift-left-quality/P5
AI eyes only
Rule: quality is part of done, not part of QA. Run quality checks at edit time.
Reject: deferring accessibility, security, performance checks to a later stage. Reject: opening a PR that fails an a11y, security, or perf-budget check. Reject: relying on QA to catch what tooling can.
Generate: invoke the a11y MCP, security scanner, and perf-budget script at edit time, not pre-merge. Treat each as a build gate rather than a PR comment. Fix on first signal.
Diagnostic: at every edit boundary, run the closest available quality check. If a check can run in seconds and is not in the loop, the loop is wrong.
Why?
- Boehm's curve drives the case: every shift-left check is one stage earlier, one order of magnitude cheaper. The curve has not aged. The principle holds across accessibility, security, performance, and observability.
- Quality comes by default, not by retrofit. The team that runs the a11y check at PR time releases accessible products. The team that defers releases an inaccessible one until the next remediation sprint.
- Pair with P4 Continuous Quality Feedback: P5 is the strategy (move every check earlier), P4 is the tactic (run every check at the keystroke). Neither row works alone.
- The agent grounds itself in tool signals, not introspection. Shift-left is the principle that decides which signals belong in the agent's loop: the a11y MCP, the security MCP, the perf-budget script.
- QA becomes a coach instead of a gate. The Crispin / Gregory reading keeps the QA discipline intact while moving the per-change check into the developer's loop.
- No remediation sprints. The accessibility / security / performance backlog never grows because the regressions never landed. The cost of the principle is paid in continuous small effort, not in occasional large remediation.
- Compliance is a by-product. WCAG, SOC 2, performance budgets: the audit at the end finds nothing to fix because the gate at the front caught it.
Origins
The term comes from Larry Smith. “Shift-Left Testing” ( Dr. Dobb's Journal, September 2001) named the practice of moving testing left in the SDLC.1 The intellectual root is Barry Boehm's 1981 cost-of-defect curve, which Smith cites and which every modern shift-left argument descends from.2 The principle is the same in both: every minute earlier you find a defect is a multiplier on the cost.
The DevSecOps tradition is the security branch of the same idea. Gartner's 2017 “DevSecOps Should Be the Default for All Application Development” made the case that security checks belong in the developer loop; the term itself is Neil MacDonald's, coined at Gartner as DevOpsSec in 2012. and made the case that security checks belong in the developer loop.6 Snyk, Dependabot, and CodeQL are the operational instances. The principle is the same Smith named in 2001 with security as the headline example.
The accessibility branch belongs to the W3C and Deque. The W3C's WCAG (1999: present) is the standard;7 Deque's axe-core (2015: ) is the dominant developer-loop tool that brings WCAG checks into the editor and the test suite.8 Bruce Lawson and Remy Sharp's Introducing HTML5 (New Riders, 2011) is the early bridge book between web development and a11y discipline.9
The performance branch belongs to Lara Callender Hogan's Designing for Performance (O'Reilly, 2014).10 Performance budgets (an explicit upper bound on page weight, render time, or interactive time) are the shift-left analogue for performance. Lighthouse (Google, 2016 onwards) and Web Vitals (Google, 2020 onwards) are the operational instances. The principle is again the one Smith named.
DORA / Forsgren is the empirical backstop across all four branches. Accelerate (2018) names shift-left security as one of the practices that distinguishes high-performing teams.11 The 2024 DORA report continues to list these as drivers. The data has not moved against the principle.
Quotes
It is well known that the earlier a bug is detected, the easier and cheaper it is to fix.
Finding and fixing a software problem after delivery is often 100 times more expensive than finding and fixing it during the requirements and design phase.
By creating a performance budget early on, you can make performance sacrifices in one area of a page and make up for them in another. … Your outlined performance goals should always be measureable.
Use testing and tracking tools to catch issues early and reduce costs.
Evidence
20 external sources, ranked by author authority. The first five are the canon; expand to see the rest, including the qualifiers and the named opposers. Each links out to its primary source.
- 01“Shift-Left Testing”SupportsDr. Dobb’s Journal, September 2001. The article that named the practice. Cites Boehm’s cost-of-defect curve as the load-bearing source.
- 02Software Engineering EconomicsSupportsThe cost-of-defect curve. Forty years on the data has not aged. Every shift-left argument descends from this source.
- 03Coined the DevSecOps term as the security branch of shift-left. Industry-influential. Backs the case at the executive scale.
- 04The accessibility standard. The shift-left a11y branch aims at WCAG. Axe-core, Pa11y, and Lighthouse are the developer-loop tools that enforce it.
- 05axe-coreSupportsThe dominant developer-loop tool that brings WCAG checks into the editor, the test suite and the agent loop.
- 06Introducing HTML5SupportsThe early bridge book between web development and a11y discipline. Connects the WCAG standard to working developer practice.
- 07Designing for PerformanceSupportsThe performance-budget idea: explicit upper bounds on page weight, render time, or interactive time as the shift-left analogue for performance.
- 08Names shift-left security as one of the practices that distinguishes high-performing teams. Empirical backstop across all four branches.
- 09Accessibility for EveryoneSupportsThe accessible-by-default idea for design and development. Backs the case that a11y belongs in the team’s workflow, not in a remediation sprint.
- 10Web Performance in ActionSupportsOperational treatment of the performance-budget idea. Useful as the implementation companion to Hogan.
- 11The qualifier: shift-left without team capability is blame transfer. The fix is QA-as-coach, not QA elimination.
- 12Testing and Checking RefinedOpposesThe testing-as-craft steelman. A check can be completely automated; testing is “intrinsically a human activity”. Shift-left that moves only the checks leaves the testing behind.
- 13More Agile TestingQualifiesUpdates the 2009 idea for continuous-delivery teams. Codifies the shift-left + QA-as-coach pattern.
- 14LighthouseSupportsPerformance, accessibility, SEO, and best-practice audits in one tool. The dominant developer-loop instance of shift-left across the accessibility and performance branches.
- 15Web VitalsSupportsCore Web Vitals as the agreed measurement set for performance budgets. The metrics shift-left aims at when the principle is operationalised for the web.
- 16Snyk Open SourceSupportsDependency vulnerability scanning at PR time. The dominant DevSecOps tool that enforces the security branch of shift-left in the developer loop.
- 17DependabotSupportsAutomated dependency-update PRs. Shift-left applied to dependency hygiene. Closes the patch loop without remediation sprints.
- 18CodeQLSupportsCode-security scanning at PR time. Catches the SQLi / XSS / RCE class of failure before it goes out. The canonical PR-level instance of DevSecOps.
- 19Pairs shift-left with shift-right (testing in production). Useful as the qualifier: not all signals reduce to pre-deploy checks. Observability is the missing half.
- 20Empirical case for grounding the agent in machine-checkable feedback. The shift-left signals (a11y, security, perf) are exactly the loops the agent must run.
Twenty sources, three stances. The supporters are Smith, Boehm, Gartner, W3C, and Deque: the shift-left / DevSecOps / a11y canon. The qualifiers further down push the line that shift-left without team capability is just blame transfer. The opposers argue that shift-left collapses the QA function into development. The steelman the case has to address.
Enforcement
Apply these rules in eslint.config.mjs. The full enforcement across every tenet lives on the implementation page.
| Rule | Tool | Catches |
|---|---|---|
| eslint-plugin-jsx-a11y | eslint-plugin-jsx-a11y | static a11y violations in JSX: missing alt text, invalid ARIA attributes, role mismatches. |
| axe-core (vitest integration) | axe-core | runtime a11y violations against rendered components. Pair with @testing-library/react and toHaveNoViolations. |
| Lighthouse CI | Lighthouse CI | performance, accessibility, SEO, and best-practice budgets at PR time. Fail the build when a budget is breached. |
| eslint-plugin-security | eslint-plugin-security | the OWASP-flavoured static rules (eval, unsafe regex, object injection) at the keystroke. |
| CodeQL | CodeQL | deeper security scans at PR time. Comes with GitHub Advanced Security. |
| Snyk Open Source | Snyk | dependency vulnerabilities at install time and at PR time. The DevSecOps loop in the editor. |
| Dependabot | Dependabot | automated dependency-update PRs. Closes the patch loop without remediation sprints. |
| Web Vitals SDK | Web Vitals | Core Web Vitals in production. The shift-right complement; closes the loop the perf budget at PR time can’t cover. |
eslint.config.mjsconfiguration snippet
import { defineConfig } from 'eslint/config';
import tseslint from 'typescript-eslint';
import jsxA11y from 'eslint-plugin-jsx-a11y';
import security from 'eslint-plugin-security';
export default defineConfig({
files: ['**/*.{ts,tsx,jsx}'],
plugins: { 'jsx-a11y': jsxA11y, security },
rules: {
...jsxA11y.configs.recommended.rules,
'security/detect-object-injection': 'error',
'security/detect-eval-with-expression': 'error',
'security/detect-unsafe-regex': 'error',
}
});Apply these rules in eslint.config.mjs. The full enforcement across every tenet lives on the implementation page.
| Rule | Tool | Catches |
|---|---|---|
| eslint-plugin-jsx-a11y | eslint-plugin-jsx-a11y | static a11y violations in JSX: missing alt text, invalid ARIA attributes, role mismatches. |
| axe-core (vitest integration) | axe-core | runtime a11y violations against rendered components. Pair with @testing-library/react and toHaveNoViolations. |
| Lighthouse CI | Lighthouse CI | performance, accessibility, SEO, and best-practice budgets at PR time. Fail the build when a budget is breached. |
| eslint-plugin-security | eslint-plugin-security | the OWASP-flavoured static rules (eval, unsafe regex, object injection) at the keystroke. |
| CodeQL | CodeQL | deeper security scans at PR time. Comes with GitHub Advanced Security. |
| Snyk Open Source | Snyk | dependency vulnerabilities at install time and at PR time. The DevSecOps loop in the editor. |
| Dependabot | Dependabot | automated dependency-update PRs. Closes the patch loop without remediation sprints. |
| Web Vitals SDK | Web Vitals | Core Web Vitals in production. The shift-right complement; closes the loop the perf budget at PR time can’t cover. |
eslint.config.mjsconfiguration snippet
import { defineConfig } from 'eslint/config';
import tseslint from 'typescript-eslint';
import jsxA11y from 'eslint-plugin-jsx-a11y';
import security from 'eslint-plugin-security';
export default defineConfig({
files: ['**/*.{ts,tsx,jsx}'],
plugins: { 'jsx-a11y': jsxA11y, security },
rules: {
...jsxA11y.configs.recommended.rules,
'security/detect-object-injection': 'error',
'security/detect-eval-with-expression': 'error',
'security/detect-unsafe-regex': 'error',
}
});Apply these rules in lighthouserc.json. The full enforcement across every tenet lives on the implementation page.
| Rule | Tool | Catches |
|---|---|---|
| eslint-plugin-jsx-a11y | eslint-plugin-jsx-a11y | static a11y violations in JSX. |
| Pa11y CI | Pa11y | the alternative a11y tool to axe-core, useful for headless browser scans of static pages. |
| Lighthouse CI | Lighthouse CI | performance, accessibility, SEO, and best-practice budgets at PR time. |
| Snyk Open Source | Snyk | dependency vulnerabilities at install time and at PR time. |
| Semgrep | Semgrep | deeper security scans at PR time: a rule-based scanner that catches the injection, taint and unsafe-API patterns the linter misses. |
| Dependabot | Dependabot | automated dependency-update PRs. |
lighthouserc.jsonconfiguration snippet
{
"ci": {
"assert": {
"preset": "lighthouse:no-pwa",
"assertions": {
"categories:performance": ["error", { "minScore": 0.9 }],
"categories:accessibility": ["error", { "minScore": 1.0 }],
"categories:best-practices": ["error", { "minScore": 0.95 }],
"first-contentful-paint": ["error", { "maxNumericValue": 1500 }],
"largest-contentful-paint": ["error", { "maxNumericValue": 2500 }]
}
}
}
}Apply these rules in pyproject.toml. The full enforcement across every tenet lives on the implementation page.
| Rule | Tool | Catches |
|---|---|---|
| ruff check . --select S | Ruff (S: flake8-bandit) | the Bandit security rules at lint time. Catches use of eval, weak crypto, hardcoded passwords, sql injection. |
| ruff check . --select B | Ruff (B: flake8-bugbear) | the bugbear rules: common bug patterns, unsafe defaults, raise-without-from. Shift-left for defect-prone idioms. |
| bandit -r src/ | Bandit | the deeper Bandit rules that Ruff’s S family doesn’t cover. Standalone scan at PR time. |
| pip-audit | pip-audit | dependency vulnerabilities. The Python equivalent of Dependabot’s scan. |
| axe-playwright (Python) | axe-core | runtime a11y violations against rendered pages in Playwright Python tests. |
| Semgrep (python rules) | Semgrep | rule-based security and quality scans at PR time. Useful for the cross-cutting checks Ruff misses. |
pyproject.tomlconfiguration snippet
[tool.ruff.lint]
select = ["S", "B"]
[tool.bandit]
exclude_dirs = ["tests", "build"]
skips = ["B101"]Apply these rules in pom.xml. The full enforcement across every tenet lives on the implementation page.
| Rule | Tool | Catches |
|---|---|---|
| OWASP Dependency-Check | OWASP Dependency-Check | dependency vulnerabilities at build time. Configure failBuildOnCVSS=7 to gate on the CVSS score. |
| Find Security Bugs | Find Security Bugs | the OWASP-flavoured static rules for Java; pairs with SpotBugs as the bytecode-level scan. |
| SonarQube Security Hotspots | SonarQube Java | the second-layer security review. Hotspots are areas the team must verify; the gate enforces review. |
| axe-core via Selenium | axe-core | runtime a11y violations against rendered web pages in Selenium-Java integration tests. |
| JMH | JMH | JVM micro-benchmarks at CI time. The performance-budget loop for Java; pairs with Lighthouse for the front-end. |
| Snyk for Maven | Snyk | dependency vulnerabilities at PR time; alternative to OWASP Dependency-Check with a richer policy engine. |
pom.xmlconfiguration snippet
<?xml version="1.0"?>
<plugin>
<groupId>org.owasp</groupId>
<artifactId>dependency-check-maven</artifactId>
<executions>
<execution>
<goals><goal>check</goal></goals>
<configuration>
<failBuildOnCVSS>7</failBuildOnCVSS>
</configuration>
</execution>
</executions>
</plugin>Apply these rules in .php-cs-fixer.dist.php. The full enforcement across every tenet lives on the implementation page.
| Rule | Tool | Catches |
|---|---|---|
| Symfony Security Checker | Symfony Security Checker | dependency vulnerabilities by checking installed packages against the Symfony advisories database. |
| Roave Security Advisories | Roave Security Advisories | build-time gating: composer refuses to install a known-vulnerable dependency. Stops the issue at install time, not at PR time. |
| PHPStan | PHPStan | the type-level security checks: tainted strings reaching SQL, missing nullable handling, unsafe casts. Shift-left at the keystroke. |
| Snyk for Composer | Snyk | dependency vulnerabilities at PR time; alternative to the Symfony checker with a richer policy engine. |
| axe-core via Selenium | axe-core | runtime a11y violations against rendered web pages in PHPUnit + Panther tests. |
| Lighthouse CI (per-route) | Lighthouse CI | performance and a11y budgets per route. Useful for any PHP app rendering server-side HTML. |
.php-cs-fixer.dist.phpconfiguration snippet
<?php
return (new PhpCsFixer\Config())
->setRiskyAllowed(true)
->setRules([
'@PHP82Migration:risky' => true,
'no_alias_functions' => true,
'random_api_migration' => true,
])
->setFinder(
(new PhpCsFixer\Finder())->in(__DIR__ . '/src')
);AI rules
.cursor/rules/p5-shift-left-quality.mdc--- alwaysApply: true --- ## Prickles P5: Shift-Left Quality Move every check earlier in the SDLC. From QA into PR. From PR into CI. From CI into the editor. Accessibility, security, performance, observability: all in the gate, all run while the change is fresh. Shift-left without team capability is blame transfer. Pair the move with training, tooling and an actionable signal the engineer can fix in the editor. For agents: configure the a11y MCP, the security MCP and the perf-budget script so the model grounds every change in the same shift-left signals the human gets.
Repo layout, CI, and ESLint wiring for these paths live on /implementation, not repeated on every tenet.
Counter-argument
The strongest steelman is James Bach and Michael Bolton's testing-as-craft tradition: a check can be automated, testing cannot, and shift-left taken to its limit moves the checks into the pipeline and hands the testing to a generalist who lacks the training.4 The Crispin / Gregory qualification is sharper: shift-left without team capability is blame transfer. The engineer who has not been trained to test for a11y will not catch the failure the QA specialist would have.5 The opposing position deserves a fair hearing: shift-left can become a euphemism for “we let the QA team go.”
Counter-argument retort
Bach and Bolton are right about the team that shifts left without investing in the capability. Shift-left isn't a cost-cutting move. It is a capability-building move. The reply is to keep the QA discipline and put it in the developer's hand, not to eliminate it. The Crispin / Gregory Agile Testing tradition is the corrective: QA turns into a coach instead of a gate.5
The larger qualification is that shift-left works only when the check is actionable for the developer. An a11y violation the developer can't interpret is a CI failure they will route around. An axe-core message that names the rule, the element and the fix is a check they will act on. The fix is to invest in the tooling, not to retreat from the principle. Pair this with P4 Continuous Quality Feedback and the loop gives the developer the actionable signal at the keystroke.
For the agent, shift-left is the principle that decides which signals belong in the loop. The model that has run the a11y MCP at edit time produces accessible code. The model that hasn't produces accessible-looking code that fails axe-core. The same shape applies across security and performance. Without shift-left, the agent grades itself against its priors and merges the regression at machine speed.
In production work, the row that fires the a11y check, the security scan and the perf budget at PR time is the row whose product goes out accessible, secure, and performant by default rather than by retrofit. The compounding effect is large: a year of shift-left reduces the year-end regression backlog to near zero. A year of shift-right produces the backlog that becomes a quarter of remediation work.
Notes
- [1]Larry Smith: “Shift-Left Testing”, Dr. Dobb’s Journal, September 2001. The article that named the practice. Cites Boehm’s cost-of-defect curve as the load-bearing source.
- [2]Barry W. Boehm: Software Engineering Economics (Prentice Hall, 1981). The cost-of-defect curve. Forty-five years on the data has not aged. Every shift-left argument descends from this source.
- [3]Noah Shinn et al.: “Reflexion: Language Agents with Verbal Reinforcement Learning”, NeurIPS 2023. The agent grounded in machine-checkable feedback improves. The agent grading itself does not. Generalised by Madaan (Self-Refine) and Gou (CRITIC).
- [4]James Bach & Michael Bolton: “Testing and Checking Refined” (satisfice.com, 2013). The testing-as-craft steelman: a check can be completely automated, testing is “intrinsically a human activity”. Shift-left that moves only the checks leaves the testing behind.
- [5]Lisa Crispin & Janet Gregory: Agile Testing: A Practical Guide for Testers and Agile Teams (Addison-Wesley, 2009). The qualifier: shift-left without team capability is blame transfer. The fix is to keep the QA discipline and put it in the developer’s hand.
- [6]Gartner: “DevSecOps Should Be the Default for All Application Development”, Gartner Research G00318180, 2017. The security branch of shift-left. The term DevSecOps coined here as the operational form.
- [7]W3C: Web Content Accessibility Guidelines (WCAG) 2.2, 2023. The standard the a11y branch of shift-left aims at. The canonical reference for what an accessibility check should verify.
- [8]Deque Systems: axe-core (github.com/dequelabs/axe-core, 2015: ). The dominant developer-loop tool that brings WCAG checks into the editor, the test suite and the agent loop.
- [9]Bruce Lawson & Remy Sharp: Introducing HTML5 (New Riders, 2011). The early bridge book between web development and a11y discipline. The source that connected the WCAG standard to working developer practice.
- [10]Lara Callender Hogan: Designing for Performance: Weighing Aesthetics and Speed (O’Reilly, 2014). The performance-budget idea: an explicit upper bound on page weight, render time, or interactive time as a shift-left analogue for performance.
- [11]Forsgren, Humble & Kim: Accelerate: The Science of Lean Software and DevOps (IT Revolution, 2018). Names shift-left security as one of the practices that distinguishes high-performing teams. The empirical backstop across the four branches.