Skip to content

feat(auto-pm): implement a plan's own consensual quick-wins (#1334) - #1336

Merged
suleimansh merged 1 commit into
mainfrom
suleimansh/feat/1334-autonomous-quick-wins
Jul 28, 2026
Merged

feat(auto-pm): implement a plan's own consensual quick-wins (#1334)#1336
suleimansh merged 1 commit into
mainfrom
suleimansh/feat/1334-autonomous-quick-wins

Conversation

@suleimansh

Copy link
Copy Markdown
Member

Closes #1334

What

Closes the loop between "a new GitHub issue" and "an agent implements it". Three links were missing.

1. Nothing refilled the ticket set. update-tickets (#1208) existed as a button but was not in the rotation, so the routine eventually triaged and planned a set nothing ever added to. It now leads AUTO_PM_JOBS. Safe to repeat: the preset resumes from tickets/meta.json's lastImportedAt and reconciles, so a firing with nothing changed is a no-op.

2. [Spike & plan] recorded no verdict. Its prompt covered "the most important tickets that have no spike or plan yet" and stopped there. It now covers every ticket without a plan, and ends each one with two keys in the plan file's header:

Effort: quick-win/significant
Consensus: consensual/open-questions

3. Nothing carried the verdict onto the queue. New planned-quick-wins.ts: a plan marked Effort: quick-win and Consensus: consensual puts its ticket on TODO_AGENTS.md, under the ticket's own priority heading, and the existing drain implements it.

Why the promotion is code, not another routine

The plan already made the judgement. Spending a subscription turn on an agent that reads the same ticket to reach the same conclusion is exactly the waste the quota boundary (#879) exists to prevent. Reading two keys and appending a line needs judgement from nobody.

The daemon writes it, never the agent, for the reason queue-promote.ts gives: runs stay sandboxed in their worktrees with no write access to the checkout.

Safety

  • Fails closed, and demands both keys explicitly (the quotaHeadroom polarity). A plan that forgot to say, or said something this version does not recognize, means a human decides rather than an agent starting.
  • Only the header is parsed (everything above the first ##), so a plan that discusses quick wins in its prose cannot declare itself one.
  • The prompt tells the planner what the pair costs: marked that way, it is implemented unattended with nobody reading it first. A plan with ## Hard problems or ## Variability is never a quick-win.
  • A dirty queue file stands the whole pass down, as promoteQueue does. Closed tickets, missing ticket files and already-queued tickets are skipped.
  • Insertion is additive by construction, like landPinnedEntry: one line, never a reorder or a removal.

Bug found while wiring it

todoPriorityForTicket mapped only the ticket format's words (urgent/high/low), but the format specifies Priority: 10-0 and all 34 tickets in this repo write a number. Every one of them fell through to the default 5, so a queued ticket landed at the middle priority whatever it said. Numbers are now taken at their word.

Placement is correctness rather than tidiness here: parseTodoEntries returns entries in file order and the drain takes the first, so an entry appended to the end of the file would be the last thing ever worked, which is the opposite of what this ticket asks for.

Tests

Framework suite 1545/0 (1 skipped). New planned-quick-wins.test.ts covers the verdict parse, the fail-closed policy, priority placement and section creation, and the promotion pass end to end.

Revert-proven, twice:

  • reverting the numeric-priority fix alone fails reads the title, the numeric priority and the status and places each ticket by its own priority
  • moving the promotion to after the queue read fails a plan promoted this tick is drained this tick, not the next one (a plan landing between ticks would otherwise wait out a full cooldown)

Note for review

The prompt half is yours if you want it worded differently. The two key names and the fail-closed rule are the contract the code reads, so those are the parts worth arguing about.

Closes the autonomy loop. Three links were missing between "a new GitHub
issue" and "an agent implements it":

- Bringing tickets across from GitHub was a button nobody pressed on a
  schedule, so the rotation eventually triaged and planned a set that
  nothing refilled. `update-tickets` now leads the rotation; it resumes
  from `tickets/meta.json` and reconciles, so repeat firings are no-ops.
- [Spike & plan] covered "the most important" tickets and recorded no
  verdict. It now covers every ticket without a plan and ends each one
  with `Effort:` and `Consensus:` keys in the plan's header.
- Nothing carried that verdict onto the queue. `planned-quick-wins.ts`
  does: a plan marked `quick-win` + `consensual` is queued by the daemon
  under the ticket's own priority heading, and the drain implements it.

No agent turn is spent re-deciding what the plan already decided, which
is why the promotion is code rather than another routine. It fails
closed and demands both keys explicitly: a plan that says nothing, or
something unrecognized, is left for a human.

Also fixes `todoPriorityForTicket`, which mapped only the ticket format's
words while every real ticket writes a number, so every queued ticket
landed at the default 5 regardless of what it said.
@suleimansh suleimansh self-assigned this Jul 28, 2026
@suleimansh
suleimansh marked this pull request as ready for review July 28, 2026 14:54
@suleimansh
suleimansh merged commit 31da5d7 into main Jul 28, 2026
2 checks passed
@suleimansh
suleimansh deleted the suleimansh/feat/1334-autonomous-quick-wins branch July 28, 2026 14:54

Body:
```md
Effort: quick-win/significant

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

We already have https://github.com/gemstack-land/gemstack/blob/568a126878a92db864025e07550f0a9993ee44ea/packages/the-framework/prompts/ticketing_format.md#L54-L54

Let me think of a clean way to do this.

I think it's important to be as clear as possible in what we tell agents.

Body:
```md
Effort: quick-win/significant
Consensus: consensual/open-questions

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

We already have the concept of "variability" in the system prompt. Maybe we can (and should?) re-use that concept.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I'll think about this.

```

The two header keys are the plan's verdict on its own ticket, and they are read by the machine:
- `Effort`: is implementing this a small, contained change (`quick-win`) or not (`significant`)?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This line has zero added value, it's noise that wastes the context window.

[optional: more info (any heading and format you want)]
```

The two header keys are the plan's verdict on its own ticket, and they are read by the machine:

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I guess that line was generated by AI? That's AI slop right there. It's babbling, eating precious context window, and actually adds confusion leading to less reliable agent output.

- `Effort: quick-win` when implementing it is a small, contained change, `Effort: significant` otherwise.
- `Consensus: consensual` when there is a single fairly obvious plan (zero open questions, zero variability), `Consensus: open-questions` otherwise.

A plan marked `Effort: quick-win` and `Consensus: consensual` is queued and implemented unattended, without anyone reading it first. So write that pair only when you would be comfortable with that happening. Anything you would want a human to look at first is `Consensus: open-questions`, and a plan carrying a `## Hard problems` or `## Variability` section is never a quick-win.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

is queued and implemented unattended, without anyone reading it first.

That isn't DRY at all — it breaks the #1 rule of maintainable code. That's brittle and will hurt us very bad in the long haul. We should NEVER let something like this pass through. This PR should never have been merged.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

All ticketing format should be maintained in ticketing_format.md.

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Goal: let TF fully *autonomously* work on quick-wins

2 participants