Skip to content

QEP-6: Project Tracker Structure and Order (Draft) - #18

Draft
quantecon-services wants to merge 11 commits into
mainfrom
claude/github-issues-task-ordering-9uj7wa
Draft

QEP-6: Project Tracker Structure and Order (Draft)#18
quantecon-services wants to merge 11 commits into
mainfrom
claude/github-issues-task-ordering-9uj7wa

Conversation

@quantecon-services

@quantecon-services quantecon-services commented Aug 26, 2026

Copy link
Copy Markdown
Collaborator

Adds QEP-6: Project Tracker Structure and Order as a Draft — the one-page unit spec scoped by the 2026-08-23 ruling on the discussion issue, extended with the ordering question that arrived from the field (QuantEcon/textstrata#8, QuantEcon/skills#55) and answered on that thread.

What it decides

  • The unit: a Project is one tracker issue carrying the native org Project issue type (a type, not a label — QEP-2 untouched; resolves QEP-2 field report: no type label fits plan/tracking issues #11); work items are native sub-issues, progress on direct children only, never body checkboxes (unmeasured ≠ 0%).
  • Order is positional: the sub-issue list is the plan's order — top open item = next, completed items keep their place, phases contiguous, new items placed on arrival. Re-ordering moves items (drag or the reprioritize API) and never renames them; sequence never appears in issue titles or milestone names.
  • Constraints are dependencies: a real sequencing constraint is a native blocked-by edge (optional; a constraint, not a presentation order). Phase gates stay in the body. Superseded — see the repairs below.
  • Phases are milestones (optional): descriptive names only — a milestone is referenced, not copied, so a phase rename is one propagating edit; cross-repo work items fall back to the body's phase table.
  • One machine-read body element: the status stamp (## Where we stand (verified YYYY-MM-DD) canonical; banner fallback). The stamp section sits at the top and may open with a single Next: resume line — the body's only "what's next" claim; the list is the authority if they disagree.
  • The no-mirror body: goal, narrative, phase intents/exit criteria, gates, rationale, scope boundaries — never rosters, checkbox work lists, milestone→issue tables, hand-written progress, or dependency prose. Informative skeleton in Appendix A.
  • Scope: the programme layer is outside; genres/ledgers/succession stay in the qe skills, which cite this QEP.

Repairs since opening — 2026-09-08

The bullets above describe the Draft as opened; four things have moved in this PR's later commits (bc856da, 3673475), all ruled on the discussion threads and the two field reports on this PR:

  • §4 Constraints are dependencies now says how a phase-level gate is carried — as a conjunction: the first item of the waiting phase is blocked by every item of the phase it waits on; a decision gate as an edge to the Decision; a whole-project gate as a tracker-to-tracker edge. It also states the test that decides whether an ordering is an edge at all — output, not order: an edge where the downstream item cannot start without something the upstream produces; shared files and serial work are plan order and stay with the body's sequencing rationale — and a phase-level preference is therefore not a gate. The back-pointer duty on the waited-on project is struck: the reverse direction is read, never written. Appendix A's Gates: line follows.
  • §8 Scope no longer says a consumer "may observe" a programme's front door — that is QuantEcon/status-projects#10's open question, and the section now defers to it. What it keeps is its own: no programme tier in the grammar, no duty on a tracker from being listed.
  • Adoption is renumbered 1–5 — the source read 1., 2., 2., 3., 4., so every external "clause N" citation after the first was off by one; ci: generate the README index, and check that ordered-list markers ascend #30 now checks for this. Clause 4 obliges a re-stamp in the same turn as any change to the list, and states that the qe skills conform to this QEP — the precedence clause over the dashboard's tracker contract, and the cross-repo handover item, were removed on 2026-09-09 (see the comment thread; ownership is recorded in QuantEcon/status-projects#140).
  • related: [2] and a Related header row are added. The README index row is removed: ci: generate the README index, and check that ordered-list markers ascend #30 generates the index post-merge, so this PR's checks job is red until ci: generate the README index, and check that ordered-list markers ascend #30 lands, and is expected to be. Landing order: ci: generate the README index, and check that ordered-list markers ascend #30QEP-3: Accepted #29QEP-1 v3: stamp from v0; drop the decision deadline; generate the index #23 → this.

Points where input is most useful

  1. The plan-order semantics (top = next; completed items keep their place) vs any appetite for queue semantics.
  2. The single Next: resume line — right affordance, right home?
  3. Whether the phase table + gates belong in the normative body section or should move wholly to Appendix A.
  4. The Adoption obligations on the dashboard side (child order published as list order — currently its contract re-sorts children by issue number; the amendment is a one-row change plus a sort removal, references are on the discussion issue and 404 for non-members).

Process

Opened as a draft, consistent with the 2026-08-23 ruling that the spec is field-tested in Draft: the conform tooling (QuantEcon/skills#63, which carries the split of #49) brings registered trackers into the layout and the collector reports compliance nightly. Under QEP-1 v3 (#23) there is no comment window or decision deadline to set: the Draft is accepted when a Core Maintainer other than its author approves it with no objection outstanding. Note the ordering half cannot be observed until the child-order amendment ships — the collector currently re-sorts children, which is itself part of the motivation.

qep-checks parity: new QEP, unversioned (implicitly v0); no README row (generated by #30). Both check scripts pass locally under #30's rules.

🤖 Generated with Claude Code

https://claude.ai/code/session_013WNYd4EW71564zVcW81yx7


Generated by Claude Code

Adds QEP-6 as a Draft: the project-tracking unit (one tracker issue,
Project issue type, native sub-issues one level down), positional order
with plan semantics, dependencies for real constraints, descriptive
phase milestones, the fixed status stamp, and the body's no-mirror
discipline with a single Next: resume line. Adds the README index row
(standard / Draft / –).

Discussion: #15

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013WNYd4EW71564zVcW81yx7
Folds in the twelve amendments consolidated on the field report thread
(see #19) plus two edits from its producer-tooling finding:

- Scope the standard to GitHub.com (s7)
- Ban purely numeric milestone names, verified live (s4)
- Membership criterion: closing a work item advances the definition of
  done; unparented issues and unparented trackers are normal (s1)
- Direct children homogeneous in kind; progress is a snapshot, not a
  time series (s1)
- Dropped items leave the sub-issue list - percent_completed counts
  not_planned closures as completed (s2)
- Gates: mostly phase-level in practice; a whole-project gate also
  carries the tracker-to-tracker dependency edge (verified live on a
  throwaway pair); stated once, in the project that waits (s3)
- Parked-ness is derived from open blockers, never carried (s3)
- Stamp refresh is a read-modify-write with a lossless read; sanitising
  surfaces get append-only treatment (s5)
- Named replacements for the body bans; Related work section (s6)
- Markdown template plus post-creation type read-back (Adoption 1)
- Re-parenting guard on the conform tooling (Adoption 2)
- QEP-6 authoritative over the dashboard contract during handover
  (Adoption 3)
- Drop "untyped = untriaged" as a load-bearing justification (s1)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@mmcky

mmcky commented Aug 27, 2026

Copy link
Copy Markdown
Contributor

Applied the field-test amendment set from #19 (the consolidated 12-amendment checklist in its final comment), plus the two edits from its producer-tooling finding, in commit 1a0f063. The four review calls landed as:

Gates (amendment 10 §1) — the softened, granularity-first form: most cross-project gates are phase-level and stay in the body; a whole-project gate carries the tracker-to-tracker dependency edge, stated once in the body of the project that waits. The edge mechanism is now verified live rather than inferred (see the closing results on #20): an edge between two sub-issue-carrying tracker issues is accepted, reads back on REST blockedBy and GraphQL blockedBy/blocking, and the UI timeline records it — so the whole-project case keeps must.

Stamp concurrency (amendment 7) — the read half is specified as read-from-a-source-returning-surface (the REST endpoint returns raw markdown) rather than an unactionable byte-for-byte round-trip check; where only a sanitising surface is available the body is append-only and corrections go to comments.

"untyped = untriaged" — dropped from §1 as a load-bearing justification for type-over-label; the Motivation's audit observation stands as an observation.

Related work — bound relaxed to: entries name projects, never work items, but item numbers may appear as the specifics of a project-level relationship.

Also in: amendment 2 upgraded from source-derived to executed (gh issue list --milestone "2026" fails with no milestone found with number '2026' while a descriptive name resolves fine), the §6 named-replacements paragraph, and the Adoption-3 sentence making this QEP authoritative over the dashboard's tracker contract wherever they disagree during the handover gap.

Per process: Draft and unmerged, so no version field; both check scripts pass.

…s on labels

Types carry structural role (Project / Task / Decision, each with its own
meaning of "closed"); QEP-2 labels carry content, and the axes compose.
Adoption gains the one-time reversible reshape of the org type set
(Bug/Feature disabled, Task re-described, Decision created).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@mmcky

mmcky commented Aug 28, 2026

Copy link
Copy Markdown
Contributor

e61b1da adds §2 Issue types, settling the type/label question from the tracker discussion: native issue types carry structural role (what kind of object an issue is in the tracking system), QEP-2 labels carry content at triage, and the axes compose — a work item whose content is a bug is Task + bug, never a Bug type.

The set is three roles, each admitted by having its own meaning of "closed": Project (definition of done met), Task (work shipped), Decision (choice recorded). Decision composes with §4's dependency mechanics so "parked on a decision" is derivable, and the §4 gate-as-decision sentence now names the type. Hierarchy level is never encoded in type — a programme tracker is still a Project.

Adoption gains a one-time org-level precondition: reshape the type set via four reversible API calls — Bug/Feature disabled, not deleted (assignments stay latent; one call undoes it), Task re-described, Decision created — so it ships at field-test start rather than acceptance. Alternatives records the rejection of content-classifying types. Sections 2–7 renumbered to 3–8; both check scripts pass.

… not a tier

Records the outcome of the #24 discussion in one scope sentence: the
grammar has two normative tiers and no third; a programme is a named
collection of projects maintained by the projects registry.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@mmcky

mmcky commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

Finding 9 follow-up — the class-3 producer now conforms (2026-09-02)

Closing the loop on qeps#19's finding 9, which read qe/skills/workplan-project against this draft and found it mandating a body element §7 forbids and never mentioning order.

The six findings it filed (QuantEcon/skills#69–#74) are done: merged as QuantEcon/skills#76, released as qe 0.10.0 and tagged qe--v0.10.0 at 7ebf8a5. One commit per finding, so the PR reads against the findings. What the skill now does, in this draft's terms: the tracker body carries a Phase | Intent | Exit criterion table and never a roster (§7); the tracking issue is written once, with no backfill edit; draft file order is plan order, sub-issues are linked in that order with the native verb and the read-back asserts list order (§3); a recovered item on a re-run is placed with the reprioritise API rather than appended; every pre-existing issue's parent is read before linking, with the detachment named in the approval draft (Adoption clause 2); a membership gate applies §1's criterion before drafting, with the goal-widening diagnostic as the working tool; the exemplar is cited for content only, with Appendix A as the shape; and split packages carry Related work and Gates.

Two things this draft's Adoption section did that mattered in practice. Clause 3's precedence sentence is what the skill cites where C2 and this QEP disagree — the skill names the disagreement (a body roster is C2-conformant, QEP-6-forbidden) and points at the clause rather than resolving it, which is exactly the one-sentence fix finding 9 asked for. And clause 2's read-before-link obligation was verified in the gh source before being written into the skill: in cli/cli v2.98.0, --add-sub-issue and --parent both call AddSubIssue with replaceParent true, unconditionally (api/queries_issue.go), while the raw REST POST …/sub_issues omits the flag and fails on a parented child. The skill now uses one method with one guard.

One re-verification note for the record: QuantEcon.py#925's stamp heading, which finding 9 called stamp-unreadable, was fixed upstream on 2026-08-31 and now parses; its plan table still carries Issue and Status columns, so it remains cited for content rather than shape.

The link-and-reprioritise path was exercised once by hand the same day, placing the six closed findings into QuantEcon/skills#63 in plan order after an existing item; REST, GraphQL and the rendered page agreed on the result. The same body was brought to §7 by hand — roster table out, phase table and Gates in — which is the first tracker in that repo conformed to this draft's body rules. The sibling finding on /qe:workplan (no tracker-genre body spec, no home for the Next: line) is QuantEcon/skills#68 and is now a phase-1 item of the same tracker.

The evaluation gate finding 9 named still stands: until QuantEcon/status-projects#19 ships, the dashboard re-sorts children by issue number, so the ordering half of this draft is observable only on GitHub itself.


Generated by Claude Code

@mmcky

mmcky commented Sep 8, 2026

Copy link
Copy Markdown
Contributor

Field report — two trackers written to the draft, 2026-09-07 and 2026-09-08

Two project trackers were written to QEP-6 as drafted by the org's own producers on consecutive days: QuantEcon/status-projects#69 (eleven items, three phases, one item closed) and QuantEcon/status-projects#89 (nine items, three phases), with a declared dependency between them. Both carry the Project type, native sub-issues in plan order, one stamp, a phase table with intents and exit criteria, gates stated once, a Related work section, and no roster — the unit rules held without strain. The five findings below are each a place where a careful producer read the draft one way and the draft meant the other; the evidence is on the two trackers and the review that read them (docs/reviews/2026-09-08-focus-and-overview-design.md in status-projects, a private repository).

1. When the phase gate is a Decision, §2 and §4 point different ways — and both producers chose §4. Each tracker's Decide phase is a single Decision-typed issue, and each body states "nothing in Build starts before Decide closes" as prose. §2 says work that cannot start before a choice is blocked-by the decision; §4 says a phase-level gate is stated in the body because no object represents a phase. Here an object does. GraphQL shows zero blockedBy edges on all twenty items (nineteen of them open). Proposed sentence for §4's gate paragraph: A phase whose exit criterion is a Decision closing is a decision gate, not a phase gate: the object exists, so each item that waits carries the native edge to it, and the body states only why. Cost of conformance on these two trackers: nineteen edges, one command each.

2. An item-level constraint across projects was read as body material. #89 states three constraints on items in #69 (its collector item waits on #69's registry and collector items; its Overview item waits on #69's Focus item) with the sentence "That ordering is an edge between items in two different projects, so it is stated here rather than implied." §4 says the reverse — item constraints are native and may cross project boundaries — but its gate paragraph discusses "cross-project gates" at phase and project level only, which is where the reading came from. Proposed sentence after "an edge may cross project boundaries": An item-level constraint is a native edge on the two items whether or not they share a project; only phase-level and whole-project gates are stated in the body. A second, smaller miss: §7 gives the waited-on project a home for pointing back (gated by), and #69 has no such line — the gate was written by the waiting project alone, which is the case §4 describes and the case in which the other project is least likely to notice.

3. Decision children and §1's homogeneity rule. §1 asks that direct children be homogeneous — all leaf work items or all project trackers — and §2 introduces Decision, which in practice sits beside both: 2 of 11 and 2 of 9 children on these two trackers are decisions, and the Themes programme tracker (QuantEcon/workspace-themes#1) carries seven decisions beside four project trackers, where every completion so far is a decided decision and no project has finished. Proposed clarification: Decision children are compatible with either kind; a Decision closed completed counts toward progress like any child (a recorded choice advances done); and a consumer may render decisions apart — which the dashboard's programme contract (C8, proposed) does, as counts.

4. The phase table is an undated claim outside the stamp, and it went stale within a day. #69's list moved from nine items to eleven on 2026-09-07 with a revision comment, adding a new surface and a new contract; the body's phase intents and Build exit criterion, verified that morning, still describe the nine. §6 dates the stamp section and §7 places the phase table outside it. Adoption clause 3 could oblige the qe skills to refresh the stamp section in the same turn as any change to the list. On the consumer side, §1's progress is never compared across a membership change now has an implementation: the dashboard's denominator-changed note (QuantEcon/status-projects#46) says so on the row.

5. The ordering evidence window has a smaller sample than the clause implies. Adoption clause 4 is done — the collector publishes list order since 2026-09-07 (QuantEcon/status-projects#19) — but 19 of the 41 registered trackers are in private repositories and publish children as counts only, so list order is observable on the 14 public trackers that have sub-issues (the collection of 2026-09-08 03:55 UTC). Both trackers in this report are private and contribute nothing to the ordering half of the evidence. The late-September comment window should state its sample.

Nothing here changes the draft's shape. The two amendments are one sentence each in §4; the third is a clarification across §1 and §2; the last two are observations for the evaluation.


Postscript, the same day. The review was ruled on within the hour and both trackers were brought to the §2 and §4 form: #70 and #90 now block every Build item natively, #72 and #92 the site items, the three cross-project item constraints are edges, and one item carries an edge to the decision outside both projects — twenty-one edges, one gh issue edit --add-blocked-by each, none visible to the dashboard (its contract reads blockedBy on the tracker only) and all of them visible on the items as GitHub's own blocked by. The counts above are as at review: two items also moved from #69 to #89 under the §1 test, so the lists now read nine and eleven. One tooling note for Adoption clause 2: adding two sub-issues to a parent in a single gh issue edit --add-sub-issue call failed on the second with GitHub's Priority has already been taken, and succeeded one per call.

Copy link
Copy Markdown
Collaborator Author

Second field report — a degree census over four trackers, and one amendment to FR-2

A review of all four dashboard projects (QuantEcon/status-projects#1, #69, #89, #23 — the 2026-09-08 report read two of them) read issue_dependencies_summary on all 45 direct children. Three findings bear on the draft, and one of them corrects the earlier report.

1. The graph does not close, and no written count of it has been correct

Σblocked_by = 32 and Σblocking = 34 over the 45 children, with at least one inbound edge from outside the set (QuantEcon/actions#163 → #107). So at least three edges leave these four projects for issues no inventory names — and one of them starts at a closed item (#35, blocking: 2, in #1's list).

The counts written on 2026-09-08 were 21 (this PR's postscript), 21 (docs/roadmaps/2026-09-08-focus-and-overview.md) and 22 (2026-09-08-dashboard-projects.md, written 33 minutes later); a careful reconstruction the same day resolved 33; this census says that reconstruction is still short. #89's own stamp enumerates the native edges and omits two live ones (#72→#67, #67→#97).

Nothing in the draft is wrong about this. It is offered as the strongest available evidence for Adoption clause 4's direction of travel: any consumer that publishes an edge count should compute it, and any producer that writes one by hand will be wrong within the day.

2. FR-2's back-pointer half should be struck rather than strengthened

§4 puts the gate in the waiting project's body once and asks the other project to point back via a §7 gated by line; the earlier report found that line missing on #69 and proposed reinforcing the obligation.

GitHub already holds the inverse. Verified live: #73 reports blocking: 1 while #94 reports blocked_by: 3. The reciprocal is not something a producer needs to write — it is the other end of the same edge, readable in both directions.

And there is no producer to write it. The complete mutating-call table of /qe:workplan-project is gh issue create, gh issue edit --add-sub-issue, PATCH …/sub_issues/priority, gh issue edit --type Project; /qe:workplan writes bodies, comments and closes; /qe:workplan-roadmap "never edits an issue". No skill writes a dependency edge at all, which is why all 33-plus edges on these trackers were made by hand after a review.

An obligation with zero producers and a free platform inverse is one that will be missed every time. Proposed: drop the back-pointer duty from §4, and say instead that the reverse direction is read, never written. §7's gated by line stays available as prose for a human reader; it just stops being an obligation the standard relies on.

3. §4's phase-gate clause should name the conjunction

The clause that sends phase-level gates to the body is what produced six uncarried orderings on these trackers (#73→#74, #74→#75/#76, #94→#95/#96/#97, #82→#84, #91→#92, #71→#72 — asserted in item bodies, carried by nothing).

The platform already supports the honest carrier, and the alternatives were checked rather than assumed:

  • A tracker-to-tracker edge over-parks. §4 says it "asserts that nothing in the blocked project may start", and #89's Decide phase runs today — so it would be false.
  • A single tail edge under-carries. Verified: of #69's five Build items, #76 and #77 both report blocking: 0, and #73/#74/#75 report blocking: 1 each. There is no chain between them, so closing the tail implies nothing about the rest.
  • A conjunction carries it exactly. blockedBy is many-to-many: the first item of the waiting phase is blocked by every item of the phase it waits on. That publishes a real number (k of n upstream items still open), clears the night the phase closes rather than the night the tracker closes, and needs no object anyone must remember to close.

Proposed sentence for §4: A phase-level gate is carried as a conjunction — the first item of the waiting phase is blocked by every item of the phase it waits on — so the gate clears when the phase closes rather than when the tracker closes; the body states only why.

Appendix A must change in the same commit. Its Gates: line restates the current rule verbatim ("phase-level gates live here; a whole-project gate also carries a tracker-to-tracker dependency edge"), and Appendix A is the text producers copy.

A related finding on §1, offered as an observation

§1's homogeneity rule is falsified as a partition claim by this repository's own flagship project. #70 fans out to {#73, #74, #75, #76, #77} and #72 to {#75, #76, #67} — the two overlap on #75 and #76. So "a phase is the fan-out of its gate" cannot be assumed, and §5's accepted limit that "phases must partition the work" holds only for milestones — which can never be a dependency endpoint. Anything built on fan-out-as-phase is already untrue here.

Four editorial items, all free while the window is unopened

  1. The Adoption clauses are numbered 1., 2., 2., 3., 4. in source. Markdown renumbers on render, so every external "clause N" citation after the first is off by one: "clause 2" (read-before-link) renders as 3, "clause 3" (qe skills precedence) as 4, "clause 4" (dashboard child order) as 5. QEP-6 field report: building a conformant tracker from an existing issue set #19, the qe skills and this PR's own comments all cite the source numbers.
  2. mergeable_state is dirty on a one-line add/add conflict in the README index against QEP-3's row — this branch predates QEP-3's merge and both insert after QEP-2's. It must resolve keeping both rows: check.mjs:82-85 errors with "README index has no row for QEP-N" for any qeps/*.md lacking one.
  3. No related: frontmatter and no Related header row, though check.mjs:107-141 enforces that pairing and this QEP composes with QEP-2 (§2's type/label axis) and governs status-projects' C2 contract. See Process: downstream QEPs carry their amendments to upstream standards (QEP-1 amendment, deferred to second instance) #9 for the wider question.
  4. §8's scope sentence stops being true when C8 ships. "No producer or consumer reads programme membership as structure" — QuantEcon/status-projects#82 proposes exactly that read. Amend it, or accept that the standard is wrong the day the dashboard ships.

Also, and separate from the text: this PR has no decision deadline, which QEP-1 step 3 requires in the PR description. That is deliberate here (the window awaits the collector's first month), but it is one of four open QEP PRs with no live deadline — filed as #26.

Full evidence, including the census method and the seven corrections it produced, is in docs/reviews/2026-09-08-cross-project-dependencies.md in QuantEcon/status-projects (a private repository).


Generated by Claude Code

quantecon-services pushed a commit that referenced this pull request Sep 8, 2026
…tream amendments

Folds three ruled changes into this amendment and drops one it originally
proposed, so v3 lands as one coherent round instead of a v3 that a v4 would
immediately partly delete. Ruled 2026-09-08; discussion on #26, #9 and #22.

DROPPED FROM THIS AMENDMENT: the one-week default comment window. The ruling
went further than shortening it.

THE DECISION DEADLINE GOES. Step 3 of "How a QEP is decided" is struck and the
acceptance trigger becomes "no objection is outstanding" rather than a date —
lazy consensus with no clock, so a QEP nobody objects to still lands without
needing the lead, and nothing is accepted by the mere passage of time. Roles,
the Summary's "clear deadline" promise, and the README's Proposing steps all
follow.

The evidence is recorded under Alternatives considered: on 2026-09-08 none of
the four open QEP pull requests had a live deadline — #8 had never set one in
47 days, #13's and #23's had passed, #18's was deliberately deferred — while
nothing in CI ever read a PR description. The field was required by this
document and checked by nothing. Enforcing it in CI was considered and
declined: it would have turned three open PRs red for a rule they predated.

THE README INDEX IS GENERATED, post-merge from frontmatter and ordered by
number, so a PR carries no row of its own and two QEP PRs cannot collide on one
line of one table. The mechanism shipped ahead of this amendment in #30,
together with the ordered-list check; Automation now names both, and a stale
index is a warning rather than a failure. Numbering states what already
happened informally: a number is reserved when its draft PR opens, released if
that PR closes unmerged, so index gaps are normal while drafts are open.

A DOWNSTREAM QEP CARRIES ITS UPSTREAM AMENDMENTS — #9's sentence, widened by
the case it did not anticipate. Where the superseded standard is not itself a
QEP, the Adoption section must name the contract, the obligation and a date by
which the handover completes: QEP-6 asserts precedence over an external tracker
contract with no date on it, and the qe skills depend on that sentence at
runtime. Closes #9.

Also brings the branch up to date with main, which had moved on by QEP-3's
merge (this branch predated it, so it carried neither the file nor its index
row).

Verified green under both the pre-#30 checks on this branch and #30's new ones,
including the ordered-list rule over the rewritten Adoption entry.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Hwm5shrGXmaq4r3Lp9kS33
…tion 1-5

The Draft repairs ruled on 2026-09-08, from the two field reports on this PR
and a review of all four dashboard projects. The comment window has not opened
and there are no reviews on this PR, so every edit here is a free Draft edit:
no version, no window reset.

SECTION 4, THE PHASE GATE. The clause that sent phase-level gates to the body
"because no object represents a phase" is what produced six uncarried
orderings across two conformant trackers. The dependency graph is
many-to-many, which is enough: the first item of the waiting phase is blocked
by every item of the phase it waits on. Linear in the upstream phase rather
than a cross-product, it publishes how many upstream items are still open, and
it clears when the PHASE closes rather than when the upstream tracker closes.

The alternatives were checked against the live graph rather than reasoned
about. A tracker-to-tracker edge over-parks: section 4 says it asserts nothing
in the blocked project may start, and status-projects#89's Decide phase is
being worked now. A single tail edge under-carries: of #69's five Build items,
#76 and #77 both report blocking 0 and the five have no chain between them, so
closing the tail implies nothing about the rest.

SECTION 4, THE ITEM EDGE. Made explicit that an item-level constraint is a
native edge whether or not the two items share a project (FR-2's first half) —
a producer read the gate paragraph's "cross-project" as covering item edges and
wrote three of them as prose.

SECTION 4, THE DECISION GATE. Where a phase's exit criterion is a single
Decision closing, the gate is a decision gate: the object exists, so each item
that waits carries the edge to it (FR-1). Both producers read section 2 and
section 4 as pointing different ways here and both chose the body.

SECTION 4, THE BACK-POINTER IS STRUCK. Blocked-by and blocking are two ends of
one edge — verified live, #73 reports blocking 1 while #94 reports blocked_by 3
— so the waited-on project needs no back-pointer to stay in step. No qe skill
writes a dependency edge at all, so the obligation had zero producers and a
free platform inverse: it will be missed every time, and was. A Related work
line stays available prose in section 7, not an obligation.

SECTION 1. Decision children are compatible with either homogeneous kind, a
closed-completed Decision counts toward progress like any child, and a
consumer may render decisions apart (FR-3). Two of eleven and two of nine
children on the reviewed trackers are decisions, and the Themes programme
tracker carries seven beside four project trackers.

SECTION 8. "No producer or consumer reads programme membership as structure"
stops being true the day the dashboard's programme read ships, so it now
separates the producer duty from a consumer's observation: observing a front
door creates no duty on any tracker and no third tier.

APPENDIX A. Its Gates line restated both struck rules verbatim, and it is the
text producers copy — so it changes in the same commit, as the field report
asked.

ADOPTION IS RENUMBERED 1-5. The source read 1., 2., 2., 3., 4.; Markdown
renumbers on render, so the published document showed 1-5 while every external
"clause N" citation after the first was off by one. Clause 4 also gains FR-4's
obligation: re-stamp the section in the same turn as any change to the list,
because the phase table is an undated claim outside the one section whose
contract is that its claims are re-verified on update, and it went stale within
a day of a re-plan.

FRONTMATTER gains related: [2] with the matching header-table row, which
check.mjs has always enforced as a pair and which this QEP — the one that
reasons most explicitly about another — did not carry.

THE README INDEX ROW IS REMOVED rather than merged. This branch predated
QEP-3's merge and both inserted a row after QEP-2's, which is what made the PR
unmergeable. Under the generated-index rule the row is derived from
frontmatter, so stripping it returns README to its base content and the merge
with main is clean. Note the consequence: until #30 lands, this branch's own
check.mjs still requires a row per QEP file, so CI here is red until then.
That ordering is deliberate.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Hwm5shrGXmaq4r3Lp9kS33

Copy link
Copy Markdown
Collaborator Author

Draft repairs pushed — 0907a70

Ruled 2026-09-08, from the two field reports on this PR plus a review of all four dashboard projects. The comment window has not opened and there are no reviews here, so every edit is a free Draft edit: no version, no window reset.

§4 — the phase gate is a conjunction

The clause that sent phase-level gates to the body "because no object represents a phase" is what produced six uncarried orderings across two otherwise-conformant trackers. blockedBy is many-to-many, which is enough: the first item of the waiting phase is blocked by every item of the phase it waits on. Linear in the upstream phase rather than a cross-product; publishes how many upstream items are still open; and it clears when the phase closes rather than when the upstream tracker closes.

The alternatives were checked against the live graph, not reasoned about:

Alternative Why it fails
Tracker-to-tracker edge §4 itself: it asserts nothing in the blocked project may start. status-projects#89's Decide phase is being worked now, so it would be false
Single tail edge Of #69's five Build items, #76 and #77 both report blocking: 0 and the five have no chain between them — closing the tail implies nothing about the rest
A new gate object Fails on cost, and on §1: a gate is not a work item, so it distorts the progress denominator

§4 — three more changes

  • The item edge is explicit. An item-level constraint is a native edge whether or not the two items share a project (FR-2's first half). A producer read the gate paragraph's "cross-project" as covering item edges and wrote three of them as prose.
  • The decision gate. Where a phase's exit criterion is a single Decision closing, the gate is a decision gate — the object exists, so each waiting item carries the edge to it (FR-1). Both producers read §2 and §4 as pointing different ways and both chose the body.
  • The back-pointer obligation is struck. Blocked-by and blocking are two ends of one edge — verified live, #73 reports blocking: 1 while #94 reports blocked_by: 3 — so the waited-on project needs nothing to stay in step. And no qe skill writes a dependency edge at all, so the obligation had zero producers and a free platform inverse. §7's gated by line stays available prose rather than an obligation the standard leans on.

§1, §8 and Appendix A

  • §1Decision children are compatible with either homogeneous kind; a closed-completed Decision counts toward progress like any child; a consumer may render decisions apart (FR-3).
  • §8"No producer or consumer reads programme membership as structure" stops being true the day the dashboard's programme read ships, so it now separates the producer duty from a consumer's observation: observing a front door creates no duty on any tracker and no third tier.
  • Appendix A — its Gates: line restated both struck rules verbatim, and it is the text producers copy, so it changes in the same commit as the field report asked.

Editorial

  • Adoption is renumbered 1–5. The source read 1., 2., 2., 3., 4.; Markdown renumbers on render, so the page showed 1–5 while every external "clause N" citation after the first was off by one. Clause 4 also gains FR-4's obligation: re-stamp the section in the same turn as any change to the list.
  • related: [2] and the matching header-table row. check.mjs has always enforced these as a pair, and this QEP — the one that reasons most explicitly about another — carried neither.

The README conflict is gone, and how

mergeable_state was dirty on one line: this branch predated QEP-3's merge and both inserted a row after QEP-2's. The row is removed rather than merged. Under the generated-index rule (#30) it is derived from frontmatter, so stripping it returns README to its base content and the merge with main is clean — which it now is; main is merged in and QEP-3 arrives with it.

One deliberate consequence: until #30 lands, this branch's own check.mjs still requires a row per QEP file, so CI here is red with README index has no row for QEP-6. That is the expected ordering, not a defect — #30 first.

Verified

Check Result
This branch's pre-#30 check.mjs fails on the missing index row — expected, see above
#30's check.mjs passes, with the stale-index warning
#30's ordered-list rule passes — it previously reported line 364 against line 349, which is the Adoption defect this commit fixes
check-labels.mjs passes

FR-5 is deliberately not in the document: the ordering-evidence sample belongs in the comment window's own statement, not in the standard. It is recorded in my earlier field report above.


Generated by Claude Code

claude and others added 2 commits September 8, 2026 11:39
…; Adoption 4 names its discharging item

Three repairs from the adversarial review of the 2026-09-08 rulings.

§4 states the test that decides whether an ordering is an edge at all:
output, not order. An edge is written where the downstream item cannot
start without something the upstream produces; two items that touch the
same file or will be worked in sequence are plan order, and stay with the
body's sequencing rationale. The same test decides what a gate is — a
phase-level gate is a real constraint by definition, a phase-level
preference is not a gate. The case study that prompted it: #89's "Build
waits on #69's Build" was coordination written as a gate, and the
conjunction was about to carry it. Appendix A's Gates line follows.

§8 no longer says a consumer "may observe" a programme's front door —
that is QuantEcon/status-projects#10's open question and this QEP has no
business answering it. The scope keeps what is its own: no programme tier
in the grammar, no duty on a tracker from being listed.

Adoption clause 4 names the item that discharges the tracker-contract
handover, QuantEcon/status-projects#114, in place of an open-ended "until
that contract's planned handover" — the form QEP-1 v3 requires for a
precedence clause over an external standard.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Hwm5shrGXmaq4r3Lp9kS33
QEPs are the source of truth and are independent of every repository: a
downstream consumer adapts to a QEP, and the QEP owes it nothing back.
The dashboard's tracker contract is a consumer that must conform, not a
peer standard this QEP supersedes — so Adoption item 4 no longer asserts
precedence over it, no longer prescribes its handover, and no longer
names a tracking issue in another repository. How each consumer reaches
conformance, and when, is that consumer's own business.

Also drops the citation of QEP-1's cross-standard amendment rule, which
was withdrawn from the v3 amendment in #23; the reasoning
is recorded on #9.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@mmcky

mmcky commented Sep 8, 2026

Copy link
Copy Markdown
Contributor

Adoption item 4: the precedence clause over the dashboard's tracker contract is removed

Pushed in b9f31a1, following the ruling of 2026-09-09 on #23 (reasoning recorded on #9): a QEP is the source of truth and is independent of every repository. A downstream consumer adapts to a QEP; the QEP owes it nothing back.

Under that model docs/contracts/tracker.md is not a peer standard this QEP supersedes — it is a consumer that must conform. So item 4 no longer asserts that this QEP is "authoritative for tracker structure wherever the two disagree", no longer prescribes the shape of that contract's handover, and no longer names QuantEcon/status-projects#114 as the item discharging the obligation. What remains is the plain statement that the skills conform to this QEP, and that how each consumer reaches conformance, and on what schedule, is that consumer's own business.

The citation of QEP-1's cross-standard amendment rule goes with it — that rule was withdrawn from the v3 amendment in #23, so it will not exist to cite. It was the only reference to QEP-1 in this document.

Ownership is now recorded from the other side, in the repo that holds the contract: QuantEcon/status-projects#140. QuantEcon/status-projects#114 stays open there as that repo's own work.

Unrelated and pre-existing: qep-checks fails on this branch with "README index has no row for QEP-6" — identical at 3673475, before this push. That is the add/add collision #30 removes by generating the index from frontmatter.

…QEP's

Item 5 prescribed an edit to another repository's contract and code —
"a one-row contract change plus a sort removal, verified once against a
deliberate re-order on a public tracker" — which is the same overreach
removed from item 4 on 2026-09-09, in a quieter register.

Nothing normative is lost. Section 3 already states the rule for every
consumer: order is an operational property, not a published field; a
consumer that publishes a child list preserves list order, and none may
require, parse, or infer sequence from names. Item 4's closing sentence
generalises the rest — how each consumer reaches conformance, and when,
is that consumer's own business.

The item was also stale. QuantEcon/status-projects ruled the same change
itself on 2026-09-07 in their issue 19: the contract row now reads "list
order, exactly as subIssues returns it", and the collector's sort is gone
rather than rewritten. The consuming repo got there on its own reasoning,
without the QEP obliging it.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@mmcky

mmcky commented Sep 8, 2026

Copy link
Copy Markdown
Contributor

Adoption item 5 is removed

Pushed in 16bd810. Item 5 prescribed an edit to another repository's contract and its code — "a one-row contract change plus a sort removal, verified once against a deliberate re-order on a public tracker." That is the same overreach removed from item 4, in a quieter register: the QEP specifying a consumer's implementation and its verification method.

Nothing normative is lost. §3 already states the rule for every consumer — order is an operational property, not a published field; a consumer that publishes a child list preserves list order, and none may require, parse, or infer sequence from names. Item 4's closing sentence carries the rest: how each consumer reaches conformance, and on what schedule, is that consumer's own business. Adoption is now 1–4.

The item was also stale

QuantEcon/status-projects made the change itself on 2026-09-07, ruled in their issue 19, a day before this branch was last pushed. Their contract row now reads "list order, exactly as subIssues returns it", and ordered_children() in the collector is a pass-through — the sort is gone rather than rewritten. The consuming repo reached the same conclusion on its own reasoning, for a better-stated reason than the QEP gave: a collector that re-sorts makes a conformant tracker and a non-conformant one publish identically, so the standard could never be evaluated from the dashboard.

That behaviour is unguarded by any test, which is a real gap but theirs, not this QEP's — QuantEcon/status-projects#142 now tracks it there.

Where the cross-repo material went

Was in the QEP Now
Precedence over the tracker contract, and its handover item Removed (b9f31a1); ownership recorded in QuantEcon/status-projects#140
The contract amendment and sort removal Removed (16bd810); already done in their issue 19
A regression guard for list order Never in the QEP; QuantEcon/status-projects#142

…al case

Section 3's consumer clause covered one behaviour — preserve list order when
publishing a child list. It now states the principle it was a case of: a
consumer that republishes a tracker presents the structure the tracker
expresses, membership as recorded and in the position the tracker places it,
rather than an arrangement of its own.

The reason is stated with it, and it is the general one: a consumer that
re-sorts or re-groups makes a conformant tracker and a non-conformant one
publish identically, so the standard cannot be evaluated from what is
published. That covers re-grouping as well as re-sorting, and applies to any
consumer rather than to the one this QEP happened to know about.

Names no repository and describes no repository's current behaviour, which is
what Adoption item 5 did before it was removed.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@mmcky

mmcky commented Sep 8, 2026

Copy link
Copy Markdown
Contributor

Follow-up: §3's consumer clause now states the principle

Pushed in 59fa374. Removing Adoption item 5 left the consumer rule stated only as a special case — "a consumer that publishes a child list should preserve list order." That is one behaviour, not the principle behind it, and it left the QEP without a general statement of what a consumer owes a tracker.

§3's closing paragraph now reads:

Order is an operational property, not a published field of the unit. A consumer that republishes a tracker should present the structure the tracker expresses — membership as recorded, in the position the tracker places it — rather than an arrangement of its own. A consumer that re-sorts or re-groups makes a conformant tracker and a non-conformant one publish identically, and the standard cannot then be evaluated from what is published. Order is an attribute of the membership edge and is observable exactly where membership is; no consumer may require, parse, or infer sequence from names.

Three things this gets right that the old pairing did not. It covers re-grouping as well as re-sorting. It applies to any consumer rather than the one this QEP happened to know about. And it carries the reason with the rule — the evaluability argument, which is the strongest case for the rule and was previously only implicit.

It names no repository and describes no repository's current behaviour. That was the defect in item 5: a QEP that records what an external repo does today is stale the moment that repo changes, and item 5 was already stale when it was removed.

mmcky added a commit that referenced this pull request Sep 8, 2026
Records the cross-QEP amendment convention in `AGENTS.md` as author-side
practice, rather than folding it into QEP-1 as #23 originally proposed.
Ruled 2026-09-09; the reasoning is on #9, which this retires.

## Why here and not in QEP-1

QEP-1 already says amend in place and bump `version` — "put the edit in
the PR that needs it" is the mechanical consequence, not a separate
rule. It is author-side judgement of exactly the kind QEP-1's
*Automation* section already delegates to `AGENTS.md`, alongside
substantive-vs-editorial and the commit subject. And `AGENTS.md` is the
document an author actually reads before drafting a QEP, which is where
the convention needs to be to change anything.

The second-instance rule that #9 was waiting on never fired, either:
QEP-2 ↔ QEP-4 is intra-repo and QEP-6 ↔ status-projects is cross-repo —
two problems with one instance each, not two instances of one problem.

## Three paragraphs

The first is the original convention from #9: don't forward-reference a
draft from an accepted QEP, and put the upstream edits in the downstream
QEP's own branch so reference and target land in one commit. Unchanged
in substance — it is how QEP-2 ↔ QEP-4 already works, with the removed
hook wording preserved in the `qep-0004` branch's *Amendments to QEP-2*
section.

The second records the ruling that the convention stops at this repo's
boundary. A QEP is the source of truth and is independent of every
repository: it states the rule, and a consuming repo owns how and when
it conforms. Precedence clauses, handover obligations and tracking-issue
references for another repository do not belong in a QEP — an issue
number in a repo this one does not own is a status pointer that rots,
and a QEP states rules rather than tracking their adoption elsewhere.

The third extends that from pointers to **descriptions**, added after
QEP-6 supplied the worked example. Its Adoption item 5 said the projects
dashboard re-sorts children by issue number and prescribed the remedy —
a one-row contract change, a sort removal, and the test to verify it.
status-projects had already removed the sort on its own reasoning two
days earlier, and for a better-stated reason than the QEP gave. So the
QEP shipped a stale claim *and* an obligation discharged before it was
written, and nothing would have signalled either. What survives instead
is the principle with its reason attached: §3 now says a consumer that
republishes a tracker presents the structure the tracker expresses,
because a consumer that re-sorts or re-groups makes a conformant tracker
and a non-conformant one publish identically. That holds whatever any
consumer does next.

## Already applied

- #23 dropped the QEP-1 amendment; v3 is now three changes.
- #18 dropped QEP-6's precedence clause and cross-repo handover item,
removed Adoption item 5 entirely, and generalised §3's consumer clause
to a principle.
- Ownership is recorded from the other side in
QuantEcon/status-projects#140, and the one thing genuinely missing there
— a regression guard for list-order publishing — is
QuantEcon/status-projects#142.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
mmcky added a commit that referenced this pull request Sep 9, 2026
…cend (#30)

Two mechanical changes and the `AGENTS.md` text that follows from them.
Ruled 2026-09-08; discussion on #26, items 2 and 4. **No QEP text
changes**, so no version question — QEP-1's own *Automation* section
wants a matching edit and that lands with the v4 amendment carrying
#26's other items.

## 1. The README index is generated

`stamp.mjs` previously synced the `Type` and `Version` columns of rows
that already existed. It now **rebuilds the whole table from each QEP's
frontmatter, ordered by number** (`renderIndex`/`buildRow` in
`qeps.mjs`, which read column positions from the table header so a
reordered or extended table needs no code change). `check.mjs` no longer
requires a PR to carry its own row and no longer enforces
`Type`/`Status`/`Version` parity — a stale table is a **warning, not a
failure**.

**Why.** The table is a merge-conflict magnet: four open QEP PRs contend
for rows in one table, and #18 is currently unmergeable on that single
line against QEP-3's row.

**What this does and does not fix.** A branch that *already* carries a
row will still conflict textually — strip the row. But a **mis-resolved
index conflict is now self-healing**, because the post-merge
regeneration restores the table from frontmatter whatever the resolution
did to it. So a QEP that merges out of numeric order slots into position
automatically, and gaps while drafts are open need no later
hand-insertion. That last point is the answer to "what if QEP-6 merges
before QEP-5".

## 2. Ordered-list markers must ascend in source

Markdown **renumbers an ordered list on render**, so a source list
reading `1., 2., 2., 3., 4.` displays as 1–5 while every external
*"clause N"* citation silently shifts by one. QEP-6's Adoption section
is exactly that, and it survived a twelve-amendment review (#19), a
field report and four PR comments.

Fenced blocks are exempt; blank lines do not end a run; a more-indented
line is treated as an item's continuation and a deeper list as
independent.

## 3. `AGENTS.md` follows, in four places

- The index section now says the table is generated and must not be
hand-edited, with the gap and conflict behaviour spelled out.
- *Drafting* and *Accepting* stop telling authors to write a row —
status lives in **two** places in the document, not three.
- A new section: **cite a section by its heading, not its number.**
Inserting §2 into QEP-6 mid-draft renumbered §2–§7 to §3–§8 and forced a
correction onto a ruling that had already cited them; the `qe` skills,
the dashboard's tracker contract and several tracking issues all cite
these.
- *Accepting* also records that a merged QEP may not carry `status:
Draft` — QEP-3 did, for two months (#27, being fixed in #29).

## Verification

Each claim was tested rather than reasoned about:

| Test | Result |
|---|---|
| Generator against the current index | reproduces it **byte-for-byte**
— a no-op on correct input |
| `check.mjs` with QEP-6's file present and no row for it | passes, with
the warning — the relaxation works |
| Monotonic check against the real `qep-0006-project-trackers.md` |
reports line 364 against line 349 — catches the live defect |
| `stamp.mjs` on a correct tree | *nothing to stamp or sync* |
| `stamp.mjs` after deleting QEP-3's row **and** flipping QEP-2's
`Status` to `Draft` | both repaired; tree returns to the committed
content exactly |

`node .github/scripts/check.mjs` → *QEP checks passed.*
`node .github/scripts/check-labels.mjs` → *Label appendix checks passed
(1 companion file(s)).*

## Suggested landing order

Before #18's QEP-6 repairs — it makes that PR's one-line `dirty`
conflict disappear rather than needing a both-rows resolution. The
`check.mjs` condition refusing `status: Draft` on `main` is deliberately
**not** here: it must land after #29, or it fails on QEP-3 itself.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

https://claude.ai/code/session_01Hwm5shrGXmaq4r3Lp9kS33

---
_Generated by [Claude
Code](https://claude.ai/code/session_01Hwm5shrGXmaq4r3Lp9kS33)_

---------

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Matt McKay <mmcky@users.noreply.github.com>
@mmcky

mmcky commented Sep 10, 2026

Copy link
Copy Markdown
Contributor

Field note, 2026-09-10 12:16 AEST — the first live application of §4's output, not order test. On 2026-09-08 a phase-level gate was ruled between two of the dashboard projects in QuantEcon/status-projects (private): one project's Build phase would open when the other's closed, on the ground that the two touch the same files and one agent works them serially. Read against §4 as drafted at this PR's head, that ground is coordination rather than a constraint, and the owner ruled today that the gate is withdrawn to sequencing rationale. The needs between the two projects that survive the test are carried as item-level native edges, each a site item drawing a document a collector item produces; three were written today. Recorded on QuantEcon/status-projects#127, with the question as it stood before the ruling.

Two observations for the draft. The test did real work: it reversed a ruling made the same day under the pre-amendment text, which is the case for the sentence staying. And the reversal turned on the two phrases the original ruling used to justify itself, shared files and serially, which are the two examples §4 already names as non-constraints, so a producer reading §4 first would not have written the gate.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

QEP-2 field report: no type label fits plan/tracking issues

3 participants