Files
Jarvis/scripts/check-bus-protocol-version.sh
james.maes 2bb710d3e6 fix(bus): bump Injection.js placeholder to v2.3.0 + extend parity gate
The WKUserScript at packages/Bus/Sources/Bus/Resources/Injection.js
installs window.jarvisBus at document-start with a hardcoded
`protocolVersion` placeholder. Because the full TS bundle's installer
shape-checks window.jarvisBus and skip-replaces when send/receive/
onOutbound already exist (Vy() in the minified output), the placeholder
IS the version reported in helloAck at runtime. The placeholder had been
stale at 2.0.0 since the first protocol bump (2.0.0 → 2.1.0 → 2.2.0 →
2.3.0), surfacing as runtime 'HUD bundle was built against bus protocol
v2.0.0; the app expects v2.3.0' hard-fails after Phase 9's Plan 04
re-bumped the protocol.

Fix:
- Bump Injection.js's protocolVersion literal to '2.3.0'.
- Extend scripts/check-bus-protocol-version.sh to assert three-way
  parity (Swift Protocol.swift ↔ TS protocol.ts ↔ Injection.js) so
  this drift can never recur silently.

Verified: bus parity OK at v2.3.0; check-app-builds green; runtime
launch with PID 32607.
2026-05-02 06:54:46 -05:00

115 lines
4.7 KiB
Bash
Executable File

#!/usr/bin/env bash
#
# check-bus-protocol-version.sh — Xcode pre-build phase.
#
# Asserts the Swift and TS BUS_PROTOCOL_VERSION constants match, and that
# the Swift fixture directory (`packages/Bus/Tests/BusTests/Fixtures/`) is
# byte-identical to the TS fixture directory (`webview/packages/bus/fixtures/`).
#
# Load-bearing for SEC-09 — the build is the final drift catcher for
# Swift/TS wire-format parity.
#
# Usage:
# scripts/check-bus-protocol-version.sh # production
# SWIFT_FILE=... TS_FILE=... SWIFT_FIXTURES=... TS_FIXTURES=... \
# scripts/check-bus-protocol-version.sh # test-harness mode
#
# Every env var is optional and falls back to the real repo layout. Setting
# them lets the smoke-test harness point the checker at a fault-injected
# fixture directory without touching the real tree.
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
: "${REPO:=$(cd "$SCRIPT_DIR/.." && pwd)}"
: "${SWIFT_FILE:=$REPO/packages/Bus/Sources/Bus/Protocol.swift}"
: "${TS_FILE:=$REPO/webview/packages/bus/src/protocol.ts}"
: "${INJECTION_FILE:=$REPO/packages/Bus/Sources/Bus/Resources/Injection.js}"
: "${SWIFT_FIXTURES:=$REPO/packages/Bus/Tests/BusTests/Fixtures}"
: "${TS_FIXTURES:=$REPO/webview/packages/bus/fixtures}"
err() {
echo "FAIL: $*" >&2
exit 1
}
[[ -f "$SWIFT_FILE" ]] || err "Swift protocol file not found: $SWIFT_FILE"
[[ -f "$TS_FILE" ]] || err "TS protocol file not found: $TS_FILE"
[[ -f "$INJECTION_FILE" ]] || err "Injection file not found: $INJECTION_FILE"
# Extract Swift constant:
# public let BUS_PROTOCOL_VERSION: String = "x.y.z"
SWIFT_VER=$(grep -E '^[[:space:]]*public[[:space:]]+let[[:space:]]+BUS_PROTOCOL_VERSION[[:space:]]*:[[:space:]]*String[[:space:]]*=' "$SWIFT_FILE" \
| sed -E 's/.*"([^"]+)".*/\1/' \
| head -n 1)
[[ -n "$SWIFT_VER" ]] || err "BUS_PROTOCOL_VERSION not found or malformed in $SWIFT_FILE"
# Extract TS constant:
# export const BUS_PROTOCOL_VERSION = "x.y.z"
TS_VER=$(grep -E '^export[[:space:]]+const[[:space:]]+BUS_PROTOCOL_VERSION[[:space:]]*=' "$TS_FILE" \
| sed -E 's/.*"([^"]+)".*/\1/' \
| head -n 1)
[[ -n "$TS_VER" ]] || err "BUS_PROTOCOL_VERSION not found or malformed in $TS_FILE"
if [[ "$SWIFT_VER" != "$TS_VER" ]]; then
{
echo "FAIL: BUS_PROTOCOL_VERSION mismatch"
echo " Swift ($SWIFT_FILE): $SWIFT_VER"
echo " TS ($TS_FILE): $TS_VER"
echo " Bump both to the same value before building. This is SEC-09's build-breaker."
} >&2
exit 1
fi
# Extract Injection.js placeholder:
# protocolVersion: "x.y.z"
# This stub is injected at document-start in WKContentWorld and is NOT replaced
# by the full TS bundle (the bundle's installer skip-replaces when send/receive/
# onOutbound already exist on window.jarvisBus). The placeholder IS the version
# reported in helloAck — drift here causes runtime "HUD bundle was built against
# bus protocol vX.Y.Z" failures.
INJECTION_VER=$(grep -E 'protocolVersion[[:space:]]*:[[:space:]]*"' "$INJECTION_FILE" \
| sed -E 's/.*"([^"]+)".*/\1/' \
| head -n 1)
[[ -n "$INJECTION_VER" ]] || err "protocolVersion not found or malformed in $INJECTION_FILE"
if [[ "$INJECTION_VER" != "$SWIFT_VER" ]]; then
{
echo "FAIL: BUS_PROTOCOL_VERSION mismatch in Injection.js"
echo " Swift ($SWIFT_FILE): $SWIFT_VER"
echo " Injection ($INJECTION_FILE): $INJECTION_VER"
echo " Bump Injection.js's protocolVersion literal to match. The injected"
echo " stub is what window.jarvisBus.protocolVersion reports at runtime —"
echo " the full bundle does not overwrite it."
} >&2
exit 1
fi
# Assert fixture directories are byte-identical.
if [[ -d "$SWIFT_FIXTURES" && -d "$TS_FIXTURES" ]]; then
DIFF_OUT="/tmp/bus-fixture-diff.$$"
if ! /usr/bin/diff -r "$SWIFT_FIXTURES" "$TS_FIXTURES" >"$DIFF_OUT" 2>&1; then
{
echo "FAIL: fixture directories differ"
echo " Swift: $SWIFT_FIXTURES"
echo " TS: $TS_FIXTURES"
echo ""
cat "$DIFF_OUT"
} >&2
rm -f "$DIFF_OUT"
exit 1
fi
rm -f "$DIFF_OUT"
else
# In production mode both directories must exist.
# In test-harness mode (env vars set), either side may be absent.
if [[ "$REPO" == "$(cd "$SCRIPT_DIR/.." && pwd)" ]]; then
[[ -d "$SWIFT_FIXTURES" ]] || err "fixtures missing: $SWIFT_FIXTURES"
[[ -d "$TS_FIXTURES" ]] || err "fixtures missing: $TS_FIXTURES"
fi
fi
# Note: full Vitest + XCTest round-trip runs via `swift test` / `pnpm test`,
# not on every build. The grep + `diff -r` covers the wire-shape risk here.
echo "bus parity OK at v$SWIFT_VER"