Uh oh!
There was an error while loading. Please reload this page.
feat(pm): add --reconcile to ensure-pm-labels, aligning drifted label objects with the wordbook - #10193
Merged
Merged
Conversation
… objects Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019T1sSZbQTnLhrK9HhNdNiB
qq9340100
marked this pull request as ready for review
August 20, 2026 13:35
qq9340100
enabled auto-merge
August 20, 2026 13:35
Uh oh!
There was an error while loading. Please reload this page.
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 freeto 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#10117
Adds an explicit
--reconcilemode toscripts/pm/ensure-pm-labels.sh, and carries the one-time per-repo reconciliation command list the maintainer runs to discharge the currently-measured drift.The change
The default stays create-only. A no-flag run creates the labels this file names where they are absent and leaves every existing label object completely alone — the script's deliberate safety posture, stated in its own comments, preserved byte-for-byte. Verified, not asserted: the 20
gh label createlines are untouched by this diff (git diffshows zero changed vocabulary lines), and a fake-ghcapture of a default run produces a call sequence identical to the one captured from the pre-change script.--reconcilealigns colour and description of the labels the file names, whether or not they already matched. It never deletes a label, never renames one (it never passes--name), and never touches a label the file does not name — retired lane objects and repo-local labels are left exactly as they are. Re-running changes nothing the second time.Why the mode is a shim over the existing lines rather than a second table
Every label is still written once, in the ordinary
gh label create NAME -R REPO -c COLOUR -d "DESCRIPTION"form. A shell function shadowsghand, in reconcile mode, follows each create with the equivalentgh label edit. Two consequences, both load-bearing:check:pm-label-desc-cap— which measures the-dtext on those create lines — bounds the edited description too. This is what makes the grading note's premise (the desc-cap gate already covers edits) true rather than assumed. A separately-written edit table would drift from the create table and would be measured by nothing.Two failure-shape decisions worth review:
--reconsilethat fell through to the default would print the ordinary success line, and the operator would read a reconciliation that never happened as done.|| trueis mandatory for rerunnability, but the same silence on an edit would report success while leaving the drift live — the exact failure this mode exists to end. Edit stderr is captured rather than inherited, because the call sites send create stderr to/dev/null.What the measurement actually found
The card named three drifted labels. Measuring every vocabulary label the script names, on the two repos this session can read, found the drift is close to total:
objectstack-ai/objectstack: all 21 labels differ. 19 are GitHub's default grey with an empty description — they were auto-created by first application and the create-only script has been a no-op on them ever since. The two exceptions arepriority:p0(correct colour, and the reversed description the card reported) andpm:seat(correct colour, older wording).objectstack-ai/objectui: all 11 differ. 9 grey-and-empty includingpriority:p0, plustarget:v17carrying a hand-written 2026-08-04 description — andpm:retriageandpm:epicdo not exist there at all, which no amount of reconciling fixes but which the same run creates.The card's framing was that drift is structurally permanent; the measurement says the create-only path has in practice never applied a colour or description to either repo. That strengthens the case for the mode rather than changing it.
One comment in the script was measurably false and is corrected here: the
needs:contract-reviewblock claimed its description "matches the live label object". That object is grey with an empty description, so the claim had never been true — nothing had ever checked it.priority:p0's wordbook entry was checked against the state machine before propagating it, per the dispatch's standing instruction to stop rather than propagate a wrong entry:SKILL.mdline 86 reads插队:可超 batch、破轮次立即派发;⛔ 不豁免同文件串行与认领协议— ordering, explicitly not an exemption. The wordbook is right and the live object is the reversed one. No wordbook entry was found wrong.Reconciliation command list (the one-time PM action)
Recommended — one command, all four repos, discharges every drift below including the two repos this session could not read:
It prints one
↻ LABEL @ REPOline per aligned label and exits non-zero if any edit fails.objectstack-ai/cloudandobjectstack-ai/objectoswere NOT measured. This session's GitHub access is limited toobjectstackandobjectui(Access denied: repository "objectstack-ai/cloud" is not configured for this session), so their live label state is unknown to me. Thegh label editlines given for them below are the wordbook's desired state, which is idempotent regardless of current values — but the drift columns that exist for the other two repos honestly cannot be filled in for these.The per-repo explicit form follows, for auditing exactly what
--reconcilewill change before running it. Note thegh label editlines only align labels that already exist; where a label is absent (objectui'spm:retriageandpm:epic) the script's create path is what supplies it, which is another reason to prefer the single command above.objectstack-ai/objectstack— 21 labels (drift measured this session)pm:queueedededpm:dispatchededededneeds-user-decisionedededpm:on-holdedededpm:blockededededpriority:p0B60205Critical: blocker, must ship before MVPpm:blockingedededpm:retriageedededfindingedededpm:epicedededneeds:contract-reviewedededrepo:objectuiedededrepo:cloudedededpm:seat1d76dbPM seat registry issue - single-writer body, index = this …domain:engineedededdomain:servicesedededdomain:devxedededdomain:specedededdomain:cliedededdomain:skillsedededtarget:v17ededed21 of 21 rows differ from the wordbook.
Explicit
gh label editequivalents (21 commands):objectstack-ai/objectui— 11 labels (drift measured this session)pm:queueedededpm:dispatchededededneeds-user-decisionedededpm:on-holdedededpm:blockededededpriority:p0edededpm:blockingedededpm:retriagefindingedededpm:epictarget:v17edededv17 发布窗口工作集(GA 前排查 2026-08-04)11 of 11 rows differ from the wordbook.
Explicit
gh label editequivalents (11 commands):objectstack-ai/cloud— 11 labels (drift NOT measured — see note above)Explicit
gh label editequivalents (11 commands):objectstack-ai/objectos— 10 labels (drift NOT measured — see note above)Explicit
gh label editequivalents (10 commands):Verification
Gates re-derived from the actual diff with
node scripts/pm/dispatch-gates.mjs(no paths passed — it takes its own changeset from the merge base); the derived set matched the dispatch clue exactly, no additions. All run at final commitd47fba7, each throughscripts/pm/os-verify-lock.sh:pnpm check:pm-label-desc-cap—✓ check-label-desc-cap --self-test: all cases passed, then✓ check:pm-label-desc-cap: 16 label descriptions in scripts/pm/ensure-pm-labels.sh, all ≤100 characters (longest: 100, repo:objectui).·os-verify-lock: VERDICT command-exit 0pnpm check:cross-package-test-inputsandnode scripts/check-cross-package-test-inputs.mjs—All 60 self-test cases passed./OK: 12 package(s) read outside themselves, all declared, and turbo.json hashes every declared glob.pnpm check:nul-bytes—check-nul-bytes: OK (scanned 6069 text file(s) ...; no raw ASCII control bytes).Plus a direct control-byte scan of both changed files, which matched nothing.New selftest coverage
14 cases were added to
check-label-desc-cap.mjs --self-test, which is the family's CI-wired selftest (lint.yml). They belong there rather than in a new file because the gate's charter is "no description this script sends to GitHub can 422", and reconcile adds a second way to send one: without them the gate would keep passing while silently covering only the create path — the parser-matches-nothing failure the gate was written to prevent, reappearing in a new place. The load-bearing cases assert that reconcile edits exactly the labels it creates with the same name, repo, colour and description; that no verb other than create/edit is ever issued; that no--namereachesgh; and that a second run issues an identical call sequence.Ablation
The new assertions were checked to be capable of failing. Predicted direction before running: red, specifically the edits-match-creates case and the failing-edit case.
Mutation: the
--reconcilearm of the flag parser was changed to set the flag to 0, neutering the mode. Confirmed on disk by grepping for the injected and the deleted text, not by the editor's exit code — the injected form went 0 → 1 occurrences and the deleted form 1 → 0. No build step is involved (both files are read from source at runtime), so there is nodist/leg to rebuild.Ablated result, as predicted:
The restore leg was taken from the commit (
git checkoutof the branch's copy), and confirmed on disk by the same two greps returning to 1 → 0 / 0 → 1, with a cleangit status; the gate was then re-run green on the restored tree. Note the third case, "every description reconcile SENDS is one this gate already measured", stayed green under ablation — vacuously, over an empty edit list. That is why the edits-equal-creates case is the load-bearing one and is stated separately.Scope
skip-changeset: internal PM tooling, nothing user-visible, nothing published.Not addressed here, recorded for triage rather than fixed in this PR: this session could not read
objectstack-ai/cloudorobjectstack-ai/objectos, so their drift is unmeasured; and the reconcile mode aligns only labels the file names, so leftover retired lane objects (domain:ui,domain:spec-surface, and the rest listed in the script header) are deliberately still untouched — deleting those remains the separate PM action the header describes.Generated by Claude Code