Feature

Feature

Workloads

Every machine accumulates things that run: a report at 06:30, a poller every fifteen minutes, a daemon, a tunnel, an agent waiting for requests. They are usually spread across a service manager, a crontab, a note in a wiki and somebody's memory. A workload is one of those things, written down once, in one file, with an owner.

Auf jeder Maschine sammelt sich an, was läuft: ein Bericht um 06:30, ein Poller alle fünfzehn Minuten, ein Daemon, ein Tunnel, ein Agent, der auf Anfragen wartet. Verteilt ist das üblicherweise über einen Dienstverwalter, eine Crontab, eine Notiz im Wiki und jemandes Gedächtnis. Ein Workload ist eines dieser Dinge, einmal aufgeschrieben, in einer Datei, mit einem Eigentümer.

What is a workload?
Was ist ein Workload?

One declared run on one machine. It lives in workflow/workloads/<id>.yaml, and that file is the truth. The unit the service manager holds is an artifact rendered from it, and may be rebuilt at any time.

Ein deklarierter Lauf auf einer Maschine. Er liegt in workflow/workloads/<id>.yaml, und diese Datei ist die Wahrheit. Die Einheit beim Dienstverwalter ist ein daraus gerendertes Artefakt und kann jederzeit neu gebaut werden.

Read the full workloads guide →Den vollständigen Workloads-Guide lesen →

The state it grew out of

Der Zustand, aus dem es entstand

Five places to register a run, and no ownership anywhere

Fünf Anmeldeflächen, und nirgends ein Eigentümer

This is not a hypothetical. It is what one real machine looked like after a few years of use, measured rather than remembered: 74 service entries in an inventory that describes runs and creates none. A scheduling skill that promised to create, deploy and disable them, whose registry file did not exist. A calendar with eight entries, all of which had never fired. And an executor whose registry lived outside the repository, on the machine.

Das ist kein gedachtes Beispiel. So sah eine echte Maschine nach einigen Jahren Gebrauch aus, gemessen statt erinnert: 74 Diensteinträge in einem Inventar, das Läufe beschreibt und keinen anlegt. Ein Skill, der versprach anzulegen, auszurollen und abzuschalten, dessen Registry-Datei nicht existierte. Ein Kalender mit acht Einträgen, von denen keiner je gefeuert hatte. Und ein Ausführer, dessen Registry außerhalb des Repositories lag, auf der Maschine.

The missing thing was not a scheduler. Of everything running on that host, nothing recorded which runs the Bridge had created, which a person had made by hand, and which a tool had left behind. The visible consequences were eleven backup copies of one registry file in five naming schemes, a launchd.broken-<date> directory nobody had touched in months, and 1428 log files with no rotation.

Was fehlte, war kein Planer. Von allem, was auf diesem Wirt lief, hielt nichts fest, welche Läufe die Bridge angelegt hatte, welche ein Mensch von Hand und welche ein Werkzeug hinterlassen hatte. Sichtbare Folgen: elf Sicherungskopien einer Registry-Datei in fünf Namensschemata, ein Verzeichnis launchd.broken-<datum>, das seit Monaten niemand angefasst hatte, und 1428 Logdateien ohne Rotation.

Everything in the contract below except one field is the union of what already existed, scattered: the appointment comes from the calendar, the probe from the health checks, the host from the machine inventory. The one field none of the five had is owner.

Alles im Vertrag unten außer einem Feld ist die Vereinigung dessen, was verstreut schon existierte: der Termin aus dem Kalender, die Sonde aus den Gesundheitsprüfungen, der Wirt aus dem Maschineninventar. Das eine Feld, das keine der fünf Flächen hatte, ist owner.

The contract

Der Vertrag

Four parts, and one optional probe

Vier Teile, und eine optionale Sonde

A declaration answers four questions and nothing else: where it sits, when it fires, how it runs, and how it answers. A fifth block says how you would know it is still there.

Eine Deklaration beantwortet vier Fragen und sonst nichts: wo sie sitzt, wann sie feuert, wie sie läuft, wie sie antwortet. Ein fünfter Block sagt, woran man erkennt, dass sie noch da ist.

