Conversation
Re-records the label-set decision from QuantEcon/meta#324 as a worked Standard-type QEP, per QEP-1's rollout. Defines the standard label set (18 core + 2 lecture), the labelling policy, and the one behavioural change (retire status labels in favour of native GitHub PR lifecycle). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Apply the final decisions from QuantEcon/meta#324: - infrastructure split approved (no longer flagged open) - Q2 rollout is a staged pilot on lecture-python-programming, then wider - add the separate `qe gh labels prune` step (one-by-one review) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
Thanks @mmcky , looking forward to having a consistent set of labels. |
|
Ran a pre-finalisation audit of this draft (fidelity to meta#324, label gaps, automation coverage, colour/template consistency, source-of-truth). Full write-up and checklist in #3. Verdict: QEP-2 is a faithful, complete, template-conformant capture of the #324 decisions — nothing dropped or over-claimed, counts correct. A handful of fixes to settle before it goes up for decision:
Plus two live emitter bugs to fix at rollout (the "automation writes label names that don't exist" problem this QEP is about): |
…gent Address the PR review's must-fixes and cheap hardening. - stamp.mjs (#1): detect a merge commit and diff against the first parent (`git diff --name-only HEAD^1 HEAD`) instead of `git diff-tree -r HEAD`, which prints nothing for a merge and would make stamping silently no-op if a QEP PR is merged as a merge commit rather than squashed. Verified on synthetic merge and squash commits. - check.mjs (#2, #5): a new QEP must start unversioned (v0); a versioned QEP may not drop its version field (once versioned, stays versioned). Distinguishes a brand-new file from a v0 file via a base-existence check. - check.mjs (#3): validate that type/status are known enum values. - check.mjs (#8): tolerate a hand-typed ASCII "-" or empty README Version cell for a v0 QEP (stamp.mjs normalises it to the en dash post-merge), so the cell no longer blocks the PR with a visually identical-looking parity error. - stamp-version.yml (#6b): push explicitly with `git push origin HEAD:main`. - QEP-1 + AGENTS.md (#7): the site uses book-theme today, so make the type/version pills and git-history-dropdown claims contingent on the QuantEcon theme; lead with the always-true README columns. Describe the strengthened PR checks. All eight check.mjs scenarios pass in an isolated synthetic repo; check.mjs passes on the real tree. Stays at v1 (no normative rule changed). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Adds QEP-2 as a new draft proposal documenting QuantEcon’s standard GitHub label set and labeling policy, and registers it in the repository-wide QEP index.
Changes:
- Add new QEP document: QEP-2: Standard GitHub Label Set and Labelling Policy (draft).
- Update the README QEP index to include QEP-2 with status Draft.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
| README.md | Adds QEP-2 to the QEP registry table with status “Draft”. |
| qeps/qep-0002-standard-github-labels.md | Introduces the QEP-2 draft defining the standard label set and labeling policy. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Field report: applied the draft set to
|
Present in actions |
QEP-2 disposition |
|---|---|
high priority (space) |
rename → high-priority |
in-work, ready, blocked |
retire per the status-label change |
editor |
lecture-extension label sitting in a tooling repo — prune candidate |
security, testing |
non-standard; see above |
infrastructure |
created today at #006b75 per this draft |
We used the spaced high priority as-is rather than pre-empting the rename, so actions is a clean test case for the sync tool when you get to it.
One wording suggestion
The infrastructure vs maintenance boundary is the call I expect people to get wrong most often, and the current test — "engineering a teammate should know shipped" vs "invisible churn a reader never sees" — took me a couple of passes to apply confidently, because both are invisible to a lecture reader. The maintenance row's parenthetical ("rendered lectures look identical after") is the sharper test but it's phrased for lecture repos and doesn't transfer to tooling repos. Something like "would this appear in a release note?" might carry better across both.
On the placeholder #006b75 for infrastructure: it reads fine next to the new documentation tan and is far enough from the discuss pink. No objection from me.
…se type Resolves the README index conflict by taking main's five-column table and adding the QEP-2 row, and normalises QEP-2's frontmatter/body type to lowercase `standard` per the enum introduced by the QEP-1 v1 CI checks. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…rce of truth From the QuantEcon/actions field report and follow-up discussion: - Add `security` as a cross-cutting non-Type modifier (like priority): one Type label per issue, plus optionally security. 19 core + 2 lecture = 21. Recorded the Type-label / repo-local alternatives. - Settle the `infrastructure` colour: #1d3c78 (the #006b75 placeholder clashed with the `help wanted` teal). - Sharpen the infrastructure/maintenance boundary with a repo-agnostic test: would it appear in a release note? - Add `testing` to the deliberately-unlabelled list; add the `high priority` -> `high-priority` rename example. - Ship the normative schema as a co-located machine-readable appendix (qep-0002-labels.yml) — the source of truth tooling consumes, versioned with the QEP per QEP-1's substantive-amendment rule. The yml carries only the standard itself; rename/prune knowledge stays in the CLI. - CI: check-labels.mjs keeps the tables and the yml in lockstep and requires a version bump when an Accepted QEP's appendix changes. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
Reviewed the
PR description refreshed to match. Remaining before decision: none from the field report — the draft is back to wording-polish territory. |
The Summary described the behavioural change as moving only in-work/ready/review off labels; align it with the retire-table, which also covers blocked/on-hold via native issue dependencies. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Automation labels: the policy describes one kind of bot label, but we have twoContinuing the field report from applying this draft — this one surfaced from wiring the set into The two kindsDiagnostics — what the automation found. Origin labels — which automation produced it, existing because a downstream consumer queries on it. "Carries "Exactly one" is also wrong for diagnosticsSeparate from the origin-label gap, the quantifier doesn't hold. Our weekly status-report issues diagnose nothing — they are routine scheduled output, not a failure report. Under "exactly one diagnostic" they would have to carry Suggested replacement for the automation policy bullet
The "only where a documented consumer queries on it" clause is the load-bearing part. It is the justification bar that stops the namespace re-growing one label per action, which is the concern that put bot behaviour into a separate QEP in the first place — and unlike a style rule it is testable, because you can point at the query. Both current cases pass: Worth pre-empting one objection: an origin label looks like a grouping label, which What we deliberately don't label sends to Milestones. It isn't — it is a routing key an automation queries on a schedule, and a Milestone would have to be created afresh each period and cannot be filtered the same way through the issues API. Colour: one rule, no recolouringThe draft says the automation family "shares a quiet grey (a machine made this)", but that claim is contradicted inside the document — the Meta labels are grey too, and Since Where origin labels get registeredKeep What this buys, concretelyIt gives |
… defer to QEP-4 From the reports-activity field report and the namespace design discussion on the PR: the diagnostic quantifier becomes at most one (routine scheduled output diagnoses nothing); registered automations carry a durable origin label and may use transient /-namespaced task labels, legislated in QEP-4 rather than enumerated here; the grey colour claim is amended (grey = low-salience state, automation vs meta distinguished by text) with a band allocation rule; prune skips registered zones by rule. Records the retired closed-vocabulary rule in Alternatives. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Where the automation-label discussion landedFollowing up the comment above — we workshopped the policy and landed on a registrar model rather than per-label registration. Summary of the outcome (QEP-2 amended in 392b279; the registry and coordination policy are drafted as QEP-4, #8):
Ideas considered and set aside, with reasons recorded in QEP-4's Alternatives: a shared org prefix ( |
…, CI parity The header table's Related row is the primary human record (with the why); related: [N] in frontmatter is its machine mirror. check.mjs enforces lockstep (one without the other, differing sets, or a self-reference fails); a related QEP missing from the branch only warns, since in-flight drafts reference each other across branches. Editing related is editorial. Inline links remain the normative mechanism; no MyST admonitions, which don't render on github.com. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…nd allocation ambiguity Rollout step 5 predated the security modifier's addition to the core set. The band rule now says 'unused by any label', since duplicate's #cfd3d7 sits numerically inside #ededed–#bdbdbd. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The description field is machine-consumed — qe gh labels sync writes it to every repo adopting the core set, including tooling repos and the org default — so bug / enhancement / documentation lose their lecture wording and the lecture guidance moves to the human-only When-to-use column. build-failure drops 'Notebook' from the description, and its When-to-use now states the boundary: scheduled checks label the issues they open; a failing check on a PR carries no label (the red ✗ is the signal). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Cross-QEP process pivot: the QEP that creates a dependency ships the amendments to the standards it touches, in its own PR (QEP-1's amend-in-place model). QEP-2 therefore carries no forward references to the in-flight automation-registry QEP: the Related pairing, the origin/task-label sentences, the prune skip-rule, and the grey-band registration clause come back as amendments in that QEP's landing PR, in whatever form its review settles. Until then main never holds a dangling link, and this standard asserts nothing still under review elsewhere. The removed wording is preserved verbatim on the qep-0004 branch. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Field report: applying QEP-2 to a real triage passI applied this schema while triaging ~92 findings from a validation audit of one of our documentation repos into a set of ~13 issues. Everything below came out of friction hit in practice rather than review-by-reading. Item 3 now proposes one addition to the label set; the rest is scope and wording, plus two confirmations that rules earn their keep. 1.
|
| Query | Result |
|---|---|
repo:… is:issue is:open |
29 |
repo:… is:issue is:open has:sub-issue |
29 |
repo:… is:issue is:open has:banana |
29 |
The nonsense qualifier returns the same count, so has:sub-issue is being silently ignored rather than honoured. parent-issue: and sub-issue-of: also returned nothing. So there is no way to answer "show me every active workstream across the org" without a label. (Tested on REST search; GraphQL or the web UI may behave differently — worth a second check before relying on this.)
Why workflow rather than Type. The Type group answers "what kind of work is this?" and keeps its members mutually exclusive on purpose. A tracking issue isn't a kind of work, it's structure. The workflow group is the right home, and do-not-merge is the precedent: it survives the cull precisely because GitHub has approvals but no native "approved yet must be held" state. tracking has the same shape — native sub-issues cover the relationship, but not discovery. That also keeps this consistent with the QEP's headline change rather than contradicting it: status labels were retired because native features took over; this is added because a native feature does not cover the need.
| Field | Value |
|---|---|
| name | tracking |
| group | workflow |
| scope | core |
| description | Umbrella issue grouping related work; carries no Type |
Paired with one policy line, since the label alone doesn't resolve the original ambiguity: a tracking issue is a sub-issue parent, carries tracking instead of a Type, and is exempt from the one-Type rule.
The honest counter-argument. It duplicates state the platform already holds, so it can drift — someone labels an issue with no children, or builds a sub-issue tree and forgets the label. do-not-merge carries identical drift risk and this QEP accepts it, so I don't think that's disqualifying, but it is real. And if GitHub ships a working has:sub-issue qualifier, this label becomes redundant the way the status labels did. Worth marking it provisional in the text so a future amendment can retire it without looking like a reversal.
4. security doesn't say when to escalate off-issue
Our audit turned up a credential published in a repo. The label correctly signals a different review bar, but for a live exposure the right vehicle may be a private security advisory rather than a labelled issue that notifies watchers and sits in a public queue.
Suggest distinguishing the two cases: security is for security-relevant work (hardening, permissions, review-bar changes), whereas an actual secret exposure or vulnerability goes through private reporting first and gets an issue only once it is safe to file one.
5. Confirmation: applied-by: bot earned its keep
I reached for broken-links for an issue covering 19 dead URLs found by a link checker, and the bot-only rule correctly stopped me and sent it to maintenance. That distinction — the label describes what automation found, not what a human noticed — is the kind of rule that reads as overhead until it prevents a mislabel. It held up in practice; worth keeping exactly as specified.
6. Confirmation: the native replacements for the retired status labels are available today
The "one behavioural change" depends on GitHub features that are actually reachable. Verified on one of our repos via the REST API: both /issues/{n}/sub_issues and /issues/{n}/dependencies/blocked_by respond, and I used both in anger — twelve sub-issues attached to one parent, and two real "Blocked by #N" dependencies in place of a blocked label. So Draft PRs, review requests, sub-issues and dependencies can all carry the load that in-work / ready / review / blocked used to, and retiring those labels is implementable now rather than aspirational.
The caveat from item 3 applies here too: the relationships work, but only sub-issue creation and retrieval — not search.
Happy to fold any of 1-4 into the PR as a suggested diff if that is easier than discussing in-thread.
Three policy-prose clarifications from applying the draft to a real 92-finding triage pass (see the field report on #2); no yml changes, set stays 19 core + 2 lecture: - infrastructure vs maintenance: state the axis explicitly - the boundary is effort, not subject (release-note test decides). - documentation: generalise the lecture rule - product content is never documentation, even where the product is docs; defects and gaps take bug / maintenance / enhancement. - sub-issue parents: structure, not work - exempt from the one-Type rule and not "needs triage" when unlabelled. No tracking label: has:sub-issue works in the advanced issue search org-wide, so discovery is native; legacy REST search caveat noted for tooling. security stays a single broad cross-cutting modifier (no escalation carve-out - incident practice is out of scope for a label spec). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
Reviewed the triage-pass field report; all six items settled, draft revised in 27f1a84.
No |
…tracking issue The sequenced checklist (CLI integration, pilot target, widening order, org defaults, closing meta#178 / meta#290) goes stale as steps complete and would force no-op amendments of an accepted standard. It moves to a tracking issue opened at acceptance - a sub-issue parent, dogfooding the new umbrella-issue policy. Rollout keeps the durable content: additive history-preserving sync from the co-located appendix, one-by-one prune, pilot-first ordering, core-19 org default. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
Two phrases read as claims about future events (that the CLI tool is the implementation; that a tracking issue is opened at acceptance). Recast as conditional obligations so nothing in the section can be falsified by work not happening: applying the set reads the appendix from this repo and is additive; the execution checklist belongs in a tracking issue rather than this document. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Adoption names what accepting a QEP requires - mechanism, tooling, and the guarantees any implementation must honour - as obligations rather than a plan, so nothing in the section can be falsified by work not happening. Sequenced execution (who does what, when) belongs in a tracking issue, per the convention QEP-2 established. Renames the heading in template.md (with matching guidance text), QEP-1's format rule and its own section (adding the (v2) entry to its adoption record), and QEP-2; bumps QEP-1 to version 2 and syncs the README index. version-hash restamps at merge. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
Drop the fourth-attempt narrative, the discovered-mismatch anecdote, and the closing paragraph justifying use of the QEP process itself - the QEP process is assumed. Motivation now states the drift and the three things one standard set fixes: consistent triage, a stable label contract for automation, and shared cross-repo workflow. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Promote the core point to its own dot point - one label, one meaning, org-wide - absorbing the cross-repo workflow examples; Triage and Automation stay single-purpose. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Same square-sharing precedent as the four automation greys under ⬜; the hex is the definition, the emoji only the family. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Previously fully carved out under Not touched, which left a hole in the org-wide standing queries (security, discuss, question) exactly where their traffic is heaviest. The additive sync plus the bespoke prune allowance already make inclusion safe: project / education survive like jax-conversion and reading-group-* do elsewhere. A meta-specific extension was considered and rejected - a profile of one repo standardises single-repo vocabulary at QEP amendment cost. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Each entry now states only why the rejected option loses; approval citations, draft-evolution narrative, and field-test attributions move to git history and the PR thread where they already live. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Summary drops the adoption-mechanics clause (Scope and Adoption carry the additive/history guarantee in full); the colour intro loses the CLI-speak 'profile' and a mid-list grammar wobble; rewrap debris from successive edits tidied in the don't-label list, the security alternative, and the Adoption paragraphs. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
@jstac I am finally happy with this QEP. When you get a chance you do a final pass and then approve -- then I'll merge. Note: This PR includes a minor adjustment to QEP-1 which moves the template from |
Field report: QEP-2 applied to a 19-issue technical-debt milestoneApplied the draft set to the remediation plan from a technical-debt audit of 1. No Type label fits a semantics-preserving source refactor. Five of the nineteen are multi-day architectural refactors: extract a testable seam from a 1,314-LOC entry point, introduce a write-path choke point, consolidate six copies of an API client. None of the three candidate Types fits. Suggest a clarifying line in the When to use column rather than a new label — something like " 2. Priority re-centres inside a Milestone. I ended up marking 5 of 19 Confirmed: grouping → Milestones held up well. The milestone replaced what would otherwise have been a For the sync tool: this repo's pre-existing |
…r-preserving restructuring Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…he scale Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
Resolution of the field report — landed in f865f26, 5758c91, 16754a5:
|
Field report: QEP-2 applied to a whole tracker (52 open issues)Third field application, and the first to a complete tracker rather than a milestone or an audit slice — a full triage pass over 1. Retiring
Each is deliberately parked, not neglected, and a reader cannot tell. I don't think the answer is re-adding 2. Native dependencies are binary; much real sequencing isn't. I recorded one issue as blocked-by another and reverted it within minutes — the true relation was "should ideally follow, but can run first with a caveat in the report", and a hard dependency renders in the UI as a blocker, which overstates it. Suggest one clause: use dependencies for hard blocks only; soft ordering belongs to sub-issue order or the parent's body. 3. Additive adoption makes "unlabelled = needs triage" unreadable mid-migration. After typing every issue I could, exactly six were left unlabelled: three are legitimate sub-issue parents (correctly exempt, and the policy says so), and three are 4. Minor: the sub-issue-parent exemption is subtractive. One parent here carries two pre-existing Type labels. It now has native sub-issues, so it should carry none — but conforming means removing labels, and Adoption defers removal to the separate prune pass. Worth permitting label removal at triage time as the one subtractive operation, or noting that pre-existing parents conform only after the prune. Confirmed, with a number. Priority-as-outliers works at repo scale: 3 of 52 = 6% |
Field report — applying the draft set to
|
QEP-2: Standard GitHub Label Set and Labelling Policy
Status: Draft · Type: standard · Discussion: QuantEcon/meta#324
This is the DRAFT of QEP-2, re-recording the label-set decision from QuantEcon/meta#324 as a worked
Standard-type QEP — step 2 of QEP-1's rollout. It's opened as a draft so we can keep iterating on the wording before it goes up for a decision; the substantive calls in #324 are all settled, and the draft has since been revised from field testing (see below).What it defines
new-lecture,editor) = 21, with standard names, colours, and descriptions. The core 19 also becomes the org-level default for new repos.security); unlabelled = needs-triage/normal-priority (and the clarification that "no labels" ≠ "no priority label"); priority is a heat-scale that marks only outliers;questionvsdiscussand adiscussclosing convention; automation labels are bot-applied.in-work/ready/review/blocked) in favour of native GitHub (Draft PRs, "Ready for review", review requests, issue dependencies). Onlydo-not-mergesurvives.qeps/qep-0002-labels.yml, the single source of truth that tooling consumes, versioned with the QEP.mainatomically, never as dangling links. The CI plumbing still ships here:check.mjskeepsrelated:frontmatter and the Related header row in lockstep (used when QEP-4: Automation Registry and Label Coordination (Draft) #8 lands), andcheck-labels.mjsenforces table↔yml parity for anyqep-NNNN-*.ymlcompanion plus the post-acceptance version bump.Decisions from #324, folded into this draft
infrastructuremaintenancediscuss(@jstac)#f904a0, split cleanly fromquestiondocumentation(@xuanguang-li)#b08968, off the blue "new content" familygood first issue/help wantedspacing (@longye-tian)blocked?lecture-python-programmingfirst, then roll out more widelydiscussexit)qe gh labels syncadditive; a separateqe gh labels prunereviews non-standard labels one-by-oneRevisions from field testing (
QuantEcon/actions)We applied the draft set to a full maintenance audit of
QuantEcon/actions(#103–#110); the field report is in the comments below. Theinfrastructure/maintenancesplit and the "grouping labels → Milestones" rule both held up well; the following revisions came out of the report, the follow-up review, and reviewer feedback on the draft:securitysecurity(e.g.bug+security+high-priority). Makesorg:QuantEcon label:securitya standing query and signals a different review bar. Type-level and repo-local alternatives are recorded in the QEPinfrastructurecolour#1d3c78— the placeholder#006b75clashed with thehelp wantedtealinfrastructurevsmaintenancetestinginfrastructureormaintenanceqep-0002-labels.yml; a change to it is a substantive amendment (bumpsversion) per QEP-1. CI (check-labels.mjs) fails any PR where the tables and the yml disagree, and requires the version bump once the QEP is Accepted.QuantEcon/clireads the yml from this repo and carries no copyhigh priority→high-priorityadded as a sync example. Alias/variant/prune knowledge deliberately stays in the CLI — the yml records only the standard itself/-namespaced task labels) are spun out to QEP-4 (#8), which amends QEP-2 with the registry hooks when accepted — see Cross-QEP process above. Grey = low-salience state, with a#ededed–#bdbdbdband allocation ruledescriptionis machine-synced to every adopting repo (incl. tooling repos and the org default), sobug/enhancement/documentationdrop their lecture wording — the lecture guidance moves to the human-only When to use column.build-failureis scoped while we're at it: scheduled checks label the issues they open; a failing check on a PR carries no label (the red ✗ is the signal)Notes
QuantEcon/cli'slabels.ymlis retired rather than updated — the sync tool readsqep-0002-labels.ymlfrom this repository.qep-candidate(meta-only) label is deliberately out of scope here — he flagged it for #325, not this rollout.Decision
No formal deadline window — #324 already reached consensus by its 17 June deadline, so this is largely a formalisation. The author will circulate the draft to the team by email for a final look before it moves out of Draft.
🤖 Generated with Claude Code