Tracking: 2026-08-12 full-surface QA sweep of the eco MCP (22 tools, 23 findings) #240

Closed
opened 2026-08-12 23:16:48 +00:00 by coilyco-ops · 4 comments
Member

Tracking issue for a full adversarial sweep of all 22 eco MCP tools against Eco via Sirens (eco.coilysiren.me:3001), cycle 14 / day 40, Eco 0.13.0.4, on 2026-08-12. Cross-server probes against GreenLeaf Prime and one unreachable host.

Method: every tool called at least once, every filter parameter exercised, every stateful verb round-tripped, and each tool's answers cross-checked against every other tool's answer to the same question. Most findings below were only visible from that cross-check — no single tool used alone would surface the trade-total or byCitizen discrepancies.

Root-cause clustering and suggested fix order are in the comments below. Short version: 23 findings collapse into four families plus a tail of six one-offs.

Findings index

Family 1 — currency never parsed out of the trade ledger

  • #217 — all 3,668 trades attributed to numeric IDs; 167 named currencies read zero
  • #236get_stores.currencies[] empty on stores with 4.6k volume
  • #234fair_price in-game side entirely null
  • #218get_market returns markets: [] for every query

Family 2 — event-log rows get no entity resolution

  • #223 — unresolved title id rendered as a citizen; all subject/settlement blank
  • #226 — pollution unattributed; top_stations: [{"(unknown)": 6858.75}]
  • #227 — reputation graph empty, giver column unrecognised
  • #224 — demographic event blocks duplicated

Family 3 — no response-size policy (detail below)

  • #230 — base64 images inline
  • #231get_currency filter never narrows
  • #232get_progression per-citizen timelines

Family 4 — derived and narrative fields computed loosely

  • #220 — species classifier drops the sign, labels growing populations "declining"
  • #221 — four contradictory trade totals across four tools
  • #222byCitizen sums quantities under an event-shaped name
  • #225settlementsFounded adds foundings to foundation placements
  • #235 — gross flux reported as a rate of change
  • #237 — upstream totalCulture: 0 republished as a KPI

Tail — one-offs

  • #219get_species claims a missing admin key that is present
  • #228 — unreachable-server error drops the exception text
  • #229get_map negative coords at the world seam
  • #233explain_item ignores category, always facts: []
  • #238get_government.scope names one settlement, returns five
  • #239trade_watchers create summary discards the supplied label

Family 3 detail: response size

Retained here because the three Family 3 issues reference these measurements.

Tool Size (chars) Over cap
get_species 286,264 yes
get_progression 275,159 yes
get_trades 182,083 yes
get_stores 164,527 yes
get_currency 135,178 – 136,670 yes
explain_item ~100,000 yes
get_crafting_atlas 68,321 yes
get_region ~55,000 borderline
get_map ~45,000 borderline
get_civics ~40,000 borderline

7 of 22 tools cannot return a usable answer to an MCP client. The caller gets an error plus a spill file and has to re-query it out of band, which defeats the point of the tool.

