Add ImportGenius customs shipment monitoring

This commit is contained in:
seanbetts committed 2026-05-22 20:29:25 +01:00
1 parent cde4f5f5fc
commit a1fee7a4df
17 files changed
+864 -31

No files matched your search

+2 -1
View File
@@ -287,11 +287,12 @@ Run customs checks every normal watch run because ImportInfo is quick and high-s
Primary automated customs source:
- ImportInfo search pages for `CEVA C/O VALVE CORPORATION`, `INGRAM MICRO C/O VALVE CORPORATION`, `TECH-FRONT GAME CONSOLE VALVE`, and `VALVE CORPORATION GAME CONSOLE`
- ImportGenius public importer page for `INGRAM MICRO C/O VALVE CORPORATION`
Corroborating/manual sources:
- NBD Valve and Ingram/Valve trader pages
- ImportGenius public previews for CEVA/Valve, Ingram/Valve, and Tech-Front
- ImportGenius public previews for CEVA/Valve and Tech-Front when not covered by the automated importer page
Do not use HMRC UK Trade Info for launch monitoring. It is lagged monthly trader/commodity presence, not shipment-level evidence.
+1
View File
@@ -228,6 +228,7 @@ Run ImportInfo customs checks every normal watch run because they are quick and
- ImportInfo automated search for Ingram/Valve: `https://www.importinfo.com/search?s=INGRAM%20MICRO%20C%2FO%20VALVE%20CORPORATION`
- ImportInfo automated search for Tech-Front game console Valve: `https://www.importinfo.com/search?s=TECH-FRONT%20GAME%20CONSOLE%20VALVE`
- ImportInfo automated search for Valve Corporation game console: `https://www.importinfo.com/search?s=VALVE%20CORPORATION%20GAME%20CONSOLE`
- ImportGenius automated importer page for Ingram Micro C/O Valve Corporation: `https://www.importgenius.com/importers/ingram-micro-c-o-valve-corporation`
- ImportInfo manual/corroborating Tech-Front supplier page: `https://www.importinfo.com/tech-front-chongqing-computer-co`
- ImportInfo manual/corroborating Valve Corporation page: `https://www.importinfo.com/valve-corporation`
- NBD Valve Corporation public company page: `https://en.nbd.ltd/trader/info/NBDD3Y527621220`
+45
View File
@@ -31,6 +31,16 @@ looks_like_importinfo_shipment_table() {
return 0
}
looks_like_importgenius_shipment_page() {
path=$1
for marker in "Bill of Lading" "GAME CONSOLE" "VALVE CORPORATION"; do
if ! grep -qi "$marker" "$path"; then
return 1
fi
done
return 0
}
fetch_importinfo() {
slug=$1
query=$2
@@ -62,6 +72,37 @@ fetch_importinfo() {
return 1
}
fetch_importgenius() {
slug=$1
query=$2
url=$3
tmp=$OUT_DIR/$slug.html.tmp
out=$OUT_DIR/$slug.html
if curl \
-A "$IMPORTINFO_USER_AGENT" \
-H "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8" \
-H "Accept-Language: en-US,en;q=0.9" \
--retry 2 \
--retry-delay 2 \
--max-time 45 \
-fsSL "$url" > "$tmp" 2>/dev/null
then
if ! looks_like_importgenius_shipment_page "$tmp"; then
rm -f "$tmp" "$out"
printf 'unexpected or blocked content from %s\n' "$url" >> "$ERROR_FILE"
return 0
fi
mv "$tmp" "$out"
printf '%s\t%s\t%s\n' "$query" "$url" "$out" >> "$MANIFEST"
return 0
fi
rm -f "$tmp" "$out"
printf 'failed to fetch %s\n' "$url" >> "$ERROR_FILE"
return 1
}
fetch_importinfo \
"importinfo-ceva-valve" \
"ceva-valve" \
@@ -78,6 +119,10 @@ fetch_importinfo \
"importinfo-valve-corporation" \
"valve-corporation-game-console" \
"https://www.importinfo.com/search?s=VALVE%20CORPORATION%20GAME%20CONSOLE" || true
fetch_importgenius \
"importgenius-ingram-valve" \
"importgenius-ingram-valve" \
"https://www.importgenius.com/importers/ingram-micro-c-o-valve-corporation" || true
python3 "$SCRIPT_DIR/parse_importinfo_shipments.py" \
--manifest "$MANIFEST" \
+5 -5
View File
@@ -74,7 +74,7 @@ fetch_json() {
if [ "$allow_fallback" = "1" ] && [ "${KOMODO_PLAYWRIGHT_FALLBACK:-0}" = "1" ] && command -v playwright-cli >/dev/null 2>&1; then
maybe_set_cdp_endpoint
PLAYWRIGHT_CLI_BIN="$(command -v playwright-cli)"
PLAYWRIGHT_CORE_PATH="$(CDPATH= cd -- "$(dirname "$PLAYWRIGHT_CLI_BIN")/../lib/node_modules/@playwright/cli/node_modules/playwright-core" && pwd 2>/dev/null || true)"
PLAYWRIGHT_CORE_PATH="$(CDPATH= cd -- "$(dirname "$PLAYWRIGHT_CLI_BIN")/../lib/node_modules/@playwright/cli/node_modules/playwright-core" 2>/dev/null && pwd || true)"
PLAYWRIGHT_CORE_PATH="$PLAYWRIGHT_CORE_PATH" node "$SCRIPT_DIR/fetch_with_playwright.js" "$url" "$tmp"
if jq empty "$tmp" >/dev/null 2>&1; then
mv "$tmp" "$OUT_DIR/$name.json"
@@ -99,12 +99,12 @@ if ! fetch_json "product-controller-jpy" "https://komodostation.com/wp-json/wp/v
exit 0
fi
fetch_json "product-machine-jpy" "https://komodostation.com/wp-json/wp/v2/product/413772" 0 || true
fetch_json "product-frame-jpy" "https://komodostation.com/wp-json/wp/v2/product/413776" 0 || true
fetch_json "product-machine-jpy" "https://komodostation.com/wp-json/wp/v2/product/413772" || true
fetch_json "product-frame-jpy" "https://komodostation.com/wp-json/wp/v2/product/413776" || true
fetch_json "sections-controller-search" "https://komodostation.com/wp-json/wp/v2/sections?search=Steam%20Controller&per_page=100" || true
fetch_json "sections-machine-search" "https://komodostation.com/wp-json/wp/v2/sections?search=Steam%20Machine&per_page=100" 0 || true
fetch_json "sections-frame-search" "https://komodostation.com/wp-json/wp/v2/sections?search=Steam%20Frame&per_page=100" 0 || true
fetch_json "sections-machine-search" "https://komodostation.com/wp-json/wp/v2/sections?search=Steam%20Machine&per_page=100" || true
fetch_json "sections-frame-search" "https://komodostation.com/wp-json/wp/v2/sections?search=Steam%20Frame&per_page=100" || true
fetch_json "media-controller-search" "https://komodostation.com/wp-json/wp/v2/media?search=Steam%20Controller&per_page=100" || true
fetch_json "media-parent-product-controller" "https://komodostation.com/wp-json/wp/v2/media?parent=413763&per_page=100" || true
+2
View File
@@ -155,6 +155,8 @@ def build_draft(run_dir: Path):
lines.extend(["", "#### Customs / Shipments"])
if not customs_outputs_available:
lines.append("- Customs shipment outputs were not generated or are unavailable for this run.")
elif customs_blocked and customs_lines:
lines.append("- Customs shipment rows were captured, but some source fetches failed or were blocked. See `customs-shipments-errors.txt`.")
elif customs_blocked:
lines.append("- Customs shipment fetches failed or were partially blocked in this run. See `customs-shipments-errors.txt`.")
if customs_lines:
+65
View File
@@ -2,6 +2,7 @@
import argparse
import csv
import html
import re
from dataclasses import dataclass
from html.parser import HTMLParser
from pathlib import Path
@@ -68,6 +69,7 @@ SOURCE_URLS = {
"ingram-valve": "https://www.importinfo.com/search?s=INGRAM%20MICRO%20C%2FO%20VALVE%20CORPORATION",
"tech-front-game-console": "https://www.importinfo.com/search?s=TECH-FRONT%20GAME%20CONSOLE%20VALVE",
"valve-corporation-game-console": "https://www.importinfo.com/search?s=VALVE%20CORPORATION%20GAME%20CONSOLE",
"importgenius-ingram-valve": "https://www.importgenius.com/importers/ingram-micro-c-o-valve-corporation",
}
@@ -127,11 +129,34 @@ class TableParser(HTMLParser):
self._current_cell_parts.append(data)
class TextParser(HTMLParser):
def __init__(self):
super().__init__()
self.parts = []
def handle_starttag(self, tag, attrs):
if tag in ("br", "p", "tr", "li", "h1", "h2", "h3", "section"):
self.parts.append("\n")
def handle_endtag(self, tag):
if tag in ("p", "tr", "li", "h1", "h2", "h3", "section"):
self.parts.append("\n")
def handle_data(self, data):
self.parts.append(data)
def text(self):
return html.unescape(" ".join("".join(self.parts).split()))
def normalize_header(value):
return FIELD_MAP.get(value.strip().lower(), "")
def parse_rows(spec):
if spec.query.startswith("importgenius-"):
return parse_importgenius_rows(spec)
parser = TableParser()
parser.feed(spec.path.read_text(encoding="utf-8", errors="ignore"))
rows = []
@@ -149,6 +174,46 @@ def parse_rows(spec):
return rows
def parse_importgenius_rows(spec):
parser = TextParser()
parser.feed(spec.path.read_text(encoding="utf-8", errors="ignore"))
text = parser.text()
pattern = re.compile(
r"(?:^|\s)(?P<rank>\d+)\s+"
r"(?P<bol>[A-Z0-9]+)\s+"
r"(?P<product>GAME\s+CONSOLE\s*\.?)\s+"
r"(?P<importer>(?:INGRAM\s+MICRO|CEVA)\s+C/O\s+VALVE\s+CORPORATION)\s+"
r"(?P<supplier>TECH-?FRONT\s+\(CHONGQING\)\s+COMPUTER\s+CO)\s+"
r"(?P<arrival>\d{4}-\d{2}-\d{2})\s+"
r"(?P<country>[A-Za-z ]+?)\s+"
r"(?P<weight>[\d,]+\s+Kgs)\s+"
r"(?P<quantity>\d+\s+PKG)",
re.IGNORECASE,
)
rows = []
for match in pattern.finditer(text):
record = {field: "" for field in OUTPUT_FIELDS}
record["source"] = "importgenius"
record["query"] = spec.query
record["house_bol"] = match.group("bol").upper()
record["arrival_date"] = match.group("arrival")
record["foreign_port"] = match.group("country").strip()
record["quantity"] = " ".join(match.group("quantity").split())
record["weight"] = " ".join(match.group("weight").split())
record["shipper"] = normalize_company(match.group("supplier"))
record["consignee"] = normalize_company(match.group("importer"))
record["notify_party"] = record["consignee"]
record["commodity"] = " ".join(match.group("product").upper().split())
record["source_url"] = spec.source_url
if is_relevant(record):
rows.append(record)
return rows
def normalize_company(value):
return " ".join(value.upper().replace("TECH FRONT", "TECH-FRONT").split())
def is_relevant(record):
party_text = " ".join(
(
+2
View File
@@ -96,6 +96,8 @@ def customs_status(reports: Path):
report = reports / "customs-shipments.md"
if not any(path.exists() for path in (key_lines, errors, report)):
return "unavailable"
if count(key_lines) and count(errors):
return "partial"
if count(errors):
return "blocked"
return "available"
+28 -21
View File
@@ -1,54 +1,56 @@
# Steam Hardware Watch Status
Last updated: `2026-05-14`
Last updated: `2026-05-22`
## Best Current Answer
- `Price`: Steam Controller remains confirmed by official Valve store APIs at `$99.00` in the US. Steam Machine and Steam Frame still have no confirmed public price.
- `Release date`: Steam Controller remains confirmed with release date `May 4, 2026` and package `1558609`. Steam Machine and Steam Frame still only expose broad `Coming soon` / `2026` timing.
- `Same-time launch`: same-day availability for the full trio is ruled out. Steam Controller is public and purchasable; Machine and Frame still have no public package, package group, price, or exact availability. Steam Machine reservation package changenumbers have now moved twice: a multi-package cluster on `2026-05-12`, followed by another bump across all four watched Machine packages on `2026-05-14`. That is a stronger Controller-like backend-prep signal for Machine, but public Valve APIs still do not expose Machine purchase or reservation readiness.
- `Same-time launch`: same-day availability for the full trio is ruled out. Steam Controller is public and purchasable; Machine and Frame still have no public package, package group, price, or exact availability. Steam Machine reservation package changenumbers have now moved twice: a multi-package cluster on `2026-05-12`, followed by another bump across all four watched Machine packages on `2026-05-14`. ImportGenius now shows continued `GAME CONSOLE` shipments to `INGRAM MICRO C/O VALVE CORPORATION` through `2026-05-18`; this is a stronger logistics corroboration signal, but public Valve APIs still do not expose Machine purchase or reservation readiness.
## Source Snapshot
### Komodo
- Komodo was partially available on `2026-05-14` through the dedicated browser fallback.
- Komodo was available again on `2026-05-22` through the dedicated browser fallback after the `2026-05-19` waiting-room block.
- Product modified timestamps captured in this run:
- Controller: `2026-05-13T09:02:58`
- Machine: `n/a` in this run because the optional Machine product fetch failed
- Frame: `n/a` in this run because the optional Frame product fetch failed
- Controller changed from `2026-05-12T09:15:51` to `2026-05-13T09:02:58`, but a direct JSON diff versus `2026-05-12` found only `modified` / `modified_gmt` changes. Treat this as timestamp-only until corroborated by visible content, media, store-state movement, or Steam metadata.
- Machine and Frame Komodo product/section endpoints failed in this run. Any compare-report lines about Machine or Frame section removal are partial-fetch artifacts, not evidence that Valve removed sections.
- Controller: `2026-05-22T15:28:27`
- Machine: `2026-04-24T14:32:54`
- Frame: `2026-04-24T14:33:36`
- Controller changed from `2026-05-15T15:50:21` to `2026-05-22T15:28:27`, but a direct JSON diff versus `2026-05-18` found only `modified` / `modified_gmt` changes. Treat this as timestamp-only until corroborated by visible content, media, store-state movement, or Steam metadata.
- Machine and Frame remain unchanged from their April 24 product timestamps, and their visible Komodo section baseline is still the old wishlist section only.
- Visual asset retrieval found `141` candidate assets, retrieved `136`, and left `5` blocked known Komodo URLs for manual retry.
### SteamKit / PICS
- SteamKit/PICS is the primary direct Steam metadata source for watched app and package movement.
- Current changenumbers from the `2026-05-14` run:
- Current changenumbers from the `2026-05-22` run:
- Controller app `4165870`: `35731145`
- Frame app `4165890`: `35675573`
- Machine app `4165910`: `35675573`
- Controller package `1558609`: `35745078`
- Machine package `1629446`: `35842876` (`35819604` on `2026-05-12`)
- Machine package `1629447`: `35842851` (`35819607` on `2026-05-12`)
- Machine package `1629458`: `35842860` (`35819602` on `2026-05-12`)
- Machine package `1629460`: `35842863` (`35819593` on `2026-05-12`)
- Controller package `1558609`: `35893035`
- Machine package `1629446`: `35842876`
- Machine package `1629447`: `35842851`
- Machine package `1629458`: `35842860`
- Machine package `1629460`: `35842863`
- Frame packages `1629484`, `1629486`: `35672606`
- The four watched Steam Machine package IDs received a follow-up SteamKit/PICS changenumber bump on `2026-05-14`. This is the strongest current signal of fresh Machine-specific backend work, especially because the two watched Steam Frame package IDs did not move.
- No watched SteamKit/PICS changenumbers moved on `2026-05-22`.
- The latest Controller package signal remains the `2026-05-17` private PICS change on package `1558609`, where `ignorereservationifstockavailable=1` was removed from the package `extended` fields. Public Valve `appdetails` / `packagedetails` still did not change.
- The latest material Machine signal remains the `2026-05-14` follow-up bump across all four watched Steam Machine package IDs, especially because the two watched Steam Frame package IDs did not move.
- Manual package-history context remains important: Steam Controller package `1558609` reportedly had a clustered change pattern plus one later follow-up change roughly two days before Valve's public purchase-timing update appeared. The Machine set now has both the initial multi-package cluster and the later follow-up bump. Treat this as a stronger imminent-preorder heuristic, not confirmation.
- Machine and Frame apps/packages currently require private PICS metadata tokens, but changenumbers are visible and suitable for movement monitoring.
- Raw snapshot: `/Users/sean/Coding/steam-hardware-watch/runs/2026-05-14/api/steamkit/pics-product-info.json`
- Human-readable detail: `/Users/sean/Coding/steam-hardware-watch/runs/2026-05-14/reports/steamkit-pics-detail.md`
- Raw snapshot: `/Users/sean/Coding/steam-hardware-watch/runs/2026-05-22/api/steamkit/pics-product-info.json`
- Human-readable detail: `/Users/sean/Coding/steam-hardware-watch/runs/2026-05-22/reports/steamkit-pics-detail.md`
### SteamDB
- Automated SteamDB access remained blocked on `2026-05-14`.
- Automated SteamDB access remained blocked on `2026-05-22`.
- The package report is still a structural baseline, not a content baseline: all watched SteamDB package rows are `missing_or_blocked`.
- SteamDB remains useful as corroborating/human-readable metadata once a trusted browser session can pass the challenge, but SteamKit/PICS now covers primary package movement.
### SteamTracking / GameTracking
- Fresh SteamTracking content still contains the known Triton/Ibex controller pairing surface:
- Fresh SteamTracking content at commit `28f5287` (`2026-05-22T04:56:58Z`) still contains the known Triton/Ibex controller pairing surface:
- `ibex_internal`
- `ibex_external`
- `PairDongleTritonConnected`
@@ -82,8 +84,13 @@ Last updated: `2026-05-14`
### Customs / Regulatory
- ImportInfo automated customs fetches were blocked on `2026-05-14`.
- The latest useful customs evidence remains the `2026-05-01` NBD / ImportGenius pass:
- Customs status on `2026-05-22`: partial. ImportInfo automated fetches were blocked, but the ImportGenius importer page fetched and parsed successfully.
- ImportGenius now lists `10` relevant `GAME CONSOLE` rows for `INGRAM MICRO C/O VALVE CORPORATION` from `2026-03-27` through `2026-05-18`.
- Newer rows since the old `2026-04-23` baseline include:
- `SNHBSHACHI265020`, arrived `2026-05-18`, `42 PKG`, `14353 Kgs`.
- `SNHBSHACHI264140`, arrived `2026-05-18`, `42 PKG`, `14533 Kgs`.
- `SNHBSHACHI264031`, arrived `2026-05-08`, `42 PKG`, `12615 Kgs`.
- The prior NBD / ImportGenius context also remains relevant:
- `WIRELESS PC CONTROLLER` row dated `2026-04-04`.
- `GAME CONSOLE` shipment arriving `2026-04-23` for `INGRAM MICRO C/O VALVE CORPORATION`.
- Customs data remains corroborating evidence only, not price/date/product-identity proof.
+2
View File
@@ -41,3 +41,5 @@
{"date_checked": "2026-05-12", "source": "steamkit-pics", "entity": "steam-machine", "claim": "SteamKit/PICS shows all four watched Steam Machine reservation package IDs moved since the 2026-05-11 baseline.", "evidence_type": "steam_product_info_changenumber_delta", "confidence": "high", "ref": "/Users/sean/Coding/steam-hardware-watch/runs/2026-05-12/reports/steamkit-pics-detail.md", "notes": "Machine packages 1629446, 1629447, 1629458, and 1629460 changed from changenumber 35672615 to 35819604, 35819607, 35819602, and 35819593 respectively. Rows still require private PICS metadata tokens and Valve appdetails/packagedetails remain non-public, so this is backend movement rather than confirmed public launch readiness."}
{"date_checked": "2026-05-12", "source": "manual-steamdb-pattern", "entity": "steam-machine,steam-controller", "claim": "Steam Machine package-history movement resembles the Steam Controller package pattern observed before public purchase timing appeared.", "evidence_type": "package_history_pattern_comparison", "confidence": "medium", "ref": "/Users/sean/Coding/steam-hardware-watch/status/runs/2026-05-12.md", "notes": "Manual package-history observation: Steam Machine packages changed in an uneven 1/3/3/4 pattern across about three minutes. Steam Controller package 1558609 reportedly had three changes in about 40 minutes plus one later follow-up roughly two days before Valve publicly exposed purchase timing. This increases near-term watch priority but does not confirm preorder timing without public Valve API movement."}
{"date_checked": "2026-05-14", "source": "steamkit-pics", "entity": "steam-machine", "claim": "SteamKit/PICS shows a second follow-up changenumber bump across all four watched Steam Machine reservation package IDs.", "evidence_type": "steam_product_info_followup_changenumber_delta", "confidence": "high", "ref": "/Users/sean/Coding/steam-hardware-watch/runs/2026-05-14/reports/steamkit-pics-detail.md", "notes": "Machine packages 1629446, 1629447, 1629458, and 1629460 moved from 35819604/35819607/35819602/35819593 on 2026-05-12 to 35842876/35842851/35842860/35842863 on 2026-05-14. Frame packages 1629484 and 1629486 stayed at 35672606, and public Valve appdetails/packagedetails still expose no Machine packages, package groups, price, or exact timing."}
{"date_checked": "2026-05-17", "source": "steamkit-pics", "entity": "steam-controller", "claim": "SteamKit/PICS shows Steam Controller package 1558609 moved and removed an ignore-reservation-if-stock-available flag.", "evidence_type": "steam_product_info_package_field_delta", "confidence": "high", "ref": "/Users/sean/Coding/steam-hardware-watch/runs/2026-05-17/reports/steamkit-pics-detail.md", "notes": "Controller package 1558609 moved from changenumber 35745078 to 35893035 and changed SHA from 02235CA28137E71E7AFA02A0F45743DBEBA925EF to CE75692F2679EF8A91C3C9CBB58D09456350EC64. The available PICS KeyValues diff shows extended field ignorereservationifstockavailable=1 was removed. Public Valve appdetails/packagedetails were unchanged, and watched Machine and Frame package changenumbers did not move."}
{"date_checked": "2026-05-22", "source": "importgenius-customs", "entity": "steam-machine,steam-frame", "claim": "ImportGenius shows continued US-bound GAME CONSOLE shipments to Ingram Micro C/O Valve Corporation through May 18, 2026.", "evidence_type": "customs_import_record", "confidence": "medium", "ref": "/Users/sean/Coding/steam-hardware-watch/runs/2026-05-22/reports/customs-shipments.md", "notes": "Parsed 10 relevant ImportGenius rows for INGRAM MICRO C/O VALVE CORPORATION / TECH-FRONT (CHONGQING) COMPUTER CO. Newer rows since the April 23 baseline include May 18 BOLs SNHBSHACHI265020 and SNHBSHACHI264140 plus May 8 BOL SNHBSHACHI264031. Customs rows say GAME CONSOLE but do not identify the specific Valve hardware SKU."}
+8 -4
View File
@@ -6,16 +6,20 @@
- Material finding: SteamKit/PICS shows a second/follow-up changenumber bump across all four watched Steam Machine reservation package IDs since the `2026-05-12` run.
- Steam Frame package IDs did not move.
- Valve public APIs still do not expose Steam Machine or Steam Frame package groups, public package details, price, exact release timing, or purchase/reservation readiness.
- Komodo was partially recovered through the dedicated browser fallback for Controller data, but Machine and Frame optional Komodo endpoints still failed.
- Komodo was recovered through the dedicated browser fallback after raw `curl` hit Cloudflare challenge pages.
## Source Checks
### Komodo
- Initial automated Komodo access was blocked.
- Dedicated browser fallback recovered the Controller product enough to record a new modified timestamp: `2026-05-13T09:02:58`.
- Initial automated Komodo access was blocked by Cloudflare challenge pages.
- Dedicated browser fallback recovered Controller, Machine, and Frame product/section data.
- Product modified timestamps:
- Controller: `2026-05-13T09:02:58`
- Machine: `2026-04-24T14:32:54`
- Frame: `2026-04-24T14:33:36`
- Controller JSON diff versus `2026-05-12` is timestamp-only (`modified` / `modified_gmt`).
- Machine and Frame product/section fetches failed in this run. Compare-report lines suggesting Machine/Frame section removal should be treated as partial-fetch artifacts.
- Machine and Frame remain unchanged on Komodo and still only expose the old wishlist section baseline.
- Visual assets: `141` discovered, `136` retrieved, `5` blocked known Komodo URLs.
### SteamKit / PICS
+85
View File
@@ -0,0 +1,85 @@
# Run Note: 2026-05-15
## Summary
- Full skill run completed with artifacts under `/Users/sean/Coding/steam-hardware-watch/runs/2026-05-15`.
- No watched SteamKit/PICS changenumbers moved versus the `2026-05-14` report.
- Valve public APIs still do not expose Steam Machine or Steam Frame package groups, public package details, price, exact release timing, or purchase/reservation readiness.
- Komodo was recovered through the dedicated browser fallback after the first attempt hit a stale CDP endpoint and raw `curl` hit Cloudflare challenge pages.
- Komodo Controller has a new modified timestamp, but the product JSON diff versus `2026-05-14` is timestamp-only.
## Source Checks
### Komodo
- Dedicated browser fallback recovered Controller, Machine, and Frame product/section data.
- Product modified timestamps:
- Controller: `2026-05-15T15:50:21`
- Machine: `2026-04-24T14:32:54`
- Frame: `2026-04-24T14:33:36`
- Controller JSON diff versus `2026-05-14` is timestamp-only (`modified` / `modified_gmt`).
- Machine and Frame remain unchanged on Komodo and still only expose the old wishlist section baseline.
- Visual assets: `141` discovered, `136` retrieved, `5` blocked known Komodo URLs.
### SteamKit / PICS
- SteamKit/PICS completed successfully.
- No watched app or package changenumbers moved versus `2026-05-14`.
- Current Machine package changenumbers:
- `1629446`: `35842876`
- `1629447`: `35842851`
- `1629458`: `35842860`
- `1629460`: `35842863`
- Frame packages stayed unchanged:
- `1629484`: `35672606`
- `1629486`: `35672606`
- Interpretation: today's run does not add a new Machine signal. The latest material Machine signal remains the `2026-05-14` follow-up bump across all four watched Machine package IDs.
### SteamDB
- Automated SteamDB access remained blocked.
- Reservation package rows remain `missing_or_blocked`, so SteamDB is still not a human-readable corroborating baseline for the recent Machine package movement.
### SteamTracking / GameTracking
- No new Machine or Frame price, reservation, package, or release-date signal was found.
### SteamVR Depots
- SteamVR news metadata was saved.
- SteamDB SteamVR depot metadata remained blocked.
- No fresh depot manifest/build comparison was collected.
### SteamOS Package Mirror
- Public mirror remained reachable.
- `fremont-hw-support 20260506.1-1` remains visible in `holo-3.8` and `holo-main`.
- No direct Steam Machine, Steam Frame, Deckard, Roy, ARM/Snapdragon, or new product-specific namespace surfaced in this pass.
### Valve Support / CDN
- Valve public endpoints were reachable.
- Controller remains public with package `1558609`, package group present, and `$99.00`.
- Frame app `4165890` remains `Coming soon`, with no public packages, no package groups, and no price.
- Machine app `4165910` remains `Coming soon`, with no public packages, no package groups, and no price.
- Machine packages `1629446`, `1629447`, `1629458`, `1629460` still return `packagedetails success:false`.
- Frame packages `1629484`, `1629486` still return `packagedetails success:false`.
### Customs / Regulatory
- ImportInfo automated customs fetches were blocked.
- No new customs evidence was added.
## Effect On Key Questions
- Price: unchanged. Only Steam Controller has a confirmed price.
- Release date: unchanged. Only Steam Controller has a confirmed exact date.
- Same-time launch: unchanged. Full same-day launch remains ruled out.
- Product furthest along: Steam Controller is already public/purchasable. Among unreleased hardware, Steam Machine still has the strongest recent backend-prep signal because of the `2026-05-12` and `2026-05-14` package movement, but there was no additional PICS movement today.
## Next Checks
- Continue focused SteamKit/PICS checks for watched package IDs.
- Watch Valve public `appdetails` / `packagedetails` for Machine package exposure, package groups, price, reservation text, or purchase eligibility.
- Complete a trusted-browser SteamDB package-history pass for Machine packages `1629446`, `1629447`, `1629458`, and `1629460`.
- Treat Komodo Controller timestamp movement as low-value unless a future diff shows content, media, stock-state, or section changes.
+92
View File
@@ -0,0 +1,92 @@
# Run Note: 2026-05-17
## Summary
- Full skill run completed with artifacts under `/Users/sean/Coding/steam-hardware-watch/runs/2026-05-17`.
- Material update: Steam Controller package `1558609` moved in SteamKit/PICS from changenumber `35745078` to `35893035`.
- The Controller package metadata change is specific: `ignorereservationifstockavailable=1` was removed from the package `extended` fields.
- Steam Machine and Steam Frame watched app/package changenumbers did not move.
- Valve public APIs still do not expose Steam Machine or Steam Frame package groups, public package details, price, exact release timing, or purchase/reservation readiness.
- Komodo recovered through the dedicated browser fallback; Machine and Frame remained unchanged there.
## Source Checks
### Komodo
- Dedicated browser fallback recovered Controller, Machine, and Frame product/section data.
- Product modified timestamps:
- Controller: `2026-05-15T15:50:21`
- Machine: `2026-04-24T14:32:54`
- Frame: `2026-04-24T14:33:36`
- Machine and Frame remain unchanged on Komodo and still only expose the old wishlist section baseline.
- Visual assets: `141` discovered, `136` retrieved, `5` blocked known Komodo URLs.
### SteamKit / PICS
- SteamKit/PICS completed successfully.
- Controller package movement:
- `1558609`: `35745078` -> `35893035`
- SHA hash: `02235CA28137E71E7AFA02A0F45743DBEBA925EF` -> `CE75692F2679EF8A91C3C9CBB58D09456350EC64`
- Field removed from `extended`: `ignorereservationifstockavailable=1`
- Machine packages stayed unchanged:
- `1629446`: `35842876`
- `1629447`: `35842851`
- `1629458`: `35842860`
- `1629460`: `35842863`
- Frame packages stayed unchanged:
- `1629484`: `35672606`
- `1629486`: `35672606`
- Interpretation: today's new PICS movement is Controller-only. It may reflect reservation/stock handling cleanup for the already-public Controller package, but it does not add a Machine or Frame launch-readiness signal.
### SteamDB
- Automated SteamDB access remained blocked.
- Reservation package rows remain `missing_or_blocked`, so SteamDB is still not a human-readable corroborating baseline for the recent Machine package movement or today's Controller package change.
### SteamTracking / GameTracking
- Recreated the missing local SteamTracking checkout at `/tmp/SteamTracking-master`.
- Current checkout: `d99b64c` (`2026-05-16T04:23:35Z`, `1 files | v7_promo.css`).
- Known Triton/Ibex pairing surfaces remain present.
- No new Machine or Frame price, reservation, package, or release-date signal was found.
### SteamVR Depots
- SteamVR news metadata was saved.
- SteamDB SteamVR depot metadata remained blocked.
- No fresh depot manifest/build comparison was collected.
### SteamOS Package Mirror
- Public mirror remained reachable.
- `fremont-hw-support 20260506.1-1` remains visible in `holo-3.8` and `holo-main`.
- No direct Steam Machine, Steam Frame, Deckard, Roy, ARM/Snapdragon, or new product-specific namespace surfaced in this pass.
### Valve Support / CDN
- Valve public endpoints were reachable.
- Controller remains public with package `1558609`, package group present, and `$99.00`.
- Frame app `4165890` remains `Coming soon`, with no public packages, no package groups, and no price.
- Machine app `4165910` remains `Coming soon`, with no public packages, no package groups, and no price.
- Machine packages `1629446`, `1629447`, `1629458`, `1629460` still return `packagedetails success:false`.
- Frame packages `1629484`, `1629486` still return `packagedetails success:false`.
- Public Valve `appdetails` and `packagedetails` JSON for Controller package `1558609` did not change versus `2026-05-15`, despite the private PICS package metadata change.
### Customs / Regulatory
- ImportInfo automated customs fetches were blocked.
- No new customs evidence was added.
## Effect On Key Questions
- Price: unchanged. Only Steam Controller has a confirmed price.
- Release date: unchanged. Only Steam Controller has a confirmed exact date.
- Same-time launch: unchanged. Full same-day launch remains ruled out.
- Product furthest along: Steam Controller is already public/purchasable. Among unreleased hardware, Steam Machine still has the strongest recent backend-prep signal because of the `2026-05-12` and `2026-05-14` package movement, but there was no additional Machine or Frame PICS movement today.
## Next Checks
- Continue focused SteamKit/PICS checks for watched package IDs.
- Watch whether Controller package `1558609` gets public stock/reservation behavior changes after the removal of `ignorereservationifstockavailable=1`.
- Watch Valve public `appdetails` / `packagedetails` for Machine package exposure, package groups, price, reservation text, or purchase eligibility.
- Complete a trusted-browser SteamDB package-history pass for Machine packages `1629446`, `1629447`, `1629458`, and `1629460`.
+88
View File
@@ -0,0 +1,88 @@
# Run Note: 2026-05-18
## Summary
- Full skill run completed with artifacts under `/Users/sean/Coding/steam-hardware-watch/runs/2026-05-18`.
- No watched SteamKit/PICS changenumbers moved versus the `2026-05-17` report.
- No Steam Machine or Steam Frame public-readiness movement was found.
- Valve public APIs still do not expose Steam Machine or Steam Frame package groups, public package details, price, exact release timing, or purchase/reservation readiness.
- Komodo recovered through the dedicated browser fallback; Controller, Machine, and Frame timestamps were unchanged.
- Later same-day recheck refreshed the same run artifacts at `2026-05-18T16:50:41Z` for SteamKit/PICS. Same-day diffs for SteamKit/PICS, Komodo product timestamps, and Valve reservation/package status were empty.
## Source Checks
### Komodo
- Dedicated browser fallback recovered Controller, Machine, and Frame product/section data.
- Product modified timestamps:
- Controller: `2026-05-15T15:50:21`
- Machine: `2026-04-24T14:32:54`
- Frame: `2026-04-24T14:33:36`
- Machine and Frame remain unchanged on Komodo and still only expose the old wishlist section baseline.
- Visual assets: `141` discovered, `136` retrieved, `5` blocked known Komodo URLs.
### SteamKit / PICS
- SteamKit/PICS completed successfully.
- No watched app or package changenumbers moved versus `2026-05-17`.
- Controller package `1558609` stayed at `35893035` after the `2026-05-17` private metadata change.
- Machine packages stayed unchanged:
- `1629446`: `35842876`
- `1629447`: `35842851`
- `1629458`: `35842860`
- `1629460`: `35842863`
- Frame packages stayed unchanged:
- `1629484`: `35672606`
- `1629486`: `35672606`
- Interpretation: today's run does not add a new Controller, Machine, or Frame PICS signal. The latest material Machine signal remains the `2026-05-14` follow-up bump across all four watched Machine package IDs.
### SteamDB
- Automated SteamDB access remained blocked.
- Reservation package rows remain `missing_or_blocked`, so SteamDB is still not a human-readable corroborating baseline for the recent Machine package movement or the `2026-05-17` Controller package change.
### SteamTracking / GameTracking
- Known Triton/Ibex pairing surfaces remain present.
- No new Machine or Frame price, reservation, package, or release-date signal was found.
### SteamVR Depots
- SteamVR news metadata was saved.
- SteamDB SteamVR depot metadata remained blocked.
- No fresh depot manifest/build comparison was collected.
### SteamOS Package Mirror
- Public mirror remained reachable.
- `fremont-hw-support 20260506.1-1` remains visible in `holo-3.8` and `holo-main`.
- No direct Steam Machine, Steam Frame, Deckard, Roy, ARM/Snapdragon, or new product-specific namespace surfaced in this pass.
### Valve Support / CDN
- Valve public endpoints were reachable.
- Controller remains public with package `1558609`, package group present, and `$99.00`.
- Frame app `4165890` remains `Coming soon`, with no public packages, no package groups, and no price.
- Machine app `4165910` remains `Coming soon`, with no public packages, no package groups, and no price.
- Machine packages `1629446`, `1629447`, `1629458`, `1629460` still return `packagedetails success:false`.
- Frame packages `1629484`, `1629486` still return `packagedetails success:false`.
- Public Valve `appdetails` and `packagedetails` JSON did not expose the `2026-05-17` Controller private PICS package change.
### Customs / Regulatory
- ImportInfo automated customs fetches were blocked.
- No new customs evidence was added.
## Effect On Key Questions
- Price: unchanged. Only Steam Controller has a confirmed price.
- Release date: unchanged. Only Steam Controller has a confirmed exact date.
- Same-time launch: unchanged. Full same-day launch remains ruled out.
- Product furthest along: Steam Controller is already public/purchasable. Among unreleased hardware, Steam Machine still has the strongest recent backend-prep signal because of the `2026-05-12` and `2026-05-14` package movement, but there was no additional Machine or Frame PICS movement today.
## Next Checks
- Continue focused SteamKit/PICS checks for watched package IDs.
- Watch whether Controller package `1558609` gets public stock/reservation behavior changes after the `2026-05-17` removal of `ignorereservationifstockavailable=1`.
- Watch Valve public `appdetails` / `packagedetails` for Machine package exposure, package groups, price, reservation text, or purchase eligibility.
- Complete a trusted-browser SteamDB package-history pass for Machine packages `1629446`, `1629447`, `1629458`, and `1629460`.
+88
View File
@@ -0,0 +1,88 @@
# Run Note: 2026-05-19
## Summary
- Full skill run completed with artifacts under `/Users/sean/Coding/steam-hardware-watch/runs/2026-05-19`.
- No watched SteamKit/PICS changenumbers moved versus the `2026-05-18` report.
- No Steam Machine or Steam Frame public-readiness movement was found.
- Valve public APIs still do not expose Steam Machine or Steam Frame package groups, public package details, price, exact release timing, or purchase/reservation readiness.
- Komodo was blocked by Komodo waiting-room HTML even through the dedicated browser fallback. Treat compare-report Komodo section removals as blocked-fetch artifacts, not real removals.
## Source Checks
### Komodo
- Raw `curl` and browser-backed JSON fetches did not recover Komodo JSON in this run.
- Direct browser-backed probe of `/wp-json/` returned Komodo waiting-room HTML.
- Latest known good product modified timestamps remain from the `2026-05-18` pass:
- Controller: `2026-05-15T15:50:21`
- Machine: `2026-04-24T14:32:54`
- Frame: `2026-04-24T14:33:36`
- Visual asset reporting fell back to previous discovered assets: `141` discovered, `136` retrieved, `5` blocked known Komodo URLs.
### SteamKit / PICS
- SteamKit/PICS completed successfully.
- No watched app or package changenumbers moved versus `2026-05-18`.
- Controller package `1558609` stayed at `35893035` after the `2026-05-17` private metadata change.
- Machine packages stayed unchanged:
- `1629446`: `35842876`
- `1629447`: `35842851`
- `1629458`: `35842860`
- `1629460`: `35842863`
- Frame packages stayed unchanged:
- `1629484`: `35672606`
- `1629486`: `35672606`
- Interpretation: today's run does not add a new Controller, Machine, or Frame PICS signal. The latest material Machine signal remains the `2026-05-14` follow-up bump across all four watched Machine package IDs.
### SteamDB
- Automated SteamDB access remained blocked.
- Reservation package rows remain `missing_or_blocked`, so SteamDB is still not a human-readable corroborating baseline for the recent Machine package movement or the `2026-05-17` Controller package change.
### SteamTracking / GameTracking
- Known Triton/Ibex pairing surfaces remain present.
- No new Machine or Frame price, reservation, package, or release-date signal was found.
### SteamVR Depots
- SteamVR news metadata was saved.
- SteamDB SteamVR depot metadata remained blocked.
- No fresh depot manifest/build comparison was collected.
### SteamOS Package Mirror
- Public mirror remained reachable.
- `fremont-hw-support 20260506.1-1` remains visible in `holo-3.8` and `holo-main`.
- No direct Steam Machine, Steam Frame, Deckard, Roy, ARM/Snapdragon, or new product-specific namespace surfaced in this pass.
### Valve Support / CDN
- Valve public endpoints were reachable.
- Controller remains public with package `1558609`, package group present, and `$99.00`.
- Frame app `4165890` remains `Coming soon`, with no public packages, no package groups, and no price.
- Machine app `4165910` remains `Coming soon`, with no public packages, no package groups, and no price.
- Machine packages `1629446`, `1629447`, `1629458`, `1629460` still return `packagedetails success:false`.
- Frame packages `1629484`, `1629486` still return `packagedetails success:false`.
- Public Valve `appdetails` and `packagedetails` JSON still do not expose the `2026-05-17` Controller private PICS package change.
### Customs / Regulatory
- ImportInfo automated customs fetches were blocked.
- No new customs evidence was added.
## Effect On Key Questions
- Price: unchanged. Only Steam Controller has a confirmed price.
- Release date: unchanged. Only Steam Controller has a confirmed exact date.
- Same-time launch: unchanged. Full same-day launch remains ruled out.
- Product furthest along: Steam Controller is already public/purchasable. Among unreleased hardware, Steam Machine still has the strongest recent backend-prep signal because of the `2026-05-12` and `2026-05-14` package movement, but there was no additional Machine or Frame PICS movement today.
## Next Checks
- Continue focused SteamKit/PICS checks for watched package IDs.
- Retry Komodo after the waiting room clears; do not interpret today's empty Komodo section reports as removals.
- Watch whether Controller package `1558609` gets public stock/reservation behavior changes after the `2026-05-17` removal of `ignorereservationifstockavailable=1`.
- Watch Valve public `appdetails` / `packagedetails` for Machine package exposure, package groups, price, reservation text, or purchase eligibility.
- Complete a trusted-browser SteamDB package-history pass for Machine packages `1629446`, `1629447`, `1629458`, and `1629460`.
+98
View File
@@ -0,0 +1,98 @@
# Run Note: 2026-05-22
## Summary
- Full skill run completed with artifacts under `/Users/sean/Coding/steam-hardware-watch/runs/2026-05-22`.
- No watched SteamKit/PICS changenumbers moved versus the `2026-05-19` report.
- No Steam Machine or Steam Frame public-readiness movement was found.
- Valve public APIs still do not expose Steam Machine or Steam Frame package groups, public package details, price, exact release timing, or purchase/reservation readiness.
- Customs coverage was corrected after the initial summary missed ImportGenius. ImportInfo remained blocked, but ImportGenius produced `10` relevant `GAME CONSOLE` shipment rows through `2026-05-18`.
- Komodo recovered after the `2026-05-19` waiting-room block. The compare report lists Komodo sections as "added" because the previous run was blocked; these are restored baseline rows, not newly published sections.
- The temporary SteamTracking checkout was corrupt/partial and produced an empty first report. It was replaced with a fresh checkout and the SteamTracking report was regenerated.
## Source Checks
### Komodo
- Dedicated browser fallback recovered Controller, Machine, and Frame product/section data.
- Product modified timestamps:
- Controller: `2026-05-22T15:28:27`
- Machine: `2026-04-24T14:32:54`
- Frame: `2026-04-24T14:33:36`
- Controller JSON diff versus `2026-05-18` is timestamp-only (`modified` / `modified_gmt`).
- Machine and Frame product JSON and section reports are unchanged versus the last good Komodo baseline.
- Visual assets: `141` discovered, `136` retrieved, `5` blocked known Komodo URLs.
### SteamKit / PICS
- SteamKit/PICS completed successfully.
- No watched app or package changenumbers moved versus `2026-05-19`.
- Controller package `1558609` stayed at `35893035` after the `2026-05-17` private metadata change.
- Machine packages stayed unchanged:
- `1629446`: `35842876`
- `1629447`: `35842851`
- `1629458`: `35842860`
- `1629460`: `35842863`
- Frame packages stayed unchanged:
- `1629484`: `35672606`
- `1629486`: `35672606`
- Interpretation: today's run does not add a new Controller, Machine, or Frame PICS signal. The latest material Machine signal remains the `2026-05-14` follow-up bump across all four watched Machine package IDs.
### SteamDB
- Automated SteamDB access remained blocked.
- Reservation package rows remain `missing_or_blocked`, so SteamDB is still not a human-readable corroborating baseline for the recent Machine package movement or the `2026-05-17` Controller package change.
### SteamTracking / GameTracking
- Replaced a corrupt/partial `/tmp/SteamTracking-master` checkout with a fresh clone.
- Current checkout: `28f5287` (`2026-05-22T04:56:58Z`).
- Known Triton/Ibex pairing surfaces remain present.
- No new Machine or Frame price, reservation, package, or release-date signal was found.
### SteamVR Depots
- SteamVR news metadata was saved.
- SteamDB SteamVR depot metadata remained blocked.
- No fresh depot manifest/build comparison was collected.
### SteamOS Package Mirror
- Public mirror remained reachable.
- `fremont-hw-support 20260506.1-1` remains visible in `holo-3.8` and `holo-main`.
- No direct Steam Machine, Steam Frame, Deckard, Roy, ARM/Snapdragon, or new product-specific namespace surfaced in this pass.
### Valve Support / CDN
- Valve public endpoints were reachable.
- Controller remains public with package `1558609`, package group present, and `$99.00`.
- Frame app `4165890` remains `Coming soon`, with no public packages, no package groups, and no price.
- Machine app `4165910` remains `Coming soon`, with no public packages, no package groups, and no price.
- Machine packages `1629446`, `1629447`, `1629458`, `1629460` still return `packagedetails success:false`.
- Frame packages `1629484`, `1629486` still return `packagedetails success:false`.
- Public Valve `appdetails` and `packagedetails` JSON still do not expose the `2026-05-17` Controller private PICS package change.
### Customs / Regulatory
- ImportInfo automated customs fetches were blocked.
- ImportGenius fetched successfully after the customs helper was updated to treat it as a first-class automated customs source.
- Parsed `10` relevant `GAME CONSOLE` rows for `INGRAM MICRO C/O VALVE CORPORATION` / `TECH-FRONT (CHONGQING) COMPUTER CO`.
- Newer rows since the previous April 23 baseline:
- `2026-05-18`, BOL `SNHBSHACHI265020`, `42 PKG`, `14353 Kgs`.
- `2026-05-18`, BOL `SNHBSHACHI264140`, `42 PKG`, `14533 Kgs`.
- `2026-05-08`, BOL `SNHBSHACHI264031`, `42 PKG`, `12615 Kgs`.
- Interpretation: this is a material logistics corroboration signal for continued US-bound game-console hardware flow to Valve's Ingram path, but it does not identify whether the goods are Steam Machine, Steam Frame, or another Valve hardware SKU.
## Effect On Key Questions
- Price: unchanged. Only Steam Controller has a confirmed price.
- Release date: unchanged. Only Steam Controller has a confirmed exact date.
- Same-time launch: unchanged. Full same-day launch remains ruled out.
- Product furthest along: Steam Controller is already public/purchasable. Among unreleased hardware, Steam Machine still has the strongest recent backend-prep signal because of the `2026-05-12` and `2026-05-14` package movement, now with continued May `GAME CONSOLE` logistics corroboration. There was no additional Machine or Frame PICS movement today.
## Next Checks
- Continue focused SteamKit/PICS checks for watched package IDs.
- Watch whether Controller package `1558609` gets public stock/reservation behavior changes after the `2026-05-17` removal of `ignorereservationifstockavailable=1`.
- Watch Valve public `appdetails` / `packagedetails` for Machine package exposure, package groups, price, reservation text, or purchase eligibility.
- Complete a trusted-browser SteamDB package-history pass for Machine packages `1629446`, `1629447`, `1629458`, and `1629460`.
+99
View File
@@ -89,6 +89,105 @@ class CheckKomodoTests(unittest.TestCase):
(run_dir / "reports" / "komodo-frame-sections.tsv").read_text(encoding="utf-8"),
)
def test_optional_machine_and_frame_fetches_use_playwright_fallback(self):
tmp = TemporaryDirectory()
self.addCleanup(tmp.cleanup)
tmp_path = Path(tmp.name)
run_dir = tmp_path / "run"
fake_bin = tmp_path / "bin"
fake_bin.mkdir()
write_executable(
fake_bin / "curl",
r"""
#!/bin/sh
for arg do
url="$arg"
done
case "$url" in
*wp-json/wp/v2/product/413763*)
printf '%s\n' '{"modified":"2026-05-14T12:00:00","title":{"rendered":"Steam Controller"}}'
;;
*wp-json/wp/v2/sections?search=Steam%20Controller*|*wp-json/wp/v2/media?search=Steam%20Controller*|*wp-json/wp/v2/media?parent=*)
printf '%s\n' '[]'
;;
*wp-json/wp/v2/product/413772*|*wp-json/wp/v2/product/413776*|*wp-json/wp/v2/sections?search=Steam%20Machine*|*wp-json/wp/v2/sections?search=Steam%20Frame*)
exit 22
;;
*wp-json/*)
printf '%s\n' '{"name":"Komodo"}'
;;
*)
exit 22
;;
esac
""",
)
write_executable(
fake_bin / "playwright-cli",
"#!/bin/sh\nexit 0",
)
write_executable(
fake_bin / "node",
r"""
#!/bin/sh
url="$2"
output="$3"
case "$url" in
*wp-json/wp/v2/product/413772*)
printf '%s\n' '{"modified":"2026-04-24T14:32:54","title":{"rendered":"Steam Machine"}}' > "$output"
;;
*wp-json/wp/v2/product/413776*)
printf '%s\n' '{"modified":"2026-04-24T14:33:36","title":{"rendered":"Steam Frame"}}' > "$output"
;;
*wp-json/wp/v2/sections?search=Steam%20Machine*)
printf '%s\n' '[{"id":413808,"date":"2025-11-12T14:04:51","modified":"2026-03-03T16:01:51","slug":"en-steam-machine-wishlist","title":{"rendered":"JA &#8211; Steam Machine Wishlist"}}]' > "$output"
;;
*wp-json/wp/v2/sections?search=Steam%20Frame*)
printf '%s\n' '[{"id":413804,"date":"2025-11-12T14:06:55","modified":"2025-11-12T14:09:51","slug":"413801","title":{"rendered":"JA &#8211; Steam Frame Wishlist"}}]' > "$output"
;;
*)
exit 22
;;
esac
""",
)
env = os.environ.copy()
env.update(
{
"PATH": f"{fake_bin}:{env['PATH']}",
"KOMODO_ENV_FILE": str(tmp_path / "missing-komodo-env.sh"),
"KOMODO_PLAYWRIGHT_FALLBACK": "1",
}
)
result = subprocess.run(
[str(ROOT / "scripts" / "check_komodo.sh"), str(run_dir)],
cwd=ROOT,
env=env,
text=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
check=False,
)
self.assertEqual("", result.stderr)
self.assertEqual(0, result.returncode)
product_modified = (run_dir / "reports" / "komodo-product-modified.tsv").read_text(
encoding="utf-8"
)
self.assertIn("machine\t2026-04-24T14:32:54", product_modified)
self.assertIn("frame\t2026-04-24T14:33:36", product_modified)
self.assertIn(
"en-steam-machine-wishlist",
(run_dir / "reports" / "komodo-machine-sections.tsv").read_text(encoding="utf-8"),
)
self.assertIn(
"Steam Frame Wishlist",
(run_dir / "reports" / "komodo-frame-sections.tsv").read_text(encoding="utf-8"),
)
if __name__ == "__main__":
unittest.main()
+154
View File
@@ -51,6 +51,25 @@ IMPORTINFO_HTML = textwrap.dedent(
)
IMPORTGENIUS_HTML = textwrap.dedent(
"""
<html>
<body>
<h1>Ingram Micro C/o Valve Corporation</h1>
<p>Updated: 2026-05-18</p>
<section>
<h2>Importer Shipments</h2>
<p># Bill of Lading Product Importer Supplier Arrival Date Country of Origin Gross Weight KGS Quantity</p>
<p>1 SNHBSHACHI265020 GAME CONSOLE INGRAM MICRO C/O VALVE CORPORATION TECH-FRONT (CHONGQING) COMPUTER CO 2026-05-18 China 14353 Kgs 42 PKG</p>
<p>2 SNHBSHACHI264140 GAME CONSOLE INGRAM MICRO C/O VALVE CORPORATION TECH-FRONT (CHONGQING) COMPUTER CO 2026-05-18 China 14533 Kgs 42 PKG</p>
<p>3 SNHBSHACHI264031 GAME CONSOLE INGRAM MICRO C/O VALVE CORPORATION TECH-FRONT (CHONGQING) COMPUTER CO 2026-05-08 China 12615 Kgs 42 PKG</p>
</section>
</body>
</html>
"""
)
def run_parser(args, reports):
return subprocess.run(
[
@@ -242,6 +261,34 @@ class CustomsShipmentParserTests(unittest.TestCase):
self.assertEqual(["SNHBSHALAX264014"], [row["house_bol"] for row in rows])
self.assertEqual("https://example.test/ceva", rows[0]["source_url"])
def test_extracts_relevant_importgenius_rows(self):
with TemporaryDirectory() as tmp:
tmp_path = Path(tmp)
html = tmp_path / "importgenius-ingram.html"
html.write_text(IMPORTGENIUS_HTML, encoding="utf-8")
reports = tmp_path / "reports"
result = run_parser(["--input", f"importgenius-ingram-valve={html}"], reports)
self.assertEqual("", result.stderr)
self.assertEqual(0, result.returncode)
rows = read_rows(reports)
self.assertEqual(
["SNHBSHACHI265020", "SNHBSHACHI264140", "SNHBSHACHI264031"],
[row["house_bol"] for row in rows],
)
self.assertEqual("GAME CONSOLE", rows[0]["commodity"])
self.assertEqual("INGRAM MICRO C/O VALVE CORPORATION", rows[0]["consignee"])
self.assertEqual("TECH-FRONT (CHONGQING) COMPUTER CO", rows[0]["shipper"])
self.assertEqual("2026-05-18", rows[0]["arrival_date"])
self.assertEqual("14353 Kgs", rows[0]["weight"])
key_lines = (reports / "customs-shipments-key-lines.txt").read_text(
encoding="utf-8"
)
self.assertIn("SNHBSHACHI265020", key_lines)
self.assertIn("2026-05-18", key_lines)
class CheckCustomsShipmentsShellTests(unittest.TestCase):
def test_fetches_pages_and_runs_parser(self):
@@ -357,6 +404,60 @@ class CheckCustomsShipmentsShellTests(unittest.TestCase):
).read_text(encoding="utf-8")
self.assertEqual("", key_lines)
def test_fetches_importgenius_public_importer_page(self):
with TemporaryDirectory() as tmp:
tmp_path = Path(tmp)
run_dir = tmp_path / "run"
fake_bin = tmp_path / "bin"
fake_bin.mkdir()
(tmp_path / "importgenius-fixture.html").write_text(
IMPORTGENIUS_HTML, encoding="utf-8"
)
write_executable(
fake_bin / "curl",
f"""
#!/bin/sh
for arg do
url="$arg"
done
case "$url" in
*importgenius.com/importers/ingram-micro-c-o-valve-corporation)
cat "{tmp_path / "importgenius-fixture.html"}"
;;
*)
exit 22
;;
esac
""",
)
env = os.environ.copy()
env["PATH"] = f"{fake_bin}{os.pathsep}{env['PATH']}"
result = subprocess.run(
[str(ROOT / "scripts" / "check_customs_shipments.sh"), str(run_dir)],
cwd=ROOT,
env=env,
text=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
check=False,
)
self.assertEqual("", result.stderr)
self.assertEqual(0, result.returncode)
self.assertTrue(
(
run_dir
/ "api"
/ "customs"
/ "importgenius-ingram-valve.html"
).exists()
)
key_lines = (
run_dir / "reports" / "customs-shipments-key-lines.txt"
).read_text(encoding="utf-8")
self.assertIn("SNHBSHACHI265020", key_lines)
class CustomsSummaryIntegrationTests(unittest.TestCase):
def test_run_summary_and_status_draft_include_customs_lines(self):
@@ -406,6 +507,59 @@ class CustomsSummaryIntegrationTests(unittest.TestCase):
self.assertIn("Customs / Shipments", status_draft)
self.assertIn("GAME CONSOLE", status_draft)
def test_customs_rows_with_source_errors_are_reported_as_partial(self):
with TemporaryDirectory() as tmp:
run_dir = Path(tmp) / "2026-05-22"
reports = run_dir / "reports"
reports.mkdir(parents=True)
(reports / "customs-shipments-key-lines.txt").write_text(
"2026-05-18\tINGRAM MICRO C/O VALVE CORPORATION\tTECH-FRONT (CHONGQING) COMPUTER CO\tGAME CONSOLE\t42 PKG\t14353 Kgs\tSNHBSHACHI265020\n",
encoding="utf-8",
)
(reports / "customs-shipments-errors.txt").write_text(
"failed to fetch https://www.importinfo.com/search?s=CEVA%20C%2FO%20VALVE%20CORPORATION\n",
encoding="utf-8",
)
(reports / "customs-shipments.md").write_text(
"# Customs Shipments\n\nRelevant shipment count: 1\n",
encoding="utf-8",
)
summary = subprocess.run(
[
"python3",
str(ROOT / "scripts" / "write_run_summary.py"),
"--run-dir",
str(run_dir),
],
cwd=ROOT,
text=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
check=False,
)
draft = subprocess.run(
[
"python3",
str(ROOT / "scripts" / "draft_status_update.py"),
"--run-dir",
str(run_dir),
],
cwd=ROOT,
text=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
check=False,
)
self.assertEqual(0, summary.returncode)
self.assertEqual(0, draft.returncode)
run_summary = (reports / "run-summary.md").read_text(encoding="utf-8")
status_draft = (reports / "status-draft.md").read_text(encoding="utf-8")
self.assertIn("Customs shipments status: `partial`", run_summary)
self.assertIn("Customs shipment rows were captured", status_draft)
self.assertIn("SNHBSHACHI265020", status_draft)
def test_status_draft_reports_missing_customs_outputs_as_unavailable(self):
with TemporaryDirectory() as tmp:
run_dir = Path(tmp) / "2026-05-05"