From 31872c218807c5694c0bbf4fd742819529adf794 Mon Sep 17 00:00:00 2001 From: Jon Langevin Date: Sun, 31 May 2026 19:56:39 -0400 Subject: [PATCH] docs(retro): #804 cigen jenkins/circleci retro + scope-lock-complete + design backport --- ...026-05-31-cigen-jenkins-circleci-design.md | 17 ++++ .../2026-05-31-cigen-jenkins-circleci.md | 2 +- ...05-31-cigen-jenkins-circleci.md.scope-lock | 1 - ...2026-05-31-cigen-jenkins-circleci-retro.md | 83 +++++++++++++++++++ 4 files changed, 101 insertions(+), 2 deletions(-) delete mode 100644 docs/plans/2026-05-31-cigen-jenkins-circleci.md.scope-lock create mode 100644 docs/retros/2026-05-31-cigen-jenkins-circleci-retro.md diff --git a/docs/plans/2026-05-31-cigen-jenkins-circleci-design.md b/docs/plans/2026-05-31-cigen-jenkins-circleci-design.md index ffb1cf17..9a52a245 100644 --- a/docs/plans/2026-05-31-cigen-jenkins-circleci-design.md +++ b/docs/plans/2026-05-31-cigen-jenkins-circleci-design.md @@ -371,6 +371,23 @@ audit + rollback notes apply (see Rollback). to v0.1.6 + workflow consumers to v0.67.0 and rebuild. Version-skew audit at finish: plugin's workflow pin must equal the freshly tagged v0.68.0 (no lag). +## Backport (2026-05-31, post-execution — manifest scope unchanged) + +Three existence-check discoveries at execution (all the `Existence / +runtime-validity` class from autodev #55; no manifest scope change): +- **Scenario id 97 → 100.** Plan guessed "next free id 97"; 97–99 were already + taken. Used actual next-free 100. +- **Scenario config `app.yaml` → `deploy.yaml`.** The scenarios CI strict-`wfctl + validate`s every `config/app.yaml`; an infra/cigen-input config has no app + entry point and fails. Renamed to `config/deploy.yaml` (matches `wfctl ci + generate -c deploy.yaml`; excluded from the app-validate glob, like scenarios + 88/93). The local run.sh only ran `ci generate` (cigen analyze, no entry-point + requirement), so it didn't catch this. +- **Plugin version 0.2.0 → 0.3.0.** Plan's Task 7 read plugin.json (0.1.6) and + bumped to 0.2.0, but `v0.2.0` was already a released tag (PR #18; plugin.json + had drifted below it). Bumped to v0.3.0 (PR #22). Lesson: check `git + ls-remote --tags`, not just the version file, before choosing a release version. + ## Follow-ups (out of scope for #804) - **GitLab plan-guard + scoped-secret parity:** `render_gitlab.go` lacks both the diff --git a/docs/plans/2026-05-31-cigen-jenkins-circleci.md b/docs/plans/2026-05-31-cigen-jenkins-circleci.md index 78a61831..3c68f46c 100644 --- a/docs/plans/2026-05-31-cigen-jenkins-circleci.md +++ b/docs/plans/2026-05-31-cigen-jenkins-circleci.md @@ -34,7 +34,7 @@ | 2 | feat: route jenkins/circleci through cigen, retire template generators (#804) | Task 5, Task 6, Task 7 | workflow-plugin-ci-generator: feat/cigen-jenkins-circleci-804 | | 3 | test(scenario-97): config-derived jenkins/circleci CI generation proof (#804) | Task 8, Task 9 | workflow-scenarios: feat/cigen-jenkins-circleci-proof-804 | -**Status:** Locked 2026-05-31T22:52:06Z +**Status:** Complete 2026-05-31T23:56:30Z --- diff --git a/docs/plans/2026-05-31-cigen-jenkins-circleci.md.scope-lock b/docs/plans/2026-05-31-cigen-jenkins-circleci.md.scope-lock deleted file mode 100644 index 78d608d2..00000000 --- a/docs/plans/2026-05-31-cigen-jenkins-circleci.md.scope-lock +++ /dev/null @@ -1 +0,0 @@ -cb67a561b4ccb7f9cc3cdaadb04837bcb4f3e1f67dc94cdd261d8d6872a1c62b diff --git a/docs/retros/2026-05-31-cigen-jenkins-circleci-retro.md b/docs/retros/2026-05-31-cigen-jenkins-circleci-retro.md new file mode 100644 index 00000000..430cd455 --- /dev/null +++ b/docs/retros/2026-05-31-cigen-jenkins-circleci-retro.md @@ -0,0 +1,83 @@ +# Retro: cigen config-derived Jenkins + CircleCI (#804) + +**Issue:** https://github.com/GoCodeAlone/workflow/issues/804 +**Merged:** 2026-05-31 +**PRs:** workflow #810 (v0.68.0) · workflow-plugin-ci-generator #21 + #22 (v0.3.0) · workflow-scenarios #47 (scenario 100) +**Design:** docs/plans/2026-05-31-cigen-jenkins-circleci-design.md (adversarial PASS @ cycle 3) +**Plan:** docs/plans/2026-05-31-cigen-jenkins-circleci.md (plan-phase PASS @ cycle 2; alignment PASS; scope locked) +**ADR:** decisions/0044-cigen-renderers-omit-legacy-build-deploy-stages.md + +## What shipped + +`cigen.RenderJenkins` + `cigen.RenderCircleCI` (config-derived emitters from the +existing CIPlan, mirroring the GHA job set) wired into `wfctl ci generate` +(4 platforms) and the ci-generator plugin (all 4 routed through cigen; the entire +`internal/platforms` template package retired). Proof: workflow-scenarios +scenario 100 runs the real `wfctl ci generate` and asserts config-derived output +(22/22). v0.68.0 / plugin v0.3.0. + +## Adversarial-review findings, scored + +| Phase | Finding | Sev | Outcome | +|---|---|---|---| +| design c1 | "mirror GitLab" wrong — GitLab lacks plan-guard/scoped-secrets | Critical | Resolved upfront — GHA named authoritative; GitLab gap recorded as follow-up | +| design c1 | Jenkins declarative multi-phase structure undefined | Important | Resolved upfront — concrete `when`/per-stage-`environment{}` sketch added | +| design c1 | proof didn't cover plugin path (acceptance #2) | Important | Resolved upfront — PR2 integration test designated | +| design c1 | Jenkins `credentials('NAME')` operator burden | Important | Resolved upfront — required-credentials header comment | +| design c2 | Jenkins `when{changeRequest()}` only works in a Multibranch job | Critical | Resolved upfront — Multibranch header comment + accepted consequence | +| design c2 | generator_test/integration_test file split + helper deletions | Important×2 | Resolved upfront — precise test-rewrite spec | +| plan c1 | Jenkins credentials test sort-fragility | Critical | Resolved upfront — per-credential assertions added | +| plan c1 | Task 6/7 broken-CI window | Critical | Resolved upfront — "no push until Task 7 green" note | +| plan c1 | release→module-proxy timing before `go get @v0.68.0` | Important | **Prescient** — the I4 poll-gate is exactly what unblocked PR2 (module resolved ~30s post-tag) | +| plan c1 | test-quality gaps (CircleCI secret, Task3 trivial, testdata richness) | Important×3 | Resolved upfront | + +Design converged in 3 cycles, plan in 2. Every code PR's two-stage review caught +a real issue (below). + +## Gate misses + +Two real misses slipped to CI/runtime — both **existence-check** misses, the exact +class autodev #55 (shipped earlier this same session) targets: + +| Issue | Gate that missed | Why it slipped | Fix | +|---|---|---|---| +| Scenario `config/app.yaml` failed the scenarios-CI strict `wfctl validate` (no entry point) | plan / local run.sh | The local proof ran only `ci generate` (cigen analyze — no entry-point requirement), never `wfctl validate`; the repo CI validates **every** `config/app.yaml` | Renamed to `config/deploy.yaml` (infra config, correctly excluded from the app-validate glob) | +| plugin `v0.2.0` already released (PR #18) — bump collided with an existing tag | plan (Task 7 guessed `0.1.6→0.2.0` from plugin.json) | Plan read the version *file* (0.1.6) but never checked existing *tags*; plugin.json had drifted below the released tag | Bumped to `v0.3.0` (PR #22) | + +Both are the **Existence / runtime-validity** bug-class verbatim: assert the +artifact you mutate/emit actually validates against the real consumer, and that +the tag/artifact you create does not already exist. The class was added to +`adversarial-design-review` in #55 the same day but was **not yet active** for +this design's reviews (it merged into the skill in parallel). Had it been live, +both misses were one `wfctl validate` / one `git ls-remote --tags` at design time. + +## What worked + +- **The I4 release-availability poll-gate was prescient** — the plan-phase + adversarial review flagged the tag→module-proxy race; the bash poll-loop + ([[feedback_ci_wait_use_bash_poll_loop]]) confirmed v0.68.0 on the proxy in + ~30s and unblocked PR2 cleanly. No "version not found" failure. +- **Two-stage code review earned its keep on every PR**: PR1 → `jenkinsCredentialUnion` + used by the circleci renderer (renamed `secretUnion`); PR2 → `minEngineVersion` + still 0.67.0 (a 0.67.0 consumer would fail plugin load) + stale doc comment. +- **Demonstration-fidelity**: scenario 100 ran the real `wfctl ci generate` + (22 assertions), not a reimplementation; honest evidence committed. +- **Cross-repo sequencing held**: PR1 merge → tag → module proxy → PR2 dep bump → + PR3, with no premature step. + +## Plugin-level follow-ups (autodev) + +The two gate misses are a **trend with the autodev #55 retro's own evidence** +(required_secrets sweep + smart-CI gen). Recommendation already shipped: the +`Existence / runtime-validity` bug-class (autodev v6.2.2). This retro is the third +data point — when that class is live in the skill, a design that (a) generates a +config a CI consumer will `validate`, or (b) creates a version tag, must show the +`validate`/`ls-remote` check at design time. No new plugin change needed; the +existing class covers both. (If a *fourth* occurrence appears with the class +live and still missed, escalate to a hard pre-flight in `finishing-a-development-branch`.) + +## Project guidance updates + +| File | Change | Reason | +|---|---|---| +| (none) | no change | No durable cross-design lesson beyond what ADR 0044 + the #55 bug-class already capture. GitLab plan-guard/scoped-secret parity is filed as a code follow-up, not guidance. |