{"id":"linked-art/metahistorybook-prod-harvest-evidence","relativePath":"linked-art/metahistorybook-prod-harvest-evidence.md","title":"MetaHistoryBook Production Consumer Evidence","markdown":"# MetaHistoryBook Production Consumer Evidence\n\nLast updated: 2026-07-07\n\n## 2026-07-05 Production Harvest\n\nMetaHistoryBook ran the first passing production-ID harvest against MetaMuseum as `metahistorybook-harvester-prod` after the canonical record URL and `equivalent[]` projection fix deployed.\n\nPartner-reported result: **PASS, 4/4 validation points**.\n\n| Validation point | Result | Evidence |\n|---|---|---|\n| Multi-page walk-back ordering | PASS | `?provider=met` reported `53` items; `last -> page/2 -> page/1 -> page/0` traversal worked with page sizes `3`, `25`, and `25`; `endTime` was strictly ascending across all `53` activities. |\n| Real non-epoch timestamps | PASS | `53/53` timestamps were valid UTC values with zero epoch fallbacks. `record-backfill` timestamps are documented as import/republication times. |\n| `equivalent[]` reconciliation hooks | PASS | Five sampled records across pages dereferenced from MetaMuseum activity `object.id` values; each record returned `record.id === _links.self.href`, preserved the upstream Met URL as `object.sourceId`, and exposed Met collection API URL, Met public URL, and Wikidata entity hooks when upstream Wikidata exists. |\n| Dedupe behavior | PASS | Default view returned `53/53` unique `object.id` values; `source=record-backfill` diagnostic view also reported `53`. |\n\nThe partner confirmed `47/53` Met records expose a Wikidata QID; the remaining six lack upstream object Wikidata links and are source-dependent rather than a projection failure. The concrete overlap proof is `Q432253` (`Garden at Sainte-Adresse`): MetaHistoryBook resolved the same QID through its own `/api/linked-art/{qid}` corpus, establishing the first Met-to-MetaHistoryBook join through the shared Wikidata anchor.\n\n## 2026-07-05 Daily Artwork-Of-The-Day Consumer\n\nDaily (`daily.metahistorybook.com`) confirmed a separate production application read as `daily-metahistorybook-prod`, distinct from `metahistorybook-harvester-prod`. The consumer ID is sent in Daily's production `User-Agent`.\n\nPartner-reported result: **PASS, distinct external product consumer**.\n\n| Validation point | Result | Evidence |\n|---|---|---|\n| Collection read | PASS | `GET /api/activity/collection?provider=met` returned HTTP `200`, `application/activity+json`, IIIF Change Discovery 1.0 `OrderedCollection`, `totalItems: 53`, and `first -> page/0 ... last -> page/2`. |\n| Page walk-back | PASS | Daily walked `last -> prev -> first` across all three pages: `25 + 25 + 3 = 53` activities, all `Create`, reconciling with `totalItems`. |\n| Record dereference | PASS | Each activity `object.id` resolved to a MetaMuseum Met Linked Art `HumanMadeObject`; the partner specifically confirmed object `437133`, Monet's `Garden at Sainte-Adresse`. |\n| Product integration | PASS | Daily ingests the feed into a supplementary artwork-of-the-day candidate pool and selection queue alongside its Wikidata-based picks. First production run created `53` candidates, including `15` paintings; cursor persisted at `2026-05-31T10:40:54.290Z`; repeat refresh processed zero new changes. |\n\nDaily also reports cursor-based reconciliation: it persists the newest activity timestamp and walks back only until that cursor on refresh. Delete activities remove records from the pool, and updates reconcile in the same refresh path. The current MetaMuseum Met backfill evidence still observes only `Create` activities, so strict MetaMuseum activity-type coverage remains missing live `Update` and `Delete` reads until those activity types are actually present and read.\n\n## 2026-07-05 Callback And Typed Cursor-Feed Reply\n\nMetaHistoryBook replied to the refreshed partner pack with the stable consumer\nID `metahistorybook-harvester-prod`, callback URL\n`https://www.metahistorybook.com/api/metamuseum/callback`, event types\n`Create`, `Update`, and `Delete`, and signing label\n`metahistorybook-harvester-prod-v1`.\n\nPartner-reported typed read timestamp: `2026-07-05T16:37Z`.\n\n| Read | Result |\n|---|---|\n| `/api/activity?limit=100` | `totalItems: 108`, `100` items on page 1, `next` to offset `100` |\n| `type=Create` | `108` Create rows, `100` on page 1 |\n| `type=Update` | `0`, explicitly reported as zero |\n| `type=Delete` | `0`, explicitly reported as zero |\n| Object-scoped `544320` | `2` Create rows |\n\nThey confirmed the callback is public HTTPS, fail-closed for signed deliveries,\nvalidates HMAC-SHA256 over `<timestamp>.<raw JSON payload>`, and returns `204 No\nContent` for verified delivery POSTs. Strict callback proof is still pending\nbecause the authentic proof is MetaMuseum's first signed delivery after the\nHMAC secret is exchanged out of band. MetaHistoryBook later confirmed the `404`\nGET result was deploy-pending. A repeat MetaMuseum GET liveness check returned\n`200`, and MetaMuseum sent one signed production `Create` Activity payload to the\ncallback. The delivery returned `204` at `2026-07-05T17:13:13.312Z` and is\nrecorded as accepted durable callback evidence for\n`metahistorybook-harvester-prod`. Evidence:\n`artifacts/activity-syndication/metahistorybook-harvester-prod-callback-2026-07-05T17-13-13-312Z.json`.\nThe HMAC secret and signature value are intentionally omitted from the proof\nartifact, chat, and email.\n\nThey also reported that the cursor feed lagged the Change Discovery projection:\ndefault `/api/activity` exposed semantic diagnostic rows with placeholder object\ndates and upstream object IDs. The follow-up fix applies the same\ndereferenceable `object.id`, `object.sourceId`, valid UTC `endTime`, and default\nper-object dedupe projection to `/api/activity` while keeping cursor-feed\n`linkedArt` embeds.\n\n## 2026-07-05 Post-Callback Partner Alignment\n\nMetaHistoryBook acknowledged the `2026-07-05T17:13:13.312Z` signed callback\nproof and confirmed the callback item is closed for\n`metahistorybook-harvester-prod`. They rechecked the public typed feed and\nreported `type=Update -> 0` and `type=Delete -> 0`, explicitly agreeing that no\nfake activity rows should be generated on either side.\n\nMetaMuseum independently rechecked the public typed endpoints at\n`2026-07-05T17:21:34Z`:\n\n| Read | Result |\n|---|---|\n| `/api/activity?limit=100&type=Update` | `totalItems: 0`, `0` items |\n| `/api/activity?limit=100&type=Delete` | `totalItems: 0`, `0` items |\n\nMetaHistoryBook's reader is ready to re-read `type=Update` and `type=Delete` as\n`metahistorybook-harvester-prod` after MetaMuseum deploys real reviewed update\nrows and real upstream `404`/`410` tombstone delete rows.\n\n## 2026-07-05 Deploy-Note Standby Confirmation\n\nMetaHistoryBook confirmed there is no remaining partner-side setup pending. The\ncallback endpoint and `metahistorybook-harvester-prod-v1` signing secret will\nstay active while MetaMuseum produces the real source rows.\n\nWhen MetaMuseum sends the deploy-note ping, MetaHistoryBook will re-read\n`type=Update` and `type=Delete` as `metahistorybook-harvester-prod` and return:\n\n- read timestamp;\n- per-type `totalItems` and item counts;\n- confirmation that the rows are real non-empty `Update`/`Delete` rows;\n- projection notes for `object.id`, `object.sourceId`, `equivalent[]`, and UTC\n  `endTime`.\n\nNo partner action is pending until MetaMuseum sends the next deploy-note. The\npartner now prefers two separate deploy-note pings: first when the reviewed\nmetadata `Update` row is live, and later when a real upstream `404`/`410`\ntombstone `Delete` row exists. The strict blocker is now MetaMuseum source data,\nnot MetaHistoryBook callback readiness.\n\n## 2026-07-05 Reviewed Update Evidence And Tombstone Scan\n\nMetaMuseum generated the first local real `Update` source row after comparing\nthe stored Met record for object `437133` with the live Met Collection API.\nThe live upstream response returned `200` and changed\n`_source.raw.measurements` order from `Framed, Overall` to `Overall, Framed`.\nMetaMuseum wrote the refreshed Linked Art record through `/api/records` for the\nexisting record id, so the audit ledger appended a real `record.update` row at\n`2026-07-05T19:21:57.761Z`.\n\nEvidence:\n`artifacts/activity-syndication/met-437133-reviewed-update-2026-07-05T19-21-57-765Z.json`.\n\nLocal typed feed check after the update:\n\n| Read | Result |\n|---|---|\n| `/api/activity?type=Update&limit=10` | `totalItems: 1`, `1` item; first row is `record.update via POST /api/records` for Met object `437133` |\n| `/api/activity?type=Delete&limit=10` | `totalItems: 0`, `0` items |\n\nMetaMuseum also probed the `56` stored canonical upstream record ids eligible\nfor tombstone evidence. All returned `200`. No `Delete` row was generated,\nbecause there is no real upstream `404`/`410` tombstone candidate in the current\nstored canonical record set.\n\nMetaHistoryBook replied that they prefer decoupled evidence pings. MetaMuseum\nshould send an `Update` deploy-note as soon as the real reviewed update is live,\nso they can confirm `type=Update` coverage immediately. MetaMuseum should send a\nsecond deploy-note only when the first genuine upstream `404`/`410` tombstone\nappears and a real `Delete` row is live. MetaHistoryBook will keep the callback\nendpoint and `metahistorybook-harvester-prod-v1` secret active for both pings.\n\n## 2026-07-05 Update Deploy Proof\n\nMetaMuseum deployed the reviewed `Update` source path to production in Vercel\ndeployment `dpl_3EDWJr6ooUdDhW9rA6aBj3HoUdW8`, aliased to\n`https://www.metamuseum.org`. Production proof was captured at\n`2026-07-05T19:48:09.519Z` in\n`artifacts/activity-syndication/met-437133-update-production-deploy-2026-07-05T19-48-09-519Z.json`.\n\nLive typed feed reads after deploy:\n\n| Read | Result |\n|---|---|\n| `/api/activity?type=Update&limit=10` | HTTP `200`, `totalItems: 1`, `1` row |\n| `/api/activity?type=Update&source=reviewed-update&limit=10` | HTTP `200`, `totalItems: 1`, `1` row |\n| `/api/activity?type=Delete&limit=10` | HTTP `200`, `totalItems: 0`, `0` rows |\n\nThe `Update` row is\n`https://collectionapi.metmuseum.org/public/collection/v1/objects/437133#reviewed-update-2026-07-05-measurements#activity-stream`.\nIts `endTime` is `2026-07-05T19:21:57.765Z`, its projected `object.id` is the\ndereferenceable MetaMuseum record URL, its `object.sourceId` is the canonical Met\nCollection API object URL, and `object.equivalent[]` includes the Met API URL,\nMet public collection URL, and Wikidata object `Q432253`.\n\nThe production record detail now returns the reviewed live Met measurement order\n`Overall, Framed` and carries `_source.reviewedUpdates[]` with the same evidence\nreference. `Delete` remains intentionally empty because no genuine upstream\n`404`/`410` tombstone exists yet.\n\n## 2026-07-05 Update Partner Re-Read Confirmation\n\nMetaHistoryBook re-read the production feed as `metahistorybook-harvester-prod`\nat `2026-07-05T19:50:30Z`.\n\nPartner-reported result: **PASS, real Update coverage confirmed**.\n\n| Read | Result |\n|---|---|\n| `/api/activity?type=Update&limit=100` | `totalItems: 1`, `1` item, `type: Update` |\n| `/api/activity?type=Delete&limit=100` | `totalItems: 0`, `0` rows, intentionally empty |\n\nThey confirmed the `Update` row is real and non-synthetic, with `source.kind:\nreviewed-update`, object `437133` (`Garden at Sainte-Adresse`), and summary text\nmatching the live Met measurements-order delta.\n\nProjection notes from partner re-read:\n\n- `object.id`: dereferenceable MetaMuseum record URL; fetched with HTTP `200`,\n  with `record.id === _links.self.href`.\n- `object.sourceId`: `https://collectionapi.metmuseum.org/public/collection/v1/objects/437133`.\n- `equivalent[]`: Met API URL, Met public collection URL, and Wikidata\n  `Q432253`.\n- `endTime`: `2026-07-05T19:21:57.765Z`, valid UTC.\n\nMetaHistoryBook also confirmed the cross-reconciliation join still holds:\n`https://www.metahistorybook.com/api/linked-art/Q432253` returns HTTP `200`, so\nthe real `Update` now joins Met and MetaHistoryBook through the shared Wikidata\nanchor. They recorded Update coverage on their side and will wait for the second\ndeploy-note when a genuine upstream `404`/`410` tombstone exists.\n\n## 2026-07-07 Optional Update Event Dereference Follow-Up\n\nMetaMuseum refreshed the partner onboarding pack for\n`metahistorybook-harvester-prod` after ActivityStreams `linkedArt` projections\nstarted using dereferenceable MetaMuseum event URLs. The generated pack is:\n\n- `artifacts/activity-syndication/activity-partner-onboarding-pack-latest.json`\n- `artifacts/activity-syndication/activity-partner-onboarding-pack-latest.md`\n- `artifacts/activity-syndication/runs/activity-partner-onboarding-pack-2026-07-07T22-54-21-368Z.json`\n\nOptional partner ask: re-read\n`/api/activity?limit=100&type=Update` with\n`x-linked-art-consumer-id: metahistorybook-harvester-prod`, then fetch the first\nrow's `linkedArt.id`. Expected result: HTTP `200`, Linked Art JSON-LD context,\n`entity.id` equal to the requested `/api/events/...` URL, `entity._complete:\nfalse`, and `entity.equivalent[]` preserving the source activity URI.\n\nThis is partner-facing compatibility evidence for the existing real `Update`\nrow. It does not replace the strict type-coverage row and it does not request\n`type=Delete` re-verification. `Delete` remains blocked until a genuine upstream\n`404`/`410` tombstone exists and a real deletion row is live.\n\n## 2026-07-10 Optional Evidence Ledger and Update Dereference Verification\n\nMetaHistoryBook re-ran the optional production checks from outside MetaMuseum at\n`2026-07-10T00:18:38Z`, using the server `Date` header on\n`https://www.metamuseum.org` as the read timestamp.\n\nPartner-reported result: **PASS, all three fixes confirmed live**.\n\n| Check | Result |\n|---|---|\n| Evidence page | `/evidence` redirects to `/en/evidence`, and the destination returns HTTP `200`. |\n| Evidence APIs | `/api/evidence` and `/api/evidence/ledger` return HTTP `200`. |\n| Evaluator boundary | The ledger clearly presents `Create`/`Update` as covered, `Delete` as pending, and tombstone-watch scans as monitoring evidence rather than synthetic deletion proof. |\n| Update row | `/api/activity?type=Update&limit=1` returns the same real reviewed `Update` row for Met object `437133`, `Garden at Sainte-Adresse`. |\n| `linkedArt.id` dereference | The Update row now points at MetaMuseum-hosted `/api/events/...` rather than the upstream Met URI; dereferencing returns HTTP `200` with the Linked Art JSON-LD context. |\n| Linked Art activity shape | The dereferenced entity has `type: Activity`, `_complete: false`, and source-preserving `equivalent[]`. |\n| Delete boundary | `/api/activity?type=Delete` remains `totalItems: 0`; MetaHistoryBook did not issue a Delete verification request and will wait for a genuine upstream `404`/`410` tombstone. |\n\nEvidence:\n\n- `artifacts/activity-syndication/metahistorybook-optional-ledger-linkedart-verification-2026-07-10.json`\n\nThis closes the optional evidence-ledger and Update event-dereference thread.\nIt does **not** close the strict ActivityStreams `Delete` blocker. The next\nMetaHistoryBook ping should still wait until a real upstream `404`/`410`\ntombstone exists and a real deployed `Delete` row can be read.\n\n## 2026-07-05 Tombstone Watch Refresh\n\nMetaMuseum added `pnpm activity:tombstone:scan` as the recurring upstream watch\nfor real `Delete` evidence. The first scan run at `2026-07-05T20:13:24.792Z`\nchecked `55` stored Met canonical upstream record ids and found `0` upstream\n`404`/`410` tombstones.\n\nEvidence:\n\n- `artifacts/activity-syndication/activity-tombstone-scan-latest.json`\n- `artifacts/activity-syndication/runs/activity-tombstone-scan-2026-07-05T20-13-24-792Z.json`\n\nNo `pipeline/state/deletion-activities.json` row was written from this scan, and\nMetaHistoryBook should not be pinged for `type=Delete` until a future scan finds\na genuine tombstone and the resulting deletion ledger is deployed.\n\n## 2026-07-06 Dataset Reuse Confirmation\n\nMetaHistoryBook re-read the public dataset surface after the dataset export\n`equivalent[]` projection fix and confirmed the FAIR/LOUD reuse package is no\nlonger only self-verified. The partner read dataset version\n`2026.07.06+sha256.43eb7f0049c9` from `https://www.metamuseum.org`.\n\nPartner-reported result: **PASS, dataset thread closed**.\n\n| Check | Result |\n|---|---|\n| Object-level `record.equivalent[]` | `53/54` export records carry non-empty equivalents, up from the previously reported `0/54`. |\n| Wikidata reconciliation | `47/54` export records include a Wikidata entity, matching the activity-stream projection population rate. |\n| Object `437133` | `Garden at Sainte-Adresse` carries the Met API URL, Met public collection URL, and Wikidata `Q432253`, identical to the ActivityStreams projection. |\n| Integrity | `X-Metamuseum-Response-Checksum-Sha256` matches `sha256(body)` on the new export version. |\n| Discovery and pagination | Capabilities discovery and export pagination remain green. |\n| License scope | The dataset profile states that CC BY 4.0 governs packaging/metadata while per-record rights govern object/content/media reuse. |\n\nEvidence:\n\n- `artifacts/dataset-publication/metahistorybook-dataset-reuse-confirmation-2026-07-06.json`\n- `artifacts/dataset-publication/metahistorybook-dataset-reuse-confirmation-2026-07-06.md`\n\nThis closes the partner-confirmed dataset reuse thread. `Delete` remains\nunchanged: MetaHistoryBook should receive a second deploy-note only after a\ngenuine upstream `404`/`410` tombstone exists and the real deletion row is live.\n\n## Evidence Classification\n\nThese are MetaMuseum's first two production-grade external-consumer ActivityStreams read evidence rows. They count as real declared external consumer reads for `metahistorybook-harvester-prod` and `daily-metahistorybook-prod`, and prove production interoperability for the Met backfill slice plus product integration in Daily's candidate-selection workflow.\n\nIt does **not** by itself complete the strict ActivityStreams syndication gate. The strict gate still needs:\n\n- `3/3` real external consumers in the adoption window; current tracked status is `3/3` after `wikidataexplorer-metamuseum-prod`.\n- Feed-read activity-type coverage for `Create`, `Update`, and `Delete`; `Create`\n  and `Update` now have production partner proof, while `Delete` remains blocked\n  on a real upstream `404`/`410` tombstone.\n- Durable external HTTPS callback subscriptions for those same consumers; current tracked status is `3/3`.\n- Recent 2xx callback verification evidence; current tracked status is `3/3`.\n\nTracked evidence surfaces:\n\n- `artifacts/activity-syndication/activity-syndication-evidence-latest.json`\n- `artifacts/activity-syndication/activity-provider-backfill-evidence-latest.json`\n- `docs/linked-art/metahistorybook-reciprocal-harvest-checklist.md`\n","sections":[{"level":2,"heading":"2026-07-05 Production Harvest","anchor":"2026-07-05-production-harvest"},{"level":2,"heading":"2026-07-05 Daily Artwork-Of-The-Day Consumer","anchor":"2026-07-05-daily-artwork-of-the-day-consumer"},{"level":2,"heading":"2026-07-05 Callback And Typed Cursor-Feed Reply","anchor":"2026-07-05-callback-and-typed-cursor-feed-reply"},{"level":2,"heading":"2026-07-05 Post-Callback Partner Alignment","anchor":"2026-07-05-post-callback-partner-alignment"},{"level":2,"heading":"2026-07-05 Deploy-Note Standby Confirmation","anchor":"2026-07-05-deploy-note-standby-confirmation"},{"level":2,"heading":"2026-07-05 Reviewed Update Evidence And Tombstone Scan","anchor":"2026-07-05-reviewed-update-evidence-and-tombstone-scan"},{"level":2,"heading":"2026-07-05 Update Deploy Proof","anchor":"2026-07-05-update-deploy-proof"},{"level":2,"heading":"2026-07-05 Update Partner Re-Read Confirmation","anchor":"2026-07-05-update-partner-re-read-confirmation"},{"level":2,"heading":"2026-07-07 Optional Update Event Dereference Follow-Up","anchor":"2026-07-07-optional-update-event-dereference-follow-up"},{"level":2,"heading":"2026-07-10 Optional Evidence Ledger and Update Dereference Verification","anchor":"2026-07-10-optional-evidence-ledger-and-update-dereference-verification"},{"level":2,"heading":"2026-07-05 Tombstone Watch Refresh","anchor":"2026-07-05-tombstone-watch-refresh"},{"level":2,"heading":"2026-07-06 Dataset Reuse Confirmation","anchor":"2026-07-06-dataset-reuse-confirmation"},{"level":2,"heading":"Evidence Classification","anchor":"evidence-classification"}],"html":"<h1 id=\"metahistorybook-production-consumer-evidence\">MetaHistoryBook Production Consumer Evidence</h1>\n<p>Last updated: 2026-07-07</p>\n<h2 id=\"2026-07-05-production-harvest\">2026-07-05 Production Harvest</h2>\n<p>MetaHistoryBook ran the first passing production-ID harvest against MetaMuseum as `metahistorybook-harvester-prod` after the canonical record URL and `equivalent[]` projection fix deployed.</p>\n<p>Partner-reported result: <strong>PASS, 4/4 validation points</strong>.</p>\n<p>| Validation point | Result | Evidence |</p>\n<p>|---|---|---|</p>\n<p>| Multi-page walk-back ordering | PASS | `?provider=met` reported `53` items; `last -&gt; page/2 -&gt; page/1 -&gt; page/0` traversal worked with page sizes `3`, `25`, and `25`; `endTime` was strictly ascending across all `53` activities. |</p>\n<p>| Real non-epoch timestamps | PASS | `53/53` timestamps were valid UTC values with zero epoch fallbacks. `record-backfill` timestamps are documented as import/republication times. |</p>\n<p>| `equivalent[]` reconciliation hooks | PASS | Five sampled records across pages dereferenced from MetaMuseum activity `object.id` values; each record returned `record.id === _links.self.href`, preserved the upstream Met URL as `object.sourceId`, and exposed Met collection API URL, Met public URL, and Wikidata entity hooks when upstream Wikidata exists. |</p>\n<p>| Dedupe behavior | PASS | Default view returned `53/53` unique `object.id` values; `source=record-backfill` diagnostic view also reported `53`. |</p>\n<p>The partner confirmed `47/53` Met records expose a Wikidata QID; the remaining six lack upstream object Wikidata links and are source-dependent rather than a projection failure. The concrete overlap proof is `Q432253` (`Garden at Sainte-Adresse`): MetaHistoryBook resolved the same QID through its own `/api/linked-art/{qid}` corpus, establishing the first Met-to-MetaHistoryBook join through the shared Wikidata anchor.</p>\n<h2 id=\"2026-07-05-daily-artwork-of-the-day-consumer\">2026-07-05 Daily Artwork-Of-The-Day Consumer</h2>\n<p>Daily (`daily.metahistorybook.com`) confirmed a separate production application read as `daily-metahistorybook-prod`, distinct from `metahistorybook-harvester-prod`. The consumer ID is sent in Daily&#39;s production `User-Agent`.</p>\n<p>Partner-reported result: <strong>PASS, distinct external product consumer</strong>.</p>\n<p>| Validation point | Result | Evidence |</p>\n<p>|---|---|---|</p>\n<p>| Collection read | PASS | `GET /api/activity/collection?provider=met` returned HTTP `200`, `application/activity+json`, IIIF Change Discovery 1.0 `OrderedCollection`, `totalItems: 53`, and `first -&gt; page/0 ... last -&gt; page/2`. |</p>\n<p>| Page walk-back | PASS | Daily walked `last -&gt; prev -&gt; first` across all three pages: `25 + 25 + 3 = 53` activities, all `Create`, reconciling with `totalItems`. |</p>\n<p>| Record dereference | PASS | Each activity `object.id` resolved to a MetaMuseum Met Linked Art `HumanMadeObject`; the partner specifically confirmed object `437133`, Monet&#39;s `Garden at Sainte-Adresse`. |</p>\n<p>| Product integration | PASS | Daily ingests the feed into a supplementary artwork-of-the-day candidate pool and selection queue alongside its Wikidata-based picks. First production run created `53` candidates, including `15` paintings; cursor persisted at `2026-05-31T10:40:54.290Z`; repeat refresh processed zero new changes. |</p>\n<p>Daily also reports cursor-based reconciliation: it persists the newest activity timestamp and walks back only until that cursor on refresh. Delete activities remove records from the pool, and updates reconcile in the same refresh path. The current MetaMuseum Met backfill evidence still observes only `Create` activities, so strict MetaMuseum activity-type coverage remains missing live `Update` and `Delete` reads until those activity types are actually present and read.</p>\n<h2 id=\"2026-07-05-callback-and-typed-cursor-feed-reply\">2026-07-05 Callback And Typed Cursor-Feed Reply</h2>\n<p>MetaHistoryBook replied to the refreshed partner pack with the stable consumer</p>\n<p>ID `metahistorybook-harvester-prod`, callback URL</p>\n<p>`https://www.metahistorybook.com/api/metamuseum/callback`, event types</p>\n<p>`Create`, `Update`, and `Delete`, and signing label</p>\n<p>`metahistorybook-harvester-prod-v1`.</p>\n<p>Partner-reported typed read timestamp: `2026-07-05T16:37Z`.</p>\n<p>| Read | Result |</p>\n<p>|---|---|</p>\n<p>| `/api/activity?limit=100` | `totalItems: 108`, `100` items on page 1, `next` to offset `100` |</p>\n<p>| `type=Create` | `108` Create rows, `100` on page 1 |</p>\n<p>| `type=Update` | `0`, explicitly reported as zero |</p>\n<p>| `type=Delete` | `0`, explicitly reported as zero |</p>\n<p>| Object-scoped `544320` | `2` Create rows |</p>\n<p>They confirmed the callback is public HTTPS, fail-closed for signed deliveries,</p>\n<p>validates HMAC-SHA256 over `&lt;timestamp&gt;.&lt;raw JSON payload&gt;`, and returns `204 No</p>\n<p>Content` for verified delivery POSTs. Strict callback proof is still pending</p>\n<p>because the authentic proof is MetaMuseum&#39;s first signed delivery after the</p>\n<p>HMAC secret is exchanged out of band. MetaHistoryBook later confirmed the `404`</p>\n<p>GET result was deploy-pending. A repeat MetaMuseum GET liveness check returned</p>\n<p>`200`, and MetaMuseum sent one signed production `Create` Activity payload to the</p>\n<p>callback. The delivery returned `204` at `2026-07-05T17:13:13.312Z` and is</p>\n<p>recorded as accepted durable callback evidence for</p>\n<p>`metahistorybook-harvester-prod`. Evidence:</p>\n<p>`artifacts/activity-syndication/metahistorybook-harvester-prod-callback-2026-07-05T17-13-13-312Z.json`.</p>\n<p>The HMAC secret and signature value are intentionally omitted from the proof</p>\n<p>artifact, chat, and email.</p>\n<p>They also reported that the cursor feed lagged the Change Discovery projection:</p>\n<p>default `/api/activity` exposed semantic diagnostic rows with placeholder object</p>\n<p>dates and upstream object IDs. The follow-up fix applies the same</p>\n<p>dereferenceable `object.id`, `object.sourceId`, valid UTC `endTime`, and default</p>\n<p>per-object dedupe projection to `/api/activity` while keeping cursor-feed</p>\n<p>`linkedArt` embeds.</p>\n<h2 id=\"2026-07-05-post-callback-partner-alignment\">2026-07-05 Post-Callback Partner Alignment</h2>\n<p>MetaHistoryBook acknowledged the `2026-07-05T17:13:13.312Z` signed callback</p>\n<p>proof and confirmed the callback item is closed for</p>\n<p>`metahistorybook-harvester-prod`. They rechecked the public typed feed and</p>\n<p>reported `type=Update -&gt; 0` and `type=Delete -&gt; 0`, explicitly agreeing that no</p>\n<p>fake activity rows should be generated on either side.</p>\n<p>MetaMuseum independently rechecked the public typed endpoints at</p>\n<p>`2026-07-05T17:21:34Z`:</p>\n<p>| Read | Result |</p>\n<p>|---|---|</p>\n<p>| `/api/activity?limit=100&amp;type=Update` | `totalItems: 0`, `0` items |</p>\n<p>| `/api/activity?limit=100&amp;type=Delete` | `totalItems: 0`, `0` items |</p>\n<p>MetaHistoryBook&#39;s reader is ready to re-read `type=Update` and `type=Delete` as</p>\n<p>`metahistorybook-harvester-prod` after MetaMuseum deploys real reviewed update</p>\n<p>rows and real upstream `404`/`410` tombstone delete rows.</p>\n<h2 id=\"2026-07-05-deploy-note-standby-confirmation\">2026-07-05 Deploy-Note Standby Confirmation</h2>\n<p>MetaHistoryBook confirmed there is no remaining partner-side setup pending. The</p>\n<p>callback endpoint and `metahistorybook-harvester-prod-v1` signing secret will</p>\n<p>stay active while MetaMuseum produces the real source rows.</p>\n<p>When MetaMuseum sends the deploy-note ping, MetaHistoryBook will re-read</p>\n<p>`type=Update` and `type=Delete` as `metahistorybook-harvester-prod` and return:</p>\n<p>  `endTime`.</p>\n<ul><li>read timestamp;</li><li>per-type `totalItems` and item counts;</li><li>confirmation that the rows are real non-empty `Update`/`Delete` rows;</li><li>projection notes for `object.id`, `object.sourceId`, `equivalent[]`, and UTC</li></ul>\n<p>No partner action is pending until MetaMuseum sends the next deploy-note. The</p>\n<p>partner now prefers two separate deploy-note pings: first when the reviewed</p>\n<p>metadata `Update` row is live, and later when a real upstream `404`/`410`</p>\n<p>tombstone `Delete` row exists. The strict blocker is now MetaMuseum source data,</p>\n<p>not MetaHistoryBook callback readiness.</p>\n<h2 id=\"2026-07-05-reviewed-update-evidence-and-tombstone-scan\">2026-07-05 Reviewed Update Evidence And Tombstone Scan</h2>\n<p>MetaMuseum generated the first local real `Update` source row after comparing</p>\n<p>the stored Met record for object `437133` with the live Met Collection API.</p>\n<p>The live upstream response returned `200` and changed</p>\n<p>`_source.raw.measurements` order from `Framed, Overall` to `Overall, Framed`.</p>\n<p>MetaMuseum wrote the refreshed Linked Art record through `/api/records` for the</p>\n<p>existing record id, so the audit ledger appended a real `record.update` row at</p>\n<p>`2026-07-05T19:21:57.761Z`.</p>\n<p>Evidence:</p>\n<p>`artifacts/activity-syndication/met-437133-reviewed-update-2026-07-05T19-21-57-765Z.json`.</p>\n<p>Local typed feed check after the update:</p>\n<p>| Read | Result |</p>\n<p>|---|---|</p>\n<p>| `/api/activity?type=Update&amp;limit=10` | `totalItems: 1`, `1` item; first row is `record.update via POST /api/records` for Met object `437133` |</p>\n<p>| `/api/activity?type=Delete&amp;limit=10` | `totalItems: 0`, `0` items |</p>\n<p>MetaMuseum also probed the `56` stored canonical upstream record ids eligible</p>\n<p>for tombstone evidence. All returned `200`. No `Delete` row was generated,</p>\n<p>because there is no real upstream `404`/`410` tombstone candidate in the current</p>\n<p>stored canonical record set.</p>\n<p>MetaHistoryBook replied that they prefer decoupled evidence pings. MetaMuseum</p>\n<p>should send an `Update` deploy-note as soon as the real reviewed update is live,</p>\n<p>so they can confirm `type=Update` coverage immediately. MetaMuseum should send a</p>\n<p>second deploy-note only when the first genuine upstream `404`/`410` tombstone</p>\n<p>appears and a real `Delete` row is live. MetaHistoryBook will keep the callback</p>\n<p>endpoint and `metahistorybook-harvester-prod-v1` secret active for both pings.</p>\n<h2 id=\"2026-07-05-update-deploy-proof\">2026-07-05 Update Deploy Proof</h2>\n<p>MetaMuseum deployed the reviewed `Update` source path to production in Vercel</p>\n<p>deployment `dpl_3EDWJr6ooUdDhW9rA6aBj3HoUdW8`, aliased to</p>\n<p>`https://www.metamuseum.org`. Production proof was captured at</p>\n<p>`2026-07-05T19:48:09.519Z` in</p>\n<p>`artifacts/activity-syndication/met-437133-update-production-deploy-2026-07-05T19-48-09-519Z.json`.</p>\n<p>Live typed feed reads after deploy:</p>\n<p>| Read | Result |</p>\n<p>|---|---|</p>\n<p>| `/api/activity?type=Update&amp;limit=10` | HTTP `200`, `totalItems: 1`, `1` row |</p>\n<p>| `/api/activity?type=Update&amp;source=reviewed-update&amp;limit=10` | HTTP `200`, `totalItems: 1`, `1` row |</p>\n<p>| `/api/activity?type=Delete&amp;limit=10` | HTTP `200`, `totalItems: 0`, `0` rows |</p>\n<p>The `Update` row is</p>\n<p>`https://collectionapi.metmuseum.org/public/collection/v1/objects/437133#reviewed-update-2026-07-05-measurements#activity-stream`.</p>\n<p>Its `endTime` is `2026-07-05T19:21:57.765Z`, its projected `object.id` is the</p>\n<p>dereferenceable MetaMuseum record URL, its `object.sourceId` is the canonical Met</p>\n<p>Collection API object URL, and `object.equivalent[]` includes the Met API URL,</p>\n<p>Met public collection URL, and Wikidata object `Q432253`.</p>\n<p>The production record detail now returns the reviewed live Met measurement order</p>\n<p>`Overall, Framed` and carries `_source.reviewedUpdates[]` with the same evidence</p>\n<p>reference. `Delete` remains intentionally empty because no genuine upstream</p>\n<p>`404`/`410` tombstone exists yet.</p>\n<h2 id=\"2026-07-05-update-partner-re-read-confirmation\">2026-07-05 Update Partner Re-Read Confirmation</h2>\n<p>MetaHistoryBook re-read the production feed as `metahistorybook-harvester-prod`</p>\n<p>at `2026-07-05T19:50:30Z`.</p>\n<p>Partner-reported result: <strong>PASS, real Update coverage confirmed</strong>.</p>\n<p>| Read | Result |</p>\n<p>|---|---|</p>\n<p>| `/api/activity?type=Update&amp;limit=100` | `totalItems: 1`, `1` item, `type: Update` |</p>\n<p>| `/api/activity?type=Delete&amp;limit=100` | `totalItems: 0`, `0` rows, intentionally empty |</p>\n<p>They confirmed the `Update` row is real and non-synthetic, with `source.kind:</p>\n<p>reviewed-update`, object `437133` (`Garden at Sainte-Adresse`), and summary text</p>\n<p>matching the live Met measurements-order delta.</p>\n<p>Projection notes from partner re-read:</p>\n<p>  with `record.id === _links.self.href`.</p>\n<p>  `Q432253`.</p>\n<ul><li>`object.id`: dereferenceable MetaMuseum record URL; fetched with HTTP `200`,</li><li>`object.sourceId`: `https://collectionapi.metmuseum.org/public/collection/v1/objects/437133`.</li><li>`equivalent[]`: Met API URL, Met public collection URL, and Wikidata</li><li>`endTime`: `2026-07-05T19:21:57.765Z`, valid UTC.</li></ul>\n<p>MetaHistoryBook also confirmed the cross-reconciliation join still holds:</p>\n<p>`https://www.metahistorybook.com/api/linked-art/Q432253` returns HTTP `200`, so</p>\n<p>the real `Update` now joins Met and MetaHistoryBook through the shared Wikidata</p>\n<p>anchor. They recorded Update coverage on their side and will wait for the second</p>\n<p>deploy-note when a genuine upstream `404`/`410` tombstone exists.</p>\n<h2 id=\"2026-07-07-optional-update-event-dereference-follow-up\">2026-07-07 Optional Update Event Dereference Follow-Up</h2>\n<p>MetaMuseum refreshed the partner onboarding pack for</p>\n<p>`metahistorybook-harvester-prod` after ActivityStreams `linkedArt` projections</p>\n<p>started using dereferenceable MetaMuseum event URLs. The generated pack is:</p>\n<ul><li>`artifacts/activity-syndication/activity-partner-onboarding-pack-latest.json`</li><li>`artifacts/activity-syndication/activity-partner-onboarding-pack-latest.md`</li><li>`artifacts/activity-syndication/runs/activity-partner-onboarding-pack-2026-07-07T22-54-21-368Z.json`</li></ul>\n<p>Optional partner ask: re-read</p>\n<p>`/api/activity?limit=100&amp;type=Update` with</p>\n<p>`x-linked-art-consumer-id: metahistorybook-harvester-prod`, then fetch the first</p>\n<p>row&#39;s `linkedArt.id`. Expected result: HTTP `200`, Linked Art JSON-LD context,</p>\n<p>`entity.id` equal to the requested `/api/events/...` URL, `entity._complete:</p>\n<p>false`, and `entity.equivalent[]` preserving the source activity URI.</p>\n<p>This is partner-facing compatibility evidence for the existing real `Update`</p>\n<p>row. It does not replace the strict type-coverage row and it does not request</p>\n<p>`type=Delete` re-verification. `Delete` remains blocked until a genuine upstream</p>\n<p>`404`/`410` tombstone exists and a real deletion row is live.</p>\n<h2 id=\"2026-07-10-optional-evidence-ledger-and-update-dereference-verification\">2026-07-10 Optional Evidence Ledger and Update Dereference Verification</h2>\n<p>MetaHistoryBook re-ran the optional production checks from outside MetaMuseum at</p>\n<p>`2026-07-10T00:18:38Z`, using the server `Date` header on</p>\n<p>`https://www.metamuseum.org` as the read timestamp.</p>\n<p>Partner-reported result: <strong>PASS, all three fixes confirmed live</strong>.</p>\n<p>| Check | Result |</p>\n<p>|---|---|</p>\n<p>| Evidence page | `/evidence` redirects to `/en/evidence`, and the destination returns HTTP `200`. |</p>\n<p>| Evidence APIs | `/api/evidence` and `/api/evidence/ledger` return HTTP `200`. |</p>\n<p>| Evaluator boundary | The ledger clearly presents `Create`/`Update` as covered, `Delete` as pending, and tombstone-watch scans as monitoring evidence rather than synthetic deletion proof. |</p>\n<p>| Update row | `/api/activity?type=Update&amp;limit=1` returns the same real reviewed `Update` row for Met object `437133`, `Garden at Sainte-Adresse`. |</p>\n<p>| `linkedArt.id` dereference | The Update row now points at MetaMuseum-hosted `/api/events/...` rather than the upstream Met URI; dereferencing returns HTTP `200` with the Linked Art JSON-LD context. |</p>\n<p>| Linked Art activity shape | The dereferenced entity has `type: Activity`, `_complete: false`, and source-preserving `equivalent[]`. |</p>\n<p>| Delete boundary | `/api/activity?type=Delete` remains `totalItems: 0`; MetaHistoryBook did not issue a Delete verification request and will wait for a genuine upstream `404`/`410` tombstone. |</p>\n<p>Evidence:</p>\n<ul><li>`artifacts/activity-syndication/metahistorybook-optional-ledger-linkedart-verification-2026-07-10.json`</li></ul>\n<p>This closes the optional evidence-ledger and Update event-dereference thread.</p>\n<p>It does <strong>not</strong> close the strict ActivityStreams `Delete` blocker. The next</p>\n<p>MetaHistoryBook ping should still wait until a real upstream `404`/`410`</p>\n<p>tombstone exists and a real deployed `Delete` row can be read.</p>\n<h2 id=\"2026-07-05-tombstone-watch-refresh\">2026-07-05 Tombstone Watch Refresh</h2>\n<p>MetaMuseum added `pnpm activity:tombstone:scan` as the recurring upstream watch</p>\n<p>for real `Delete` evidence. The first scan run at `2026-07-05T20:13:24.792Z`</p>\n<p>checked `55` stored Met canonical upstream record ids and found `0` upstream</p>\n<p>`404`/`410` tombstones.</p>\n<p>Evidence:</p>\n<ul><li>`artifacts/activity-syndication/activity-tombstone-scan-latest.json`</li><li>`artifacts/activity-syndication/runs/activity-tombstone-scan-2026-07-05T20-13-24-792Z.json`</li></ul>\n<p>No `pipeline/state/deletion-activities.json` row was written from this scan, and</p>\n<p>MetaHistoryBook should not be pinged for `type=Delete` until a future scan finds</p>\n<p>a genuine tombstone and the resulting deletion ledger is deployed.</p>\n<h2 id=\"2026-07-06-dataset-reuse-confirmation\">2026-07-06 Dataset Reuse Confirmation</h2>\n<p>MetaHistoryBook re-read the public dataset surface after the dataset export</p>\n<p>`equivalent[]` projection fix and confirmed the FAIR/LOUD reuse package is no</p>\n<p>longer only self-verified. The partner read dataset version</p>\n<p>`2026.07.06+sha256.43eb7f0049c9` from `https://www.metamuseum.org`.</p>\n<p>Partner-reported result: <strong>PASS, dataset thread closed</strong>.</p>\n<p>| Check | Result |</p>\n<p>|---|---|</p>\n<p>| Object-level `record.equivalent[]` | `53/54` export records carry non-empty equivalents, up from the previously reported `0/54`. |</p>\n<p>| Wikidata reconciliation | `47/54` export records include a Wikidata entity, matching the activity-stream projection population rate. |</p>\n<p>| Object `437133` | `Garden at Sainte-Adresse` carries the Met API URL, Met public collection URL, and Wikidata `Q432253`, identical to the ActivityStreams projection. |</p>\n<p>| Integrity | `X-Metamuseum-Response-Checksum-Sha256` matches `sha256(body)` on the new export version. |</p>\n<p>| Discovery and pagination | Capabilities discovery and export pagination remain green. |</p>\n<p>| License scope | The dataset profile states that CC BY 4.0 governs packaging/metadata while per-record rights govern object/content/media reuse. |</p>\n<p>Evidence:</p>\n<ul><li>`artifacts/dataset-publication/metahistorybook-dataset-reuse-confirmation-2026-07-06.json`</li><li>`artifacts/dataset-publication/metahistorybook-dataset-reuse-confirmation-2026-07-06.md`</li></ul>\n<p>This closes the partner-confirmed dataset reuse thread. `Delete` remains</p>\n<p>unchanged: MetaHistoryBook should receive a second deploy-note only after a</p>\n<p>genuine upstream `404`/`410` tombstone exists and the real deletion row is live.</p>\n<h2 id=\"evidence-classification\">Evidence Classification</h2>\n<p>These are MetaMuseum&#39;s first two production-grade external-consumer ActivityStreams read evidence rows. They count as real declared external consumer reads for `metahistorybook-harvester-prod` and `daily-metahistorybook-prod`, and prove production interoperability for the Met backfill slice plus product integration in Daily&#39;s candidate-selection workflow.</p>\n<p>It does <strong>not</strong> by itself complete the strict ActivityStreams syndication gate. The strict gate still needs:</p>\n<p>  and `Update` now have production partner proof, while `Delete` remains blocked</p>\n<p>  on a real upstream `404`/`410` tombstone.</p>\n<ul><li>`3/3` real external consumers in the adoption window; current tracked status is `3/3` after `wikidataexplorer-metamuseum-prod`.</li><li>Feed-read activity-type coverage for `Create`, `Update`, and `Delete`; `Create`</li><li>Durable external HTTPS callback subscriptions for those same consumers; current tracked status is `3/3`.</li><li>Recent 2xx callback verification evidence; current tracked status is `3/3`.</li></ul>\n<p>Tracked evidence surfaces:</p>\n<ul><li>`artifacts/activity-syndication/activity-syndication-evidence-latest.json`</li><li>`artifacts/activity-syndication/activity-provider-backfill-evidence-latest.json`</li><li>`docs/linked-art/metahistorybook-reciprocal-harvest-checklist.md`</li></ul>","updatedAt":"2018-10-20T01:46:40.000Z","checksum":"1577a970c8b0ad092e89e3df19f52d0d08d8bff3cc310f87e3e6f020f96278ef","checksumPrefix":"1577a970c8b0","anchorCount":13,"lineCount":316,"rawUrl":"/api/docs/content?path=linked-art%2Fmetahistorybook-prod-harvest-evidence.md","htmlUrl":"/docs?doc=linked-art%2Fmetahistorybook-prod-harvest-evidence.md","apiUrl":"/api/docs/content?path=linked-art%2Fmetahistorybook-prod-harvest-evidence.md"}