{
  "$comment": "CANONICAL SPECIFICATION OF THE BLACK HOLE INDEX. This file is the statement of record for the instrument's constants, aggregation and interpretation zones. Every other statement of the specification — the research paper, the site, the public replication package, the executable model in lib/model.ts — is checked against this file by scripts/check-canonical-spec.py, and the publication audit fails on divergence. It exists because on 7 September 2026 the public replication package was found to have contradicted its own code from the day it was published: its methodology document gave zone thresholds of 0.5 / 1.0 / 1.5 / 2.5 while its model, the paper and the production site all used 0.4 / 0.7 / 1.3 / 2.5. An external researcher taking that document as canonical had a different instrument. This file is what such a researcher should take instead.",
  "specVersion": "1.0",
  "frozen": "2026-09-08",
  "modelVersion": "V3.1",
  "citeAs": "Savich, I. (2026). Black Hole Index canonical specification v1.0. https://blackholeindex.com/bhi-spec.json",
  "licence": "CC BY 4.0",
  "originOfRecord": {
    "narrative": "paper/bhi-structural-lock-in.md, sections 3.3, 3.4, 3.5 and 3.6",
    "executable": "lib/model.ts, function V3 and function zone",
    "note": "Neither is subordinate to the other: they are two statements of the same specification, and this file is what both are checked against. The executable model is not modified by the existence of this file and does not import it."
  },
  "scale": {
    "min": 0,
    "max": 10,
    "normalisation": "each parameter score is divided by 10 before aggregation, so every input to the formula lies in [0, 1]",
    "anchorsPublishedAt": "paper/bhi-structural-lock-in.md, Appendix A"
  },
  "parameters": [
    {
      "symbol": "d",
      "name": "Data Depth",
      "group": "capture",
      "definition": "Volume and density of observable user and organizational context"
    },
    {
      "symbol": "m",
      "name": "Memory",
      "group": "capture",
      "definition": "Persistent non-portable state - embeddings, profiles, learned policies"
    },
    {
      "symbol": "a",
      "name": "Action",
      "group": "capture",
      "definition": "Ability to initiate and complete real-world actions autonomously"
    },
    {
      "symbol": "p",
      "name": "Process Centrality",
      "group": "capture",
      "definition": "Degree of embedding inside daily workflow chains"
    },
    {
      "symbol": "n",
      "name": "Network Effects",
      "group": "capture",
      "definition": "Ecosystem reinforcement - complementors, standards, multi-homing cost"
    },
    {
      "symbol": "c",
      "name": "Closeness",
      "group": "capture",
      "definition": "Frequency of contact and cognitive offloading habit formation"
    },
    {
      "symbol": "x",
      "name": "Portability",
      "group": "escape",
      "definition": "Data and state exportability - GDPR Art.20 excludes inferred data"
    },
    {
      "symbol": "s",
      "name": "Substitutability",
      "group": "escape",
      "definition": "Existence of functionally equivalent alternatives at integration level"
    },
    {
      "symbol": "h",
      "name": "Human Fallback",
      "group": "escape",
      "definition": "Ability to maintain productivity without the system"
    },
    {
      "symbol": "o",
      "name": "Org Depth",
      "group": "extended",
      "definition": "Institutional procurement lock-in - Granovetter cascade threshold"
    },
    {
      "symbol": "t",
      "name": "Momentum",
      "group": "extended",
      "definition": "Capability growth velocity - Arthur increasing returns"
    }
  ],
  "aggregation": {
    "cesForm": "((sum of sqrt(xi)) / n)^2",
    "elasticityOfSubstitution": 2,
    "substitutionParameter": 0.5,
    "captureBase": {
      "inputs": [
        "d",
        "m",
        "a",
        "p"
      ],
      "expression": "((sqrt(d) + sqrt(m) + sqrt(a) + sqrt(p)) / 4)^2"
    },
    "escapeCore": {
      "inputs": [
        "x",
        "s",
        "h"
      ],
      "expression": "((sqrt(x) + sqrt(s) + sqrt(h)) / 3)^2"
    },
    "synergy": {
      "knowledge": "sigma_K = sqrt(d * m)",
      "operational": "sigma_O = sqrt(a * p)",
      "boost": "SynergyBoost = 1 + 0.3 * (sigma_K + sigma_O) / 2"
    },
    "captureCore": "CaptureBase * SynergyBoost",
    "capture": "c * (1 + 0.5 * n) * CaptureCore * (1 + 0.5 * o) * (1 + 0.3 * t)",
    "feedback": "max(0.3, 1 - 0.35 * CaptureBase)",
    "escape": "epsilon + EscapeCore * feedback",
    "index": "B = Capture / (epsilon + EscapeCore * feedback)"
  },
  "constants": {
    "epsilon": {
      "symbol": "epsilon",
      "value": 0.1,
      "role": "floor on the denominator; what actually bounds B away from infinity"
    },
    "networkAmplification": {
      "symbol": "alpha",
      "value": 0.5,
      "role": "coefficient on n in the capture multiplier"
    },
    "synergyCoefficient": {
      "symbol": null,
      "value": 0.3,
      "role": "coefficient on the mean of the two synergy terms"
    },
    "organizationalMultiplier": {
      "symbol": "omega",
      "value": 0.5,
      "role": "coefficient on o in the capture multiplier"
    },
    "momentumMultiplier": {
      "symbol": "tau",
      "value": 0.3,
      "role": "coefficient on t in the capture multiplier"
    },
    "feedbackCoefficient": {
      "symbol": "delta",
      "value": 0.35,
      "role": "coefficient on CaptureBase in the feedback term"
    },
    "feedbackFloor": {
      "symbol": null,
      "value": 0.3,
      "role": "written guard that is unreachable and never binds: CaptureBase is bounded by [0,1], so feedback is bounded below by 0.65 for every possible input. Stated so that a reader does not mistake an inert guard for an active one."
    }
  },
  "theoreticalMaximum": {
    "value": 38.025,
    "roundedInPaper": 38.03,
    "at": "all capture and extended parameters at 10, all escape parameters at 0",
    "note": "reproducible from this specification alone; the checker recomputes it and fails on divergence"
  },
  "zones": [
    {
      "id": "tool",
      "name": "Useful Tool",
      "lowerInclusive": null,
      "upperExclusive": 0.4,
      "interpretation": "System is genuinely optional. Users can leave with minimal cost."
    },
    {
      "id": "gravity",
      "name": "Growing Gravity",
      "lowerInclusive": 0.4,
      "upperExclusive": 0.7,
      "interpretation": "Dependency forming. Switching feasible but increasingly inconvenient."
    },
    {
      "id": "transition",
      "name": "Transition Zone",
      "lowerInclusive": 0.7,
      "upperExclusive": 1.3,
      "interpretation": "Gray zone (cf. Altman Z-Score methodology). Outcome depends on trajectory."
    },
    {
      "id": "horizon",
      "name": "Event Horizon",
      "lowerInclusive": 1.3,
      "upperExclusive": 2.5,
      "interpretation": "Leaving is expensive and gets more expensive over time."
    },
    {
      "id": "blackhole",
      "name": "Black Hole",
      "lowerInclusive": 2.5,
      "upperExclusive": null,
      "interpretation": "Structural lock-in. Leaving requires organizational restructuring."
    }
  ],
  "zoneDerivation": {
    "derived": [
      "B = 1 is definitional: the point at which capture equals escape."
    ],
    "notDerived": [
      0.4,
      0.7,
      1.3,
      2.5
    ],
    "statedPlainly": "The four numeric boundaries have no published derivation. The Transition band cites the Altman Z-Score by analogy, which is an analogy and not a derivation. A zone chip is displayed on every ranking row, and roughly 9 per cent of platforms cross a boundary under plus-or-minus-one scoring noise. Whether these boundaries correspond to anything observable is an open question, registered as part of condition I of the research programme and not yet answered."
  },
  "declaredVariances": [
    {
      "what": "zone name of the transition band",
      "canonical": "Transition Zone",
      "variantsInUse": [
        "Transition",
        "TRANSITION",
        "TRANSITION ZONE"
      ],
      "where": "the research paper's Appendix B and its footnote; the majority of site components; several generator scripts",
      "why": "The paper is a published artefact with a DOI and is not re-issued; the site's uppercase forms are display casing. No threshold, no classification and no published number differs - only the label text. Recorded here so the inconsistency is declared rather than accidental, and so that any NEW variance fails the checker.",
      "recordedOn": "2026-09-08"
    }
  ],
  "nonBoundaryComparisons": [
    {
      "file": "scripts/validate-expansion.ts",
      "matchLine": "if (capMean > 8 && escMean > 6 && r.b < 2)",
      "value": 2.0,
      "why": "A data-entry sanity heuristic in a development script, not an interpretation boundary: it flags for human review a platform whose capture and escape are both high yet whose B is low. It sits a few lines from a zone assignment, which is why the boundary checker sees it. Declared here rather than loosening the rule, so that the boundary check stays strict and any new comparison of B against a non-canonical number has to be justified in this file.",
      "recordedOn": "2026-09-08"
    }
  ]
}