No tool in the set takes a limit, page, top_n, or since parameter. The three filters that exist (item, currency, server) either do not reduce payload (#231) or return nothing (#218). Every large response is "everything, always":

  • get_trades — all 526 detailed rows plus every aggregate
  • get_stores — 111 stores and 43 traders with full topItems / topCounterparties
  • get_progression — per-citizen event timelines for 80 citizens
  • get_region — all 94 species including the 78 marked stable
  • get_civics — every demographic row, duplicates included

Direction:

  1. A shared limit / top_n on every list-returning tool, with a default a client can consume.
  2. Summary-first: the aggregate layer (small, and genuinely good) by default; detail behind a flag.
  3. Drop repeated boilerplate — the get_currency holders note (185 copies, ~37 KB) and the get_map colour tables.

What the sweep did not find

Recorded so the finding count is not read as "the pipeline is unsound". Every arithmetic check against the raw layer passed:

  • get_world — nine perActionCounts sum exactly to totalEvents (13,333)
  • get_crafting_atlas — four sum exactly to totalEvents (18,092)
  • DigOrMine 3,129 and ChopTree 1,331 agree across two independently-computed tools
  • get_civics turnout: 90 / (90 + 218) = 0.2922 ✓
  • get_tradesrollupTrades + detailedTrades = totalTrades
  • trade_watchers — full createlistevaluateremove lifecycle correct, predicate correct, no residue

No crashes, no security findings, no data loss. This is an accuracy-and-trust problem in the presentation layer, not an ingest problem.

Tracking issue for a full adversarial sweep of all 22 eco MCP tools against Eco via Sirens (`eco.coilysiren.me:3001`), cycle 14 / day 40, Eco 0.13.0.4, on 2026-08-12. Cross-server probes against GreenLeaf Prime and one unreachable host. Method: every tool called at least once, every filter parameter exercised, every stateful verb round-tripped, and each tool's answers cross-checked against every other tool's answer to the same question. Most findings below were only visible from that cross-check — no single tool used alone would surface the trade-total or `byCitizen` discrepancies. **Root-cause clustering and suggested fix order are in the comments below.** Short version: 23 findings collapse into four families plus a tail of six one-offs. ## Findings index ### Family 1 — currency never parsed out of the trade ledger - https://forgejo.coilysiren.me/coilyco-gaming/eco-app/issues/217 — all 3,668 trades attributed to numeric IDs; 167 named currencies read zero - https://forgejo.coilysiren.me/coilyco-gaming/eco-app/issues/236 — `get_stores.currencies[]` empty on stores with 4.6k volume - https://forgejo.coilysiren.me/coilyco-gaming/eco-app/issues/234 — `fair_price` in-game side entirely null - https://forgejo.coilysiren.me/coilyco-gaming/eco-app/issues/218 — `get_market` returns `markets: []` for every query ### Family 2 — event-log rows get no entity resolution - https://forgejo.coilysiren.me/coilyco-gaming/eco-app/issues/223 — unresolved title id rendered as a citizen; all `subject`/`settlement` blank - https://forgejo.coilysiren.me/coilyco-gaming/eco-app/issues/226 — pollution unattributed; `top_stations: [{"(unknown)": 6858.75}]` - https://forgejo.coilysiren.me/coilyco-gaming/eco-app/issues/227 — reputation graph empty, giver column unrecognised - https://forgejo.coilysiren.me/coilyco-gaming/eco-app/issues/224 — demographic event blocks duplicated ### Family 3 — no response-size policy (detail below) - https://forgejo.coilysiren.me/coilyco-gaming/eco-app/issues/230 — base64 images inline - https://forgejo.coilysiren.me/coilyco-gaming/eco-app/issues/231 — `get_currency` filter never narrows - https://forgejo.coilysiren.me/coilyco-gaming/eco-app/issues/232 — `get_progression` per-citizen timelines ### Family 4 — derived and narrative fields computed loosely - https://forgejo.coilysiren.me/coilyco-gaming/eco-app/issues/220 — species classifier drops the sign, labels growing populations "declining" - https://forgejo.coilysiren.me/coilyco-gaming/eco-app/issues/221 — four contradictory trade totals across four tools - https://forgejo.coilysiren.me/coilyco-gaming/eco-app/issues/222 — `byCitizen` sums quantities under an event-shaped name - https://forgejo.coilysiren.me/coilyco-gaming/eco-app/issues/225 — `settlementsFounded` adds foundings to foundation placements - https://forgejo.coilysiren.me/coilyco-gaming/eco-app/issues/235 — gross flux reported as a rate of change - https://forgejo.coilysiren.me/coilyco-gaming/eco-app/issues/237 — upstream `totalCulture: 0` republished as a KPI ### Tail — one-offs - https://forgejo.coilysiren.me/coilyco-gaming/eco-app/issues/219 — `get_species` claims a missing admin key that is present - https://forgejo.coilysiren.me/coilyco-gaming/eco-app/issues/228 — unreachable-server error drops the exception text - https://forgejo.coilysiren.me/coilyco-gaming/eco-app/issues/229 — `get_map` negative coords at the world seam - https://forgejo.coilysiren.me/coilyco-gaming/eco-app/issues/233 — `explain_item` ignores `category`, always `facts: []` - https://forgejo.coilysiren.me/coilyco-gaming/eco-app/issues/238 — `get_government.scope` names one settlement, returns five - https://forgejo.coilysiren.me/coilyco-gaming/eco-app/issues/239 — `trade_watchers` create summary discards the supplied label --- ## Family 3 detail: response size Retained here because the three Family 3 issues reference these measurements. | Tool | Size (chars) | Over cap | |---|---|---| | `get_species` | 286,264 | yes | | `get_progression` | 275,159 | yes | | `get_trades` | 182,083 | yes | | `get_stores` | 164,527 | yes | | `get_currency` | 135,178 – 136,670 | yes | | `explain_item` | ~100,000 | yes | | `get_crafting_atlas` | 68,321 | yes | | `get_region` | ~55,000 | borderline | | `get_map` | ~45,000 | borderline | | `get_civics` | ~40,000 | borderline | 7 of 22 tools cannot return a usable answer to an MCP client. The caller gets an error plus a spill file and has to re-query it out of band, which defeats the point of the tool. **No tool in the set takes a `limit`, `page`, `top_n`, or `since` parameter.** The three filters that exist (`item`, `currency`, `server`) either do not reduce payload (https://forgejo.coilysiren.me/coilyco-gaming/eco-app/issues/231) or return nothing (https://forgejo.coilysiren.me/coilyco-gaming/eco-app/issues/218). Every large response is "everything, always": - `get_trades` — all 526 detailed rows plus every aggregate - `get_stores` — 111 stores and 43 traders with full `topItems` / `topCounterparties` - `get_progression` — per-citizen event timelines for 80 citizens - `get_region` — all 94 species including the 78 marked stable - `get_civics` — every demographic row, duplicates included Direction: 1. A shared `limit` / `top_n` on every list-returning tool, with a default a client can consume. 2. Summary-first: the aggregate layer (small, and genuinely good) by default; detail behind a flag. 3. Drop repeated boilerplate — the `get_currency` holders note (185 copies, ~37 KB) and the `get_map` colour tables. --- ## What the sweep did not find Recorded so the finding count is not read as "the pipeline is unsound". Every arithmetic check against the raw layer passed: - `get_world` — nine `perActionCounts` sum exactly to `totalEvents` (13,333) - `get_crafting_atlas` — four sum exactly to `totalEvents` (18,092) - `DigOrMine` 3,129 and `ChopTree` 1,331 agree across two independently-computed tools - `get_civics` turnout: 90 / (90 + 218) = 0.2922 ✓ - `get_trades` — `rollupTrades` + `detailedTrades` = `totalTrades` ✓ - `trade_watchers` — full `create` → `list` → `evaluate` → `remove` lifecycle correct, predicate correct, no residue No crashes, no security findings, no data loss. This is an accuracy-and-trust problem in the presentation layer, not an ingest problem.
Author
Member

Root-cause clustering for the 2026-08-12 sweep (#217–#239)

Note on scope: this issue was filed for payload size specifically. Parking the full clustering here because it is the closest thing the sweep has to a tracking issue — retitle or move if you'd rather keep this one narrow.

24 issues came out of the sweep, but they are not 24 independent defects. They collapse into four families plus a tail of one-offs. Suggested fix order is by how much each family unblocks.

1. Currency is never parsed out of the trade ledger

get_trades returns currency: "" on all 526 detailed rows while setting trade_currency_column_seen: true. Everything downstream that needs a currency name then fails in its own way.

  • #217 — all trade volume attributed to numeric IDs; 167 named currencies read zero
  • #236get_stores.currencies[] empty on stores with 4.6k volume
  • #234fair_price in-game side null (partly; also depends on family 2 of #218)
  • #218get_market empty (unconfirmed dependency, but same data path)

One fix, up to four issues. Start here. find_trade resolves currency correctly from live store data (Spectres, Racines), so there is a working reference implementation in-tree.

2. Event-log rows do not get entity resolution

Actor and subject columns come through as ids, blanks, or unmapped names, and each consumer papers over it differently.

  • #223 — unresolved title id formatted as Citizen #456767; all subject/settlement blank
  • #226byPolluter: [], top_citizens: [], top_stations: [{"(unknown)": 6858.75}]
  • #227ReputationTransfer giver column unrecognised after six candidate names
  • #224 — duplicated demographic blocks (likely the same rows re-emitted per unresolved settlement key)

Worth a single shared resolver and one debug-level log of unmapped column keys, rather than four independent guesses at column naming.

3. No response-size policy was ever set

This issue. Not four defects — one design decision that has not been made.

  • #240 (this) — 7 of 22 tools over cap, no limit/page/top_n anywhere
  • #230 — base64 images inline (286 KB around a 150-char extract)
  • #231get_currency filter adds selected but never narrows
  • #232get_progression per-citizen timelines, 266 KB of 275 KB

4. Derived and narrative fields computed loosely over correct raw data

The raw layer is sound (see below). These are all summary-layer arithmetic and wording.

  • #220 — species classifier drops the sign, labels growing populations "declining" ← highest user-facing harm, likely one line
  • #221 — four contradictory trade totals across four tools
  • #222byCitizen sums quantities under an event-shaped name, exceeding totalEvents 15×
  • #225settlementsFounded adds foundings to foundation placements
  • #235 — explainer reports a gross flux as a rate of change
  • #237 — upstream totalCulture: 0 republished as a KPI beside 910 culture of progress

Tail — genuine one-offs

#219 (get_species own credential path), #228 (empty exception text), #229 (map seam wrap), #233 (explain_item category ignored), #238 (get_government.scope), #239 (watcher label, cosmetic).

What is not broken

Recording this so the issue count is not read as "the ingest is unsound". Every arithmetic check against the raw layer passed:

  • get_world — nine perActionCounts sum exactly to totalEvents (13,333)
  • get_crafting_atlas — four sum exactly to totalEvents (18,092)
  • DigOrMine 3,129 and ChopTree 1,331 agree across two independently-computed tools
  • get_civics turnout: 90 / (90 + 218) = 0.2922 ✓
  • get_tradesrollupTrades + detailedTrades = totalTrades
  • find_trade, trade_watchers, get_stores, get_progression, get_world all returned correct, useful data

Nothing crashed, nothing was unsafe, and no data was lost. This is an accuracy-and-trust problem in the presentation layer, not a pipeline problem.

Suggested order

  1. Family 1 (currency parse) — unblocks the most surface
  2. #220 alone — cheapest fix, worst wrong answer
  3. Family 3 (size policy) — makes the rest of the tools usable from a client at all
  4. Family 2 (entity resolution)
  5. Family 4 remainder, then the tail
## Root-cause clustering for the 2026-08-12 sweep (#217–#239) Note on scope: this issue was filed for payload size specifically. Parking the full clustering here because it is the closest thing the sweep has to a tracking issue — retitle or move if you'd rather keep this one narrow. 24 issues came out of the sweep, but they are not 24 independent defects. They collapse into four families plus a tail of one-offs. Suggested fix order is by how much each family unblocks. ### 1. Currency is never parsed out of the trade ledger `get_trades` returns `currency: ""` on all 526 detailed rows while setting `trade_currency_column_seen: true`. Everything downstream that needs a currency name then fails in its own way. - #217 — all trade volume attributed to numeric IDs; 167 named currencies read zero - #236 — `get_stores.currencies[]` empty on stores with 4.6k volume - #234 — `fair_price` in-game side null (partly; also depends on family 2 of #218) - #218 — `get_market` empty (unconfirmed dependency, but same data path) **One fix, up to four issues.** Start here. `find_trade` resolves currency correctly from live store data (Spectres, Racines), so there is a working reference implementation in-tree. ### 2. Event-log rows do not get entity resolution Actor and subject columns come through as ids, blanks, or unmapped names, and each consumer papers over it differently. - #223 — unresolved title id formatted as `Citizen #456767`; all `subject`/`settlement` blank - #226 — `byPolluter: []`, `top_citizens: []`, `top_stations: [{"(unknown)": 6858.75}]` - #227 — `ReputationTransfer` giver column unrecognised after six candidate names - #224 — duplicated demographic blocks (likely the same rows re-emitted per unresolved settlement key) Worth a single shared resolver and one debug-level log of unmapped column keys, rather than four independent guesses at column naming. ### 3. No response-size policy was ever set This issue. Not four defects — one design decision that has not been made. - #240 (this) — 7 of 22 tools over cap, no `limit`/`page`/`top_n` anywhere - #230 — base64 images inline (286 KB around a 150-char extract) - #231 — `get_currency` filter adds `selected` but never narrows - #232 — `get_progression` per-citizen timelines, 266 KB of 275 KB ### 4. Derived and narrative fields computed loosely over correct raw data The raw layer is sound (see below). These are all summary-layer arithmetic and wording. - #220 — species classifier drops the sign, labels growing populations "declining" ← **highest user-facing harm, likely one line** - #221 — four contradictory trade totals across four tools - #222 — `byCitizen` sums quantities under an event-shaped name, exceeding `totalEvents` 15× - #225 — `settlementsFounded` adds foundings to foundation placements - #235 — explainer reports a gross flux as a rate of change - #237 — upstream `totalCulture: 0` republished as a KPI beside 910 culture of progress ### Tail — genuine one-offs #219 (`get_species` own credential path), #228 (empty exception text), #229 (map seam wrap), #233 (`explain_item` category ignored), #238 (`get_government.scope`), #239 (watcher label, cosmetic). ### What is *not* broken Recording this so the issue count is not read as "the ingest is unsound". Every arithmetic check against the raw layer passed: - `get_world` — nine `perActionCounts` sum exactly to `totalEvents` (13,333) - `get_crafting_atlas` — four sum exactly to `totalEvents` (18,092) - `DigOrMine` 3,129 and `ChopTree` 1,331 agree across two independently-computed tools - `get_civics` turnout: 90 / (90 + 218) = 0.2922 ✓ - `get_trades` — `rollupTrades` + `detailedTrades` = `totalTrades` ✓ - `find_trade`, `trade_watchers`, `get_stores`, `get_progression`, `get_world` all returned correct, useful data Nothing crashed, nothing was unsafe, and no data was lost. This is an accuracy-and-trust problem in the presentation layer, not a pipeline problem. ### Suggested order 1. Family 1 (currency parse) — unblocks the most surface 2. #220 alone — cheapest fix, worst wrong answer 3. Family 3 (size policy) — makes the rest of the tools usable from a client at all 4. Family 2 (entity resolution) 5. Family 4 remainder, then the tail
coilyco-ops changed title from Tracking: 7 of 22 MCP tools exceed the client response cap, and no tool offers a limit or pagination parameter to Tracking: 2026-08-12 full-surface QA sweep of the eco MCP (22 tools, 23 findings) 2026-08-12 23:36:08 +00:00
Author
Member

Scope note in the comment above is now resolved — this issue has been retitled and rewritten as the tracking issue for the whole sweep. The original payload-size content is preserved in the body under "Family 3 detail: response size", so the measurements referenced by #230 / #231 / #232 are unchanged and still here.

Ignore the "retitle or move if you'd rather keep this one narrow" line; that already happened.

Scope note in the comment above is now resolved — this issue has been retitled and rewritten as the tracking issue for the whole sweep. The original payload-size content is preserved in the body under "Family 3 detail: response size", so the measurements referenced by #230 / #231 / #232 are unchanged and still here. Ignore the "retitle or move if you'd rather keep this one narrow" line; that already happened.
Author
Member

Supersedes the two comments above. They used short-form #NNN cross-references, which are ambiguous post-org-migration. Reposting the clustering with canonical URLs; the earlier two comments are retained for history only and should not be used for triage.

Root-cause clustering for the 2026-08-12 sweep

23 findings, not 23 independent defects. Four families plus a tail of one-offs. Fix order below is by how much each family unblocks.

1. Currency is never parsed out of the trade ledger

get_trades returns currency: "" on all 526 detailed rows while setting trade_currency_column_seen: true. Everything downstream that needs a currency name then fails in its own way.

  • #217 — all trade volume attributed to numeric IDs; 167 named currencies read zero
  • #236get_stores.currencies[] empty on stores with 4.6k volume
  • #234fair_price in-game side null (partly)
  • #218get_market empty (unconfirmed dependency, same data path)

One fix, up to four issues. Start here. find_trade resolves currency correctly from live store data (Spectres, Racines), so there is a working reference implementation in-tree.

2. Event-log rows do not get entity resolution

Actor and subject columns come through as ids, blanks, or unmapped names, and each consumer papers over it differently.

  • #223 — unresolved title id formatted as a citizen; all subject/settlement blank
  • #226byPolluter: [], top_citizens: [], top_stations: [{"(unknown)": 6858.75}]
  • #227ReputationTransfer giver column unrecognised after six candidate names
  • #224 — duplicated demographic blocks (likely the same rows re-emitted per unresolved settlement key)

Worth a single shared resolver plus one debug-level log of unmapped column keys, rather than four independent guesses at column naming.

3. No response-size policy was ever set

One design decision that has not been made, not four defects. Measurements are in the issue body above.

  • #230 — base64 images inline (286 KB around a 150-char extract)
  • #231get_currency filter adds selected but never narrows
  • #232get_progression per-citizen timelines, 266 KB of 275 KB

4. Derived and narrative fields computed loosely over correct raw data

The raw layer is sound. These are all summary-layer arithmetic and wording.

  • #220 — species classifier drops the sign, labels growing populations "declining" ← highest user-facing harm, likely one line
  • #221 — four contradictory trade totals across four tools
  • #222byCitizen sums quantities under an event-shaped name, exceeding totalEvents 15×
  • #225settlementsFounded adds foundings to foundation placements
  • #235 — gross flux reported as a rate of change
  • #237 — upstream totalCulture: 0 republished as a KPI beside 910 culture of progress

Tail — genuine one-offs

  • #219get_species own credential path
  • #228 — empty exception text
  • #229 — map seam wrap
  • #233explain_item category ignored
  • #238get_government.scope
  • #239 — watcher label, cosmetic

Suggested order

  1. Family 1 (currency parse) — unblocks the most surface
  2. #220 alone — cheapest fix, worst wrong answer
  3. Family 3 (size policy) — makes the rest of the tools usable from a client at all
  4. Family 2 (entity resolution)
  5. Family 4 remainder, then the tail
**Supersedes the two comments above.** They used short-form `#NNN` cross-references, which are ambiguous post-org-migration. Reposting the clustering with canonical URLs; the earlier two comments are retained for history only and should not be used for triage. ## Root-cause clustering for the 2026-08-12 sweep 23 findings, not 23 independent defects. Four families plus a tail of one-offs. Fix order below is by how much each family unblocks. ### 1. Currency is never parsed out of the trade ledger `get_trades` returns `currency: ""` on all 526 detailed rows while setting `trade_currency_column_seen: true`. Everything downstream that needs a currency name then fails in its own way. - https://forgejo.coilysiren.me/coilyco-gaming/eco-app/issues/217 — all trade volume attributed to numeric IDs; 167 named currencies read zero - https://forgejo.coilysiren.me/coilyco-gaming/eco-app/issues/236 — `get_stores.currencies[]` empty on stores with 4.6k volume - https://forgejo.coilysiren.me/coilyco-gaming/eco-app/issues/234 — `fair_price` in-game side null (partly) - https://forgejo.coilysiren.me/coilyco-gaming/eco-app/issues/218 — `get_market` empty (unconfirmed dependency, same data path) **One fix, up to four issues. Start here.** `find_trade` resolves currency correctly from live store data (Spectres, Racines), so there is a working reference implementation in-tree. ### 2. Event-log rows do not get entity resolution Actor and subject columns come through as ids, blanks, or unmapped names, and each consumer papers over it differently. - https://forgejo.coilysiren.me/coilyco-gaming/eco-app/issues/223 — unresolved title id formatted as a citizen; all `subject`/`settlement` blank - https://forgejo.coilysiren.me/coilyco-gaming/eco-app/issues/226 — `byPolluter: []`, `top_citizens: []`, `top_stations: [{"(unknown)": 6858.75}]` - https://forgejo.coilysiren.me/coilyco-gaming/eco-app/issues/227 — `ReputationTransfer` giver column unrecognised after six candidate names - https://forgejo.coilysiren.me/coilyco-gaming/eco-app/issues/224 — duplicated demographic blocks (likely the same rows re-emitted per unresolved settlement key) Worth a single shared resolver plus one debug-level log of unmapped column keys, rather than four independent guesses at column naming. ### 3. No response-size policy was ever set One design decision that has not been made, not four defects. Measurements are in the issue body above. - https://forgejo.coilysiren.me/coilyco-gaming/eco-app/issues/230 — base64 images inline (286 KB around a 150-char extract) - https://forgejo.coilysiren.me/coilyco-gaming/eco-app/issues/231 — `get_currency` filter adds `selected` but never narrows - https://forgejo.coilysiren.me/coilyco-gaming/eco-app/issues/232 — `get_progression` per-citizen timelines, 266 KB of 275 KB ### 4. Derived and narrative fields computed loosely over correct raw data The raw layer is sound. These are all summary-layer arithmetic and wording. - https://forgejo.coilysiren.me/coilyco-gaming/eco-app/issues/220 — species classifier drops the sign, labels growing populations "declining" ← **highest user-facing harm, likely one line** - https://forgejo.coilysiren.me/coilyco-gaming/eco-app/issues/221 — four contradictory trade totals across four tools - https://forgejo.coilysiren.me/coilyco-gaming/eco-app/issues/222 — `byCitizen` sums quantities under an event-shaped name, exceeding `totalEvents` 15× - https://forgejo.coilysiren.me/coilyco-gaming/eco-app/issues/225 — `settlementsFounded` adds foundings to foundation placements - https://forgejo.coilysiren.me/coilyco-gaming/eco-app/issues/235 — gross flux reported as a rate of change - https://forgejo.coilysiren.me/coilyco-gaming/eco-app/issues/237 — upstream `totalCulture: 0` republished as a KPI beside 910 culture of progress ### Tail — genuine one-offs - https://forgejo.coilysiren.me/coilyco-gaming/eco-app/issues/219 — `get_species` own credential path - https://forgejo.coilysiren.me/coilyco-gaming/eco-app/issues/228 — empty exception text - https://forgejo.coilysiren.me/coilyco-gaming/eco-app/issues/229 — map seam wrap - https://forgejo.coilysiren.me/coilyco-gaming/eco-app/issues/233 — `explain_item` category ignored - https://forgejo.coilysiren.me/coilyco-gaming/eco-app/issues/238 — `get_government.scope` - https://forgejo.coilysiren.me/coilyco-gaming/eco-app/issues/239 — watcher label, cosmetic ### Suggested order 1. Family 1 (currency parse) — unblocks the most surface 2. https://forgejo.coilysiren.me/coilyco-gaming/eco-app/issues/220 alone — cheapest fix, worst wrong answer 3. Family 3 (size policy) — makes the rest of the tools usable from a client at all 4. Family 2 (entity resolution) 5. Family 4 remainder, then the tail
Author
Member

All 23 findings are closed. Summary of what landed, by the families this issue named.

Family 1 — currency never parsed out of the trade ledger

Root cause: the exporter keys a CurrencyTrade row by the Currency object's id, while CreateCurrency writes its name, and nothing joined them. Both consumers mishandled the same column in opposite directions — currency.py minted a phantom currency named after the id, trades.py blanked it as a misalignment artifact.

No export carried both halves of the key, so the stores/economy exporter mod now emits the id alongside the name and eco-app joins on it once, over the shared parsed rows, so the ledger, store directory and market boards all inherit it.

  • 217 currency attribution — needs an operator step: the rebuilt mod DLL has to be installed and the server restarted before attribution resolves live. Detail and verification commands are on that issue.
  • 236 store currencies, plus mixedCurrencyVolume on a scalar that adds unlike units
  • 218 get_market builds markets again, and explains itself when it cannot
  • 234 fair_price in-game evidence, plus the silent IronIngot → iron ore substitution

Family 2 — event-log rows get no entity resolution

  • 223 unresolved ids no longer render as Citizen #<id> people. Two of the observed ones were election title ids. Blank subject / settlement fields now resolve or surface as subjectId / settlementId.
  • 224 demographic events separated from the people behind them: citizensGained still counts events and says so, distinctCitizensGained counts people, and exact repeats are dropped from the browsable list
  • 226 pollution: the (unknown) station bucket is gone, has_data tells the truth, values are labelled emissions rather than count, and both tools name the columns they tried
  • 227 the reputation warning now carries the export's actual header, so the candidate list can be extended without another live probe

Family 3 — no response-size policy

  • 230 inlined base64 images are opt-in; the image URL is always returned
  • 231 get_currency's filter narrows for real, a miss returns suggestions instead of the corpus, and the 185 repeated holder notes are hoisted to one
  • 232 get_progression is summary-first, with include_timelines and a citizen argument

Family 4 — derived and narrative fields computed loosely

  • 220 the species classifier tests the signed change; growth gets a growing state instead of being called declining
  • 221 every trade count is labelled with what it counts, in a counts block that reconciles them
  • 222 byCitizen is an event count matching get_world; iterations moved to byCitizenIterations
  • 225 settlement foundings counted apart from foundation placements
  • 235 CO2 flux is described as flux; the level's own movement is observed_per_day
  • 237 totalCulture: 0 reconciles against milestone progress, with the source named

Tail

  • 219 get_species uses the same admin credential path as every other tool
  • 228 unreachable-server errors name the cause and the URL, via one shared helper that replaced 17 hand-rolled blocks
  • 229 seam-crossing map copies are flagged
  • 233 explain_item echoes its category and explains empty facts
  • 238 get_government.scope describes the query
  • 239 trade_watchers keeps the supplied label

Filed along the way

  • #246world.animals: 0, split out of 237 because it has no in-payload reconciliation source and wants an upstream look first
  • #248 — the Discord worker could not start on Python 3.13. Unrelated to the sweep, found as the standing red test.

State

ward exec test is green at 767 passed, from 631 passed / 1 failed when this started. ward exec lint and ward exec smoke pass; smoke runs against the live Sirens server and was used to confirm the culture and site-link fixes end to end.

Closing this tracker: every finding it indexes is resolved.

All 23 findings are closed. Summary of what landed, by the families this issue named. ## Family 1 — currency never parsed out of the trade ledger Root cause: the exporter keys a `CurrencyTrade` row by the Currency object's **id**, while `CreateCurrency` writes its **name**, and nothing joined them. Both consumers mishandled the same column in opposite directions — `currency.py` minted a phantom currency named after the id, `trades.py` blanked it as a misalignment artifact. No export carried both halves of the key, so the stores/economy exporter mod now emits the id alongside the name and eco-app joins on it once, over the shared parsed rows, so the ledger, store directory and market boards all inherit it. - 217 currency attribution — **needs an operator step**: the rebuilt mod DLL has to be installed and the server restarted before attribution resolves live. Detail and verification commands are on that issue. - 236 store currencies, plus `mixedCurrencyVolume` on a scalar that adds unlike units - 218 `get_market` builds markets again, and explains itself when it cannot - 234 `fair_price` in-game evidence, plus the silent `IronIngot` → iron ore substitution ## Family 2 — event-log rows get no entity resolution - 223 unresolved ids no longer render as `Citizen #<id>` people. Two of the observed ones were election *title* ids. Blank `subject` / `settlement` fields now resolve or surface as `subjectId` / `settlementId`. - 224 demographic events separated from the people behind them: `citizensGained` still counts events and says so, `distinctCitizensGained` counts people, and exact repeats are dropped from the browsable list - 226 pollution: the `(unknown)` station bucket is gone, `has_data` tells the truth, values are labelled `emissions` rather than `count`, and both tools name the columns they tried - 227 the reputation warning now carries the export's actual header, so the candidate list can be extended without another live probe ## Family 3 — no response-size policy - 230 inlined base64 images are opt-in; the image URL is always returned - 231 `get_currency`'s filter narrows for real, a miss returns suggestions instead of the corpus, and the 185 repeated holder notes are hoisted to one - 232 `get_progression` is summary-first, with `include_timelines` and a `citizen` argument ## Family 4 — derived and narrative fields computed loosely - 220 the species classifier tests the signed change; growth gets a `growing` state instead of being called declining - 221 every trade count is labelled with what it counts, in a `counts` block that reconciles them - 222 `byCitizen` is an event count matching `get_world`; iterations moved to `byCitizenIterations` - 225 settlement foundings counted apart from foundation placements - 235 CO2 flux is described as flux; the level's own movement is `observed_per_day` - 237 `totalCulture: 0` reconciles against milestone progress, with the source named ## Tail - 219 `get_species` uses the same admin credential path as every other tool - 228 unreachable-server errors name the cause and the URL, via one shared helper that replaced 17 hand-rolled blocks - 229 seam-crossing map copies are flagged - 233 `explain_item` echoes its category and explains empty facts - 238 `get_government.scope` describes the query - 239 `trade_watchers` keeps the supplied label ## Filed along the way - https://forgejo.coilysiren.me/coilyco-gaming/eco-app/issues/246 — `world.animals: 0`, split out of 237 because it has no in-payload reconciliation source and wants an upstream look first - https://forgejo.coilysiren.me/coilyco-gaming/eco-app/issues/248 — the Discord worker could not start on Python 3.13. Unrelated to the sweep, found as the standing red test. ## State `ward exec test` is green at 767 passed, from 631 passed / 1 failed when this started. `ward exec lint` and `ward exec smoke` pass; smoke runs against the live Sirens server and was used to confirm the culture and site-link fixes end to end. Closing this tracker: every finding it indexes is resolved.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
coilyco-gaming/eco-app#240
No description provided.