{
  "policy": {
    "version": 5,
    "patterns": {
      "version": 1,
      "method": "CURATED_PRACTICE_TOPIC",
      "notice": "Pattern topics identify design choices to practice. Read the ticket's acceptance criteria and justify the simplest suitable approach. Tags are not capability or ownership evidence; an untagged ticket has no curated pattern topic assigned."
    },
    "fieldMix": {
      "version": 1,
      "method": "CURATED_ESTIMATE",
      "notice": "Field percentages are editorial estimates of the ticket's engineering focus. They total 100%; they are not measured time, proficiency scores, or ownership evidence."
    },
    "contentStatus": "PRACTICE_BRIEF",
    "assessmentStatus": "NOT_QUALIFIED",
    "evidenceUse": "NONE",
    "aiPolicy": "AI tools are welcome during implementation. Record assumptions, review the result, and verify its behavior.",
    "notice": "Fictional engineering practice briefs. Starter repositories, fixtures, automated grading, and verified ownership are not included.",
    "outcomeEvidence": "Tests, patches, and runbooks are requested deliverables. They become Outcome Evidence only through a qualified Mission and immutable Evidence IDs.",
    "ownershipEvidence": "Independent adaptation must be observed under a declared verification policy and cite immutable Evidence IDs. Completing a planning ticket establishes no Ownership Evidence."
  },
  "patternTopics": [
    {
      "id": "factory-method",
      "label": "Factory Method",
      "group": "Creational"
    },
    {
      "id": "abstract-factory",
      "label": "Abstract Factory",
      "group": "Creational"
    },
    {
      "id": "builder",
      "label": "Builder",
      "group": "Creational"
    },
    {
      "id": "prototype",
      "label": "Prototype",
      "group": "Creational"
    },
    {
      "id": "singleton",
      "label": "Singleton",
      "group": "Creational"
    },
    {
      "id": "adapter",
      "label": "Adapter",
      "group": "Structural"
    },
    {
      "id": "bridge",
      "label": "Bridge",
      "group": "Structural"
    },
    {
      "id": "composite",
      "label": "Composite",
      "group": "Structural"
    },
    {
      "id": "decorator",
      "label": "Decorator",
      "group": "Structural"
    },
    {
      "id": "facade",
      "label": "Facade",
      "group": "Structural"
    },
    {
      "id": "flyweight",
      "label": "Flyweight",
      "group": "Structural"
    },
    {
      "id": "proxy",
      "label": "Proxy",
      "group": "Structural"
    },
    {
      "id": "chain-of-responsibility",
      "label": "Chain of Responsibility",
      "group": "Behavioral"
    },
    {
      "id": "command",
      "label": "Command",
      "group": "Behavioral"
    },
    {
      "id": "interpreter",
      "label": "Interpreter",
      "group": "Behavioral"
    },
    {
      "id": "iterator",
      "label": "Iterator",
      "group": "Behavioral"
    },
    {
      "id": "mediator",
      "label": "Mediator",
      "group": "Behavioral"
    },
    {
      "id": "memento",
      "label": "Memento",
      "group": "Behavioral"
    },
    {
      "id": "observer",
      "label": "Observer",
      "group": "Behavioral"
    },
    {
      "id": "state",
      "label": "State",
      "group": "Behavioral"
    },
    {
      "id": "strategy",
      "label": "Strategy",
      "group": "Behavioral"
    },
    {
      "id": "template-method",
      "label": "Template Method",
      "group": "Behavioral"
    },
    {
      "id": "visitor",
      "label": "Visitor",
      "group": "Behavioral"
    },
    {
      "id": "ports-and-adapters",
      "label": "Ports and Adapters",
      "group": "Architectural"
    },
    {
      "id": "cqrs",
      "label": "CQRS",
      "group": "Architectural"
    },
    {
      "id": "strangler-fig",
      "label": "Strangler Fig",
      "group": "Architectural"
    },
    {
      "id": "saga",
      "label": "Saga",
      "group": "Distributed and reliability"
    },
    {
      "id": "transactional-outbox",
      "label": "Transactional Outbox",
      "group": "Distributed and reliability"
    },
    {
      "id": "circuit-breaker",
      "label": "Circuit Breaker",
      "group": "Distributed and reliability"
    },
    {
      "id": "bulkhead",
      "label": "Bulkhead",
      "group": "Distributed and reliability"
    }
  ],
  "projects": [
    {
      "id": "ad866514-92f4-416e-a03d-35fd85fa48d1",
      "key": "A11Y",
      "title": "A civic appointment flow people can complete",
      "field": "Accessibility",
      "summary": "Repair public-service booking across keyboard use, zoom, timeouts, and changing availability.",
      "context": "The fictional Riverside desk books appointments for permit paperwork and library assistance. Its browser flow was assembled from separate forms and dialogs. Work uses synthetic availability and booking adapters; actual appointments and personal records are excluded.",
      "stack": [
        "TypeScript",
        "Semantic HTML",
        "CSS Modules",
        "Playwright",
        "axe-core"
      ],
      "prerequisites": [
        "Synthetic services, slots, and booking API contract",
        "Keyboard and screen-reader access for a documented manual check"
      ],
      "developerValue": "Practice accessibility as complete interaction behavior, including recovery and asynchronous updates.",
      "companyValue": "Inspect whether an engineer removes concrete barriers while preserving appointment integrity and supportability.",
      "delivery": "Choose a bounded issue and record automated and manual checks separately. A passing scanner does not establish complete accessibility.",
      "phases": [
        {
          "id": "entry",
          "title": "Enter the flow",
          "goal": "Make service selection and entry understandable."
        },
        {
          "id": "availability",
          "title": "Choose an appointment",
          "goal": "Handle date navigation and changing slots."
        },
        {
          "id": "continuity",
          "title": "Preserve progress",
          "goal": "Recover focus, drafts, and session interruptions."
        },
        {
          "id": "completion",
          "title": "Complete and verify",
          "goal": "Make confirmation and release evidence usable."
        }
      ],
      "tickets": [
        {
          "id": "312991f5-f46f-4887-9604-5fbd55d9d91f",
          "key": "A11Y-101",
          "title": "Replace clickable service tiles with a named selection group",
          "type": "BUG",
          "priority": "HIGH",
          "difficulty": "FOUNDATIONAL",
          "estimateMinutes": 60,
          "phaseId": "entry",
          "dependsOn": [],
          "scenario": "Service choices are clickable divs. Keyboard users cannot reach them, and a screen reader announces no selected service. Repair selection without changing the taxonomy.",
          "acceptanceCriteria": [
            "Every service belongs to a semantic single-choice group with a visible label.",
            "Selected value is announced and included in the form value.",
            "Unavailable services explain their status and cannot be selected by keyboard or pointer."
          ],
          "implementationNotes": [
            "Prefer native radio inputs and associated labels over a custom interaction model."
          ],
          "verification": [
            "Choose Library assistance using only the keyboard and inspect the form value.",
            "Try selecting an unavailable service through pointer and keyboard; selection remains unchanged and its reason is readable."
          ],
          "deliverables": [
            "Semantic service chooser and keyboard regression case"
          ],
          "rollout": "Release independently; restore native unstyled controls if decoration hides focus or selection.",
          "skills": [
            "Semantic HTML",
            "Keyboard access",
            "Forms"
          ],
          "fieldMix": [
            {
              "field": "Accessibility",
              "percentage": 70
            },
            {
              "field": "Frontend",
              "percentage": 30
            }
          ],
          "patterns": []
        },
        {
          "id": "98ed49e2-ea4f-44c6-bb90-01f96088b443",
          "key": "A11Y-102",
          "title": "Keep contact-field help and errors understandable together",
          "type": "TASK",
          "priority": "MEDIUM",
          "difficulty": "FOUNDATIONAL",
          "estimateMinutes": 75,
          "phaseId": "entry",
          "dependsOn": [],
          "scenario": "A phone-field error replaces the format hint, then disappears on the first keystroke while the value remains invalid. Give help and validation a coherent lifecycle.",
          "acceptanceCriteria": [
            "Persistent help and current errors are associated with their field.",
            "Submitted errors remain until correction or the next documented validation point.",
            "Invalid submission provides a focusable summary linked to every invalid field."
          ],
          "implementationNotes": [
            "Do not announce errors on every keystroke; document validation timing."
          ],
          "verification": [
            "Submit an invalid phone and navigate from summary to field; hear both hint and error.",
            "Correct one of two invalid fields and resubmit; only the remaining error appears and values persist."
          ],
          "deliverables": [
            "Contact validation semantics and assistive-technology notes"
          ],
          "rollout": "Apply to contact fields first; retain plain inline errors if enhanced summary behavior loses focus.",
          "skills": [
            "Accessible validation",
            "Forms",
            "Focus management"
          ],
          "fieldMix": [
            {
              "field": "Accessibility",
              "percentage": 70
            },
            {
              "field": "Frontend",
              "percentage": 30
            }
          ],
          "patterns": []
        },
        {
          "id": "4abee102-a2a8-4c2c-ab3e-505834c454ef",
          "key": "A11Y-103",
          "title": "Make month navigation work without a pointer",
          "type": "STORY",
          "priority": "HIGH",
          "difficulty": "INTERMEDIATE",
          "estimateMinutes": 120,
          "phaseId": "availability",
          "dependsOn": [
            "A11Y-101"
          ],
          "scenario": "The calendar exposes 42 unnamed buttons and moves focus to the page top on month changes. Add a deliberate keyboard model and plain date-entry alternative.",
          "acceptanceCriteria": [
            "Date controls announce full date, availability, and selection.",
            "Changing month retains focus at a predictable date or documented month control.",
            "Manual date entry uses the same availability validation and reports invalid dates clearly."
          ],
          "implementationNotes": [
            "Document the calendar keyboard model; shortcuts must not conflict with text entry."
          ],
          "verification": [
            "Select an available date across a month boundary by keyboard.",
            "Enter an impossible date and navigate to an unavailable date; neither becomes selected and focus remains recoverable."
          ],
          "deliverables": [
            "Accessible date selection and month-boundary walkthrough"
          ],
          "rollout": "Keep manual entry during rollout; disable the custom calendar on keyboard-navigation regression.",
          "skills": [
            "Keyboard interaction",
            "Date input",
            "Accessibility"
          ],
          "fieldMix": [
            {
              "field": "Accessibility",
              "percentage": 70
            },
            {
              "field": "Frontend",
              "percentage": 30
            }
          ],
          "patterns": []
        },
        {
          "id": "5df57444-3feb-4776-9b5b-b0b079e212c6",
          "key": "A11Y-104",
          "title": "Keep the booking action visible at high zoom",
          "type": "BUG",
          "priority": "HIGH",
          "difficulty": "INTERMEDIATE",
          "estimateMinutes": 90,
          "phaseId": "availability",
          "dependsOn": [
            "A11Y-102",
            "A11Y-103"
          ],
          "scenario": "At 400% zoom the fixed step header and cookie banner cover the selected time and Continue button. Repair reflow across booking steps.",
          "acceptanceCriteria": [
            "At the documented desktop viewport and 400% zoom, essential content reflows without horizontal page scrolling.",
            "Fixed UI never covers focused fields, error links, or booking actions.",
            "Long service names and expanded text spacing do not clip labels or values."
          ],
          "implementationNotes": [
            "Use normal flow where fixed positioning provides no user benefit."
          ],
          "verification": [
            "Complete service and slot selection at 400% zoom by keyboard.",
            "Apply expanded text spacing and a long service name with an error summary; check clipping and focus obstruction."
          ],
          "deliverables": [
            "Reflow corrections and viewport/zoom evidence notes"
          ],
          "rollout": "Check every step before shared layout release; revert sticky behavior first if actions become obscured.",
          "skills": [
            "CSS layout",
            "Reflow",
            "Visual verification"
          ],
          "fieldMix": [
            {
              "field": "Accessibility",
              "percentage": 60
            },
            {
              "field": "Frontend",
              "percentage": 40
            }
          ],
          "patterns": []
        },
        {
          "id": "725c23d9-c49b-4453-aaba-854a809f806c",
          "key": "A11Y-105",
          "title": "Recover when another visitor takes the chosen slot",
          "type": "BUG",
          "priority": "HIGH",
          "difficulty": "ADVANCED",
          "estimateMinutes": 150,
          "phaseId": "availability",
          "dependsOn": [
            "A11Y-103"
          ],
          "scenario": "The last 10:30 appointment is taken while a visitor enters contact details. Submission reports Slot unavailable and resets the entire flow.",
          "acceptanceCriteria": [
            "Conflict preserves contact values and service while clearing the unavailable slot.",
            "The conflict is announced once and focus moves to a useful recovery heading with alternatives.",
            "A replacement needs explicit confirmation and current availability revision data."
          ],
          "implementationNotes": [
            "Never automatically book a different time; availability remains server-authoritative."
          ],
          "verification": [
            "Conflict the slot, choose 11:00, and finish without re-entering contact details.",
            "Return no alternatives and fail refresh; explain the state without trapping focus or inventing availability."
          ],
          "deliverables": [
            "Slot-conflict recovery and accessible failure scenario"
          ],
          "rollout": "Exercise synthetic capacity conflicts before pilot; pause booking if contact recovery or slot identity is unreliable.",
          "skills": [
            "Concurrency UX",
            "Accessibility",
            "Recovery"
          ],
          "fieldMix": [
            {
              "field": "Accessibility",
              "percentage": 50
            },
            {
              "field": "Frontend",
              "percentage": 30
            },
            {
              "field": "API design",
              "percentage": 20
            }
          ],
          "patterns": []
        },
        {
          "id": "46ae0b00-a876-43ea-9882-bc0be5081646",
          "key": "A11Y-106",
          "title": "Announce availability changes without reading the whole page again",
          "type": "TASK",
          "priority": "MEDIUM",
          "difficulty": "ADVANCED",
          "estimateMinutes": 135,
          "phaseId": "continuity",
          "dependsOn": [
            "A11Y-105"
          ],
          "scenario": "Each refresh rewrites a large live region. A screen reader repeats all slots and interrupts contact entry even when nothing changed.",
          "acceptanceCriteria": [
            "Unchanged slot lists generate no routine announcements.",
            "Meaningful changes produce a short status without moving focus.",
            "Loss of a selected slot takes priority over routine counts; stale request messages are ignored."
          ],
          "implementationNotes": [
            "Use a small status region and coalesce bursts; never mark the entire form live."
          ],
          "verification": [
            "Refresh identical data three times while typing; no repeated list announcement occurs.",
            "Remove the selected slot while delayed old data arrives; announce loss once and retain current focus."
          ],
          "deliverables": [
            "Announcement coordinator and manual speech-output log"
          ],
          "rollout": "Pilot with routine announcements disabled; retain only actionable notices if speech becomes noisy.",
          "skills": [
            "Live regions",
            "Async interaction",
            "Assistive technology"
          ],
          "fieldMix": [
            {
              "field": "Accessibility",
              "percentage": 70
            },
            {
              "field": "Frontend",
              "percentage": 30
            }
          ],
          "patterns": []
        },
        {
          "id": "5eb64f66-3485-4c53-9e3f-77bdc39ff100",
          "key": "A11Y-107",
          "title": "Handle expiry without an inaccessible countdown trap",
          "type": "STORY",
          "priority": "HIGH",
          "difficulty": "EXPERT",
          "estimateMinutes": 210,
          "phaseId": "continuity",
          "dependsOn": [
            "A11Y-102",
            "A11Y-105",
            "A11Y-106"
          ],
          "scenario": "A slow form session expires after details are entered. The countdown steals focus every second, and Extend reports success after the server session has ended.",
          "acceptanceCriteria": [
            "Advance warning offers an accessible extension action without announcing each second.",
            "Extension success requires server confirmation and preserves the active form location.",
            "Expiry or uncertain extension preserves a scoped draft but requires session recovery and fresh slot validation before booking."
          ],
          "implementationNotes": [
            "Use a fake clock and session adapter; do not weaken expiry or record contact data in analytics."
          ],
          "verification": [
            "Extend before expiry by keyboard and verify confirmed continuation with focus restoration.",
            "Race expiry and a lost extension response; expired authority cannot book, and recovery revalidates the slot."
          ],
          "deliverables": [
            "Session continuity state machine and expiry-race walkthrough"
          ],
          "rollout": "Pilot against short synthetic sessions; disable booking under ambiguous session authority while preserving recoverable drafts.",
          "skills": [
            "Session lifecycle",
            "Accessibility",
            "Race conditions"
          ],
          "fieldMix": [
            {
              "field": "Accessibility",
              "percentage": 50
            },
            {
              "field": "Frontend",
              "percentage": 30
            },
            {
              "field": "Backend",
              "percentage": 20
            }
          ],
          "patterns": []
        },
        {
          "id": "1c7d02f4-9646-48c7-9146-bd1afaf24e45",
          "key": "A11Y-108",
          "title": "Return focus correctly after reviewing contact details",
          "type": "BUG",
          "priority": "MEDIUM",
          "difficulty": "ADVANCED",
          "estimateMinutes": 120,
          "phaseId": "continuity",
          "dependsOn": [
            "A11Y-104",
            "A11Y-107"
          ],
          "scenario": "Edit contact opens a dialog from review. Closing returns focus to a control removed by session refresh, stranding keyboard users.",
          "acceptanceCriteria": [
            "The dialog has a name, contained focus, and visible close action.",
            "Closing restores the invoking control or a documented visible fallback if the step changed.",
            "Recovery and dialog close cannot race focus into hidden or inert content."
          ],
          "implementationNotes": [
            "Use an accessible primitive with local styling and coordinate focus ownership across states."
          ],
          "verification": [
            "Edit and close normally; focus returns to Edit contact with revised details visible.",
            "Expire the session while editing and close during recovery; focus lands on the current recovery heading."
          ],
          "deliverables": [
            "Dialog focus ownership fix and interleaved-state keyboard test"
          ],
          "rollout": "Enable only on review; switch to inline editing if dialog focus ownership regresses.",
          "skills": [
            "Focus management",
            "Dialogs",
            "State coordination"
          ],
          "fieldMix": [
            {
              "field": "Accessibility",
              "percentage": 70
            },
            {
              "field": "Frontend",
              "percentage": 30
            }
          ],
          "patterns": []
        },
        {
          "id": "371d9ad9-7cac-4885-96da-51c55e4d9b45",
          "key": "A11Y-109",
          "title": "Make confirmation usable on screen and in print",
          "type": "STORY",
          "priority": "MEDIUM",
          "difficulty": "INTERMEDIATE",
          "estimateMinutes": 105,
          "phaseId": "completion",
          "dependsOn": [
            "A11Y-105",
            "A11Y-108"
          ],
          "scenario": "The screenshot-style confirmation cannot be selected, print cuts off the address, and appointment time omits the time zone.",
          "acceptanceCriteria": [
            "Service, date, time zone, location, and reference are selectable semantic text.",
            "Print includes all appointment details without navigation chrome or clipping.",
            "Only confirmed bookings show confirmation, with an accessible copy-reference action."
          ],
          "implementationNotes": [
            "An HTML print view is sufficient; PDF generation is excluded."
          ],
          "verification": [
            "Confirm a synthetic appointment, copy its reference, and inspect print preview.",
            "Return an uncertain result and use a long location; no false confirmation appears and reconciled print details remain complete."
          ],
          "deliverables": [
            "Semantic confirmation and print stylesheet"
          ],
          "rollout": "Release styling after booking-identity checks; retain plain-text details if print styling fails.",
          "skills": [
            "Semantic content",
            "Print CSS",
            "Transaction UX"
          ],
          "fieldMix": [
            {
              "field": "Accessibility",
              "percentage": 60
            },
            {
              "field": "Frontend",
              "percentage": 40
            }
          ],
          "patterns": []
        },
        {
          "id": "213b2b9c-39b4-489f-a724-1077b6d818ee",
          "key": "A11Y-110",
          "title": "Build a barrier-focused release check for booking",
          "type": "CHORE",
          "priority": "HIGH",
          "difficulty": "ADVANCED",
          "estimateMinutes": 150,
          "phaseId": "completion",
          "dependsOn": [
            "A11Y-106",
            "A11Y-107",
            "A11Y-109"
          ],
          "scenario": "Scanners pass while keyboard testers still lose drafts after conflicts. Add a release check covering actual booking and recovery.",
          "acceptanceCriteria": [
            "Checks cover keyboard completion, zoom, named controls, slot conflicts, and session recovery.",
            "Automated assertions and manual observations are recorded separately with browser/tool versions.",
            "Unresolved barriers name affected steps and usable fallbacks without claiming universal accessibility."
          ],
          "implementationNotes": [
            "Bound the manual matrix to agreed combinations and include a reproduction script per barrier."
          ],
          "verification": [
            "Run normal booking plus slot-conflict and session-expiry scenarios and record outcomes.",
            "Introduce a missing dialog name or broken return focus in a local fixture; the relevant check detects it."
          ],
          "deliverables": [
            "Booking accessibility regression matrix and release decision note"
          ],
          "rollout": "Use before pilot expansion; block steps with unrecoverable barriers and retain the documented alternative flow.",
          "skills": [
            "Accessibility testing",
            "Release verification",
            "Documentation"
          ],
          "fieldMix": [
            {
              "field": "Accessibility",
              "percentage": 60
            },
            {
              "field": "Quality engineering",
              "percentage": 40
            }
          ],
          "patterns": []
        }
      ]
    }
  ]
}
