{
  "schemaVersion": 1,
  "version": 1,
  "updated": "2026-11-03",
  "weights": {
    "design": 10,
    "ux": 10,
    "seo": 10,
    "performance": 10,
    "accessibility": 10,
    "mobile": 10,
    "content": 10,
    "branding": 5,
    "technical": 10,
    "conversion": 5,
    "security": 5,
    "reliability": 5
  },
  "categories": [
    {
      "id": "design",
      "name": "Design and visual quality",
      "weight": 10,
      "method": "Manual review of screenshots at 390 and 1440 px in both themes against the rubric; no automated score exists for this category.",
      "sources": ["Screenshots from scripts/qa/shots.mjs", "Theme and token inspection"],
      "rubric": [
        {
          "score": 10,
          "meaning": "Consistent system across every page and theme, reviewed by an independent designer"
        },
        {
          "score": 9,
          "meaning": "Consistent tokens, typography and spacing on every page in both themes; self-reviewed"
        },
        { "score": 7, "meaning": "Minor inconsistencies between pages or themes" },
        { "score": 5, "meaning": "Visible inconsistencies or broken layouts on some pages" },
        { "score": 3, "meaning": "No coherent system" }
      ]
    },
    {
      "id": "ux",
      "name": "UX and navigation",
      "weight": 10,
      "method": "Manual review of navigation, hierarchy, empty and error states and interactive feedback, supported by the keyboard suite.",
      "sources": ["scripts/qa/kbd.mjs", "Manual walkthrough"],
      "rubric": [
        { "score": 10, "meaning": "Every task completes without friction; validated with real users" },
        {
          "score": 9,
          "meaning": "Clear hierarchy, breadcrumbs, previous/next, filters, lightbox, 404 and empty states all working; self-reviewed"
        },
        { "score": 7, "meaning": "Some pages hard to reach or interactive states unclear" },
        { "score": 5, "meaning": "Navigation gaps or confusing structure" },
        { "score": 3, "meaning": "Key content unreachable" }
      ]
    },
    {
      "id": "seo",
      "name": "SEO",
      "weight": 10,
      "method": "Automated crawl of every indexable page (titles, descriptions, canonicals, Open Graph, Twitter card, heading count, alt text, links), structured-data validation, sitemap and robots checks, live redirect checks. Indexing and rich-result status are not measurable without Search Console.",
      "sources": ["scripts/qa/full.mjs", "scripts/qa/jsonld.mjs", "Live redirect and sitemap checks"],
      "rubric": [
        { "score": 10, "meaning": "All automated checks pass and Search Console confirms indexing and rich results" },
        { "score": 9, "meaning": "All automated checks pass on every page; indexing not yet confirmed" },
        { "score": 7, "meaning": "Isolated metadata defects or missing structured data" },
        { "score": 5, "meaning": "Duplicate or missing metadata on several pages" },
        { "score": 3, "meaning": "Pages blocked or uncrawlable" }
      ]
    },
    {
      "id": "performance",
      "name": "Performance",
      "weight": 10,
      "method": "Lighthouse lab runs (median of several mobile runs plus desktop) on six representative pages, plus page weight. Real-user Core Web Vitals are reported only when field data exists; TBT is a lab proxy, not INP.",
      "sources": ["scripts/qa/lh-batch.mjs", "Lighthouse"],
      "rubric": [
        { "score": 10, "meaning": "Lab 100 on every page and field vitals pass" },
        {
          "score": 9.5,
          "meaning": "Lab 99 to 100 on every page, CLS 0, pages under 100 KB except media galleries; no field data yet"
        },
        { "score": 8, "meaning": "Lab 90 to 98 on some pages" },
        { "score": 6, "meaning": "Lab under 90 on important pages" },
        { "score": 3, "meaning": "Poor Core Web Vitals" }
      ]
    },
    {
      "id": "accessibility",
      "name": "Accessibility",
      "weight": 10,
      "method": "axe-core (WCAG 2.0/2.1/2.2 A and AA plus best practice) on every page in both themes, keyboard suite in three engines, target-size sweep, manual focus review. Zero automated violations is evidence, not proof of compliance; no screen-reader session has been run.",
      "sources": ["scripts/qa/full.mjs", "scripts/qa/kbd.mjs", "scripts/qa/viewports.mjs"],
      "rubric": [
        {
          "score": 10,
          "meaning": "Zero violations, keyboard and screen-reader sessions passed, reviewed by an accessibility specialist"
        },
        {
          "score": 9,
          "meaning": "Zero automated violations on every page and theme, keyboard suite passing, targets at least 24 px; no screen-reader session"
        },
        { "score": 7, "meaning": "Minor violations or focus issues" },
        { "score": 5, "meaning": "Serious violations on some pages" },
        { "score": 3, "meaning": "Content unusable without a mouse" }
      ]
    },
    {
      "id": "mobile",
      "name": "Mobile responsiveness",
      "weight": 10,
      "method": "Viewport sweep at 320, 375, 390, 768, 1024 and 1440 px in both themes: horizontal overflow, targets under 24 px, text under 12 px; cross-browser render pass at three widths.",
      "sources": ["scripts/qa/viewports.mjs", "scripts/qa/kbd.mjs"],
      "rubric": [
        { "score": 10, "meaning": "All widths and themes pass and diagrams remain legible on phones" },
        { "score": 9.5, "meaning": "All widths and themes pass; some diagram labels small on phones" },
        { "score": 8, "meaning": "Minor overflow or small targets on some pages" },
        { "score": 6, "meaning": "Broken layouts at common widths" },
        { "score": 3, "meaning": "Not usable on phones" }
      ]
    },
    {
      "id": "content",
      "name": "Content and credibility",
      "weight": 10,
      "method": "Manual verification that every claim, number, stack and link traces to a repository, document or live site; gallery credits; completeness of case studies.",
      "sources": ["Project repositories and READMEs", "Live client sites", "docs/AUDIT-2026-11-03.md"],
      "rubric": [
        {
          "score": 10,
          "meaning": "Every claim verified, every case study complete, all imagery original or clearly credited"
        },
        {
          "score": 9,
          "meaning": "Every claim verified; one case study incomplete or imagery credited rather than original"
        },
        { "score": 7, "meaning": "Some claims unverifiable or placeholders visible" },
        { "score": 5, "meaning": "Inaccurate stacks or unsupported numbers" },
        { "score": 3, "meaning": "Invented content" }
      ]
    },
    {
      "id": "branding",
      "name": "Branding",
      "weight": 5,
      "method": "Manual review of identity consistency: mark, accent, typography, tone and social images across pages.",
      "sources": ["Screenshots", "OG images"],
      "rubric": [
        { "score": 10, "meaning": "Distinct, consistent identity validated with an audience" },
        { "score": 9, "meaning": "Consistent identity on every page and social image; self-reviewed" },
        { "score": 7, "meaning": "Minor inconsistencies" },
        { "score": 5, "meaning": "Generic or inconsistent" },
        { "score": 3, "meaning": "No identity" }
      ]
    },
    {
      "id": "technical",
      "name": "Technical implementation",
      "weight": 10,
      "method": "TypeScript strict check, ESLint, Prettier, dependency audit, build gates, client JavaScript size, architecture review.",
      "sources": ["astro check", "eslint", "prettier", "npm audit", "scripts/verify-build.mjs"],
      "rubric": [
        {
          "score": 10,
          "meaning": "Clean checks, no vulnerable dependencies, unit tests for logic, reviewed architecture"
        },
        {
          "score": 9,
          "meaning": "Clean checks and build gates; vulnerable dependencies confined to development tooling"
        },
        { "score": 7, "meaning": "Lint or type issues, or shipped vulnerable dependencies" },
        { "score": 5, "meaning": "Failing checks" },
        { "score": 3, "meaning": "No checks" }
      ]
    },
    {
      "id": "conversion",
      "name": "Conversion and contact",
      "weight": 5,
      "method": "Manual review of calls to action, contact paths, email and social link correctness; link checks.",
      "sources": ["scripts/qa/full.mjs link check", "Manual review"],
      "rubric": [
        { "score": 10, "meaning": "Clear offer, every contact path verified including by hand" },
        {
          "score": 9,
          "meaning": "Clear calls to action and contact page, links verified; one profile unverifiable by script"
        },
        { "score": 7, "meaning": "Contact path exists but is hard to find" },
        { "score": 5, "meaning": "Broken or missing contact details" },
        { "score": 3, "meaning": "No way to get in touch" }
      ]
    },
    {
      "id": "security",
      "name": "Security",
      "weight": 5,
      "method": "Static and configuration checks only: live security headers, CSP, HTTPS, redirects, security.txt, dependency audit, CMS authentication tests, OAuth Worker tests, exposure probes. No penetration test has been performed.",
      "sources": [
        "Live header checks",
        "npm audit",
        "scripts/qa/admin-sec.mjs",
        "workers/decap-oauth/test.mjs",
        "scripts/qa/admin-online.mjs"
      ],
      "rubric": [
        { "score": 10, "meaning": "All controls present and an independent penetration test passed" },
        {
          "score": 9.5,
          "meaning": "All headers, CSP, HTTPS, secret handling and CMS controls verified; development-only vulnerable dependencies; no penetration test"
        },
        { "score": 7, "meaning": "Missing headers or weak CSP" },
        { "score": 5, "meaning": "Exposed configuration or shipped vulnerable dependencies" },
        { "score": 3, "meaning": "Exposed secrets" }
      ]
    },
    {
      "id": "reliability",
      "name": "Reliability and testing",
      "weight": 5,
      "method": "Count and health of the automated suites, CI status, deployment gates, reproducibility of every check.",
      "sources": ["GitHub Actions", "scripts/qa/*", "scripts/audit/score.test.mjs"],
      "rubric": [
        { "score": 10, "meaning": "Every check automated in CI with history and alerting" },
        { "score": 9.5, "meaning": "All suites automated and passing; CI gates deployment; history recorded" },
        { "score": 8, "meaning": "Suites exist but run manually" },
        { "score": 6, "meaning": "Partial coverage" },
        { "score": 3, "meaning": "No tests" }
      ]
    }
  ],
  "rules": [
    "Category scores are assessed against the rubric and must cite evidence; automated pass rates are evidence, never scores.",
    "Lighthouse scores are shown separately from the quality score and never substitute for it.",
    "Accessibility violations are reported independently of the accessibility rating.",
    "Security checks are static and configuration checks; nothing here is a penetration test.",
    "Missing evidence lowers confidence or yields 'not enough evidence to score'; it is never treated as a pass.",
    "Historical scores are never rewritten; a new assessment adds an entry.",
    "Every score is reproducible from methodology.json, assessments.json and the linked evidence.",
    "Rounding is for presentation only; the precise weighted value is stored.",
    "A check older than staleAfterDays is shown as stale regardless of its result."
  ],
  "confidence": {
    "high": "Assessment made for the same commit as the latest automated run, and every check passed.",
    "medium": "Same commit with warnings, or an older assessment with all current checks passing.",
    "low": "Failed, stale or untested checks, or no assessment."
  },
  "staleAfterDays": 30
}
