Skip to content

Plan integration follow-on (D-E): age-aware nudge and a learner-issued retire/snooze for an overdue item #26

Description

@NetDevAutomate

Origin

  • Owner decision D-E (docs/architecture/plan-integration/HANDOFF-2026-09-16.md §2): "an overdue item unrelated to the plan must not sit as an alternate indefinitely. Fact: due score already grows +1/day (cap +30), so it overtakes the +12 bias in ~2 weeks; missing are an age-aware nudge line and a retire/snooze action for a due card (only backlog topics can be resolved today)."
  • Evidence: rubric row 2 (receipts/now-rubric-2026-09-16.md), owner verdict yes — clear the overdue review first — with the note that an unrelated overdue item must be proposed explicitly or be retirable by the learner.
  • Full proposal, written from the code on main a5b9f903: proposals/2026-09-16-overdue-nudge-and-retire.md. Follows on from Integrate Study Plans across Now, Web architect, and MCP #7 (plan integration); not a blocker of Integrate Study Plans across Now, Web architect, and MCP #7.

What exists today (read from the code)

  • A due item is a study_progress row whose last_seen reaches an interval in REVIEW_INTERVALS (history/progress.py: 1, 3, 7, 14, 30 days); a struggling row is always due. There is no next_review column and no "not due" state — a row stays due, and stays a now candidate, until it is studied again (record_progress) or deleted.
  • learning/decision.py scores a due candidate 100 + min(days_ago, 30) (+35 struggling, +15 learning); a plan-related candidate adds PLAN_RELATED_BIAS = 12. An unrelated item overtakes a plan-related one on age alone after ~2 weeks — silently: nothing tells the learner why it moved up, and nothing offers "I have moved on from this".
  • resolved exists only for parked backlog topics (record_topic_progress(confidence="resolved") → parking.resolve_parked_topic), not for study_progress rows. The Today card and CLI now have no control on a due item.

What to build

Two additions on the existing candidate — no new ranking rule.

  1. Age-aware nudge line. When an eligible due candidate is unrelated to every matchable plan and days_ago ≥ threshold, with the threshold derived from the constants (the smallest days_ago at which min(days_ago, 30) ≥ PLAN_RELATED_BIAS plus the plan-related candidate's own age — no second constant, so it moves with D-D), the candidate carries a nudge line: "Overdue 16 days and unrelated to your plan — do it, or retire it: studyloop review retire <topic> <concept>." Rendered where item 4's completion-review evidence lines render (CLI now beneath the action, Today card beside it, MCP payload as an additive key). A fact about age, not a proposal to rank differently.

  2. Retire / snooze door for a due item, through the seam every surface uses:

Door Meaning Mechanism Undo
retire "done with this concept for now" retired_at timestamp on the study_progress row (or a confidence value the due predicate excludes — decided at RED with the migration); no longer due; history kept; gone from every consumer of spaced_repetition_due (now CLI/Today/MCP get_next_action, recap, studyloop review, the plan evaluation's due count) record_progress on the concept clears it
snooze "not this week" snoozed_until date; not due before it; normal intervals after expiry, or explicit un-snooze

Exposed like the plan lifecycle: a CLI verb (studyloop review retire|snooze), a Today-card control on the due item, one MCP tool beside record_study_progress (the mirror of record_topic_progress(confidence="resolved") for cards).

Constraints:

  1. Learner-issued only — nothing retires or snoozes on the learner's behalf (the nudge proposes, the learner decides; same shape as item 4's consensual close).
  2. History kept — excluded from the due set, never deleted; get_study_history and unverified_milestones still see it.
  3. Plan-aware, not plan-bound — the nudge fires only for items unrelated to every matchable plan; a plan-related overdue item is the plan's business (item 4's closing review counts it).
  4. Golden unchanged — the no-plan golden has no due items; the nudge is an additive key on a due candidate.
  5. Threshold derived, not a new constant.

Out of scope

  • REVIEW_INTERVALS and how days_ago is computed.
  • Reranking — the overtaking-on-age behaviour is correct (row 2); what is missing is the explanation and the exit.
  • Flashcard/quiz card_reviews (a different store with its own SM-2 scheduler in review_db.py); a retire door for those is a separate ticket if wanted.

Acceptance criteria

  • RED: a due unrelated item past the derived threshold carries the nudge line on CLI, Today and MCP; a plan-related one does not; one below the threshold does not.
  • RED: retire removes the row from the due set and from now candidates, keeps its history row, and record_progress on the same concept clears it; snooze excludes it until the date and not after.
  • The migration lives in agent_session_tools.migrations and the clean-rebuild closure classifies the new column/state (the 2026-09-12 rebuild caught two tables the migrations did not create; do not repeat that).
  • Golden now_plan_no_active.json byte-identical; test_docs_plan_integration_contract.py green with the doc sentence added to docs/study-plans.md "Plan-aware now" and docs/cli-reference.md.
  • A D-16 rubric row: row 2's world advanced 16 days; the owner asked whether the nudge line is one they would act on.

Blocked by

  • Nothing. Independent of D-D (the threshold derivation is written so it follows D-D's derived bias when that lands).

Definition of Done

  • Full unit suite green; just lint; just typecheck.
  • Council review of the RED and the arbitration before merge (one commit per accepted finding).
  • Docs, CLI reference and MCP/CLI specs updated in the same change.

Activity

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

    ready-for-agentImplementation-ready specification with settled requirements and test seams

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions