Skip to content

feat(planning): terminal commands to set and clear superseded-by-plan ledger rows #6124

Description

@kyle-sexton

Problem

/planning:plan's "Plan changes after the Brief" (plugins/planning/skills/plan/SKILL.md:280-282) has the session edit interview-ledger rows by hand. It sets a row to superseded-by-plan with plan proposes: <new>; was: <old>, then on the user's reply rewrites it as answered with proposal:: <new>; was:: <old>; answer:: accepted: <new>, escaping each value the way surface/exporters.py does. surface/round.py has record-terminal and apply, but they write the page's responses.json, not the markdown register, and many plans run with no page at all. No script edits the register.

Every plan that displaces an answer pays for this. In one multi-workstream effort, four plans in a row (2026-10-03) each needed a throwaway Python script for it (reconfirm_rows.py in one session, ws_u_supersede.py in the next), each re-deriving the escape rules and copying the old resolution into was by hand. A wrong escape breaks the register's parse (the history in #4611 and #5534), and a hand copy can drop part of the old answer without anything noticing.

Proposed fix

Two terminal commands, beside check-open-questions.sh or as round.py subcommands that target the ledger file:

  • supersede --ledger <file> <Q> --proposes <text>: takes the row's current resolution as was itself, escapes through the exporter's own function, refuses a row that is not answered.
  • resolve --ledger <file> <Q> reconfirm|restore [--note <text>]: reconfirm writes the answered proposal::/was::/answer:: form; restore puts back the original row byte for byte.

Both back up the ledger first and print the check-open-questions.sh verdict after. SKILL.md:280-282 then names the commands instead of describing the grammar.

Acceptance

  • supersede then reconfirm on a fixture row produces the text the exporter writes for the same pair, and it round-trips through import-ledger.
  • supersede then restore leaves the ledger byte-identical to the original.
  • check-open-questions.sh counts the row as superseded after supersede and answered after reconfirm.
  • A row containing a literal ;, \ or | survives both paths.

Activity

  1. added
    needs-triageNot yet classified. Floor until a type and one priority tier are set.
    on Oct 3, 2026
  2. kyle-sexton commented on Oct 4, 2026

    @kyle-sexton
    MemberAuthor

    This was generated by AI during triage.

    Decision defaulted: add supersede and resolve as round.py (and round.sh) subcommands that take a --ledger <file> target, not a separate script beside check-open-questions.sh — veto before merge
    Basis: verified, plugins/planning/surface/round.py:2120-2136 already hosts the ledger-facing export-ledger and import-ledger subcommands, and plugins/planning/surface/exporters.py:140 (esc_field) is the escape function the new commands must reuse, importable from round.py directly; a standalone script would have to re-import or re-implement it. Alternative: a standalone script under plugins/planning/scripts/, which only moves the entry point.

    Routing: decision-defaulted, work-class: scoped (C3, feature), priority: medium (every plan that displaces an answer pays for it; hand-written escaping has broken the register's parse before, #4611, #5534). Verified: the plan skill's "Plan changes after the Brief" section has the session hand-edit register rows (plugins/planning/skills/plan/SKILL.md:280-282), and no existing subcommand writes the markdown register: record-terminal and apply write the page's data files. check-open-questions.sh already counts superseded-by-plan as superseded=<n> (plugins/planning/scripts/check-open-questions.sh:42-44).

    Agent Brief

    Type: Feature
    Summary: Ship terminal commands that set a ledger register row to superseded-by-plan and later clear it (reconfirm or restore), so plans stop hand-editing the register.

    Current behavior:
    When a plan displaces an interview answer, the session edits the interview ledger's open-question register by hand: it sets the row to superseded-by-plan with plan proposes: <new>; was: <old>, and on the user's reply rewrites it as answered with proposal:: <new>; was:: <old>; answer:: accepted: <new>, escaping each value as the exporter does. Sessions write throwaway scripts for this, and a wrong escape or a partial copy of the old answer goes unnoticed.

    Desired behavior:

    • supersede --ledger <file> <Q> --proposes <text>: reads the row's current resolution and records it as was itself; escapes every value through the exporter's own escape function; refuses a row whose status is not answered, with a clear error and no write.
    • resolve --ledger <file> <Q> reconfirm|restore [--note <text>]: reconfirm writes the answered proposal::/was::/answer:: form the exporter writes for the same pair; restore returns the row to exactly its pre-supersede bytes. Refuses a row that is not superseded-by-plan.
    • Both commands back up the ledger before writing and print the check-open-questions.sh verdict line afterwards.
    • The plan skill's "Plan changes after the Brief" section names the commands instead of describing the row grammar and escaping rules.

    Key interfaces:

    • round.py / round.sh subcommands supersede and resolve (defaulted placement, see the decision line above).
    • The exporter's field-escape function and the register row grammar it documents; reuse both, do not re-implement.
    • import-ledger, which must read the written rows back.

    Acceptance criteria:

    • supersede then reconfirm on a fixture row produces the same text the exporter writes for that pair, and the ledger round-trips through import-ledger.
    • supersede then restore leaves the ledger byte-identical to the original.
    • check-open-questions.sh counts the row as superseded after supersede and as answered after reconfirm.
    • A row containing a literal ;, \ or | survives both paths.
    • supersede on a non-answered row, and resolve on a non-superseded row, exit non-zero without changing the file.
    • Existing surface and planning script tests pass, with new tests covering the above.

    Out of scope:

    • The page's responses.json flow (record-terminal, apply).
    • Changes to the register grammar or the exporter's escape rules.
    • The Step 5 "Displaced answers and new external effects" block's wording beyond pointing at the commands.
  3. added
    priority: mediumReal value, no hard deadline; normal backlog flow.
    agent-readyFully specified and briefed; eligible for autonomous pickup from the frontier.
    work-class: scopedA briefed fix or small feature; blast radius bounded by the brief, tests exist.
    status: readyTriaged, unblocked, and fully specified; eligible to pick up.
    and removed
    needs-triageNot yet classified. Floor until a type and one priority tier are set.
    on Oct 4, 2026
  4. kyle-sexton commented on Oct 4, 2026

    @kyle-sexton
    MemberAuthor

    This was generated by AI during work-loop.

    Approve this for autonomous dispatch (with its defaulted decision), or keep it for a human?

    Triage marked this decision-defaulted as a feature-shaped C3 (work-class: scoped). The work-loop admission gate human-gates feature-shaped C3 work, so the lane removed agent-ready and applied needs-human. Flip it back through /work-items:attend-queue to dispatch.

    Lane: work-loop, instance melo-worker-1, cycle 2.

  5. added
    needs-humanHuman-in-the-loop required; autonomous sessions must not resolve items carrying this.
    and removed
    agent-readyFully specified and briefed; eligible for autonomous pickup from the frontier.
    on Oct 4, 2026
  6. kyle-sexton commented on Oct 11, 2026

    @kyle-sexton
    MemberAuthor

    Owner decision (2026-10-11): Add supersede and resolve subcommands to round.py, reusing the exporter's escape function.

    Recorded by the coordinating agent session with the owner's approval. Removing needs-human; implementation is queued and will link its branch here.

  7. removed
    needs-humanHuman-in-the-loop required; autonomous sessions must not resolve items carrying this.
    on Oct 11, 2026
  8. kyle-sexton commented on Oct 13, 2026

    @kyle-sexton
    MemberAuthor

    Owner batch-ratified this admission in an attended session on 2026-10-12: work-class: scoped. Rule: class C1-C3, no trust surface, the independent check confirmed the recorded decision, and no owner step remains.

  9. added
    agent-readyFully specified and briefed; eligible for autonomous pickup from the frontier.
    and removed
    agent-readyFully specified and briefed; eligible for autonomous pickup from the frontier.
    on Oct 13, 2026
  10. kyle-sexton commented on Oct 18, 2026

    @kyle-sexton
    MemberAuthor

    Agent Brief

    Type: Feature
    Summary: Add terminal commands that set an interview-ledger register row to superseded-by-plan and later clear it, so plans stop hand-editing the register.

    Current behavior:
    When a plan displaces an interview answer, the session edits the open-question register by hand: it writes superseded-by-plan with plan proposes: <new>; was: <old>, then rewrites the row as answered with proposal:: <new>; was:: <old>; answer:: accepted: <new>, escaping each value as the exporter does. Sessions write throwaway scripts for this, and a wrong escape breaks the register's parse.

    Desired behavior:

    • The round command gains supersede --ledger <file> <Q> --proposes <text>: it takes the row's current resolution as was, escapes through the exporter's own field-escape function, and refuses a row that is not answered.
    • It gains resolve --ledger <file> <Q> reconfirm|restore [--note <text>]: reconfirm writes the answered proposal/was/answer form; restore puts back the original row byte for byte.
    • Both back up the ledger first and print the open-questions check verdict afterwards.
    • The plan skill's 'Plan changes after the Brief' section names the commands instead of describing the grammar.

    Key interfaces:

    • Round command: two new subcommands with the flags above, also reachable through its shell wrapper.
    • Exporter field-escape function: reused, not copied.

    Acceptance criteria:

    • A test shows supersede then reconfirm on a fixture row produces the text the exporter writes for the same pair and round-trips through import-ledger.
    • A test shows supersede then restore leaves the ledger byte-identical.
    • A test shows the open-questions check counts the row superseded after supersede and answered after reconfirm.
    • A test shows a value holding ;, a backslash or | survives both paths.
    • scripts/run-test-file.sh passes on the round test file.
    • A changelog entry or fragment for planning passes scripts/check-changelog-fragments.sh.

    Out of scope:

    • The page surface's responses data and record-terminal.
    • The interview skill's SKILL.md text.

    This was generated by AI during backlog shaping. Held, not admitted: this brief is drafted and checked, but the issue lane would stop on it today. It is admitted, by adding agent-ready, once the lane can run the skill-quality check scripts (Automation Lanes' PR #7912). Held under the owner's 2026-10-18 lane-narrowing course correction.

  11. added
    needs-humanHuman-in-the-loop required; autonomous sessions must not resolve items carrying this.
    agent-readyFully specified and briefed; eligible for autonomous pickup from the frontier.
    and removed
    needs-humanHuman-in-the-loop required; autonomous sessions must not resolve items carrying this.
    on Oct 18, 2026
  12. melodic-automation-lanes commented on Oct 18, 2026

    @melodic-automation-lanes
    Contributor

    The work-resolve-issue run that agent-ready started failed before it reported, or the token broker refused it because its workflow files differ from main's. work-unblock removed and added agent-ready back to start a fresh run on main's workflow files. It does this once per version of those files, so if this run fails the same way, a person looks at it.

  13. added
    agent-readyFully specified and briefed; eligible for autonomous pickup from the frontier.
    and removed
    agent-readyFully specified and briefed; eligible for autonomous pickup from the frontier.
    on Oct 18, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    agent-readyFully specified and briefed; eligible for autonomous pickup from the frontier.priority: mediumReal value, no hard deadline; normal backlog flow.status: readyTriaged, unblocked, and fully specified; eligible to pick up.work-class: scopedA briefed fix or small feature; blast radius bounded by the brief, tests exist.

    Fields

    No fields configured for Feature.

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions