7.1 KiB
Evidence Topic: Channel BI post-update data contamination
Metadata
- Date: 2026-07-30
- Status: Active
- Scope: ARR2 local Web port 8766, controlled
booking_test, Channel BI and July monthly publication - Confidence: Fact
- Source: source/hash inspection, isolated deterministic replay, live privacy-minimized APIs, repeatable-read read-only PostgreSQL reconciliation and focused tests
- Last verified: 2026-07-30
- Stale trigger: any change to July current Finance pins, retirement of fixture version 2, monthly republication, or BI grouping/label behavior
Question
What data does Channel BI consume, and why did its July values look wrong after the latest uploads?
Evidence
Implemented source and formulas
- The browser calls
/api/analytics?month=YYYY-MM;PostgresPortalRepositorydelegates toPostgresAnalyticsRepositoryagainstbooking_test. - Month/date pins come from
finance.current_daily_versions, channel membership/order/count expectations fromfinance.daily_channel_metrics, and aggregates/detail from current retainedfinance.v_active_daily_facts. - Sold rooms are
sum(no_of_rooms), room nights aresum(no_of_rooms * nights), and revenue issum(total_price)without multiplying the stored total again. Monthly XLSX files are not a BI source.
Live reconciliation
The active ARR2 Web API on port 8766 and direct PostgreSQL reads return the same current projection. Legacy port 8765 is no longer listening.
| Business date | Daily version | Provenance | Retained rows | Revenue | Current role |
|---|---|---|---|---|---|
| 2026-07-20 | 5 | 0720.XML, hash-matched real upload |
100 | 370,500 | valid real daily slice |
| 2026-07-21 | 4 | real ARR upload | 119 | 452,000 | V01 operational source |
| 2026-07-22 | 6 | 0722.XML, hash-matched real upload |
88 | 269,700 | valid real daily slice |
| 2026-07-23 | 7 | 0723-RES_DETAIL-修正版.xml, hash-matched real upload |
109 | 359,150 | valid real daily slice |
| 2026-07-27 | 2 | mvp-v1-fixture-20260727 / synthetic.xml / local_fixture |
1 | 5,400 | test contamination |
- The 07-23 upload committed at 16:12:27, after the earlier 15:44 diagnostic snapshot. This explains why that snapshot contained only 307 real rows; it did not prove the four-day business total.
- Excluding fixture version 2 now yields 416 rows/rooms, 853 room-nights, 1,451,350 revenue, nine room types, six worksheet channels and latest real ARRIVAL 2026-07-23.
- The live BI includes the fixture and therefore returns 417 rows/rooms, 856 room-nights, 1,456,750 revenue, ten room
types and
更新至 2026-07-27. Its extra type is explicitlySYNTHETIC ROOM TYPE. - July monthly V04 is active with 417 rows; V01–V04 all inherit fixture version 2 and its false operational 7.27 watermark.
Source identity and date attribution
- Immutable source SHA-256 maps the accepted sources exactly to local originals:
0720.XMLis version 5 and0722.XMLis version 6;0721.XMLand0723-RES_DETAIL-修正版.xmlmap to versions 4 and 7 respectively. - The processor derives business date from agreeing XML
GROUPBY1_SORT_COL/GROUPBY1_COLvalues and requires each retained reservation ARRIVAL to match it; filename and upload order are not date authorities. - An isolated replay independently reproduced
0720.XML -> 2026-07-20 -> 100 retainedand0722.XML -> 2026-07-22 -> 88 retained. The user was correct about the 416 total but had those two day counts verbally reversed.
Frontend freshness
- Channel BI loads at page boot, month change, or first BI-tab entry only. A successful XML upload refreshes daily jobs
but not analytics, and later BI-tab entries skip reload once
state.analyticsexists. - Therefore an already-open page can continue showing the pre-07-23 value 308 even though the API has advanced to 417. Unlike the monthly list, Channel BI has no polling or visibility-aware reload.
Exact V01 reconciliation
- V01 report ID 1 is persisted as superseded,
as_of_date=2026-07-27, 120 rows and five channels. - Its legitimate OSS source lineage is daily version 4: 119 retained rows, all with
ARRIVAL=2026-07-21. - Its only later lineage is daily version 2: one retained row with
ARRIVAL=2026-07-27, accepted under runmvp-v1-fixture-20260727fromsynthetic.xmlusing providerlocal_fixture. - Reopening the exact registered V01 workbook independently found the same 119/1 ARRIVAL distribution. The file is
20,741 bytes and its SHA-256
a43cdac3f6d97f6b73f635d0f386cffd0ad8b6416e8f92a7b6afc2f79f1e8635matches the artifact registry. - Therefore the user's operational statement “V01 is updated through 2026-07-21” is correct. The stored 7.27 label is the consequence of contaminated report content, not a filename parser or a metadata-only rendering defect.
Channel/company semantics
- Six channel keys are valid for these real facts: LianTai intentionally splits into
LIANTAI-GROUPandLIANTAI-FIT, alongside QBD, DY-AI-Easy-KB, FENGRUN and HanaTour. - The BI card renders worksheet-level
channel_countbut labels it公司数; six channels can represent five top-level companies, so the label is misleading even after data cleanup.
Regression and mutation boundary
- The corrected focused run passed 24 analytics-contract, PostgreSQL-provider and Web tests.
- All database investigations used
REPEATABLE READ READ ONLY; no Finance pointer, version, artifact or report was changed during diagnosis.
Finding
Channel BI is correctly reading and aggregating its configured current PostgreSQL facts. One proven cause of the reported mismatch is a data-hygiene incident: a database acceptance fixture remained pinned as a current Finance day after real uploads were enabled. It explains the one-room difference between the correct real total 416 and live API total 417, as well as every false 7.27 watermark. A second frontend defect can leave an open BI view showing 308 after the 07-23 commit. The user's 07-20/07-22 verbal attribution was reversed, but this does not change the 416 total. A smaller UX issue independently mislabels worksheet-channel count as company count.
Impact
- Business-facing July BI and monthly V04 are not clean acceptance outputs until fixture version 2 is removed from the current projection and a clean July monthly version is published.
- Historical V01 cannot be truthfully corrected by changing only its
as_of_dateor filename because the registered workbook itself contains the fixture row. Preserve that immutable artifact as contaminated audit history and publish a clean operational replacement after the current projection is corrected. - Remediation should preserve immutable audit history; retire/unpin the fixture instead of deleting its version rows.
- Production/readiness checks should reject any current Finance source whose provider is
local_fixture(or other explicitly non-operational provenance).
Open Items
- Obtain authorization for the controlled Finance-pointer repair and clean monthly republication.
- Make Channel BI refresh after successful upload and/or on visible BI-tab re-entry so it cannot retain an old snapshot.
- Decide whether to relabel the BI card as
渠道/子表数or add a distinct five-company aggregation.