{
  "schemaVersion": 1,
  "study": "cold-email-sequence-length-experiment",
  "title": "Sequence length experiment: study protocol",
  "status": "awaiting-real-data",
  "scope": "Collection template, not a dataset or completed field study. All null values are intentionally uncollected.",
  "unitOfObservation": "prospect",
  "requiredInputs": "Eligible prospects and approved short and longer sequences sharing the initial steps.",
  "controls": "Assign at entry; retain stop-after-reply and suppression in both arms.",
  "primaryAnalysis": "Outcomes per assigned eligible prospect; never restrict analysis to those reaching the final step.",
  "registration": {
    "owner": null,
    "protocolVersion": "1",
    "registeredAt": null,
    "population": null,
    "eligibilityRules": null,
    "primaryOutcomeDefinition": null,
    "denominator": null,
    "observationWindow": null,
    "targetSampleAndJustification": null,
    "assignmentProcedureAndSeed": null,
    "exclusionRules": null,
    "safetyStopConditions": null,
    "missingDataPolicy": null,
    "retentionAndAccessOwner": null
  },
  "collectionRules": [
    "Assign pseudonymous IDs; do not store mailbox passwords, access tokens or unnecessary identifiers.",
    "Freeze the outcome and exclusions before collection; retain exclusions with reasons.",
    "Do not use repeated observations as independent people. Record clustering by person, company or mailbox.",
    "Do not treat a software test, simulated reply or researcher-written example as participant or campaign evidence.",
    "Record complaints and opt-outs and follow the actual suppression workflow.",
    "For interviews obtain permission before recording and respect withdrawal.",
    "Publish aggregate or redacted evidence only after review; keep original private records outside the public website."
  ],
  "fieldDictionary": {
    "assignment_id": {
      "required": true,
      "type": "string, number or boolean as specified by the registered protocol; null until collected",
      "meaning": "assignment id",
      "missingValue": null
    },
    "company_id": {
      "required": true,
      "type": "string, number or boolean as specified by the registered protocol; null until collected",
      "meaning": "company id",
      "missingValue": null
    },
    "arm": {
      "required": true,
      "type": "string, number or boolean as specified by the registered protocol; null until collected",
      "meaning": "arm",
      "missingValue": null
    },
    "max_steps": {
      "required": true,
      "type": "string, number or boolean as specified by the registered protocol; null until collected",
      "meaning": "max steps",
      "missingValue": null
    },
    "actual_messages": {
      "required": true,
      "type": "string, number or boolean as specified by the registered protocol; null until collected",
      "meaning": "actual messages",
      "missingValue": null
    },
    "stop_reason": {
      "required": true,
      "type": "string, number or boolean as specified by the registered protocol; null until collected",
      "meaning": "stop reason",
      "missingValue": null
    },
    "assigned_at": {
      "required": true,
      "type": "string, number or boolean as specified by the registered protocol; null until collected",
      "meaning": "assigned at",
      "missingValue": null
    },
    "cutoff_at": {
      "required": true,
      "type": "string, number or boolean as specified by the registered protocol; null until collected",
      "meaning": "cutoff at",
      "missingValue": null
    },
    "qualified_reply": {
      "required": true,
      "type": "string, number or boolean as specified by the registered protocol; null until collected",
      "meaning": "qualified reply",
      "missingValue": null
    },
    "complaint": {
      "required": true,
      "type": "string, number or boolean as specified by the registered protocol; null until collected",
      "meaning": "complaint",
      "missingValue": null
    },
    "optout": {
      "required": true,
      "type": "string, number or boolean as specified by the registered protocol; null until collected",
      "meaning": "optout",
      "missingValue": null
    }
  },
  "blankRecord": {
    "observation_id": null,
    "assignment_id": null,
    "company_id": null,
    "arm": null,
    "max_steps": null,
    "actual_messages": null,
    "stop_reason": null,
    "assigned_at": null,
    "cutoff_at": null,
    "qualified_reply": null,
    "complaint": null,
    "optout": null,
    "excluded": false,
    "exclusion_reason": null,
    "protocol_deviation": null
  },
  "records": [],
  "analysisStatus": "not-run",
  "results": null,
  "interpretationLimits": "Define complaint and opt-out stopping criteria before launch. A longer sequence is not automatically more productive. Publish results only after the evidence, method and limitations have been reviewed. This protocol provides no benchmark, expected lift or completed-study claim.",
  "procedure": [
    "Specify shared initial steps, the extra message, stopping rules and a common mature outcome window.",
    "Randomize at entry. Preserve suppression and stop-after-reply in both arms; count actual messages as a secondary exposure metric.",
    "Before collection, write the primary outcome, observation window, exclusion rules and stopping conditions. Preserve excluded observations with a reason rather than quietly removing them.",
    "Pilot the procedure with fictional or owned test data, resolve ambiguous fields, and freeze a dated protocol version before the main run."
  ],
  "interviewPrompts": []
}
