# Changelog of RVO Subsidy Tracker – Dutch Grant Schemes (`lwsdjfls/rvo-subsidy-tracker`) Actor

- **URL**: https://apify.com/lwsdjfls/rvo-subsidy-tracker/changelog.md
- **Full Actor documentation**: https://apify.com/lwsdjfls/rvo-subsidy-tracker.md

## Changelog

### 0.1

- Every RVO regeling from the official RVO open data API, with status, budget, opening and closing dates, target groups, sectors and apply link read from the regeling pages.
- Change feed: each regeling once, then only new regelingen, status, budget, opening-date and closing-date changes, plus a one-time alert 30 days before a deadline.
- Full list mode for a one-off overview, soonest deadline first.
- Filters for sector, target group (mkb, zzp, grootbedrijf), minimum budget and open-only.
- Removals are free; runs that cannot read the RVO data fail without charging.
- A regeling whose rvo.nl page answers 404 or 410 while RVO still lists it is not reported as removed until the page has been missing for 7 days, counted from the first run of any feed on the account that found it missing (kept in the key-value store `rvo-subsidy-tracker-page-checks`; a page that loads again starts over, and so does a page that no run found missing for two weeks, unless the feed itself ran in the meantime). Meanwhile a change feed keeps the regeling unchanged and a full list leaves it out and reports no removals, each with a warning, so a regeling whose page is back within those days is not reported as removed and then as new (and charged again). A regeling is reported as removed when RVO takes it off its open data list, when its page has been missing for 7 days, or when its page is no longer a regeling of its own. When many listed pages answer 404 or 410, the run fails without charging and records none of them as missing.
- A full list fails without charging when a page of the RVO open data list keeps failing or the list changes while it is read, instead of leaving regelingen out unnoticed. Any run fails without charging when rvo.nl refuses or does not answer most regeling pages.
- In a change feed, `maxRegelingenPerRun` caps only new regelingen, soonest deadline first, and never holds back changes or removals: changes to regelingen already in the feed come before new regelingen, also when the spending limit stops a run. The run log says how many new regelingen were held back; they follow in later runs, at most `maxRegelingenPerRun` per run.
- A run without a task or feed name keeps one feed per mode and filters, so direct runs with different filters can overlap. Runs that share a feed (the same feed name, the same task, or direct runs with the same mode and filters) must not overlap. Repeated sectors or target groups in the input count once.
- The RVO open data list is bounded: list pages of at most 512 KB, at most 5,000 entries, and size limits per entry (at most 300 sectors, subjects, subsidies and targets of 6,000 characters together); an entry beyond them fails the run as a changed API format.
- "Charges nothing" is replaced everywhere by what a failed or quiet run really costs: no scheme is charged, and Apify's start event of $0.00005 always is. The GDPR answer no longer claims that no personal data is collected; RVO's own summary text is copied as published, so a person RVO names on a scheme page can appear in it.
- The two charged events are `scheme-delivered` and `scheme-change`, in English like the rest of the Actor. The input schema says "scheme" too, where it said "regeling"; the dataset views and the `maxRegelingenPerRun` field keep their names, because renaming those would break anyone who already reads them.
- README corrected to match the code and the recorded runs: the introduction no longer says that RVO publishes "hundreds" of schemes or that a budget running out is reported (a change in the published total is), pricing no longer compares 100 schemes with an hour of advisory time, the FAQ no longer names a TechBridge call, no longer says that most schemes are applied for through eLoket or Mijn RVO or that RVO updates during office hours, and gives the measured run times instead of "one to three minutes", and the unrecorded promise to respond within a day is removed. Added: the start event in the pricing example, what a run with the default input costs at most, that the maximum cost per run is set in the run options in Apify Console, that coverage is limited to RVO's open data list and that sub-pages are filtered out by words in their title, that `budgetEur` is the total and a change to only the budget remark sends no change, and the date the README was last verified against RVO.
- `maxRegelingenPerRun` defaults to 25 instead of 1,000, so a run with the default input charges for at most 25 delivered schemes, $31.25, where it could charge $1,250. In a change feed the other new schemes follow in later runs and are charged when they arrive; changes to schemes already in the feed are still never held back. A full list with the default input shows the 25 with the soonest deadline. Set the field higher to get more in one run.
- Runs that share a feed take turns instead of failing. A run that starts while another run of the same feed (the same feed name, the same task, or direct runs with the same mode and filters) is still working waits for it, at most 10 minutes or half of the time it has left before its own timeout, and then continues on that run's results; only a run that is still waiting after that fails, charging for no scheme.
- When the first page of the RVO open data list keeps failing on a temporary error (no answer, or a server error), the run waits for it once, for at most 10 minutes, before it counts that page as failed. A full list, which fails without that page, reads it on its own before the others and waits whenever it fails. A change feed reads the list as before and waits only when the API does not answer at all (more than three list pages keep failing, or no list page gives a scheme); when only the first page, or up to three pages, keep failing, it carries on without them at once, as before, and checks the schemes already in the feed that are listed there through their own pages. A wait for the first page alone took the time a change feed needs for its other pages: it also checks new schemes held back by `maxRegelingenPerRun` and pages that are closed or no scheme of their own, so a run with a timeout of a few minutes left pages unchecked that fit in its timeout. The wait keeps free half of the time the run has left when it starts, plus the time the run needs for the schemes already in a change feed (125 ms for a page at the rate limit of 8 requests a second, and a tenth of a second to deliver a record, for each). The list's own retries pause for at most 37.5 seconds in all, so an outage of the API at the start of a run failed the first five list pages at once, and with them the run.
- When most regeling pages cannot be loaded because of a temporary error (not a refusal such as HTTP 403), the run checks rvo.nl once more before it fails: it waits for one of those pages, for at most 10 minutes and keeping free the time to load the others again and deliver what it found, and loads the others again only if that page answered. A run waits like this at most once, for the list and the pages together. When rvo.nl stays down, the run still fails without charging.
- A run whose regeling pages do not fit in its timeout checks as many as it can and delivers what it found, where it used to time out with nothing delivered; a run whose pages fit checks every page and delivers exactly what it did without a timeout. It keeps starting pages while the rest of them, at the pace of the run so far, and a tenth of a second for every record they and the pages already checked will deliver still fit before the time it keeps free at the end to save its state. Once they no longer fit, it starts a page only while 45 seconds (one attempt at the page) and a tenth of a second for every record found so far are left. The log and the status message say how many pages were not checked. The next run of a change feed starts at the first of them and goes on in list order, wrapping around to the top (kept per feed in the key-value store `rvo-subsidy-tracker-page-checks`), so runs with the same timeout check every page in turn; only a run that checks every page reports removals. When that place cannot be recorded, the log says so instead of promising where the next run starts. A full list leaves their regelingen out.
- The default run timeout is one hour. The largest list this Actor reads has 5,000 entries: at most 100 list pages and 5,000 regeling pages take 638 seconds at 8 requests a second, and at most 10,000 records (5,000 new or changed, 5,000 removed) take 1,000 seconds to deliver at a tenth of a second each; 1,638 seconds plus 10% is about 30 minutes, so one hour. A caller can set another timeout in the run options.
- Feed name (`stateKey`) is a secret input: stored encrypted, like the webhook URL, because it often names a customer. Apify checks no pattern on a secret field, so any text is now accepted instead of failing the run: a key of letters, digits, dashes and underscores keeps the state it had, other text gets a state of its own, spaces around it are ignored and a blank one counts as none.
- Store discounts: Apify's paid plans pay less for every event except the Actor start, 5% on the Bronze tier, 10% on Silver and 15% on Gold and higher. The prices in the README are the list prices, which the Free plan pays.
