-
Notifications
You must be signed in to change notification settings - Fork 0
docs: record org-wide CI workflow duplication audit (no new consolidation found) #1731
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
130 changes: 130 additions & 0 deletions
130
docs/doctoring/ci-workflow-duplication-audit-20260902.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,130 @@ | ||
| # Doctoring record: org-wide CI workflow duplication audit (2026-09-02) | ||
|
|
||
| - **Date:** 2026-09-02 | ||
| - **Subject:** the standing user directive "GitHub Actions 파일을 최대한 통합하라" (consolidate GitHub | ||
| Actions files as much as possible) had already yielded three genuine consolidations this session: | ||
| `hourly-review-repair.yml` (18 per-repository callers → one matrix-based file, ADR-0021), | ||
| `r-package-check.yml` (kaefa/nonnest2 R-CMD-check, ADR-0023, #1716), and a reusable | ||
| `dependency-review.yml` target built to reconcile mightyETL/newsdom-api/scopeweave's diverging | ||
| policies. A prior repo survey (referred to in this session as "the `wynkr83x1` survey") that found | ||
| those candidates may have run with a result-count cap, so this audit re-swept the full org for any | ||
| further duplication it might have missed. | ||
| - **Decision record:** none in `docs/adr/` — this is a negative/confirmatory finding (no new | ||
| consolidation to decide), not an architecture decision. | ||
| - **PR:** see the PR that carries this commit. | ||
| - **Method:** enumerated all 63 non-archived, non-fork `ContextualWisdomLab` repositories via | ||
| `gh api orgs/ContextualWisdomLab/repos --paginate`, listed every `.github/workflows/*.yml` file in | ||
| each (255 files total, 19 repos with no `.github/workflows` directory at all), grouped by exact | ||
| filename, and — for every filename appearing in 2+ repos — fetched and read the **full content** of | ||
| every instance, comparing triggers, job topology, permissions, actual commands/tooling, and security | ||
| posture. A shared filename was treated as a hypothesis to verify, never as evidence of duplication by | ||
| itself, per the explicit caution this session already learned from the `dependency-review.yml` | ||
| consolidation (where superficially similar files hid real severity-threshold and allowlist | ||
| differences). | ||
|
|
||
| ## Result: 19 filename groups checked, 1 real (trivial) duplicate found | ||
|
|
||
| | Filename | Repos checked | Verdict | | ||
| |---|---|---| | ||
| | `hourly-product-development.yml` | DiagramWeave, EgressWeave, OriginWeave, ThreadWeave, keyverse, noema | NOT_SAFE | | ||
| | `hourly-pr-maintenance.yml` | DiagramWeave, EgressWeave, TEPP, ThreadWeave | MIXED — DiagramWeave/ThreadWeave are a genuine duplicate | | ||
| | `hourly-product-loop.yml` | disksage, four-pillars, saju-caldav | NOT_SAFE | | ||
| | `hourly-nim-product-development.yml` | TEPP, four-pillars | NOT_SAFE | | ||
| | `dependency-review.yml` | `.github`, mightyETL, naruon, newsdom-api, scopeweave | NOT_SAFE (see note below) | | ||
| | `codeql.yml` | ContextualWisdomLab.github.io, bandscope, fast-mlsirm, keyverse, litellm-patched-proxy, mightyETL, newsdom-api, scopeweave | NOT_SAFE | | ||
| | `release.yml` | EgressWeave, ThreadWeave, bandscope, disksage, four-pillars, inkspan, newsdom-api | NOT_SAFE | | ||
| | `fuzz.yml` | clearfolio, codec-carver, contextual-orchestrator, linux-cluster-ops, scopeweave, semantic-data-portal, wardnet | NOT_SAFE | | ||
| | `tests.yml` | LineageWeave, appguardrail, newsdom-api, semantic-data-portal | NOT_SAFE | | ||
| | `ci.yml` | 26 repos (see full evidence in the workflow journal) | NOT_SAFE | | ||
| | `security-audit.yml` | aFIPC, bandscope | NOT_SAFE | | ||
| | `scorecard.yml` | litellm-patched-proxy, mightyETL | NOT_SAFE | | ||
| | `scorecard-analysis.yml` | `.github`, semantic-data-portal, wardnet | NOT_SAFE | | ||
| | `sbom.yml` | bandscope, mightyETL | NOT_SAFE | | ||
| | `publish-pypi.yml` | appguardrail, fast-mlsirm | NOT_SAFE | | ||
| | `bandit.yml` | bandscope, naruon | NOT_SAFE | | ||
| | `pr-governance.yml` | linux-cluster-ops, naruon | NOT_SAFE | | ||
| | `deploy.yml` | life-os, naruon | NOT_SAFE | | ||
| | `app-ci.yml` | gyeot, naruon | NOT_SAFE | | ||
|
|
||
| **Why NOT_SAFE, not just "different repo names":** every NOT_SAFE verdict above is backed by named, | ||
| quoted differences in *policy*, not cosmetics — different languages/toolchains (Rust vs Node vs Python | ||
| vs Java/Maven vs Java/Gradle), different security postures (SARIF upload present/absent, | ||
| `step-security/harden-runner` present/absent, `security-events: write` present/absent), different | ||
| trust models (OIDC trusted publishing vs secret-based PyPI auth), different thresholds (Bandit's | ||
| target directory and exclusions, Scorecard's `publish_results` toggle, a SARIF-finding suppression | ||
| step present in one file and absent in its closest sibling), and different job topology (job counts | ||
| from 1 to 7 within a single filename group). The full per-group evidence (concrete quoted lines, | ||
| action-pin SHAs, and reasoning) is preserved in this audit's workflow run journal — see Audit trail | ||
| below — and is too long to duplicate here without losing readability. | ||
|
|
||
| ### The one genuine duplicate: `hourly-pr-maintenance.yml` in DiagramWeave and ThreadWeave | ||
|
|
||
| Byte-for-byte identical except the cron minute offset (`13` vs `11`, a deliberate stagger to avoid | ||
| simultaneous org-wide runs) and the wording of one explanatory comment block (same substance, | ||
| different phrasing). Same job name, same job permissions, same reusable-workflow pin | ||
| (`ContextualWisdomLab/.github/.github/workflows/pr-review-merge-scheduler.yml@3f65dbee6672b78802e7d71d49c390f3817bb03b`), | ||
| same `workflow_dispatch.inputs.dry_run` block, same concurrency group pattern, same full `with:` tuning | ||
| (`max_prs: "20"`, `stale_opencode_minutes: "60"`, `project_flow: "github-flow"`, `base_branch: "main"`, | ||
| `merge_mode: "direct_or_auto"`, `enable_auto_merge: true`, and the rest). | ||
|
|
||
| **Not acted on, deliberately.** These are already two ~20-30 line thin callers of a shared reusable | ||
| workflow (`pr-review-merge-scheduler.yml`) — the duplication here is in the *configuration values* | ||
| (`with:` block), not in any logic that would benefit from a further reusable-workflow layer. Wrapping | ||
| an already-thin wrapper in another reusable workflow for two files this small would be the kind of | ||
| unrequested abstraction this repo's own conventions warn against. If a third repo adopts the identical | ||
| tuning, promoting `max_prs: "20"`/`stale_opencode_minutes: "60"`/`project_flow: "github-flow"` to | ||
| `pr-review-merge-scheduler.yml`'s own input defaults (rather than requiring every caller to repeat | ||
| them) would be the right-sized fix at that point, not a new wrapper workflow now. | ||
|
|
||
| **TEPP and EgressWeave were checked and are genuinely NOT part of this duplicate**, despite sharing the | ||
| filename and calling the same reusable workflow: TEPP passes no `with:` block at all (runs on the | ||
| reusable workflow's own defaults — `max_prs` defaults to `"100"` vs the D/T pair's explicit `"20"`, a | ||
| 5x difference in per-run scan scope; `stale_opencode_minutes` defaults to `"90"` vs `"60"`, a real | ||
| redispatch-threshold difference); EgressWeave is structurally different — two jobs instead of one, the | ||
| first calling a different reusable workflow entirely (`pr-review-fix-scheduler.yml`, autofix) and the | ||
| second running the merge scheduler with `enable_auto_merge: false` / `merge_mode: disabled` (never | ||
| merges, only rechecks) versus the D/T pair's `direct_or_auto`/`true`. | ||
|
|
||
| ### Discrepancy found: `dependency-review.yml`'s central reusable target exists but no caller has migrated to it yet | ||
|
|
||
| `.github/workflows/dependency-review.yml` is already a `workflow_call` reusable target with inputs | ||
| (`fail_on_severity`, `allow_ghsas`, `continue_on_error`) and a dynamic dependency-graph-availability | ||
| probe, and its own header comment documents that it was built specifically to reconcile policy | ||
| differences found in mightyETL/newsdom-api/scopeweave's original standalone files. However, as of this | ||
| audit, **none of the four caller repos checked (mightyETL, naruon, newsdom-api, scopeweave) has | ||
| actually switched its own `dependency-review.yml` to `uses:` the central target** — each still carries | ||
| a full standalone implementation, and those standalone implementations still genuinely diverge on | ||
| severity threshold (`high` vs `moderate` vs unset), dependency-graph-unavailability handling (a static | ||
| `private == false` job split vs a dynamic curl probe vs no gating at all), presence of | ||
| `step-security/harden-runner` (naruon only), PR trigger branch scoping (naruon only restricts to | ||
| `develop`/`master`/`release/**`), and a vulnerability allowlist entry (newsdom-api only). | ||
|
Comment on lines
+88
to
+100
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
|
|
||
| This session had understood from another agent's summary that this consolidation was "already merged" | ||
| (the central reusable workflow itself). That appears accurate for the central target's own creation, | ||
| but the caller-side migration (each of the four repos actually switching to `uses:` it) had not | ||
| happened as of this audit. Recorded here rather than silently assumed complete — a follow-up should | ||
| either confirm the caller migrations are tracked elsewhere and just not yet landed, or open the four | ||
| caller PRs, in each case checking that repo's `branch-protection required_status_checks` for the old | ||
| standalone job name first (the SHA-pin and check-run-rename pitfalls already documented in | ||
| `docs/adr/0023-r-cmd-check-reusable-workflow-consolidation.md` and PR #1728 apply identically here). | ||
|
|
||
| ## Conclusion | ||
|
|
||
| The org's earlier consolidations (hourly-review-repair, R-CMD-check, and the dependency-review reusable | ||
| target) already captured the genuinely duplicated CI logic that existed. What remains under shared | ||
| filenames is, with one trivial exception, bespoke per-repo automation that happens to share a naming | ||
| convention — different languages, different security postures, and different product-specific policy | ||
| in nearly every case checked. Further org-wide filename-based searching is unlikely to surface more | ||
| candidates; if new duplication emerges, it will more likely come from two repos independently adopting | ||
| the *same new pattern* going forward (worth catching at PR-review time) than from an archaeological | ||
| sweep of existing files. | ||
|
|
||
| ## Audit trail | ||
|
|
||
| - Workflow run `wf_9d141ecd-c03` (13 parallel agents, one per filename cluster or small bundle) — the | ||
| full per-group evidence (quoted differing lines, action-pin SHAs) lives in that run's journal. | ||
| - `docs/adr/0021-hourly-review-repair-single-file-consolidation.md`, | ||
| `docs/adr/0023-r-cmd-check-reusable-workflow-consolidation.md` — the prior genuine consolidations | ||
| this audit checked against for completeness. | ||
| - `.github/workflows/dependency-review.yml` — the already-built but not-yet-adopted reusable target | ||
| discussed above. | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🔍 Audit evidence remains private
The 19 verdicts defer their concrete evidence to
wf_9d141ecd-c03. Repository rules require durable knowledge in the repository or Project.Was this helpful? React with 👍 or 👎 to provide feedback.