{
  "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": "0909ba43-5033-42cd-85a6-86a00937c69d",
      "key": "PMIGRATE",
      "title": "Replace an account service one tenant at a time",
      "field": "System design",
      "summary": "Evolve a long-lived account module while preserving tenant boundaries, client contracts, and a credible route back from partial migration.",
      "context": "A fictional B2B scheduling service stores account settings in a legacy module whose database access leaks into HTTP handlers. A replacement must support existing clients and migration by tenant. Build a local modular application, a synthetic two-tenant dataset, and controllable old/new adapters; no baseline repository or fixtures are supplied. Keep the exercise in one application and local database, with no live customer traffic.",
      "stack": [
        "TypeScript",
        "Node.js",
        "PostgreSQL",
        "Vitest"
      ],
      "prerequisites": [
        "REST contracts",
        "Tenant authorization",
        "Transactions",
        "Dependency injection"
      ],
      "developerValue": "Practice incremental migration, dependency boundaries, compatibility testing, and removing abstractions that obscure behavior rather than enabling change.",
      "companyValue": "Inspect a migration plan with measurable parity, explicit write ownership, tenant-safe routing, and rollback limits instead of accepting a rewrite diagram alone.",
      "delivery": "Ten tickets in three migration phases. An individual ticket needs a minimal local reproduction of its legacy behavior; the full project ends with a rehearsed synthetic tenant cutover and retirement checklist.",
      "phases": [
        {
          "id": "boundary",
          "title": "Establish a stable boundary",
          "goal": "Capture old behavior and remove hidden tenant state before routing changes."
        },
        {
          "id": "transition",
          "title": "Compare and route deliberately",
          "goal": "Introduce the replacement without duplicate effects or unexamined abstractions."
        },
        {
          "id": "retire",
          "title": "Cut over and retire",
          "goal": "Prove write ownership, compatibility, and recovery before removing legacy paths."
        }
      ],
      "tickets": [
        {
          "id": "a01f0881-6ef8-42ec-877b-5b9d389b551f",
          "key": "PMIGRATE-101",
          "title": "Put legacy account lookups behind a contract the replacement can keep",
          "type": "TASK",
          "priority": "HIGH",
          "difficulty": "FOUNDATIONAL",
          "estimateMinutes": 90,
          "phaseId": "boundary",
          "dependsOn": [],
          "scenario": "Three HTTP handlers each translate a legacy account row differently. One returns an absent timezone as null, another inserts UTC, and a third exposes an internal migration flag.",
          "acceptanceCriteria": [
            "Create a narrow account-read facade with explicit tenant and account identifiers and one documented public response shape.",
            "Capture the intended null, not-found, and permission behavior before routing the three handlers through it.",
            "Keep legacy storage columns and migration flags out of the public response while preserving required client fields."
          ],
          "implementationNotes": [
            "Use the facade to bound a specific compatibility surface; do not add a generic wrapper around every repository method."
          ],
          "verification": [
            "Exercise all three handlers against synthetic missing, configured, and null-timezone accounts and compare their response contracts.",
            "Request another tenant's account and assert denial with no internal migration metadata in the response."
          ],
          "deliverables": [
            "Account-read facade and legacy response characterization cases"
          ],
          "rollout": "Move one local handler at a time through the facade and compare response snapshots; revert a handler without changing stored account data.",
          "skills": [
            "Compatibility",
            "API boundaries",
            "Characterization testing"
          ],
          "fieldMix": [
            {
              "field": "API design",
              "percentage": 50
            },
            {
              "field": "System design",
              "percentage": 30
            },
            {
              "field": "Backend",
              "percentage": 20
            }
          ],
          "patterns": [
            {
              "pattern": "facade",
              "activity": "APPLY",
              "focus": "Give callers one stable account-read contract while containing legacy row translation and keeping the boundary deliberately narrow."
            }
          ]
        },
        {
          "id": "9481cd3b-715d-4254-8f42-da4085c39081",
          "key": "PMIGRATE-102",
          "title": "Remove the process-wide current-tenant account client",
          "type": "BUG",
          "priority": "URGENT",
          "difficulty": "ADVANCED",
          "estimateMinutes": 210,
          "phaseId": "boundary",
          "dependsOn": [
            "PMIGRATE-101"
          ],
          "scenario": "The legacy account client is a singleton with a mutable currentTenant field. Two overlapping requests can overwrite that field between authorization and the database query, selecting the wrong tenant's settings.",
          "acceptanceCriteria": [
            "Remove mutable request or tenant context from the process-wide client and pass authorized scope explicitly into the service/repository boundary.",
            "Every account query constrains both tenant and account identity, including background lookups and the not-found path.",
            "Connection pooling may remain shared, but tests and request handlers cannot alter another operation's tenant context."
          ],
          "implementationNotes": [
            "Distinguish safe shared infrastructure lifetime from unsafe shared request state; replacing the singleton with a different global container is insufficient."
          ],
          "verification": [
            "Interleave two tenant requests with barriers at authorization and lookup; assert each receives only its own settings.",
            "Omit tenant scope and use a cross-tenant account identifier in direct service calls; verify rejection before data is returned."
          ],
          "deliverables": [
            "Explicit-scope account access change and deterministic overlap reproduction"
          ],
          "rollout": "Block further migration until the scope checks pass; revert optional routing changes if needed while retaining the tenant-isolation fix.",
          "skills": [
            "Tenant isolation",
            "Concurrency",
            "Dependency lifetimes"
          ],
          "fieldMix": [
            {
              "field": "Security",
              "percentage": 50
            },
            {
              "field": "Backend",
              "percentage": 30
            },
            {
              "field": "System design",
              "percentage": 20
            }
          ],
          "patterns": [
            {
              "pattern": "singleton",
              "activity": "REMOVE",
              "focus": "Remove singleton-held tenant state while preserving safe shared connection infrastructure, using an interleaved request failure to justify the lifetime change."
            }
          ]
        },
        {
          "id": "114b45f9-e50b-4aba-872c-471bc60bd1ca",
          "key": "PMIGRATE-103",
          "title": "Separate account policy from legacy SQL and replacement storage",
          "type": "STORY",
          "priority": "HIGH",
          "difficulty": "INTERMEDIATE",
          "estimateMinutes": 180,
          "phaseId": "boundary",
          "dependsOn": [
            "PMIGRATE-102"
          ],
          "scenario": "The rule that a suspended account cannot enable a new booking channel lives inside a legacy SQL helper. The replacement adapter would bypass that rule if handlers called it directly.",
          "acceptanceCriteria": [
            "Place the account policy in an application operation depending on explicit read/write ports instead of concrete database helpers.",
            "Run the same operation against old and new storage adapters with identical authorization and suspended-account behavior.",
            "Keep transaction and expected-revision requirements explicit in the port contract; adapters cannot report success after a failed commit."
          ],
          "implementationNotes": [
            "Introduce ports for the needed use case only; do not create a universal repository abstraction or change the application into microservices."
          ],
          "verification": [
            "Run a shared contract suite for both adapters over active, suspended, and missing accounts.",
            "Inject a stale revision and commit failure in each adapter and verify no enabled channel or success response is produced."
          ],
          "deliverables": [
            "Account operation, two local adapters, and shared behavior contract"
          ],
          "rollout": "Keep the legacy adapter selected while introducing the boundary; enable the replacement only after parity cases pass.",
          "skills": [
            "Dependency inversion",
            "Domain policy",
            "Transaction contracts"
          ],
          "fieldMix": [
            {
              "field": "System design",
              "percentage": 50
            },
            {
              "field": "Backend",
              "percentage": 30
            },
            {
              "field": "Database engineering",
              "percentage": 20
            }
          ],
          "patterns": [
            {
              "pattern": "ports-and-adapters",
              "activity": "REFACTOR",
              "focus": "Move account policy above concrete storage and give both adapters the same explicit authorization, revision, and transaction obligations."
            }
          ]
        },
        {
          "id": "c3f3b65f-2f31-4003-a67c-fb108636f1d0",
          "key": "PMIGRATE-104",
          "title": "Shadow account reads without duplicating booking-channel writes",
          "type": "TASK",
          "priority": "HIGH",
          "difficulty": "ADVANCED",
          "estimateMinutes": 210,
          "phaseId": "transition",
          "dependsOn": [
            "PMIGRATE-103"
          ],
          "scenario": "The migration proposal mirrors every request to the replacement and compares responses. Some apparent reads update lastSeenAt, and write mirroring would enable a booking channel twice through different storage paths.",
          "acceptanceCriteria": [
            "Define an allowlist of side-effect-free reads that may run against both implementations for synthetic tenant comparison.",
            "Return the active implementation's response without letting shadow timeouts or failures change client behavior.",
            "Record bounded field-level parity differences without account content, and route every command to exactly one active implementation."
          ],
          "implementationNotes": [
            "Use the migration boundary to incrementally replace routes; do not call a mutating operation just because its HTTP verb is GET."
          ],
          "verification": [
            "Inject a replacement timeout and mismatched timezone; verify the active result remains correct and a bounded mismatch is recorded.",
            "Run an enable-channel command and a last-seen update; assert one write owner and zero shadow side effects."
          ],
          "deliverables": [
            "Safe shadow-read routing, mismatch report, and side-effect inventory"
          ],
          "rollout": "Enable shadow reads for one synthetic tenant with an independent off switch; disable comparison without changing command ownership.",
          "skills": [
            "Incremental migration",
            "Side-effect analysis",
            "Observability"
          ],
          "fieldMix": [
            {
              "field": "System design",
              "percentage": 50
            },
            {
              "field": "Backend",
              "percentage": 30
            },
            {
              "field": "Site reliability",
              "percentage": 20
            }
          ],
          "patterns": [
            {
              "pattern": "strangler-fig",
              "activity": "APPLY",
              "focus": "Replace a bounded read surface gradually while keeping command ownership singular and making shadow failures independent of served responses."
            }
          ]
        },
        {
          "id": "49f73a1b-189e-40b2-b4af-f42b73633f8c",
          "key": "PMIGRATE-105",
          "title": "Preserve tenant scope and conditional reads through the migration proxy",
          "type": "BUG",
          "priority": "HIGH",
          "difficulty": "INTERMEDIATE",
          "estimateMinutes": 150,
          "phaseId": "transition",
          "dependsOn": [
            "PMIGRATE-104"
          ],
          "scenario": "A local migration proxy forwards the account identifier but drops the authorized tenant context and If-None-Match value. The new path both loses cache semantics and trusts a tenant header supplied by the caller.",
          "acceptanceCriteria": [
            "Forward server-derived tenant scope and conditional-read metadata through a typed proxy boundary without trusting caller-supplied scope.",
            "Preserve documented ETag, not-modified, not-found, and error behavior for both active implementations.",
            "Reject missing authorized scope before forwarding and keep proxy diagnostics free of credentials and full account bodies."
          ],
          "implementationNotes": [
            "The proxy controls access and delegation; keep storage mapping in adapters rather than accumulating business rules in the proxy."
          ],
          "verification": [
            "Send matching and stale ETags through old and new routes and compare their public conditional responses.",
            "Spoof a tenant header, omit authorized context, and force an adapter error; assert denial and sanitized error output."
          ],
          "deliverables": [
            "Proxy context contract and conditional-read/tenant regression cases"
          ],
          "rollout": "Exercise the proxy with local synthetic clients before enabling tenant routing; route back through the corrected legacy boundary on failure.",
          "skills": [
            "Delegation boundaries",
            "HTTP semantics",
            "Authorization"
          ],
          "fieldMix": [
            {
              "field": "API design",
              "percentage": 40
            },
            {
              "field": "Security",
              "percentage": 40
            },
            {
              "field": "System design",
              "percentage": 20
            }
          ],
          "patterns": [
            {
              "pattern": "proxy",
              "activity": "REFACTOR",
              "focus": "Keep access control and delegation transparent to the account contract while ensuring proxy forwarding cannot weaken tenant or cache semantics."
            }
          ]
        },
        {
          "id": "08c74343-ebf8-4714-b4ff-dc6bf42ee583",
          "key": "PMIGRATE-106",
          "title": "Decide whether a separate account summary read model earns its lag",
          "type": "TASK",
          "priority": "MEDIUM",
          "difficulty": "EXPERT",
          "estimateMinutes": 300,
          "phaseId": "transition",
          "dependsOn": [
            "PMIGRATE-103",
            "PMIGRATE-104"
          ],
          "scenario": "The account summary joins five tables and is the slowest synthetic endpoint. A CQRS proposal introduces a projection, but support must see a just-disabled booking channel immediately after issuing the command.",
          "acceptanceCriteria": [
            "Compare an indexed transactional query with a separate projection using a declared synthetic dataset and equivalent authorization boundaries.",
            "For the projection option, expose freshness/version semantics and define a read-after-write path that cannot show a disabled channel as enabled after an acknowledged command.",
            "Document latency, write cost, rebuild behavior, and operational complexity; implement the selected option and justify rejecting the other."
          ],
          "implementationNotes": [
            "CQRS does not require separate services or event sourcing here; evaluate command/query separation within the existing local application."
          ],
          "verification": [
            "Measure both options with identical account counts and query mix, reporting warmup and repeated-run variability.",
            "Pause projection updates, issue a disable command, and exercise the declared freshness strategy; test an interrupted rebuild without cross-tenant reads."
          ],
          "deliverables": [
            "Read-model comparison, selected implementation, and freshness/rebuild contract"
          ],
          "rollout": "Canary the selected read path for one synthetic tenant; retain the transactional path until freshness and rebuild failure checks pass.",
          "skills": [
            "Read-model design",
            "Consistency",
            "Performance analysis",
            "Tradeoff analysis"
          ],
          "fieldMix": [
            {
              "field": "System design",
              "percentage": 40
            },
            {
              "field": "Database engineering",
              "percentage": 30
            },
            {
              "field": "Performance engineering",
              "percentage": 30
            }
          ],
          "patterns": [
            {
              "pattern": "cqrs",
              "activity": "COMPARE",
              "focus": "Compare command/query separation with an indexed query using freshness, rebuild, and write-cost requirements rather than assuming a projection is necessary."
            }
          ]
        },
        {
          "id": "63ede710-2e17-4fef-b54d-334b6c0a8e31",
          "key": "PMIGRATE-107",
          "title": "Delete account facade layers that only rename the same call",
          "type": "CHORE",
          "priority": "LOW",
          "difficulty": "FOUNDATIONAL",
          "estimateMinutes": 90,
          "phaseId": "transition",
          "dependsOn": [
            "PMIGRATE-101",
            "PMIGRATE-103"
          ],
          "scenario": "A timezone field now crosses AccountFacade, AccountGatewayFacade, AccountServiceFacade, and AccountAccessFacade. Three wrappers have one consumer, add no behavior, and make a one-field change touch twelve files.",
          "acceptanceCriteria": [
            "Trace the timezone read and identify which boundary owns compatibility, policy, authorization, and persistence responsibilities.",
            "Remove pass-through facades that add no independent responsibility while retaining the public compatibility boundary and storage port.",
            "The timezone response, authorization behavior, and adapter substitution remain unchanged with fewer forwarding sites to maintain."
          ],
          "implementationNotes": [
            "Do not replace deleted facades with a dynamic service locator or merge authorization checks into controllers only."
          ],
          "verification": [
            "Run the same response and adapter-substitution cases before and after the simplification.",
            "Exercise cross-tenant denial and a storage failure through the simplified path; verify neither is swallowed by forwarding code."
          ],
          "deliverables": [
            "Focused simplification patch and a before/after responsibility map"
          ],
          "rollout": "Land the forwarding cleanup separately from routing changes so a regression can be traced and reverted without changing migration state.",
          "skills": [
            "Refactoring",
            "Responsibility analysis",
            "Maintainability"
          ],
          "fieldMix": [
            {
              "field": "System design",
              "percentage": 60
            },
            {
              "field": "Backend",
              "percentage": 40
            }
          ],
          "patterns": [
            {
              "pattern": "facade",
              "activity": "REMOVE",
              "focus": "Remove redundant facade layers with no compatibility or policy responsibility while retaining the one boundary that protects callers from the legacy model."
            }
          ]
        },
        {
          "id": "cadaa88f-1e22-4b30-91d3-9d285e73e3ee",
          "key": "PMIGRATE-108",
          "title": "Transfer tenant write ownership without accepting commands on both sides",
          "type": "STORY",
          "priority": "HIGH",
          "difficulty": "EXPERT",
          "estimateMinutes": 330,
          "phaseId": "retire",
          "dependsOn": [
            "PMIGRATE-105",
            "PMIGRATE-106"
          ],
          "scenario": "Two local application instances cache the tenant migration flag at different times. During cutover, one writes the legacy table while another writes the replacement, leaving two conflicting account revisions.",
          "acceptanceCriteria": [
            "Represent write ownership with a durable tenant migration revision and reject commands using a stale ownership revision at the write boundary.",
            "Backfill replacement data and reconcile it through the final legacy revision under the ownership fence; do not open the new writer while any committed legacy change remains unapplied.",
            "Define a cutover sequence that drains or rejects in-flight old-owner commands before the new owner accepts writes.",
            "Document and rehearse how rollback handles writes already accepted by the new owner; switching a read flag alone cannot declare rollback complete."
          ],
          "implementationNotes": [
            "Keep the exercise in one local database and explicit transactions; do not claim cross-database atomicity or solve stale ownership with cache TTL alone."
          ],
          "verification": [
            "Copy tenant data, commit a later legacy write, then interleave commands from two instances around cutover; assert the new owner includes that write and a single accepted ownership lineage loses no successful writes.",
            "Crash after ownership transfer and attempt rollback after a new-side write; verify the recovery procedure detects and reconciles that write before reopening old ownership."
          ],
          "deliverables": [
            "Tenant cutover command, stale-owner rejection checks, and write-aware rollback drill"
          ],
          "rollout": "Rehearse with one synthetic tenant and a paused writer; expand only after cutover and rollback counts reconcile.",
          "skills": [
            "Migration fencing",
            "Concurrency",
            "Transactional state",
            "Recovery planning"
          ],
          "fieldMix": [
            {
              "field": "System design",
              "percentage": 40
            },
            {
              "field": "Distributed systems",
              "percentage": 40
            },
            {
              "field": "Database engineering",
              "percentage": 20
            }
          ],
          "patterns": [
            {
              "pattern": "strangler-fig",
              "activity": "APPLY",
              "focus": "Make incremental replacement include durable write ownership and a data-aware rollback boundary, rather than treating tenant routing as a cosmetic flag."
            }
          ]
        },
        {
          "id": "3a2a767b-6d6d-46a0-a261-e6d7f01c5c2c",
          "key": "PMIGRATE-109",
          "title": "Catch replacement-adapter drift before declaring tenant parity",
          "type": "TASK",
          "priority": "HIGH",
          "difficulty": "INTERMEDIATE",
          "estimateMinutes": 180,
          "phaseId": "retire",
          "dependsOn": [
            "PMIGRATE-103",
            "PMIGRATE-105",
            "PMIGRATE-107"
          ],
          "scenario": "Both adapters pass the happy-path tests, but the replacement sorts equal-name accounts differently and rounds stored revision values when decoding a database result. Parity dashboards currently compare only HTTP status codes.",
          "acceptanceCriteria": [
            "Extend the shared port contract to stable sort tie-breakers, null handling, exact revisions, and documented domain error mapping.",
            "Run a fixed synthetic corpus against each adapter and compare normalized semantic results rather than timestamps or implementation-only columns.",
            "A mismatch report identifies the contract case and differing public fields without dumping tenant data or silently accepting expected failures."
          ],
          "implementationNotes": [
            "Keep adapter-specific SQL assertions separate from the shared behavior contract so the suite does not require identical internal implementations."
          ],
          "verification": [
            "Use equal-name accounts, null settings, and large valid revision values to verify exact contract parity.",
            "Inject a deliberate order reversal and stale-revision acceptance into one local adapter; confirm the comparison fails with an actionable case identifier."
          ],
          "deliverables": [
            "Expanded adapter contract suite and sanitized parity report"
          ],
          "rollout": "Require a clean contract report before moving the next synthetic tenant; keep mismatched tenants on their current owner until the discrepancy is resolved.",
          "skills": [
            "Contract testing",
            "Data fidelity",
            "Regression diagnosis"
          ],
          "fieldMix": [
            {
              "field": "Quality engineering",
              "percentage": 50
            },
            {
              "field": "System design",
              "percentage": 30
            },
            {
              "field": "Database engineering",
              "percentage": 20
            }
          ],
          "patterns": [
            {
              "pattern": "ports-and-adapters",
              "activity": "APPLY",
              "focus": "Use the shared port as a behavioral contract for interchangeable adapters, testing semantic parity without binding the contract to either storage implementation."
            }
          ]
        },
        {
          "id": "a1cb85cf-cd9f-4008-bb8a-8181ba0d94ba",
          "key": "PMIGRATE-110",
          "title": "Retire the legacy account path only after the last caller is accounted for",
          "type": "CHORE",
          "priority": "MEDIUM",
          "difficulty": "ADVANCED",
          "estimateMinutes": 210,
          "phaseId": "retire",
          "dependsOn": [
            "PMIGRATE-108",
            "PMIGRATE-109"
          ],
          "scenario": "All interactive tenants use the replacement, but a weekly synthetic export still imports the legacy repository directly. Deleting the old table based on request traffic would break that job and erase the only rollback copy.",
          "acceptanceCriteria": [
            "Inventory HTTP, scheduled, and direct module callers and migrate remaining accesses through the supported contract.",
            "Define observable retirement criteria including zero old-owner tenants, a complete job cycle, reconciled data, and an explicit rollback-retention decision.",
            "Separate code-path removal from any destructive schema change and provide a rehearsed restore path for the retained synthetic snapshot."
          ],
          "implementationNotes": [
            "Remove obsolete migration facades and proxy branches once their responsibilities end; keep the public account contract independent of temporary migration machinery."
          ],
          "verification": [
            "Run the weekly export and interactive contract suite with legacy routing disabled; assert no code path queries the retired repository.",
            "Leave one synthetic old-owner tenant or omit a scheduled caller and confirm retirement validation blocks removal; rehearse restoring the retained data snapshot."
          ],
          "deliverables": [
            "Caller inventory, retirement checks, cleanup patch, and synthetic restore report"
          ],
          "rollout": "Disable legacy routing, observe one full synthetic job cycle, then remove unused code; schedule schema deletion separately after the retention decision.",
          "skills": [
            "Dependency analysis",
            "Migration completion",
            "Operational handoff"
          ],
          "fieldMix": [
            {
              "field": "System design",
              "percentage": 50
            },
            {
              "field": "Site reliability",
              "percentage": 30
            },
            {
              "field": "Database engineering",
              "percentage": 20
            }
          ],
          "patterns": [
            {
              "pattern": "strangler-fig",
              "activity": "APPLY",
              "focus": "Complete the replacement by accounting for background callers and rollback data, with explicit criteria for retiring the old implementation."
            },
            {
              "pattern": "proxy",
              "activity": "REMOVE",
              "focus": "Remove migration-only routing branches after the transition ends so temporary delegation machinery does not become a permanent maintenance layer."
            }
          ]
        }
      ]
    }
  ]
}
