Skip to content

adopter-upgrades — An adopting repository survives a Majordomus upgrade, and what the tool vendors into it is adopter-neutral

An adopter can upgrade the tool, or vendor its rules, and be told exactly what to migrate before anything refuses its commits. The migration is a command, not a hand replay. What the tool writes into an adopter (rules, skeleton, scope, candidates) is neutral to this repository and keeps a PR-only trunk clean.

ACTIVE 14 of 20 issues done

ready
4
blocked
2
active
0
verify
0
done
14
cancelled
0

Problem

A downstream repository, OSCILLA, audited on 2026-10-04 against v0.13.0 (e08aec8651), shows the tool breaking its adopters in ways no test in this repository sees, because every test here runs this repository's own layout. Installing 0.12.0 machine-wide made doctor report 433 failures in OSCILLA: unsealed plan stamps and use-case steps reclassified as state-mutating. Its pre-commit hook runs doctor, so every commit was refused until the layer was migrated by hand, and the migrated layer is then rejected by 0.10. Nothing records which tool version a layer was written for, and migrate handles only .majordomus to .ai. Live use-case scenarios refuse read-only knowledge subcommands while admitting check --checkpoint, which writes. Upgrading the vendored rules leaves the policy and source keys they depend on behind. The knowledge deriver writes untracked candidates onto a trunk that only pull requests change. The vendored rules and the init skeleton carry this repository's narrative, test paths and stack.

Outcome

An adopter can upgrade the tool, or vendor its rules, and be told exactly what to migrate before anything refuses its commits. The migration is a command, not a hand replay. What the tool writes into an adopter (rules, skeleton, scope, candidates) is neutral to this repository and keeps a PR-only trunk clean.

Current state

At e08aec8651 the manifest and policy name no tool or layer version. SEALED_FROM is one global constant (lib/project.awk:45, plan.rs:122). share/commands.yaml classes each top-level command once. lib/migrate.sh moves only .majordomus/. docs/INSTALL.md says only to re-run the installer to upgrade. The knowledge deriver writes .ai/repo/knowledge/candidates/ in whichever checkout closes an episode. The rule package manifest says source_revision 0.6.0.

Desired state

doctor separates version-skew findings from defects and names the migration that clears them. migrate carries a layer from one version to the next, including re-sealing old plan stamps with their original times. The effect class is judged per subcommand and flag. rules vendor update reports or applies the skeleton keys the new rules need. Candidates never dirty a trunk. Vendored rules and the init skeleton say nothing that is only true of this repository.

Scope

  • .ai/repo/project
  • lib
  • share
  • apps/majordomus-cli/src/plan.rs
  • docs
  • test/cases

Out of scope

  • OSCILLA itself: it is the evidence, read only
  • Fixes already in flight: #780-#784, fix/context-resolves-a-path-not-yet-created, #746 and 9030dc4795
  • Accepting any ADR these issues propose; acceptance is the owner's act

Acceptance criteria

  • Upgrading the tool over a layer written by the previous minor version yields a doctor report that names version skew and the migration command, not defects; proven by the case I1980 adds
  • A live use-case scenario may run a read-only subcommand of a command that also writes, and may not run a writing flag of a read-only command; proven by the case I1981 adds
  • Every issue of this milestone is DONE or CANCELLED with its reason

Validation

  • bin/majordomus plan validate
  • bin/majordomus usecase validate
  • scripts/derive-check

Evidence required

  • version_skew_is_named
  • effect_class_per_subcommand

Issues

Each one is an execution contract with its own acceptance criteria, validation command and required evidence. The wave column is the layer of the dependency graph it sits in.

