docs: explain how GitOps is actually wired - #15
Conversation
A developer at the design presentation — one who already knew ArgoCD — found the README's repository layout hard to follow. That is the informative part: the tree names directories accurately and explains no mechanism, so a reader who knows the tool arrives with questions it cannot answer. Which of the 22 Applications runs first? Why two ApplicationSets? What happens when I commit? Adds docs/gitops.md rather than moving the tree. The tree is doing a real job — orientation for someone deciding whether this repo is what they think it is — and was not what confused him. What was missing had never been written down anywhere. It covers the app-of-apps chain from infra-root-app.yaml to the 22 common-service Applications; the sync-wave table with the reason each service sits where it does, collected from the per-Application header comments where that reasoning already existed but was unfindable; the two project ApplicationSets and why they get different trust; what actually happens between a push and a change in the cluster; the bootstrap exception; and a symptom-to-look-here table. Three things it states plainly because each has cost time in this repo: waves order the START of a sync rather than its completion, a file whose name misses projectset.yaml's include glob is ignored SILENTLY while ArgoCD still reports Synced/Healthy, and Synced compares against the revision the Application last recorded rather than the tip of main. Written for both audiences in one document, as asked: a project developer can stop after Layer 2, a maintainer reads on. Every claim verified rather than recalled: 22 Applications confirmed, all six wave groups checked against the manifests, ArgoCD's reconciliation interval confirmed as the 180s default (argocd-cm sets no override), and all 22 infra Applications confirmed to use automated sync. All links and the README anchor resolve, and the new decisions-pointers job validates the two entry references. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Adds a dedicated GitOps wiring document to explain the repo’s ArgoCD “app-of-apps” and project ApplicationSet flow, and links it from the main entry points so readers can move from “what lives where” to “how it actually runs.”
Changes:
- Add
docs/gitops.mddescribing the infra root → 22 infra Applications chain, sync-wave ordering rationale, and the two project ApplicationSets. - Link the new GitOps wiring doc from the top-level
README.mdrepository layout section. - Add
gitops.mdtodocs/README.mdto make it discoverable alongside the other runbooks.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
| README.md | Adds a pointer from repository layout to the new GitOps wiring document. |
| docs/README.md | Adds gitops.md to the documentation index table. |
| docs/gitops.md | New end-to-end explanation of ArgoCD layering, sync waves, project ApplicationSets, and troubleshooting cues. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| 2. ArgoCD polls the repo (roughly every three minutes) or reacts to a webhook. The | ||
| affected Application goes `OutOfSync`. |
There was a problem hiding this comment.
Right on both halves — fixed in 5132b84, though I went further than the suggested wording.
The webhook half is the real finding. I checked: gh api /repos/Scouterna/azure-webservices/hooks returns zero, and nothing in k8s/argocd/ or the runbook configures one. The only webhook mentions in the repo are Alertmanager's Slack URL and the External Secrets admission webhook, neither related. So I described a delivery path this platform does not have.
That matters more than it looks: a reader who knows ArgoCD would reasonably assume a push reaches the cluster promptly, then hit a three-minute wait with no way to explain it — the doc would have caused the confusion it exists to prevent.
On the interval, I made it conditional but sourced rather than vague: timeout.reconciliation at its 180s default, with argocd-cm setting no override. If someone later sets one, that sentence names the knob to look at.
Rather than your suggested "may react to a webhook if one is configured", the doc now says "polling is the only trigger here — no repository webhook is configured, so a push is never pushed to the cluster", and points at argocd.md for forcing a refresh instead of waiting. Naming what is actually configured beats hedging, when the answer is "nothing".
Also swept the rest of the doc and the other docs for the same claim — this was the only occurrence.
The step said ArgoCD "polls the repo (roughly every three minutes) or reacts to a webhook" — describing a delivery path this platform does not have. Verified: the repo has zero webhooks configured, and nothing in k8s/argocd/ or the runbook sets one up. The only webhook mentions anywhere are Alertmanager's Slack URL and the External Secrets admission webhook, neither related. That mattered more than the imprecision it looked like. A reader who knows ArgoCD would reasonably assume a push reaches the cluster promptly, then be surprised by a three-minute wait with no way to explain it. Saying "polling is the only trigger" is a fact worth knowing, not a hedge. Also sourced the interval rather than asserting it: timeout.reconciliation at its 180s default, with argocd-cm setting no override. Points at argocd.md for forcing a refresh instead of waiting. From Copilot's review of #15. It suggested conditional wording; naming what is actually configured is more useful, since the answer is "nothing". Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
From the design presentation: a developer who already knew ArgoCD found the
README's repository layout hard to follow.
That detail is the useful part. The tree names directories accurately and explains
no mechanism — so someone who knows the tool arrives with exactly the questions it
cannot answer. Which of the 22 Applications runs first? Why are there two
ApplicationSets? What happens when I commit? None of that was written down
anywhere in the repo, though most of the reasoning existed scattered across
individual Application headers.
Why a new doc rather than moving the tree
Håkan's instinct was that this belongs in
docs/rather than the README, and Iagree — but by adding, not moving. The tree is doing a real job: orientation
for someone deciding whether this repo is what they think it is. It was not the
thing that confused him. Cutting it would trade one gap for another.
So the README keeps its tree and gains a pointer;
docs/gitops.mdfills the gap.What it covers
infra-root-app.yaml→ 22 Applications → charts andmanifests, with "adding a service is one file" made concrete.
it does. That reasoning mostly existed already in the per-Application header
comments; it was just unfindable unless you opened all 22 files.
infra-committed, the other points at a repo nobody on the infra side reviews.
Three things it states plainly, each having cost time in this repo:
projectset.yaml's include glob is ignoredsilently — ArgoCD still reports
Synced/Healthy.Syncedcompares against the revision the Application last recorded, not thetip of
main.Written for both audiences in one document, as requested: a project developer can
stop after Layer 2; a maintainer reads on.
Verified, not recalled
ls k8s/argocd/infra-apps/*.yaml | wc -lsync-wavefrom all 22 manifests, all six groups matchargocd-cmsets notimeout.reconciliation, so ArgoCD's 180s default appliesAll links and the README anchor resolve. Five CI jobs pass — including the new
decisions-pointersjob, which validates the twodecisions.mdentry referencesthis doc adds. First real use of that check.