mirror of
https://github.com/stablyai/orca.git
synced 2026-09-22 16:02:32 +00:00
* fix(skills): source released history from the committed ledger, not a tag walk verify:skill-bundle-manifest rebuilt the entire released-skill history by walking every local refs/tags/v* on each run and demanded byte-equality with the committed artifacts. Output was therefore a function of (skill bytes x local tag set x release timing), so any clone holding stray, deleted, or fork tags the committed artifacts predate rebuilt a divergent registry and failed lint. This was the 4th instance of one failure class (#8637 -> #9119 version bumps -> #9778 new tags -> local tag drift), each patched with a new tolerance rather than removing the tag coupling. Fix: the committed snapshot-registry + release-mapping ARE the released history; trust them instead of re-deriving from tags. - releasedHistoryFromCommitted() seeds generation from the committed ledger, dropping the floating unreleased tail (entries beyond what the mapping names). verify and --write are now pure functions of working-tree bytes with zero tag access. The tag walk survives only behind --rebuild-from-tags (disaster recovery), off the everyday path. - --release <version> + appendReleaseRow() perform the O(1) append of one mapping row at release cut (dedupes vs the last row, strips the v-prefix) -- the single authoritative point where working-tree bytes become an immutable released revision. - release-cut.yml runs generate --release "$VERSION" before the release commit (Node built-ins only, no install needed); pr.yml drops fetch-depth: 0 from the lint job since verify no longer needs tag history. Recognition is unaffected: the runtime uses knownSnapshots = registry.skills (all entries, incl. the tail committed at PR-merge time), so a missing mapping row only loses a version label, never recognition or the update nudge. Trade-off: lint no longer cross-checks committed historical snapshots against tags. A hand-edit to an old released entry is still caught by the runtime manifest<->registry consistency check when the current manifest points at it, and can be audited anytime with --rebuild-from-tags. Verified: verify passes committed-sourced; --write is zero-diff (byte parity); a planted stray v-tag no longer changes output; edit-stub -> --write -> --release appends the correct single row; double --release is idempotent; --rebuild-from-tags reproduces the committed artifacts. Generator tests 14 pass/ 1 skip; runtime skill-bundle-artifacts + freshness-inventory 14 pass; bundled skill guides verify passes. * fix(skills): keep one release-mapping row per version on a re-cut A cut that pushed the version bump to main but died before pushing the tag is re-cut at the same version. If skills changed in between, the second --release appended a duplicate row, and the stale one named revisions that tag never ships — which verify-skill-update-roundtrip then pairs with the tag's real bytes. Overwrite the trailing row instead (the tag is absent, so that version was never published). Refuse only when an earlier row claims the version, which the cut workflow already rejects upstream, so this cannot wedge a recovering cut.
168 lines
6.9 KiB
YAML
168 lines
6.9 KiB
YAML
name: PR Checks
|
|
|
|
on:
|
|
pull_request:
|
|
types:
|
|
- opened
|
|
- synchronize
|
|
- reopened
|
|
- ready_for_review
|
|
|
|
jobs:
|
|
verify:
|
|
runs-on: ubuntu-latest
|
|
|
|
steps:
|
|
- name: Checkout
|
|
uses: actions/checkout@v6
|
|
with:
|
|
# Why: verify:skill-bundle-manifest now checks working-tree bytes
|
|
# against the committed skill ledger (advanced only at release cut) and
|
|
# no longer walks release tags, so a shallow checkout is sufficient.
|
|
persist-credentials: false
|
|
|
|
- name: Install native build tools
|
|
run: sudo apt-get update && sudo apt-get install -y build-essential python3 zlib1g-dev zsh
|
|
|
|
- name: Setup Node.js
|
|
uses: actions/setup-node@v6
|
|
with:
|
|
node-version-file: package.json
|
|
|
|
- name: Setup pnpm
|
|
uses: pnpm/action-setup@v6
|
|
with:
|
|
run_install: false
|
|
|
|
# Why: pnpm's bundled node-gyp ships gyp_main.py without execute
|
|
# permission, which breaks native module builds (e.g. node-pty's
|
|
# postinstall) with "/bin/sh: gyp_main.py: Permission denied".
|
|
# Pin the fallback to the lockfile's node-gyp version so CI stays
|
|
# reproducible while forcing pnpm to bypass its broken bundled copy.
|
|
# Gate on runner.os == 'Linux' to match release.yml — the
|
|
# npm-global path layout this step assumes is POSIX-shaped, and the
|
|
# failure has only been observed on Linux runners. Today this job
|
|
# pins runs-on: ubuntu-latest so the guard is a no-op, but it
|
|
# prevents a silent break if a Windows/macOS matrix is added later.
|
|
- name: Use external node-gyp to avoid pnpm's bundled copy (Linux only)
|
|
if: runner.os == 'Linux'
|
|
run: |
|
|
npm install -g node-gyp@11.5.0
|
|
echo "npm_config_node_gyp=$(npm root -g)/node-gyp/bin/node-gyp.js" >> "$GITHUB_ENV"
|
|
|
|
- name: Prepare dependency install
|
|
run: |
|
|
if [ -e node_modules ]; then
|
|
ls -ld node_modules
|
|
rm -rf node_modules
|
|
fi
|
|
|
|
- name: Install dependencies
|
|
# Why: pnpm 10.24's frozen headless fast path can fail on fresh Ubuntu
|
|
# runners while creating the root node_modules. Use the normal resolver
|
|
# path, then verify package metadata stayed unchanged.
|
|
run: |
|
|
pnpm install --no-frozen-lockfile --prefer-frozen-lockfile=false
|
|
git diff --exit-code package.json pnpm-lock.yaml
|
|
|
|
- name: Lint
|
|
run: pnpm exec oxlint --format github
|
|
|
|
- name: Check styled scrollbars
|
|
run: pnpm check:styled-scrollbars
|
|
|
|
- name: Check reliability gate manifest
|
|
run: pnpm run check:reliability-gates
|
|
|
|
# Why: oxlint fails any file over max-lines that is NOT suppressed, so this
|
|
# ratchet forbids ADDING a new suppression (inline disable or mobile max
|
|
# bump). Existing oversized files are grandfathered in
|
|
# config/max-lines-baseline.txt, which may only shrink — new bypasses fail
|
|
# here with a clear message instead of silently growing the debt.
|
|
- name: Enforce max-lines ratchet (no new bypasses)
|
|
run: pnpm run check:max-lines-ratchet
|
|
|
|
# Why: the CLI embeds guide content while the skills CLI installs generated
|
|
# projections from the repository, so stale output would split those two truths.
|
|
- name: Verify bundled skill guides
|
|
run: pnpm run verify:bundled-skill-guides
|
|
|
|
- name: Verify skill freshness manifest
|
|
run: pnpm run verify:skill-bundle-manifest
|
|
|
|
# Why: project-owned type declarations must live in .ts so tsc
|
|
# actually checks them. TypeScript's skipLibCheck: true (inherited
|
|
# from @electron-toolkit/tsconfig) silently widens unresolved names
|
|
# in .d.ts to `any`, which is how #1186 shipped a broken IPC signature
|
|
# past typecheck. See docs/preload-typecheck-hole.md.
|
|
- name: Guard against project-owned .d.ts in preload/shared
|
|
run: |
|
|
matches=$(find src/preload src/shared -name '*.d.ts' 2>/dev/null || true)
|
|
if [ -n "$matches" ]; then
|
|
echo "::error::Project-owned .d.ts files are not allowed under src/preload or src/shared."
|
|
echo "Move type declarations into a .ts file so skipLibCheck does not hide errors."
|
|
echo "See docs/preload-typecheck-hole.md."
|
|
echo "Found:"
|
|
echo "$matches"
|
|
exit 1
|
|
fi
|
|
|
|
- name: Check feature wall asset budget
|
|
run: pnpm check:feature-wall-assets
|
|
|
|
- name: Verify macOS entitlements
|
|
run: pnpm verify:macos-entitlements
|
|
|
|
- name: Typecheck
|
|
run: pnpm typecheck
|
|
|
|
# Why: real old Git diagnostics differ from mocked errors. Keep the
|
|
# fallback predicates executable across the baseline, transition, and
|
|
# current command shapes so a newly added flag cannot silently regress.
|
|
- name: Verify Git binary compatibility matrix
|
|
run: |
|
|
archive="$RUNNER_TEMP/git-2.25.5.tar.gz"
|
|
source="$RUNNER_TEMP/git-2.25.5"
|
|
curl -fsSL https://www.kernel.org/pub/software/scm/git/git-2.25.5.tar.gz -o "$archive"
|
|
echo "41662c52fc16fec4963bfc41075e71f8ead6b5e386797eb6f9a1111ff95a8ddf $archive" \
|
|
| sha256sum --check
|
|
mkdir -p "$source"
|
|
tar -xzf "$archive" -C "$source" --strip-components=1
|
|
make -C "$source" -j2 NO_GETTEXT=YesPlease NO_TCLTK=YesPlease NO_PYTHON=YesPlease git
|
|
ORCA_GIT_COMPAT_BINARY="$source/git" ORCA_GIT_COMPAT_VERSION="2.25.5" \
|
|
pnpm exec vitest run --config config/vitest.config.ts \
|
|
src/shared/git-binary-compatibility.test.ts
|
|
|
|
for spec in \
|
|
"alpine/git:edge-2.38.1|2.38.1" \
|
|
"alpine/git:v2.49.1|2.49.1"; do
|
|
image="${spec%%|*}"
|
|
version="${spec#*|}"
|
|
ORCA_GIT_COMPAT_IMAGE="$image" ORCA_GIT_COMPAT_VERSION="$version" \
|
|
pnpm exec vitest run --config config/vitest.config.ts \
|
|
src/shared/git-binary-compatibility.test.ts
|
|
done
|
|
|
|
# Why: postinstall rebuilds better-sqlite3 for Electron's ABI via
|
|
# @electron/rebuild, but vitest runs under system Node.js. Rebuild
|
|
# it for Node so orchestration tests can load the native module.
|
|
- name: Rebuild better-sqlite3 for Node
|
|
run: pnpm rebuild better-sqlite3
|
|
|
|
# Why: install intentionally blocks Electron's package postinstall, but
|
|
# some unit tests import `electron` under Node and require path.txt.
|
|
- name: Install Electron package binary for tests
|
|
run: node config/scripts/install-electron-package-binary.mjs
|
|
|
|
- name: Test
|
|
run: pnpm test
|
|
|
|
- name: Build unpacked app
|
|
run: pnpm build:unpack
|
|
|
|
# Why: the packaged CLI runs outside Electron's asar integration, so
|
|
# bare runtime imports must be present in the package itself. Run from a
|
|
# temp copy so Node cannot mask missing package deps with repo node_modules.
|
|
- name: Smoke packaged CLI
|
|
run: node config/scripts/smoke-packaged-cli.mjs --app-dir=dist/linux-unpacked
|