Skip to content

feat(autonomy): add host merge revocation protocol #1661

feat(autonomy): add host merge revocation protocol

feat(autonomy): add host merge revocation protocol #1661

Workflow file for this run

name: CI
on:
push:
branches: [master]
pull_request:
branches: ["**"]
workflow_call:
permissions:
contents: read
# Feature-branch updates are validated through the PR merge ref, not an
# equivalent push checkout. Superseded PR revisions can stop safely; default
# branch pushes and reusable workflow callers retain independent full matrices.
concurrency:
group: ci-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
jobs:
ci:
# Node 22 is the hard minimum — install.sh and CONTRIBUTING.md both enforce it.
# Ubuntu is the exhaustive authority, partitioned by Vitest's deterministic
# file sharding so the full suite has margin below the hermetic hard cap.
# Windows runs named portability contracts over fleet durability,
# verification, merge authority, handoff, telemetry, and watchdog surfaces.
name: CI (Node 22, ${{ matrix.label }})
strategy:
fail-fast: false
matrix:
include:
- os: ubuntu-latest
label: ubuntu, authority 1/3
test_args: "--shard=1/3"
- os: ubuntu-latest
label: ubuntu, authority 2/3
test_args: "--shard=2/3"
- os: ubuntu-latest
label: ubuntu, authority 3/3
test_args: "--shard=3/3"
- os: windows-latest
label: windows, portability 1/3
test_args: >-
test/setup/home.test.ts test/classify.test.ts
test/m2.doctor.test.ts test/m3.tools-registry.test.ts
test/m43.verify-commands.test.ts
test/m113.coordinator-wire.test.ts test/m373.directory-durability.test.ts
test/m395.effect-terminal-retention.test.ts
test/m403.automerge-mutation-fence.test.ts
test/m404.policy-result-surfaces.test.ts
test/m428.goal-source-quality.test.ts
test/m409.engine-execution-mutation-fence.test.ts
test/m410.policy-opposing-race.test.ts
test/m414.local-store-lock-unknown-owner.test.ts
test/m415.policy-durability-races.test.ts
test/m422.policy-transaction-recovery.test.ts
test/m425.policy-startup-recovery.test.ts
test/m416.local-store-lock-handoff.test.ts
- os: windows-latest
label: windows, portability 2/3
test_args: >-
test/m21.worktree.test.ts test/m23.apply.test.ts
test/m100.web-open.test.ts test/m119.quality-metrics.test.ts
test/m332.outcome-watcher.test.ts
test/m405.apply-mutation-fence.test.ts
test/m406.daemon-stop-quiescence.test.ts
test/m411.local-merge-reconciliation.test.ts
test/m412.sandbox-pre-effect-recovery.test.ts
test/m413.engineer-run-mutation-fence.test.ts
test/m417.sandbox-cleanup-quiescence.test.ts
test/m424.legacy-swarm-mutation-fence.test.ts
test/m425.persistence-private-temp.test.ts
test/m426.sandbox-reservation-identity.test.ts
test/sandbox-reservation-recovery.test.ts
- os: windows-latest
label: windows, portability 3/3
test_args: >-
--reporter=dot
test/m315.remote-handoff-truth.test.ts
test/m372.test-ci-watchdog.test.ts
test/m423.control-plane-lock-order.test.ts
test/m455.external-skill-maturity.test.ts
test/m456.skill-retrieval-calibration.test.ts
test/m457.external-skill-artifact-firewall.test.ts
test/m460.policy-assignment-receipts.test.ts
test/m463.claimed-batch-admission.test.ts
- os: windows-latest
label: windows, portability overflow
test_args: >-
--reporter=dot
test/m220.anticlog-verdict-feedback.test.ts
test/m286.worktree-verify-env.test.ts
test/m367.daemon-observer-scheduler.test.ts
test/m379.private-storage.test.ts test/m385.cutoff-checkpoint-windows.test.ts
test/m385.cutoff-checkpoint-scheduler.test.ts
test/m407.verification-mutation-fence.test.ts
test/m408.sandbox-creation-mutation-fence.test.ts
test/m418.pulse-quiescence.test.ts
test/m419.remote-handoff-intent.test.ts
test/m420.remote-handoff-recovery.test.ts
test/m421.legacy-pulse-quiescence.test.ts
- os: macos-latest
label: macos, shared queue authority
test_args: >-
test/m111.work-queue.test.ts test/m392.queue-lease-epochs.test.ts
test/m395.effect-terminal-retention.test.ts
test/m367.daemon-observer-scheduler.test.ts
test/m455.external-skill-maturity.test.ts
test/m456.skill-retrieval-calibration.test.ts
test/m457.external-skill-artifact-firewall.test.ts
test/m460.policy-assignment-receipts.test.ts
test/m463.claimed-batch-admission.test.ts
runs-on: ${{ matrix.os }}
env:
ASHLR_VITEST_TEST_TIMEOUT_MS: ${{ matrix.os == 'windows-latest' && '30000' || '5000' }}
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Set up Node.js 22
uses: actions/setup-node@v4
with:
node-version: "22"
cache: "npm"
- name: Install dependencies
run: npm ci
- name: Typecheck
run: npm run typecheck
- name: Lint
run: npm run lint
- name: Build
run: npm run build
- name: Test (hermetic)
# scripts/test-ci.mjs isolates HOME from real ~/.ashlr/ state and adds
# inactivity and hard-runtime watchdogs. Windows portability partitions run
# serially in independent checkouts so they cannot share mutable state.
# This is the canonical CI invocation documented in CONTRIBUTING.md.
run: npm run test:ci -- ${{ matrix.test_args }}
- name: Test native alias authority (hermetic)
if: matrix.os == 'macos-latest' || matrix.label == 'windows, portability 2/3'
run: npm run test:ci -- test/m426.sandbox-reservation-identity.test.ts test/h7.rollback.test.ts
- name: Test native path and lifecycle authority (hermetic)
if: matrix.label == 'windows, portability 1/3'
run: >-
node scripts/test-native-path-lifecycle.mjs --
test/h1.fixture.test.ts test/h4.sandbox-enrollment-kill.test.ts
test/m165.self-heal.test.ts test/m201.daemon-loop.test.ts
test/m22.backlog.test.ts test/m229.goal-engine-trio.test.ts
test/m310.queued-autonomy-work.test.ts
test/m342.dispatch-production-ledger.test.ts
test/m362.repair-handoff-journal.test.ts
test/m360.generated-repair-lifecycle.test.ts
test/m353.dispatch-manifest.test.ts test/m84.goal-direct.test.ts
-t "relocates homedir\(\) to the fresh tmp HOME while active|cleanup\(\) restores the prior HOME, USERPROFILE, and ASHLR_HOME exactly|3.8 secures a fresh Windows authority root before enrollment|3.9 refuses without rewriting a pre-existing permissive Windows authority root|3.10 refuses a permissive pre-existing Windows fence directory|retires an uncommitted intent so a cross-day retry can acquire authority|materializes exact failure receipts for treatment-free capture and proposal repair lineage|recovers a failure append crash without duplicating its authoritative raw event|recovers one exact failure append beyond the analytics partition read bound|fails closed when a crashed failure append partition suffers replacement|fails closed when a crashed failure append partition suffers truncation|fails closed when a crashed failure append partition suffers mutation|bounds and crash-recovers 2,048 same-generation failures with batched assurance|recovers an interrupted retention manifest for an exact failure-receipt artifact|recovers an interrupted retention manifest for an exact failure-intent artifact|establishes exact private DACLs for attempt authority writes|exact-inspects receipt directory DACLs during pure authority reads|rejects owner-safe but non-exact Windows ACLs before parsing treatment authority|establishes exact private DACLs for treatment receipt, retention, and protocol writes|consumes protocol v5 emitted by the real dispatch writer|publishes an ordinal-2 retained proof at the writer retention cutoff|accepts an exact-inspected v2 receipt tombstone after the live receipt is retained|keeps a proven converted witness pending until exact immutable publication|retries converted publication after receipt storage is repaired|treats exact immutable publication replay as idempotent|establishes exact private DACLs for lifecycle treatment receipt and existing retention storage|journal activation authority: canonicalizes UUID casing before persistence and lookup|journal activation authority: quarantines UUID case-variant timestamp collisions|journal activation authority: reports the latest same-generation recurrence|journal activation authority: rejects recurrence authority when its immutable anchor parent is missing|journal activation authority: preserves unbound v2 rows written before activation|journal activation authority: quarantines unbound v2 rows written after activation|journal activation authority: reconciles a file-durable append crash before parent settlement|preserves the journal-wide high-water through compaction and rejects a stale writer generation|rejects a distinct writer id claiming the high-water activation instant|rejects an activation id that mutates its timestamp|degrades summary when an active-epoch recurrence loses its parent|tracks the active writer epoch without moving the immutable generation anchor|keeps the first exact route tuple as the immutable generation anchor|does not let a backdated recurrence replace the first durable anchor|quarantines a malformed claimed id across compaction and later replay|projects the immutable first v2 attempt while compaction preserves recurrence history|keeps compacted history able to quarantine a changed old replay|quarantines an exact parent with a conflicting backend/tier sibling|reports the true latest authority timestamp across current-activation generations|preserves generation proof across an intentional writer activation rollover|accepts a current physical alias only for an exactly canonical enrolled path|proves an old complete sequence from a physical attempt receipt without scanning global partitions|A0a: retargeted legacy enrollment aliases are not counted, scanned, or dispatched|A0b: a temporarily missing exact canonical enrollment degrades the tick|keeps the healthy full snapshot when an exact canonical enrollment is temporarily missing|fails closed on a legacy lexical enrollment row after its alias is retargeted|correlates a canonical proposal for a symlink-bound goal|correlates a canonical proposal for a symlink project caller|correlates a canonical swarm proposal for a lexical project caller|persists physical proposal repo identity and rejects legacy alias authority|does not derive or journal repair authority from an invalid raw repo identity|persists physical repo identity and rejects legacy lexical or linked aliases|idempotently rejects relative and secret-shaped raw repo identities without fallback rows|idempotently rejects relative and secret-shaped repo identities without unknown or cwd rows|persists physical assignment repo identity and rejects legacy alias authority"
# M33: keep the published exports map honest — pack the tarball, install
# it into a clean dir, and exercise the bin + the ./types entry point.
# M83: run once on the first Ubuntu authority shard. The tarball-exports
# check is OS-independent, and the bash heredoc is not worth porting to Windows.
- name: Pack smoke (exports map)
if: matrix.label == 'ubuntu, authority 1/3'
shell: bash
run: |
npm pack
SMOKE_DIR=$(mktemp -d)
TARBALL="$PWD"/ashlr-hub-*.tgz
cd "$SMOKE_DIR"
npm init -y > /dev/null
npm install $TARBALL > /dev/null
./node_modules/.bin/ashlr help > /dev/null
node -e "import('@ashlr/hub/types').then(() => console.log('exports map ok'))"
node -e "import('@ashlr/hub/core').then((m) => { if (typeof m.loadConfig !== 'function') throw new Error('core surface broken'); console.log('core surface ok'); })"