# Changelog of NYC Building Permit Feed, unofficial (`amplelabs/nyc-building-permit-feed`) Actor

- **URL**: https://apify.com/amplelabs/nyc-building-permit-feed/changelog.md
- **Full Actor documentation**: https://apify.com/amplelabs/nyc-building-permit-feed.md

## Changelog

This Actor uses semantic versioning. Apify's `actor.json` `version` is `0.2` because removing the retired city from the input schema is not backward compatible. The package version is the full semver.

### Unreleased

- The dataset schema accepts either a permit item or a `no-new-permits` status row. A status row is no longer rejected for missing permit fields.
- Listing copy: the README opens with the Compliance disclaimer and the Store intro. The outreach rules and the sole-trader line sit after Privacy defaults. Section 2 no longer repeats the non-affiliation line. The datasets input no longer names `chicago` as an example. Support points to the Issues tab and support@haveample.com, and a takedown includes the details under Removal requests. The sentence that named version 0.2.2 is removed.
- The Console form prefills `datasets` to `nyc_dob_now` and `maxResults` to 10. The defaults stay both datasets and 5,000. `resetState` is not prefilled, so a saved schedule keeps its watermark. A repeat run that pushes no permits still writes the status row.
- A run that delivers no permits pushes one `no-new-permits` status row, including when it stops for `failed-graceful`, `access-blocked`, `spending-limit`, or `timeout`. An unhandled error does not. `stopReason` gives the reason. The row is not a `permit-record` charge.
- Launch price is $0.01 per `apify-actor-start` event (Apify charges one event per GB of run memory, minimum one; this Actor's 256 MB default and 512 MB maximum mean one event per run), and $0.003 each for `permit-record`, `day-scanned`, and `bulk-scan`.

### 0.2.2

- The only outbound calls are NYC Open Data API `https://data.cityofnewyork.us/resource/<id>.json` requests. `source_rows_updated_at` is `max(:updated_at)` from that endpoint. The egress lookup is gone.
- HTTP 403 is never retried. Two consecutive 403 responses stop the run. The status is not a success message.
- User-facing text says NYC Open Data API, source record id, and source row creation time.
- `source_attribution` begins `Source: NYC Department of Buildings (DOB) via NYC Open Data,` followed by the dataset name, id, URL, retrieval time, and as-of times.
- Free-text fields are dropped unless `includeFreeText` is on. Customers run the default build, `latest`. `beta` is only for private build checks.

### 0.2.1

- Store title is `NYC Building Permit Feed, unofficial`. The README states the non-affiliation line, the outreach rules, the 15 U.S.C. 7704(a)(4) 10-business-day opt-out, and that addresses stay on because they are part of the public permit record.
- Exclusion entries use `nyc_dob_now` or `nyc_bis`. A BIN must be 7 digits and a BBL 10 digits after spaces and hyphens are removed. Permit numbers and record keys are trimmed and compared in upper case. A malformed entry names its index and field and fails the run.
- The README quotes NYC Administrative Code § 23-502(d) with the statute's "may require" wording.
- An unknown `datasets` value is an Apify input-schema HTTP 400 only for an API start. The Console blocks it in the form. Anywhere else the run fails with `unknown dataset`.

### 0.2.0

#### Breaking

- Chicago building permits are removed. The Actor reads NYC DOB NOW (`rbx6-tga4`) and NYC BIS (`ipu4-2q9a`) only. `chicago`, `chicagoWards`, and `chicagoCommunityAreas` are no longer inputs. A saved task that still sends `chicago` fails input validation. Apify `actor.json` version is `0.2`.
- Output no longer includes `ward`, `community_area`, or `permit_condition`.

#### Added

- `exclusions.json` drops matching rows before push and before any charge. A permit number or record key drops that row in that dataset. A BIN or BBL drops every row at that building or lot in that dataset. Excluded keys are marked handled and are not charged or redelivered. The log records a count only, as `excluded dataset=nyc_dob_now count=3`. A malformed file fails the run at startup. See EXCLUSIONS.md.
- Each item names the NYC Open Data dataset, its id, and its dataset URL, records when the run retrieved it, records `rowsUpdatedAt` from the dataset view when that metadata is available, records the row `:updated_at` when the row has it, and describes the modifications Ample Labs makes. NYC Administrative Code § 23-502(d).

### 0.1.4

- A NYC permit whose key is already in the delivered set is not sent or charged again when a later batch republishes it. A changed expiration date does not make a new record. A work-type republish that still has the earlier row stays a free update.

### 0.1.3

- A Chicago first run delivers the lookback window (today minus 2 days through the last published issue date, in Chicago local time, or an explicit `dateFrom`) and charges those permits. Only ids issued before that start date are saved as the baseline.

### 0.1.2

- A default first NYC run (no `dateFrom`, no saved cursor) scans issue dates from today minus 2 days through the last published issue date, in the city's local calendar. It does not start at the earliest issue date in the newest batch. Late permits in that batch issued before the window are not delivered on the first run.
- That window is pinned, including the `max(:created_at)` taken at the start. The watermark is set to that snapshot only when the window finishes. A stop for the timeout, the 5,000-permit cap (`maxResults`), or the budget resumes the same dates.
- Hitting `maxResults` says to run again. The cap is the per-run input, default 5,000.

### 0.1.1

- Record every finished backfill day, including the free day and days with no rows. A same-input rerun after a timeout continues after the last finished day and does not charge those permits again.
- A later `dateTo` window skips issue dates this stateKey already finished, and skips keys already delivered. Changing filters or `includeFreeText` on that key does not replay those days; use a new `stateKey`.
- On a Chicago first run or `resetState`, ids in the 30-day window issued before the start date are saved as a seen baseline and are not delivered or charged. Later runs deliver only new or late ids.
- A default first NYC run starts at the earliest eligible issue date in the newest batch, or two days back, whichever is earlier, and does not move the watermark past a batch it did not cover.
- `day-scanned` is not charged for a day that returned no rows. The backfill stops at the last issue date the source has published.
- `maxBackfillDays` counts back from `dateTo`. A clipped range logs a warning and sets the status to the scanned-of-requested sentence.
- `stateKey` selects the named store `multi-city-permit-feed-state-<stateKey>`.
- Log the egress IP once per run.

### 0.1.0

First release of the Multi-City Permit Feed.

Each run reads NYC DOB NOW (`rbx6-tga4`), NYC BIS (`ipu4-2q9a`), and Chicago building permits (`ydr8-5enu`) from each city's open data API, at most one request per second, and writes them to the dataset of the account that started the run. Free text and business names are off unless the run asks for them. NYC follows a `:created_at` watermark and commits it after each batch. Chicago re-reads a 30-day issue-date window. Prices in `pricing.json` are proposals and are not applied on push.
