Přeskočit na obsah

Tato stránka byla automaticky přeložena z angličtiny, jediného jazyka, ve kterém se tento web píše. Číst originál.

Provedení je sledované volání schopnosti, ne druhý registr

Provedení je sledované volání schopnosti, ne druhý registr

majordomus://adr/adr-0033přijato architekturacapabilitiesrusthttpcockpitagenti

odkazuje na

odkazuje na něj

22. Provedení je sledované volání schopnosti, ne druhý registr

Kontext

Registr (ADR 2) odpoví na volání a vrátí se. To je správné pro vše, co držel: čtení neměnného indexu, zodpovězená v mikrosekundách, přes MCP, HTTP, příkazovou řádku a generovaný runner Cockpitu. Člověk nebo agent se zeptá a odpověď přijde v rámci požadavku.

Dvě věci, které nepokrývá, a obě přicházely:

  1. Práce, která trvá déle než požadavek, by se neměla držet otevřená. Ověření každého objektu vrstvy proti pracovnímu stromu čte devět set souborů. Budoucí schopnost, která spouští kontrolu, řídí providera nebo prochází třicet worktrees, trvá minuty. Držet po tu dobu otevřené HTTP spojení je špatný kontrakt pro prohlížeč a nemožný pro stránku, kterou člověk může znovu načíst.
  2. Práce, jejíž střed je stejně zajímavý jako konec. „Běží to“ a „povedlo se to“ jsou dva fakty a řídicí rovina, která hlásí jen druhý, je řídicí rovina, kterou lidé nahrazují sledováním terminálu.

Zřejmý tvar — a ten, který tento repozitář už dříve odmítl v jiných podobách — je druhý subsystém: registr akcí s vlastními definicemi, vlastními schématy, vlastní tabulkou tras, vlastním seznamem v Cockpitu a implementací v prohlížeči vedle implementace v CLI. To jsou čtyři kopie identity každé schopnosti a kopie se rozejdou při první úpravě, která na některou zapomene.

Rozhodnutí

Provedení je volání schopnosti, kterému tento proces dal identitu. Neexistuje registr akcí, definice akce ani druhá implementace čehokoli. Přidáno bylo:

flowchart TD
  declaration["capability!"] --> registry["CapabilityRegistry"]
  registry --> execute["Context::execute"]
  execute --> handler["the handler"]
  registry --> engine["ExecutionEngine"]
  engine --> execute
  handler -->|"Progress"| event["ExecutionEvent"]
  engine --> store["ExecutionStore"]
  event --> store
  store --> get["executions.get"]
  store --> events["executions.events"]
  store --> socket["the WebSocket"]

Čtyři rozhodnutí uvnitř toho:

Vlastní API roviny provádění jsou schopnosti. executions.start, executions.list, executions.get, executions.events, executions.cancel a executions.protocol jsou bloky capability! jako každé jiné, takže HTTP routy, nástroje a zdroje MCP, operace OpenAPI, příkazová řádka, runner Cockpitu a generovaná reference se odvozují přesně tak, jako u všeho ostatního. Nic o provedeních se nikde neregistruje podruhé. Záměrně neexistuje žádná schopnost, která by vypisovala, co lze spustit: to je capabilities.list, které na to už odpovídá.

Hlášení je pole kontextu, ne druh handleru. Každý Context nese handle Progress. Mimo provedení je tichý a volání je zdarma, takže se handler píše jednou a hlásí stejně, ať jej volal benchmark, klient MCP, terminál nebo prohlížeč. health.report se stal pozorovatelným změnou sedmi volání checks.push(…) na record(&mut checks, &ctx.progress, …); jeho trasa, schéma, odpověď ani volající se vůbec nezměnili.

Jak dlouho volání trvá, není druh. Tři druhy zůstávají třemi: čtení, které projde devět set souborů, je stále čtení. Deklarace přidává jedinou vlastnost svého handleru — .cancellable(), což znamená, že se dívá na svůj příznak zrušení a zastaví se — a zbytek ExecutionPolicy, tedy efekt a zda se dva smějí překrývat, se klasifikuje z druhu přesně tak, jako už dostupnost a viditelnost. Tlačítko Cancel v Cockpitu a jeho potvrzovací dotaz se čtou z tohoto deskriptoru, ne rozhodují v šabloně, a handler, který svůj příznak ignoruje, nikdy nevytvoří ovládací prvek, který lže.

Transport leží za událostí. ExecutionEvent je typovaný enum s verzí, hustou sekvencí a obálkou type/data; jeho JSON Schema se odvozuje z typu v Rustu toutéž cestou schemars, kterou jde každé schéma vstupu a výstupu. Store drží a rozesílá; http::events vykresluje. Auditní stopa, notifikátor nebo druhý protokol se přihlásí ke store; žádný z nich se neprotahuje enginem.

Nativní WebSocket, psaný ručně, nad serverem, který tento repozitář už má. Živý kanál je GET /events, povýšený na stejném socketu tiny_http, na kterém se obsluhuje zbytek povrchu: jeden proces, jeden port, jedna cesta startu. Framing a handshake jsou asi dvě stě řádků v http::ws, vedle base64 a percent-encodingu, které tento crate už píše ručně.

Zvažované alternativy

Registr ActionDefinition vedle registru schopností. Věc, kterou toto ADR existuje, aby odmítlo. Každá akce by nesla id, název, popis, vstupní schéma a výstupní schéma — vše, co deskriptor schopnosti už nese — a oba by se navždy sladovaly ručně. project.no-new-nouns i project.interfaces-are-projections to zakazují a ani jedno nebylo třeba konzultovat: druhý registr neobsahuje žádný fakt, který nemá první.

