Repository navigation
Post Slack release alerts from changes to releases.json - #279
Merged
Merged
Conversation
When an update to a release repository's main changes releases.json, the Hugging Face webhook is to compare the record before and after and post: - for a newly published build: "New Microcosm UK build `<release>/<build>`: now current", or "...: published, not current (current stays `<build>`)"; - for a change of current build: "Microcosm UK `<release>`: current build changed from `<old>` to `<new>`"; - for a withdrawal: "Microcosm UK build `<release>/<build>` withdrawn"; - for the update that first creates releases.json: one summary message. Each message keeps the existing context text (repository, publication time, dashboard link). An invalid or unreadable record before or after the update is logged and nothing is posted. Repositories without releases.json keep their tag alerts, and staging repositories read no record. The webhook reads releases.json with a Hugging Face token from HF_TOKEN or HUGGINGFACE_TOKEN. The dispatch tests' repositories answer releases.json with Hugging Face's "entry not found" 404, so their GitHub calls are counted as before. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
For an update to a release repository's main, the Hugging Face webhook now reads releases.json at the commits before and after the update and posts one message to the country's channel for each newly published build (saying whether it became current), each change of current build and each withdrawal (release-record-alerts.ts, releaseRecordAlertPayload). The update that first creates releases.json gets one summary message instead of one per listed build. A record that cannot be read or that the release writer's rules refuse is logged and nothing is posted; the dispatch is unaffected. Repositories without releases.json read as having none on both sides, so they keep only their tag alerts. The webhook reads releases.json with HF_TOKEN, or else HUGGINGFACE_TOKEN, from its configuration (huggingFaceToken). The Slack webhook variables are unchanged. The docs describe the alerts and the replay advice. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
CI at ce68777 failed two tests in reviewed-repository-import.test.ts: a tag delivery's answer now also carries release_record_alerted, an empty list, although no releases.json was read. The answer to a delivery without a main update should be unchanged; a main update's answer lists the alerts posted. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The webhook's answer carries release_record_alerted only when it read releases.json for a release repository's main update. A delivery without one, such as a new tag alone, answers exactly as before. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Brings in microcosm-releases-json-readers at 2571995: the build folder listing's timeout, single-build modes through the manifest store, the promotion check by name, one head lookup per step and the docs. No conflicts. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Review round 1 of this PR, as tests: - Bug: the summary for a record with no releases had an empty section, and a long one had a section over Slack's 3,000-character limit; Slack refuses both. - A transient Hugging Face failure (5xx, 429, a network error, a timeout) reading releases.json answers 503 before the dispatch or any alert, so Hugging Face's retry posts each alert once. A lasting failure (401, RevisionNotFound) is logged, and the dispatch and tag alerts go ahead. - A deleted record, a change of default release and an un-withdrawal are logged without posting. - published_at and tag names are escaped for Slack's formatted text. - The Hugging Face token is read as the dashboard's other readers read it. The comparison and the payloads get direct tests: - several alerts in one update, a new release, both "no current" texts; - through the webhook: a null oldSha, a Slack failure for one alert, and no token. These already passed and guard the existing behaviour. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… changes - Retry: the webhook reads releases.json before it dispatches or posts anything. A transient failure (5xx, 429, a failed or timed-out request) answers 503 with nothing done, so Hugging Face's retry of the delivery dispatches and posts each alert once. A lasting failure (401, RevisionNotFound, a refused record) is logged, and the dispatch and tag alerts go ahead without record alerts. - The summary: an empty release list adds no section, and the list is split into sections of at most 3,000 characters, within 50 blocks. - Escaping: published_at, tag names and the repository are escaped for Slack's formatted text (slackEscape). - Logged, not posted: a deleted record, a change of default release and an un-withdrawal (unannouncedRecordChanges). - The token: huggingFaceToken is required, and resolved by huggingFaceReadToken, the rule the dashboard's other Hugging Face reads now share. - Docs: "on both sides", only new-build messages carry a time, the retry and the 503. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Brings in microcosm-releases-json-readers at d06face: the current build's read failure in the latest-release message, and the store's required upload method. No conflicts. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Bug: a failure while the body of releases.json is read (the headers arrived) counts as lasting, so the delivery is answered 200 and that update's alerts are lost. It should be transient and answered 503. - When one side fails for a lasting reason and the other transiently, the lasting failure should decide, since a retry cannot help. - A lasting failure should be named in the answer (release_record_problem), unlike a record that did not change. - A release repository whose country has no Slack channel (Belgium) should read no releases.json and never be answered 503. The configuration should list the countries with a channel (releaseAlertCountries). - The summary's "…and N more" branch, which already works, gets a test. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… alerted - The body of a 200 for releases.json is read inside the same try as the request, so a timeout or a dropped connection while it arrives is transient and answered 503, like a failed request. - Both reads are settled before deciding. A lasting failure on either side wins over a transient one on the other, since a retry cannot help, and it is named in the answer as release_record_problem. A record that did not change still answers release_record_alerted: [] alone. - Only release repositories whose country has a Slack channel read releases.json (releaseAlertCountries, from hasReleaseAlertChannel), so only they can be answered 503. Belgium, which has none, never is. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The guide now says that only release repositories with a Slack channel read releases.json, that one webhook serves all five watched datasets, and that a late retry can post after newer messages. Its recovery steps say to replay every delivery answered 503, oldest first and never one answered 200, and how to cover updates made while the webhook was suspended. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…tart Documentation and comments, plus one test simplification: - The recovery steps apply whenever deliveries were answered 503, not only after a suspension, and use the function logs as the record of each answer. The last delivered commit is the newSha of the repository's latest delivery answered 200, after the replays. The hand-made payload adds a refs/tags entry for each tag created meanwhile. A delivery answered with release_record_problem is replayed once its cause is corrected. - The token and the Slack variables are read when the server starts, so a change takes effect with the next Deploy production run. The verification replay also requires an answer without release_record_problem. - The comments on TransientRecordReadError, compareReleaseRecords and releaseAlertCountries mention the body read, that a lasting failure decides, and the read at server start. - The configuration test reads the now-required releaseAlertCountries without "?? []". Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This branch was successfully deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #278
Stacked on #241 (base
microcosm-releases-json-readers), which readsreleases.jsonwith the release writer's rules (releasesRecordFromResponseinrelease-record.ts). This PR's own changes are the diff against that base, which GitHub shows.f8614fe,ce68777,bc72806,a13909c,c4c8ae0,4555362,847b8fb,4bbc59a,20c4ccaand4a93ac3.bdfca47and4e6b89f, are reviewed in Read Microcosm releases from releases.json wherever a repository has it, and from tags otherwise #241.Once #241 merges, change the base to
main.Why
Builds that Microcosm publishes into build folders get no Hugging Face tag. The webhook's Slack release alert has only ever fired for new tags, so these publications would go unannounced. This PR adds alerts from
releases.json. It has to be live before the UK repository switches toreleases.json; until then, UK alerts keep coming from new tags.What changes
When an update to the
mainof a release repository whose country has a Slack channel arrives (the US and the UK; Belgium has none), the webhook first readsreleases.jsonat the update'soldShaandnewSha(onlynewShafor a newmain). It then dispatches the tree publication and posts the tag alerts, as before, and posts one Slack message to the country's channel for each change in the record:New Microcosm UK build `<release>/<build>`: now currentNew Microcosm UK build `<release>/<build>`: published, not current (current stays `<build>`)(or(`<release>` has no current build))Microcosm UK `<release>`: current build changed from `<old>` to `<new>`Microcosm UK build `<release>/<build>` withdrawnreleases.jsondid not exist before the update (Microcosm's switch commit)Microcosm UK now records its releases in `releases.json`: N builds in M releases, then one entry per release with its current buildpublished_at.UKis the country code, so US and Belgian messages read the same way.published_at, a tag's name in tag alerts) are escaped for Slack's formatted text (&,<,>), so none can mention a channel or form a link.releases.jsonon both sides gets none of these messages. Only Hugging Face's 404 for the file counts as no record; a 404 for a missing repository or revision does not.mainupdates are neither dispatched nor alerted until a retry succeeds.mainentry runs from thenewShaof the repository's latest delivery answered 200 to its head, and it has onerefs/tags/<tag>entry, witholdShanull, for each tag created meanwhile. Send one staging payload as well.release_record_problemis replayed once its cause is corrected. That replay repeats any tag alert it carried.release_record_problem, which shows the token can read the UK repository.<build>" may be out of date.console.error), and the answer names it asrelease_record_problem, so Hugging Face's activity page tells it apart from "nothing changed" (release_record_alerted: []alone).releases.json, a change ofdefault, and a build that is no longer withdrawn are logged as warnings (console.warn), and nothing is posted.releases.json.releases.json(amainupdate of a release repository whose country has a Slack channel, so not Belgium's), its JSON answer addsrelease_record_alerted, describing each alert it posted, andrelease_record_problemafter a lasting failure. Any other delivery, including a Belgianmainupdate, answers exactly as before.Code:
lib/microcosm/release-record-alerts.ts: the comparison.lib/slack.ts:releaseRecordAlertPayloadandpostReleaseRecordAlert. The tag alert shares their posting and context code, and its payload is unchanged.lib/microcosm/hf-webhook-handler.ts: the two reads and the posting.hf-webhook-config.ts:huggingFaceTokenandreleaseAlertCountries, both required and both read when the server starts. A change toHF_TOKENor to aSLACK_WEBHOOK_POPULACE_*variable takes effect only with the nextDeploy productionrun.huggingFaceTokenis resolved byhuggingFaceReadToken, new inlatest-artifact.ts:HF_TOKEN, elseHUGGINGFACE_TOKEN, as set, and an empty value sends no token.latest-artifact.tscalls the function. Three modules keep their own copies of the same rule, all already onmain:publish-calibration-tree.ts,calibration-release-locator.tsandstaging-artifact.ts.4555362's commit message says the other readers "now share" it; that overstates it.route.tsresolves it there by design). So a new token takes a redeploy, as a newHF_WEBHOOK_SECRETdoes.docs/calibration-tree-artifacts.md("Slack release alerts", and the replay advice) andfrontend/HOSTED_RUNTIME.md(Hugging Face reads).Decided by Anthony on 2026-11-04
releases.json;Still with Anthony, unchanged here: the summary's wording, the "published, not current (
<release>has no current build)" variant and "current build changed from none to<build>" are mine and await his agreement. The Vercel checks onHF_TOKENare also his.Known limit, left for later (review round 1, quality 2): the webhook compares only the two ends of an update. A delivery that carries several commits reports their net change. For example, a build published and then withdrawn within one push is announced as "published, not current", with no withdrawal. A build published as not current while another became current says "current stays
<build>" before the separate change message. Microcosm's release writer pushes one commit per change through the Hub API, so this needs a push of several commits.Environment variables
This PR adds one new read of an existing variable: the webhook now reads
HF_TOKEN(orHUGGINGFACE_TOKEN). It adds no new variable and changes no workflow or deployment file. None of the Vercel project settings could be inspected from here, so each of the four is unverified:SLACK_WEBHOOK_POPULACE_UKlib/slack.ts, at runtime, for UK alerts (tag andreleases.json); also, new here,hf-webhook-config.tsat server start, to decide whether the UK release repository'sreleases.jsonis readprocess.envwhen an alert is posted, and once at server start (hasReleaseAlertChannel).HOSTED_RUNTIME.mdlists it among the Vercel Production settings (names listed on 2026-10-26). If it were unset, the UK would read no record and get no record alerts.SLACK_WEBHOOK_POPULACE_USHF_WEBHOOK_SECREThf-webhook-config.ts, at server start, to authenticate deliveriesHF_TOKEN(orHUGGINGFACE_TOKEN)hf-webhook-config.ts, at server start (new here), to readreleases.jsonof the private UK repositorydeploy.ymlpasses the repository Actions secretHF_RELEASE_READ_TOKEN(it exists) todeploy-dashboard.sh, which sets it withvercel deploy --env HF_TOKEN=…on production deployments. The Vercel project also stores its own ProductionHF_TOKEN; which value a deployment uses, and whether the token can read the UK repository, are not verified. Previews use the Vercel PreviewHF_TOKEN.Belgium has no Slack webhook variable, so it gets no alerts, as before. If
HF_TOKENcannot read the UK repository (401), every UK update logs a failedreleases.jsonread and posts noreleases.jsonalert. That failure is lasting, so it is not retried, and tag alerts and the dispatch are unaffected.Tests
Only the tests this PR adds or changes were run locally, each selected by exact name:
bun test <file> -t "^(<names>)$". That covers the webhook route tests whose shared helper this PR changes. CI runs the rest. All repositories, records and the Slack incoming webhook address are synthetic; nothing is sent to Slack or read from Hugging Face.f8614feTest Slack release alerts from changes to releases.jsonapp/api/hf-webhook/route.test.ts, 20 selected: the 10 new alert tests failed on their assertions (noreleases.jsonread and no message posted). The 9 existing dispatch tests and "a staging repository's main update reads no releases.json" passed.lib/microcosm/hf-webhook-config.test.ts"reads the Hugging Face token for releases.json alerts from HF_TOKEN, or else HUGGINGFACE_TOKEN" failed ontoBe. The new tests didn't type-check at red: they pass the newhuggingFaceTokensetting.ce68777Post Slack release alerts from changes to releases.jsonbc72806/a13909cAnswer a delivery without a main update as beforece68777failed two existing tests inlib/microcosm/reviewed-repository-import.test.ts: a tag delivery's answer gained an emptyrelease_record_alerted. The new route test "a delivery without a main update answers as before, naming no releases.json alerts" failed ontoEqual. "a main update's answer lists the releases.json alerts it posted" passed: it guards the main-update answer.bdfca47Merge #241's review round 1 fixes (no conflicts)c4c8ae0Test review round 1's fixes to the releases.json alerts4555362Retry transient releases.json failures, escape Slack text, log silent changesc4c8ae0)4e6b89fMerge #241's review round 2 fixes (no conflicts)bun run lintclean847b8fbTest review round 2's points4bbc59aRetry body failures, let lasting failures decide, and read only where alerted20c4ccaThe guide: the 503's scope and the recovery steps4a93ac3Review round 3: the recovery steps' open cases, what is read at server start, and the verification check?? []on the now-required field)bun run lintcleanThe existing dispatch tests' helper answers
releases.jsonwith Hugging Face's "entry not found" 404 before their own fetch, so their GitHub call counts are unchanged. The configuration's helper in the route test gainshuggingFaceToken: undefined, because the field is now required (a type change only, in4555362).The 7 failures at
c4c8ae0:lib/microcosm/release-record-alerts.test.ts:toBeGreaterThan);toBeLessThanOrEqual);toContain);toContain).app/api/hf-webhook/route.test.ts:toBe: 200);toContain).lib/microcosm/hf-webhook-config.test.ts: "reads the Hugging Face token for releases.json alerts as the dashboard's other readers do: HF_TOKEN, else HUGGINGFACE_TOKEN" (toBe). It replaces the token test fromf8614fe, which expected trimming.The 5 failures at
847b8fb, all inapp/api/hf-webhook/route.test.tsexcept the last:toBe: 200 instead of 503, the review's bug);toBe: 503);toContain);toBe: 503);lib/microcosm/hf-webhook-config.test.ts"reads releases.json only for the countries whose Slack channel is configured" (toEqual).The 2 that passed: the summary's "…and N more" branch (2,000 releases, in
release-record-alerts.test.ts), and "a delivery without a main update answers as before, naming no releases.json alerts", rerun to check the answer's content still holds.The 8 that passed guard behaviour that already held:
release-record-alerts.test.ts: several alerts in one update and their order; a new release; "from none"; an unchanged or absent record;RevisionNotFound, 401) with the dispatch and tag alert going ahead. This replaces the earlier "cannot be read" test, whose 503 case is now the transient test;nulloldSha;Authorizationheader.bun run lint(tsc --noEmitfor the app and the package) is clean.🤖 Generated with Claude Code