I3204 — The backlog's bound is declared once in policy, and every session brief says when the landable backlog is past it
Move the landable-backlog threshold from the MJ_BACKLOG_MAX default in scripts/ci/backlog-check into .ai/repo/policy.yaml, read it in both backlog-check and the session brief, and have the brief's integration section say 'past the bound' from the last recorded observation, without a network call and without refusing anything.
BLOCKED wave 0 · p1 · implementation profile · parallel safe
Blocked. This issue cannot start until milestone:delivery-flow-is-measured is done. The status is derived from that, not declared.
Objective
Move the landable-backlog threshold from the MJ_BACKLOG_MAX default in scripts/ci/backlog-check into .ai/repo/policy.yaml, read it in both backlog-check and the session brief, and have the brief's integration section say 'past the bound' from the last recorded observation, without a network call and without refusing anything.
Why
The owner's repeated demand was that pull requests be processed, not accumulate (c209#0, c220#0); on 2026-09-11 the review asked for one typed policy source for staleness and age thresholds and a cached entry warning (c112#3). Rule project.accumulation-is-measured asks for a threshold that makes growth loud; today the threshold is an environment default of one script. Proposed in ADR 0197 (The backlog is bounded by a declared bound that every session reads at start, and the bound reports rather than refuses) (proposed; it carries no authority until the owner accepts it). Sources: chatgpt-majordomus:c112#3.
Current state
scripts/ci/backlog-check --remote measures the landable backlog against MJ_BACKLOG_MAX (default 10); the brief (apps/majordomus-cli/src/capability/builtin/brief.rs) reports prs brief without any bound; .ai/repo/policy.yaml declares release.floor but no integration bound. The session-start context does not pass through brief.rs: lib/context.sh mj_context_integration calls prs brief and writes no section for a checkout that never observed the forge.
Desired state
policy.yaml declares integration.backlog_max (and the age after which a ready pull request is starving); backlog-check and the brief read it; the brief line reads 'N landable, bound M: past the bound' when exceeded. Rule project.blocking-checks-cheap holds: it is reported, never a refusal.
Scope
- .ai/repo/policy.yaml
- scripts/ci/backlog-check
- apps/majordomus-cli/src/capability/builtin/brief.rs
- apps/majordomus-cli/src/commands/prs.rs
- test/cases/131_backlog_hygiene.sh
- lib/context.sh
Out of scope
- Refusing new work (an open question to the owner)
- Querying the forge at session start
Dependencies
None. This issue is a root of the graph.
What waits on this
Acceptance criteria
- The bound appears in exactly one canonical file and both readers name it
- A recorded observation over the bound makes the brief say so; under it the brief says nothing extra
- A checkout that never observed the forge says the backlog is unobserved, not zero
- The session-start context (lib/context.sh mj_context_integration) writes 'backlog unobserved' for a checkout that never observed the forge when policy declares integration.backlog_max, and writes nothing when no bound is declared, keeping its rule that a repository which does not integrate pull requests grows no section
- The context line and the brief line are the same text, produced by prs brief
Validation
- bash test/run.sh 131_backlog_hygiene
- majordomus prs brief
Evidence required
- case_the_backlog_bound_is_read_at_start
Evidence
None recorded. Every token above needs a command or an artifact behind it before this issue can be completed; narrative is refused.
Timeline
- started
- —
- verified
- —
- completed
- —
Those three fields, the evidence above and the state of the dependencies are all the status is made of. There is no status field to disagree with them.
Canonical record: .ai/repo/project/issues/I3204.yaml. Read it back with majordomus plan show I3204.