{
  "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": "95589e41-9d4d-454a-be77-5bb342933b1a",
      "key": "ADBT",
      "title": "Make a subscription analytics mart reproducible",
      "field": "Data engineering",
      "summary": "Model subscription movement with explicit grains, revisions and data contracts.",
      "context": "A fictional SaaS analyst reports expansion revenue differently from finance because snapshots, refunds and contract changes are joined at incompatible grains.",
      "stack": [
        "SQL",
        "PostgreSQL",
        "dbt"
      ],
      "prerequisites": [
        "Create a synthetic source schema and local transformation project.",
        "Use integer minor units and distinct reporting currencies."
      ],
      "developerValue": "Practice analytical modeling and explainable transformation contracts.",
      "companyValue": "Review trustworthy reporting definitions and the cost of correcting historical reports.",
      "delivery": "Ten scoped tickets across three phases. Build a synthetic local service or select a ticket after recreating its prerequisites; estimates exclude setup.",
      "phases": [
        {
          "id": "grain",
          "title": "Define reporting grain",
          "goal": "Specify source and metric contracts."
        },
        {
          "id": "model",
          "title": "Transform consistently",
          "goal": "Handle temporal joins and incremental updates."
        },
        {
          "id": "publish",
          "title": "Publish reliable outputs",
          "goal": "Validate releases and retain reproducible reports."
        }
      ],
      "tickets": [
        {
          "id": "013961bd-b99a-4f3d-bfa2-33a6e7cdf4a7",
          "key": "ADBT-101",
          "title": "Declare the subscription-movement grain before joining invoice lines",
          "type": "TASK",
          "priority": "MEDIUM",
          "difficulty": "FOUNDATIONAL",
          "estimateMinutes": 90,
          "phaseId": "grain",
          "dependsOn": [],
          "scenario": "A report doubles subscription movement when a contract has two invoice lines in the same month.",
          "acceptanceCriteria": [
            "Document one row per subscription, period and currency.",
            "Identify source keys and permitted multiplicity.",
            "Reject duplicate grain keys in a contract check."
          ],
          "implementationNotes": [
            "Create a small synthetic multi-line invoice example."
          ],
          "verification": [
            "Reconcile a two-line invoice to one movement row.",
            "Insert duplicate source identity and fail the grain check."
          ],
          "deliverables": [
            "Grain specification and executable uniqueness check"
          ],
          "rollout": "Review the grain contract before enabling downstream joins.",
          "skills": [
            "Dimensional modeling",
            "SQL"
          ],
          "fieldMix": [
            {
              "field": "Data engineering",
              "percentage": 70
            },
            {
              "field": "Database engineering",
              "percentage": 30
            }
          ],
          "patterns": []
        },
        {
          "id": "2865613f-3f76-4cf8-8d87-0f39a76e326b",
          "key": "ADBT-102",
          "title": "Separate recurring contract value from collected cash",
          "type": "STORY",
          "priority": "MEDIUM",
          "difficulty": "INTERMEDIATE",
          "estimateMinutes": 150,
          "phaseId": "grain",
          "dependsOn": [
            "ADBT-101"
          ],
          "scenario": "A late payment makes the recurring-revenue chart dip even though no subscription changed.",
          "acceptanceCriteria": [
            "Define contract value and cash collection as separate measures.",
            "Document refund and unpaid-invoice treatment.",
            "Keep currency amounts separate without implicit conversion."
          ],
          "implementationNotes": [
            "Use named business definitions in model metadata."
          ],
          "verification": [
            "Delay a payment and keep contracted recurring value unchanged.",
            "Mix currencies and reject an unsupported combined total."
          ],
          "deliverables": [
            "Metric definitions and contrasting examples"
          ],
          "rollout": "Publish separate metric names; retire ambiguous aliases after consumer review.",
          "skills": [
            "Metric design",
            "Data semantics"
          ],
          "fieldMix": [
            {
              "field": "Data engineering",
              "percentage": 100
            }
          ],
          "patterns": []
        },
        {
          "id": "eba6f358-5964-4f77-aa0b-1cd401b174bf",
          "key": "ADBT-103",
          "title": "Reject source schema drift before materializing the mart",
          "type": "CHORE",
          "priority": "HIGH",
          "difficulty": "FOUNDATIONAL",
          "estimateMinutes": 90,
          "phaseId": "grain",
          "dependsOn": [
            "ADBT-101"
          ],
          "scenario": "A partner renamed subscription_id and the daily transformation published an empty table successfully.",
          "acceptanceCriteria": [
            "Validate required columns and accepted types.",
            "Fail before replacing the active reporting relation.",
            "Report the missing contract field and source version."
          ],
          "implementationNotes": [
            "Avoid relying on a row-count check alone."
          ],
          "verification": [
            "Transform a valid empty source under its declared contract.",
            "Rename a required column and retain the previous active mart."
          ],
          "deliverables": [
            "Source contract gate"
          ],
          "rollout": "Run the contract gate before scheduled builds; keep prior output on failure.",
          "skills": [
            "Data contracts",
            "Schema evolution"
          ],
          "fieldMix": [
            {
              "field": "Data engineering",
              "percentage": 70
            },
            {
              "field": "Quality engineering",
              "percentage": 30
            }
          ],
          "patterns": []
        },
        {
          "id": "bdbaa9d0-ed51-494f-aca8-95b33de1a1e9",
          "key": "ADBT-104",
          "title": "Join customer segments as of the revenue event date",
          "type": "BUG",
          "priority": "MEDIUM",
          "difficulty": "ADVANCED",
          "estimateMinutes": 210,
          "phaseId": "model",
          "dependsOn": [
            "ADBT-101",
            "ADBT-102"
          ],
          "scenario": "Historical enterprise revenue changes whenever sales updates a customer's current segment.",
          "acceptanceCriteria": [
            "Use valid-time segment intervals for the event date.",
            "Detect overlapping or missing segment intervals explicitly.",
            "Preserve the event's original reporting currency."
          ],
          "implementationNotes": [
            "Do not fill missing historical segments with the current value."
          ],
          "verification": [
            "Change today's segment and keep prior periods unchanged.",
            "Create overlapping segment periods and fail the temporal join check."
          ],
          "deliverables": [
            "As-of join model and interval assertions"
          ],
          "rollout": "Build a comparison table; switch readers after historical differences are reviewed.",
          "skills": [
            "Temporal joins",
            "Slowly changing dimensions"
          ],
          "fieldMix": [
            {
              "field": "Data engineering",
              "percentage": 70
            },
            {
              "field": "Database engineering",
              "percentage": 30
            }
          ],
          "patterns": []
        },
        {
          "id": "bea3352f-a9dc-4d3e-b915-e1620ea4ae57",
          "key": "ADBT-105",
          "title": "Make incremental movement loads include revised source rows",
          "type": "STORY",
          "priority": "MEDIUM",
          "difficulty": "ADVANCED",
          "estimateMinutes": 240,
          "phaseId": "model",
          "dependsOn": [
            "ADBT-103",
            "ADBT-104"
          ],
          "scenario": "The incremental model filters only creation time, so a corrected subscription end date never reaches the mart.",
          "acceptanceCriteria": [
            "Track source revision or updated watermark with tie breaking.",
            "Recompute affected grain keys deterministically.",
            "Commit the output and checkpoint consistently."
          ],
          "implementationNotes": [
            "Document how deletions and corrections identify affected periods."
          ],
          "verification": [
            "Correct a prior end date and update the affected month.",
            "Retry after an interrupted run and avoid duplicate movement rows."
          ],
          "deliverables": [
            "Revision-aware incremental model"
          ],
          "rollout": "Shadow full and incremental builds on a synthetic corpus; fall back to full rebuild if they diverge.",
          "skills": [
            "Incremental processing",
            "Idempotency"
          ],
          "fieldMix": [
            {
              "field": "Data engineering",
              "percentage": 70
            },
            {
              "field": "Database engineering",
              "percentage": 30
            }
          ],
          "patterns": []
        },
        {
          "id": "eeacfd9e-d873-4af7-a9d6-cb76876f64d6",
          "key": "ADBT-106",
          "title": "Represent cancelled subscriptions as movements instead of deleting them",
          "type": "TASK",
          "priority": "MEDIUM",
          "difficulty": "INTERMEDIATE",
          "estimateMinutes": 150,
          "phaseId": "model",
          "dependsOn": [
            "ADBT-102",
            "ADBT-105"
          ],
          "scenario": "Deleting a cancelled subscription from the source erases the churn event from the report.",
          "acceptanceCriteria": [
            "Retain cancellation effective date and source tombstone lineage.",
            "Emit one cancellation movement per effective revision.",
            "Expose unavailable source history as incomplete reporting."
          ],
          "implementationNotes": [
            "Use synthetic deletion events rather than recovering private backups."
          ],
          "verification": [
            "Apply a cancellation tombstone and retain its churn movement.",
            "Replay the tombstone and verify no double cancellation."
          ],
          "deliverables": [
            "Tombstone handling and movement fixtures"
          ],
          "rollout": "Enable tombstone capture before source deletion; halt destructive cleanup if lineage is missing.",
          "skills": [
            "Change data",
            "Lineage"
          ],
          "fieldMix": [
            {
              "field": "Data engineering",
              "percentage": 100
            }
          ],
          "patterns": []
        },
        {
          "id": "422184d7-8cc3-4b69-84d7-5654c9ef073a",
          "key": "ADBT-107",
          "title": "Detect fan-out before publishing account-level revenue totals",
          "type": "BUG",
          "priority": "HIGH",
          "difficulty": "EXPERT",
          "estimateMinutes": 300,
          "phaseId": "model",
          "dependsOn": [
            "ADBT-104",
            "ADBT-105",
            "ADBT-106"
          ],
          "scenario": "A new feature joins account tags to movement rows and inflates revenue for accounts with multiple tags.",
          "acceptanceCriteria": [
            "Assert row and amount conservation across the join.",
            "Define tag allocation or a nonduplicating existence filter.",
            "Fail publication when conservation fails."
          ],
          "implementationNotes": [
            "Keep tag-level attribution distinct from account-level totals."
          ],
          "verification": [
            "Add two tags to an account and preserve its revenue total.",
            "Use the naive many-to-many join in a regression and detect inflation."
          ],
          "deliverables": [
            "Fan-out guard and corrected account model"
          ],
          "rollout": "Canary the model in a separate schema; restore prior view selection on failed conservation.",
          "skills": [
            "Join cardinality",
            "Data invariants"
          ],
          "fieldMix": [
            {
              "field": "Data engineering",
              "percentage": 70
            },
            {
              "field": "Quality engineering",
              "percentage": 30
            }
          ],
          "patterns": []
        },
        {
          "id": "87aed20b-94d9-4594-af20-14c3712a55d9",
          "key": "ADBT-108",
          "title": "Generate a report manifest with exact model and source revisions",
          "type": "TASK",
          "priority": "MEDIUM",
          "difficulty": "FOUNDATIONAL",
          "estimateMinutes": 90,
          "phaseId": "publish",
          "dependsOn": [
            "ADBT-105",
            "ADBT-107"
          ],
          "scenario": "An analyst sends a CSV to finance and later cannot identify which transformation commit or source cutoff produced it.",
          "acceptanceCriteria": [
            "Include model commit, source checkpoints and generated UTC time.",
            "Hash exported bytes and preserve a report identity.",
            "Exclude credentials and raw customer fields from the manifest."
          ],
          "implementationNotes": [
            "Keep the manifest next to synthetic exports."
          ],
          "verification": [
            "Regenerate the same named inputs and compare content hashes.",
            "Change a source revision and receive a distinct manifest."
          ],
          "deliverables": [
            "Report manifest and reproducibility command"
          ],
          "rollout": "Attach manifests to new reports; label earlier exports as lacking lineage.",
          "skills": [
            "Provenance",
            "Reproducibility"
          ],
          "fieldMix": [
            {
              "field": "Data engineering",
              "percentage": 80
            },
            {
              "field": "Storage systems",
              "percentage": 20
            }
          ],
          "patterns": []
        },
        {
          "id": "89ae0367-f0d8-4ff7-b2bb-ec4d82f4c7f6",
          "key": "ADBT-109",
          "title": "Prove an incremental mart matches a full refresh after corrections",
          "type": "TASK",
          "priority": "MEDIUM",
          "difficulty": "EXPERT",
          "estimateMinutes": 360,
          "phaseId": "publish",
          "dependsOn": [
            "ADBT-106",
            "ADBT-107",
            "ADBT-108"
          ],
          "scenario": "The team wants to reduce daily build cost but needs confidence that incremental state does not drift after late corrections.",
          "acceptanceCriteria": [
            "Author a sequence of inserts, revisions and tombstones.",
            "Compare every grain key and measure to a full refresh.",
            "Report extra, missing and changed rows separately."
          ],
          "implementationNotes": [
            "Run both paths against the same immutable synthetic inputs."
          ],
          "verification": [
            "Replay the complete change sequence with equal final outputs.",
            "Skip one revision intentionally and verify a precise discrepancy report."
          ],
          "deliverables": [
            "Differential transformation harness"
          ],
          "rollout": "Require a clean differential run before changing schedule; revert to full refresh on mismatch.",
          "skills": [
            "Differential testing",
            "Data reliability"
          ],
          "fieldMix": [
            {
              "field": "Quality engineering",
              "percentage": 50
            },
            {
              "field": "Data engineering",
              "percentage": 50
            }
          ],
          "patterns": []
        },
        {
          "id": "8e810bb2-2ec7-46cb-994c-69592059ac28",
          "key": "ADBT-110",
          "title": "Write the analytics incident handoff for an unexplained revenue shift",
          "type": "CHORE",
          "priority": "MEDIUM",
          "difficulty": "INTERMEDIATE",
          "estimateMinutes": 120,
          "phaseId": "publish",
          "dependsOn": [
            "ADBT-108",
            "ADBT-109"
          ],
          "scenario": "A report moves after a release and on-call staff cannot tell a genuine source correction from a transformation regression.",
          "acceptanceCriteria": [
            "Start investigation from report manifests and affected grain keys.",
            "Separate source, definition and implementation changes.",
            "Include restore-view and corrected-export procedures."
          ],
          "implementationNotes": [
            "Use a fabricated incident with no real financial assertions."
          ],
          "verification": [
            "Trace one legitimate correction through source lineage.",
            "Trace a fan-out regression and restore the prior reporting view."
          ],
          "deliverables": [
            "Analytics incident runbook"
          ],
          "rollout": "Validate the runbook with local reports; version it with model publication.",
          "skills": [
            "Incident response",
            "Data lineage"
          ],
          "fieldMix": [
            {
              "field": "Data engineering",
              "percentage": 60
            },
            {
              "field": "Site reliability",
              "percentage": 40
            }
          ],
          "patterns": []
        }
      ]
    }
  ]
}
