ASSEMBLY-WP-0017 finished: IMM filter on observed US data (B3 through mid-2026, B3→B4 flip candidate Q3 2026, not confirmed), robustness, checkpoint pointer; residual to WP-0015-T07
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Assistant: claude-code Assistant-Model: opus Assistant-Process: 14913@bnt-lap001 Assistant-Session: add7ef69-b901-4756-9a67-34cf1125d96f
This commit is contained in:
parent
97d0fb71a9
commit
945b28e6ab
8 changed files with 239 additions and 16 deletions
|
|
@ -159,6 +159,9 @@ def render(day: date, kind: str, phase: str, obs: list[dict], assess: str | None
|
|||
"## Follow-ups", "",
|
||||
"- Band positions against registered predictions (`predictions.md`) are judged at review"
|
||||
if preds else "- No predictions registered yet; band positions follow once the register has entries.",
|
||||
*(["- Current regime per jurisdiction and flip candidates: `simulations/gadm02/results/matching.md`"
|
||||
" (model matching, re-run at the review of this checkpoint; not computed by this runner)"]
|
||||
if kind == "full" else []),
|
||||
""]
|
||||
return "\n".join(lines)
|
||||
|
||||
|
|
|
|||
|
|
@ -35,6 +35,14 @@ class TestPredictions(unittest.TestCase):
|
|||
self.assertEqual(rc.band_position(preds, "L9", "US"), "no prediction registered")
|
||||
|
||||
|
||||
class TestRegimePointer(unittest.TestCase):
|
||||
def test_full_record_points_to_regime_report(self):
|
||||
full = rc.render(date(2027, 1, 15), "full", "steady", [], None, "x", "d.jsonl")
|
||||
light = rc.render(date(2027, 1, 15), "light", "steady", [], None, "x", "d.jsonl")
|
||||
self.assertIn("results/matching.md", full)
|
||||
self.assertNotIn("results/matching.md", light)
|
||||
|
||||
|
||||
class TestNumberGuard(unittest.TestCase):
|
||||
def test_numbers_extraction(self):
|
||||
self.assertEqual(rc._numbers("EU at 19.95 % in 2025, US 23.8."), {"19.95", "2025", "23.8"})
|
||||
|
|
|
|||
|
|
@ -3,9 +3,10 @@
|
|||
Regime changes of jurisdictions, detected by model matching
|
||||
(`research/ModelMatching.md` § 3). **Never edit or delete an entry.**
|
||||
|
||||
**Status 2026-10-13:** no entries. Flip detection has not passed its
|
||||
synthetic test (`research/ModelMatching.md` § 4), so no measured flip may be
|
||||
recorded yet. Simulated flips (regime crossings inside model runs) are
|
||||
**Status 2026-10-13:** no entries. The filter passed its synthetic test
|
||||
(`research/ModelMatching.md` § 4.2). Its observation noise for real data is
|
||||
not yet calibrated (WP-0015-T07), so a candidate on the watch list needs
|
||||
confirmation at the next review. Simulated flips (regime crossings inside model runs) are
|
||||
recorded in the break register until then (for example BR-005).
|
||||
|
||||
## Entry format
|
||||
|
|
@ -17,6 +18,16 @@ recorded in the break register until then (for example BR-005).
|
|||
- Consequences: predictions superseded (ids), break-register links
|
||||
```
|
||||
|
||||
## Watch list (candidates, not entries)
|
||||
|
||||
Candidates seen in one evaluation. They become entries only when the rule in
|
||||
`research/ModelMatching.md` § 3 is met (new anchor ≥ 0.75 in two consecutive
|
||||
quarters, filter acceptance passed).
|
||||
|
||||
| Seen | Jurisdiction | Candidate | Evidence | Check at |
|
||||
|---|---|---|---|---|
|
||||
| 2026-10-13 (data to Q3 2026) | US | B3 → B4 | IMM last quarter B4 1.00 (noise × 2: 0.96; × 3: 0.42; without investment 0.69); BTOS 21.8 → 23.8 % in two months; data-center construction +20 % in four months | next review with Q4 2026 data |
|
||||
|
||||
## Entries
|
||||
|
||||
(none)
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
# Model matching and regime flipping
|
||||
|
||||
**Status:** v0.3 (2026-10-13), ASSEMBLY-WP-0012 and WP-0017. The IMM filter
|
||||
passes its synthetic acceptance test (§ 4.2) under two caveats: a perfect
|
||||
model, and an investment indicator that the real data provide only roughly.
|
||||
Measured flips may be declared only after an AI-specific investment series is
|
||||
in place (WP-0017-T06).
|
||||
**Status:** v0.4 (2026-10-13), ASSEMBLY-WP-0012 and WP-0017. The IMM filter
|
||||
passes its synthetic acceptance test (§ 4.2). It runs on the observed US
|
||||
series (§ 4.3). There it is overconfident: its observation noise is not yet
|
||||
calibrated for real data. Its first output is a flip **candidate**
|
||||
(B3 → B4), not a flip.
|
||||
|
||||
Code: `simulations/gadm02/matching.py`. Data: `observed_series.json`.
|
||||
Results: `results/matching.md` (observed), `results/matching_synthetic.md`
|
||||
|
|
@ -182,3 +182,49 @@ Caveats:
|
|||
3. **The loop state stays undetectable while sentiment is flat.** Loop flips
|
||||
are therefore not declared from the filter at all until a sentiment shock
|
||||
gives evidence.
|
||||
|
||||
### 4.3 The filter on observed US data (WP-0017-T05)
|
||||
|
||||
`matching.py` now also runs the IMM filter on the observed US series
|
||||
(`results/matching.md`).
|
||||
|
||||
- **Calendar:** t 0 = 2025-08-01.
|
||||
- **Series:** adoption (BTOS, biweekly, 22 points after the start),
|
||||
investment (L5b, Census private office construction including data centers,
|
||||
monthly) and discovery (StatCounter, monthly).
|
||||
- **Start:** the static matching weights.
|
||||
|
||||
| Calendar t (quarter) | B2 | B3 | B4 |
|
||||
|---|---|---|---|
|
||||
| 0.32 (late Nov 2025, start) | 0.38 | 0.40 | 0.21 |
|
||||
| 0.57 | 0.00 | 1.00 | 0.00 |
|
||||
| 0.82 | 0.00 | 1.00 | 0.00 |
|
||||
| 1.07 (Q3 2026) | 0.00 | 0.00 | **1.00** |
|
||||
|
||||
Robustness of the last quarter: noise × 2: B4 0.96; noise × 3: B3 0.58 /
|
||||
B4 0.42; without investment: B4 0.69. The search share does not affect the
|
||||
result.
|
||||
|
||||
Readings:
|
||||
|
||||
1. **The US was in B3 from early to mid-2026.** B2 drops out after the first
|
||||
quarter in all variants.
|
||||
2. **Q3 2026 shows a move toward B4: a flip candidate, not a flip.** Two
|
||||
things drive it. Adoption rose from 21.8 % to 23.8 % within about two
|
||||
months, and data-center construction keeps accelerating (L5b +20 % in four
|
||||
months). The move shows without the investment series too (0.69). It is not
|
||||
robust to 3× noise. The rule needs a second quarter at ≥ 0.75, so it is
|
||||
checked at the next review (`research/FlipRegister.md`, watch list).
|
||||
3. **The filter is overconfident on real data.** Weights jump to 1.00 within
|
||||
one quarter, which a perfect-model noise level allows but real model error
|
||||
does not justify. Calibrating the observation noise against real model
|
||||
residuals is the next step (ASSEMBLY-WP-0015-T07).
|
||||
4. **Meaning for predictions:** a confirmed B4 regime would move the US
|
||||
adoption path of P-2026-001 toward the B4 band. That band peaks early and
|
||||
predicts a plateau or decline by 2030. Predictions are not changed on a
|
||||
candidate.
|
||||
|
||||
**Checkpoint integration.** Full checkpoint records point to
|
||||
`results/matching.md`, which is re-run at the review of each checkpoint. The
|
||||
unattended runner does not compute regimes, so the approved execution
|
||||
declaration stays unchanged.
|
||||
|
|
|
|||
|
|
@ -45,12 +45,21 @@ T_PATH = 30.0
|
|||
FLIP_WEIGHT = 0.75
|
||||
SWITCH = 0.02 # prior probability per quarter that the regime changes (filter)
|
||||
_CACHE: dict = {}
|
||||
_START: dict = {}
|
||||
|
||||
|
||||
def start(jur: str, anchor: str) -> tuple[dict, dict]:
|
||||
"""cd.start_state, cached (it is deterministic and slow)."""
|
||||
if (jur, anchor) not in _START:
|
||||
_START[(jur, anchor)] = cd.start_state(jur, anchor)
|
||||
p, s = _START[(jur, anchor)]
|
||||
return dict(p), dict(s)
|
||||
|
||||
|
||||
def path(jur: str, anchor: str, loop: str) -> list[dict]:
|
||||
key = (jur, anchor, loop)
|
||||
if key not in _CACHE:
|
||||
p, s = cd.start_state(jur, anchor)
|
||||
p, s = start(jur, anchor)
|
||||
_CACHE[key] = g.simulate({**p, "sent": 1.0 if loop == "on" else 0.0}, s, T=T_PATH, record_every=1)
|
||||
return _CACHE[key]
|
||||
|
||||
|
|
@ -183,6 +192,7 @@ def main_observed() -> None:
|
|||
lines += ["", f"**Best:** {fmt(b)} (weight {res[b]['w']:.2f}). Anchor weights: "
|
||||
+ ", ".join(f"{a} {w:.2f}" for a, w in anchors.items())
|
||||
+ f". Loop weights: off {loops['off']:.2f}, on {loops['on']:.2f}.", ""]
|
||||
lines += observed_imm_lines()
|
||||
(OUT / "matching.md").write_text("\n".join(lines))
|
||||
print("\n".join(lines))
|
||||
|
||||
|
|
@ -207,7 +217,7 @@ _PARAMS: dict = {}
|
|||
def regime_params(jur: str, cand: tuple) -> dict:
|
||||
"""Parameters of a regime (anchor dynamics, loop switch) for jurisdiction `jur`."""
|
||||
if (jur, cand) not in _PARAMS:
|
||||
p, _s = cd.start_state(jur, cand[0])
|
||||
p, _s = start(jur, cand[0])
|
||||
_PARAMS[(jur, cand)] = {**p, "sent": 1.0 if cand[1] == "on" else 0.0}
|
||||
return _PARAMS[(jur, cand)]
|
||||
|
||||
|
|
@ -337,10 +347,14 @@ NOISE = {"adopt": ("log", 0.03), "invest": ("log", 0.05), "pd": ("abs", 0.01), "
|
|||
CADENCE = {"adopt": 2 / 52, "invest": 0.25, "pd": 1 / 12, "sig": 0.5}
|
||||
|
||||
|
||||
NOISE_FACTOR = 1.0 # > 1 widens all observation noise (robustness against model error on real data)
|
||||
|
||||
|
||||
def obs_ll(rows: list[dict], obs: list, scales: dict) -> float:
|
||||
ll = 0.0
|
||||
for tau, kind, y in obs:
|
||||
mode, sd = NOISE[kind]
|
||||
sd *= NOISE_FACTOR
|
||||
m_ = observe(rows, tau, kind)
|
||||
if mode == "log":
|
||||
ll += -0.5 * ((math.log(y) - math.log(max(1e-9, m_)) - scales[kind]) / sd) ** 2
|
||||
|
|
@ -388,18 +402,25 @@ def imm_run(truth: list[dict], start: float, years: float, seed: int, kinds: tup
|
|||
i = min(len(rc) - 1, int(round((first[c]["t0"] + 1.0) / STEP)))
|
||||
states[c] = {k: rc[i][k] for k in g.STOCKS}
|
||||
w = {c: first[c]["w"] for c in CANDIDATES}
|
||||
evals = [(te0, {c: {"w": w[c]} for c in CANDIDATES})]
|
||||
return imm_core("US", obs, states, w, scales, te0, start + years, step, switch)
|
||||
|
||||
|
||||
def imm_core(jur: str, obs: list, states: dict, w: dict, scales: dict, t_from: float, t_to: float,
|
||||
step: float = 0.25, switch: float = None) -> list[tuple[float, dict]]:
|
||||
"""IMM steps from t_from to t_to: mix regime states, run each regime, update weights."""
|
||||
switch = IMM_SWITCH if switch is None else switch
|
||||
evals = [(t_from, {c: {"w": w[c]} for c in CANDIDATES})]
|
||||
n = len(CANDIDATES)
|
||||
pi = {(i, c): (1 - switch) if i == c else switch / (n - 1) for i in CANDIDATES for c in CANDIDATES}
|
||||
te = te0 + step
|
||||
while te <= start + years + 1e-9:
|
||||
te = t_from + step
|
||||
while te <= t_to + 1e-9:
|
||||
window = [(t - (te - step), k, y) for t, k, y in obs if te - step < t <= te + 1e-9]
|
||||
cbar = {c: sum(pi[(i, c)] * w[i] for i in CANDIDATES) for c in CANDIDATES}
|
||||
lls, ends = {}, {}
|
||||
for c in CANDIDATES:
|
||||
mu = {i: pi[(i, c)] * w[i] / cbar[c] for i in CANDIDATES}
|
||||
x0 = {k: sum(mu[i] * states[i][k] for i in CANDIDATES) for k in g.STOCKS}
|
||||
rows = g.simulate(regime_params("US", c), x0, T=step, record_every=1)
|
||||
rows = g.simulate(regime_params(jur, c), x0, T=step, record_every=1)
|
||||
lls[c] = obs_ll(rows, window, scales)
|
||||
ends[c] = {k: rows[-1][k] for k in g.STOCKS}
|
||||
mx = max(lls.values())
|
||||
|
|
@ -462,6 +483,79 @@ def main_imm() -> None:
|
|||
print("\n".join(lines))
|
||||
|
||||
|
||||
# --- WP-0017-T05: IMM filter on the observed US series --------------------------------------------
|
||||
|
||||
CAL = {"US_adoption": 0.32, "US_dc_construction": 0.0, "US_discovery": 1 / 6} # calendar offsets, t 0 = 2025-08-01
|
||||
KIND = {"US_adoption": "adopt", "US_dc_construction": "invest", "US_discovery": "pd"}
|
||||
|
||||
|
||||
def observed_imm(jur: str = "US") -> tuple[list[tuple[float, dict]], dict]:
|
||||
"""Run the IMM filter on the observed series. Returns (evaluations, info)."""
|
||||
obs = []
|
||||
for name, off in CAL.items():
|
||||
for tau, y in SERIES[name]["points"]:
|
||||
obs.append((off + tau, KIND[name], y))
|
||||
adop = SERIES["US_adoption"]
|
||||
static = score(jur, path, adop, level=cd.targets(jur)["Ko"])
|
||||
b = best(static)
|
||||
t_from = CAL["US_adoption"]
|
||||
def model_t(c, t):
|
||||
return static[c]["t0"] + (t - t_from)
|
||||
rb = path(jur, *b)
|
||||
scales = {"adopt": static[b]["ls"]}
|
||||
inv = [(t, y) for t, k, y in obs if k == "invest" and model_t(b, t) >= STEP]
|
||||
if inv:
|
||||
scales["invest"] = sum(math.log(y) - math.log(observe(rb, model_t(b, t), "invest")) for t, y in inv) / len(inv)
|
||||
states = {}
|
||||
for c in CANDIDATES:
|
||||
rc = path(jur, *c)
|
||||
i = min(len(rc) - 1, max(0, int(round(model_t(c, t_from) / STEP))))
|
||||
states[c] = {k: rc[i][k] for k in g.STOCKS}
|
||||
w = {c: static[c]["w"] for c in CANDIDATES}
|
||||
t_to = max(t for t, _k, _y in obs)
|
||||
evals = imm_core(jur, [o for o in obs if o[0] > t_from], states, w, scales, t_from, t_to)
|
||||
return evals, {"start_best": b, "scales": scales, "t_from": t_from, "t_to": t_to,
|
||||
"n_obs": {k: sum(1 for o in obs if o[1] == k and o[0] > t_from) for k in ("adopt", "invest", "pd")}}
|
||||
|
||||
|
||||
def observed_imm_lines() -> list[str]:
|
||||
evals, info = observed_imm("US")
|
||||
lines = ["## US: IMM regime filter on the observed series (WP-0017-T05)", "",
|
||||
"Calendar t 0 = 2025-08-01. Indicators: adoption (BTOS, biweekly), investment (L5b, Census private",
|
||||
"office construction incl. data centers, monthly), discovery channel (StatCounter search share,",
|
||||
f"monthly). Observations after the start: {info['n_obs']}. Start: static matching weights; quarterly",
|
||||
f"IMM steps from t {info['t_from']:.2f} to {info['t_to']:.2f}. Flips judged on anchor weights.", "",
|
||||
"| Calendar t | B1 | B2 | B3 | B4 | loop off | loop on |", "|---|---|---|---|---|---|---|"]
|
||||
for t, res in evals:
|
||||
an = marginal(res, 0)
|
||||
lp = marginal(res, 1)
|
||||
lines.append(f"| {t:.2f} | " + " | ".join(f"{an[(a,)]['w']:.2f}" for a in ("B1", "B2", "B3", "B4"))
|
||||
+ f" | {lp[('off',)]['w']:.2f} | {lp[('on',)]['w']:.2f} |")
|
||||
global NOISE_FACTOR, CAL
|
||||
rob = []
|
||||
for label, factor, drop in (("noise × 2", 2.0, None), ("noise × 3", 3.0, None), ("without investment", 1.0, "US_dc_construction")):
|
||||
keep_f, keep_cal = NOISE_FACTOR, CAL
|
||||
NOISE_FACTOR = factor
|
||||
CAL = {k: v for k, v in CAL.items() if k != drop}
|
||||
ev2, _i = observed_imm("US")
|
||||
NOISE_FACTOR, CAL = keep_f, keep_cal
|
||||
an2 = marginal(ev2[-1][1], 0)
|
||||
rob.append(f"| {label} | " + " | ".join(f"{an2[(a,)]['w']:.2f}" for a in ("B1", "B2", "B3", "B4")) + " |")
|
||||
lines += ["", "Robustness of the last evaluation (anchor weights):", "", "| Variant | B1 | B2 | B3 | B4 |",
|
||||
"|---|---|---|---|---|", *rob]
|
||||
fl = flips(evals, by=0)
|
||||
an = marginal(evals[-1][1], 0)
|
||||
top = max(an, key=lambda k: an[k]["w"])
|
||||
prev = marginal(evals[-2][1], 0)
|
||||
ptop = max(prev, key=lambda k: prev[k]["w"])
|
||||
lines += ["", f"**Last evaluation (US):** anchor {top[0]} with weight {an[top]['w']:.2f}; previous quarter "
|
||||
f"{ptop[0]} {prev[ptop]['w']:.2f}. A flip needs the new anchor at ≥ {FLIP_WEIGHT} in two consecutive "
|
||||
"quarters; a change seen in one quarter is a **flip candidate** to check at the next review."
|
||||
+ (" Confirmed flips: " + "; ".join(f"{t:.2f}: {a[0]} → {b_[0]}" for t, a, b_ in fl) if fl else
|
||||
" Confirmed flips: none."), ""]
|
||||
return lines
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
if "--imm" in sys.argv:
|
||||
main_imm()
|
||||
|
|
|
|||
|
|
@ -56,3 +56,27 @@ Series: Eurostat isoc_eb_ai, DE, reference years 2023-2025 (2021: 10.56, exclude
|
|||
| B1/loop on | -43.5 | 0.000 | 0.00 | 0.059 |
|
||||
|
||||
**Best:** B3/loop on (weight 0.29). Anchor weights: B1 0.00, B2 0.44, B3 0.56, B4 0.00. Loop weights: off 0.49, on 0.51.
|
||||
|
||||
## US: IMM regime filter on the observed series (WP-0017-T05)
|
||||
|
||||
Calendar t 0 = 2025-08-01. Indicators: adoption (BTOS, biweekly), investment (L5b, Census private
|
||||
office construction incl. data centers, monthly), discovery channel (StatCounter search share,
|
||||
monthly). Observations after the start: {'adopt': 22, 'invest': 5, 'pd': 10}. Start: static matching weights; quarterly
|
||||
IMM steps from t 0.32 to 1.17. Flips judged on anchor weights.
|
||||
|
||||
| Calendar t | B1 | B2 | B3 | B4 | loop off | loop on |
|
||||
|---|---|---|---|---|---|---|
|
||||
| 0.32 | 0.00 | 0.38 | 0.40 | 0.21 | 0.52 | 0.48 |
|
||||
| 0.57 | 0.00 | 0.00 | 1.00 | 0.00 | 0.70 | 0.30 |
|
||||
| 0.82 | 0.00 | 0.00 | 1.00 | 0.00 | 0.77 | 0.23 |
|
||||
| 1.07 | 0.00 | 0.00 | 0.00 | 1.00 | 0.49 | 0.51 |
|
||||
|
||||
Robustness of the last evaluation (anchor weights):
|
||||
|
||||
| Variant | B1 | B2 | B3 | B4 |
|
||||
|---|---|---|---|---|
|
||||
| noise × 2 | 0.00 | 0.00 | 0.04 | 0.96 |
|
||||
| noise × 3 | 0.00 | 0.00 | 0.58 | 0.42 |
|
||||
| without investment | 0.00 | 0.00 | 0.31 | 0.69 |
|
||||
|
||||
**Last evaluation (US):** anchor B4 with weight 1.00; previous quarter B3 1.00. A flip needs the new anchor at ≥ 0.75 in two consecutive quarters; a change seen in one quarter is a **flip candidate** to check at the next review. Confirmed flips: none.
|
||||
|
|
|
|||
|
|
@ -156,3 +156,24 @@ Waits for data that does not exist yet as of 2026-10-13.
|
|||
Then re-calibrate (`models/Calibration.md` § 5) and check whether readings
|
||||
R1–R4 change. Also verify the secondary-source figures marked in
|
||||
`checkpoints/2026/2026-10-13-review.md` against their originals.
|
||||
|
||||
## Regime filter on real data: noise calibration and the B3 → B4 candidate
|
||||
|
||||
```task
|
||||
id: ASSEMBLY-WP-0015-T07
|
||||
status: todo
|
||||
priority: high
|
||||
```
|
||||
|
||||
From ASSEMBLY-WP-0017. The IMM filter is overconfident on observed data:
|
||||
weights jump to 1.00 within a quarter (`research/ModelMatching.md` § 4.3).
|
||||
|
||||
1. Calibrate the observation noise per indicator from real residuals. Fit
|
||||
the best regime to each series, and set the noise to the residual
|
||||
standard deviation, including model error, not only sampling error.
|
||||
2. At the next review with Q4 2026 data, re-run `matching.py`. Check the
|
||||
watch-list candidate US B3 → B4 (`research/FlipRegister.md`): record a flip
|
||||
only if the new anchor holds ≥ 0.75 for a second quarter under the
|
||||
calibrated noise. Otherwise drop the candidate with a note.
|
||||
3. If a flip is recorded, register predictions v2 from the new regime
|
||||
(superseding P-2026-001, not editing it).
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ type: workplan
|
|||
title: "Reliable flip detection: indicators, per-regime filter, sentiment equation"
|
||||
domain: communication
|
||||
repo: assembly-economics
|
||||
status: active
|
||||
status: finished
|
||||
flavor: residual
|
||||
depends_on: [ASSEMBLY-WP-0012]
|
||||
owner: claude-code
|
||||
|
|
@ -96,11 +96,19 @@ years (`matching.py --synthetic`). Add the criteria as a slow test.
|
|||
|
||||
```task
|
||||
id: ASSEMBLY-WP-0017-T05
|
||||
status: todo
|
||||
status: done
|
||||
priority: medium
|
||||
state_hub_task_id: "93477fd0-6d90-51dd-a41a-75a22715bf29"
|
||||
```
|
||||
|
||||
**Done 2026-10-13:** `observed_imm` runs the IMM filter on the observed US
|
||||
series (`results/matching.md`, `research/ModelMatching.md` § 4.3). Full
|
||||
checkpoint records point to the report, which is re-run at reviews. The runner
|
||||
computes nothing new, so the execution declaration stays unchanged. First
|
||||
output: US in B3 through mid-2026, flip **candidate** B3 → B4 in Q3 2026 (watch
|
||||
list). The filter is overconfident on real data; noise calibration goes to
|
||||
WP-0015-T07.
|
||||
|
||||
Unblocked 2026-10-13 (T04 passed, T06 provides L5b). First extend
|
||||
`main_observed` to the IMM filter with the observed series (adoption, L5b,
|
||||
discovery, sentiment once available), then run matching at every full
|
||||
|
|
@ -130,3 +138,11 @@ closer to organism investment, for example hyperscaler capital expenditure
|
|||
or a Census AI-spending question if one exists. Add it to `sources.json`
|
||||
(if machine-readable) and `observed_series.json`. Then re-run
|
||||
`matching.py --imm` with this series' realistic noise.
|
||||
|
||||
## Close-out 2026-10-13
|
||||
|
||||
T01–T06 are done: sentiment reference (BR-009), indicators, IMM filter,
|
||||
acceptance test passed, L5b investment series, filter on observed data with
|
||||
checkpoint pointer. Residuals go to ASSEMBLY-WP-0015-T07: calibrate the
|
||||
observation noise for real data, and confirm or drop the B3 → B4 candidate at
|
||||
the next review.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue