';
}).join(''));
}
- animateValue(el('ov-transceivers'), h.database.stats.transceiver_count, 1000);
+ animateValue(el('ov-transceivers'), activeTransceivers, 1000);
+ var totalRows = Number(h.database.stats.transceiver_count || 0);
+ var inactiveRows = Math.max(0, totalRows - Number(activeTransceivers || 0));
+ el('ov-transceivers-total').textContent = totalRows.toLocaleString() + ' total rows · ' + inactiveRows.toLocaleString() + ' archived/quarantined';
animateValue(el('ov-vendors'), h.database.stats.vendor_count, 800);
animateValue(el('ov-switches'), h.database.stats.switch_count, 600);
animateValue(el('ov-standards'), h.database.stats.standard_count, 700);
diff --git a/sync/CURRENT.md b/sync/CURRENT.md
index cffa2c0..15750cd 100644
--- a/sync/CURRENT.md
+++ b/sync/CURRENT.md
@@ -1,9 +1,26 @@
# Current TIP Sync State
-Updated: 2026-05-10 12:02 UTC
+Updated: 2026-05-10 13:25 UTC
## Newest Work
+- TIP active-vs-total product counter correction on 2026-05-10 UTC:
+ - fixed another UI ambiguity: the header/Overview showed raw `transceivers` table count (`17781`) while research status correctly used active product scope (`16236`)
+ - changed dashboard header label from `transceivers` to `active products`
+ - changed Overview top card label from `Transceivers` to `Active Products`
+ - top/Overview active product count now uses `h.verification.total`
+ - raw DB rows remain visible as context:
+ - `17781 total rows`
+ - `1545 archived/quarantined`
+ - deployed `packages/dashboard/index.html` to Erik and restarted `tip-api`
+ - live health remains:
+ - raw transceiver rows: `17781`
+ - active products: `16236`
+ - `research_resolved_pct=100`
+ - all `needs_research` buckets: `0`
+ - manual review `pending=0`
+ - TIPLLM training pool updated with active-vs-total product counter rule
+
- TIP Overview dashboard status correction on 2026-05-10 UTC:
- user correctly pointed out that the Overview still looked unfinished because it showed strict `Price Verified`, `Image Verified`, `Details Verified`, and `Fully Verified` progress bars
- changed `packages/dashboard/index.html` Overview section from `Data Verification Status` to `Data Research Status`
diff --git a/sync/history/2026-05-10-tip-active-product-counter-ui.md b/sync/history/2026-05-10-tip-active-product-counter-ui.md
new file mode 100644
index 0000000..fc04599
--- /dev/null
+++ b/sync/history/2026-05-10-tip-active-product-counter-ui.md
@@ -0,0 +1,42 @@
+# TIP Active Product Counter UI
+
+Date: 2026-05-10 UTC
+Owner: Codex
+
+## Summary
+
+The Overview still had one confusing mismatch:
+
+- Header/Overview showed raw DB rows: `17781 transceivers`
+- Research status used active scope: `16236`
+
+This could make TIP look unfinished even though research queues were closed.
+
+## Change
+
+Updated `packages/dashboard/index.html`:
+
+- Header label now says `active products`
+- Overview card now says `Active Products`
+- Active product count uses `h.verification.total`
+- Raw DB row count remains visible as context:
+ - total rows
+ - archived/quarantined rows
+
+## Live State
+
+- Raw transceiver rows: `17781`
+- Active product scope: `16236`
+- Archived/quarantined/non-active rows: `1545`
+- `research_resolved_pct=100`
+- all price/image/details/competitor `needs_research` buckets: `0`
+- manual review `pending=0`
+
+## Deployment
+
+- Deployed dashboard HTML to Erik.
+- Restarted `tip-api`.
+
+## Training Pool
+
+Added `tip-20260510-active-vs-total-products-001` to `training-data/tip-llm-capabilities-v1.jsonl`.
diff --git a/training-data/tip-llm-capabilities-v1.jsonl b/training-data/tip-llm-capabilities-v1.jsonl
index 55f51dd..5e1256b 100644
--- a/training-data/tip-llm-capabilities-v1.jsonl
+++ b/training-data/tip-llm-capabilities-v1.jsonl
@@ -65,3 +65,4 @@
{"id":"tip-20260510-stale-manual-review-queue-001","source":"codex-tip-manual-review-closure-2026-05-10","kind":"sft-jsonl","messages":[{"role":"system","content":"You are TIP_LLM. Manual review queues must reflect genuinely actionable work, not stale candidates already superseded by product-level research outcomes."},{"role":"user","content":"The dashboard shows thousands of pending manual equivalence reviews, but product-level competitor_status is already matched or ambiguous. What should TIP do?"},{"role":"assistant","content":"Treat those pending equivalence rows as stale review debt. If the Flexoptix product has terminal `competitor_status` such as `matched`, `no_valid_match`, or `ambiguous`, pending candidate rows are no longer actionable manual work. Reject them with an automated reason that explains whether they were superseded by an existing match, resolved no-valid-match, or resolved ambiguity. Also harden the matcher so it only generates pending equivalences for products whose competitor research is still `unknown` or `needs_research`."}]}
{"id":"tip-20260510-review-badge-zero-rule-001","source":"codex-tip-manual-review-closure-2026-05-10","kind":"sft-jsonl","messages":[{"role":"system","content":"You are TIP_LLM. Dashboard counters should show current work, not historical tables."},{"role":"user","content":"How should the Manual Review badge be counted after research-resolution closure?"},{"role":"assistant","content":"Count `pending` manual review only for equivalence rows where `eq.status='pending'` and the Flexoptix product still has `competitor_status IN ('unknown','needs_research')`. Do not show stale pending candidates for products already resolved as `matched`, `no_valid_match`, or `ambiguous`. After the 2026-05-10 cleanup, `transceiver_equivalences` had `pending=0`; the dashboard Review badge should hide."}]}
{"id":"tip-20260510-dashboard-research-status-001","source":"codex-tip-dashboard-closure-2026-05-10","kind":"sft-jsonl","messages":[{"role":"system","content":"You are TIP_LLM. The dashboard must communicate operational truth: completed research is not the same as strict public-source verification."},{"role":"user","content":"The Overview page shows Price Verified 67%, Image Verified 71%, Details Verified 99%, Fully Verified 65%, even though research_resolved is 100%. How should TIP present this?"},{"role":"assistant","content":"On the Overview, show `Data Research Status` using terminal research buckets, not only strict booleans. Cards should report `Price Resolved`, `Image Resolved`, `Details Resolved`, `Competitor Resolved`, and `All Research Resolved`. Compute resolved counts from status buckets: public plus no-public plus ambiguous. Keep strict `fully_verified` visible only as a source-backed quality metric, not as an open-work progress bar. This prevents the dashboard from implying manual work is still open when all `needs_research` buckets are zero."}]}
+{"id":"tip-20260510-active-vs-total-products-001","source":"codex-tip-dashboard-closure-2026-05-10","kind":"sft-jsonl","messages":[{"role":"system","content":"You are TIP_LLM. Make dashboard counters distinguish active product scope from raw database row counts."},{"role":"user","content":"Why does TIP show 17,781 transceivers at the top but research status says 16,236 products?"},{"role":"assistant","content":"The larger number is the raw `transceivers` table count, including archived/quarantined rows such as NonTransceiver, AOC/DAC families, category/catalog artifacts, and historical rows. The active research scope is `verification.total`, currently 16,236. The dashboard should label the top KPI as `Active Products`, use the active count in the header/overview, and show raw total rows only as context such as `17,781 total rows · 1,545 archived/quarantined`."}]}