schema_version: 1
scope: user                    # core | org | personal | user
id: daily-health-report
purpose: "Daily operations report, due before the morning stand-up"

placement:                     # 1. WHERE IT SITS
  host: host-a                 # a slug under infra/remotes/, or `local`
  kind: recurring              # recurring | interval | daemon | watch | agent | oneshot
  runtime: launchd             # launchd | launchd-system | systemd | cron | dispatcher | manual | external
  owner: bridge                # bridge | human | foreign

schedule:                      # 2. WHEN IT FIRES
  rrule: "FREQ=WEEKLY;BYDAY=MO,TU,WE,TH,FR"
  delivery_at: "06:30"         # DELIVERY, not start
  duration_estimate_min: 20    # start = delivery_at minus this
  timezone: Europe/Berlin      # a zone, never a fixed offset

execution:                     # 3. HOW IT RUNS
  command: ["/opt/example/bin/report.sh"]
  timeout_sec: 600
  isolation: process-group
  single_flight: true

response:                      # 4. HOW IT ANSWERS
  evidence: log-trace          # exit-code | log-trace | delivery-receipt
  recipients: [{mandant: example-team, person: first_person}]
  notify_on: [failure, timeout, missing]

reconcile:                     # optional: how you know it is still there
  probe: "launchctl print gui/501/com.example.dispatcher"
  expect: "state = running"
kind ≠ runtime kind ≠ runtime

What it is, and what carries it

Was es ist, und was es trägt

An inventory that folds these into one type: field ends up with a single word covering both a 06:30 weekday report and a poller firing every 900 seconds. One has appointments, the other only a cadence. Keeping them apart is what lets a calendar draw appointment ticks for the first and a cadence band for the second without inventing times that never existed.

Ein Inventar, das beides in ein type:-Feld faltet, hat am Ende ein Wort für den Wochenbericht um 06:30 und für den Poller alle 900 Sekunden. Das eine hat Termine, das andere nur einen Takt. Die Trennung ist das, was einen Kalender Terminmarken für das eine und ein Taktband für das andere zeichnen lässt, ohne Zeiten zu erfinden, die es nie gab.

delivery, not start Zustellung, nicht Start

The appointment is when the result is due

Der Termin ist, wann das Ergebnis fällig ist

delivery_at is the moment somebody expects the answer, and duration_estimate_min is how long the run needs. The start time is derived, so making a report slower moves its start and never its deadline. A declaration that stated the start instead would silently deliver late the day the job grew.

delivery_at ist der Moment, zu dem jemand die Antwort erwartet, und duration_estimate_min ist, wie lange der Lauf braucht. Die Startzeit wird abgeleitet, ein langsamer gewordener Bericht verschiebt also seinen Start und nie seine Frist. Eine Deklaration, die stattdessen den Start nennt, liefert am Tag des Wachstums still zu spät.

The deliberate absence

Die bewusste Abwesenheit

There is no status: field

Es gibt kein status:-Feld

This is the reason the schema exists, not an omission. A declared status is never the truth; the service manager is. State comes from asking the live source, every time.

Das ist der Daseinsgrund des Schemas, kein Versehen. Ein deklarierter Status ist nie die Wahrheit, der Dienstverwalter ist es. Der Zustand kommt jedes Mal daher, dass die lebende Quelle gefragt wird.

The inventory this replaced proves the point without argument: 52 of its 74 entries carried no status at all, and the ones that did had drifted. A field that half the entries skip and the other half get wrong is not a source of truth, it is a second thing to maintain. additionalProperties: false at the top level is what keeps it from coming back through the side door, and it is the single heaviest rule in the file.

Das abgelöste Inventar beweist es ohne Argument: 52 seiner 74 Einträge trugen überhaupt keinen Status, und die übrigen waren gedriftet. Ein Feld, das die Hälfte auslässt und die andere Hälfte falsch hat, ist keine Quelle der Wahrheit, sondern eine zweite Sache zum Pflegen. additionalProperties: false auf oberster Ebene hält es von der Hintertür fern und ist die schwerste Einzelregel der Datei.

