[desgin-docs] v1.0.0 design set, Phase 1 implementation plan, and Stage 0 + Stage 1 of failproofaid #1334
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: CI | |
| on: | |
| push: | |
| branches: [main] | |
| pull_request: | |
| branches: [main] | |
| concurrency: | |
| group: ci-${{ github.ref }} | |
| cancel-in-progress: true | |
| jobs: | |
| quality: | |
| runs-on: ubuntu-latest | |
| env: | |
| FAILPROOFAI_TELEMETRY_DISABLED: "1" | |
| steps: | |
| - uses: actions/checkout@v7.0.1 | |
| - uses: oven-sh/setup-bun@v2 | |
| with: | |
| bun-version: latest | |
| - uses: actions/cache@v6 | |
| with: | |
| path: ~/.bun/install/cache | |
| key: bun-${{ runner.os }}-${{ hashFiles('bun.lock') }} | |
| restore-keys: bun-${{ runner.os }}- | |
| - name: Install dependencies | |
| uses: nick-fields/retry@v4 | |
| with: | |
| max_attempts: 3 | |
| timeout_minutes: 5 | |
| command: bun install --frozen-lockfile | |
| # Replaces the inline shell that used to live here. That shell only ever | |
| # looked at `packages/*/package.json` and `packages/wrapper/package.json`, | |
| # neither of which exists in this repository, so it passed vacuously from | |
| # the initial import onward. The script keeps those semantics and adds the | |
| # Cargo workspace version, crate version inheritance, and a ban on npm | |
| # lifecycle scripts (see scripts/check-versions.mjs). Unit-tested in | |
| # __tests__/scripts/check-versions.test.ts. | |
| - name: Check version consistency | |
| run: node scripts/check-versions.mjs | |
| # Tripwire on the published tarball's top-level shape, so a new directory | |
| # can neither silently ship nor silently fail to ship. This job does not | |
| # build, so the two gitignored build outputs (`dist`, `.next`) are skipped | |
| # with a notice here and enforced in the `build` job below, which runs the | |
| # same check against a real build. | |
| - name: Check pack allowlist | |
| run: node scripts/check-pack-allowlist.mjs | |
| # The sealed worker bundle is committed under crates/generated/ and | |
| # embedded into the daemon binary with include_str!. If it drifts from | |
| # src/policy-runtime/, the daemon evaluates policy source that no longer | |
| # exists in the tree — a divergence that produces a *wrong verdict* | |
| # rather than an error, and that no other test would notice. | |
| - name: Check sealed worker bundle is current | |
| run: bun scripts/build-sealed-bundle.ts --check | |
| # Same contract for the canonicalization tables, which are generated from | |
| # src/hooks/types.ts and likewise compiled into the daemon. | |
| - name: Check canonicalization tables are current | |
| run: | | |
| bun scripts/gen-canon-tables.ts | |
| git diff --exit-code -- crates/generated/canonicalization-tables.json \ | |
| crates/generated/enforcement-capability.json \ | |
| || { echo "::error::crates/generated/*.json is stale. Regenerate: bun scripts/gen-canon-tables.ts"; exit 1; } | |
| - name: Lint | |
| uses: nick-fields/retry@v4 | |
| with: | |
| max_attempts: 3 | |
| timeout_minutes: 5 | |
| command: bun run lint | |
| - name: Type check | |
| uses: nick-fields/retry@v4 | |
| with: | |
| max_attempts: 3 | |
| timeout_minutes: 5 | |
| command: bunx tsc --noEmit | |
| test: | |
| runs-on: ubuntu-latest | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| env-config: | |
| - { name: default, env: {} } | |
| - { name: log-debug, env: { FAILPROOFAI_LOG_LEVEL: debug } } | |
| - { name: hook-log-file, env: { FAILPROOFAI_HOOK_LOG_FILE: "1" } } | |
| env: | |
| FAILPROOFAI_TELEMETRY_DISABLED: "1" | |
| NEXT_TELEMETRY_DISABLED: "1" | |
| steps: | |
| - uses: actions/checkout@v7.0.1 | |
| - uses: oven-sh/setup-bun@v2 | |
| with: | |
| bun-version: latest | |
| - uses: actions/cache@v6 | |
| with: | |
| path: ~/.bun/install/cache | |
| key: bun-${{ runner.os }}-${{ hashFiles('bun.lock') }} | |
| restore-keys: bun-${{ runner.os }}- | |
| - name: Install dependencies | |
| uses: nick-fields/retry@v4 | |
| with: | |
| max_attempts: 3 | |
| timeout_minutes: 5 | |
| command: bun install --frozen-lockfile | |
| - name: Test (${{ matrix.env-config.name }}) | |
| uses: nick-fields/retry@v4 | |
| env: ${{ matrix.env-config.env }} | |
| with: | |
| max_attempts: 3 | |
| timeout_minutes: 10 | |
| command: bun run test:run | |
| build: | |
| runs-on: ubuntu-latest | |
| env: | |
| FAILPROOFAI_TELEMETRY_DISABLED: "1" | |
| NEXT_TELEMETRY_DISABLED: "1" | |
| steps: | |
| - uses: actions/checkout@v7.0.1 | |
| - uses: oven-sh/setup-bun@v2 | |
| with: | |
| bun-version: latest | |
| - uses: actions/cache@v6 | |
| with: | |
| path: ~/.bun/install/cache | |
| key: bun-${{ runner.os }}-${{ hashFiles('bun.lock') }} | |
| restore-keys: bun-${{ runner.os }}- | |
| - name: Install dependencies | |
| uses: nick-fields/retry@v4 | |
| with: | |
| max_attempts: 3 | |
| timeout_minutes: 5 | |
| command: bun install --frozen-lockfile | |
| - name: Build | |
| uses: nick-fields/retry@v4 | |
| with: | |
| max_attempts: 3 | |
| timeout_minutes: 10 | |
| command: bun run build | |
| # Same check the quality job runs, but against a built tree — so the | |
| # "would NOT be published" direction is fatal here. This is what stands | |
| # between `publish.yml` and shipping a package with an empty `dist/`. | |
| - name: Check pack allowlist (built tree) | |
| run: node scripts/check-pack-allowlist.mjs | |
| rust-quality: | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v7.0.1 | |
| # rust-toolchain.toml pins the channel and asks for rustfmt + clippy, so a | |
| # bare `rustup toolchain install` (no argument) reads the file and installs | |
| # exactly that. Doing it explicitly keeps the download out of the timing of | |
| # the checks, and asserting both component versions here means a toolchain | |
| # that installed without them fails on this step rather than several steps | |
| # later with "no such command: `fmt`". | |
| - name: Install pinned toolchain | |
| run: | | |
| set -euxo pipefail | |
| rustup toolchain install | |
| rustup show active-toolchain | |
| rustc --version | |
| cargo fmt --version | |
| cargo clippy --version | |
| # Plain actions/cache rather than Swatinem/rust-cache: that action derives | |
| # its key from `cargo metadata` plus a lockfile, and this workspace has | |
| # zero members and therefore no Cargo.lock, which is not a case it is | |
| # documented to handle. The requirement here is that the job be green from | |
| # the first commit, so the cache is kept dumb. Revisit once crates exist. | |
| - uses: actions/cache@v6 | |
| with: | |
| path: | | |
| ~/.cargo/registry/index | |
| ~/.cargo/registry/cache | |
| ~/.cargo/git/db | |
| target | |
| key: cargo-${{ runner.os }}-${{ hashFiles('rust-toolchain.toml', 'Cargo.lock', 'crates/*/Cargo.toml') }} | |
| restore-keys: cargo-${{ runner.os }}- | |
| # The workspace is deliberately empty for now (Stage 0 lands the plumbing | |
| # before the first crate). Verified against cargo 1.97.1: `cargo metadata` | |
| # succeeds on a zero-member workspace, but `cargo fmt --all` exits 1 with | |
| # "Failed to find targets" and `cargo clippy`/`cargo test` exit 101 with | |
| # "the manifest is virtual, and the workspace has no members". So the three | |
| # checks are gated on a crate actually existing, and the manifest itself is | |
| # validated unconditionally. The gate turns itself on with the first crate. | |
| - name: Detect crates | |
| id: crates | |
| run: | | |
| if ls crates/*/Cargo.toml >/dev/null 2>&1; then | |
| echo "present=true" >> "$GITHUB_OUTPUT" | |
| echo "Crates found — running fmt, clippy and test." | |
| else | |
| echo "present=false" >> "$GITHUB_OUTPUT" | |
| echo "::notice::No crates under crates/ yet — validating the workspace manifest only." | |
| fi | |
| - name: Validate workspace manifest | |
| run: cargo metadata --no-deps --format-version 1 > /dev/null | |
| - name: cargo fmt | |
| if: steps.crates.outputs.present == 'true' | |
| run: cargo fmt --all -- --check | |
| - name: cargo clippy | |
| if: steps.crates.outputs.present == 'true' | |
| run: cargo clippy --workspace --all-targets -- -D warnings | |
| - name: cargo test | |
| if: steps.crates.outputs.present == 'true' | |
| run: cargo test --workspace | |
| docs: | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v7.0.1 | |
| - uses: oven-sh/setup-bun@v2 | |
| with: | |
| bun-version: latest | |
| - uses: actions/cache@v6 | |
| with: | |
| path: ~/.bun/install/cache | |
| key: bun-${{ runner.os }}-${{ hashFiles('bun.lock') }} | |
| restore-keys: bun-${{ runner.os }}- | |
| - name: Install dependencies | |
| uses: nick-fields/retry@v4 | |
| with: | |
| max_attempts: 3 | |
| timeout_minutes: 5 | |
| command: bun install --frozen-lockfile | |
| - uses: actions/setup-node@v7 | |
| with: | |
| node-version: 22 | |
| - name: Install Mintlify CLI | |
| run: npm install -g mintlify | |
| # Validates docs.json structure + nav-link resolution. | |
| - name: Validate docs config | |
| working-directory: docs | |
| run: mintlify validate | |
| # Parses every MDX page with the same engine Mintlify runs at deploy | |
| # time. `mintlify validate` does NOT parse page content, so a syntax | |
| # error (e.g. a translation that breaks a JSX tag or injects a `{#id}` | |
| # heading anchor) passes that step but fails the post-merge deploy. | |
| # This catches it on the PR instead. | |
| - name: Validate MDX pages parse | |
| run: bun run validate:mdx | |
| test-e2e: | |
| runs-on: ubuntu-latest | |
| env: | |
| FAILPROOFAI_TELEMETRY_DISABLED: "1" | |
| NEXT_TELEMETRY_DISABLED: "1" | |
| steps: | |
| - uses: actions/checkout@v7.0.1 | |
| - uses: oven-sh/setup-bun@v2 | |
| with: | |
| bun-version: latest | |
| - uses: actions/cache@v6 | |
| with: | |
| path: ~/.bun/install/cache | |
| key: bun-${{ runner.os }}-${{ hashFiles('bun.lock') }} | |
| restore-keys: bun-${{ runner.os }}- | |
| - name: Install dependencies | |
| uses: nick-fields/retry@v4 | |
| with: | |
| max_attempts: 3 | |
| timeout_minutes: 5 | |
| command: bun install --frozen-lockfile | |
| - name: Build E2E fixtures | |
| run: bun build src/index.ts --outdir dist --target node --format cjs | |
| - name: E2E Hook Tests | |
| uses: nick-fields/retry@v4 | |
| with: | |
| max_attempts: 2 | |
| timeout_minutes: 10 | |
| command: bun run test:e2e |