Files
forge/claude_artifacts/audit-20260827-180746.md
T
Dmytro Tkachenko 9868b18818 Agents
2026-08-29 12:55:39 +03:00

302 lines
23 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# audit — Gap analysis: "Let it Snow" → FORGE (what has NOT been ported)
**Date:** 2026-08-27 · Author: audit (read-only) · Scope: full parity sweep
**Checklist source:** [FORGE-parity-spec.md](FORGE-parity-spec.md) (29 charts + PM-Insights + boards + data contract)
**Compared against:** live FORGE code (`server/*.ts`, `client/src/**`, `extension/*`) and the initial app source
(`/Users/dmytrotkachenko/WebstormProjects/Let It Snow/Let it Snow/*.js`, verified by grep — files are huge).
Legend: ✅ done · 🟡 partial · ❌ missing. Value: **MH** must-have · **NTH** nice-to-have · **LOW**.
---
## 0. Executive summary
FORGE has delivered a solid **read-only spine**: full data ingest (966 tickets + finance + jira + config),
a server analytics engine, the **Overall** tab (~9 of 11 charts), the **Active** tab (5 of 6), the **6 SLA
heatmaps** (charts 2429), **PM Insights** (alert groups + waiting-PO + per-PM roll-up), a **6-column board**
with list view + filtered Excel export, and **new** RBAC/Users/Tokens admin (beyond the original).
What is **not** ported is roughly **half of the analytics surface and nearly all of the operator tooling**:
- **PMs-KPI tab** is only the 6 heatmaps — charts **1823** (workload, engagement + dual calendar heatmaps,
missing-cost, awaiting-PO money, brand/market sub-cards) are **absent**, and the heatmaps have **no
period/year granularity and no editable norms**.
- **Board** is missing the 7th synthetic column, 13 of 16 card fields, all 14 sorts, all 6 group-by
permutations, and ~9 of 11 filters (region, staleness, jira, requester, custom-label…).
- **Whole features missing:** the standalone **Jira board**, the **Size CALC** estimator, the **finance
view**, and the entire **options/config editor surface** (brand colours, norms, thresholds, card-field
toggles, colleagues/region, currency, custom labels).
- **Sync** is shallow: active-**RITM only**, 9 fields, **no SCTASK, no Jira, no closed, no finance,
no statusDurations** collectors.
- Overall/Active charts lack the **YoY pies (#5/#6)**, **CGO overlay**, **#/% toggle**, **Jira status
durations (#17)**, and **time-in-status min/median/max (#15)**.
Per the spec, **AI Advisor / at-risk, weather** are intentionally out of scope (confirmed below).
---
## 1. Overall analytics tab — `client/src/pages/Overview/index.tsx` + `server/analytics.ts:getOverview`
| # | Item | Status | Note / where it lives |
|---|---|:--:|---|
| 1 | Opened per month | ✅ | `GroupedBars` — multi-year grouped, bars/line toggle, YoY badge. |
| 2 | Closed per month | ✅ | `GroupedBars`, same. |
| 3 | Revenue per month (cost/tickets, ±YoY) | ✅ | `GroupedBars` + Cost/Tickets toggle in Overview; GBP via fixed FX. |
| 4 | Lifetime-at-close histogram + median/avg/closed tiles | ✅ | `BarList` 6 buckets + median tile. `avgDays`/`closed` computed server-side. |
| 5 | **Opened YoY pie (fair/full)** | ❌ | No opened-YoY donut. Would live in Overview as a `DonutChart`; server has `openedByMonth` but no fair-window (same-day-of-year) series. **MH** |
| 6 | **Closed YoY pie (fair/full)** | ❌ | Same — no closed-YoY donut / fair-vs-full comparison. **MH** |
| 7 | By business unit (per-year, **brand drill**) | 🟡 | Flat `BarList` (`byBusinessUnit`), **no per-year split, no brand drill-down**. `server/analytics.ts:169`. **NTH** |
| 8 | By requester (bars + YoY, **market drill**) | 🟡 | `ExpandBarList` drills requester→**brand** (spec wants →market), **no YoY**. `analytics.ts:170`. **NTH** |
| 9 | Ticket-share donut (#/%, top 18 + Others) | 🟡 | `DonutChart` on `byRequesterShare` (full 966 dist — the REDO fix). **No #/% toggle, no top-18+Others rollup.** **NTH** |
| 10 | By brand (per-year **segments**, market drill, YoY) | 🟡 | `ExpandBarList` brand→market counts only. **No per-year segments, no YoY, no size/status segmentation.** **NTH** |
| 11 | By market | 🟡 | Flat `BarList`, top-20. No brand drill / segments. **LOW** |
| — | Toggle: bars/line | ✅ | `GroupedBars` per-chart. |
| — | Toggle: ±YoY | 🟡 | Shown as a computed badge, not a user toggle; only on the month `GroupedBars`. **LOW** |
| — | Toggle: cost/tickets | 🟡 | Only on the Revenue chart; original applies it across money charts. **LOW** |
| — | Toggle: #/% | ❌ | No percentage mode anywhere. **NTH** |
| — | Growth badges | 🟡 | Only the month-total YoY badge; no per-series/per-requester growth. **LOW** |
| — | **CGO overlay** | ❌ | Original overlays a "CGO" series per group (`dashboard.js` `CgoBars`/`CGO_REQUESTER`, toggle). Not in FORGE — needs a CGO flag on tickets + overlay in `GroupedBars`. **NTH** |
**Bottom line:** the month/revenue/lifetime core is faithful; the **two YoY pies are missing outright**, and
the by-dimension charts are **flat counts without the per-year segmentation, drill, and YoY** the original had.
---
## 2. Active tab — `client/src/pages/Active/index.tsx` (client-computed from active tickets)
| # | Item | Status | Note / where it lives |
|---|---|:--:|---|
| 12 | Open-not-closed by month | ✅ | `TrendChart` area, `openedByMonth`. |
| 13 | By status (kanban cats) | ✅ | `BarList` over `BOARD_COLUMNS`, state colours. |
| 14 | Age histogram (0-50…200+ d) | ✅ | `BarList`, 5 buckets. |
| 15 | **Time-in-status min/median/max** | 🟡 | Only **median** days-in-state per column (`Active/index.tsx:62`). No min/max grouped mini-bars. **NTH** |
| 16 | By brand, **status-segmented** (market drill) | 🟡 | Flat `BarList` of active-by-brand. **No status segmentation, no market drill.** **NTH** |
| 17 | **Jira status durations (workflow order)** | ❌ | Requires `statusDurations` from `jira_status_map`**not ingested** (only `status`/`statusChangedAt`/`key` land in `jira` JSONB; see `scripts/dump-to-archives.mjs:36`). No chart. **MH** for Jira ops. |
---
## 3. PMs-KPI tab — `client/src/pages/SlaKpi/index.tsx` + `server/analytics.ts:getSlaHeatmaps`
The whole tab is currently **only** the 6 SLA heatmaps. The original "PMs KPI" tab was 12 items (1829).
### 3a. The 6 SLA heatmaps (2429) — present but reduced
| # | Item | Status | Note |
|---|---|:--:|---|
| 24 | On-Time Delivery heatmap | ✅ | `otd` metric, PM×size, on-time% vs `otd` norms. |
| 25 | Avg days to close heatmap | ✅ | `avgclose` vs `avgdays`. |
| 26 | Time to assign PM heatmap | ✅ | `assign` = `max(0, fulfillment→firstAssigned)` vs `asla`. |
| 27 | Time to send preview heatmap | ✅ | `preview` = `toDoAt→inUatAt` vs `psla`. |
| 28 | Avg TTFR heatmap | ✅ | `ttfr` = `ttfrMinutes/1440` vs `ttfr` norms (hrs). |
| 29 | Avg PM response heatmap | ✅ | `cresp` = `clientRespMinutes/1440` vs `cresp` norms. |
| — | **Current + previous year** side by side | ❌ | `getSlaHeatmaps` computes one all-time grid; original renders cur-yr + prev-yr heatmaps. **MH** |
| — | **Period granularity (year / Q1-Q4 / month)** | ❌ | No period control at all. **MH** |
| — | **Editable norms panels** | ❌ | Norms are read-only from `app_config`/`config.json`; original has inline norm editors (`buildNormsPanel` etc.) that persist. Needs a write endpoint + UI. **MH** |
| — | Hidden PMs from `pm_kpi_settings` | ❌ | `getSlaHeatmaps:223` has a stubbed `hidden = new Set()` — never populated. **NTH** |
### 3b. Charts 1823 — entirely missing
| # | Item | Status | Note / where it'd live |
|---|---|:--:|---|
| 18 | **Workload by month** (revenue prev/cur yr, per-PM) | ❌ | New `GroupedBars`+per-PM series; new server agg (closed cost by PM×month). **MH** |
| 19 | **PM Engagement** (backlog/Assist✓/Jira✓/Stale) + **dual daily-activity calendar heatmaps** | ❌ | Needs `CalendarHeatmap` component (GitHub-style) + activity/jira-movement ingest per day. Original: `EngagementKpi()` with PM-row accordion. **MH** |
| 20 | **Missing final cost** (ranked PM bars + drill) | ❌ | `AssigneeBars` + list; server: closed rows where `finalCost` null, grouped by PM. Partial data exists. **MH** (margin-leak) |
| 21 | **Awaiting PO** (ranked, Cost / Avg-d / Max-d, sortable) | 🟡 | Insights has a count + L1/L2/L3 + revenue, but **no per-PM Cost/Avg-days/Max-days sortable table**. **MH** |
| 22 | No-cost by **brand / market** | ❌ | Two `BucketBars`. **NTH** |
| 23 | Awaiting-PO by **brand / market** | ❌ | Two `BucketBars`. **NTH** |
**Bottom line:** PMs-KPI is the **largest single gap** — 6 of 12 charts absent, and the 6 present ones lack
year/period slicing and the editable norms that make them operational.
---
## 4. Board — `client/src/pages/Board/index.tsx`, `utils/board.ts`, `components/Board/BoardCard`
| Item | Status | Note / where it lives |
|---|:--:|---|
| 7-state columns | 🟡 | **6 columns** built (`unassigned, open, hold, wip, replied, awaiting`; `board.ts:18`). **7th synthetic `Closed / Awaiting-PO` column is missing** (original `CLOSED / AWAITING PO SYNTHETIC` overlay). **MH** |
| Customer-replied pseudo-status | ✅ | `boardColumn`/`isAwaitingAgency` — WIP + last touch ∉ colleague roster. Faithful. |
| Column SLA subtitles + per-column count | ✅ | `col.slaVerb(thr)` + count badge. |
| Group-by (6 permutations of WIP·Replied·Awaiting) | ❌ | Column order is fixed; original has 6 orderings (`wip-agency-await``await-agency-wip`). **NTH** |
| **16 toggleable card fields** (`card_fields`) | ❌ | `BoardCard` is a **fixed** layout showing ~8 fields (number, jira status, link, shortDesc, brand·market, assignee, in-state days, lifetime, last activity). **None toggleable.** Missing: description, raisedBy, dueDate, stateChanged, comments, createJira, jiraBar, teamsLink. Original fields: `cf-stateBadge/shortDesc/description/assignee/assignmentGroup/brandMarket/raisedBy/lifetime/dueDate/stateChanged/lastActivity/comments/createJira/showJiraStatus/showJiraBar/teamsChannelLink`. **NTH** |
| Custom labels registry | ❌ | Original `custom_label` system (per-ticket labels + filter). Absent. **NTH** |
| Staleness / PO / jira-stuck / missing-cost badges | ❌ | `BoardCard` has no badges beyond the jira-status chip. **NTH** |
| **Sort (14 options)** | ❌ | No sort control. Original: `default, number, status-age-asc/desc, lifetime-asc/desc, jira-assignee, jira-status, brand, cost-asc/desc, due-asc/desc, analyzed`. **NTH** |
| Filters: search / brand / market / assignee | ✅ | Present in the board header. |
| Filters: **region EU/LATAM** sentinels | ❌ | `latamAssignees` is ingested (`config.json`) but the assignee dropdown has no EU/LATAM region grouping. **NTH** |
| Filters: requester, custom-label, jira-assignee, jira-status | ❌ | None. **NTH** |
| Filters: staleness (stale/updated/inactive/PO/jira-stuck/missing-cost), hide-empty, hide-cost | ❌ | Original `group-by` chips + status-label filters. Absent. **NTH** |
| List view | ✅ | `TicketTable` toggle (fixed columns, not the same field set). |
| Card click behaviour | 🟡 | Opens an in-app `TicketDetailModal` (+ a SNOW link icon). Original opens ServiceNow directly. Acceptable divergence. |
| Filtered Excel export | ✅ | **New**`utils/excel.utils.ts`, 17 cols, honours active filters. |
| Azure DevOps focus board | ❌ | Out of scope per spec (§0). **LOW** |
---
## 5. PM Insights — `client/src/pages/Insights/index.tsx` + `server/insights.ts`
| Item | Status | Note / where it lives |
|---|:--:|---|
| Alert groups (Unassigned, Open/Assigned, On-Hold, WIP-stalled, WIP-no-Jira, Customer-replied, Awaiting) | ✅ | `insights.ts` 9 groups; support rules `jiraBreached`/`clientOwed`/`isAwaitingAgency` ported. |
| Informational groups (Lifetime ≥90d, Inactive requester) | ✅ | Present, excluded from Total Alerts. |
| ∑ Total Alerts + Revenue-at-Risk | ✅ | Distinct-count reconciled (verifier-log). |
| Waiting-PO count + revenue + **L1/L2/L3** | 🟡 | Counts + revenue present; **no per-level (L1/L2/L3) drill-down lists**. `insights.ts:140`. **NTH** |
| PM-KPI table (# Tickets · $ Revenue · ⚠ Rev-at-Risk) | 🟡 | Table present; **not sortable**, and **hidden-PMs from `pm_kpi_settings` not honoured**. **NTH** |
| **Excel export of the insights subtree** (PM→Size→Ticket) | ❌ | Original `xl-export.js` writes PM/Size/Ticket-grouped sheets. FORGE has board export only. **MH** |
| **Region / PO / people filters** | ❌ | Original insights has EU/LATAM region + PO + people filters. Absent. **NTH** |
| **Per-PM size stats** | ❌ | No size breakdown inside the PM roll-up. **NTH** |
| **"Missing tickets" overlay** | ❌ | Original reconciliation overlay (tickets present in one source, absent in another). Absent. **LOW** |
---
## 6. Jira board page — **MISSING ENTIRELY** ❌ (MH for Jira ops, else NTH)
Original `jira-board.html` + `jira-board.js` (2378 LOC): columns from `jira_board_state`, cards, RITM↔Jira
link (`jira-ritm-link.js`), quick-filters, settings panel (board URL, scan controls, PO-cache clear), toasts,
scan countdown. FORGE has **no route, no page, no `jira_board_state` ingest** (`dump-to-archives.mjs` only
reads `jira_status_map`). Would live as `client/src/pages/JiraBoard/` + a `jira_board` archive/table + a
`/api/jira/board` endpoint.
---
## 7. Sync / extension — `extension/background.js` (+ `popup.js`, `options.js`)
FORGE's collector is **active-RITM only, shallow**. Original `background.js` (5219 LOC) is far deeper.
| Aspect | Status | Note |
|---|:--:|---|
| SNOW active RITM scan | ✅ | `pageCollector` pages `sc_req_item`, `assignment_groupLIKEMarketing Web Presence`. |
| Field depth | 🟡 | Only **9 fields** (number, short_desc, state, assigned_to, group, opened_at, due_date, updated_by, updated_on). No brand/market/BU/requester/cost/activity timeline/state-change history. Rich fields survive only from the **seed**, kept alive by COALESCE upsert. **MH** |
| **SCTASK support** | ❌ | RITM-only. Original scans **SCTASK** too (`background.js` `sctask`/`SCTASK`). **NTH** |
| **Closed-ticket collector** | ❌ | No closed scan; closed data is seed-only, goes stale. **MH** |
| **Jira collector (+ statusDurations)** | ❌ | No Jira scanning; `jira_status_map`/`statusDurations`/`jira_board_state` never refreshed. **MH** |
| **Finance xlsx scan** | ❌ | Original scans the SharePoint finance workbook (`finance_xlsx`); FORGE finance is a one-shot seed from the dump. **MH** |
| Popup = RITM list + Jira tab | 🟡 | FORGE popup is **sync-only** (server URL + token + "Sync now"). Original popup is a RITM browser + Jira tab. **LOW** (by design — web app replaces it) |
---
## 8. Finance — `server/db.ts:applyFinance` + `scripts/dump-to-archives.mjs:106`
| Item | Status | Note |
|---|:--:|---|
| Finance ingest (cost / currency / PO / invoiced) | ✅ | `finance.json` (860 rows) → fills `finalCost`/`poNumber`/`invoiced`, recomputes size. |
| Milestone / PM / state columns | 🟡 | **Parsed into `finance.json`** (`milestone`, `pm`, `state`) **but never surfaced** — DB has no columns for them and no UI reads them. **NTH** |
| **Finance view** (invoicing / milestone / filters) | ❌ | No finance page. PO/invoiced only appear as an Excel column + waiting-PO signal. **NTH** |
---
## 9. Size CALC tool — **MISSING ENTIRELY** ❌ (NTH)
Original `size-calc.js` (692 LOC): a labor→size estimator (inputs by **role × hours × rate**, config
`lis_size_calc_cfg`, `MATCH`/`composite` algorithms). FORGE has a server `sizeOf(cost)` helper
(`db.ts:156`) that assigns sizes to tickets, but **no interactive estimator tool/page**. Would live as
`client/src/pages/SizeCalc/` + a `lis_size_calc_cfg` config key.
---
## 10. Config / options editors — **MISSING ENTIRELY** ❌ (mixed)
FORGE loads config **read-only** from `config.json`/`app_config` (seeded once). The original `options.html`/
`options.js` (629 LOC) is a rich settings surface with **no FORGE equivalent** (the FORGE Admin page is
Users+Tokens only). Missing editors, each `GET /api/config` reads but nothing writes:
| Setting (original id) | Status | Value |
|---|:--:|---|
| Brand colours editor (`brand_colors`, add/reset) | ❌ | **NTH** — 45 brands seeded, not editable in-app. |
| SLA norms editors (otd/avgdays/asla/psla/ttfr/cresp) | ❌ | **MH** — required by §3a editable-norms gap. |
| Insights thresholds editor (`insights_thresholds`) | ❌ | **NTH** |
| Size cost-thresholds editor (`otd_cost_thresh`) | ❌ | **NTH** |
| Card-field toggles (`cf-*`, 16) + mobile fields (`mf-*`) | ❌ | **NTH** — pairs with the board card-fields gap. |
| Colleague names (`colleagueNames`) / LATAM assignees (`latamAssignees`) | ❌ | **NTH** — seeded, not editable. |
| Display currency (`displayCurrency`) | ❌ | **LOW** — fixed GBP. |
| Custom labels (`custom-labels`, clear-all) | ❌ | **NTH** |
| SNOW field colours (`color-*`, 6) | ❌ | **LOW** — SNOW-page injection only, N/A to web app. |
| Card layout breakpoints (`card_layout`) | ❌ | **LOW** |
| Scan intervals / enables (analyticsIntervalHours, snRescanInterval, dashboardEnabled, jiraNotificationsEnabled, soundEnabled, analyzeButtonsEnabled) | ❌ | **LOW** — extension/SNOW-page behaviour. |
| Teams bot (`teamsBotEnabled`, chat names) | ❌ | **LOW** — out of scope. |
---
## 11. Other
| Item | Status | Note |
|---|:--:|---|
| AI Advisor / at-risk (`advisor-*.js`, `advisor-server/`) | ❌ (intended) | **Excluded per spec §1** ("user excluded AI"). Confirmed out of scope — do not port. |
| Teams integration (`teamsChannelLink`, teams bot) | ❌ | Out of scope-ish. **LOW** |
| Figma links (`figma-links.js`, 244 LOC) | ❌ | Optional per spec. **LOW** |
| Weather | — (no gap) | Excluded per spec **and dead in the original** — manifest keeps open-meteo/nominatim host perms but no weather JS remains. Nothing to port. |
| Docs page (`docs.html`/`docs.js`) | ❌ | In-app help. **LOW** |
| Archive import / export | 🟡 | `scripts/dump-to-archives.mjs` + `npm run reseed` is a **manual CLI** path; no in-app import/export UI. **LOW** |
| SCTASK support | ❌ | See §7 — RITM-only. **NTH** |
| Extension popup RITM browser | 🟡 | See §7. **LOW** |
| **New in FORGE (beyond original):** RBAC (4 roles), Users/Tokens Admin page, session auth, Postgres, server analytics engine | ✅ | Net-additive; no parity gap. |
| Legacy/unrouted FORGE pages: `pages/Dashboard`, `pages/Stats` | — | `Dashboard` is unrouted (superseded by `Board`); `Stats` is a thin `/stats` count page. Housekeeping, not a gap. |
---
## 12. Recommended next phases (prioritized)
**Phase A — PMs-KPI completion (highest value, biggest gap).**
1. Add **year/period granularity + current-vs-previous-year** to the 6 SLA heatmaps (`getSlaHeatmaps` + period control). *(MH)*
2. **Editable norms** — a `POST /api/config/norms` write path + inline norm panels (also unblocks the options editor). *(MH)*
3. Charts **18 (workload/month per-PM)**, **20 (missing final cost)**, **21 (awaiting-PO Cost/Avg/Max sortable)**. *(MH)*
4. Chart **19 engagement + `CalendarHeatmap`** (needs per-day activity/jira-movement ingest). *(MH, larger)*
5. Charts **22/23** brand-market sub-cards. *(NTH)*
**Phase B — Overall/Active fidelity.**
6. **YoY pies #5/#6** (fair-window + full) as `DonutChart`s. *(MH)*
7. **#17 Jira status durations** (requires `statusDurations` ingest — see Phase D). *(MH)*
8. Per-year segmentation + drill + YoY on by-BU/by-brand/by-market/by-requester; **#15 min/median/max**; **#16 status-segmented brand**; **#/% toggle**; **CGO overlay**. *(NTH)*
**Phase C — Board operability.**
9. **Sort (14)** + **group-by (6)** controls. *(NTH)*
10. **Toggleable card fields (16)** + badges (stale/PO/jira-stuck/missing-cost). *(NTH)*
11. Filters: region EU/LATAM, requester, jira-status/assignee, staleness, custom labels. *(NTH)*
12. **7th synthetic Closed/Awaiting-PO column.** *(MH)*
**Phase D — Deeper sync (unblocks a lot above).**
13. Extend the collector: **richer RITM fields + closed scan + Jira (statusDurations, jira_board_state) + finance scan + SCTASK.** *(MH — currently rich data is seed-only and goes stale.)*
**Phase E — Insights depth.**
14. **Excel export of the insights subtree** (PM→Size→Ticket); waiting-PO L1/L2/L3 drill; sortable PM table + hidden-PM support; region/PO/people filters. *(MH for export, else NTH.)*
**Phase F — Standalone features.**
15. **Jira board page** (needs Phase D jira ingest). *(MH for Jira ops.)*
16. **Options/config editor** page (brand colours, thresholds, card fields, colleagues/region, currency, custom labels). *(NTH.)*
17. **Size CALC** estimator; **finance view** (milestone/invoicing — data already parsed). *(NTH.)*
**Do not port:** AI Advisor/at-risk, weather (excluded); Teams/Figma/ADO board/docs page (low/optional).
---
## 13. Addendum — refinements from the source inventory (corroborated)
A parallel deep read of the initial app's source confirmed the above and adds:
- **Board columns:** the original renders **5 live columns** (Open/Assigned, On Hold, WIP, Customer-replied,
Awaiting) **+ the synthetic Closed/Awaiting-PO** column; Unassigned is folded into Open/Assigned. FORGE
builds 6 (splits Unassigned out) and still lacks the synthetic 7th — the §4 "7th column MH" gap stands.
- **Per-chart Excel export:** in the original **every analytics chart** carries its own Excel button
(`_xlData`/`_xlBtn``xl-export.js`). FORGE has **no per-chart export** — only the board export.
Add as an **NTH** gap across Overall/Active/PMs-KPI. Insights groups also each export (see §5, MH).
- **Missing-tickets overlay** lives on the **3 SLA/OTD charts** (OTD/AvgDays/Assign/Preview), grouping the
timestamp-less tickets by current Jira status (reachedUat / beforeUat / noJira) — reclassify the §5
"missing-tickets overlay" as part of the **PMs-KPI SLA charts** (still ❌).
- **Collector scope:** the original SN scan handles **RITM + SCTASK + INC** (not just RITM), computes
per-ticket `statusDurations` from status-change history, and runs a **Jira scan as a tail after every SN
scan**. FORGE's collector does none of this (§7) — add **INC** alongside the SCTASK gap.
- **Threshold value drift:** FORGE `config.json` has `waitingPo3: 18` and `customerReplied: 1`, vs the
original defaults `waitingPo3: 21` / `customerReplied: 3`. Minor, but reconcile when the norms/thresholds
editor lands (§10). **LOW**
- **Engagement KPI** reads the **live board** (not `ticketsMeta`), with twin Assist|Jira calendar heatmaps
and a ~14-column sortable drill-down — confirms the §3b #19 scope (**MH**, larger build).
- **Size CALC** uses 4 currencies (GBP/EUR/MXN + MXN·Brazil uplift ×1.111), roles DEV/CM/QA + auto-PM,
PM-budget tiering (`pmThreshold`/`pmHi`/`pmLo`) — confirms §9.
- **AI Advisor** is a full masked-digest + Node-bridge-to-Claude-CLI subsystem (`advisor-*.js` +
`advisor-server/`) with the At-risk breach engine — **correctly excluded**, do not port.
- **Archive import/export** exists as in-app **⬇ Archive / ⬇ Active** buttons in the original (FORGE has only
the `dump-to-archives.mjs` CLI) — the §11 🟡 stands.
None of these change the phase priorities; they sharpen scope for Phases A, D, and E.
## Next
principal — sequence Phase A (PMs-KPI) as the next build; confirm which board/insights sub-items are in v1 scope.