- enterprise_pdf_checker.py: resolve custom tag names through PDF RoleMap
in _check_headings so PDFs using /Heading1-style tags (mapped to /H1)
are correctly detected; add depth guard to walk_tree
- js/results.js: add CP14 (Heading Structure) to CP_TO_CHECK; relax
H-type restriction so M-type CPs with a linked check also get
Mark as Passed / Undo buttons
- api.php: add 'Heading Structure' => ['14'] to $check_to_cp for
server-side recalculate score with heading override
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
handleResult() now overlays accessibility_score/wcag_compliance from
.adjusted.json (if it exists) while keeping the original severity_counts
as the recalculation baseline — prevents double-subtraction.
displayResults() auto-calls applyScoreRecalc() on load when the result
was previously adjusted, restoring the (Adjusted) label and WCAG badges
without triggering another server save.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
recalculateScore() was only updating the DOM — it never called
save_adjusted_result, so .adjusted.json was never written and the
library always showed the original score. Now saves automatically
after each recalculate.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Issue 1: Recompute WCAG A/AA compliance badges after dismissing issues (JS +
backend); exported reports now reflect updated pass/fail status
- Issue 2: Group document-wide table issues into collapsible cards with
Dismiss All button; reduces noise for multi-table documents
- Issue 3: Split cleanup retention — uploads deleted after 24h, result/meta
JSONs retained 30 days (RESULTS_RETENTION_HOURS env var, default 720h)
- Issue 4A: Library shows adjusted score when available (.adjusted.json preferred)
- Issue 4B: History page groups documents by retention countdown (red/yellow/green
sections); adds 30-day retention banner
- Issue 5+6: AI prompt updated — describe people by role/action not appearance,
use specific brand names; flags images with people for human review
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- api.php: add save_adjusted_result action that merges dismissed issues,
check overrides and recalculated score into {job_id}.adjusted.json;
handleExport() now prefers .adjusted.json over .result.json
- js/results.js: displayMatterhorn() shows Mark as Passed / Undo buttons
for H-type CPs (CP04, CP13) linked to overridden checks; overrideCheck /
unoverrideCheck refresh Matterhorn table and recompute overall banner
- js/batch.js: exportReport() saves adjusted result before opening export
URL, using pre-opened window to avoid popup blockers
- report_generator.py: filter dismissed issues, show (Adjusted) badge,
Manual Pass in checks and Matterhorn tables; switch generate_html() to
Montserrat + Oliver branding (#1a1a1a header, #FFC407 skip-link)
- css/styles.css: fix dark-mode log-header from blue-ish #252840 to #242424
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- api.php: extractUserFromToken() decodes Azure AD JWT payload (oid/name/email)
- Upload: stores user_id, user_name, user_email in job .meta.json
- handleList(): filters jobs by authenticated user's oid — full user isolation
(jobs without user_id are excluded for authenticated users to prevent leakage);
enriches each entry with score, grade, critical/error counts from result JSON
- index.html: "My Documents" history section, shown after login
- js/app.js: showAuthenticatedUI() triggers loadHistory(); full renderHistory()
renders sortable table with score, grade, severity badges, and Open/HTML/PDF/JSON
action buttons; openHistoryJob() loads any past result into the results panel
- js/results.js: calls loadHistory() after displayResults() so table refreshes
immediately after a new check completes
- css/styles.css: history table styles with colour-coded score/grade/severity badges
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Each issue card's WCAG criterion (e.g. "1.4.3") is now a link to the
WAI Understanding page at w3.org. Comma-separated multi-criteria and
PDF/UA are handled separately. Links open in a new tab.
- js/utils.js: WCAG_SLUGS map + wcagCriterionLinks() helper
- js/results.js: issue-meta now calls wcagCriterionLinks()
- css/styles.css: .wcag-link style (dotted underline, hover accent)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Page viewer:
- loadVisualPage() now accepts highlightNum; highlights marker after image onload
(was using fixed 300ms timeout which fired before GCS image finished loading)
- viewOnPage() passes markerNum directly to loadVisualPage()
Image analysis:
- Quality concerns downgraded WARNING → INFO (advisory, not WCAG violations)
- Cap at 2 concerns per image (was unlimited)
- Google Vision label detections removed — not actionable accessibility issues
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Part 1 — CSS/Contrast/Accessibility:
- Raise --text-muted contrast to WCAG AA (#696969 light, #9a9a9a dark)
- Add body font-size: 16px baseline
- Enlarge #themeToggle to 15px / 10px 20px padding
Part 2 — Start Button (user-controlled analysis):
- Upload no longer auto-starts check; shows ready state with filename/size
- New showReadyState() / removeFile() functions in upload.js
- beginCheck() now shows progress + hides ready state on click
- Add prominent "Check Another PDF" button at bottom of results
Part 3 — Scoring recalibration:
- Replace deduction formula with check-pass ratio + soft penalty (cap 20)
- Fix run_check() to only examine issues added by the current check
- Add score_breakdown (per-check table) to JSON output + results UI
- Downgrade readability ERROR → WARNING (advisory, not hard failure)
Part 4 — Auto-fix debugging:
- Remediation failure now returns up to 2000 chars of log (was 500)
- pdf_remediation.py: stderr output, sys.exit(0/1), output dir creation
Part 5 — Error location: View on Page button on each issue card
Part 6 — Matterhorn Protocol PDF/UA-1:
- _build_matterhorn_summary() maps 19 checks → 31 checkpoints
- Matterhorn card in index.html with grouped PASS/FAIL/Not-tested table
- Correct M/H badges per checkpoint
Part 7 — Dismiss / False Positive:
- dismissed_issues table in db/init.sql + dismiss/undismiss in db_manager.py
- api.php: dismiss/undismiss endpoints (file-backed), dismissed_indices
injected into both handleStatus and handleResult responses
- results.js: dismissIssue/undismissIssue with visual strikethrough
- CSS: .dismissed, .btn-dismiss, .btn-undismiss styles
Part 8 — PDF Report (WeasyPrint):
- generate_pdf() in report_generator.py: PAC-style A4, Oliver branding
- api.php handleExport() supports format=pdf
- index.html: "PDF Report" download button in results header
- requirements.txt: weasyprint>=60.0
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Font: Outfit/Figtree → Montserrat
- Accent: coral #e8553d → Oliver yellow #FFC407 with black text
- Dark mode: neutral blacks instead of blue-tinted navy
- Fix score display, stat cards, and log entries contrast in dark mode
- Replace hardcoded light-mode colors in JS with CSS variables
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>