issuestatuswavedepends ontitle
I1980 READY 0 — A layer names the tool version it was written for, and doctor tells version skew from defects
I1981 DONE 0 — A command's effect class is declared per subcommand and flag, and live scenarios judge the whole argv
I1982 BLOCKED 1 I1980 Plan stamps written before seals existed are re-sealed by a command that keeps their original times
I1983 BLOCKED 1 I1980 Upgrading the vendored rules reports or applies the policy and source keys those rules depend on
I1984 DONE 0 — Knowledge candidates never leave untracked files on a trunk that only pull requests change
I1985 DONE 1 I1984 A knowledge candidate relates to its own decision and commit, not to the whole episode
I1986 DONE 0 — The vendored rule package says nothing that is only true of this repository
I1987 DONE 0 — A knowledge record's file provenance survives the file's deletion
I1988 READY 1 I1981 A use case's setup scripts live where the adopter declares, and its scenarios may run the adopter's own commands
I1989 DONE 0 — init seeds a scope for the stack it finds, not for this repository's
I1990 READY 0 — The pre-push check judges the refs being pushed, or says why the checkout's task binds them
I1991 DONE 0 — A comment-only edit of the policy regenerates no bootstrap
I1996 DONE 0 — doctor does not fail an adopter on a check written for this repository
I1998 DONE 0 — A health command in an unsupervised repository does not exit 0
I1999 READY 0 — A tracked file a hook regenerates does not refuse a task that never touched it
I2464 DONE 0 — A path that holds a space is one path to the scope doctrine
I2491 DONE 0 — A personal layer changes nothing shared: init --personal and install.sh --personal keep the layer one person's own, verify it, and --shared hands it to the team
I2849 DONE 0 — release next raises from the trunk the repository names, never from a branch name written in the tool
I2941 DONE 0 — A fresh init leaves doctor clean: a README that does not name AGENTS.md gains one paragraph that does
I2942 DONE 0 — An installer dry run changes nothing, and the install guide says only what is true

The graph

adopter-upgrades dependency graphfrom .ai/repo/project
flowchart LR
    I1980["I1980<br/>A layer names the tool version it was written for, and doctor tells version skew from defects"]:::ready
    I1981["I1981<br/>A command's effect class is declared per subcommand and flag, and live scenarios judge the whole argv"]:::done
    I1982["I1982<br/>Plan stamps written before seals existed are re-sealed by a command that keeps their original times"]:::blocked
    I1983["I1983<br/>Upgrading the vendored rules reports or applies the policy and source keys those rules depend on"]:::blocked
    I1984["I1984<br/>Knowledge candidates never leave untracked files on a trunk that only pull requests change"]:::done
    I1985["I1985<br/>A knowledge candidate relates to its own decision and commit, not to the whole episode"]:::done
    I1986["I1986<br/>The vendored rule package says nothing that is only true of this repository"]:::done
    I1987["I1987<br/>A knowledge record's file provenance survives the file's deletion"]:::done
    I1988["I1988<br/>A use case's setup scripts live where the adopter declares, and its scenarios may run the adopter's own commands"]:::ready
    I1989["I1989<br/>init seeds a scope for the stack it finds, not for this repository's"]:::done
    I1990["I1990<br/>The pre-push check judges the refs being pushed, or says why the checkout's task binds them"]:::ready
    I1991["I1991<br/>A comment-only edit of the policy regenerates no bootstrap"]:::done
    I1996["I1996<br/>doctor does not fail an adopter on a check written for this repository"]:::done
    I1998["I1998<br/>A health command in an unsupervised repository does not exit 0"]:::done
    I1999["I1999<br/>A tracked file a hook regenerates does not refuse a task that never touched it"]:::ready
    I2464["I2464<br/>A path that holds a space is one path to the scope doctrine"]:::done
    I2491["I2491<br/>A personal layer changes nothing shared: init --personal and install.sh --personal keep the layer one person's own, verify it, and --shared hands it to the team"]:::done
    I2849["I2849<br/>release next raises from the trunk the repository names, never from a branch name written in the tool"]:::done
    I2941["I2941<br/>A fresh init leaves doctor clean: a README that does not name AGENTS.md gains one paragraph that does"]:::done
    I2942["I2942<br/>An installer dry run changes nothing, and the install guide says only what is true"]:::done
    I1980 --> I1982
    I1980 --> I1983
    I1981 --> I1988
    I1984 --> I1985
    classDef done stroke:#16a34a,fill:#dcfce7,color:#14532d,stroke-width:2px
    classDef active stroke:#2563eb,fill:#eff6ff,color:#1e3a8a,stroke-width:2px
    classDef verify stroke:#7c3aed,fill:#f5f3ff,color:#4c1d95,stroke-width:2px
    classDef ready stroke:#0891b2,fill:#ecfeff,color:#164e63,stroke-width:2px
    classDef planned stroke:#0891b2,fill:#ecfeff,color:#164e63,stroke-width:2px
    classDef blocked stroke:#b45309,fill:#fffbeb,color:#78350f,stroke-width:2px
    classDef cancelled stroke:#6b7280,fill:#f9fafb,color:#374151,stroke-width:2px
    classDef superseded stroke:#6b7280,fill:#f9fafb,color:#374151,stroke-width:2px

Canonical record: .ai/repo/project/milestones/adopter-upgrades.yaml. Read it back with majordomus plan show adopter-upgrades.

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