All notable changes to this actor will be documented here.
Format: YYYY-MM-DD | version | description | author
2026-07-23 | 0.1.0 | Initial build — CABA procurement feed actor (query + sync modes, BAC CSV stream-parse, KVS state management for sync dedup, PPE charging for tender-matched/tender-new events) | builder-agent
2026-07-24 | 0.1.1 | Native alert delivery — optional slackWebhookUrl/discordWebhookUrl inputs (isSecret) POST a Spanish-language run summary (count, top-5 tenders with links, total amount when present) after any query/sync run with matched/new tenders; notifyOnEmpty input to also notify on zero results (default off). Webhook failures are caught and logged as warnings only — never fail the run or affect charging. New src/notify.ts pure message builders + I/O sender, 29 new unit tests (59 total). README "Slack / Discord alerts" section with setup walkthrough. | Sonnet (builder agent)
2026-07-30 | 0.1.9 | Preventive QA hardening (actor was not yet flagged, but measured at 178s of the 300s Apify QA budget). (1) downloadCsv() had NO timeout — https.get() with only an error listener does not fire on a stalled-but-open socket, so a hung government CDN would hang until the platform killed the run. Replaced with fetch() + AbortSignal.timeout() in a new src/download.ts, following the pattern already used by domain-trust-monitor; total time is budgeted across retries, not per attempt. (2) Zero-matches-after-filter was exiting exitCode: 1, reporting a CORRECT EMPTY RESULT to Apify QA and to customers as a FAILED run — a direct violation of AGENTS.md § No silent incompleteness rule (c), in the opposite direction from the usual bug. Now exits 0 with both counts in the status message; a download/parse failure or a source returning zero rows at all STILL fails loudly with exitCode 1. New src/run-outcome.ts separates the two cases. Verified on-platform: run KzL9vcDRvZpuIa6gK with an impossible keyword now reports SUCCEEDED/exit 0, "Scanned 24911 tenders from the source; 0 matched your filters. This is a correct empty result, not a failure"; prefill runs green and total runtime measured at 66s (down from 177.9s). 68/68 tests. | Claude Sonnet (builder agent), verified by Opus 5
2026-10-09 | 0.1.10 | Fix "Under maintenance": the source file outgrew the actor. bac_anual.csv is year-to-date and grew from ~53 MB (July) to 133 MB / 55,385 tenders (October). Two independent failures, either one fatal: (1) a single connection from the platform measured ~340 KB/s, so the download went from ~155s to ~390s against a 200s ceiling; (2) csv-parse/sync materialised every ~110-column raw row — measured 1.28 GB RSS against a 1024 MB default, i.e. OOM. Apify QA recorded 18 FAILED + 2 TIMED-OUT of 27 public runs in 30 days. Fix: new downloadRanged() fetches the file over 8 parallel HTTP Range connections under ONE total timeout (150s), verifies every part (206 + exact length, If-Range pinned to the ETag) and falls back to a plain GET when ranges are unavailable; new parseBacCsvChunks() stream-parses and keeps only the 15 columns we map. Measured locally against the live CDN: download 55s → 12.5s, parse 4.6s, peak RSS ~350 MB, output byte-for-byte identical to the old parser on all 55,385 rows. Also replaced an O(n²) includes() in sync mode with a Set. 76/76 tests. | Claude Opus 5.5