Skip to content

I3763 — A cancelled dependency that names its replacement is satisfied by that replacement, and one that names none is reported

An issue record may declare superseded_by (an issue id), and only beside cancelled true. In both engines a dependency on such an issue is satisfied exactly when its replacement, followed through further replacements, is DONE, and blocked_by names the replacement instead of the cancelled id. A dependency on a cancelled issue that names no replacement still blocks, and plan validate warns cancelled_dependency naming both issues, so a dependent that can never become READY is visible rather than silent.

READY wave 0 · p2 · implementation profile · runs alone

Part of truthful-plan-surfaces — The plan's surfaces are inferred from delivery, and nothing they show is typed beside the repository.

Ready. Every dependency is done, so majordomus plan start I3763 will be accepted.

Objective

An issue record may declare superseded_by (an issue id), and only beside cancelled true. In both engines a dependency on such an issue is satisfied exactly when its replacement, followed through further replacements, is DONE, and blocked_by names the replacement instead of the cancelled id. A dependency on a cancelled issue that names no replacement still blocks, and plan validate warns cancelled_dependency naming both issues, so a dependent that can never become READY is visible rather than silent.

Why

The plan inventory of 2026-10-20 found I0925 (needs I0915), I0926 (needs I0913 and I0924), I0916 (needs I0914) and I0932 (needs I0929 and I0931) BLOCKED for ever on cancelled issues, because only a DONE dependency satisfies one. Nothing reported it, and the only remedy was to rewrite every dependent by hand. A cancellation that moves work elsewhere should carry that move, the way a milestone's superseded_by already does.

Current state

Verified on origin/master 91c0b5d5658. apps/majordomus-cli/src/plan.rs:874-884 counts a dependency satisfied only when it is DONE, and :717-723 never makes a cancelled issue DONE; lib/project.awk:164 is the same rule and :93 reads cancelled. share/schemas/majordomus/issue/issue.v1.schema.json closes its keys (:9, additionalProperties false) and declares no superseded_by, so share/allow/issue.txt, generated from it, has none either, while milestones already declare one (plan.rs:1017, lib/project.awk:236). .ai/repo/project/issues/I0925.yaml:17-18 depends on I0915, which is cancelled true and names no replacement.

Desired state

The issue schema declares superseded_by as an optional string and share/allow/issue.txt is regenerated from it. plan.rs and lib/project.awk resolve each dependency through its replacement chain before the satisfied test, identically; a replacement that is not an issue fails unknown_replacement, superseded_by on an issue that is not cancelled fails replacement_without_cancel, a replacement chain that loops fails replacement_cycle, and an open issue depending on a cancelled issue without a replacement warns cancelled_dependency. Waves follow the same resolved edges. case 99 compares the resolved blocked_by and the new findings over its fixture.

Scope

  • apps/majordomus-cli/src/plan.rs
  • lib/project.awk
  • share/schemas/majordomus/issue/issue.v1.schema.json
  • share/allow/issue.txt
  • test/cases/99_plan_capabilities.sh
  • test/cases/3736_a_cancelled_dependency_is_satisfied_by_its_replacement.sh
  • docs/PLANNING.md
  • docs/PLAN_STATUS.md
  • docs/generated
  • site/data/generated
  • .ai/repo/project/issues/I3763.yaml

Out of scope

  • Repointing or cancelling the existing dependents of cancelled issues; those are records
  • Treating a cancelled dependency without a replacement as satisfied
  • A replacement for a milestone, which superseded_by already gives

Dependencies

None. This issue is a root of the graph.

Acceptance criteria

  • An issue depending on a cancelled issue whose replacement is DONE is READY in both engines
  • Negative: an issue depending on a cancelled issue whose replacement is not DONE is BLOCKED, and blocked_by names the replacement, not the cancelled id
  • Negative: an issue depending on a cancelled issue with no replacement stays BLOCKED and plan validate warns cancelled_dependency naming both ids
  • superseded_by on an issue that is not cancelled, a replacement that is not an issue and a replacement chain that loops each fail plan validate by name in both engines
  • case 99 agrees on statuses, blocked_by and findings over a fixture holding each of these

Validation

  • env -u MAJORDOMUS_SHARE -u MAJORDOMUS_HTTP_HOST -u MJ_ROOT bash test/run.sh 3736_a_cancelled_dependency_is_satisfied_by_its_replacement 99_plan_capabilities
  • cargo test --manifest-path apps/majordomus-cli/Cargo.toml --lib plan::tests
  • majordomus plan validate

Evidence required

  • cancelled_dependency_is_satisfied_by_its_replacement
  • cancelled_dependency_without_replacement_is_reported

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/I3763.yaml. Read it back with majordomus plan show I3763.

Searches the titles and descriptions of every page this site publishes.