Skip to content

QEP-2: Standard GitHub Label Set and Labelling Policy#2

Open
mmcky wants to merge 23 commits into
mainfrom
qep-0002
Open

QEP-2: Standard GitHub Label Set and Labelling Policy#2
mmcky wants to merge 23 commits into
mainfrom
qep-0002

Conversation

@mmcky

@mmcky mmcky commented Jun 17, 2026

Copy link
Copy Markdown
Contributor

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

  • The standard label set — 19 core labels (universal) + 2 lecture-extension labels (new-lecture, editor) = 21, with standard names, colours, and descriptions. The core 19 also becomes the org-level default for new repos.
  • The labelling policy — one Type label per issue at triage, plus optional cross-cutting modifiers (priority, security); unlabelled = needs-triage/normal-priority (and the clarification that "no labels" ≠ "no priority label"); priority is a heat-scale that marks only outliers; question vs discuss and a discuss closing convention; automation labels are bot-applied.
  • The one behavioural change — retire the status labels (in-work / ready / review / blocked) in favour of native GitHub (Draft PRs, "Ready for review", review requests, issue dependencies). Only do-not-merge survives.
  • The machine-readable appendix — the normative schema ships as a co-located qeps/qep-0002-labels.yml, the single source of truth that tooling consumes, versioned with the QEP.
  • Cross-QEP process — QEP-2 is fully self-contained: it carries no forward references to the in-review automation-registry QEP. Under the convention adopted in Process: downstream QEPs carry their amendments to upstream standards (QEP-1 amendment, deferred to second instance) #9, QEP-4 (#8) preserves the registry hooks drafted here (Related pairing, origin/task-label policy, prune skip-rule, grey-band registration) and re-applies them by amending QEP-2 in its own acceptance PR — cross-references land on main atomically, never as dangling links. The CI plumbing still ships here: check.mjs keeps related: frontmatter and the Related header row in lockstep (used when QEP-4: Automation Registry and Label Coordination (Draft) #8 lands), and check-labels.mjs enforces table↔yml parity for any qep-NNNN-*.yml companion plus the post-acceptance version bump.

Decisions from #324, folded into this draft