The life of a run

Das Leben eines Laufs

Declare, provision, reconcile, retire

Deklarieren, einrichten, abgleichen, stilllegen

declare · validate · render

Write it down, before anything is touched

Aufschreiben, bevor etwas angefasst wird

declare builds a declaration from the template and checks it against the contract. render prints the exact bytes that would land on the machine, and it is pure: no filesystem, no child process, no clock. The same declaration renders the same bytes forever, which is what makes a second provisioning run a no-op instead of a hope, and a difference on disk mean drift instead of noise.

declare baut eine Deklaration aus der Vorlage und prüft sie gegen den Vertrag. render druckt die exakten Bytes, die auf der Maschine landen würden, und ist rein: kein Dateisystem, kein Kindprozess, keine Uhr. Dieselbe Deklaration rendert für immer dieselben Bytes, und genau das macht ein zweites Einrichten zu einem No-op statt zu einer Hoffnung, und einen Unterschied auf der Platte zu Drift statt zu Rauschen.

provision · adopt

Put it there, then prove it at the live object

Hinstellen, dann am lebenden Objekt beweisen

provision writes the unit, stamps ownership, and then asks the service manager whether it is really loaded. Applied and verified are two answers, and the command distinguishes them. adopt takes over a unit somebody made by hand without any downtime, and never overwrites it.

provision schreibt die Einheit, stempelt den Besitz und fragt danach den Dienstverwalter, ob sie wirklich geladen ist. Angewandt und bewiesen sind zwei Antworten, und der Befehl unterscheidet sie. adopt übernimmt eine von Hand angelegte Einheit ohne Ausfallzeit und überschreibt sie nie.

reconcile

Ask three sources, and never a declared field

Drei Quellen fragen, und nie ein deklariertes Feld

What should be there (the declarations), what is there (the machine, asked live), and what the inventory believes. The verdicts are a closed set, and unknown never collapses into absent: a host that did not answer means nobody answered, not that the run is gone. One closed laptop lid would otherwise report every job on every host as missing.

Was da sein soll (die Deklarationen), was da ist (die Maschine, live gefragt), und was das Inventar glaubt. Die Urteile sind eine geschlossene Menge, und unknown fällt nie in absent: ein Wirt, der nicht geantwortet hat, heißt niemand hat geantwortet, nicht der Lauf ist weg. Sonst meldete ein zugeklappter Laptop jeden Job auf jedem Wirt als verschwunden.

retire

Switching off is switching off plus a reason

Abschalten heißt abschalten plus Grund

A retirement carries a date and a written reason, and the declaration is marked only once every unit is proven down. A run stopped by half is still running, and a file claiming otherwise is worse than one that says nothing: the next reader stops looking.

Eine Stilllegung trägt ein Datum und einen geschriebenen Grund, und die Deklaration wird erst markiert, wenn jede Einheit nachweislich unten ist. Ein halb gestoppter Lauf läuft noch, und eine Datei, die etwas anderes behauptet, ist schlimmer als eine, die schweigt: der nächste Leser hört auf zu suchen.

Ownership

Eigentum

Two signals, never one

Zwei Signale, nie eines

A stamp on the machine, and a marker inside the artifact itself. A stamp without a marker is drift, and so is the reverse. The reason for two is not redundancy: two blind procedures that can only ever agree with each other would prove nothing. Because they are written by different steps and read from different places, a disagreement between them is information.

Ein Stempel auf der Maschine, und eine Marke im Artefakt selbst. Ein Stempel ohne Marke ist Drift, und umgekehrt genauso. Der Grund für zwei ist nicht Redundanz: zwei blinde Verfahren, die einander nur zustimmen können, bewiesen nichts. Weil sie von verschiedenen Schritten geschrieben und an verschiedenen Stellen gelesen werden, ist ein Widerspruch zwischen ihnen eine Information.

This is also what makes owner: human and owner: foreign useful rather than decorative. A run the Bridge does not execute can still be declared, so it becomes visible in the report, and the tooling then leaves it alone on purpose instead of by accident.

