Skip to content

fix(ci): gate the directory that is itself a gate - #5050

Merged
lidge-jun merged 1 commit into
devfrom
codex/5001-structure-gate
Sep 18, 2026
Merged

lidge-jun merged 1 commit into
devfrom
codex/5001-structure-gate

Conversation

@lidge-jun

@lidge-jun lidge-jun commented Sep 18, 2026

Copy link
Copy Markdown
Owner

Summary

structure/ is the one directory whose entire purpose is a gate, and it was the one directory the gate never saw.

bun run structure:check reaches CI only through tests/ci-workflows/structure-ssot.test.ts, which lives in the suite that the changes job's ci path filter decides whether to run — and that filter does not list structure/**. So a pull request touching only structure/ skipped every expensive leg and the aggregate ci check reported success over a change nothing had verified. #4999, a pure doc split, is the live example: windows, macos, macos control, test 1/4 through 4/4, gates, npm-global, docker smoke, keyring, api usage, storage policy and docs site build all reported skipped.

It stayed invisible because the ownership rule in structure/AGENTS.md means a structure/ change almost always arrives beside a src/ one, which the ci filter does match. Three pull requests hit the structure/runtime.md line budget earlier the same evening and all three were caught, precisely because they also touched src/. Only a pure doc change exposes the gap, and it took a doc reaching its size budget to produce one.

What this adds. A structure filter on the changes job, and a structure gate job that runs bun run structure:check directly when it fires.

Why not widen ci. That would close the hole too, and it would start nine Windows shards and two macOS shards on every prose edit — the cost this workflow's own comments already refuse for docs-site. The narrow job takes seconds. It runs whenever structure/ changes, including beside a src/ change where the suite covers it anyway; a duplicate of a seconds-long check is not worth a condition that could be wrong.

Why pull-request scope. The push trigger's paths: is pinned by tests/ci-workflows/ci-workflows.test.ts to equal the ci filter exactly, and structure/** deliberately is not in that filter. docs-site-build already sits in the same position. It costs nothing here: dev, main and preview are all protected to require a pull request, so no structure/ change reaches an integration line without passing through one.

Closes #5001.

Verification

This pull request verifies itself. .github/workflows/ci.yml is in both the ci filter and the new structure filter, so this run starts the full suite and the new gate.

tests/ci-workflows/ci-structure-gate.test.ts is new. It reads the condition off the job rather than naming it, so renaming the job does not quietly pass: it asserts that exactly one job is selected by needs.changes.outputs.structure == 'true' and runs bun run structure:check.

