Stop the baseline growth guard from failing open

The base-baseline lookup swallowed every git error, not just a missing file,
so any failure to read the base blob left TYPECHECK_BASELINE_BASE_PATH unset
and the job passed printing "no drift". That guard is the only thing that
catches a raised baseline: the drift check compares the tree against its own
committed baseline, so growth is invisible to it.

Ask tree objects whether the base has the file, which also distinguishes a
genuine absence from a failure, and hard-fail on anything else. The lookup is
a bare assignment because inside `[ -n "$(...)" ]` the exit status is
discarded, which would have preserved the same fail-open. Each branch now
says which one it took, since the guard is silently inactive on any PR that
introduces a baseline.

Run mobile checks on src/shared changes. Mobile's program pulls 300+ files
from there and its baseline now matches on message text, so a desktop-side
rename can reword a mobile diagnostic and redden that job for an unrelated
author, on a PR that never triggers it.

Scan the whole tree for extension shadowing rather than a list of roots that
drifts from the tsconfig globs, covering repo-root and mobile/scripts files
it previously missed, plus .mts/.cts pairs.

State what the e2e ratchet does and does not catch: identity excludes line
and column, so a new error is caught unless it exactly matches one fixed in
the same file.
This commit is contained in:
Brennan Benson
2026-08-28 03:49:48 -07:00
parent c4f33a044c
commit a1e1d295ff
4 changed files with 60 additions and 21 deletions
+18 -1
View File
@@ -12,6 +12,13 @@ on:
# Why: the mobile terminal link parsers are conformance-tested against
# these shared fixtures; desktop-side fixture edits must re-run this suite.
- 'src/shared/terminal-file-link-conformance.ts'
# Why all of src/shared: mobile's tsconfig pulls 300+ files from it, and the
# typecheck baseline now matches on message text, so a desktop-side rename can
# reword a mobile diagnostic and redden this job for an unrelated author.
- 'src/shared/**'
# Why: the mobile typecheck runs through this script and its baseline.
- 'config/scripts/typecheck-diagnostic-baseline.mjs'
- 'mobile/typecheck-test-diagnostics.json'
# Why: this job holds the only checks that load the Fastfile, so edits to
# it or to the release workflow it guards must re-run them.
- '.github/workflows/mobile.yml'
@@ -44,10 +51,20 @@ jobs:
run: |
set -euo pipefail
git cat-file -e "$BASE_SHA^{commit}"
if git cat-file -e "$BASE_SHA:mobile/typecheck-test-diagnostics.json" 2>/dev/null; then
# Why ls-tree --full-tree: it answers "does the base have this file" from tree
# objects alone, so a missing baseline is distinguishable from a git failure.
# Anything other than a clean absence aborts the step rather than silently
# leaving the growth guard unset, which would pass as "no drift".
# Why a bare assignment: inside `[ -n "$(...)" ]` the substitution's exit status
# is discarded, so a git failure would read as "base has no baseline" and pass.
base_entry="$(git ls-tree -r --full-tree --name-only "$BASE_SHA" -- mobile/typecheck-test-diagnostics.json)"
if [ -n "$base_entry" ]; then
base_baseline="$RUNNER_TEMP/typecheck-mobile-base.json"
git show "$BASE_SHA:mobile/typecheck-test-diagnostics.json" > "$base_baseline"
echo "TYPECHECK_BASELINE_BASE_PATH=$base_baseline" >> "$GITHUB_ENV"
echo "Mobile growth guard ACTIVE against $BASE_SHA."
else
echo "Mobile base has no baseline; this is the introducing PR, growth guard INACTIVE."
fi
- name: Setup Node.js
+11 -1
View File
@@ -219,10 +219,20 @@ jobs:
run: |
set -euo pipefail
git cat-file -e "$BASE_SHA^{commit}"
if git cat-file -e "$BASE_SHA:config/typecheck-e2e-diagnostics.json" 2>/dev/null; then
# Why ls-tree --full-tree: it answers "does the base have this file" from tree
# objects alone, so a missing baseline is distinguishable from a git failure.
# Anything other than a clean absence aborts the step rather than silently
# leaving the growth guard unset, which would pass as "no drift".
# Why a bare assignment: inside `[ -n "$(...)" ]` the substitution's exit status
# is discarded, so a git failure would read as "base has no baseline" and pass.
base_entry="$(git ls-tree -r --full-tree --name-only "$BASE_SHA" -- config/typecheck-e2e-diagnostics.json)"
if [ -n "$base_entry" ]; then
base_baseline="$RUNNER_TEMP/typecheck-e2e-base.json"
git show "$BASE_SHA:config/typecheck-e2e-diagnostics.json" > "$base_baseline"
echo "TYPECHECK_BASELINE_BASE_PATH=$base_baseline" >> "$GITHUB_ENV"
echo "E2E growth guard ACTIVE against $BASE_SHA."
else
echo "E2E base has no baseline; this is the introducing PR, growth guard INACTIVE."
fi
- uses: ./.github/actions/install-node-dependencies