Item Resolution (from #324)
Q1 — infrastructure Approved as a distinct Type label, split from maintenance
Add discuss (@jstac) In — core label, reuses meta's pink #f904a0, split cleanly from question
Recolour documentation (@xuanguang-li) Done — moved to tan #b08968, off the blue "new content" family
good first issue / help wanted spacing (@longye-tian) Keep the spaces — GitHub's Contribute-page algorithm needs the exact names
Add blocked? No — native issue dependencies + Draft/"Blocked by #N" cover it
Q2 — rollout Pilot lecture-python-programming first, then roll out more widely
Q3 — retire status labels Settled — unanimous in the thread
Guide clarifications (@shlff) Folded into the policy section (unlabelled vs no-priority; discuss exit)
Tooling (@mmcky) qe gh labels sync additive; a separate qe gh labels prune reviews non-standard labels one-by-one

Revisions 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. The infrastructure/maintenance split 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:

Change Outcome
security Added as a cross-cutting modifier, like priority: exactly one Type label, plus optionally security (e.g. bug + security + high-priority). Makes org:QuantEcon label:security a standing query and signals a different review bar. Type-level and repo-local alternatives are recorded in the QEP
infrastructure colour Settled at #1d3c78 — the placeholder #006b75 clashed with the help wanted teal
infrastructure vs maintenance The boundary test is now repo-agnostic: would it appear in a release note?
testing Added to the deliberately-not-labelled list — test work reads as infrastructure or maintenance
Source of truth The QEP carries the schema itself as qep-0002-labels.yml; a change to it is a substantive amendment (bumps version) 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/cli reads the yml from this repo and carries no copy
Rename map high priorityhigh-priority added as a sync example. Alias/variant/prune knowledge deliberately stays in the CLI — the yml records only the standard itself
Automation policy Diagnostics are at most one (routine output diagnoses nothing). Coordination labels (origin labels, /-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#bdbdbd band allocation rule
Tier-neutral descriptions description is machine-synced to every adopting repo (incl. tooling repos and the org default), so bug / enhancement / documentation drop their lecture wording — the lecture guidance moves to the human-only When to use column. build-failure is 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

  • With the appendix as source of truth, QuantEcon/cli's labels.yml is retired rather than updated — the sync tool reads qep-0002-labels.yml from this repository.
  • @shlff's optional 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

mmcky and others added 2 commits June 17, 2026 19:40
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>
@jstac

jstac commented Jun 17, 2026

Copy link
Copy Markdown

Thanks @mmcky , looking forward to having a consistent set of labels.

@mmcky

mmcky commented Jun 18, 2026

Copy link
Copy Markdown
Contributor Author

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:

  • infrastructure colour#006b75 is a placeholder and clashes with help wanted teal; proposing #1d3c78 (slate-blue), refine on sight.
  • Scope — add a note that QEP-2 is lecture-focused; software/library labels are a separate QEP (different audience; performance / breaking-change / upstream belong there, not the core).
  • Automation — adopt an origin-tagging rule: bots tag automated + their own name + a diagnostic. Translation → action-translation + sync + automated (keeps the name reporting already routes on). Homes the otherwise-orphaned action-translation label.
  • Source of truth — make the QEP the sole source of truth (a co-located qep-0002-labels.yml); cli references it rather than carrying a duplicate labels.yml. This dissolves the schema-divergence the audit found.
  • Minor: clarify new-lecture under the "one Type label" rule; soften Q2 to "pilot lecture-python-programming, then widen to all lecture-*"; note the grey family is intentionally near-identical; note Dependabot's dependencies-only exemption.

Plus two live emitter bugs to fix at rollout (the "automation writes label names that don't exist" problem this QEP is about): action-check-warnings emits execution/python-warnings (→ automated+build-failure); action-link-checker misses automated. Detail and a checklist in #3.

mmcky added a commit that referenced this pull request Jun 25, 2026
…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>
@mmcky
mmcky marked this pull request as ready for review July 5, 2026 10:11
Copilot AI review requested due to automatic review settings July 5, 2026 10:11

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Comment thread qeps/qep-0002-standard-github-labels.md Outdated
@mmcky

mmcky commented Jul 23, 2026

Copy link
Copy Markdown
Contributor Author

Field report: applied the draft set to QuantEcon/actions today

We ran a full maintenance audit on QuantEcon/actions and filed the results as 7 issues plus a tracker (#103–#110), deliberately labelling them against this draft rather than the repo's existing ad-hoc set. Two things worked well, and one gap showed up that I think is worth a decision before this moves out of Draft.

What worked. The infrastructure / maintenance split (Q1) earned its keep immediately. Five of the eight issues are CI/build/deploy engineering — repairing the container publish pipeline, unifying the container smoke tests — and calling those maintenance would have been actively misleading; they are exactly the "engineering a teammate should know shipped" case the QEP describes. Without the split I'd have reached for maintenance and undersold them.

The "project / grouping labels → Milestones" rule also settled a question cleanly. My instinct was to mint an audit label to group the batch; the QEP says don't, so we used a Maintenance audit 2026-07 milestone instead. That's better — it gives a burndown, and it self-retires rather than accumulating one dead label per audit. Worth keeping that line prominent, since "just add a label for this batch" is the natural reflex.

The gap: no security label in the core 18

This is the one I'd like reconsidered. QuantEcon/actions currently has a local security label (#ee0701, "Security hardening"), and it is load-bearing there — the repo handles NETLIFY_AUTH_TOKEN / CLOUDFLARE_API_TOKEN and publishes the @v0 tag that every lecture repo consumes, so a supply-chain problem there is an org-wide problem.

The audit turned up two findings that are genuinely security work and nothing else: both preview-action READMEs recommend pull_request_target for fork PRs (the pwn-request pattern, and it sits under a heading titled "Security"), and a scheduled workflow executes notebook code from three external lecture repos as root with a write-scoped GITHUB_TOKEN persisted to .git/config.

Under the core 18 those become bug or infrastructure. That's not wrong per the Type taxonomy, but it loses the thing the label is actually for: org:QuantEcon label:security as a standing query, and a way to see at a glance that an issue needs a different review bar. Three options as I see them:

  1. Add security as a 19th core label. Cleanest for querying. Costs one label and slightly muddies "exactly one Type label" unless it's explicitly scoped as a non-Type modifier, the way the priority labels are.
  2. Treat it as a non-Type cross-cutting label, like priority — an issue gets one Type label plus optionally security. This is what I did in actions (#105 carries bug + security + high priority), and it read naturally.
  3. Leave it out of core, keep it local to repos that handle credentials. Consistent with "pruning is separate and deliberate", but then the cross-repo query never works, which is most of the value.

I'd favour 2 — it mirrors how priority already behaves, doesn't touch the Type mutual-exclusivity argument, and makes the cross-repo query work.

testing (also local in actions) I'd argue doesn't need the same treatment — test work reads fine as infrastructure or maintenance, and our one testing issue took infrastructure + testing without the second label carrying much weight. Happy to drop it locally at prune time.

Variants in actions for qe gh labels sync

Flagging these so the rename map is complete when the pilot expands past lecture-python-programming:

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.

mmcky and others added 2 commits July 23, 2026 11:09
…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>
@mmcky

mmcky commented Jul 23, 2026

Copy link
Copy Markdown
Contributor Author

Reviewed the QuantEcon/actions field report above and settled the open items; the draft is revised in d619872 (and the branch is synced with main, adopting the lowercase type: standard enum from the QEP-1 v1 CI checks). Decisions:

  1. security → option 2, a cross-cutting modifier. Security is orthogonal to Type (the two actions findings prove it), so it joins priority as a non-Type label: exactly one Type label, plus optionally security. Set is now 19 core + 2 lecture = 21. Colour keeps the in-the-wild #ee0701.
  2. infrastructure colour settled: #1d3c78. The audit's clash concern wins over the field report's "no objection" — #006b75 sat too close to the help wanted teal.
  3. Boundary test adopted: infrastructure vs maintenance now turns on "would it appear in a release note?" — repo-agnostic, unlike the lecture-specific phrasing.
  4. testing stays non-standard (reads as infrastructure/maintenance); added to the deliberately-not-labelled list. Prune locally in actions.
  5. Source of truth: the QEP itself. The normative schema ships as co-located qep-0002-labels.yml; changing it is a substantive amendment (bumps version) under QEP-1's existing appendix rule, so no QEP-1 change is needed — generalising the convention waits until a second QEP wants an appendix. CI now enforces table↔yml lockstep and the post-acceptance version bump.
  6. The yml records only the standard. Rename/alias maps (high priorityhigh-priority, linkcheckerbroken-links), retired-label handling, and pruning are the CLI's job as the tool implementing the QEP — no fields excluded from versioning. cli reads the yml from this repo; its own labels.yml is retired rather than updated.

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>
@mmcky

mmcky commented Jul 23, 2026

Copy link
Copy Markdown
Contributor Author

Automation labels: the policy describes one kind of bot label, but we have two

Continuing the field report from applying this draft — this one surfaced from wiring the set into QuantEcon/reports-activity, which both reads labels (the activity reports and news drafts rank on them) and writes them (its scheduled workflows open labelled issues). The writing side is where the current wording doesn't fit.

The two kinds

Diagnostics — what the automation found. broken-links, build-failure, dependencies. Semantically meaningful org-wide, legitimately a small closed set, and rightly normative here.

Origin labels — which automation produced it, existing because a downstream consumer queries on it. status-report, action-translation. Open-ended, grows with the tooling, and invisible to QEP-2 today.

"Carries automated plus exactly one diagnostic (broken-links, build-failure, or dependencies)" only describes the first kind, so every instance of the second is non-conformant by construction. That's not a hypothetical: action-translation is the label the Translation-Sync rollup routes on across the lecture repos, and status-report is the label reports-activity uses to find its own weekly issues.

"Exactly one" is also wrong for diagnostics

Separate 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 build-failure, which would be false, and would poison org:QuantEcon label:build-failure as a standing query. It should be at most one.

Suggested replacement for the automation policy bullet

Automation labels are bot-applied. Every bot-opened issue or PR carries automated. It may also carry at most one diagnostic (broken-links, build-failure, dependencies) describing what the automation found, and at most one origin label naming the producing automation — added only where a documented consumer queries on it, never by default. Humans do not hand-apply any of these.

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: cleanup-weekly-reports.yml filters on status-report,automated as an AND, and automated alone would sweep in Dependabot PRs and build-failure issues, so the origin label is doing real work; tools/highlights.py routes the Translation-Sync rollup on action-translation the same way.

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 recolouring

The 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 duplicate #cfd3d7 sits numerically inside the automation ramp, between #dddddd and #cccccc. There is also no rule for what colour a new bot label should take.

Since duplicate and wontfix carry GitHub's own default colours, the argument that keeps good first issue spaced says don't recolour them. So amend the claim rather than the palette — grey marks low-salience state (machine output or a closing outcome) rather than triage signal, with the two families distinguished by text, not hue — and add the allocation rule: automation labels take a grey in the band #ededed#bdbdbd; a new origin label takes the next unused value in that band.

Where origin labels get registered

Keep automated and the three diagnostics here as core. Origin labels belong in the separate automation QEP already agreed in #3 — and that is nearly free to set up, because check-labels.mjs already globs every qeps/qep-NNNN-*.yml companion and resolves it to its owning QEP. The automation QEP gets a companion yml and the parity check applies to it with no new code. The only schema change is one additive scope value (repo, alongside core and lecture), since origin labels are not org-wide.

What this buys, concretely

It gives qe gh labels prune a mechanical answer for these labels. Today status-report and action-translation look exactly like the bespoke local labels prune exists to remove, and the only thing standing between them and deletion is a human noticing during the one-by-one review. Registered, they are skippable by rule. That matters more for action-translation than for our own label: it lives on lecture repos that are in the pilot, and losing it degrades the Translation-Sync rollup silently rather than erroring, since labels are a ranking boost and never a gate.

… 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>
@mmcky

mmcky commented Jul 23, 2026

Copy link
Copy Markdown
Contributor Author

Where the automation-label discussion landed

Following 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):

  • Diagnostics: "at most one", not "exactly one". Routine scheduled output diagnoses nothing and carries no diagnostic.
  • Registering an automation grants a namespace, not a label. Each registration = a durable origin label (full name, on every artifact the automation creates) + optionally a short capability-named task prefix with / separator (translate/review). The "documented consumer" justification bar moves to registration time. Everything inside a namespace is the owner's contract — free to evolve without touching a QEP, which keeps team review out of the inner loop of action development.
  • Mailbox semantics, worker-owns. A task label is an inbox owned by the automation that does the work: apply = enqueue (open to org automations and maintainers by default; owners may guard by checking the event sender), owner-removes = complete, human-removes = cancel, dead-letter comment when the owner won't act. Completion is inert — the anti-loop rule; chains are designed, never emergent.
  • The token gate does the access control. GITHUB_TOKEN events don't trigger workflows, so bot→bot enqueueing only works through a deliberately provisioned App/PAT — a human decision exactly where coordination power is granted. Humans trigger freely via the UI, floored by triage permission.
  • Grey claim amended, band allocated. Grey = low-salience state (machine output or closing outcome), automation vs meta distinguished by text; new families take the next unused grey in #ededed#bdbdbd. No recolouring of GitHub-default meta labels.
  • Prune/sync become mechanical here. Registered zones are skipped by rule — action-translation and status-report stop depending on a human recognising them during one-by-one review.

Ideas considered and set aside, with reasons recorded in QEP-4's Alternatives: a shared org prefix (qebot/, task/) re-centralises the task vocabulary and can't express private state labels; writer-owns coupling points the wrong way; per-label registration puts contract churn through QEP amendments.

mmcky and others added 4 commits July 23, 2026 12:59
…, 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>
@mmcky

mmcky commented Jul 23, 2026

Copy link
Copy Markdown
Contributor Author

Field report: applying QEP-2 to a real triage pass

I 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. infrastructure vs maintenance — is the axis substance, or subject?

The descriptions draw the line on substance: infrastructure is "Substantial CI / build / deploy / tooling / automation work", maintenance is "Routine housekeeping: style, formatting, env & dependency upkeep". So bumping actions/checkout@v4→v5 is maintenance and rewriting a deploy job is infrastructure — both being Actions work.

But a reader can just as reasonably take the axis to be subject matter — "workflows and tooling are infrastructure, content and formatting are maintenance" — and that reading is also consistent with the descriptions as written. Two of us landed on different readings independently, which suggests one clarifying clause would pay for itself. Something like "the boundary is effort, not subject: routine upkeep of CI is maintenance; substantial CI work is infrastructure" (or the opposite, if subject is what's intended).

2. The Type set is awkward in a documentation-product repo

Where the product is documentation, documentation ("Repo docs and contributor meta") and the other Types collide constantly. Is "the manual documents a publish trigger that doesn't match the template" a bug or documentation? Is "40 headings violate our own capitalisation rule" maintenance or documentation? Roughly a third of my issues were genuinely ambiguous, and the tie-breaks I chose were arbitrary enough that a second triager would not reproduce them.

A one-sentence scope note would settle it. The convention that worked for me: in docs-product repos, documentation is reserved for content gaps (and contributor meta), while content defects take the Type matching the nature of the change — bug for wrong or broken, maintenance for routine sweeps, enhancement for new structure.

This matters beyond one repo: QuantEcon.manual, qeps itself, and the lecture repos are all documentation products under this schema.

3. Proposal: add a tracking label to the workflow group

Amended — this item originally asked only for an exemption clause. Testing the alternative showed a label is actually needed, so it now proposes one.

The problem. "Exactly one Type label per issue" plus "unlabelled means needs triage" leaves umbrella issues with nowhere to go — none of the seven Types describe "this issue exists to group thirteen others". Sending grouping to Milestones is right and I used a milestone, but the umbrella issue itself still needs to be labelled or it reads as untriaged forever.

Why native sub-issues don't close it. My first instinct was that sub-issues make a label redundant — GitHub knows which issue is the parent, and renders a progress bar. But the relationship is not searchable. Tested against the REST search API:

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>
@mmcky

mmcky commented Jul 23, 2026

Copy link
Copy Markdown
Contributor Author

Reviewed the triage-pass field report; all six items settled, draft revised in 27f1a84.

  1. Adopted. The infrastructure / maintenance boundary is now stated explicitly: effort, not subject — the release-note test decides, not which files were touched.
  2. Adopted, by generalising the existing rule. documentation is always about-the-repo; product content never takes it, even where the product is docs — wrong content is bug, sweeps are maintenance, gaps are enhancement. Same labels in the manual as in a lecture repo.
  3. tracking label rejected; the original exemption adopted instead. Second check: has:sub-issue is honoured by the advanced issue search (GraphQL ISSUE_ADVANCED / the new issues UI), repo-scoped and org-wide — it returns exactly our four real umbrella issues — so discovery is native and the label would be born redundant. New policy line: a sub-issue parent is structure, not work — exempt from the one-Type rule, not "needs triage" when unlabelled. Tooling caveat kept: legacy REST search silently ignores the qualifier.
  4. No change. security stays one broad cross-cutting modifier for everything security-related, with high-priority carrying urgency; escalation channels are incident practice, not label policy. (The manual's credential findings were short-lived session tokens — dead on discovery — so a public labelled issue was the right handling.)
  5. Confirmedapplied-by: bot kept as specified.
  6. Confirmed — native replacements verified reachable; discovery via the advanced search per item 3.

No qep-0002-labels.yml changes; set stays 19 core + 2 lecture.

…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>
@mmcky

mmcky commented Jul 23, 2026

Copy link
Copy Markdown
Contributor Author
  1. Rollout slimmed to mechanism and guarantees (revised in 16559e4). The section keeps what any implementation must honour — additive, history-preserving sync from the co-located appendix; one-by-one prune; pilot-first; core-19 org default — while the sequenced execution checklist (CLI integration, pilot target, widening order, org defaults, retiring the earlier unification attempts) moves to a tracking issue opened at acceptance, a sub-issue parent per item 3. Convention going forward: Rollout says how and what is guaranteed; the acceptance-time tracker says who and when — so completing a step never requires amending the standard.

mmcky and others added 2 commits July 23, 2026 15:45
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>
@mmcky

mmcky commented Jul 23, 2026

Copy link
Copy Markdown
Contributor Author
  1. Section renamed: RolloutAdoption (e8728ff). The name states what the section now contains — what adopting the QEP requires (mechanism, tooling, guarantees as obligations), not a plan that can go stale; sequenced execution stays in the acceptance tracker per item 7. Since the section list is QEP-1's format, this PR carries the upstream amendment per the cross-amendment convention: template.md guidance updated, QEP-1 bumped to v2 with a (v2) entry in its own adoption record, README index synced. ("Next Steps" was considered and rejected — it invites the checklist back in.)

mmcky and others added 6 commits July 23, 2026 15:56
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>
@mmcky
mmcky requested a review from jstac July 23, 2026 06:18
@mmcky

mmcky commented Jul 23, 2026

Copy link
Copy Markdown
Contributor Author

@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 Rollout to Adoption as the final section.

@mmcky

mmcky commented Jul 23, 2026

Copy link
Copy Markdown
Contributor Author

Field report: QEP-2 applied to a 19-issue technical-debt milestone

Applied the draft set to the remediation plan from a technical-debt audit of QuantEcon/action-translation — 19 issues in one milestone (#158–#176) plus a trigger-gated backlog issue. Two things worth folding in, one confirmation, one note for the sync tool.

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. enhancement ("improvement to existing content or functionality") is a stretch when nothing user-visible changes. maintenance ("routine housekeeping: style, formatting, env & dependency upkeep") is neither routine nor housekeeping — these are 3-6 day structural changes. infrastructure is CI/build/deploy/tooling, and this is product source. The release-note boundary test separates infrastructure from maintenance cleanly but is silent on internal restructuring, which is most of what technical-debt work actually is. I used enhancement for all five with real doubt.

Suggest a clarifying line in the When to use column rather than a new label — something like "enhancement also covers internal restructuring that changes no behaviour". That was the only Type call in nineteen I could not make confidently.

2. Priority re-centres inside a Milestone. I ended up marking 5 of 19 high-priority — 26%, well above what "marks only outliers" implies — because inside a milestone the question silently shifts from "is this urgent for the repo?" to "what do I do first within this work?". Worth stating explicitly that priority is repo-global, and that sequencing within a milestone belongs to issue order and dependencies rather than labels. One sentence would have stopped me over-labelling.

Confirmed: grouping → Milestones held up well. The milestone replaced what would otherwise have been a tech-debt label on all 19, and no grouping label was needed at any point. security as a cross-cutting modifier also worked exactly as documented — one issue carries bug + security + high-priority (a scaffolded workflow that can never fire, plus the least-privilege hardening it needs), and that combination reads correctly without a Type-level security label.

For the sync tool: this repo's pre-existing maintenance is #1D76DB against the standard's fbca04, and high priority needed the documented rename to high-priority. So qe gh labels sync needs to recolour and rename existing labels, not only create missing ones — the rename via gh label edit --name preserves the label on issues already carrying it, which makes it safe to do additively.

mmcky and others added 3 commits July 24, 2026 12:18
…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>
@mmcky

mmcky commented Jul 24, 2026

Copy link
Copy Markdown
Contributor Author

Resolution of the field report — landed in f865f26, 5758c91, 16754a5:

  1. Refactor gap → adopted, with a different fix. Stretching enhancement is rejected: nothing user-visible changes, and the reports read enhancement as user-facing improvement. Instead infrastructure's description now owns behaviour-preserving restructuring (the release-note test judges effort, not subject), and a new one-label software extension adds refactor (use instead of infrastructure; the repo's own CI/build/tooling stays infrastructure). The set is now 19 core + 2 lecture + 1 software = 22; rationale recorded under Alternatives considered. The five action-translation refactors can relabel to refactor on adoption.

  2. Priority re-centring → adopted, as one clause on the outliers bullet: genuinely off-centre "for the repo — a milestone doesn't re-centre the scale."

  3. Confirmations → no change needed. The grouping line now names a one-shot campaign (a tech-debt audit) as a milestone example alongside recurring programs, so the field reading is explicit rather than implied.

  4. Sync recolour/rename → CLI-owned, filed as QuantEcon/cli#8 with the observed drift (maintenance at #1D76DB, high priority) as test cases. The QEP keeps only the guarantee — sync guarantees the standard set — not the mechanics.

@mmcky

mmcky commented Jul 26, 2026

Copy link
Copy Markdown
Contributor Author

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 QuantEcon/action-translation (61 issues reviewed, 11 closed, 52 open at the end, 24 of which had no label at all). The refactor gap, priority re-centring and sync mechanics from the earlier reports all held as resolved. Three new items, all about the retired status labels and adoption sequencing rather than the Type set.

1. Retiring blocked leaves external blockers with nowhere to go. The decision records that native issue dependencies plus "Blocked by #N" cover it. In practice they cover issue-to-issue blocks well — I recorded two (a docs issue that closes when its consumer-side parser lands; a measurement issue that closes when its carrier harness exists) and both read correctly. But three genuinely blocked issues had no native representation, because the blocker is not an issue:

Issue Blocked on
Sync localisation A decision recorded as a report file in another repo (an estate-wide CJK-font review that may dissolve half the issue's scope)
fr terminology pin A named native speaker's availability
fa transliteration policy Same

Each is deliberately parked, not neglected, and a reader cannot tell. I don't think the answer is re-adding blocked — its staleness failure mode is real and the thread settled that. But the QEP currently gives a triager no alternative for a non-issue blocker. One line would fix it, whichever way it lands: a human-maintained "Blocked by: …" first line in the body (greppable, ages visibly), or an explicit "external blockers are recorded in the body as prose, not tracked".

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 discuss-shaped issues that could not be labelled because discuss isn't synced to this repo yet. Those two groups are indistinguishable to a reader, and the second is the most deliberately-triaged content in the tracker. The semantics are right; the sequencing isn't stated. Suggest a line in Adoption: run qe gh labels sync before the triage pass — a pass against a partially-synced set manufactures false needs-triage readings that persist until someone sweeps again.

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% high-priority, against the 26% the milestone-scoped pass hit three days ago. Same triager, same repo — the "a milestone doesn't re-centre the scale" clause did exactly its job. Also: testing's retirement mapped cleanly (a harness test-coverage gap → infrastructure, decided by the release-note test), security as a modifier read correctly again, and the eight already-standard core labels applied with no friction at all — adoption here really is cheap.

@mmcky

mmcky commented Jul 27, 2026

Copy link
Copy Markdown
Contributor Author

Field report — applying the draft set to website-dynamic

A second field test, following the QuantEcon/actions one in the PR body. This one is a data-pipeline repo rather than an actions or lecture repo, so it exercises the software extension and the sub-issue/tracker rule in a way the first test didn't.

What was applied: the full software-repo set (core 19 + refactor = 20 labels) to QuantEcon/website-dynamic, then a tracking issue with 12 sub-issues covering a correctness-and-hygiene sweep of the analytics pipeline. Every child took exactly one Type label. The set fit without a single "none of these apply" moment, and no local label was missed.

Held up well

The sub-issue parent rule. The tracker carries no labels and 12 native sub-issues; the children carry the Type labels. Having the parent be structure rather than work is the right call — the alternative (a Type label on an umbrella) would have meant choosing between infrastructure and bug for an issue that is neither.

The has:sub-issue tooling warning is exactly right, and worth keeping prominent. Empirically, on this repo: the advanced search returns 1 (the tracker), and the legacy REST search returns 20 — it silently ignores the qualifier and hands back every issue. A caller who doesn't know to set the advanced-search flag gets a plausible-looking wrong answer rather than an error, which is the worst failure mode. That note earns its place.

The release-note test for infrastructure vs maintenance. Used it on four issues and it decided each one quickly. Moving a config list out of a repository secret is infrastructure; bumping an end-of-life Python version and pinning requirements is maintenance. No hesitation.

Priority as an outlier marker. Two of twelve got high-priority, one got low-priority. The "most work sits at the unlabelled default" framing produced a distribution that looks right, rather than the creeping every-issue-is-high-priority drift.

Graceful degradation into not-yet-adopted repos. Mid-sweep, a related issue had to be filed in a repo still carrying the legacy label set (no infrastructure to apply). The policy made this a non-decision: file unlabelled — unlabelled already means needs-triage — rather than half-adopt by reaching for the nearest legacy label. Worth one sentence in the rollout guidance so the next person doesn't agonise: during the transition, standard-set labelling happens at adoption time, not issue-filing time.

Two boundary gaps worth closing

1. There is no bug vs enhancement test. The QEP gives boundary tests for infrastructure/maintenance (release note) and refactor/infrastructure, but nothing for the commonest ambiguity: is incomplete output a bug or an enhancement?

The concrete case was QuantEcon/website-dynamic#10 — a published chart titled "QuantEcon lecture series users" that aggregates 8 of the 14 available properties. Adding six properties reads as additive work (enhancement), but the chart as it stands misrepresents what its own title claims (bug). I labelled it bug on the reasoning that the current output is wrong, not merely smaller than it could be — but that reasoning is mine, not the QEP's, and the next person will land somewhere else.

Suggested test, in the same spirit as the release-note one: does the current behaviour misrepresent itself? If yes it is a bug however the fix is shaped; if it simply does less than we would like, it is an enhancement.

2. question vs discuss doesn't cover investigate-then-decide. The QEP frames these as a clean split — question seeks a single answer and is done when answered; discuss is open-ended with no single right answer. A common third shape is neither: an issue that starts factual and ends in a policy call.

The case was QuantEcon/website-dynamic#20. Traffic from one country is an eight-times per-capita outlier and dominates a public chart. Whether it is automated traffic is a factual question with a determinate answer. What to do about it on a public dashboard — filter, annotate, or publish with a caveat — is a decision. I used discuss because the issue terminates in a decision.

Suggested clarification: if the issue terminates in a decision, it is discuss even when it opens with a factual question. One sentence would settle it.

Prune scope — distinguish GitHub's defaults from bespoke labels

The QEP treats pruning as uniformly deliberate and one-by-one, which is clearly right for the labels it names as the motivating cases (jax-conversion, colab, site-refresh, reading-group-*) — labels a repo chose and may rely on.

invalid is not that. It is one of GitHub's stock labels, present because the repo was created, never deliberately adopted, and with zero usages here. Reviewing it one-by-one is ceremony over a label nobody picked.

Suggested refinement: let sync drop unused GitHub-default labels (invalid, and enhancement-style stock descriptions are already handled), and reserve the one-by-one review for labels that either have usages or are locally originated. Usage count is the machine-checkable signal, the same way the sub-issue relationship is for trackers.

Tooling notes

Neither native sub-issues nor native dependencies have a gh command. gh issue has no sub-issue subcommand, so linking goes through POST /repos/{owner}/{repo}/issues/{n}/sub_issues — and that endpoint takes the child's numeric database id, not its issue number, so each link needs an extra lookup. Native "blocked by" dependencies are the same story (POST …/issues/{n}/dependencies/blocked_by, numeric issue_id). Both worked reliably once scripted — the friction is discovery, not the API.

This matters for adoption rather than for the QEP text: the QEP retires markdown checklists in favour of native sub-issues and retires the blocked label in favour of native dependencies, and the path of least resistance for anyone filing by hand is still the checklist and the label. Worth qe gh helpers (qe gh subissue add <parent> <child>…, qe gh blocked-by <issue> <blocker>) alongside labels sync, or the prescription will quietly lose to the easier option.

refactor is unexercised. Zero uses across both field tests — none in the 12 issues here, and none among the labels in use on QuantEcon/actions. Not an argument to cut it; a small pipeline repo simply gave it no occasion. But its boundary against infrastructure is still untested in practice, so it is the part of the set I would least trust to be settled.

One observation about the reference repo

QuantEcon/actions — the field-test repo cited in the PR — is not itself in the target state. It currently has 16 labels and still carries blocked, in-work and ready (the three status labels this QEP retires), testing (on the deliberately-not-labelled list), and editor (the lecture extension, on a tooling repo). Eight of the core 19 are absent, including the whole automation quartet and discuss.

That is a consequence of qe gh labels sync not existing yet, not a problem with the QEP — the field test informed the draft without the repo ever being brought to conformance. But it does mean that as things stand, anyone following the PR's field-test link sees the pre-state. Bringing actions to conformance as part of acceptance would make it a reference rather than a counter-example, and would exercise the status-label retirement and the deliberate one-by-one prune (testing, editor, blocked) on a repo with real label history — neither of which this test touched, since website-dynamic had only stock labels.

For what it is worth, website-dynamic is now at the full 20 and may be the first repo actually sitting in QEP-2's target state.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ready Marked as ready for review

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants