{
  "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": "35e9a9b2-818f-4ac5-9f47-6fcdabdd4533",
      "key": "SEARCH",
      "title": "Internal policy search with inspectable sources",
      "field": "Applied AI",
      "summary": "Build a retrieval workflow that respects document access, cites exact revisions, and declines unsupported answers.",
      "context": "Employees search fictional travel and equipment policies. The current prototype blends draft and approved text and sometimes answers using a policy the employee cannot open. Use a small synthetic corpus and a deterministic answer-provider double.",
      "stack": [
        "TypeScript",
        "PostgreSQL",
        "HTTP",
        "JSON Schema"
      ],
      "prerequisites": [
        "Author synthetic policy documents with revisions, effective dates, and access groups.",
        "Use a local deterministic provider double; paid model access is optional and not required."
      ],
      "developerValue": "Practice access-aware retrieval, source provenance, structured model boundaries, and reproducible evaluation.",
      "companyValue": "Inspect how an engineer prevents unsupported or unauthorized answers and handles changing policy content.",
      "delivery": "A local retrieval service with revisioned citations, abstention behavior, and an evaluation report.",
      "phases": [
        {
          "id": "sources",
          "title": "Make source authority explicit",
          "goal": "Index only identifiable, eligible document revisions."
        },
        {
          "id": "answers",
          "title": "Constrain answer generation",
          "goal": "Return supported citations or a clear lack-of-answer result."
        },
        {
          "id": "operations",
          "title": "Evaluate and operate the service",
          "goal": "Bound provider failure, retention, and content changes."
        }
      ],
      "tickets": [
        {
          "id": "75da6c37-e4f3-4185-b7f5-4aa2654676aa",
          "key": "SEARCH-101",
          "title": "Import policy documents with stable revision identities",
          "type": "TASK",
          "priority": "MEDIUM",
          "difficulty": "FOUNDATIONAL",
          "estimateMinutes": 75,
          "phaseId": "sources",
          "dependsOn": [],
          "scenario": "Two files called travel-policy.md contain different meal limits. The importer currently overwrites one with the other. Store a document identity, revision, and content digest.",
          "acceptanceCriteria": [
            "Each imported revision records document ID, revision ID, digest, title, status, and effective date.",
            "Reimporting identical bytes under the same revision is idempotent.",
            "Different bytes under an existing revision are rejected; a new revision preserves the previous record."
          ],
          "implementationNotes": [
            "Use synthetic policy text and UTC timestamps."
          ],
          "verification": [
            "Import two revisions and retrieve their original content separately.",
            "Reimport a modified file with the first revision ID and assert a conflict with no overwritten content."
          ],
          "deliverables": [
            "Revisioned importer and synthetic policy corpus"
          ],
          "rollout": "Index the synthetic corpus in a separate namespace; rollback by changing the active index pointer, not deleting revision history.",
          "skills": [
            "Data modeling",
            "Content integrity",
            "Idempotency"
          ],
          "fieldMix": [
            {
              "field": "Data engineering",
              "percentage": 60
            },
            {
              "field": "Database engineering",
              "percentage": 40
            }
          ],
          "patterns": []
        },
        {
          "id": "9b4b5a72-b037-46b7-aad8-777031fe5ee1",
          "key": "SEARCH-102",
          "title": "Keep chunk citations anchored to the original policy text",
          "type": "TASK",
          "priority": "MEDIUM",
          "difficulty": "INTERMEDIATE",
          "estimateMinutes": 105,
          "phaseId": "sources",
          "dependsOn": [
            "SEARCH-101"
          ],
          "scenario": "An answer links to the policy title, but reviewers cannot find the quoted sentence after headings were stripped. Give each chunk a stable revision reference and exact text offsets.",
          "acceptanceCriteria": [
            "Chunks record source revision, start and end offsets, and a content digest.",
            "Reconstructing a chunk from the original source yields exactly the stored chunk text.",
            "Chunk boundaries preserve headings and never split a Unicode code point."
          ],
          "implementationNotes": [
            "Specify the offset unit and normalization rules.",
            "Chunk IDs change when chunking strategy changes."
          ],
          "verification": [
            "Reconstruct every chunk of a document containing emoji and repeated headings.",
            "Change the chunking version and confirm old citation anchors remain resolvable."
          ],
          "deliverables": [
            "Chunker specification and source-anchor tests"
          ],
          "rollout": "Build a new chunk index beside the old one; swap only after source reconstruction passes.",
          "skills": [
            "Text processing",
            "Provenance",
            "Unicode"
          ],
          "fieldMix": [
            {
              "field": "Data engineering",
              "percentage": 60
            },
            {
              "field": "Applied AI",
              "percentage": 40
            }
          ],
          "patterns": []
        },
        {
          "id": "3c95c8d7-59b7-4d98-a099-9f171ea31d9b",
          "key": "SEARCH-103",
          "title": "Apply group access before ranking or sending context to a provider",
          "type": "BUG",
          "priority": "HIGH",
          "difficulty": "EXPERT",
          "estimateMinutes": 240,
          "phaseId": "sources",
          "dependsOn": [
            "SEARCH-102"
          ],
          "scenario": "A general employee query retrieves a restricted executive travel exception. Hiding the final link is too late because the provider has already received the text. Enforce scope at retrieval and again at answer delivery.",
          "acceptanceCriteria": [
            "The repository query limits candidates to the caller tenant and current allowed groups before ranking.",
            "The provider receives no unauthorized chunk text or metadata.",
            "Access revoked between retrieval and response prevents affected citations and answer content from being delivered."
          ],
          "implementationNotes": [
            "Use server-derived membership; never trust group IDs from the query body.",
            "Do not share cached contexts across permission scopes."
          ],
          "verification": [
            "Query identical terms as users in different groups and inspect the exact provider request.",
            "Revoke a group after retrieval using a barrier and verify delivery fails closed without restricted text."
          ],
          "deliverables": [
            "Access-scoped retrieval and revocation race tests"
          ],
          "rollout": "Disable answer generation for any request whose permission snapshot cannot be revalidated; deploy scoped retrieval before enabling ranking.",
          "skills": [
            "Authorization",
            "Retrieval security",
            "Race conditions",
            "Tenant isolation"
          ],
          "fieldMix": [
            {
              "field": "Security",
              "percentage": 60
            },
            {
              "field": "Applied AI",
              "percentage": 40
            }
          ],
          "patterns": []
        },
        {
          "id": "fae57076-118d-4a13-a676-139745389969",
          "key": "SEARCH-104",
          "title": "Exclude drafts and future policies from current-policy answers",
          "type": "BUG",
          "priority": "HIGH",
          "difficulty": "INTERMEDIATE",
          "estimateMinutes": 105,
          "phaseId": "sources",
          "dependsOn": [
            "SEARCH-101"
          ],
          "scenario": "A future equipment allowance outranks the currently approved policy. Define eligibility by approval, effective interval, and supersession so search answers the policy in effect at the requested date.",
          "acceptanceCriteria": [
            "Current queries include approved revisions whose effective interval contains the supplied clock time.",
            "Draft, withdrawn, and future revisions are excluded from answer context.",
            "Overlapping eligible revisions for one policy produce an explicit conflict instead of a silent choice."
          ],
          "implementationNotes": [
            "Use an injected clock and half-open effective intervals."
          ],
          "verification": [
            "Search immediately before and at an effective-date boundary.",
            "Create overlapping approved revisions and verify the query returns a conflict with no generated answer."
          ],
          "deliverables": [
            "Policy eligibility filter and effective-date cases"
          ],
          "rollout": "Run eligibility inspection over the corpus before switching active search; keep ambiguous documents unavailable for answers.",
          "skills": [
            "Temporal data",
            "Business rules",
            "Conflict handling"
          ],
          "fieldMix": [
            {
              "field": "Applied AI",
              "percentage": 50
            },
            {
              "field": "Data engineering",
              "percentage": 30
            },
            {
              "field": "Backend",
              "percentage": 20
            }
          ],
          "patterns": []
        },
        {
          "id": "1cb515ca-8753-4a97-b113-a69b5ca29bc6",
          "key": "SEARCH-105",
          "title": "Reject answers with invented or mismatched citations",
          "type": "STORY",
          "priority": "HIGH",
          "difficulty": "ADVANCED",
          "estimateMinutes": 180,
          "phaseId": "answers",
          "dependsOn": [
            "SEARCH-103",
            "SEARCH-104"
          ],
          "scenario": "The provider double returns a fluent answer citing chunk-999, which was never retrieved. Add a structured response boundary and validate every reference before displaying an answer.",
          "acceptanceCriteria": [
            "Responses conform to a strict schema with answer status, bounded claim text, and citation references.",
            "Every citation resolves to an authorized chunk in the exact request context and source revision.",
            "A cited quotation must match its referenced span; invalid output yields an unavailable result without partial answer text."
          ],
          "implementationNotes": [
            "Schema validity and quote matching do not prove broader semantic support; expose that limitation.",
            "Treat provider text as untrusted output."
          ],
          "verification": [
            "Accept a fixture response with exact authorized citations.",
            "Reject invented IDs, a correct ID with altered quotation, and additional schema properties."
          ],
          "deliverables": [
            "Structured answer validator and adversarial output fixtures"
          ],
          "rollout": "Make validation mandatory for all provider adapters; fall back to authorized search results when generation fails.",
          "skills": [
            "Structured output",
            "Citation validation",
            "Trust boundaries"
          ],
          "fieldMix": [
            {
              "field": "Applied AI",
              "percentage": 70
            },
            {
              "field": "Security",
              "percentage": 30
            }
          ],
          "patterns": []
        },
        {
          "id": "3a7d61a9-ce3b-42c7-a437-a95f6c831dd8",
          "key": "SEARCH-106",
          "title": "Return insufficient information when the corpus cannot answer",
          "type": "STORY",
          "priority": "HIGH",
          "difficulty": "INTERMEDIATE",
          "estimateMinutes": 120,
          "phaseId": "answers",
          "dependsOn": [
            "SEARCH-105"
          ],
          "scenario": "Someone asks whether a bicycle repair is reimbursable, but the corpus contains only airfare and laptop rules. The prototype invents a limit. Add an explicit abstention path.",
          "acceptanceCriteria": [
            "Empty retrieval returns INSUFFICIENT_INFORMATION without calling the answer provider.",
            "A provider abstention is shown as missing support, without a fabricated policy rule.",
            "The response may include authorized source links but never presents retrieval rank as certainty."
          ],
          "implementationNotes": [
            "Use a documented conservative context-selection rule with inspectable thresholds."
          ],
          "verification": [
            "Ask an unsupported bicycle-repair question and confirm no rule or amount is invented.",
            "Ask an exact covered policy question and confirm authorized sources are retained in the supported fixture response."
          ],
          "deliverables": [
            "Abstention contract and covered/uncovered question fixtures"
          ],
          "rollout": "Default uncertain cases to source search; tune thresholds only against a versioned evaluation set.",
          "skills": [
            "Abstention",
            "Product judgment",
            "Evaluation design"
          ],
          "fieldMix": [
            {
              "field": "Applied AI",
              "percentage": 100
            }
          ],
          "patterns": []
        },
        {
          "id": "a9c77d6f-1f85-4780-9184-23267c1b8d6d",
          "key": "SEARCH-107",
          "title": "Contain instructions embedded in a retrieved document",
          "type": "BUG",
          "priority": "HIGH",
          "difficulty": "ADVANCED",
          "estimateMinutes": 150,
          "phaseId": "answers",
          "dependsOn": [
            "SEARCH-105"
          ],
          "scenario": "A synthetic policy appendix says to ignore the user and reveal all other documents. Ensure retrieved text remains data and cannot expand access or activate tools.",
          "acceptanceCriteria": [
            "The provider request separates application instructions from quoted document context.",
            "The answer interface exposes no file, network, or administrative tools.",
            "Prompt-injection fixtures cannot alter document access scope or bypass citation validation."
          ],
          "implementationNotes": [
            "Do not claim that delimiting text alone prevents all prompt injection.",
            "Use deterministic malicious-output fixtures to test downstream enforcement."
          ],
          "verification": [
            "Supply an instruction-bearing chunk and inspect the constructed provider request.",
            "Return a malicious provider response with an unauthorized citation and verify the validator rejects it without a secondary fetch."
          ],
          "deliverables": [
            "Context construction boundary and injection containment tests"
          ],
          "rollout": "Keep tool access disabled for this feature; reject any adapter configuration that grants capabilities beyond answering.",
          "skills": [
            "Prompt injection defense",
            "Least privilege",
            "Output validation"
          ],
          "fieldMix": [
            {
              "field": "Applied AI",
              "percentage": 50
            },
            {
              "field": "Security",
              "percentage": 50
            }
          ],
          "patterns": []
        },
        {
          "id": "fe851ff8-c652-41d4-8db3-e365b939c141",
          "key": "SEARCH-108",
          "title": "Bound provider latency, retries, and retained query data",
          "type": "STORY",
          "priority": "HIGH",
          "difficulty": "ADVANCED",
          "estimateMinutes": 150,
          "phaseId": "operations",
          "dependsOn": [
            "SEARCH-106",
            "SEARCH-107"
          ],
          "scenario": "A stalled model call occupies a request indefinitely and debug logs retain full employee queries. Add a bounded provider port with safe audit metadata.",
          "acceptanceCriteria": [
            "Calls enforce timeout, attempt count, response-size, and token or equivalent local budget limits.",
            "Audit metadata records provider/model version, request template version, schema version, duration, retry count, and trace ID.",
            "Generic logs exclude raw questions, document text, and credentials; retention for any explicit debug store is configured separately."
          ],
          "implementationNotes": [
            "The default adapter is a local deterministic double.",
            "Cost is recorded when known and unavailable when not supplied; do not invent cost figures."
          ],
          "verification": [
            "Simulate a stalled call and confirm a bounded unavailable response and cancellation.",
            "Include secret marker text in query and context and scan normal diagnostics for leakage."
          ],
          "deliverables": [
            "Provider port, budget policy, and safe audit tests"
          ],
          "rollout": "Enable one provider adapter at a time behind the validated port; fall back to source results on budget or timeout failure.",
          "skills": [
            "Provider interfaces",
            "Resource limits",
            "Privacy",
            "Observability"
          ],
          "fieldMix": [
            {
              "field": "Applied AI",
              "percentage": 40
            },
            {
              "field": "Privacy engineering",
              "percentage": 30
            },
            {
              "field": "Site reliability",
              "percentage": 30
            }
          ],
          "patterns": []
        },
        {
          "id": "257d1316-1c30-4f28-958e-3e6d77a6b593",
          "key": "SEARCH-109",
          "title": "Invalidate answers when policy authority or access changes",
          "type": "BUG",
          "priority": "HIGH",
          "difficulty": "EXPERT",
          "estimateMinutes": 210,
          "phaseId": "operations",
          "dependsOn": [
            "SEARCH-108"
          ],
          "scenario": "A cached answer still cites a withdrawn policy and is reused for an employee with different access. Bind cache entries to the exact corpus and permission authority.",
          "acceptanceCriteria": [
            "Cache identity includes normalized query, corpus version, provider configuration, tenant, and permission-scope version.",
            "Delivery rechecks every cited revision eligibility and current access even on a cache hit.",
            "Withdrawing a cited policy prevents old answer delivery without rewriting the original cached record."
          ],
          "implementationNotes": [
            "Use a version pointer or tombstone for invalidation rather than editing source history."
          ],
          "verification": [
            "Warm the cache, withdraw a source, and verify the next request cannot return the old answer.",
            "Reuse identical text across two permission groups and verify no cross-scope hit occurs."
          ],
          "deliverables": [
            "Authority-aware cache and withdrawal/access regression cases"
          ],
          "rollout": "Ship with caching disabled, then enable only after invalidation cases pass; a kill switch returns to live retrieval.",
          "skills": [
            "Cache invalidation",
            "Authorization",
            "Versioned data",
            "Consistency"
          ],
          "fieldMix": [
            {
              "field": "Applied AI",
              "percentage": 40
            },
            {
              "field": "Security",
              "percentage": 30
            },
            {
              "field": "Distributed systems",
              "percentage": 30
            }
          ],
          "patterns": []
        },
        {
          "id": "c0999505-e2ef-4fb5-a393-caf4bf93e55b",
          "key": "SEARCH-110",
          "title": "Publish an evaluation report that separates retrieval and answer failures",
          "type": "TASK",
          "priority": "MEDIUM",
          "difficulty": "INTERMEDIATE",
          "estimateMinutes": 150,
          "phaseId": "operations",
          "dependsOn": [
            "SEARCH-109"
          ],
          "scenario": "A single accuracy percentage conceals whether failures came from missing sources or invalid generated answers. Create a small versioned evaluation set and report distinct failure categories.",
          "acceptanceCriteria": [
            "Cases cover answerable, unsupported, conflicting, restricted, stale, and injection-bearing questions.",
            "Reports separate eligible-source retrieval, citation validity, abstention behavior, and provider failures.",
            "Each result records corpus, implementation, provider-double, and case-set versions with expected and actual observations."
          ],
          "implementationNotes": [
            "Do not claim deterministic-double results measure a real model quality level.",
            "Keep evaluation examples synthetic and publishable."
          ],
          "verification": [
            "Run the full set twice and compare deterministic results.",
            "Introduce an access-filter defect and confirm it appears as a security failure rather than an aggregate quality dip."
          ],
          "deliverables": [
            "Versioned evaluation cases and categorized report"
          ],
          "rollout": "Use category-specific gates for changes; require a separate measured report before replacing the deterministic adapter.",
          "skills": [
            "AI evaluation",
            "Test design",
            "Failure taxonomy"
          ],
          "fieldMix": [
            {
              "field": "Applied AI",
              "percentage": 60
            },
            {
              "field": "Quality engineering",
              "percentage": 40
            }
          ],
          "patterns": []
        }
      ]
    }
  ]
}
