plan.transition
Zaznamenat, že provádění úkolu začalo (`start`), že implementace je dokončena a čekají se důkazy (`verify`), nebo že je hotovo (`done`). Označí se jedno pole vlastního záznamu úkolu, pečeť jeho události se zapíše vedle něj a událost se připojí do ledgeru; razítko bez té pečeti nepohne žádným stavem. Přesun se odmítne, když model říká, že je nepřípustný — úkol, který není READY, nemůže začít, ten, který nikdy nebyl ACTIVE, nelze ověřit, a ten, který nebyl nikdy zahájen, jehož závislosti nejsou dokončené nebo kterému chybí požadované důkazy, nelze dokončit — a odmítnutí pojmenuje, co v cestě stojí. Stav, který se vrátí, se potom odvozuje ze záznamu, ne z přesunu: `done` s chybějícími důkazy nechá úkol ve VERIFY a řekne to.
Zaznamenat, že provádění úkolu začalo (`start`), že implementace je dokončena a čekají se důkazy (`verify`), nebo že je hotovo (`done`). Označí se jedno pole vlastního záznamu úkolu, pečeť jeho události se zapíše vedle něj a událost se připojí do ledgeru; razítko bez té pečeti nepohne žádným stavem. Přesun se odmítne, když model říká, že je nepřípustný — úkol, který není READY, nemůže začít, ten, který nikdy nebyl ACTIVE, nelze ověřit, a ten, který nebyl nikdy zahájen, jehož závislosti nejsou dokončené nebo kterému chybí požadované důkazy, nelze dokončit — a odmítnutí pojmenuje, co v cestě stojí. Stav, který se vrátí, se potom odvozuje ze záznamu, ne z přesunu: `done` s chybějícími důkazy nechá úkol ve VERIFY a řekne to.
- command
- behaviorally_verified
- modul plan
- #plan
- #project
- #issues
- #lifecycle
Zpřístupnění
Kde je tato jedna definice dosažitelná. Absence je explicitní: povrch, který není uveden, ji nenese.
| povrch | jako |
|---|---|
| MCP | nástroj majordomus_plan_transition |
| HTTP | POST /api/v1/plan/transition operationId plan.transition |
| příkazová řádka | — |
Schémata
Kanonický vstup a výstup z typů Rustu; schéma nástroje MCP a parametry a odpovědi OpenAPI se odvozují z nich.
vstup · PlanTransitionInput
plan.transition: který úkol přesunout a kterým směrem.
Dvě pole a žádné třetí. Není tu časové razítko — přesun se označí okamžikem, kdy se stal, nikdy okamžikem, který dodá volající, protože životní cyklus, který lze zpětně datovat, není záznamem toho, co se stalo. Není tu ani pole force nebo reason: přechod, který model odmítne, je odmítnut, a způsob, jak ho učinit legálním, je splnit podmínku, ne se ptát mimo ni.
use majordomus_cli::capability::builtin::plan::PlanTransitionInput;
use majordomus_cli::plan::Transition;
// The wire form an MCP client or an HTTP POST sends.
let input: PlanTransitionInput =
serde_json::from_str(r#"{"issue":"I0001","transition":"done"}"#).unwrap();
assert_eq!(input.issue, "I0001");
assert_eq!(input.transition, Transition::Done);
assert_eq!(input.transition.field(), "completed_at");
assert_eq!(input.transition.event(), "plan_done");
// Unknown fields are refused rather than ignored: a caller that misspells `transition`
// is told so instead of having its move silently dropped.
assert!(serde_json::from_str::<PlanTransitionInput>(
r#"{"issue":"I0001","transition":"done","force":true}"#).is_err());| vlastnost | typ | povinné | popis |
|---|---|---|---|
| issue | string | ano | Úkol k přesunutí, podle jeho id — které je zároveň názvem jeho souboru. |
| transition | reference | ano | Který přesun: start, verify nebo done. |
JSON Schema
{
"$defs": {
"PlanTransition": {
"description": "One lifecycle move.\n\nThree, not four: `evidence` appends a record rather than moving an issue, and it belongs\nwith the record it proves rather than with the moves it unblocks.\n\n```\nuse majordomus_cli::plan::Transition;\n\n// The wire spelling is the one a caller types on the command line.\nlet t: Transition = serde_json::from_str(\"\\\"done\\\"\").unwrap();\nassert_eq!(t, Transition::Done);\nassert_eq!(serde_json::to_string(&Transition::Start).unwrap(), \"\\\"start\\\"\");\n\n// Each move owns the field it stamps and the event it records; nothing else decides\n// either, so a new move cannot be added without saying both.\nfor (t, field, event) in [\n (Transition::Start, \"started_at\", \"plan_start\"),\n (Transition::Verify, \"verified_at\", \"plan_verify\"),\n (Transition::Done, \"completed_at\", \"plan_done\"),\n] {\n assert_eq!(t.field(), field);\n assert_eq!(t.event(), event);\n}\n```",
"oneOf": [
{
"const": "start",
"description": "Execution began. Refused unless the issue is READY.",
"type": "string"
},
{
"const": "verify",
"description": "Implementation is complete and the evidence is still outstanding.",
"type": "string"
},
{
"const": "done",
"description": "Complete. Refused while anything it waits on is unfinished, or while any evidence\nits own record requires is absent.",
"type": "string"
}
]
}
},
"additionalProperties": false,
"description": "The input of `plan.transition`: which issue to move, and which way.\n\nTwo fields and no third. There is no timestamp — the move is stamped with the moment it\nhappened, never with one the caller supplies, because a lifecycle a caller can backdate\nis not a record of what happened. There is no force or reason field either: a transition\nthe model refuses is refused, and the way to make it legal is to satisfy the guard rather\nthan to ask past it.\n\n```\nuse majordomus_cli::capability::builtin::plan::PlanTransitionInput;\nuse majordomus_cli::plan::Transition;\n\n// The wire form an MCP client or an HTTP POST sends.\nlet input: PlanTransitionInput =\n serde_json::from_str(r#\"{\"issue\":\"I0001\",\"transition\":\"done\"}\"#).unwrap();\nassert_eq!(input.issue, \"I0001\");\nassert_eq!(input.transition, Transition::Done);\nassert_eq!(input.transition.field(), \"completed_at\");\nassert_eq!(input.transition.event(), \"plan_done\");\n\n// Unknown fields are refused rather than ignored: a caller that misspells `transition`\n// is told so instead of having its move silently dropped.\nassert!(serde_json::from_str::<PlanTransitionInput>(\n r#\"{\"issue\":\"I0001\",\"transition\":\"done\",\"force\":true}\"#).is_err());\n```",
"properties": {
"issue": {
"description": "The issue to move, by its id — which is also its file name.",
"type": "string"
},
"transition": {
"$ref": "#/$defs/PlanTransition",
"description": "Which move: `start`, `verify` or `done`."
}
},
"required": [
"issue",
"transition"
],
"title": "PlanTransitionInput",
"type": "object"
}output · PlanTransitionResult
from a to jsou obojí odvozené stavy, čtené před zápisem a po něm. Hlásí se, a nepředpokládají se, protože přesun sám stav neurčuje: done na záznamu s neúplnými důkazy ho nechá ve VERIFY a volající se to dozví, místo aby se dozvěděl, že uspěl.
use majordomus_cli::capability::builtin::plan::PlanTransitionResult;
// What a `done` looks like when the record's required evidence is not all present: the
// call succeeded, the field was written, and the issue is still in VERIFY. A caller that
// read only the absence of an error would report this as finished; a caller that reads
// `to` knows better, which is why the field is here.
let held: PlanTransitionResult = serde_json::from_str(r#"{
"issue":"I0001","transition":"done","from":"VERIFY","to":"VERIFY",
"field":"completed_at","at":"2026-09-11T12:00:00Z","event":"plan_done"
}"#).unwrap();
assert_eq!(held.to, "VERIFY", "the status is derived from the record, not from the move");
// `next_ready` is absent when the plan has none left to hand out, which is ordinary
// rather than an error, so it is omitted rather than spelled as an empty string.
assert!(held.next_ready.is_none());| vlastnost | typ | povinné | popis |
|---|---|---|---|
| v | string | ano | Časové razítko zapsané do něj a do updated_at. |
| událost | string | ano | Připojená událost ledgeru. |
| pole | string | ano | Pole, které bylo orazítkováno. |
| z | string | ano | Stav, ve kterém úkol byl předtím. |
| issue | string | ano | Úkol, který se pohnul. |
| next_ready | string | null | ne | Úkol, který by měl pracovník vzít jako další, odvozený po přesunu. Chybí, když plán žádný nemá — což je po start běžný případ, protože právě převzatý úkol už není READY. |
| do | string | ano | Stav, v němž se nyní nachází, odvozený ze záznamu tak, jak byl zapsán. |
| transition | reference | ano | Provedený přesun. |
JSON Schema
{
"$defs": {
"PlanTransition": {
"description": "One lifecycle move.\n\nThree, not four: `evidence` appends a record rather than moving an issue, and it belongs\nwith the record it proves rather than with the moves it unblocks.\n\n```\nuse majordomus_cli::plan::Transition;\n\n// The wire spelling is the one a caller types on the command line.\nlet t: Transition = serde_json::from_str(\"\\\"done\\\"\").unwrap();\nassert_eq!(t, Transition::Done);\nassert_eq!(serde_json::to_string(&Transition::Start).unwrap(), \"\\\"start\\\"\");\n\n// Each move owns the field it stamps and the event it records; nothing else decides\n// either, so a new move cannot be added without saying both.\nfor (t, field, event) in [\n (Transition::Start, \"started_at\", \"plan_start\"),\n (Transition::Verify, \"verified_at\", \"plan_verify\"),\n (Transition::Done, \"completed_at\", \"plan_done\"),\n] {\n assert_eq!(t.field(), field);\n assert_eq!(t.event(), event);\n}\n```",
"oneOf": [
{
"const": "start",
"description": "Execution began. Refused unless the issue is READY.",
"type": "string"
},
{
"const": "verify",
"description": "Implementation is complete and the evidence is still outstanding.",
"type": "string"
},
{
"const": "done",
"description": "Complete. Refused while anything it waits on is unfinished, or while any evidence\nits own record requires is absent.",
"type": "string"
}
]
}
},
"description": "What one transition did.\n\n`from` and `to` are both derived statuses, read before and after the write. They are\nreported rather than assumed because the move does not determine the status on its own:\n`done` on a record whose evidence is incomplete leaves it in VERIFY, and the caller is\ntold that rather than told it succeeded.\n\n```\nuse majordomus_cli::capability::builtin::plan::PlanTransitionResult;\n\n// What a `done` looks like when the record's required evidence is not all present: the\n// call succeeded, the field was written, and the issue is still in VERIFY. A caller that\n// read only the absence of an error would report this as finished; a caller that reads\n// `to` knows better, which is why the field is here.\nlet held: PlanTransitionResult = serde_json::from_str(r#\"{\n \"issue\":\"I0001\",\"transition\":\"done\",\"from\":\"VERIFY\",\"to\":\"VERIFY\",\n \"field\":\"completed_at\",\"at\":\"2026-09-11T12:00:00Z\",\"event\":\"plan_done\"\n}\"#).unwrap();\nassert_eq!(held.to, \"VERIFY\", \"the status is derived from the record, not from the move\");\n\n// `next_ready` is absent when the plan has none left to hand out, which is ordinary\n// rather than an error, so it is omitted rather than spelled as an empty string.\nassert!(held.next_ready.is_none());\n```",
"properties": {
"at": {
"description": "The timestamp written into it, and into `updated_at`.",
"type": "string"
},
"event": {
"description": "The ledger event appended.",
"type": "string"
},
"field": {
"description": "The field that was stamped.",
"type": "string"
},
"from": {
"description": "The status the issue was in before.",
"type": "string"
},
"issue": {
"description": "The issue that moved.",
"type": "string"
},
"next_ready": {
"description": "The issue a worker should take next, derived after the move. Absent when the plan\nhas none — which after a `start` is the ordinary case, because the issue just taken\nis no longer READY.",
"type": [
"string",
"null"
]
},
"to": {
"description": "The status it is in now, derived from the record as written.",
"type": "string"
},
"transition": {
"$ref": "#/$defs/PlanTransition",
"description": "The move that was performed."
}
},
"required": [
"issue",
"transition",
"from",
"to",
"field",
"at",
"event"
],
"title": "PlanTransitionResult",
"type": "object"
}Politiky
- benchmark
- required_when — cíl na každém přenosu, který expozice deklaruje; případy jsou případy vstupního typu
- cache
- vypnuto — každé volání spustí handler
Cíle benchmarku
Odvozeno z registru pro tento repozitář: jeden požadavek na transport a případy, které poskytuje typ vstupu. Celá matice je na stránce měření výkonu.
| transport | state | případy | targets |
|---|---|---|---|
| direct | pokryto | 1 | refused-by-status |
| mcp | pokryto | 1 | refused-by-status |
| http | pokryto | 1 | refused-by-status |