Skip to content

cron: weekly odai cache #2

cron: weekly odai cache

cron: weekly odai cache #2

name: 'cron: weekly odai cache'
run-name: 'cron: weekly odai cache'
# Fleet-canonical on-device model cache. The fleet's keyless-AI lane (the
# weekly-update decision leg, every odai-driven assist) needs the on-device
# model present on a fresh runner: this proves the chrome-builtin backend
# runs on a public ubuntu runner, fills the ~4 GB Gemini Nano component into
# a cacheable profile, and verifies a FRESH runner restores it and prompts
# offline.
#
# The weekly schedule is load-bearing twice over: Actions caches evict after
# 7 idle days, and prune-actions-caches never evicts an entry accessed within
# its fresh window — a weekly touch keeps the one 4 GB profile entry both
# alive and prune-protected.
#
# Unlike the fleet seam (exit 69 = clean skip), this workflow FAILS LOUD on
# an unavailable backend: its whole job is evidence.
#
# The setup-odai composite provisions the pinned CLI and verified Chrome.
# Both jobs exercise the published consumer entry, independent of repo builds.
on:
workflow_dispatch:
schedule:
- cron: '17 6 * * 1'
permissions:
contents: read
concurrency:
group: on-device-model-cache
cancel-in-progress: false
env:
ODAI_PROFILE_DIR: /home/runner/.cache/odai/chrome-builtin
jobs:
fill:
cache-mode: write
name: Prepare model cache
runs-on: ${{ vars.ODAI_RUNNER || 'ubuntu-26.04' }}
timeout-minutes: 50
outputs:
component-version: ${{ steps.component.outputs.version }}
cache-key: ${{ steps.component.outputs.cache-key }}
steps:
- name: Bootstrap checkout
shell: bash
env:
GITHUB_TOKEN: ${{ github.token }}
SERVER_URL: ${{ github.server_url }}
REPOSITORY: ${{ github.repository }}
TRIGGER_REF: ${{ github.ref }}
run: |
set -euo pipefail
git init -q
git config --local advice.detachedHead false
git remote remove origin 2>/dev/null || true
git remote add origin "${SERVER_URL}/${REPOSITORY}"
FETCH_ARGS=(--no-tags --prune --depth 1 origin "${TRIGGER_REF}")
if [ -n "${GITHUB_TOKEN}" ]; then
AUTH_B64="$(printf 'x-access-token:%s' "${GITHUB_TOKEN}" | base64 | tr -d '\n')"
export GIT_CONFIG_COUNT=1
export GIT_CONFIG_KEY_0="http.${SERVER_URL}/.extraheader"
export GIT_CONFIG_VALUE_0="AUTHORIZATION: basic ${AUTH_B64}"
git fetch "${FETCH_ARGS[@]}"
else
git fetch "${FETCH_ARGS[@]}"
fi
git checkout -q --detach FETCH_HEAD
# The model download wants ~22 GB free and Chrome REMOVES an installed
# model when free disk drops under 10 GB — the stock runner image does
# not leave that headroom, so the unused preinstalled toolchains go.
- name: Reclaim runner disk
shell: bash
run: |
set -euo pipefail
df -h / | tail -1
sudo rm -rf /usr/local/lib/android /usr/share/dotnet /opt/ghc \
/usr/local/.ghcup /opt/hostedtoolcache/CodeQL
df -h / | tail -1
- name: 'Set up and install'
uses: ./.github/actions/fleet/setup-and-install
with:
socket-api-token: ${{ secrets.SOCKET_API_TOKEN_FOR_CLI_AND_SFW }}
# Reuse the Release App for a contents:read token scoped to wheelhouse.
# Both credentials enable the private release fallback. Without the
# key, hydration still pulls public GHCR anonymously.
payload-token-client-id: ${{ secrets.SOCKET_RELEASE_CLIENT_ID || vars.SOCKET_RELEASE_CLIENT_ID }}
payload-token-private-key: ${{ secrets.SOCKET_RELEASE_APP_PRIVATE_KEY }}
- name: Verify model CPU capacity
timeout-minutes: 1
shell: bash
env:
ODAI_CHROME_USER_DATA_DIR: /home/runner/.cache/odai/chrome-builtin
run: |
node scripts/fleet/ai/odai/diagnostics.mts --check-capacity --json
# Cache the model components + activation state ONLY — the same set the
# bridge's clone mode copies from a system profile. The rest of the
# user-data-dir is Chrome litter (GPU/code caches, crashpad) that would
# grow the entry on every weekly refill without bounding benefit.
- name: Restore any prior model profile
shell: bash
run: |
set -euo pipefail
node scripts/fleet/cache/restore.mts \
--path "/home/runner/.cache/odai/chrome-builtin/OptGuideOnDeviceModel" \
--path "/home/runner/.cache/odai/chrome-builtin/optimization_guide_model_store" \
--path "/home/runner/.cache/odai/chrome-builtin/OptGuideOnDeviceClassifierModel" \
--path "/home/runner/.cache/odai/chrome-builtin/Local State" \
--key "odai-nano-Linux-x64-fill-anchor" \
--restore-key "odai-nano-Linux-x64-"
- name: Provision the pinned odai CLI
uses: ./.github/actions/fleet/setup-odai
with:
allow-fill: 'false'
restore-model-cache: 'false'
require-ready: 'false'
# First activation of a fresh profile needs network for one keyless
# component-metadata exchange; with a restored profile the download is
# skipped and this doubles as the warm-path timing receipt.
- name: Download and activate model
id: fill
shell: bash
env:
ODAI_CHROME_ALLOW_DOWNLOAD: '1'
ODAI_CHROME_USER_DATA_DIR: /home/runner/.cache/odai/chrome-builtin
run: |
set -euo pipefail
printf '%s\n' \
'The fleet cascade synchronizes template-owned files across member' \
'repositories. Each wave reads the committed template state, writes' \
'byte-identical copies into every member, and commits the result' \
'with a receipt naming the template commit it mirrors. Drift between' \
'a template file and a member copy is a defect the next wave heals.' \
> /tmp/on-device-model-cache-input.txt
START="$(date +%s)"
odai summarize --backend chrome-builtin \
--input /tmp/on-device-model-cache-input.txt --timeout 240000 \
> /tmp/on-device-model-cache-fill.json
ELAPSED="$(( $(date +%s) - START ))"
node -e '
const fs = require("node:fs")
const r = JSON.parse(fs.readFileSync("/tmp/on-device-model-cache-fill.json", "utf8"))
if (typeof r.summary !== "string" || r.summary.length === 0) {
console.error("on-device-model-cache: summarize reply carries no summary string.")
process.exit(1)
}
console.log("summary:", r.summary)
'
echo "fill prompt wall time: ${ELAPSED}s"
odai backends || true
du -sh /home/runner/.cache/odai/chrome-builtin
- name: Diagnose model readiness
if: ${{ failure() && steps.fill.outcome == 'failure' }}
timeout-minutes: 1
shell: bash
env:
ODAI_CHROME_USER_DATA_DIR: /home/runner/.cache/odai/chrome-builtin
run: |
node scripts/fleet/ai/odai/diagnostics.mts --json
- name: Read the component version
id: component
shell: bash
run: |
set -euo pipefail
DIR=/home/runner/.cache/odai/chrome-builtin/OptGuideOnDeviceModel
if [ ! -d "$DIR" ]; then
echo "::error::on-device-model-cache: no model component after the fill." >&2
echo "::error::Where: $DIR on the fill runner." >&2
echo "::error::Saw vs wanted: directory absent; wanted one <component-version> subdir." >&2
echo "::error::Fix: read the fill-step log — availability() reasons are printed by the CLI." >&2
exit 1
fi
VERSIONS=("$DIR"/*)
test -e "${VERSIONS[0]}"
VERSION="${VERSIONS[0]##*/}"
echo "version=${VERSION}" >> "$GITHUB_OUTPUT"
echo "cache-key=odai-nano-Linux-x64-${VERSION}" >> "$GITHUB_OUTPUT"
echo "component version: ${VERSION}"
- name: Save the profile cache
shell: bash
env:
CACHE_KEY: ${{ steps.component.outputs.cache-key }}
run: |
set -euo pipefail
node scripts/fleet/cache/save.mts \
--path "/home/runner/.cache/odai/chrome-builtin/OptGuideOnDeviceModel" \
--path "/home/runner/.cache/odai/chrome-builtin/optimization_guide_model_store" \
--path "/home/runner/.cache/odai/chrome-builtin/OptGuideOnDeviceClassifierModel" \
--path "/home/runner/.cache/odai/chrome-builtin/Local State" \
--key "$CACHE_KEY"
verify:
cache-mode: read
name: Verify model cache
needs: fill
runs-on: ${{ vars.ODAI_RUNNER || 'ubuntu-26.04' }}
timeout-minutes: 20
steps:
- name: Bootstrap checkout
shell: bash
env:
GITHUB_TOKEN: ${{ github.token }}
SERVER_URL: ${{ github.server_url }}
REPOSITORY: ${{ github.repository }}
TRIGGER_REF: ${{ github.ref }}
run: |
set -euo pipefail
git init -q
git config --local advice.detachedHead false
git remote remove origin 2>/dev/null || true
git remote add origin "${SERVER_URL}/${REPOSITORY}"
FETCH_ARGS=(--no-tags --prune --depth 1 origin "${TRIGGER_REF}")
if [ -n "${GITHUB_TOKEN}" ]; then
AUTH_B64="$(printf 'x-access-token:%s' "${GITHUB_TOKEN}" | base64 | tr -d '\n')"
export GIT_CONFIG_COUNT=1
export GIT_CONFIG_KEY_0="http.${SERVER_URL}/.extraheader"
export GIT_CONFIG_VALUE_0="AUTHORIZATION: basic ${AUTH_B64}"
git fetch "${FETCH_ARGS[@]}"
else
git fetch "${FETCH_ARGS[@]}"
fi
git checkout -q --detach FETCH_HEAD
- name: 'Set up and install'
uses: ./.github/actions/fleet/setup-and-install
with:
socket-api-token: ${{ secrets.SOCKET_API_TOKEN_FOR_CLI_AND_SFW }}
# Reuse the Release App for a contents:read token scoped to wheelhouse.
# Both credentials enable the private release fallback. Without the
# key, hydration still pulls public GHCR anonymously.
payload-token-client-id: ${{ secrets.SOCKET_RELEASE_CLIENT_ID || vars.SOCKET_RELEASE_CLIENT_ID }}
payload-token-private-key: ${{ secrets.SOCKET_RELEASE_APP_PRIVATE_KEY }}
- name: Verify model CPU capacity
timeout-minutes: 1
shell: bash
env:
ODAI_CHROME_USER_DATA_DIR: /home/runner/.cache/odai/chrome-builtin
run: |
node scripts/fleet/ai/odai/diagnostics.mts --check-capacity --json
- name: Restore the filled profile (miss = failure)
shell: bash
env:
CACHE_KEY: ${{ needs.fill.outputs.cache-key }}
run: |
set -euo pipefail
node scripts/fleet/cache/restore.mts \
--path "/home/runner/.cache/odai/chrome-builtin/OptGuideOnDeviceModel" \
--path "/home/runner/.cache/odai/chrome-builtin/optimization_guide_model_store" \
--path "/home/runner/.cache/odai/chrome-builtin/OptGuideOnDeviceClassifierModel" \
--path "/home/runner/.cache/odai/chrome-builtin/Local State" \
--key "$CACHE_KEY" \
--fail-on-miss
- name: Provision the pinned odai CLI
uses: ./.github/actions/fleet/setup-odai
with:
allow-fill: 'false'
restore-model-cache: 'false'
require-ready: 'true'
- name: Verify model offline
shell: bash
env:
ODAI_CHROME_ALLOW_DOWNLOAD: '0'
ODAI_CHROME_USER_DATA_DIR: /home/runner/.cache/odai/chrome-builtin
run: |
set -euo pipefail
printf '%s\n' \
'A worktree keeps branch work out of the primary checkout. Each' \
'worktree shares the same object store but holds its own files,' \
'so an agent can build and test a feature branch in isolation' \
'while the default branch stays clean for other sessions.' \
> /tmp/on-device-model-cache-verify.txt
START="$(date +%s)"
odai summarize --backend chrome-builtin \
--input /tmp/on-device-model-cache-verify.txt --timeout 240000 \
> /tmp/on-device-model-cache-verify.json
ELAPSED="$(( $(date +%s) - START ))"
node -e '
const fs = require("node:fs")
const r = JSON.parse(fs.readFileSync("/tmp/on-device-model-cache-verify.json", "utf8"))
if (typeof r.summary !== "string" || r.summary.length === 0) {
console.error("on-device-model-cache: offline summarize reply carries no summary string.")
process.exit(1)
}
console.log("summary:", r.summary)
'
echo "restored-profile prompt wall time: ${ELAPSED}s"