Fill the dev board's field values automatically - #1818
Merged
Merged
Conversation
…rift - grant pull-requests: write so addLabel can label PRs (14/17 of writes) - stop routing addLabel (GITHUB_TOKEN) failures through the PROJECT_TOKEN auth-failure reporter - planLabelWrites prefers a human-set Theme field over the keyword guess, and now surfaces unclassifiable/unmapped/conflicting theme labels as drift instead of writing a sticky needs-theme label - widen labels(first: 20) to 100, log a failed dedupe search, drop dead FIELDS[*].id, fix the "N theme labels" wording, and surface a Triage block that resolves a field to nothing as drift
✅ Deploy Preview for afmg ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
This was referenced Sep 9, 2026
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.
You asked whether the dev board could be automated because updating it by hand is a chore. This does the part that is genuinely mechanical, and deliberately does not do the part that isn't.
What it does
A single reconciler runs hourly, reads the whole board, and writes only what is missing:
theme:label.theme:labels are applied to itemstheme-label.ymlnever sees — it fires onissuesanddiscussiononly, which is why pull requests have none.### Triageblock in the issue body, when one is present. Nothing writes one today; that is the hook for the Discord intake bot, where a human moderator picks both values before approving.What it will not do
Nothing is ever guessed, and nothing a human set is ever overwritten. Two invariants, both enforced in code and covered by tests:
theme:labels — it writes nothing and reports it.So an empty cell on the board keeps meaning "nobody has judged this yet", which is only true because nothing writes a guess into it. There is no model and no inference anywhere in this PR.
It also never writes
needs-theme.theme-label.ymlstill applies that at creation, and you can delete it to mean "I looked, nothing fits" — if the reconciler re-applied it, your deletion would be undone within the hour. Items it cannot classify are listed in the run summary instead.Dry run against the board as it stands
118 items → 11 Theme fills, 14 label writes, 4 items reported, 0 Priority/Size writes.
The reported items are #1658, #1805 and #1808 (title and body do not classify — a human call), and #1810, which carries both
theme: ui-editorsandtheme: markers-zones, so it refuses to pick one.The run is idempotent: a second run writes nothing, and a third writes nothing. It converges in two passes because an item that gets a label in run 1 gets its Theme field in run 2.
About the change to
theme-label.ymlThat workflow already had the classifier inline, and the reconciler needs the same logic for pull requests. Rather than keep two copies of a 13-entry keyword table that would drift — and then theme the same item differently depending on which path saw it first — the classifier moves to
scripts/theme-classify.mjsand both import it.The extraction is behaviour-identical, and I checked rather than assuming: the
DROPDOWNandKEYWORDSobjects aredeepStrictEqualto the originals, and running the old inline algorithm against the new one over 109 inputs — 100 real issues from this repo plus 9 adversarial cases (null title, null body, an unmapped dropdown answer,###Themewith no space, a body-only tie, a 5000-character title) — gives 0 mismatches. The scoring threshold is unchanged.The workflow gains an
actions/checkoutstep, which it needs to import the module.Before merging
The secret is already in place — thank you. It reads the
PROJECT_TOKENyou created, and the name in the workflow matches. Recording why it had to be a classic PAT, for whoever reads this later:GITHUB_TOKENcannot write to Projects v2 at all, and because the board is user-owned rather than org-owned, fine-grained PATs and GitHub App tokens do not work either — those cover organization projects only. It needsprojectscope and nothing else; both repos are public, so noreposcope.The cron is live on merge, and the first run makes about 25 writes — most of them labels on merged pull requests, each notifying that PR's subscribers. Worth dispatching it once by hand first:
workflow_dispatchdefaults todry_run: true, which prints the full plan and writes nothing. If the plan looks right, dispatch again withdry_run: false, and the hourly schedule takes it from there.If the token ever lapses, the run stops and opens a single issue saying so, using the workflow's own token rather than the PAT.
If the token ever expires, the run opens a single issue saying so rather than failing quietly. That check is careful to fire only on genuine authentication failures, not on rate limits or transient errors.
Testing
npm run test:scripts— 31 tests under Node's built-in runner, wired intounit-tests.yml. They live outsidesrc/, sovitestdoes not collect them (its root is./src); hence the separate script. No new dependencies — globalfetchandnode:builtins only. The existing 648 unit tests are unaffected.