It also pins the tradeoff — structure/** must stay out of the ci filter, and the push paths: must keep mirroring ci — so a future edit that closes this hole by widening ci fails here and gets read by a human instead of silently buying a matrix run per prose edit.

The last case covers the aggregate. ci.yml's own comment promises that adding a job without declaring it there fails the gate by name, which only holds if the expected_for arm exists; a job missing from it reads as undeclared. The test asserts the needs entry, the GATED_JOBS line, the expected_for arm, and the CHANGES_STRUCTURE env.

Existing assertions checked and unaffected: the ci.on.push.paths / ci-filter equality at ci-workflows.test.ts, the aggregate's derived-needs check (which reads the workflow's own job keys, so it accepts the new job only because it is in needs), and the per-job timeout-minutes loop, which the new job satisfies at 10.

Hosted CI on this branch is the check; no local suite was run.

Checklist

  • Scope stays focused and avoids unrelated cleanup.
  • Docs or release notes were updated when needed.
  • Security-sensitive changes were reviewed for secrets, auth, and unsafe defaults.

This touches .github/workflows/, which MAINTAINERS.md puts behind security review. The new job adds no permission beyond the workflow default contents: read, reads no secret, pins actions/checkout to the same SHA every other job uses with persist-credentials: false, and uses the local ./.github/actions/setup-project-bun rather than a third-party action. It runs one repository script and no head-controlled code beyond what every other job in this workflow already runs.

Summary by CodeRabbit

  • CI Improvements

    • Added automated structure validation for changes affecting project structure or CI configuration.
    • Structure-only updates now receive targeted validation without unnecessarily starting the full cross-platform test matrix.
    • CI aggregation now reports structure validation results alongside other checks.
  • Tests

    • Added regression coverage to verify structure-change detection, workflow routing, and aggregate CI gating.

A pull request touching only `structure/` ran no test or gate leg at all, so
`tests/ci-workflows/structure-ssot.test.ts` never executed — and that test is
the only place CI runs `bun run structure:check`. The aggregate `ci` check
reported success over a change nothing had read.

The cause is the `changes` job's `ci` path filter, which does not list
`structure/**`. On #4999, a pure doc split, every expensive leg reported
`skipped`: windows, macos, macos control, test 1/4 through 4/4, gates,
npm-global, docker smoke, keyring, api usage, storage policy and docs site
build.

This adds a `structure` filter and a narrow `structure gate` job that runs the
check alone, rather than adding `structure/**` to `ci`. Widening `ci` would
also close the hole, and would start nine Windows shards and two macOS shards
for a check that takes seconds — the cost this workflow's own comments argue
against for `docs-site`.

The gate is pull-request scope, like `docs-site-build`, because the push
trigger's `paths:` is pinned to mirror the `ci` filter exactly. That costs
nothing: `dev`, `main` and `preview` are protected to require a pull request.

Closes #5001.
@lidge-jun
lidge-jun requested a review from Ingwannu as a code owner September 18, 2026 09:42
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 18, 2026

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review Completed 2026-09-18T09:45:35.235751Z 2882a48 PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@coderabbitai

coderabbitai Bot commented Sep 18, 2026

Copy link
Copy Markdown
Contributor

Review Change StackReview Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Advanced

Run ID: f72402aa-721a-4397-acef-6a3f87e2f6ee

📥 Commits

Reviewing files that changed from the base of the PR and between f3cb520 and 2882a48.

📒 Files selected for processing (2)
  • .github/workflows/ci.yml
  • tests/ci-workflows/ci-structure-gate.test.ts

Included review availability: Your plan provides up to 10 included reviews per hour; 8 remain after this review.


📝 Walkthrough

Walkthrough

The workflow now detects pull requests that change structure/, runs bun run structure:check in a dedicated job, and includes that job in aggregate CI validation. New tests verify the filter, job, trigger paths, and aggregate gate wiring.

Changes

Structure CI coverage

Layer / File(s) Summary
Structure change detection
.github/workflows/ci.yml
The changes job exposes a structure output. The pull-request filter matches structure/** and .github/workflows/ci.yml without adding structure/** to the broader ci filter.
Dedicated structure check
.github/workflows/ci.yml
The structure-gate job runs bun run structure:check on Ubuntu when the structure output is true.
Aggregate gate and regression coverage
.github/workflows/ci.yml, tests/ci-workflows/ci-structure-gate.test.ts
The aggregate ci job tracks structure-gate as requested or skipped. Tests verify the filter, output, job command, trigger paths, and aggregate gate wiring.

Priority: ➖ Normal

Estimated code review effort: 3 (Moderate) | ~20 minutes

Change: Bug fix · Severity of issue fixed: Medium

Sequence Diagram(s)

sequenceDiagram
  participant PullRequest
  participant changes
  participant structure-gate
  participant ci
  PullRequest->>changes: Evaluate structure/** filter
  changes->>structure-gate: Produce structure=true
  structure-gate->>structure-gate: Run bun run structure:check
  structure-gate->>ci: Report success
  ci->>ci: Require success for requested structure-gate
Loading

Merge Risk: ⚪ Minimal · up to 2882a

Structure-only pull requests now run the intended validation without widening the full cross-platform matrix. No actionable merge risk remains.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly describes the main change: adding a CI gate for the directory that previously lacked coverage. It is concise, specific, and related to the workflow and test changes.
Linked Issues check ✅ Passed Issue #5001 requires a pull request that changes only structure/ to run the structure validation without widening the full ci matrix. .github/workflows/ci.yml adds structure/** and `.github/wo…
Out of Scope Changes check ✅ Passed The reviewed changes are limited to .github/workflows/ci.yml and tests/ci-workflows/ci-structure-gate.test.ts. The workflow change implements the #5001 CI trigger and aggregate-gate behavior. The …
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check. Docstring coverage is scoped to functions touched by this diff. Analyzed 0 functions across 1…
✨ Finishing Touches
📝 Generate docstrings
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@lidge-jun

Copy link
Copy Markdown
Owner Author

리뷰 · 우선순위 77 / 80

이 PR은 structure/만 건드린 pull request가 CI에서 아무 게이트도 안 돌고도 초록으로 보이던 구멍을 막습니다. 지금 dev HEAD(f3cb52040, tip #5026 fix(service) bind service start to installed environment, package 2.59.0)의 .github/workflows/ci.yml을 보면, changes 잡의 ci 경로 필터에는 structure/**가 없습니다. bun run structure:check(실제로는 scripts/structure-ssot.ts)가 CI에 들어가는 길은 tests/ci-workflows/structure-ssot.test.ts뿐인데, 그 테스트는 ci 필터가 켠 스위트 안에 있습니다. 그래서 structure/만 고친 PR은 windows·macos·gates·docs-site-build까지 전부 skipped로 떨어지고, aggregate ci만 성공을 보고합니다. 이슈 #5001이 그 버그이고, #4999(순수 doc split)가 살아 있는 증거입니다.

왜 오랫동안 안 보였는지도 현재 체크아웃과 맞습니다. structure/AGENTS.md의 소유 규칙 때문에 structure/ 편집은 거의 항상 src/와 같이 옵니다. src/ci 필터에 걸리니 스위트가 돌고, 같은 저녁에 structure/runtime.md 라인 예산을 넘긴 PR 세 건은 모두 잡혔습니다. 순수 문서 변경만이 구멍을 드러내고, 문서가 사이즈 예산에 닿아 분리될 때야 그 형태가 나옵니다.

고치는 방식도 현재 devdocs-site-build 패턴을 그대로 따릅니다. ci 필터에 structure/**를 넣으면 구멍은 막히지만, 산문 한 줄마다 Windows 9샤드·macOS 2샤드가 뜹니다. 워크플로 주석이 docs-site에 대해 이미 거부한 비용입니다. 대신 (1) changesstructure 필터/outputs.structure를 추가하고, (2) structure-gate 잡이 needs.changes.outputs.structure == 'true'일 때만 bun run structure:check를 직접 돌리며, (3) aggregate cineeds·GATED_JOBS·expected_for·CHANGES_STRUCTURE까지 한 세트로 넣습니다. structure/src/가 같이 오면 스위트의 structure-ssot와 이 잡이 둘 다 도는 중복이 생기지만, 수 초짜리 검사를 막으려고 조건을 복잡하게 만들 가치는 없다는 본문 판단이 타당합니다.

새 테스트 tests/ci-workflows/ci-structure-gate.test.ts는 잡 이름을 하드코딩해 통과시키지 않고, needs.changes.outputs.structure == 'true'이면서 bun run structure:check를 돌리는 잡이 정확히 structure-gate 하나인지 읽습니다. 이름만 바꿔 조용히 통과하는 길을 막습니다. 거래도 고정합니다. filters.cistructure/**가 없고, push paths:는 계속 ci 필터와 같아야 합니다. 게이트는 PR 스코프만(보호 브랜치가 PR을 요구하니 integration 라인에는 충분). aggregate는 structure-gateundeclared가 아니라 structure 요청 상태로 기대합니다. 이 PR 자신은 ci.ymlci 필터와 structure 필터 양쪽에 들어 있어서, 풀 스위트와 새 게이트가 같이 검증됩니다. Closes #5001. types.ts/config.ts 분할 캠페인과 무관하고, 중복 PR도 아닙니다.

라인 (PR) .github/workflows/ci.yml changes.outputs.structure - docs와 같은 형태로 steps.filter.outputs.structure를 노출한다. 없으면 아래 잡의 if가 영원히 거짓이다.
라인 (PR) structure 필터 - structure/**.github/workflows/ci.yml만 넣는다. ci.yml 포함은 docs와 같은 이유(필터 자체의 PR이 새 잡을 건너뛰지 않게)다.
경로 .github/workflows/ci.yml structure-gate - checkout SHA·persist-credentials: false·로컬 setup-project-bun·bun install --frozen-lockfile·bun run structure:check만 쓴다. 시크릿·추가 permission·서드파티 액션 없음.
경로 aggregate ci needs/GATED_JOBS/expected_for/CHANGES_STRUCTURE - 네 군데를 같이 안 맞추면 잡이 돌거나 스킵돼도 aggregate가 undeclared/skipped로 구멍을 다시 만든다. 이 PR은 네 군데를 한 세트로 넣었다.
경로 tests/ci-workflows/ci-structure-gate.test.ts - ci 확장으로 구멍을 막는 미래 편집을 일부러 실패시킨다. 침묵 비용보다 사람이 읽는 실패가 낫다.

메인테이너의 판단이 필요한 지점

  • .github/workflows/MAINTAINERS.md 보안 리뷰 경계에 걸린다. 권한·시크릿 추가가 없고 기존 잡과 같은 checkout 핀이라 리스크는 낮지만, 누가 서명할지(이미 @Ingwannu 리뷰 요청됨).
  • structure/+src/ 동시 변경 때 structure:check 이중 실행을 계속 받아들일지, 아니면 나중에 “suite가 이미 돌면 잡 스킵” 조건을 넣을지.
  • push 트리거에 structure/**를 넣지 않는 거래(보호 브랜치 PR 필수에 의존)를 문서/AGENTS.md 쪽에 한 줄 더 남길지.

너의 추천
보안 리뷰 한 줄 받고 merge. Closes #5001이 본문에 있고, docs-site-build와 같은 좁은 잡 패턴·aggregate 배선·거래 핀 테스트가 갖춰져 있으니 범위 확장 없이 이대로 랜딩하는 편이 맞다. merge 후 structure/만 고친 작은 follow-up(또는 기존 #4999 형태)으로 structure gate만 돌고 매트릭스는 안 뜨는지 한 번 보면 증거가 닫힌다.

이 댓글은 grok-bot이 작성했습니다

@github-actions

Copy link
Copy Markdown
Contributor

Deterministic PR hygiene checks passed.

@github-actions github-actions Bot added the bug Something isn't working label Sep 18, 2026

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 2882a48c09

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@@ -0,0 +1,74 @@
import { expect, test } from "bun:test";

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Register the new test in both layout inventories

Add ci-structure-gate.test.ts to both scripts/test-layout/layout.json's explicit map and tests/fixtures/test-layout-expected.json. The current name happens to match the broad ci regex seed, so the layout checks tolerate it temporarily, but the repository requires every new test to be recorded in both authoritative inventories; leaving both entries absent makes the maintained test inventory incomplete.

AGENTS.md reference: AGENTS.md:L23-L27

Useful? React with 👍 / 👎.

@lidge-jun
lidge-jun merged commit 7103141 into dev Sep 18, 2026
30 of 31 checks passed
@lidge-jun
lidge-jun deleted the codex/5001-structure-gate branch September 18, 2026 10:27
lidge-jun added a commit that referenced this pull request Sep 18, 2026
…t inventories (#5075)

The regex seeds place a conventionally named file, so a regression test can sit in the tree, run in CI, and still be absent from the authoritative table. That is how the regression tests for #5050, #5051 and #5055 landed without ever entering scripts/test-layout/layout.json or tests/fixtures/test-layout-expected.json (#5059).

The two inventories are two copies of one table and the membership oracle already compares them, so both sides get the same three entries. A new test names the three files so they cannot fall out again silently, and checks that each one actually sits in the directory its registration claims.

No repository-wide explicit-registration policy is introduced here; the seeds keep carrying brand-new files as designed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant