Skip to content

Commit f3e4a3a

Browse files
authored
ci: refine plan orchestration and Windows payload routing (#7223)
* docs(ci): define test set orchestration * docs(ci): make orchestration guidance incremental * ci: separate merge policy from validation * ci: narrow Windows payload validation * docs(ci): restructure orchestration methodology * docs(ci): treat mapping shape as architecture feedback
1 parent 274bff4 commit f3e4a3a

9 files changed

Lines changed: 984 additions & 584 deletions

File tree

.github/config/scopes.json

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
"web_tests_required",
66
"tools_dev_tests_required",
77
"tools_pack_tests_required",
8+
"windows_tools_pack_payload_tests_required",
89
"ui_critical_validation_required",
910
"ui_p0_validation_required",
1011
"visual_validation_required",
@@ -44,6 +45,29 @@
4445
"tools/pack/src/", "tools/pack/tests/", "tools/pack/resources/"
4546
]
4647
},
48+
"windows-launcher-payload": {
49+
"prefixes": [
50+
"tools/pack/src/win/", "tools/pack/resources/win/",
51+
"packages/launcher-proto/src/", "packages/sidecar-proto/src/"
52+
],
53+
"exact": [
54+
"tools/pack/src/cache.ts",
55+
"tools/pack/src/config.ts",
56+
"tools/pack/src/launcher-layout.ts",
57+
"tools/pack/src/launcher-runtime-snapshot.ts",
58+
"tools/pack/src/lock.ts",
59+
"tools/pack/src/resources.ts",
60+
"tools/pack/src/update-cache-lifecycle-snapshot.ts",
61+
"tools/pack/src/versions.ts",
62+
"tools/pack/src/win-prebundle.ts",
63+
"tools/pack/tests/launcher-payload-windows.test.ts",
64+
"packages/platform/src/command.ts",
65+
"packages/platform/src/index.ts",
66+
"packages/release/src/index.ts",
67+
"packages/sidecar/src/index.ts",
68+
"packages/sidecar/src/paths.ts"
69+
]
70+
},
4771
"daemon-core": {
4872
"prefixes": ["apps/daemon/src/", "apps/daemon/tests/"],
4973
"exact": ["docs/agent-adapters.md"],
@@ -118,6 +142,12 @@
118142
"effects": ["tools_dev_tests_required", "tools_pack_tests_required", "workspace_validation_required"],
119143
"confidence": "certain"
120144
},
145+
{
146+
"id": "certain-windows-launcher-payload",
147+
"match": { "include": ["match://windows-launcher-payload"] },
148+
"effects": ["windows_tools_pack_payload_tests_required"],
149+
"confidence": "certain"
150+
},
121151
{
122152
"id": "tools-pack-sources",
123153
"match": {
@@ -132,7 +162,7 @@
132162
"exact": ["package.json", "pnpm-lock.yaml", "pnpm-workspace.yaml", ".github/workflows/ci.yml", "e2e/package.json"],
133163
"regexes": ["^apps/[^/]+/package\\.json$", "^packages/[^/]+/package\\.json$", "^tools/[^/]+/package\\.json$"]
134164
},
135-
"effects": ["daemon_tests_required", "web_tests_required", "tools_dev_tests_required", "tools_pack_tests_required"],
165+
"effects": ["daemon_tests_required", "web_tests_required", "tools_dev_tests_required", "tools_pack_tests_required", "windows_tools_pack_payload_tests_required"],
136166
"confidence": "medium"
137167
},
138168
{

.github/scripts/scopes.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -189,7 +189,7 @@ def enabled_workloads(outputs, ci_mode, full_lanes):
189189
"preflight": True,
190190
"workspace_unit_tests": broad,
191191
"daemon_unit_tests": outputs["daemon_tests_required"],
192-
"windows_tools_pack_payload_tests": full_lanes or outputs["tools_pack_tests_required"],
192+
"windows_tools_pack_payload_tests": full_lanes or outputs["windows_tools_pack_payload_tests_required"],
193193
"web_workspace_tests": full_lanes or outputs["web_tests_required"],
194194
"e2e_vitest": full_lanes or outputs["web_tests_required"] or outputs["ui_p0_validation_required"],
195195
"playwright_critical": outputs["ui_critical_validation_required"] and not ui_p0,

.github/workflows/ci.yml

Lines changed: 63 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -384,7 +384,7 @@ jobs:
384384
runner-labels: ${{ toJSON(fromJSON(needs.runners.outputs.runs_on).windows_tools) }}
385385

386386
- name: Windows launcher payload archive tests
387-
run: pnpm --filter @open-design/tools-pack exec vitest run tests/launcher-payload.test.ts
387+
run: pnpm --filter @open-design/tools-pack exec vitest run tests/launcher-payload-windows.test.ts
388388

389389
web_workspace_tests:
390390
name: Web workspace tests (${{ matrix.shard }}/2)
@@ -661,69 +661,26 @@ jobs:
661661
if: ${{ steps.visual.outcome != 'success' }}
662662
run: exit 1
663663

664-
validate:
665-
name: Validate workspace
666-
needs:
667-
- plan
668-
- runners
669-
- static_gate
670-
- preflight
671-
- workspace_unit_tests
672-
- daemon_unit_tests
673-
- windows_tools_pack_payload_tests
674-
- web_workspace_tests
675-
- e2e_vitest
676-
- playwright_critical
677-
- ui_p0
678-
- playwright_visual
679-
if: ${{ always() }}
664+
# This policy is a sibling of the validation workloads, not their prerequisite.
665+
# Labeled merge groups still receive the same workload coverage before the
666+
# required Validate workspace check rejects the converged result.
667+
merge_policy:
668+
name: Merge policy
669+
needs: [plan, runners]
670+
if: ${{ github.event_name == 'merge_group' }}
680671
runs-on: ${{ fromJSON(needs.runners.outputs.runs_on).control }}
681672
timeout-minutes: 5
682673

683674
steps:
684-
# The merge-blocking label gate below produces a `handoff/comment` artifact when it ejects a
675+
# The merge-blocking label gate produces a `handoff/comment` artifact when it ejects a
685676
# queued PR, and that production goes through `.github/scripts/handoff.py` (the only
686-
# sanctioned source of handoff names and layout). Only the merge_group context can eject,
687-
# so pull_request runs skip the checkout entirely.
677+
# sanctioned source of handoff names and layout).
688678
- name: Checkout handoff helper
689-
if: ${{ github.event_name == 'merge_group' }}
690679
uses: actions/checkout@v6.0.2
691680
with:
692681
sparse-checkout: .github
693682
sparse-checkout-cone-mode: true
694683

695-
- name: Check workspace validation jobs
696-
env:
697-
NEEDS_JSON: ${{ toJSON(needs) }}
698-
run: |
699-
set -euo pipefail
700-
echo "$NEEDS_JSON" | jq .
701-
failures="$(echo "$NEEDS_JSON" | jq -r '
702-
to_entries[]
703-
| select(.value.result != "success" and .value.result != "skipped")
704-
| "\(.key)=\(.value.result)"')"
705-
if [ -n "$failures" ]; then
706-
echo "Workspace validation failed:"
707-
echo "$failures"
708-
exit 1
709-
fi
710-
711-
required_misses="$(echo "$NEEDS_JSON" | jq -r '
712-
. as $needs |
713-
(($needs.plan.outputs.run // "{}") | fromjson) as $run |
714-
(
715-
["plan"]
716-
+ [$run | to_entries[] | select(.value) | .key]
717-
)[]
718-
| select(($needs[.].result // "missing") != "success")
719-
| "\(.)=\($needs[.].result // "missing")"
720-
')"
721-
if [ -n "$required_misses" ]; then
722-
echo "Required validation jobs did not succeed:"
723-
echo "$required_misses"
724-
exit 1
725-
fi
726-
727684
- name: Block merge while a merge-blocking label is present
728685
id: merge_blocking_label_gate
729686
# Hard gate: a PR that still carries `needs-validation` or `needs-maintainer-check` must
@@ -895,6 +852,59 @@ jobs:
895852
name: ${{ steps.merge_blocking_label_gate.outputs.comment_name }}
896853
path: ${{ steps.merge_blocking_label_gate.outputs.comment_path }}
897854

855+
validate:
856+
name: Validate workspace
857+
needs:
858+
- plan
859+
- runners
860+
- merge_policy
861+
- static_gate
862+
- preflight
863+
- workspace_unit_tests
864+
- daemon_unit_tests
865+
- windows_tools_pack_payload_tests
866+
- web_workspace_tests
867+
- e2e_vitest
868+
- playwright_critical
869+
- ui_p0
870+
- playwright_visual
871+
if: ${{ always() }}
872+
runs-on: ${{ fromJSON(needs.runners.outputs.runs_on).control }}
873+
timeout-minutes: 5
874+
875+
steps:
876+
- name: Check workspace validation jobs
877+
env:
878+
NEEDS_JSON: ${{ toJSON(needs) }}
879+
run: |
880+
set -euo pipefail
881+
echo "$NEEDS_JSON" | jq .
882+
failures="$(echo "$NEEDS_JSON" | jq -r '
883+
to_entries[]
884+
| select(.value.result != "success" and .value.result != "skipped")
885+
| "\(.key)=\(.value.result)"')"
886+
if [ -n "$failures" ]; then
887+
echo "Workspace validation failed:"
888+
echo "$failures"
889+
exit 1
890+
fi
891+
892+
required_misses="$(echo "$NEEDS_JSON" | jq -r '
893+
. as $needs |
894+
(($needs.plan.outputs.run // "{}") | fromjson) as $run |
895+
(
896+
["plan"]
897+
+ [$run | to_entries[] | select(.value) | .key]
898+
)[]
899+
| select(($needs[.].result // "missing") != "success")
900+
| "\(.)=\($needs[.].result // "missing")"
901+
')"
902+
if [ -n "$required_misses" ]; then
903+
echo "Required validation jobs did not succeed:"
904+
echo "$required_misses"
905+
exit 1
906+
fi
907+
898908
- name: Download pending hash map
899909
uses: actions/download-artifact@v8
900910
continue-on-error: true

AGENTS.md

Lines changed: 62 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ This file is the single source of truth for agents entering this repository. Rea
88
- Contribution and environment: `CONTRIBUTING.md`, `docs/i18n/CONTRIBUTING.zh-CN.md`.
99
- Architecture and protocols: `docs/architecture.md`, `docs/skills-protocol.md`, `docs/agent-adapters.md`, `docs/modes.md`.
1010
- Historical product baseline: `docs/spec.md`, `docs/roadmap.md` (both explicitly archived; do not treat their dated decisions as current behavior).
11-
- References and current plans: `docs/references.md`, `docs/code-review-guidelines.md`, `specs/current/maintainability-roadmap.md`, `specs/current/ci.md` (CI scope confidence methodology — required before changing confidence or guard fields in `scripts/scopes.ts`).
11+
- References and current plans: `docs/references.md`, `docs/code-review-guidelines.md`, `specs/current/maintainability-roadmap.md`, `specs/current/ci.md` (CI scope confidence methodology — required before changing planner confidence, routing, or omission policy in `.github/config/scopes.json` and `.github/scripts/scopes.py`).
1212
- Directory-level agent guidance: `.github/AGENTS.md`, `apps/AGENTS.md`, `packages/AGENTS.md`, `tools/AGENTS.md`, `e2e/AGENTS.md`.
1313
- Packaged auto-update architecture and high-confidence local harness: read `tools/pack/AGENTS.md` section "Packaged auto-update architecture and harness" before touching packaged updater code, release-channel identity, installer behavior, or updater UI.
1414
- Packaged build cache contract: `tools/pack/CACHE.md` (determinant rules, materialization-time parameters, confidence grading — required before changing any build-cache node key).
@@ -151,6 +151,67 @@ CI-related GitHub automation uses a two-layer architecture:
151151

152152
Do not add a new business-named follow-on workflow such as `foo.comment.atom.yml` or `bar.autofix.atom.yml` without first trying to express the flow as a `ci.yml` producer plus the existing `comment`, `autofix`, or `report` capability. Keep artifact naming, storage layout, and parser behavior centralized in `.github/scripts/handoff.py`; do not let individual workflows invent parallel handoff conventions.
153153

154+
## CI test-set orchestration guidance
155+
156+
Use the following as a recommended convergence model, not a repository-wide
157+
conformance gate. Existing workflows and coarse test lanes may remain while
158+
their boundaries are understood. Do not block an unrelated change or require it
159+
to repay adjacent orchestration debt solely because it touches an existing
160+
lane. Apply these recommendations incrementally when the local scope and
161+
measured scheduling benefit justify the migration.
162+
163+
Prefer one selection direction: changed paths → source units → test sets →
164+
execution workloads. Because the `plan` job runs before and governs downstream
165+
jobs, new omission policy should live in the planner rather than rely on a
166+
downstream guard to justify it after scheduling has already occurred.
167+
168+
When a CI area is being reorganized, prefer three named responsibilities:
169+
170+
- **Source units** name stable ownership or behavior boundaries in production,
171+
test, fixture, and control-plane paths. Prefer composing repeated selectors
172+
under a named unit instead of copying prefixes into unrelated rules.
173+
- **Test sets** name independently useful semantic validation groups. Their
174+
membership and execution contract should converge on one authoritative
175+
declaration instead of accumulating more matrix or file-list copies across
176+
planner configuration, workflow YAML, and framework-local registries.
177+
- **Routes** map source units to the test sets required to validate them. Routes
178+
should express impact rather than runner mechanics; runner image, setup,
179+
sharding, and job packing can remain execution concerns derived after
180+
selection.
181+
182+
Good split candidates have a stable boundary, change work that can actually be
183+
omitted, and carry enough runtime cost or diagnostic value to justify another
184+
scheduling identity. Directory size, file count, or the ability to write a
185+
narrower glob is weak evidence on its own. Prefer a small number of composable
186+
semantic units over per-file mappings, exception lists, or negative-rule
187+
forests. Treat existing duplicated or implicit declarations as migration
188+
surfaces without requiring every nearby change to remove them.
189+
190+
Before promoting a new route from observation to active omission, retain
191+
conservative behavior such as:
192+
193+
- unknown, mixed, unresolved, invalid, or below-threshold input selects the
194+
conservative full plan;
195+
- editing a test, fixture, or suite manifest selects the test set that consumes
196+
it; shared harness, contract, setup, or lockfile changes fan out to every
197+
affected set;
198+
- making a selected test-set identifier that the executor cannot run fail
199+
visibly instead of being ignored;
200+
- direct planner tests cover representative in-bound, out-of-bound, mixed, and
201+
fallback inputs without reimplementing the evaluator in another language.
202+
203+
Keep scope routing and hash invalidation conceptually orthogonal: scope answers
204+
which test sets are necessary for a change, while hash answers whether the
205+
selected workload's declared inputs equal a previous invocation. New designs
206+
should not use hash equality to weaken source-to-test coverage or copy route
207+
policy into `.github/config/hash.json`.
208+
209+
For work whose purpose is CI orchestration, start by inventorying the current
210+
chain from changed path to match, effect, workload, job command, and concrete
211+
test cases. Prefer naming or removing implicit joins before making them finer.
212+
Changes under `.github/` must also follow `.github/AGENTS.md` and the current
213+
confidence methodology in `specs/current/ci.md`.
214+
154215
## Release channel model
155216

156217
- `beta` is the daily R&D/development validation channel. It is optimized for fast development feedback and is not part of the stable promotion gate.

0 commit comments

Comments
 (0)