What
The Context Gateway overview card renders a green N/N synced badge for an
artifact type whenever in_sync == total, even when other status counts
(missing_target, missing_canonical, error, parse_error) are non-zero
on the same artifact type. As a result, partial sync states across multiple
runtimes are hidden behind a success-coloured badge.
Live repro
$ curl -s http://127.0.0.1:8080/api/context/overview | jq .commands
{
"total": 3,
"in_sync": 3,
"missing_target": 3
}
The overview card for Commands displays 3/3 synced with the
badge-success (green) class, despite three commands being unsynced for at
least one runtime.
Why this happens
/api/context/overview aggregates (runtime, name, status) triples via
_count_statuses
(packages/memtomem/src/memtomem/web/routes/context_gateway.py:17):
def _count_statuses(triples):
names = set()
counts = {}
for _runtime, name, status in triples:
names.add(name)
key = status.replace(" ", "_")
counts[key] = counts.get(key, 0) + 1
return {"total": len(names), **counts}
total is the number of distinct names, but each status count is
incremented per (runtime, name) pair. With Claude + Gemini + Codex runtimes
each contributing one triple per name, the per-status counts can sum well
above total. In the live case above:
- 3 commands total
- claude_commands: 3 ×
in sync
- gemini_commands: 3 ×
missing target
→ total=3, in_sync=3, missing_target=3. Per-runtime breakdown is
already visible at /api/context/commands, so the data is correct — it's the
overview's summary that loses information.
The frontend then computes
(packages/memtomem/src/memtomem/web/static/context-gateway.js:102):
const hasIssue = d.error || (total > 0 && inSync < total)
|| d.status === 'out_of_sync' || d.status === 'error';
This only checks whether in_sync covers total. It does not consider
missing_target, missing_canonical, parse_error, or any other non-in_sync
count. With total=3, in_sync=3, hasIssue is false, badge is green,
badgeText is 3/3 synced.
Suggested fix (frontend-only)
The _count_statuses payload already carries every status as its own key.
Compute hasIssue as "any non-in_sync count is non-zero", e.g.:
const total = d.total || 0;
const inSync = d.in_sync || 0;
const issueKeys = ['missing_target', 'missing_canonical', 'out_of_sync', 'parse_error'];
const issueCount = issueKeys.reduce((sum, k) => sum + (d[k] || 0), 0);
const hasIssue = d.error || issueCount > 0
|| d.status === 'out_of_sync' || d.status === 'error';
For the badge text, surface the dominant issue when present, e.g.
3 missing target instead of 3/3 synced. The exact wording is up for
discussion — what matters is that the warning state is visible.
Severity
Medium. Not data loss; the underlying /api/context/commands endpoint
reports the truth, so power users notice. But the overview card is the
default landing for sync state, so most users will trust the green badge
and miss the missing_target count entirely.
What
The Context Gateway overview card renders a green
N/N syncedbadge for anartifact type whenever
in_sync == total, even when other status counts(
missing_target,missing_canonical,error,parse_error) are non-zeroon the same artifact type. As a result, partial sync states across multiple
runtimes are hidden behind a success-coloured badge.
Live repro
The overview card for Commands displays
3/3 syncedwith thebadge-success(green) class, despite three commands being unsynced for atleast one runtime.
Why this happens
/api/context/overviewaggregates(runtime, name, status)triples via_count_statuses(
packages/memtomem/src/memtomem/web/routes/context_gateway.py:17):totalis the number of distinct names, but each status count isincremented per
(runtime, name)pair. With Claude + Gemini + Codex runtimeseach contributing one triple per name, the per-status counts can sum well
above
total. In the live case above:in syncmissing target→
total=3,in_sync=3,missing_target=3. Per-runtime breakdown isalready visible at
/api/context/commands, so the data is correct — it's theoverview's summary that loses information.
The frontend then computes
(
packages/memtomem/src/memtomem/web/static/context-gateway.js:102):This only checks whether
in_synccoverstotal. It does not considermissing_target,missing_canonical,parse_error, or any other non-in_synccount. With
total=3, in_sync=3,hasIssueisfalse, badge is green,badgeTextis3/3 synced.Suggested fix (frontend-only)
The
_count_statusespayload already carries every status as its own key.Compute
hasIssueas "any non-in_synccount is non-zero", e.g.:For the badge text, surface the dominant issue when present, e.g.
3 missing targetinstead of3/3 synced. The exact wording is up fordiscussion — what matters is that the warning state is visible.
Severity
Medium. Not data loss; the underlying
/api/context/commandsendpointreports the truth, so power users notice. But the overview card is the
default landing for sync state, so most users will trust the green badge
and miss the
missing_targetcount entirely.