Socket.IO. Druhý protokol nad WebSocket, klientská knihovna, kterou je třeba dodat do Cockpitu, jehož content-security policy nepovoluje žádný vzdálený původ, vlastní sémantika opětovného připojení a jmenných prostorů, kterou se musí naučit, a serverová implementace v Rustu, kterou je třeba převzít nebo napsat — výměnou za opětovné připojení s backoffem a model odběru, což je čtyřicet řádků socket.js a parametr dotazu. Bylo jmenováno v požadavku, který tuto práci vyvolal, a zamítá se věcně: nic, co tato řídicí rovina potřebuje, není mimo RFC 6455.

Server-sent events. Opravdu blízké a jednodušší: jednosměrné, textové, s opětovným připojením a kurzorem Last-Event-ID přímo v protokolu. Zamítnuto, protože strop je nižší — prohlížeč je omezen na šest souběžných spojení SSE na origin přes HTTP/1.1, čehož Cockpit s několika otevřenými záložkami provedení dosáhne — a protože obousměrný kanál je to, co bude potřebovat další konzument (agent, který se přihlásí a pak řídí). Myšlenka kurzoru zůstala: ?after=<sequence> je Last-Event-ID pod jiným jménem.

Pollovat executions.get z prohlížeče. Už je to možné a k tomu slouží HTTP trasy po znovunačtení, opětovném připojení nebo neshodě. Jako primární mechanismus je to pevná cena placená každou otevřenou kartou, ať se něco děje, nebo ne, a nemůže ukázat řádek logu v okamžiku, kdy je zapsán.

Asynchronní runtime a asynchronní server. tokio a axum by zdarma daly upgrade, broadcastový kanál a token zrušení. Také by nahradily synchronní server, na kterém je celý tento crate postaven, vložily executor pod každý handler a přidaly strom závislostí větší než crate. Synchronní úložiště s odběrateli SyncSender dělá stejnou práci v jednom souboru a meze, které vynucuje, jsou v něm vidět.

Čtení rámců klienta. tiny_http při upgradu předá jednu hodnotu Read + Write a ta se nedá rozdělit: vlákno čtenáře, které by na ní blokovalo, by drželo zámek, který potřebuje zapisovatel. Odběr je proto cílem požadavku — který opětovné připojení znovu odešle se svým kurzorem — a server ignoruje, co klient posílá. Cenou je, že zavírací rámec klienta se zaznamená až při dalším zápisu, ne okamžitě; heartbeat to omezuje na dvacet sekund.

Trvalá provádění. Záměrně nepostaveno. Provádění nepřežije proces, který jej přijal, každý limit je typován na Limits a nic nad úložištěm nepojmenovává Mutex — takže trvalé úložiště je záměna, nikoli přepis. Slibovat víc než to bez případu užití by byla fronta, o kterou nikdo nežádal.

Důsledky

Přidat operaci spustitelnou z prohlížeče znamená přidat blok capability! a žádný druhý krok neexistuje: Cockpit ji objeví, formulář řízený schématem ji vykreslí, rovina provádění ji spustí a živý kanál ji hlásí. Přidat průběh ke stávající schopnosti znamená volat ctx.progress v jejím handleru; nic na jejím kontraktu se nemění.

Do docs/CONCEPTS.md přibývají dvě nová slova: provedení a událost provedení. Čtvrtý druh schopnosti byl navržen a zahozen — jeho nasnadě ležící jméno, task, už v téže tabulce znamená „jedinou aktivní jednotku práce v checkoutu“ a slovník s jedním slovem pro dvě věci je přesně to, čemu se tento repozitář snaží vyhnout. To, co by druh nesl, se ukázalo být jedním booleanem o handleru, který je nyní metodou builderu na deklaraci.

Capability získalo pole execution, takže docs/generated/registry.json, datová sada webu i dokument OpenAPI jej nesou. Jsou generované a změna byla jedním majordomus generate.

Tři schopnosti jsou vyňaty z měření výkonu s typovaným důvodem transient_state: provedení ke čtení nemůže hostitel měření nasadit a transport MCP měří samostatný proces, kde žádné id tohoto neexistuje. To je první skutečné použití mechanismu výjimek a odhalilo, že capabilities validate a bench coverage --check selhávaly na jakékoli výjimce — což pravidlo, které vynucují, neříká. Oba nyní rozhodují podle toho, co chybí, a hlásí, co je vyňato.

Provádění běží na vlákně workeru tohoto procesu a tento proces obsluhuje jeden repozitář: nic nemůže spustit schopnost proti jinému checkoutu a nic ji nemůže spustit mimo registr. Neexistuje shellový endpoint a z návrhu není žádný dosažitelný — plane spouští registrované typované schopnosti a schopnost, která by spustila příkaz, by byla blokem capability! s povoleným seznamem, posuzovaným jako každý jiný.

Odkud to pochází

kanonický soubor
.ai/repo/adrs/0033-an-execution-is-a-watched-capability-call-not-a-second-registry.md
identity
adr-0033
dostupné také jako
Zdroj MCP majordomus://adr/adr-0033 · majordomus entity show adr/adr-0033 · GET /api/v1/entity?uri=majordomus://adr/adr-0033
v Cockpitu
/cockpit/objects/adr/adr-0033

Tato stránka je generována z výše uvedeného souboru pomocí scripts/generate-site-data; úprava stránky nic nemění, úprava souboru změní všechna rozhraní. Výše uvedené vztahy jsou hrany docs/generated/graph.json, které spustitelný program zapisuje ze stejného indexu.

Prohledává názvy a popisy všech stránek, které tento web publikuje.