Genau das macht owner: human und owner: foreign nützlich statt schmückend. Ein Lauf, den die Bridge nicht ausführt, kann trotzdem deklariert werden, wird damit im Bericht sichtbar, und das Werkzeug lässt ihn danach absichtlich in Ruhe statt aus Versehen.

Seeing it without a terminal

Sehen ohne Terminal

A page that cannot lie about its own age

Eine Seite, die über ihr eigenes Alter nicht lügen kann

The same data reconcile reports can be rendered as one self-contained page and published where a browser reaches it. Two properties of that page are load bearing rather than decorative.

Dieselben Daten, die reconcile meldet, lassen sich als eine in sich geschlossene Seite rendern und dort veröffentlichen, wo ein Browser sie erreicht. Zwei Eigenschaften dieser Seite sind tragend statt schmückend.

the reader's clock decides die Uhr des Lesers entscheidet

Freshness is computed where it is read

Frische wird dort berechnet, wo gelesen wird

On a terminal an age is free, because you just ran the command. A page on a server is opened hours later, looks identical, and is believed. So the page publishes its own moment in machine readable form and computes the age in the browser, and it judges that age only against a cadence somebody declared. Where nobody declared one, it says there is no cadence rather than inventing a threshold.

Im Terminal ist ein Alter kostenlos, weil man den Befehl gerade ausgeführt hat. Eine Seite auf einem Server wird Stunden später geöffnet, sieht identisch aus und wird geglaubt. Also veröffentlicht die Seite ihren eigenen Zeitpunkt maschinenlesbar, rechnet das Alter im Browser aus und misst es nur an einem Takt, den jemand deklariert hat. Wo niemand einen deklariert hat, sagt sie das, statt eine Schwelle zu erfinden.

two facts, never merged zwei Fakten, nie verschmolzen

How it went is a different question from when it last ran

Wie es lief ist eine andere Frage als wann zuletzt

A row showing only the newest firing renders a job that has been clean for a month exactly like one that failed twice this week and happened to succeed on the attempt before somebody looked. So each run carries a strip of what the machine actually wrote down, oldest on the left, shaped per verdict rather than coloured.

Eine Zeile, die nur das jüngste Feuern zeigt, stellt einen seit einem Monat sauberen Job genauso dar wie einen, der diese Woche zweimal scheiterte und zufällig beim Versuch vor dem Hinsehen gelang. Also trägt jeder Lauf einen Streifen dessen, was die Maschine wirklich aufgeschrieben hat, ältestes links, in Form je Urteil statt in Farbe.

How the contract is proved

Wie der Vertrag bewiesen wird

Four suites, and two of them exist to test the other two

Vier Prüfmappen, und zwei davon prüfen die anderen zwei

A skill that writes unit files onto machines is the one place where a contract broken unnoticed ends up on a service manager. So the suites come in pairs: one that checks the behaviour, and one that checks whether the first one would notice if the behaviour changed.

Ein Skill, der Einheitsdateien auf Maschinen schreibt, ist die eine Stelle, an der ein unbemerkt gebrochener Vertrag beim Dienstverwalter landet. Deshalb kommen die Mappen paarweise: eine prüft das Verhalten, die andere prüft, ob die erste es überhaupt merken würde.

bash skills/workload/run-tests.sh            # the engine
bash skills/workload/run-tests.sh --mutate   # and whether those tests bite
bash workflow/workloads/_tests/run.sh        # the declaration contract
bash workflow/workloads/_tests/run.sh --mutate # and whether those controls bite

A mutation run softens exactly one rule in a scratch copy and requires that exactly one test turns red. A test that stays green under the softening of the rule it claims to hold was never holding it. That is not a theoretical worry: three needles had already gone hollow when this was written, one matching nothing after a rule was restructured, one matching twice after a second spelling of the same pattern appeared, and one pointing at code that had been deleted. In each case the run kept reporting green for everything around it.

Ein Mutationslauf weicht genau eine Regel in einer Wegwerfkopie auf und verlangt, dass genau ein Test rot wird. Ein Test, der unter der Aufweichung seiner eigenen Regel grün bleibt, hat sie nie gehalten. Das ist keine theoretische Sorge: drei Nadeln waren beim Schreiben bereits hohl, eine traf nach einem Umbau nichts mehr, eine traf zweimal, nachdem eine zweite Schreibweise desselben Musters dazugekommen war, und eine zeigte auf gelöschten Code. Jedes Mal meldete der Lauf für alles ringsum weiter grün.

Every contract run also ends by printing what is not fully covered, class by class, so the green above it cannot be read as completeness.

Jeder Vertragslauf druckt am Ende außerdem, was nicht vollständig abgedeckt ist, Klasse für Klasse, damit das Grün darüber nicht als Vollständigkeit gelesen wird.

Where it lives

Wo es liegt

The contract ships, your declarations do not

Der Vertrag reist, deine Deklarationen nicht

A declaration names a concrete host, concrete paths and concrete recipients, so it stays in your instance and never travels upward. The contract and the engine are generic and do travel. That split is structural, decided by where a file lives rather than by a tag somebody could forget.

Eine Deklaration nennt einen konkreten Wirt, konkrete Pfade und konkrete Empfänger, bleibt also in deiner Instanz und reist nie nach oben. Vertrag und Motor sind generisch und reisen. Diese Trennung ist strukturell: sie entscheidet sich daran, wo eine Datei liegt, nicht an einer Markierung, die jemand vergessen könnte.

workflow/workloads/_schema.yaml     # CORE  the contract
workflow/workloads/_template.yaml   # CORE  the starting point
workflow/workloads/_tests/          # CORE  the contract's own regression suite
workflow/workloads/<id>.yaml        # USER  your declarations
skills/workload/                    # CORE  the engine and the skill

Limits

Grenzen

What it deliberately does not do

Was es bewusst nicht tut

  • No sudo, ever. A run that needs elevation yields a printed plan for a person, and the next reconcile verifies whatever they did.Kein sudo, nie. Ein Lauf, der Erhöhung braucht, ergibt einen gedruckten Plan für einen Menschen, und der nächste Abgleich prüft nach, was er getan hat.
  • No secrets. Neither a declaration nor the ownership stamp carries one. execution.env takes a locator such as keychain://…, and the locator is what reaches the unit file: resolving it here would write a live credential to disk. The program resolves its own at run time.Keine Geheimnisse. Weder eine Deklaration noch der Besitzstempel trägt eines. execution.env nimmt einen Locator wie keychain://…, und der Locator ist es, was die Einheitsdatei erreicht: ihn hier aufzulösen hieße, ein lebendes Zugangsmittel auf die Platte zu schreiben. Das Programm löst seinen eigenen zur Laufzeit auf.
  • No plaintext recipients. A declaration names a group and a person by reference, because it is a tracked file and travels with the scope router.Keine Klartext-Empfänger. Eine Deklaration nennt Gruppe und Person per Verweis, denn sie ist eine versionierte Datei und reist mit dem Scope-Router.
  • No general purpose dashboard. The page draws this skill's own material and nothing fetched from anywhere else.Kein Allzweck-Dashboard. Die Seite zeichnet das eigene Material dieses Skills und nichts von anderswo Geholtes.
  • No proof from a hand run. An interactive or ssh session has its own identity and its own grants, so the honest probe runs in the service manager's context.Kein Beweis aus einem Handstart. Eine interaktive oder ssh-Sitzung hat eigene Identität und eigene Genehmigungen, also läuft die ehrliche Sonde im Kontext des Dienstverwalters.

Read on

Weiterlesen

  • docs/workloads.md the full guide: contract, hard rules, and the case behind each oneder vollständige Guide: Vertrag, harte Regeln und der Fall hinter jeder einzelnen
  • skills/workload/SKILL.md every command, and every property of the pagejeder Befehl, und jede Eigenschaft der Seite
  • rules/deploy-reconciliation.md why a declared status is never trusted anywhere in this projectwarum ein deklarierter Status in diesem Projekt nirgends geglaubt wird