{
  "tradefloor_version": "0.8.7",
  "source_ref": "v0.8.7",
  "describes": "0.8.7",
  "preset": "pt-v20",
  "certified_horizon_days": 252,
  "band_basis": "ruled",
  "provenance": {
    "generated_by": "tools/docs/learn/envelope.py",
    "generated_from": "tradefloor.envelope.certified()",
    "ruler": "facts.REAL_MARKETS_RULED",
    "statistics": 19,
    "in_band": 19,
    "statistics_504": 15,
    "in_band_504": 14,
    "unreadable_504": [
      "corr_persistence_acf1"
    ],
    "seed_spread": {
      "source": "re-measured on the shipped baseline preset: facts.measure() on the committed panel roster, 252 days, seeds 101-130, sample sd across seeds",
      "date": "2026-09-03",
      "model_fingerprint": "pt-v1",
      "universe_fingerprint": "9be68b9bc37e79785765df2f395a9348650a4e9293507680532293fdf78808dd",
      "days": 252,
      "seeds": [
        101,
        102,
        103,
        104,
        105,
        106,
        107,
        108,
        109,
        110,
        111,
        112,
        113,
        114,
        115,
        116,
        117,
        118,
        119,
        120,
        121,
        122,
        123,
        124,
        125,
        126,
        127,
        128,
        129,
        130
      ],
      "estimator": "sample standard deviation (n - 1) across seeds",
      "roster_note": "the roster is read from tests/fixtures/panel-roster-40.json rather than drawn by Universe.random, so this table no longer moves when the generator does. It moved once for that reason: the generator was reconciled so a drawn roster opens at its own fair value, every roster re-rolled, and all fourteen values went stale on a change that touched no coefficient and no estimator.",
      "pinned_by": "tests/test_loss.py re-measures two of the thirty seeds live and re-derives the sd from the committed per-seed table",
      "cross_check": "the base panels of a jacobian.py run on the same roster, preset, horizon and seeds hold the same thirty panels to the bit, all 420 values",
      "cross_check_detects": "a transcription error in a hand-maintained block of 420 floats, and a platform or interpreter difference when the two sides are run on different machines",
      "cross_check_cannot_detect": "an estimator defect. Both sides call facts.measure and derive the scale through loss.seed_sd_from_panels, so they share the estimator and cannot disagree about it. A genuinely independent check would be a second estimator written against the recorded bars, which does not exist.",
      "cross_check_caveat": "this pair is bit-exact and single-platform. The pair it replaces agreed to six significant figures and spanned two platforms, macOS arm64 under CPython 3.11.15 against a table measured elsewhere, so it also carried evidence about portability that this one does not. The market is bit-reproducible across platforms and the statistics derived from it are not: the same panel under CPython 3.11.16 on Linux and 3.13.12 on Windows differs by up to 8.4e-15 relative on excess kurtosis while all three known-answer digests match.",
      "companion_not_re_measured": "the envelope module's measured tables were taken on the superseded roster and have not been re-measured on this one. SEED_SD_504 was, on 2026-09-06, by the protocol above with the horizon changed and nothing else.",
      "volume_rows": {
        "date": "2026-09-30",
        "rows": [
          "volume_abs_return_corr",
          "volume_change_acf1"
        ],
        "reason": "Engine.bars() bar volume fixed in 0.8.5: a bar's volume is the running total at its last tick minus the total before its first",
        "protocol": "unchanged: pt-v1, the committed panel roster, seeds 101-130, 252 and 504 days, sample sd",
        "before_252": {
          "volume_abs_return_corr": 0.0415843,
          "volume_change_acf1": 0.0107678
        },
        "before_504": {
          "volume_abs_return_corr": 0.01899405944,
          "volume_change_acf1": 0.008456262085
        },
        "median_252": {
          "volume_abs_return_corr": [
            0.5727,
            0.7611
          ],
          "volume_change_acf1": [
            -0.4484,
            -0.439
          ]
        },
        "median_504": {
          "volume_abs_return_corr": [
            0.6035,
            0.7595
          ],
          "volume_change_acf1": [
            -0.4371,
            -0.4293
          ]
        },
        "median_note": "thirty-seed medians at pt-v1, before and after"
      }
    },
    "seed_spread_504": {
      "source": "facts.measure() at pt-v1 on the committed forty-name panel roster, 504 days, seeds 101-130, sample sd across seeds. The 252-day companion's protocol with the horizon changed and nothing else, so the two tables are a same-source pair for the first time",
      "date": "2026-09-06",
      "model_fingerprint": "pt-v1",
      "universe_fingerprint": "9be68b9bc37e79785765df2f395a9348650a4e9293507680532293fdf78808dd",
      "days": 504,
      "seeds": [
        101,
        102,
        103,
        104,
        105,
        106,
        107,
        108,
        109,
        110,
        111,
        112,
        113,
        114,
        115,
        116,
        117,
        118,
        119,
        120,
        121,
        122,
        123,
        124,
        125,
        126,
        127,
        128,
        129,
        130
      ],
      "estimator": "sample standard deviation (n - 1) across seeds",
      "script": "facts.measure() over the thirty seeds at 504 days on a cloud box; the script is in the project's unpublished design notes",
      "measured_at_commit": "2bfb2dbf56b2444f25cc78cd2961bcf152e1cd5b",
      "relative_standard_error": 0.13130643285972254,
      "relative_standard_error_identity": "1 / sqrt(2 * (n - 1)), n = 30",
      "instrument_check": "the same run's 252-day arm reproduces facts.SEED_SD to 4.5e-06 relative on its worst row",
      "roster_note": "the roster is read from tests/fixtures/panel-roster-40.json rather than drawn by Universe.random, so this table no longer moves when the generator does. That is exactly what happened to the table this replaces",
      "pinned_by": "tests/test_loss.py re-measures two of the thirty seeds live at 504 days and re-derives the sd from the committed per-seed table",
      "bands": "facts.REAL_MARKETS_504, from the five non-crisis 505-bar windows of the same forty-name reference roster; unchanged by this measurement",
      "supersedes": {
        "date": "2026-08-23",
        "model_fingerprint": "pt-v3",
        "universe": "Universe.random(40, seed=111) on the generator before the 2026-09-03 reconciliation, roster fingerprint 5d8de78b",
        "why": "two eras of preset and a retired roster, bound by nothing but a max-ordering assert"
      }
    }
  },
  "statistics": {
    "annualised_vol_pct": {
      "measured": 20.5456,
      "band": [
        12.0,
        41.0
      ],
      "in_band": true,
      "group": "shape"
    },
    "excess_kurtosis": {
      "measured": 18.1072,
      "band": [
        -13.0,
        24.0
      ],
      "in_band": true,
      "group": "shape"
    },
    "return_acf1": {
      "measured": 0.013,
      "band": [
        -0.07,
        0.06
      ],
      "in_band": true,
      "group": "shape"
    },
    "abs_return_acf1": {
      "measured": 0.0282,
      "band": [
        0.02,
        0.17
      ],
      "in_band": true,
      "group": "shape"
    },
    "abs_return_acf5": {
      "measured": 0.0188,
      "band": [
        -0.03,
        0.1
      ],
      "in_band": true,
      "group": "shape"
    },
    "abs_return_acf20": {
      "measured": 0.0044,
      "band": [
        -0.05,
        0.06
      ],
      "in_band": true,
      "group": "shape"
    },
    "cross_sectional_corr": {
      "measured": 0.3053,
      "band": [
        0.09,
        0.49
      ],
      "in_band": true,
      "group": "shape"
    },
    "volume_abs_return_corr": {
      "measured": 0.5958,
      "band": [
        0.35,
        0.64
      ],
      "in_band": true,
      "group": "shape"
    },
    "leverage_effect": {
      "measured": -0.0341,
      "band": [
        -0.11,
        0.0
      ],
      "in_band": true,
      "group": "shape"
    },
    "volume_change_acf1": {
      "measured": -0.2681,
      "band": [
        -0.3,
        -0.2
      ],
      "in_band": true,
      "group": "shape"
    },
    "corr_asymmetry": {
      "measured": 0.0791,
      "band": [
        -0.15,
        0.23
      ],
      "in_band": true,
      "group": "shape"
    },
    "corr_asymmetry_lagged": {
      "measured": 0.086,
      "band": [
        -0.15,
        0.33
      ],
      "in_band": true,
      "group": "shape"
    },
    "sector_excess_corr": {
      "measured": 0.1165,
      "band": [
        0.04,
        0.23
      ],
      "in_band": true,
      "group": "shape"
    },
    "corr_persistence_acf1": {
      "measured": 0.2303,
      "band": [
        -0.48,
        0.69
      ],
      "in_band": true,
      "group": "shape"
    },
    "crisis_sector_dispersion": {
      "measured": 1.304,
      "band": [
        0.79,
        1.74
      ],
      "in_band": true,
      "group": "dispersion"
    },
    "index_drift_pct": {
      "measured": 7.6957,
      "band": [
        1.1,
        10.3
      ],
      "in_band": true,
      "group": "level"
    },
    "fear_gauge_dn1": {
      "measured": 1.6594,
      "band": [
        0.39,
        3.03
      ],
      "in_band": true,
      "group": "crisis"
    },
    "fear_gauge_dn3": {
      "measured": 4.2616,
      "band": [
        2.6,
        9.58
      ],
      "in_band": true,
      "group": "crisis"
    },
    "index_tail_dn3_pct": {
      "measured": 0.8898,
      "band": [
        0.64,
        2.34
      ],
      "in_band": true,
      "group": "crisis"
    }
  },
  "measured_504": {
    "annualised_vol_pct": {
      "measured": 21.1128,
      "band": [
        12.0,
        40.0
      ],
      "in_band": true
    },
    "excess_kurtosis": {
      "measured": 19.2141,
      "band": [
        -9.3,
        24.0
      ],
      "in_band": true
    },
    "return_acf1": {
      "measured": 0.025,
      "band": [
        -0.05,
        0.05
      ],
      "in_band": true
    },
    "abs_return_acf1": {
      "measured": 0.0384,
      "band": [
        0.01,
        0.19
      ],
      "in_band": true
    },
    "abs_return_acf5": {
      "measured": 0.0246,
      "band": [
        -0.01,
        0.11
      ],
      "in_band": true
    },
    "abs_return_acf20": {
      "measured": 0.0092,
      "band": [
        -0.01,
        0.07
      ],
      "in_band": true
    },
    "cross_sectional_corr": {
      "measured": 0.3116,
      "band": [
        0.11,
        0.52
      ],
      "in_band": true
    },
    "volume_abs_return_corr": {
      "measured": 0.6266,
      "band": [
        0.34,
        0.63
      ],
      "in_band": true
    },
    "leverage_effect": {
      "measured": -0.0365,
      "band": [
        -0.1,
        0.02
      ],
      "in_band": true
    },
    "volume_change_acf1": {
      "measured": -0.2606,
      "band": [
        -0.3,
        -0.2
      ],
      "in_band": true
    },
    "corr_asymmetry": {
      "measured": 0.0489,
      "band": [
        -0.06,
        0.21
      ],
      "in_band": true
    },
    "corr_asymmetry_lagged": {
      "measured": 0.0842,
      "band": [
        -0.12,
        0.32
      ],
      "in_band": true
    },
    "sector_excess_corr": {
      "measured": 0.1102,
      "band": [
        0.06,
        0.21
      ],
      "in_band": true
    },
    "corr_persistence_acf1": {
      "measured": 0.2778,
      "band": null,
      "in_band": null
    },
    "crisis_sector_dispersion": {
      "measured": 1.6591,
      "band": [
        1.03,
        1.66
      ],
      "in_band": true
    }
  },
  "gaps": [
    {
      "id": "horizon",
      "summary": "the certified horizon is 252 days",
      "detail": "Against bands re-derived at the matching window, the shipped pt-v20 holds all thirteen readable rows at 504 days on the ruled band, as pt-v19 did. corr_persistence_acf1 has no ruled band there.\n\nThe certified horizon stays at 252 days because CERTIFIED, the table this module certifies, is measured at 252 days on thirty seeds. The 504-day table is measured and not certified. Headroom no longer argues for the limit: annualised_vol_pct reads 21.1128 at 504 days on pt-v20, 12.89 inside its band (pt-v19: 22.5804 and 11.42).\n\nNothing runs away over ten years. Clustering at lags one and five stays inside its ruled bands at every horizon measured, though below real markets at every lag. The decay curve is the defect past a year, and the decay-shape gap carries it.\n\nThe longer horizons are measured on pt-v20. tools/calibration/long_horizon.py runs 756, 1260 and 2520 days on thirty seeds. At every one of them the panel holds all 13 shape rows the ruled 504-day bands can grade. On the 2015-2025 504-day bands it holds 12 of 14 at 2520 days, missing sector_excess_corr at 0.1091 against a floor of 0.11 and corr_persistence_acf1 at 0.4901 against a ceiling of 0.49. pt-v19 held all thirteen on the ruled bands and 12 of 14 on the decade bands, missing sector_excess_corr at 0.0864 and corr_persistence_acf1 at 0.6377. Both rulers are 504-day bands, quoted at ten years only because no ten-year bands have been derived. tools/calibration/memory_vs_drift.py reads annualised volatility year by year over ten years on twenty seeds, and needs no band: on pt-v20 20.1, 19.9, 20.9, 20.2, 20.4, 21.4, 20.4, 22.4, 20.4 and 19.1 percent, so volatility wanders without a trend and ends 5 per cent below year one. pt-v19 read 22.1, 21.1, 20.6, 20.3, 21.2, 21.8, 19.4, 19.6, 18.7 and 17.8, easing by about a fifth.\n\nFor the shipped preset's own long run, `preset_record()[\"long_run\"]` carries thirty 21-year histories scored against 40 long-run criteria. So a five-year study is reading numbers that exist and are published. What it does not have is a band derived at its own horizon, and no committed tool derives one. That keeps the certification at 252 days.",
      "forbids": "multi-year backtests, and anything keyed on volatility dynamics beyond one year",
      "statistics": [
        "abs_return_acf1",
        "abs_return_acf5",
        "return_acf1",
        "excess_kurtosis"
      ],
      "beyond_days": 252,
      "closed_by": []
    },
    {
      "id": "decay-shape",
      "summary": "volatility memory is weaker than real at every lag",
      "detail": "The model reads BELOW real markets at every measured lag, 0.0282 against 0.1071 at lag 1 and 0.0044 against 0.0286 at lag 20: about a quarter of real at lag 1, a third at lag 5 and a sixth at lags 8 and 20. abs_return_acf1 and abs_return_acf5 sit inside their bands and below every real 2015-2025 one-year window, so a question on clustering over one to five days meets this gap as well as one on lag 20. The memory is positive by more than one standard error to lag 20, though past lag 5 only just, indistinguishable from zero at lag 30, and resolved negative at lags 45 and 60, where real markets remain weakly positive to lag 60. The log-log slope over lags 1 to 20 is -0.676 +/- 0.188 against real markets' -0.436, about 1.3 standard errors steeper and not resolved as different, so the slope does not separate the model from a real market at thirty seeds and the level does. Measured on pt-v20, thirty seeds on the certified protocol (envelope.DECAY_252). pt-v19 read 0.0486 at lag 1 and 0.0085 at lag 20, about half of real through lag 8, negative at lags 45 and 60 by about 1.3 standard errors each, and a slope of -0.515 +/- 0.109, inside one standard error of real.\n\nThis is a mechanism gap and not a calibration one. The process is built from exponentials, and over one year two of them fake a power law well enough that no panel statistic objects. Past lag 20 a sum of exponentials dies out where a power law persists, which is the tail above. A two-component mixture was tried and is not sufficient.\n\nThe model has two timescales. De-trending |r| by a centred 252-day rolling mean over 2520 days on twenty seeds, pt-v20 keeps 54% of its lag-1 autocorrelation, 47% of lag 5 and 17% of lag 20. Lags 1 and 5 are memory from the GJR recursion. Lag 20 is mostly a slowly varying variance level fed by the VIX and business-cycle channels, and that level has no trend: annualised volatility wanders between 19.1% and 22.4% from year to year over ten years and ends 5 per cent below year one. The raw log-log slope at 2520 days reads -0.166 and the de-trended one -0.329, both flatter than real's -0.436, so a long estimator adds regime variation on top of the defect and does not cure it. pt-v19 on the same tool kept 61%, 52% and 28%, and read -0.163 raw and -0.338 de-trended.\n\nSo the target is to make the FAST component decay hyperbolically rather than exponentially. Long memory is already present and does its job at lag 20.\n\nThe slope alone is not the target. On pt-v12, turning on the market factor's slow variance component improved the log-log slope from -0.716 to -0.504 by LOWERING lag-1 autocorrelation from 0.1107 to 0.0693, while lag 20 did not move at all. A flatter line through a lower point is a better slope and a worse market. Real markets have both short-lag clustering, `abs_return_acf1` inside 0.02 to 0.17 on the ruled bands, and weakly positive autocorrelation out to lag 60, and the slope can be improved by destroying the level. pt-v19 was that case: its slope sat inside real's error and its lag-1 reading was less than half of real's. pt-v20 is further off on both: its slope sits about 1.3 standard errors steeper than real's and its lag-1 reading is about a quarter of real's. Work on this gap at lag 20 and beyond WITH LAG 1 HELD, never on the slope alone. The same pt-v12 run cost `excess_kurtosis` its 504-day band on five arms of six, because a smoother variance has thinner tails.\n\nThe claim is about this model's parameters: no setting of them turns its memory into a power law's, because a sum of exponentials is not a power law. Closing this gap needs a new mechanism, and tuning the existing dials will not do it.",
      "forbids": "strategies whose edge depends on volatility clustering at any lag: volatility forecasts over one to five days, and vol targeting and risk parity on a one-month or longer estimate",
      "statistics": [
        "abs_return_acf1",
        "abs_return_acf5",
        "abs_return_acf20"
      ],
      "beyond_days": null,
      "closed_by": []
    },
    {
      "id": "scenario-magnitude",
      "summary": "a driven scenario moves prices at a quarter to a half of the real size",
      "detail": "On pt-v20 a driven scenario moves prices in the direction theory fixes and at a quarter to a half of the size real markets showed (pt-v19: about a fifth), and the spread of daily returns around that response is close to real.\n\nThe steady-state lever, how much more violent a sustained crisis is than a calm market, reads 5.22x on pt-v19 against real markets' 6.16x, measured from a held VIX 5 to a held VIX 65 on the certified 40-name roster over 252 days at thirty seeds, after 252 discarded sessions at each pin (17.36 per cent annualised at the low pin, 90.65 at the high one). On the same method the records read pt-v18 7.06x, pt-v16 6.50x, pt-v14 6.19x, pt-v10 5.04x and pt-v3 3.08x. pt-v19 sits 15 per cent below real, where pt-v18 sat 15 per cent above, because the VIX level identity reads the market's variance target against a derived anchor rather than the dial's, so a held VIX 65 is a smaller multiple of it. A crisis held at a fixed fear level is somewhat milder here than in a real market.\n\nThe driven window is measured rather than asserted. It drives the real 2020-21 macro path (the VIX, the policy rate, a credit yield converted from the high-yield bond fund HYG, 5.54% rising to 11.4%, and the valuation proxy) through a roster of a simulated AAPL on its FY2019 accounts and 39 generated names, and compares the simulated AAPL's 504 daily returns with real AAPL's over the same window. Measured on pt-v20, the median of seven seeds (2020 and 101 to 106), with pt-v19 re-run beside it on the same build:\n  OLS slope of return on the driver's daily change\n    VIX                          -0.00134 (pt-v19 -0.00083, real -0.00500)\n    credit yield                 -3.521   (pt-v19 -1.565, real -7.445)\n    valuation proxy              +0.334   (pt-v19 +0.159, real +1.272)\n  correlation with the driver's daily change\n    VIX                          -0.135   (pt-v19 -0.092, real -0.622)\n    credit yield                 -0.238   (pt-v19 -0.127, real -0.592)\n    valuation proxy              +0.175   (pt-v19 +0.088, real +0.803)\n  absolute return vs VIX level   +0.405   (pt-v19 +0.332, real +0.489)\n\nEvery slope carries the sign theory fixes on all seven seeds. The gains are 0.27, 0.47 and 0.26 of real, so the credit response is about half of real and the other two about a quarter. pt-v19 reads 0.17, 0.21 and 0.13, and pt-v18 0.14, 0.23 and 0.14 on the same seeds. The valuation input moves nothing on pt-v16 and later, because qe_pe_gain is 0.0 there, so its slope reads what the other drivers did on the same days. The simulated AAPL's daily return sd is 1.20x real AAPL's (1.08 to 1.33 across the seeds; pt-v19 1.10x, 0.98 to 1.25; pt-v18 1.15x), so the spread is close to real and the response inside it is still small. The same script reproduces pt-v12's published gains, -0.00520, -8.194 and +1.192 with an sd ratio of 1.573, all within ten per cent of real, so the difference between presets is in the model and the method is the same.\n\nTHE RESPONSE ARRIVES THROUGH THE CREDIT LEG. Notebook 09 drives Moody's Baa (FRED DBAA, 3.86% to a 5.15% peak), the yield the model discounts at, and the NBER phases as the cycle. On that path, with the same seeds and regressions on the same build, pt-v20's VIX slope reads -0.00001, 0.003 of real, and its valuation slope -0.029, and real AAPL's slope on Baa's daily change is +0.395 at a correlation of +0.009, so the credit leg has no real response to be compared with. The phases change little: the HYG path with them reads gains of 0.25, 0.44 and 0.24, and Baa without them 0.02 on the VIX. So the quarter to a half above is what a credit leg that moves daily with the VIX carries into prices. On a scenario whose credit yield barely moves, the simulated AAPL's daily return hardly follows the VIX's daily change, through March 2020 included, though the spread of its returns still widens with the VIX. The sd ratio is 1.15x on the Baa path.\n\nAn event study over the five sessions after each of six dated 2020-21 events agrees on sign four times out of six on pt-v20 at seed 2020, three times on pt-v19 and twice on pt-v12, which is what the notebook prints for the preset it pins. Over the seven seeds pt-v20 agrees on 3 to 6 of the six (pt-v19: 2 to 5). The Fed's intermeeting cut of 3 March 2020 goes the wrong way, +11.0% on pt-v20 (pt-v19 +15.2%) against AAPL's -1.4%, because an announcement-effect channel is absent rather than miscalibrated. The VIX record close of 16 March agrees on pt-v20, -2.2% against -7.4%, where pt-v19 read +8.6%. The vaccine result and Omicron are single-name Apple news, which a run driven only by a macro path cannot know, so Omicron's agreement (+0.9% on pt-v20 and +0.7% on pt-v19, against +3.2%) is chance. The two that agree on all three presets are the two the macro path carries.\n\nSector structure is the same shortfall measured a second way, and whether it is closed turns on the BAND BASIS rather than on the model. In calm markets the shipped preset reads 0.1165 at 252 days (inside (0.11, 0.23)) and 0.1102 at 504 days (inside (0.11, 0.22)) against the 2015-2025 bands these tables carry. Against the wider 1987-2025 band, whose floor is 0.04 at 252 days and 0.06 at 504, the same two readings are inside at both horizons. Which band applies is still open, so a reader who needs this row should read both numbers and the band they're graded against.\n\nThe crisis shape is right from pt-v11 on. Under a held VIX 45 pt-v12 reads a sector excess correlation of +0.109 against a real +0.103, and crisis co-movement reads 0.696 against a real 0.664 to 0.727. What remains in this gap is the size of the driven response above, which is about sizing a scenario rather than about structure.",
      "forbids": "sizing a scenario's impact rather than detecting it",
      "statistics": [],
      "beyond_days": null,
      "closed_by": []
    },
    {
      "id": "macro-range",
      "summary": "the endogenous macro state cannot reach its own crisis regimes",
      "detail": "Left to itself the economy stays in a moderate band, and two consequences follow that are easy to mistake for defects.\n\nINFLATION. Measured over thirty seeds and five years on the shipped pt-v20 (tools/calibration/macro_range.py, seeds 101 to 130), endogenous inflation peaks at a median 3.0%, passes 4% on 4 seeds of 30 and never reaches 4.2% (its highest is 4.18%), with a median sd of 0.62 around a mean of 2.5% and monthly AR(1) 0.957. pt-v19 on the same tool and seeds, re-run on the same build: a median peak of 3.1%, 2 seeds of 30 past 4%, a highest of 4.16%, sd 0.59, mean 2.7%, AR(1) 0.922. US CPI year-on-year 2015-2025 (FRED CPIAUCSL) has mean 2.87, sd 2.18, a peak of 9.0% in June 2022 and monthly AR(1) 0.978. So the mean is close to real and the range is narrow. The cap is the inflation update's mean reversion, 0.55 of the gap to target each month, a half-life under a month. That coefficient and the 6.0% clamp are dials since 0.1.4, `inflation_reversion` and `inflation_ceiling`, shipped at the old values so every preset reproduces. Measured: at reversion 0.15 the endogenous series matches the real mean and sd to the second decimal (2.85 / 2.10 against 2.87 / 2.18) and then sits on the clamps; persistence does not move with the dial because it comes from the cycle, wages and unemployment. No preset takes either dial yet, because what a real inflation range does to the equity panel has not been scored, so this gap stands.\n\nTHE CENTRAL BANK'S CRISIS CADENCE. The bank pulls its next meeting in to 21-30 days when a decision leaves it more than 2pp behind an inflation rate above 4%. That path is correct and well exercised, firing in 22.0% of the 11,898 central-bank cases in the parity corpus, but a default run cannot reach it because inflation does not get there: on pt-v20 its condition held on none of the 37,800 simulated days above, as on pt-v19. It also fires in STAGFLATION rather than in high inflation as such: at inflation 4.5% with unemployment 9.0% the bank cuts for the output gap and leaves itself further behind, so pinning inflation high with unemployment low will not trigger it however high you pin it.\n\nSo a 2022-style inflation shock has to be driven through a scenario. It will not arise on its own, and neither will the policy response to it.\n\nDRIVING ONE WORKS, and the lever is inflation rather than the policy rate. Measured on real 2022 data over six seeds, against a real S&P of -20.0%: a scenario driving `inflation_rate` with the published CPI path returns a median -23.3%, where the same run with no scenario at all returns -12.6% and one driving only `federal_funds_rate` with the real seven-hike path returns -13.1%, which is the drift and nothing more. Inflation works because it steers the bank's own reaction into the corporate bond yield; an externally pinned policy rate does not reproduce that. Leave `corporate_bond_yield` FREE when doing this, since pinning it severs the very channel the inflation path is using.",
      "forbids": "studying inflation regimes or policy crises from the endogenous economy alone",
      "statistics": [],
      "beyond_days": null,
      "closed_by": []
    },
    {
      "id": "roster-concentration",
      "summary": "a concentrated roster is measured on pt-v19 only, for four sector mixes and the shape rows",
      "detail": "`Universe.random()` assigns sectors round-robin over the twelve in `sectors.SECTORS`, so a roster is as close to balanced as its size allows: the certified 40 names put four in each of four sectors and three in each of the other eight. No real index is balanced that way. The S&P is roughly a third technology and the Nasdaq more so.\n\nMeasured on pt-v19: the certified roster relabelled to four concentrated mixes (`ROSTER_SHAPES`), thirty seeds (101 to 130), 252 and 504 days, graded on the ruled bands `score` uses by default. The tool is tools/calibration/roster_shapes.py and its output is measurements/roster-shapes-pt-v19.json. The table gives each mix's shape rows in band and its cross-sectional correlation:\n\n                      252d     504d   xs corr 252d / 504d\n  balanced           14/14    13/13   0.3063 / 0.2966\n  S&P-like           14/14    13/13   0.3085 / 0.3008\n  technology-heavy   14/14    13/13   0.3208 / 0.3164\n  all-technology     13/13    12/12   0.3751 / 0.3933\n  defensive          14/14    13/13   0.3172 / 0.3212\n\nThe 504-day counts are over thirteen rows because corr_persistence_acf1 has no ruled band there. The all-technology counts are one lower again because sector_excess_corr is undefined with one sector: it asks how far a name moves with its own industry beyond the market, and with one sector the two are the same. On the 2015-2025 decade bands every mix but all-technology misses sector_excess_corr at both horizons, as the balanced roster does, and no other shape row. Cross-sectional correlation rises with concentration, 0.3063 balanced to 0.3751 all-technology at 252 days, and stays inside its band.\n\n`check` accepts a roster named as one of the four mixes, for example `sector_concentrated=\"tech_heavy\"`, when the question names pt-v19 as its preset (`preset=\"pt-v19\"`), the horizon is 504 days or less, and every named statistic is a shape row that mix held at that horizon (`ROSTER_SHAPE_ROWS`). The default has been pt-v20 since 0.8.5. The same run on pt-v20 (measurements/roster-shapes-pt-v20.json) held every shape row the bands could grade at 252 days for all four mixes, but at 504 days the S&P-like and technology-heavy mixes read volume_abs_return_corr at 0.6367 and 0.6332 against a ceiling of 0.63, where the balanced roster reads 0.6266. So the mixes do not hold on pt-v20 as they did on pt-v19, and `check` refuses a concentrated roster on pt-v20, and on any preset but pt-v19, and says the grant is measured on pt-v19 only. Two limits remain and come back as warnings: each mix is one roster draw, and the bands come from broad real-market windows, so a single-sector portfolio is graded on a broad market's ruler.\n\n`check` still refuses the rest. `sector_concentrated=True` does not say which mix the roster is, and no mix outside the four was measured. A question that names no statistics may lean on a level or crisis row. The level and crisis rows are certified on facts.LEVEL_PROTOCOL, where the roster varies with the seed, and this tool holds one roster. On that one roster index_drift_pct read 4.85 balanced and 18.21 to 52.74 for the concentrated mixes at 252 days, against a ruled band of 1.1 to 10.3 (`ROSTER_INDEX_DRIFT`). sector_excess_corr on an all-technology roster and corr_persistence_acf1 past 252 days were not graded, for the reasons above. Neither run went past 504 days.",
      "forbids": "citing the certification for a concentrated roster on a level or crisis row, past 504 days, on any preset but pt-v19 (the default pt-v20 included), or for a sector mix other than the four measured",
      "statistics": [
        "index_drift_pct",
        "fear_gauge_dn1",
        "fear_gauge_dn3",
        "index_tail_dn3_pct",
        "sector_excess_corr"
      ],
      "beyond_days": null,
      "closed_by": []
    }
  ]
}
