Skip to content

Add CI workflow - #20

Merged
michaelneale merged 6 commits into
mainfrom
micn/ci-workflow
Mar 24, 2026
Merged

Add CI workflow#20
michaelneale merged 6 commits into
mainfrom
micn/ci-workflow

Conversation

@michaelneale

Copy link
Copy Markdown
Collaborator

Runs on push to main and PRs:

  • cargo test (122 unit tests, ~1s)
  • cargo fmt -- --check
  • cargo clippy -- -D warnings

Uses rust-cache for fast incremental builds. No llama.cpp needed — tests are pure Rust.

@michaelneale

Copy link
Copy Markdown
Collaborator Author

CI fails on 2 pre-existing router tests that pass on macOS but fail on Linux (float scoring tie-break differs). Not introduced by this PR — needs fixing in router.rs test expectations.

@michaelneale
michaelneale merged commit e8b653d into main Mar 24, 2026
1 check passed
ndizazzo added a commit that referenced this pull request Aug 20, 2026
…ntory doc

Container jobs resolve the default run: shell to sh -e {0}, not bash -e
{0} — bare-metal Linux/macOS runners default to bash, so this only changes
once a job gains a container: block. Two chunk-5b steps hit this:

- ci-web-slice.yml's ui_e2e preflight used a <<< here-string, which dash
  rejects with "Syntax error: redirection unexpected".
