Automation design

How the running platform is rebuilt from reviewed files

Jobs, schedules, infrastructure, configuration, dashboards, policies, and the public site begin as reviewed files. Generators and controllers turn those files into the artifacts the tools consume. CI rejects a stale generated copy, and reconciliation checks the live system against the written source.

The sharpest failure was a Jenkins job that existed and looked correct but had no active schedule. Its trigger lived inside the job and would be read only after the first build, so a never-run job could never schedule itself. The seed now emits the trigger when it creates the job, which makes the schedule testable immediately.

Built from the Jenkins seed, site and documentation generators, infrastructure definitions, drift checks, and the trigger-creation regression tests in the repository.

I needed a platform that could be rebuilt without remembering the clicks

You can build a job by clicking through a web console: name it here, set its schedule there, paste a script into a box. It works, and six months later nobody can say for sure what it does or why, because the settings live inside the tool and nowhere else. Defining the same job in a text file fixes that. The file is reviewed before it takes effect, its history shows who changed what and when, and if the tool is wiped you rebuild everything from the file. The job is not a thing someone configured once. It is a thing the repository describes and the tool obeys.

Each kind of file has one owner and one way into production

“As code” does not mean one tool manages everything. Terraform owns infrastructure state, Ansible owns operating-system configuration, Jenkins Job DSL owns job definitions, Argo CD compares Kubernetes manifests with the cluster, and the site generator owns derived indexes and measured tokens. Git supplies the review history that connects them.

Reviewed source definitions move through generation and controllers into the running system, with drift returning to the source
A console remains useful for seeing current state and diagnosing a failure. Durable changes go back through the source file so a rebuild and the running environment follow the same path.
Git and pull requests
Hold the proposed change, the reason, the review, and the exact revision that passed.
Generators
Build indexes, public summaries, configuration fragments, and measured tokens from their registered sources.
Jenkins seed
Creates or updates jobs with their parameters, descriptions, identities, and schedules already attached.
Controllers
Terraform, Ansible, Argo CD, and Kubernetes turn the approved definition into infrastructure or workload state.
Drift checks
Compare generated files or live revisions with the source and fail when a difference would otherwise be silent.

The seed file is the source of truth

69 jobs are declared in one place, a seed definition that lists each job with its parameters and its schedule. A small tool reads that file and creates or updates the real jobs to match. If you want a new job you add it to the file and let the tool build it. You do not build it by hand and then try to remember to write it down. The important part is that the parameters and the trigger are declared in the seed, not discovered at runtime. What the job is and when it runs are properties of the written definition, readable before anything executes.

Generated files are never hand-edited

Some files in the repository are produced by a generator from a source of truth. An index of all the work items, for example, is built from the individual item files by a script. The rule is that you never edit the generated file directly. You edit the source and rerun the generator, and a check in the pipeline fails if the committed generated file does not match what the generator would produce. A hand-edit to a generated file is a change that the next generator run silently erases, so the pipeline treats it as an error rather than letting it rot.

What broke: the job that existed but never ran

Here is the bug that shaped how triggers work now. A scheduled job was seeded correctly. It showed up in the tool, its configuration read exactly right, and by every appearance it was fine. It never ran. The reason took a while to see: the schedule lived in the job's own properties, and those properties are only read when the job runs a build. A job that has been seeded but has never had a first build has not yet read its own schedule, so it has no trigger at all. It was waiting for a run to tell it when to run, which is a run that would never come. The job looked correct and was inert.

Emit the trigger at creation, so it is provable now

The durable fix was to stop relying on a future build to activate the schedule. The trigger is now emitted when the job is created, as part of seeding it, so the schedule is live from the moment the job exists. This is the real point of the page. Before the fix, the only way to know a job had a working trigger was to wait for its scheduled window and see whether it fired, which could be a day later. After the fix, you can prove the trigger is present the instant the job is created, by reading it, with nothing to wait for. A property you can only verify by waiting is a property you cannot really verify. Moving it to creation time turned a "wait and see" into a "check it now."

The pattern under all three

Declare the thing in a source file, generate the real world from that file, and make correctness something you can read rather than something you discover by running and waiting. The trigger bug is the sharpest example: the schedule was technically defined, but in a place that only came alive during a build, so its correctness was invisible until too late. Everything as code is not about avoiding the console for its own sake. It is about making the state of the system knowable from the text, before it runs.

Live delivery-pipeline evidence

This public dashboard shows whether the pipeline estate is reporting, the latest result under descriptive job names, completed-build activity, and duration. Build numbers, console output, users, parameters, repository links, and Jenkins management URLs stay private.

Checking the live delivery dashboard.

How it runs now

WhenWhat runsWhat happens next
On a source changeThe pull request checks syntax, policy, generated-file freshness, and public-site safety.A failure stops before the target tool sees the change.
After mergeThe owning generator, seed job, deployment pipeline, or reconciler reads the approved file.The tool creates or updates only the state that source owns.
On a generator runThe generator rebuilds the derived file from registered inputs.A hand edit disappears locally and CI reports the stale committed copy.
On a scheduled seedJenkins recreates job properties, including the trigger, from the seed definition.A new job can be inspected and scheduled before it has ever built.
On driftA checker compares the generated or live result with the approved source.The repair changes the source, then repeats generation and review.

What I would do differently

I would require every new generator to ship with its drift check and ownership comment in the same pull request. Several early generated files acquired those protections later, after it was already possible to edit the output by mistake.

I would also test creation-time behavior, not only the Jenkinsfile that runs after creation. The missing-trigger defect lived in the handoff between the seed and the first build, which neither side's original test covered.