{
  "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": "2abdd9ee-3567-4c39-b2e6-e46fbfdce62b",
      "key": "CLI",
      "title": "Release day without the shared spreadsheet",
      "field": "Developer tooling",
      "summary": "Build a local release assistant that prepares reviewable plans and survives interrupted release steps.",
      "context": "A team maintains six related packages. Release notes, version changes, and tags are copied between a spreadsheet and a terminal; a failed upload recently left two packages ahead of their dependents. The exercise uses temporary repositories and a fake registry.",
      "stack": [
        "TypeScript",
        "Node.js",
        "Git",
        "pnpm"
      ],
      "prerequisites": [
        "Create a temporary Git repository with three related fixture packages.",
        "Use a local registry double; no publishing credentials are required."
      ],
      "developerValue": "Practice CLI contracts, graph reasoning, filesystem safety, and recovery from partial work.",
      "companyValue": "Review how an engineer makes release changes inspectable and recoverable before they affect consumers.",
      "delivery": "A release-plan CLI, local fixtures, recovery tests, and an operator guide.",
      "phases": [
        {
          "id": "inspect",
          "title": "Know what will change",
          "goal": "Produce a deterministic release plan from repository inputs."
        },
        {
          "id": "prepare",
          "title": "Prepare a reviewable release",
          "goal": "Write only the planned files and make failure recovery explicit."
        },
        {
          "id": "recover",
          "title": "Handle an interrupted release",
          "goal": "Resume against a fake registry without duplicating or concealing work."
        }
      ],
      "tickets": [
        {
          "id": "39272ddf-3bb4-4c46-b110-cd43c8a61e21",
          "key": "CLI-101",
          "title": "Print package versions without depending on the current directory",
          "type": "TASK",
          "priority": "MEDIUM",
          "difficulty": "FOUNDATIONAL",
          "estimateMinutes": 60,
          "phaseId": "inspect",
          "dependsOn": [],
          "scenario": "The release coordinator runs the command from packages/ui and gets an empty package list. Add an inspect command that finds the workspace root and reports each releasable package.",
          "acceptanceCriteria": [
            "Running from the root or a nested package produces the same sorted names and versions.",
            "Private packages are labeled and excluded from the releasable count.",
            "A directory outside a workspace returns a nonzero exit code and an actionable error."
          ],
          "implementationNotes": [
            "Read manifests as data; do not run package scripts.",
            "Stop root discovery at the filesystem root."
          ],
          "verification": [
            "Run inspect from root, a nested directory, and a path containing spaces.",
            "Pass malformed package JSON and verify that the filename appears without dumping file contents."
          ],
          "deliverables": [
            "Inspect subcommand and a three-package fixture"
          ],
          "rollout": "Ship as a read-only command first; revert the command registration if root detection regresses.",
          "skills": [
            "CLI design",
            "Filesystem paths",
            "Input validation"
          ],
          "fieldMix": [
            {
              "field": "Developer tooling",
              "percentage": 100
            }
          ],
          "patterns": []
        },
        {
          "id": "985390b8-031d-46b6-aa40-2fa059dc890f",
          "key": "CLI-102",
          "title": "Give scripts a stable JSON output contract",
          "type": "STORY",
          "priority": "MEDIUM",
          "difficulty": "FOUNDATIONAL",
          "estimateMinutes": 75,
          "phaseId": "inspect",
          "dependsOn": [
            "CLI-101"
          ],
          "scenario": "CI currently scrapes a colored table and breaks when a package name wraps. Add --json to inspect so automation can consume a versioned response.",
          "acceptanceCriteria": [
            "JSON output includes schemaVersion, workspace packages, and warnings with stable field names.",
            "Stdout contains exactly one JSON document with no ANSI escapes.",
            "Diagnostics go to stderr and invalid arguments keep a documented nonzero exit code."
          ],
          "implementationNotes": [
            "Keep human rendering separate from the result model."
          ],
          "verification": [
            "Parse stdout from a successful --json run with JSON.parse.",
            "Combine --json with an unknown flag and assert no partial success document is printed."
          ],
          "deliverables": [
            "JSON response schema and CLI exit-code reference"
          ],
          "rollout": "Add the opt-in format without changing existing human output; version incompatible schema changes.",
          "skills": [
            "API contracts",
            "CLI design",
            "Compatibility"
          ],
          "fieldMix": [
            {
              "field": "Developer tooling",
              "percentage": 70
            },
            {
              "field": "API design",
              "percentage": 30
            }
          ],
          "patterns": []
        },
        {
          "id": "a767c860-d8a2-44f5-a8a9-7fa11400a811",
          "key": "CLI-103",
          "title": "Include dependent packages in the proposed version bump",
          "type": "STORY",
          "priority": "HIGH",
          "difficulty": "ADVANCED",
          "estimateMinutes": 180,
          "phaseId": "inspect",
          "dependsOn": [
            "CLI-101"
          ],
          "scenario": "A patch to @fixture/parser requires updating the exact dependency in @fixture/runner. The plan currently includes only parser, leaving runner pinned to the old release.",
          "acceptanceCriteria": [
            "The plan includes transitive dependents whose declared ranges no longer accept the proposed version.",
            "Packages already accepting the new version are not bumped solely because they depend on it.",
            "Cycles are reported with a readable cycle path and no files are written."
          ],
          "implementationNotes": [
            "Declare supported workspace range syntax and reject unsupported protocols.",
            "Use a stable topological order with package-name tie breaking."
          ],
          "verification": [
            "Plan a chain with exact, compatible-range, and dev-only dependencies and compare expected inclusion.",
            "Feed a dependency cycle and a missing workspace target; both must fail before preparation."
          ],
          "deliverables": [
            "Dependency-aware planner and graph fixtures"
          ],
          "rollout": "Expose the graph as plan output before enabling its use in file preparation; rollback to read-only inspection.",
          "skills": [
            "Dependency graphs",
            "Semantic versioning",
            "Determinism"
          ],
          "fieldMix": [
            {
              "field": "Developer tooling",
              "percentage": 100
            }
          ],
          "patterns": []
        },
        {
          "id": "1d3a02d9-0bd2-43c2-9dad-4b96587584c8",
          "key": "CLI-104",
          "title": "Make a dirty checkout a deliberate release decision",
          "type": "BUG",
          "priority": "HIGH",
          "difficulty": "INTERMEDIATE",
          "estimateMinutes": 90,
          "phaseId": "prepare",
          "dependsOn": [
            "CLI-103"
          ],
          "scenario": "A teammate prepared a release with an uncommitted dependency change and could not reproduce the resulting versions. Capture the base revision and refuse preparation when tracked files differ.",
          "acceptanceCriteria": [
            "The plan records the full base commit and a digest of release inputs.",
            "Preparation rejects staged or unstaged tracked changes with a list of affected paths.",
            "A plan whose base commit or input digest changed is rejected even when the checkout is clean."
          ],
          "implementationNotes": [
            "Use Git argument arrays rather than composing shell commands.",
            "Document whether untracked files participate in the release input set."
          ],
          "verification": [
            "Prepare a clean fixture checkout successfully.",
            "Stage one manifest change and separately advance HEAD; the old plan must be rejected in each case."
          ],
          "deliverables": [
            "Stale-plan guard and reproducibility note"
          ],
          "rollout": "Enable guards before any write command; disable preparation if repository state cannot be determined.",
          "skills": [
            "Git",
            "Integrity checks",
            "Failure handling"
          ],
          "fieldMix": [
            {
              "field": "Developer tooling",
              "percentage": 100
            }
          ],
          "patterns": []
        },
        {
          "id": "7a43f421-d232-40a7-bd8d-7d4a1f016851",
          "key": "CLI-105",
          "title": "Turn change fragments into package-specific release notes",
          "type": "TASK",
          "priority": "MEDIUM",
          "difficulty": "INTERMEDIATE",
          "estimateMinutes": 105,
          "phaseId": "prepare",
          "dependsOn": [
            "CLI-103"
          ],
          "scenario": "The same release note is pasted into all six packages, even when only one changed. Read small checked-in change fragments and render notes grouped by affected package.",
          "acceptanceCriteria": [
            "Each fragment names existing packages and one supported change category.",
            "Rendering is deterministic and includes each fragment once per affected package.",
            "Unknown packages, duplicate fragment IDs, and empty descriptions block generation with file-level errors."
          ],
          "implementationNotes": [
            "Treat fragment text as plain Markdown content, never executable templates.",
            "Preserve issue references exactly as supplied."
          ],
          "verification": [
            "Render two overlapping fragments and check package-specific sections.",
            "Use duplicate IDs and an unknown package to verify the entire notes step fails without writing output."
          ],
          "deliverables": [
            "Fragment format, examples, and release-note renderer"
          ],
          "rollout": "Generate notes to a preview path initially; switching to committed notes requires the validated plan.",
          "skills": [
            "Parsing",
            "Documentation tooling",
            "Deterministic output"
          ],
          "fieldMix": [
            {
              "field": "Developer tooling",
              "percentage": 100
            }
          ],
          "patterns": []
        },
        {
          "id": "1965cf09-8e91-425e-9488-fef6d4e18e10",
          "key": "CLI-106",
          "title": "Prepare manifests and notes as one recoverable file operation",
          "type": "STORY",
          "priority": "HIGH",
          "difficulty": "ADVANCED",
          "estimateMinutes": 180,
          "phaseId": "prepare",
          "dependsOn": [
            "CLI-104",
            "CLI-105"
          ],
          "scenario": "An interrupted process updated two manifests but left the changelog untouched. Preparation needs a journal so the next invocation can identify exactly which planned writes completed.",
          "acceptanceCriteria": [
            "Validate every target and render every new file before replacing any repository file.",
            "A journal records expected before and after hashes for each target and completed replacements.",
            "Recovery restores only files still matching the recorded after hash and refuses to overwrite user edits."
          ],
          "implementationNotes": [
            "Keep staging and target files on the same filesystem.",
            "Resolve paths inside the selected repository and reject symlink escapes."
          ],
          "verification": [
            "Inject failure after the first replacement and recover the original bytes.",
            "Edit a prepared file before recovery and confirm a conflict is reported while the edit is preserved."
          ],
          "deliverables": [
            "Preparation journal, recovery command, and failure-injection fixtures"
          ],
          "rollout": "Enable writes only after preview and recovery pass locally; use the journal to undo an interrupted preparation.",
          "skills": [
            "Filesystem transactions",
            "Recovery",
            "Concurrency safety"
          ],
          "fieldMix": [
            {
              "field": "Developer tooling",
              "percentage": 60
            },
            {
              "field": "Storage systems",
              "percentage": 40
            }
          ],
          "patterns": []
        },
        {
          "id": "cb2a1729-8d0d-48bb-bf48-bbf64d42b61c",
          "key": "CLI-107",
          "title": "Prevent a second release process from using the same checkout",
          "type": "BUG",
          "priority": "HIGH",
          "difficulty": "ADVANCED",
          "estimateMinutes": 120,
          "phaseId": "recover",
          "dependsOn": [
            "CLI-106"
          ],
          "scenario": "Two terminals started preparation within a second and both used the same temporary filenames. Add an exclusive lease for mutation commands with inspectable ownership.",
          "acceptanceCriteria": [
            "Exactly one of two concurrent preparation commands obtains the repository lease.",
            "The loser exits before replacing a file and reports the existing operation ID.",
            "Stale-lease recovery is an explicit command that verifies the recorded operation is no longer active."
          ],
          "implementationNotes": [
            "Do not decide lease ownership from a PID alone; include an operation token.",
            "Read-only commands remain usable while a lease exists."
          ],
          "verification": [
            "Start two local fixture processes behind a barrier and count successful mutations.",
            "Simulate a stale lease and verify ordinary preparation refuses it until explicit recovery."
          ],
          "deliverables": [
            "Lease implementation and concurrent-process test"
          ],
          "rollout": "Require leases for all mutation commands together; rollback by disabling mutations until both versions agree on the lease format.",
          "skills": [
            "Process coordination",
            "Race conditions",
            "Operational tooling"
          ],
          "fieldMix": [
            {
              "field": "Developer tooling",
              "percentage": 100
            }
          ],
          "patterns": []
        },
        {
          "id": "1cebb310-4a4b-48dd-b4c6-84d4b048984d",
          "key": "CLI-108",
          "title": "Resume a publish rehearsal after the registry response disappears",
          "type": "STORY",
          "priority": "HIGH",
          "difficulty": "EXPERT",
          "estimateMinutes": 240,
          "phaseId": "recover",
          "dependsOn": [
            "CLI-106",
            "CLI-107"
          ],
          "scenario": "The fake registry accepts a package and then drops the connection. A blind retry may conceal a different artifact already registered at that version. Reconcile remote state before resuming.",
          "acceptanceCriteria": [
            "Each planned package records its version and artifact digest before the fake publish call.",
            "An existing version with the same digest is treated as completed; a different digest blocks the entire resume.",
            "Resume respects dependency order and leaves a durable record of ambiguous, reconciled, and completed steps."
          ],
          "implementationNotes": [
            "Use a local registry port with deterministic lost-response behavior.",
            "A release record is append-only; do not overwrite the original failed attempt."
          ],
          "verification": [
            "Drop the first response after acceptance and verify resume makes no duplicate upload.",
            "Preload the same version with different bytes and confirm dependents remain unpublished."
          ],
          "deliverables": [
            "Resumable rehearsal workflow and ambiguity incident walkthrough"
          ],
          "rollout": "Keep the registry adapter local for this exercise; require a reviewed digest reconciliation policy before a real adapter.",
          "skills": [
            "Idempotency",
            "Distributed failure",
            "Artifact integrity",
            "State machines"
          ],
          "fieldMix": [
            {
              "field": "Developer tooling",
              "percentage": 50
            },
            {
              "field": "Distributed systems",
              "percentage": 30
            },
            {
              "field": "Integrations",
              "percentage": 20
            }
          ],
          "patterns": []
        },
        {
          "id": "3927f2dc-12c2-42af-a2cc-d46c32d24a7d",
          "key": "CLI-109",
          "title": "Keep release credentials and package contents out of logs",
          "type": "CHORE",
          "priority": "HIGH",
          "difficulty": "INTERMEDIATE",
          "estimateMinutes": 90,
          "phaseId": "recover",
          "dependsOn": [
            "CLI-102",
            "CLI-108"
          ],
          "scenario": "A registry error included an authorization header in a debug dump. Add structured diagnostics with an allowlist of safe release fields and a useful correlation ID.",
          "acceptanceCriteria": [
            "Diagnostics include operation ID, package name, step, duration, and error category.",
            "Headers, environment variables, artifact contents, and token-like fixture values are absent from all log levels.",
            "Human and JSON errors reference the same operation ID."
          ],
          "implementationNotes": [
            "Map provider failures to safe errors at the adapter boundary.",
            "Do not rely only on replacing known secret strings."
          ],
          "verification": [
            "Cause a fake provider error containing a token and scan stdout, stderr, and persisted diagnostics.",
            "Confirm a safe package conflict still carries enough information to locate the failed step."
          ],
          "deliverables": [
            "Safe error mapper and redaction regression cases"
          ],
          "rollout": "Make safe diagnostics the default; temporarily reduce diagnostic detail if an unknown provider error cannot be classified.",
          "skills": [
            "Structured logging",
            "Secret handling",
            "Error design"
          ],
          "fieldMix": [
            {
              "field": "Developer tooling",
              "percentage": 50
            },
            {
              "field": "Security",
              "percentage": 50
            }
          ],
          "patterns": []
        },
        {
          "id": "74ad2f26-7a4e-41c6-8121-4764c5c7b77b",
          "key": "CLI-110",
          "title": "Package the CLI so a fresh checkout can rehearse a release offline",
          "type": "TASK",
          "priority": "MEDIUM",
          "difficulty": "INTERMEDIATE",
          "estimateMinutes": 120,
          "phaseId": "recover",
          "dependsOn": [
            "CLI-108",
            "CLI-109"
          ],
          "scenario": "The maintainer can run the tool only through a source-tree import. Package the command and document one complete rehearsal using fixture packages and the local registry.",
          "acceptanceCriteria": [
            "The built executable supports --help and --version without source imports.",
            "An offline rehearsal covers inspect, plan, prepare, interrupted publish, and resume.",
            "The guide explains which steps mutate files and how to restore the fixture repository."
          ],
          "implementationNotes": [
            "Pin fixture inputs so example output is reproducible.",
            "Do not perform an actual registry publication."
          ],
          "verification": [
            "Install the packed artifact into a temporary directory and run the documented rehearsal.",
            "Run without a registry configuration and confirm publishing fails before any network attempt."
          ],
          "deliverables": [
            "Packed CLI artifact instructions and end-to-end rehearsal guide"
          ],
          "rollout": "Distribute a prerelease artifact for local evaluation; retract it if packed-command behavior differs from source execution.",
          "skills": [
            "Packaging",
            "Developer experience",
            "Release engineering"
          ],
          "fieldMix": [
            {
              "field": "Developer tooling",
              "percentage": 100
            }
          ],
          "patterns": []
        }
      ]
    }
  ]
}