- website-pages.yml's Stage Pages artifact used set -euo pipefail, which
  dash has no -o pipefail for. This job is unreachable pre-merge
  (push-to-main, path-filtered) and would have first failed on the next
  main push touching website/** or crates/**, taking the Pages deploy down.

Both now declare shell: bash. Added
test_ci_workflow_container_shell_contract.py, a static sweep for bashisms
in container-job run: steps that have not declared shell: bash — same
blind spot as the ternary contract test, since actionlint's shellcheck
integration assumes bash.

Also fixes three defects in current-inventory.md's containerization
section: mesh-llm-runner-images-public-web does not exist as a separate
repo (the public web backend lives on mesh-llm-runner-images main, #20 and
#21); documents the Playwright-pin/@playwright-test coupling's actual
failure mode and the four-step cross-repo bump sequence; fixes five
table rows that were missing their Job(s) cell; and records the sh-vs-bash
property itself as a named convention.
ndizazzo added a commit that referenced this pull request Aug 20, 2026
…ntory doc

Container jobs resolve the default run: shell to sh -e {0}, not bash -e
{0} — bare-metal Linux/macOS runners default to bash, so this only changes
once a job gains a container: block. Two chunk-5b steps hit this:

- ci-web-slice.yml's ui_e2e preflight used a <<< here-string, which dash
  rejects with "Syntax error: redirection unexpected".
- website-pages.yml's Stage Pages artifact used set -euo pipefail, which
  dash has no -o pipefail for. This job is unreachable pre-merge
  (push-to-main, path-filtered) and would have first failed on the next
  main push touching website/** or crates/**, taking the Pages deploy down.

Both now declare shell: bash. Added
test_ci_workflow_container_shell_contract.py, a static sweep for bashisms
in container-job run: steps that have not declared shell: bash — same
blind spot as the ternary contract test, since actionlint's shellcheck
integration assumes bash.

Also fixes three defects in current-inventory.md's containerization
section: mesh-llm-runner-images-public-web does not exist as a separate
repo (the public web backend lives on mesh-llm-runner-images main, #20 and
#21); documents the Playwright-pin/@playwright-test coupling's actual
failure mode and the four-step cross-repo bump sequence; fixes five
table rows that were missing their Job(s) cell; and records the sh-vs-bash
property itself as a named convention.
ndizazzo added a commit that referenced this pull request Aug 20, 2026
…tes the bake

install-core-tools.sh#20 bakes an exact-pinned openai into the image, but
the public cpu digest pinned in ci/slices.yml predates that change
(built 2026-07-22, openai landed 2026-08-19). The containerized row of
smoke.yml was skipping the install on the assumption the image already
had it, so Core inference smoke failed with Cannot find module 'openai'.
Run it unconditionally on both rows until the digest is promoted past #20.

Also records the general lesson in current-inventory.md: a pinned digest
is a frozen artifact, and runner-images HEAD says nothing about what's
actually inside a digest a workflow pins.
ndizazzo added a commit that referenced this pull request Aug 20, 2026
Four of the five review items; the fifth is declined below with evidence.

Pin the openai npm install (smoke.yml, both call sites). The step runs with
the full job environment, HF_TOKEN included, and npm lifecycle scripts
inherit it, so a floating `openai` lets an unreviewed upstream release
execute there -- zizmor's adhoc-packages rule flags exactly this. Pinned to
7.5.0, which is deliberately the image's own ARG OPENAI_NPM_VERSION
(mesh-llm-runner-images Dockerfile:25), so that re-gating this step on
job.container.id once the CPU digest is promoted past #20 becomes a no-op
rather than a version swap.

Drop $(( )) from the container-shell bashism sweep. Arithmetic expansion is
POSIX (Shell Command Language 2.6.4) and dash evaluates it correctly
(`dash -c 'x=2; echo $((x + 3))'` -> 5), so the pattern would have rejected
valid sh steps and forced a spurious `shell: bash`. Replaced with an inline
note so it does not get re-added; the other twelve patterns are genuine
bash-only constructs and stay.

Merge job-level permissions into each callee's requested scope set
(test_ci_workflow_permission_contract.py). The set was built from the
workflow-level block alone, which returns None for a workflow that declares
its scopes only on jobs -- and line 72 then skips every caller edge for it.
That is not hypothetical here: five reusable workflows
(native-sdk-artifact, node-sdk-addon-artifact, sdk-smoke, static-abi-artifact,
swift-sdk-artifact) declare permissions at job level only, so they were
entirely invisible to the test, including their `packages: read` -- the exact
scope whose missing grant produced the zero-job startup_failure this test was
written to catch. Read-all/write-all still returns None (unenumerable, do not
assert). Still green: the callers do grant them.

Fix MD018 in current-inventory.md by writing "PR #1380" so the line no longer
opens with a hash.

Declined: routing setup-macos-lld's probe through a `just` recipe. AGENTS.md:67
"Always use `just`. Never build manually." is the Building section, about
building mesh-llm; this is a linker sanity check that compiles a throwaway
crate in RUNNER_TEMP, deliberately outside the workspace so no .cargo/config.toml
target rustflags apply to it. `just` is installed at only one of the seven call
sites (release.yml:252, covering :270) -- ci-platform-checks-slice.yml:117,
ci-macos-host-slice.yml:118, swift-sdk-artifact.yml:174,
native-sdk-artifact.yml:362, node-sdk-addon-artifact.yml:199 and release.yml:520
have no just, so the change would mean adding taiki-e/install-action to six
macOS jobs to wrap two lines, directly against this PR's own thesis of removing
such installs. It would also move the linker environment out of the composite
that owns it and run the probe from the repo root.

Inventory updated in the same change per .github/AGENTS.md: the bashism list no
longer names $(( )) and says why it must not be re-added, the openai paragraph
records the pin and the cross-repo bump pairing, and a new
"Reusable-workflow permission chain" section documents the startup_failure
class and the job-level-permissions rule.

Validated: full scripts/tests suite, 489 tests, 7 skipped, OK. actionlint clean
on smoke.yml.
ndizazzo added a commit that referenced this pull request Aug 20, 2026
…ntory doc

Container jobs resolve the default run: shell to sh -e {0}, not bash -e
{0} — bare-metal Linux/macOS runners default to bash, so this only changes
once a job gains a container: block. Two chunk-5b steps hit this:

- ci-web-slice.yml's ui_e2e preflight used a <<< here-string, which dash
  rejects with "Syntax error: redirection unexpected".
- website-pages.yml's Stage Pages artifact used set -euo pipefail, which
  dash has no -o pipefail for. This job is unreachable pre-merge
  (push-to-main, path-filtered) and would have first failed on the next
  main push touching website/** or crates/**, taking the Pages deploy down.

Both now declare shell: bash. Added
test_ci_workflow_container_shell_contract.py, a static sweep for bashisms
in container-job run: steps that have not declared shell: bash — same
blind spot as the ternary contract test, since actionlint's shellcheck
integration assumes bash.

Also fixes three defects in current-inventory.md's containerization
section: mesh-llm-runner-images-public-web does not exist as a separate
repo (the public web backend lives on mesh-llm-runner-images main, #20 and
#21); documents the Playwright-pin/@playwright-test coupling's actual
failure mode and the four-step cross-repo bump sequence; fixes five
table rows that were missing their Job(s) cell; and records the sh-vs-bash
property itself as a named convention.
ndizazzo added a commit that referenced this pull request Aug 20, 2026
…tes the bake

install-core-tools.sh#20 bakes an exact-pinned openai into the image, but
the public cpu digest pinned in ci/slices.yml predates that change
(built 2026-07-22, openai landed 2026-08-19). The containerized row of
smoke.yml was skipping the install on the assumption the image already
had it, so Core inference smoke failed with Cannot find module 'openai'.
Run it unconditionally on both rows until the digest is promoted past #20.

Also records the general lesson in current-inventory.md: a pinned digest
is a frozen artifact, and runner-images HEAD says nothing about what's
actually inside a digest a workflow pins.
ndizazzo added a commit that referenced this pull request Aug 20, 2026
Four of the five review items; the fifth is declined below with evidence.

Pin the openai npm install (smoke.yml, both call sites). The step runs with
the full job environment, HF_TOKEN included, and npm lifecycle scripts
inherit it, so a floating `openai` lets an unreviewed upstream release
execute there -- zizmor's adhoc-packages rule flags exactly this. Pinned to
7.5.0, which is deliberately the image's own ARG OPENAI_NPM_VERSION
(mesh-llm-runner-images Dockerfile:25), so that re-gating this step on
job.container.id once the CPU digest is promoted past #20 becomes a no-op
rather than a version swap.

Drop $(( )) from the container-shell bashism sweep. Arithmetic expansion is
POSIX (Shell Command Language 2.6.4) and dash evaluates it correctly
(`dash -c 'x=2; echo $((x + 3))'` -> 5), so the pattern would have rejected
valid sh steps and forced a spurious `shell: bash`. Replaced with an inline
note so it does not get re-added; the other twelve patterns are genuine
bash-only constructs and stay.

Merge job-level permissions into each callee's requested scope set
(test_ci_workflow_permission_contract.py). The set was built from the
workflow-level block alone, which returns None for a workflow that declares
its scopes only on jobs -- and line 72 then skips every caller edge for it.
That is not hypothetical here: five reusable workflows
(native-sdk-artifact, node-sdk-addon-artifact, sdk-smoke, static-abi-artifact,
swift-sdk-artifact) declare permissions at job level only, so they were
entirely invisible to the test, including their `packages: read` -- the exact
scope whose missing grant produced the zero-job startup_failure this test was
written to catch. Read-all/write-all still returns None (unenumerable, do not
assert). Still green: the callers do grant them.

Fix MD018 in current-inventory.md by writing "PR #1380" so the line no longer
opens with a hash.

Declined: routing setup-macos-lld's probe through a `just` recipe. AGENTS.md:67
"Always use `just`. Never build manually." is the Building section, about
building mesh-llm; this is a linker sanity check that compiles a throwaway
crate in RUNNER_TEMP, deliberately outside the workspace so no .cargo/config.toml
target rustflags apply to it. `just` is installed at only one of the seven call
sites (release.yml:252, covering :270) -- ci-platform-checks-slice.yml:117,
ci-macos-host-slice.yml:118, swift-sdk-artifact.yml:174,
native-sdk-artifact.yml:362, node-sdk-addon-artifact.yml:199 and release.yml:520
have no just, so the change would mean adding taiki-e/install-action to six
macOS jobs to wrap two lines, directly against this PR's own thesis of removing
such installs. It would also move the linker environment out of the composite
that owns it and run the probe from the repo root.

Inventory updated in the same change per .github/AGENTS.md: the bashism list no
longer names $(( )) and says why it must not be re-added, the openai paragraph
records the pin and the cross-repo bump pairing, and a new
"Reusable-workflow permission chain" section documents the startup_failure
class and the job-level-permissions rule.

Validated: full scripts/tests suite, 489 tests, 7 skipped, OK. actionlint clean
on smoke.yml.
ndizazzo added a commit that referenced this pull request Aug 20, 2026
…ntory doc

Container jobs resolve the default run: shell to sh -e {0}, not bash -e
{0} — bare-metal Linux/macOS runners default to bash, so this only changes
once a job gains a container: block. Two chunk-5b steps hit this:

- ci-web-slice.yml's ui_e2e preflight used a <<< here-string, which dash
  rejects with "Syntax error: redirection unexpected".
- website-pages.yml's Stage Pages artifact used set -euo pipefail, which
  dash has no -o pipefail for. This job is unreachable pre-merge
  (push-to-main, path-filtered) and would have first failed on the next
  main push touching website/** or crates/**, taking the Pages deploy down.

Both now declare shell: bash. Added
test_ci_workflow_container_shell_contract.py, a static sweep for bashisms
in container-job run: steps that have not declared shell: bash — same
blind spot as the ternary contract test, since actionlint's shellcheck
integration assumes bash.

Also fixes three defects in current-inventory.md's containerization
section: mesh-llm-runner-images-public-web does not exist as a separate
repo (the public web backend lives on mesh-llm-runner-images main, #20 and
#21); documents the Playwright-pin/@playwright-test coupling's actual
failure mode and the four-step cross-repo bump sequence; fixes five
table rows that were missing their Job(s) cell; and records the sh-vs-bash
property itself as a named convention.
ndizazzo added a commit that referenced this pull request Aug 20, 2026
…tes the bake

install-core-tools.sh#20 bakes an exact-pinned openai into the image, but
the public cpu digest pinned in ci/slices.yml predates that change
(built 2026-07-22, openai landed 2026-08-19). The containerized row of
smoke.yml was skipping the install on the assumption the image already
had it, so Core inference smoke failed with Cannot find module 'openai'.
Run it unconditionally on both rows until the digest is promoted past #20.

Also records the general lesson in current-inventory.md: a pinned digest
is a frozen artifact, and runner-images HEAD says nothing about what's
actually inside a digest a workflow pins.
ndizazzo added a commit that referenced this pull request Aug 20, 2026
Four of the five review items; the fifth is declined below with evidence.

Pin the openai npm install (smoke.yml, both call sites). The step runs with
the full job environment, HF_TOKEN included, and npm lifecycle scripts
inherit it, so a floating `openai` lets an unreviewed upstream release
execute there -- zizmor's adhoc-packages rule flags exactly this. Pinned to
7.5.0, which is deliberately the image's own ARG OPENAI_NPM_VERSION
(mesh-llm-runner-images Dockerfile:25), so that re-gating this step on
job.container.id once the CPU digest is promoted past #20 becomes a no-op
rather than a version swap.

Drop $(( )) from the container-shell bashism sweep. Arithmetic expansion is
POSIX (Shell Command Language 2.6.4) and dash evaluates it correctly
(`dash -c 'x=2; echo $((x + 3))'` -> 5), so the pattern would have rejected
valid sh steps and forced a spurious `shell: bash`. Replaced with an inline
note so it does not get re-added; the other twelve patterns are genuine
bash-only constructs and stay.

Merge job-level permissions into each callee's requested scope set
(test_ci_workflow_permission_contract.py). The set was built from the
workflow-level block alone, which returns None for a workflow that declares
its scopes only on jobs -- and line 72 then skips every caller edge for it.
That is not hypothetical here: five reusable workflows
(native-sdk-artifact, node-sdk-addon-artifact, sdk-smoke, static-abi-artifact,
swift-sdk-artifact) declare permissions at job level only, so they were
entirely invisible to the test, including their `packages: read` -- the exact
scope whose missing grant produced the zero-job startup_failure this test was
written to catch. Read-all/write-all still returns None (unenumerable, do not
assert). Still green: the callers do grant them.

Fix MD018 in current-inventory.md by writing "PR #1380" so the line no longer
opens with a hash.

Declined: routing setup-macos-lld's probe through a `just` recipe. AGENTS.md:67
"Always use `just`. Never build manually." is the Building section, about
building mesh-llm; this is a linker sanity check that compiles a throwaway
crate in RUNNER_TEMP, deliberately outside the workspace so no .cargo/config.toml
target rustflags apply to it. `just` is installed at only one of the seven call
sites (release.yml:252, covering :270) -- ci-platform-checks-slice.yml:117,
ci-macos-host-slice.yml:118, swift-sdk-artifact.yml:174,
native-sdk-artifact.yml:362, node-sdk-addon-artifact.yml:199 and release.yml:520
have no just, so the change would mean adding taiki-e/install-action to six
macOS jobs to wrap two lines, directly against this PR's own thesis of removing
such installs. It would also move the linker environment out of the composite
that owns it and run the probe from the repo root.

Inventory updated in the same change per .github/AGENTS.md: the bashism list no
longer names $(( )) and says why it must not be re-added, the openai paragraph
records the pin and the cross-repo bump pairing, and a new
"Reusable-workflow permission chain" section documents the startup_failure
class and the job-level-permissions rule.

Validated: full scripts/tests suite, 489 tests, 7 skipped, OK. actionlint clean
on smoke.yml.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant