{
  "specificationId": "tattvabodha-content-integration",
  "specificationName": "Tattvabodha Content Integration Specification",
  "specificationVersion": "1.1.0",
  "purpose": "A portable contract for consuming Tattvabodha practices and building compatible experience players in web, mobile, and companion applications.",
  "conformance": {
    "practiceCoreSchema": "/schemas/practice-core-v1.0.0.schema.json",
    "experienceSchema": "/schemas/tattvabodha-experience-v1.0.0.schema.json",
    "practiceCoreVersion": "1.0.0",
    "experienceTemplateId": "practice-experience-v1",
    "karmaPhalaSpecification": "/specifications/tattvabodha-karma-phala-v1.0.0.json",
    "practiceCompletionSchema": "/schemas/tattvabodha-practice-completion-v1.0.0.schema.json"
  },
  "contentLayers": {
    "practiceCore": {
      "purpose": "Canonical meaning and method of a practice, independent of UI.",
      "fields": ["id", "name", "essence", "intention", "object", "skills", "cultivates", "fruits", "method"],
      "methodPhases": ["prepare", "engage", "respond", "close"],
      "referenceRule": "IDs refer to canonical library records. Resolve practice extensions before presenting a complete practice."
    },
    "practiceMetadata": {
      "purpose": "Context and evidence about a practice; stored separately from Practice Core.",
      "fields": ["practiceId", "defaultExperienceId", "subtitle", "alternateNames", "traditions", "lineages", "historicalOrigins", "sources", "relatedPractices", "relatedConcepts", "scopeNote", "interpretations"]
    },
    "practicePresentation": {
      "purpose": "Optional visual and editorial hints; applications can ignore them and render with their own design system.",
      "fields": ["practiceId", "symbol", "icon", "layout", "accent", "homeBase", "arising", "relationship"]
    },
    "relationships": {
      "purpose": "Canonical links between records such as practice-to-experience and practice-to-object.",
      "direction": "Relationship records identify source and target kind/id. Resolve links by canonical IDs; do not infer companion associations or duplicate linked objects.",
      "defaultExperience": {
        "type": "has_default_experience",
        "from": { "kind": "practice", "id": "canonical practice ID" },
        "to": { "kind": "experience", "id": "canonical Experience ID" },
        "inverseReference": "experience.practiceId",
        "metadataReference": "practiceMetadata.defaultExperienceId",
        "cardinality": "Each published practice has exactly one active default Experience. Other Experiences may also be linked to the practice."
      }
    }
  },
  "experienceRecord": {
    "type": "experience",
    "name": "Practice name, such as Śamatha",
    "practiceId": "Canonical practice ID mirrored by this experience",
    "experienceType": "default_practice",
    "templateId": "practice-experience-v1",
    "durationMinutes": "Configured Object Focus duration in minutes",
    "phases": "Ordered phase records; each has a stable id, type, title, order, optional content, and timing metadata."
  },
  "defaultExperienceResolution": {
    "purpose": "Every eligible default_practice can open in a player, including a practice that does not yet have a persisted Experience document.",
    "resolutionOrder": [
      "Use the Experience identified by practiceMetadata.defaultExperienceId or a non-legacy has_default_experience relationship. Resolve any legacy practice.experienceId reference only when no canonical default link is present.",
      "If there is no linked Experience and no explicit non-default experience type, derive an in-memory default Experience from the canonical Practice Core record and practice-experience-v1.",
      "If an explicitly specialized experience type is declared but its required Experience or template is missing, show a clear unavailable state for that specialized player rather than applying the default practice template."
    ],
    "derivedExperience": {
      "id": "{practiceId}_default",
      "type": "experience",
      "name": "Use the canonical practice name.",
      "practiceId": "Use the canonical practice ID.",
      "experienceType": "default_practice",
      "templateId": "practice-experience-v1",
      "durationMinutes": "Use the user's configured duration, defaulting to 10 minutes.",
      "phases": "Instantiate the template phases and fill their guidance from the practice's resolved Core method and selected object."
    },
    "persistence": "A derived Experience is a runtime projection of canonical Practice Core plus the shared template. Do not create or write a Firestore Experience or relationship merely to make this fallback work.",
    "canonicalData": "Every published practice should have a persisted default Experience and explicit relationship. The runtime projection is a resilience fallback for incomplete or older data only."
  },
  "practiceExperienceTemplate": {
    "id": "practice-experience-v1",
    "name": "Practice Experience Template",
    "appliesTo": "default_practice experiences",
    "orderedPhases": [
      { "id": "configure", "type": "configure", "title": "Configure", "duration": null, "behavior": "Untimed setup. Select available practice options before beginning." },
      { "id": "threshold", "type": "threshold", "title": "And now, {practiceName}", "durationSeconds": 5, "behavior": "Brief ceremonial entry splash after setup; not meditation time." },
      { "id": "take-seat", "type": "posture", "title": "Take Your Seat", "durationSeconds": 15, "behavior": "Brief arrival splash for posture and settling." },
      { "id": "guidance", "type": "instruction", "title": "Guidance", "durationSeconds": 30, "behavior": "Orient the practitioner to the canonical essence and engagement." },
      { "id": "object-focus", "type": "practice", "title": "Object Focus", "durationSource": "experience.durationMinutes", "behavior": "The main practice period. Center the selected object, show an elapsed countdown, and place concise engagement guidance beneath it." },
      { "id": "reorientation", "type": "reorientation", "title": "Emergence", "durationSeconds": 30, "behavior": "Gently release the practice and reorient to the body and surroundings." },
      { "id": "summary", "type": "summary", "title": "Results", "duration": null, "behavior": "Show previewable practice relationships and possible fruits. The user closes this final screen to return; no result is guaranteed." }
    ],
    "timingSemantics": {
      "durationSeconds": "Default guidance for a short phase. It may be shown by the player or used by an app timer.",
      "durationSource": "For Object Focus, derive durationSeconds from the selected experience durationMinutes multiplied by 60.",
      "setupAndResults": "Configure and Results are user-controlled and have no timed duration.",
      "noImplicitRecording": "A timer or preview does not mean a session, skill use, karma, or phala has been recorded. Recording requires an explicit application-level session completion action."
    }
  },
  "experiencePhaseContract": {
    "requiredFields": ["id", "type", "title", "order"],
    "optionalFields": ["practiceId", "content", "prompt", "description", "text", "durationSeconds", "durationSource", "configuration", "motif", "transition"],
    "rules": [
      "Preserve phase order; phase order is meaningful.",
      "Use practiceId when a phase belongs to a different practice in a multi-practice experience.",
      "Configure is setup, Threshold and Take Your Seat are brief splash phases, and Results is a user-dismissed endpoint.",
      "Object Focus uses the selected practice duration; do not treat the overall experience duration as the duration of every phase.",
      "A renderer may adapt layout, animation, and icons while preserving phase meaning, labels, timing, and transitions."
    ]
  },
  "defaultPlayerBehavior": {
    "overview": "Experience title page (phase 0) summarizes the linked practice, object, engagement, and configured practice duration; it can be revisited.",
    "configure": "Allow selection of valid objects and practice options linked to the practice.",
    "missingDefaultExperience": "For an eligible default_practice without a linked Experience document, derive a runtime-only Experience from its Practice Core and practice-experience-v1. Do not treat the missing document as a load error or write a replacement record.",
    "threshold": "Show an animated 'And now, {practiceName}' moment after configuration; do not present it as a 5-second meditation interval.",
    "takeSeat": "Show a calm animated arrival moment for about 15 seconds.",
    "objectFocus": "Show the chosen object in a quiet centered viewer, an optional start/pause/resume/reset countdown for the selected duration, and engagement guidance below. Pausing or leaving this phase pauses its local timer.",
    "emergence": "Offer about 30 seconds to gently release and reorient before results.",
    "results": "Present relationships that would be noted and possible fruits; clearly distinguish preview from completed session. Provide a direct close/return action.",
    "navigation": "Support sequential transport and direct phase selection. Keep the player viewport stable while phases change."
  },
  "karmaAndPhalaIntegration": {
    "specification": "/specifications/tattvabodha-karma-phala-v1.0.0.json",
    "completionPayloadSchema": "/schemas/tattvabodha-practice-completion-v1.0.0.schema.json",
    "responsibility": "The player reports meaningful lifecycle data to the shared Karma service. It does not implement Firestore persistence or Phala aggregation itself.",
    "activeDuration": "Report measured active Object Focus seconds; exclude paused time and setup, threshold, guidance, and emergence phases.",
    "observedRelationships": "Report only objects encountered and skills actually exercised. The service validates these against canonical practice content.",
    "possibleFruits": "Fruits remain possibilities and are never inferred from practice completion. A reported fruit is a separate explicit observation event.",
    "preview": "Before the user explicitly completes the practice and the shared service acknowledges it, show only preview values and do not claim that Karma or Phala was recorded.",
    "retry": "Use one stable event ID and payload across retries; queue offline completion payloads until the shared service acknowledges them. Never write Phala directly from a client."
  },
  "futureTemplateFamilies": [
    { "templateFamily": "guided_practice", "status": "future; define its own ordered phases and timing" },
    { "templateFamily": "meta_practice", "status": "future; define its own ordered phases and timing" },
    { "templateFamily": "devotional_practice", "status": "future; define its own ordered phases and timing" },
    { "templateFamily": "card_draw", "status": "future; define its own ordered phases and timing" }
  ],
  "verificationChecklist": [
    "Practice Core validates against the linked v1.0.0 JSON Schema after extension resolution.",
    "Metadata and Presentation remain separate from Practice Core.",
    "Canonical IDs and relationships resolve; linked entities are not duplicated.",
    "Every published practice has exactly one defaultExperienceId in its Metadata, a matching has_default_experience relationship, and an Experience whose practiceId matches.",
    "Experience type, templateId, linked practiceId, phase IDs, types, order, and timing follow the applicable template.",
    "A practice without a persisted Experience link still opens through the runtime-only default experience projection when no specialized experience type is declared.",
    "Object Focus duration follows the configured practice duration.",
    "Results are framed as previewable possible relationships and can be dismissed back to the practice.",
    "A preview or timer does not record a completed session.",
    "Players follow the shared Karma & Phala specification and never write Karma or Phala directly from the client."
  ]
}
