mirror of
https://github.com/koala73/worldmonitor.git
synced 2026-04-25 17:14:57 +02:00
chore(resilience): address Ship 1 self-review findings (P2 + P3)
P2: scoreTradePolicy header comment claimed RESILIENCE_SANCTIONS_KEY and normalizeSanctionCount were "retained" but both were actually removed during the typecheck pass (TS6133). Replaced with an accurate one-line pointer to the retire-tag locations at line ~263 (constant) and line ~542 (helper). P3: Added a positive-coverage assertion to the formula test — "DOES read every expected component seed key" — to defend against accidental component drops in the opposite direction. Symmetric to the existing "does NOT read sanctions:country-counts:v1" guard. P3: Cross-linked the methodology doc's "Trade Policy" section to the resolved-construct paragraph in known-limitations.md so a reader curious about the dropped sanctions component lands on the rationale in one click. 🤖 Generated with Claude Opus 4.7 (1M context, extended thinking) via [Claude Code](https://claude.com/claude-code) + Compound Engineering v3.0.0 Co-Authored-By: Claude Opus 4.7 (1M context, extended thinking) <noreply@anthropic.com>
This commit is contained in:
@@ -107,6 +107,10 @@ to total 1.0. A separate `financialSystemExposure` dim (plan Phase 2) will
|
||||
add structural sanctions exposure via BIS Locational Banking Statistics +
|
||||
WB IDS short-term external debt + FATF AML/CFT listing status.
|
||||
|
||||
For the full construct rationale and the rejected alternatives (program-
|
||||
weight categorization, transit-hub exclusion lists), see
|
||||
[known-limitations.md § tradeSanctions → tradePolicy](./known-limitations.md#tradesanctions--tradepolicy-ofac-domicile-component-dropped-ship-1-2026-04-25).
|
||||
|
||||
| Indicator | Description | Direction | Goalposts (worst-best) | Weight | Source | Cadence |
|
||||
|---|---|---|---|---|---|---|
|
||||
| tradeRestrictions | WTO trade restrictions count (IN_FORCE weighted 3x) | Lower is better | 30 - 0 | 0.30 | WTO | Weekly |
|
||||
|
||||
@@ -1068,12 +1068,14 @@ export async function scoreCurrencyExternal(
|
||||
// WTO restrictions count → 0.30 (was 0.15)
|
||||
// WTO barriers count → 0.30 (was 0.15)
|
||||
// applied tariff rate → 0.40 (was 0.25)
|
||||
// `RESILIENCE_SANCTIONS_KEY` and `normalizeSanctionCount` are retained
|
||||
// (no longer read here) pending plan 2026-04-25-004 Phase 2, which adds the
|
||||
// `financialSystemExposure` dim built from BIS LBS + WB IDS + FATF status —
|
||||
// a structural-exposure construct that does not rely on the OFAC count.
|
||||
// `scripts/seed-sanctions-pressure.mjs` continues to write the seed key for
|
||||
// other consumers (country-brief generation, ad-hoc analysis).
|
||||
// The `sanctions:country-counts:v1` seed key is no longer read by this
|
||||
// module; only `scripts/seed-sanctions-pressure.mjs` continues to WRITE it
|
||||
// for country-brief generation and ad-hoc analysis. The retired
|
||||
// `RESILIENCE_SANCTIONS_KEY` constant and `normalizeSanctionCount` helper
|
||||
// were removed in this PR (see retire-tag at lines ~263 and ~542).
|
||||
// Phase 2 (Ship 2) adds the `financialSystemExposure` dim built from
|
||||
// BIS LBS + WB IDS + FATF status — a structural-exposure construct that
|
||||
// does not rely on the OFAC count.
|
||||
export async function scoreTradePolicy(
|
||||
countryCode: string,
|
||||
reader: ResilienceSeedReader = defaultSeedReader,
|
||||
|
||||
@@ -63,6 +63,32 @@ describe('scoreTradePolicy — 3-component weighted-blend formula (Ship 1 contra
|
||||
);
|
||||
});
|
||||
|
||||
it('DOES read every expected component seed key (defends against accidental drops)', async () => {
|
||||
// Symmetric counter-positive: if a future refactor accidentally
|
||||
// drops one of the 3 remaining components, this test names the
|
||||
// missing reader call directly. The static-record key is templated
|
||||
// by `readStaticCountry` (resilience:static:{ISO2}); we accept any
|
||||
// read that includes that prefix.
|
||||
const observed = new Set<string>();
|
||||
const reader: ResilienceSeedReader = async (key) => {
|
||||
observed.add(key);
|
||||
return null;
|
||||
};
|
||||
await scoreTradePolicy(TEST_ISO2, reader);
|
||||
assert.ok(
|
||||
observed.has('trade:restrictions:v1:tariff-overview:50'),
|
||||
'scoreTradePolicy must call reader(trade:restrictions:v1:tariff-overview:50) — WTO restrictions component (weight 0.30)',
|
||||
);
|
||||
assert.ok(
|
||||
observed.has('trade:barriers:v1:tariff-gap:50'),
|
||||
'scoreTradePolicy must call reader(trade:barriers:v1:tariff-gap:50) — WTO barriers component (weight 0.30)',
|
||||
);
|
||||
assert.ok(
|
||||
[...observed].some((k) => k.startsWith('resilience:static:')),
|
||||
'scoreTradePolicy must read a resilience:static:{ISO2} key for the applied tariff rate component (weight 0.40)',
|
||||
);
|
||||
});
|
||||
|
||||
it('reporter-set country with zero restrictions/barriers and no tariff scores 100', async () => {
|
||||
// Restrictions = 0 → 100 (lowerBetter at the best anchor).
|
||||
// Barriers = 0 → 100.
|
||||
|
||||
Reference in New Issue
Block a user