Skip to content

dispatch-gates.mjs cannot derive check:i18n from an object-definition edit — the checker discovers its population at runtime, so no path literal exists to match #8352

Description

@os-zhuang

Found on PR #8348 (#8118), where it cost the PR a CI round: the dispatch prompt's gate list and a dispatch-gates.mjs re-derivation against the changed paths both omitted check:i18n, and the PR went red in the TypeScript Type Check job on services/service-messaging DRIFTED (4) — the object-definition edit (internal: true + a new field description on sys_http_delivery.headers_json in packages/services/service-messaging/src/objects/http-delivery.object.ts) regenerates that package's four translation bundles, and nothing in the derivation could say so.

Why the derivation structurally misses it — measured, both halves

  1. The path half cannot match.dispatch-gates.mjs matches a check to input paths by scanning the check script's own source for path literals ("watch hints"). scripts/check-i18n-bundles.mjs names none for the population it guards: it discovers its targets at runtime by walking packages/ for files namedi18n-extract.config.ts (its findExtractConfigs, ~line 106-112 — a readdirSync walk matching on the filename with p.includes('/scripts/')). The only package-path strings in its source are self-test fixture assertions (error-message literals about packages/platform-objects/...), which are not hints about what the gate watches — and would point at the wrong package if they were. So an edit under packages/services/service-messaging/src/objects/** has nothing to match against.
  2. The convention half does not know this kind.CHANGE_KIND_GATES carries exactly one kind today (adds or edits a test file). "Edits a file in a package that owns an i18n-extract.config.ts" is not a kind it knows, so the convention derivation cannot name check:i18n either. The script's own output honestly labels this residue a PM judgment call — which is exactly what failed here: two careful readers (the dispatching PM and the dev's re-derivation) both missed it.

The mechanical fix that respects the script's no-embedded-list philosophy

The trigger IS derivable at dispatch time without embedding any list: walk packages/ for i18n-extract.config.tsexactly the way the checker itself does, and match any input path that sits inside a package owning one → pnpm check:i18n. That is the same runtime-discovery approach the script already takes for workflows (extractCheckInvocations re-reads .github/workflows/*.yml every run) and for package.json script resolution — when a tenth package grows a bundle, the next derivation run sees it, no list to rot. It could land either as a second CHANGE_KIND_GATES entry whose matches does the walk, or as a small "runtime-discovered watch roots" extension to the path half; the former is smaller.

A narrower variant (match only src/objects/** inside such packages) would under-cover: the extraction reads whatever each package's config enumerates, and the config file itself is also part of the trigger surface.

Scope

scripts/pm/dispatch-gates.mjs only. Not the gate itself — check-i18n-bundles.mjs is correct and caught the drift; this card is about the derivation that is supposed to predict it. Sibling but distinct: #8162 (the derivation's self-tests run in no CI job).


Generated by Claude Code

Metadata

Metadata

Assignees

Labels

Type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions