diff --git a/.github/workflows/e2e-parity-compare.yaml b/.github/workflows/e2e-parity-compare.yaml new file mode 100644 index 0000000000..9d985adc99 --- /dev/null +++ b/.github/workflows/e2e-parity-compare.yaml @@ -0,0 +1,161 @@ +# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +# +# E2E parity compare. +# +# Runs a legacy `test/e2e/test-*.sh` script AND its migrated scenario on +# the same runner, collects PASS/FAIL per assertion from both, and fails +# the job if any mapped assertion in test/e2e/docs/parity-map.yaml diverges. +# +# Manual-only (workflow_dispatch). Each migration phase dispatches this +# workflow for every scenario it introduces and records zero-divergence +# before marking the phase complete. + +name: e2e-parity-compare + +on: + workflow_dispatch: + inputs: + legacy_script: + description: "Legacy script filename under test/e2e/ (e.g. test-full-e2e.sh). Empty = no legacy run, empty-diff only." + required: false + default: "" + type: string + scenario: + description: "Migrated scenario id (e.g. ubuntu-repo-cloud-openclaw). Empty = use script map/default bucket scenarios." + required: false + default: "" + type: string + bucket: + description: "Parity bucket to run (onboarding-baseline, lifecycle, rebuild-runtime, providers-messaging, final-security-policy-platform-misc)." + required: false + default: "" + type: string + all_migrated: + description: "Run all migrated buckets from parity-map.yaml." + required: false + default: false + type: boolean + strict: + description: "Pass --strict to compare-parity.sh and fail on missing mapped log assertions." + required: false + default: true + type: boolean + deferred_handling: + description: "How deferred/retired assertions are handled by reporting." + required: false + default: "skip" + type: choice + options: + - skip + - report + +permissions: + contents: read + +concurrency: + group: e2e-parity-compare-${{ github.event.inputs.legacy_script }}-${{ github.event.inputs.scenario }} + cancel-in-progress: false + +jobs: + resolve-runner: + runs-on: ubuntu-latest + outputs: + runner: ${{ steps.pick.outputs.runner }} + steps: + - id: pick + env: + SCENARIO: ${{ github.event.inputs.scenario }} + run: | + case "${SCENARIO}" in + macos-*) echo "runner=macos-latest" >> "$GITHUB_OUTPUT" ;; + wsl-*) echo "runner=windows-latest" >> "$GITHUB_OUTPUT" ;; + gpu-*) echo "runner=self-hosted" >> "$GITHUB_OUTPUT" ;; + ubuntu-*|brev-*|"") echo "runner=ubuntu-latest" >> "$GITHUB_OUTPUT" ;; + *) + echo "::error::Unknown scenario prefix for runner selection: ${SCENARIO}" >&2 + exit 1 + ;; + esac + + compare: + needs: resolve-runner + runs-on: ${{ needs.resolve-runner.outputs.runner }} + timeout-minutes: 60 + steps: + - uses: actions/checkout@v4 + + - name: Set up Node + uses: actions/setup-node@v4 + with: + node-version: 22 + cache: npm + + - name: Install root dependencies + run: npm ci --ignore-scripts + + - name: Run legacy script + id: legacy + if: ${{ github.event.inputs.legacy_script != '' }} + env: + NVIDIA_API_KEY: ${{ secrets.NVIDIA_API_KEY }} + run: | + mkdir -p .e2e/parity + LOG=".e2e/parity/legacy.log" + if [ ! -x "test/e2e/${{ github.event.inputs.legacy_script }}" ]; then + echo "::error::legacy script not found: test/e2e/${{ github.event.inputs.legacy_script }}" + exit 1 + fi + bash "test/e2e/${{ github.event.inputs.legacy_script }}" 2>&1 | tee "$LOG" || true + + - name: Run migrated scenario + id: scenario + if: ${{ github.event.inputs.scenario != '' }} + env: + NVIDIA_API_KEY: ${{ secrets.NVIDIA_API_KEY }} + run: | + mkdir -p .e2e/parity + LOG=".e2e/parity/scenario.log" + bash test/e2e/runtime/run-scenario.sh "${{ github.event.inputs.scenario }}" 2>&1 | tee "$LOG" || true + + - name: Compare parity + env: + LEGACY_SCRIPT: ${{ github.event.inputs.legacy_script }} + run: | + mkdir -p .e2e/parity + LEGACY_LOG=".e2e/parity/legacy.log" + SCENARIO_LOG=".e2e/parity/scenario.log" + [ -f "$LEGACY_LOG" ] || : > "$LEGACY_LOG" + [ -f "$SCENARIO_LOG" ] || : > "$SCENARIO_LOG" + SCRIPT_ARG="${LEGACY_SCRIPT:-none.sh}" + REPORT=".e2e/parity/parity-report.json" + STRICT_ARGS=() + if [ "${{ github.event.inputs.strict }}" = "true" ]; then + STRICT_ARGS+=(--strict) + fi + bash scripts/e2e/compare-parity.sh \ + --script "$SCRIPT_ARG" \ + --legacy "$LEGACY_LOG" \ + --scenario "$SCENARIO_LOG" \ + --map test/e2e/docs/parity-map.yaml \ + --bucket "${{ github.event.inputs.bucket }}" \ + --all-migrated "${{ github.event.inputs.all_migrated }}" \ + --deferred-handling "${{ github.event.inputs.deferred_handling }}" \ + --report "$REPORT" \ + "${STRICT_ARGS[@]}" + + - name: Render coverage report + if: always() + run: | + mkdir -p .e2e/parity + bash test/e2e/runtime/coverage-report.sh > .e2e/parity/coverage-report.md + + - name: Upload parity artifacts + if: always() + uses: actions/upload-artifact@v4 + with: + name: e2e-parity-${{ github.event.inputs.scenario }}-${{ github.event.inputs.legacy_script }} + path: | + .e2e/ + if-no-files-found: warn + retention-days: 14 diff --git a/.github/workflows/e2e-scenarios.yaml b/.github/workflows/e2e-scenarios.yaml new file mode 100644 index 0000000000..3e7f4d80a1 --- /dev/null +++ b/.github/workflows/e2e-scenarios.yaml @@ -0,0 +1,112 @@ +# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +# +# Scenario-based E2E. Runs a single setup scenario by id against the +# matching runner; can also validate resolution / coverage via --plan-only. +# +# Manual-only (workflow_dispatch) while scenario-based coverage migrates. +# Existing nightly-e2e / macos-e2e / wsl-e2e workflows remain unchanged. + +name: e2e-scenarios + +on: + workflow_dispatch: + inputs: + scenario: + description: "Scenario id (e.g. ubuntu-repo-cloud-openclaw)" + required: true + type: string + plan_only: + description: "Resolve and print plan only (no install/onboard/suites)" + required: false + default: "false" + type: choice + options: + - "true" + - "false" + suite_filter: + description: "Comma-separated suite ids to run (optional; defaults to the scenario's full suite list)" + required: false + default: "" + type: string + +permissions: + contents: read + +concurrency: + group: e2e-scenarios-${{ github.event.inputs.scenario }} + cancel-in-progress: false + +jobs: + # Route the scenario to the correct runner. + # + # Scenario ids encode their target platform as the first segment + # (e.g. `macos-repo-cloud-openclaw`, `wsl-repo-cloud-openclaw`, + # `gpu-repo-local-ollama-openclaw`). The workflow previously pinned + # `runs-on: ubuntu-latest` for every scenario, which caused non-Ubuntu + # scenarios to fail on the wrong runner (CodeRabbit review item #1). + resolve-runner: + runs-on: ubuntu-latest + outputs: + runner: ${{ steps.pick.outputs.runner }} + steps: + - id: pick + env: + SCENARIO: ${{ github.event.inputs.scenario }} + run: | + case "${SCENARIO}" in + macos-*) echo "runner=macos-latest" >> "$GITHUB_OUTPUT" ;; + wsl-*) echo "runner=windows-latest" >> "$GITHUB_OUTPUT" ;; + gpu-*) echo "runner=self-hosted" >> "$GITHUB_OUTPUT" ;; + ubuntu-*|brev-*) echo "runner=ubuntu-latest" >> "$GITHUB_OUTPUT" ;; + *) + echo "::error::Unknown scenario prefix for runner selection: ${SCENARIO}" >&2 + exit 1 + ;; + esac + + run-scenario: + needs: resolve-runner + runs-on: ${{ needs.resolve-runner.outputs.runner }} + timeout-minutes: 45 + steps: + - uses: actions/checkout@v4 + + - name: Set up Node + uses: actions/setup-node@v4 + with: + node-version: 22 + cache: npm + + - name: Install root dependencies + run: npm ci --ignore-scripts + + - name: Render coverage report + run: | + mkdir -p .e2e + bash test/e2e/runtime/coverage-report.sh > .e2e/coverage.md + echo '## E2E scenario coverage' >> "$GITHUB_STEP_SUMMARY" + cat .e2e/coverage.md >> "$GITHUB_STEP_SUMMARY" + + - name: Show resolved plan + run: | + bash test/e2e/runtime/run-scenario.sh "${{ github.event.inputs.scenario }}" --plan-only + + - name: Run scenario + if: github.event.inputs.plan_only != 'true' + env: + NVIDIA_API_KEY: ${{ secrets.NVIDIA_API_KEY }} + E2E_SUITE_FILTER: ${{ github.event.inputs.suite_filter }} + run: | + bash test/e2e/runtime/run-scenario.sh "${{ github.event.inputs.scenario }}" + + - name: Upload scenario artifacts + if: always() + uses: actions/upload-artifact@v4 + with: + name: e2e-scenario-${{ github.event.inputs.scenario }} + path: | + .e2e/ + test/e2e/logs/ + if-no-files-found: warn + retention-days: 14 diff --git a/.gitignore b/.gitignore index 10836b7127..64a4026f61 100644 --- a/.gitignore +++ b/.gitignore @@ -46,3 +46,4 @@ secrets.json secrets.yaml service-account*.json token.json +.e2e/ diff --git a/AGENTS.md b/AGENTS.md index b259129c8c..655f602918 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -27,7 +27,7 @@ This repo ships agent skills under `.agents/skills/`, organized into three audie | `nemoclaw-blueprint/model-specific-setup/` | JSON | Agent-scoped model/provider compatibility registry | | `scripts/` | Bash/JS/TS | Install helpers, setup, automation, E2E tooling | | `test/` | JavaScript (ESM) | Root-level integration tests (Vitest) | -| `test/e2e/` | Bash/JS | End-to-end tests (Brev cloud instances) | +| `test/e2e/` | Bash/JS/TS | End-to-end tests, scenario-based runner (see `test/e2e/README.md`) | | `docs/` | Markdown (MyST) | User-facing docs (Sphinx) | ## Quick Reference diff --git a/scripts/e2e/check-parity-map.ts b/scripts/e2e/check-parity-map.ts new file mode 100755 index 0000000000..38366318cb --- /dev/null +++ b/scripts/e2e/check-parity-map.ts @@ -0,0 +1,262 @@ +#!/usr/bin/env tsx +// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +/** Validate legacy assertion parity-map.yaml against generated inventory. */ + +import fs from "node:fs"; +import path from "node:path"; +import { fileURLToPath } from "node:url"; +import yaml from "js-yaml"; + +const SCRIPT_STATUSES = new Set([ + "not-started", + "migrated", + "parity-verified", + "deferred", + "retired", +]); +const ASSERTION_STATUSES = new Set(["mapped", "deferred", "retired"]); + +type AssertionStatus = "mapped" | "deferred" | "retired"; + +interface InventoryAssertion { + text: string; +} + +interface InventoryEntrypoint { + script: string; + assertions: InventoryAssertion[]; +} + +interface Inventory { + entrypoints: InventoryEntrypoint[]; +} + +interface ParityAssertion { + legacy?: unknown; + id?: unknown; + status?: unknown; + reason?: unknown; + owner?: unknown; + runner_requirement?: unknown; + secret_requirement?: unknown; + reviewer?: unknown; + approved_at?: unknown; + reusable?: unknown; +} + +interface ParityScript { + scenario?: unknown; + status?: unknown; + owner?: unknown; + assertions?: unknown; +} + +interface ParityMap { + scripts?: Record; +} + +interface ValidationOptions { + root: string; + strict: boolean; +} + +function repoRootFromScript(): string { + return path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..", ".."); +} + +function parseArgs(argv: string[]): ValidationOptions { + let root = repoRootFromScript(); + let strict = false; + const args = argv.slice(2); + while (args.length > 0) { + const arg = args.shift()!; + if (arg === "--root") root = path.resolve(args.shift() ?? ""); + else if (arg === "--strict") strict = true; + else if (arg === "-h" || arg === "--help") { + process.stdout.write("tsx scripts/e2e/check-parity-map.ts [--root ] [--strict]\n"); + process.exit(0); + } else { + process.stderr.write(`check-parity-map: unexpected arg: ${arg}\n`); + process.exit(2); + } + } + return { root, strict }; +} + +function basenameScript(scriptPath: string): string { + return path.basename(scriptPath); +} + +function isNonEmptyString(value: unknown): value is string { + return typeof value === "string" && value.trim().length > 0; +} + +function loadInventory(root: string): Inventory { + const inventoryPath = path.join(root, "test/e2e/docs/parity-inventory.generated.json"); + return JSON.parse(fs.readFileSync(inventoryPath, "utf8")) as Inventory; +} + +function loadParityMap(root: string): ParityMap { + const mapPath = path.join(root, "test/e2e/docs/parity-map.yaml"); + const loaded = yaml.load(fs.readFileSync(mapPath, "utf8")); + if (!loaded || typeof loaded !== "object") return { scripts: {} }; + return loaded as ParityMap; +} + +function validateAssertion( + scriptName: string, + assertion: ParityAssertion, + index: number, + inventoryTexts: Set, + strict: boolean, +): string[] { + const errors: string[] = []; + const label = `${scriptName} assertions[${index}]`; + const legacy = assertion.legacy; + const status = assertion.status; + + if (!isNonEmptyString(legacy)) { + errors.push(`${label}: legacy is required`); + } else if (!inventoryTexts.has(legacy)) { + errors.push(`${label}: unknown legacy assertion string not found in inventory: ${legacy}`); + } + + if (!isNonEmptyString(status)) { + if (strict) errors.push(`${label}: status is required in strict mode`); + } else if (!ASSERTION_STATUSES.has(status)) { + errors.push(`${label}: status must be one of ${Array.from(ASSERTION_STATUSES).join(", ")}`); + } + + const effectiveStatus = (status ?? "mapped") as AssertionStatus; + if (effectiveStatus === "mapped") { + if (!isNonEmptyString(assertion.id)) errors.push(`${label}: mapped assertion requires id`); + } else if (effectiveStatus === "deferred") { + if (!isNonEmptyString(assertion.reason)) + errors.push(`${label}: deferred assertion requires reason`); + if (!isNonEmptyString(assertion.owner)) + errors.push(`${label}: deferred assertion requires owner`); + if ( + !isNonEmptyString(assertion.runner_requirement) && + !isNonEmptyString(assertion.secret_requirement) + ) { + errors.push(`${label}: deferred assertion requires runner_requirement or secret_requirement`); + } + } else if (effectiveStatus === "retired") { + if (!isNonEmptyString(assertion.reason)) + errors.push(`${label}: retired assertion requires reason`); + if (!isNonEmptyString(assertion.reviewer)) + errors.push(`${label}: retired assertion requires reviewer`); + if (!isNonEmptyString(assertion.approved_at)) + errors.push(`${label}: retired assertion requires approved_at`); + } + + return errors; +} + +export function validateParityMap(options: ValidationOptions): string[] { + const inventory = loadInventory(options.root); + const parityMap = loadParityMap(options.root); + const mapScripts = parityMap.scripts ?? {}; + const errors: string[] = []; + + for (const entrypoint of inventory.entrypoints) { + const scriptName = basenameScript(entrypoint.script); + const scriptEntry = mapScripts[scriptName]; + const inventoryTexts = new Set(entrypoint.assertions.map((assertion) => assertion.text)); + + if (!scriptEntry) { + errors.push(`${scriptName}: missing parity-map entry`); + continue; + } + + const scriptStatus = scriptEntry.status; + if ( + scriptStatus !== undefined && + (!isNonEmptyString(scriptStatus) || !SCRIPT_STATUSES.has(scriptStatus)) + ) { + errors.push(`${scriptName}: status must be one of ${Array.from(SCRIPT_STATUSES).join(", ")}`); + } + + const assertions = Array.isArray(scriptEntry.assertions) + ? (scriptEntry.assertions as ParityAssertion[]) + : []; + const effectiveScriptStatus = isNonEmptyString(scriptStatus) + ? scriptStatus + : assertions.length === 0 + ? "not-started" + : "migrated"; + + if ( + (effectiveScriptStatus === "migrated" || effectiveScriptStatus === "parity-verified") && + !isNonEmptyString(scriptEntry.scenario) + ) { + errors.push(`${scriptName}: ${effectiveScriptStatus} script requires scenario`); + } + + if (options.strict && assertions.length === 0 && entrypoint.assertions.length > 0) { + errors.push(`${scriptName}: strict mode rejects empty or uncategorized assertion mappings`); + } + + const mappedIds = new Map(); + assertions.forEach((assertion, index) => { + errors.push( + ...validateAssertion(scriptName, assertion, index, inventoryTexts, options.strict), + ); + const status = assertion.status ?? "mapped"; + if (status === "mapped" && isNonEmptyString(assertion.id)) { + const entries = mappedIds.get(assertion.id) ?? []; + entries.push(index); + mappedIds.set(assertion.id, entries); + } + }); + + for (const [id, indexes] of mappedIds.entries()) { + if (indexes.length <= 1) continue; + const allReusable = indexes.every((index) => assertions[index]?.reusable === true); + if (!allReusable) { + errors.push( + `${scriptName}: duplicate scenario assertion id ${id}; set reusable: true on all duplicates if intentional`, + ); + } + } + + if (options.strict) { + const categorized = new Set( + assertions + .filter( + (assertion) => + isNonEmptyString(assertion.legacy) && + ASSERTION_STATUSES.has(assertion.status as string), + ) + .map((assertion) => assertion.legacy as string), + ); + for (const inventoryText of inventoryTexts) { + if (!categorized.has(inventoryText)) { + errors.push(`${scriptName}: uncategorized assertion in strict mode: ${inventoryText}`); + } + } + } + } + + return errors; +} + +function main(): number { + const options = parseArgs(process.argv); + const errors = validateParityMap(options); + if (errors.length > 0) { + for (const error of errors) process.stderr.write(`${error}\n`); + process.stderr.write( + `\ncheck-parity-map: ${errors.length} error(s)${options.strict ? " in strict mode" : ""}\n`, + ); + return 1; + } + process.stdout.write(`parity map valid${options.strict ? " (strict)" : ""}\n`); + return 0; +} + +if (process.argv[1] && path.resolve(process.argv[1]) === fileURLToPath(import.meta.url)) { + process.exit(main()); +} diff --git a/scripts/e2e/compare-parity.sh b/scripts/e2e/compare-parity.sh new file mode 100755 index 0000000000..a48eea05a0 --- /dev/null +++ b/scripts/e2e/compare-parity.sh @@ -0,0 +1,248 @@ +#!/usr/bin/env bash +# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +# +# Compare PASS/FAIL outcomes between a legacy e2e log and a migrated +# scenario log using the mapping in test/e2e/docs/parity-map.yaml. +# +# Usage: +# scripts/e2e/compare-parity.sh \ +# --script .sh \ +# --legacy \ +# --scenario \ +# [--map ] [--strict] [--report ] +# [--bucket ] [--all-migrated true|false] [--deferred-handling skip|report] +# +# Emits a JSON divergence report on stdout when divergence is found, plus +# a human summary line. Exits 0 on no divergence, non-zero on divergence +# or misuse. +# +# The "normalize both logs into {assertion_id, status}" logic is kept in +# one place so CI and local repro stay in lock-step. + +set -euo pipefail + +SCRIPT_NAME="" +LEGACY_LOG="" +SCENARIO_LOG="" +MAP_FILE="" +STRICT=0 +REPORT_FILE="" +BUCKET="" +ALL_MIGRATED="false" +DEFERRED_HANDLING="skip" + +usage() { + cat >&2 <<'USAGE' +Usage: compare-parity.sh --script --legacy --scenario [--map ] [--strict] [--report ] [--bucket ] [--all-migrated true|false] [--deferred-handling skip|report] +USAGE +} + +while [[ $# -gt 0 ]]; do + case "$1" in + --script) + SCRIPT_NAME="${2:?}" + shift 2 + ;; + --legacy) + LEGACY_LOG="${2:?}" + shift 2 + ;; + --scenario) + SCENARIO_LOG="${2:?}" + shift 2 + ;; + --map) + MAP_FILE="${2:?}" + shift 2 + ;; + --strict) + STRICT=1 + shift + ;; + --report) + REPORT_FILE="${2:?}" + shift 2 + ;; + --bucket) + BUCKET="${2:?}" + shift 2 + ;; + --all-migrated) + ALL_MIGRATED="${2:?}" + shift 2 + ;; + --deferred-handling) + DEFERRED_HANDLING="${2:?}" + shift 2 + ;; + -h | --help) + usage + exit 0 + ;; + *) + echo "compare-parity: unknown arg: $1" >&2 + usage + exit 2 + ;; + esac +done + +if [[ -z "${SCRIPT_NAME}" || -z "${LEGACY_LOG}" || -z "${SCENARIO_LOG}" ]]; then + usage + exit 2 +fi + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +REPO_ROOT="$(cd "${SCRIPT_DIR}/../.." && pwd)" +if [[ -z "${MAP_FILE}" ]]; then + MAP_FILE="${REPO_ROOT}/test/e2e/docs/parity-map.yaml" +fi +if [[ ! -f "${MAP_FILE}" ]]; then + echo "compare-parity: map file not found: ${MAP_FILE}" >&2 + exit 2 +fi + +# The comparison logic is implemented in Node (available on all CI runners +# without extra setup) so we can parse YAML cleanly. +node --no-warnings - "${SCRIPT_NAME}" "${LEGACY_LOG}" "${SCENARIO_LOG}" "${MAP_FILE}" "${STRICT}" "${REPORT_FILE}" "${BUCKET}" "${ALL_MIGRATED}" "${DEFERRED_HANDLING}" <<'JS' +const fs = require("node:fs"); +const path = require("node:path"); + +const [scriptName, legacyLog, scenarioLog, mapFile, strictRaw, reportFile, bucket, allMigratedRaw, deferredHandling] = process.argv.slice(2); +const strict = strictRaw === "1"; + +function loadYaml(file) { + // Use the repo's vendored js-yaml (a root dependency) when available; + // otherwise fall back to a tiny parser sufficient for the narrow schema. + try { + const yaml = require("js-yaml"); + return yaml.load(fs.readFileSync(file, "utf8")) ?? {}; + } catch (_) { + // Ultra-minimal YAML fallback: only handles the parity-map shape. + const text = fs.readFileSync(file, "utf8"); + const out = { scripts: {} }; + let currentScript = null; + let currentEntry = null; + const lines = text.split("\n"); + for (const raw of lines) { + if (raw.trimStart().startsWith("#")) continue; + if (/^scripts:\s*(\{\})?\s*$/.test(raw)) continue; + // scripts: + // name.sh: + let m = raw.match(/^\s{2}([\w.\-]+):\s*$/); + if (m) { currentScript = m[1]; out.scripts[currentScript] = { assertions: [] }; currentEntry = null; continue; } + m = raw.match(/^\s{4}scenario:\s*(.+?)\s*$/); + if (m && currentScript) { out.scripts[currentScript].scenario = m[1]; continue; } + m = raw.match(/^\s{4}assertions:\s*$/); + if (m && currentScript) { out.scripts[currentScript].assertions = []; continue; } + m = raw.match(/^\s{6}-\s*legacy:\s*"(.*)"\s*$/); + if (m && currentScript) { currentEntry = { legacy: m[1] }; out.scripts[currentScript].assertions.push(currentEntry); continue; } + m = raw.match(/^\s{8}id:\s*(.+?)\s*$/); + if (m && currentEntry) { currentEntry.id = m[1]; continue; } + m = raw.match(/^\s{8}flaky:\s*(true|false)\s*$/); + if (m && currentEntry) { currentEntry.flaky = m[1] === "true"; continue; } + } + return out; + } +} + +function readLog(file) { + try { return fs.readFileSync(file, "utf8"); } catch { return ""; } +} + +function normalize(logText, legacyString, scenarioId) { + // Returns { legacy: "PASS"|"FAIL"|"MISSING", scenario: ... } + const has = (needle) => { + if (!needle) return null; + const lines = logText.split(/\r?\n/); + let pass = false, fail = false; + for (const line of lines) { + if (line.startsWith("PASS:") && line.includes(needle)) pass = true; + if (line.startsWith("FAIL:") && line.includes(needle)) fail = true; + } + if (fail) return "FAIL"; + if (pass) return "PASS"; + return "MISSING"; + }; + return { legacy: has(legacyString), scenario: has(scenarioId) }; +} + +const map = loadYaml(mapFile); +const entry = (map.scripts ?? {})[scriptName]; +if (!entry || !Array.isArray(entry.assertions) || entry.assertions.length === 0) { + const report = { script: scriptName, bucket, all_migrated: allMigratedRaw === "true", strict, deferred_handling: deferredHandling, divergence: [], counts: { mapped: 0, deferred: 0, retired: 0 }, note: "no mappings" }; + if (reportFile) fs.writeFileSync(reportFile, JSON.stringify(report, null, 2) + "\n"); + console.log(JSON.stringify(report)); + if (strict) { + console.error(`compare-parity: no mappings for ${scriptName} in strict mode`); + process.exit(1); + } + console.log(`compare-parity: no mappings for ${scriptName}; no-divergence`); + process.exit(0); +} + +const legacyText = readLog(legacyLog); +const scenarioText = readLog(scenarioLog); +const divergence = []; +const counts = { mapped: 0, deferred: 0, retired: 0 }; +const outcomes = []; +for (const a of entry.assertions) { + const status = a.status || "mapped"; + if (status === "deferred" || status === "retired") { + counts[status]++; + if (deferredHandling === "report") outcomes.push({ legacy: a.legacy, status }); + continue; + } + counts.mapped++; + const n = normalize("", a.legacy, a.id); // placeholder + // Run legacy lookup against the legacy log, scenario against the scenario log. + const legacyStatus = (() => { + const lines = legacyText.split(/\r?\n/); + let pass = false, fail = false; + for (const line of lines) { + if (line.startsWith("PASS:") && line.includes(a.legacy)) pass = true; + if (line.startsWith("FAIL:") && line.includes(a.legacy)) fail = true; + } + if (fail) return "FAIL"; + if (pass) return "PASS"; + return "MISSING"; + })(); + const scenarioStatus = (() => { + const lines = scenarioText.split(/\r?\n/); + let pass = false, fail = false; + const needle = a.id; + for (const line of lines) { + if (line.startsWith("PASS:") && line.includes(needle)) pass = true; + if (line.startsWith("FAIL:") && line.includes(needle)) fail = true; + } + if (fail) return "FAIL"; + if (pass) return "PASS"; + return "MISSING"; + })(); + + if (a.flaky) { + // Flaky: both-pass-or-both-fail counts as aligned. + if (legacyStatus !== scenarioStatus) { + divergence.push({ id: a.id, legacy: legacyStatus, scenario: scenarioStatus, flaky: true }); + } + continue; + } + if (legacyStatus !== scenarioStatus) { + divergence.push({ id: a.id, legacy: legacyStatus, scenario: scenarioStatus }); + } + outcomes.push({ id: a.id, legacy: legacyStatus, scenario: scenarioStatus }); +} + +const report = { script: scriptName, scenario: entry.scenario, bucket: entry.bucket || bucket, all_migrated: allMigratedRaw === "true", strict, deferred_handling: deferredHandling, counts, outcomes, divergence }; +if (reportFile) fs.writeFileSync(reportFile, JSON.stringify(report, null, 2) + "\n"); +console.log(JSON.stringify(report)); +if (divergence.length > 0) { + console.error(`compare-parity: ${divergence.length} diverging assertion(s) for ${scriptName}`); + for (const d of divergence) { + console.error(` ${d.id}: legacy=${d.legacy} scenario=${d.scenario}`); + } + process.exit(1); +} +console.log(`compare-parity: no divergence for ${scriptName}`); +JS diff --git a/scripts/e2e/extract-legacy-assertions.ts b/scripts/e2e/extract-legacy-assertions.ts new file mode 100755 index 0000000000..89eae882b8 --- /dev/null +++ b/scripts/e2e/extract-legacy-assertions.ts @@ -0,0 +1,284 @@ +#!/usr/bin/env tsx +// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +/** + * Generate the legacy E2E assertion inventory used by parity migration. + * + * The inventory is intentionally deterministic and reviewer-readable: every + * legacy E2E entrypoint discovered from the filesystem is listed, including + * scripts with zero extractable PASS/FAIL assertions. + */ + +import fs from "node:fs"; +import path from "node:path"; +import { fileURLToPath } from "node:url"; +import yaml from "js-yaml"; + +export type AssertionPolarity = "pass" | "fail"; +export type MappingStatus = "mapped" | "deferred" | "retired" | "unmapped"; + +export interface LegacyAssertionRecord { + script: string; + line: number; + text: string; + polarity: AssertionPolarity; + normalized_id: string; + mapping_status: MappingStatus; +} + +export interface LegacyEntrypointInventory { + script: string; + assertions: LegacyAssertionRecord[]; + zero_assertion_review?: { + reason: string; + }; +} + +export interface LegacyAssertionInventory { + generated_by: string; + entrypoints: LegacyEntrypointInventory[]; + totals: { + scripts: number; + assertions: number; + zero_assertion_scripts: number; + }; +} + +interface ParityAssertionEntry { + legacy?: unknown; + status?: unknown; +} + +interface ParityScriptEntry { + assertions?: unknown; +} + +interface ParsedParityMap { + scripts?: Record; +} + +function repoRootFromScript(): string { + return path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..", ".."); +} + +function toPosix(p: string): string { + return p.split(path.sep).join("/"); +} + +function unescapeShellString(text: string): string { + return text.replace(/\\(["'\\])/g, "$1"); +} + +export function normalizeAssertionId(text: string): string { + const normalized = text + .toLowerCase() + .replace(/[^a-z0-9]+/g, ".") + .replace(/^\.+|\.+$/g, "") + .replace(/\.{2,}/g, "."); + return normalized || "assertion"; +} + +function discoverLegacyEntrypoints(root: string): string[] { + const e2eDir = path.join(root, "test/e2e"); + let entries: fs.Dirent[] = []; + try { + entries = fs.readdirSync(e2eDir, { withFileTypes: true }); + } catch { + return []; + } + const scripts = entries + .filter((entry) => entry.isFile()) + .map((entry) => entry.name) + .filter((name) => /^test-.*\.sh$/.test(name) || name === "brev-e2e.test.ts") + .sort((a, b) => a.localeCompare(b)); + return scripts.map((name) => path.join(e2eDir, name)); +} + +function loadMappedStatuses(root: string): Map { + const mapPath = path.join(root, "test/e2e/docs/parity-map.yaml"); + if (!fs.existsSync(mapPath)) return new Map(); + const text = fs.readFileSync(mapPath, "utf8"); + const parsed = (yaml.load(text) ?? {}) as ParsedParityMap; + const statuses = new Map(); + + for (const [script, entry] of Object.entries(parsed.scripts ?? {})) { + if (!Array.isArray(entry.assertions)) continue; + for (const assertion of entry.assertions as ParityAssertionEntry[]) { + if (typeof assertion.legacy !== "string") continue; + const status = + assertion.status === "mapped" || + assertion.status === "deferred" || + assertion.status === "retired" + ? assertion.status + : "mapped"; + statuses.set(`${script}\u0000${assertion.legacy}`, status); + } + } + + return statuses; +} + +function extractQuotedCall(line: string, helper: AssertionPolarity): string[] { + const out: string[] = []; + const helperPattern = new RegExp( + `(?:^|[^A-Za-z0-9_-])${helper}\\s+(["'])((?:\\\\.|(?!\\1).)*)\\1`, + "g", + ); + for (const match of line.matchAll(helperPattern)) { + out.push(unescapeShellString(match[2])); + } + return out; +} + +function extractDirectOutput(line: string, polarity: AssertionPolarity): string[] { + const out: string[] = []; + const label = polarity === "pass" ? "PASS" : "FAIL"; + const pattern = new RegExp(`${label}:\\s*([^"'\\)\\r\\n]+|["']?[^"'\\r\\n]*["']?)`, "g"); + for (const match of line.matchAll(pattern)) { + const previous = match.index && match.index > 0 ? line[match.index - 1] : ""; + if (previous === "/") continue; + if (/^\s*(printf|echo)\s+['\"][^'\"]*%s/.test(line)) continue; + let text = match[1].trim(); + text = text + .replace(/["'`);]+$/g, "") + .replace(/^["'`]+/g, "") + .trim(); + if (text.length > 0 && !/^\$[A-Z_][A-Z0-9_]*$/.test(text)) out.push(text); + } + return out; +} + +export function extractAssertionsFromText(script: string, text: string): LegacyAssertionRecord[] { + const assertions: LegacyAssertionRecord[] = []; + const lines = text.split("\n"); + + lines.forEach((line, index) => { + const trimmed = line.trimStart(); + if (trimmed.startsWith("#")) return; + + for (const polarity of ["pass", "fail"] as const) { + const seenOnLine = new Set(); + for (const extracted of [ + ...extractQuotedCall(line, polarity), + ...extractDirectOutput(line, polarity), + ]) { + const key = `${polarity}\u0000${extracted}`; + if (seenOnLine.has(key)) continue; + seenOnLine.add(key); + assertions.push({ + script, + line: index + 1, + text: extracted, + polarity, + normalized_id: normalizeAssertionId(extracted), + mapping_status: "unmapped", + }); + } + } + }); + + return assertions; +} + +export function buildLegacyAssertionInventory(root: string): LegacyAssertionInventory { + const mappedStatuses = loadMappedStatuses(root); + const entrypoints = discoverLegacyEntrypoints(root).map((file): LegacyEntrypointInventory => { + const script = toPosix(path.relative(root, file)); + const scriptName = path.basename(file); + const text = fs.readFileSync(file, "utf8"); + const assertions = extractAssertionsFromText(script, text).map((assertion) => ({ + ...assertion, + mapping_status: mappedStatuses.get(`${scriptName}\u0000${assertion.text}`) ?? "unmapped", + })); + if (assertions.length === 0) { + return { + script, + assertions, + zero_assertion_review: { + reason: "TODO: review legacy entrypoint for assertions not expressed as PASS/FAIL output", + }, + }; + } + return { script, assertions }; + }); + + const assertions = entrypoints.reduce((sum, entry) => sum + entry.assertions.length, 0); + const zeroAssertionScripts = entrypoints.filter((entry) => entry.assertions.length === 0).length; + + return { + generated_by: "scripts/e2e/extract-legacy-assertions.ts", + entrypoints, + totals: { + scripts: entrypoints.length, + assertions, + zero_assertion_scripts: zeroAssertionScripts, + }, + }; +} + +function parseArgs(argv: string[]): { root: string; output: string; check: boolean } { + let root = repoRootFromScript(); + let output = path.join(root, "test/e2e/docs/parity-inventory.generated.json"); + let check = false; + const args = argv.slice(2); + while (args.length > 0) { + const arg = args.shift()!; + if (arg === "--root") { + root = path.resolve(args.shift() ?? ""); + output = path.join(root, "test/e2e/docs/parity-inventory.generated.json"); + } else if (arg === "--output") { + output = path.resolve(args.shift() ?? ""); + } else if (arg === "--check") { + check = true; + } else if (arg === "-h" || arg === "--help") { + process.stdout.write( + "tsx scripts/e2e/extract-legacy-assertions.ts [--root ] [--output ] [--check]\n", + ); + process.exit(0); + } else { + process.stderr.write(`extract-legacy-assertions: unexpected arg: ${arg}\n`); + process.exit(2); + } + } + return { root, output, check }; +} + +function stableJson(value: unknown): string { + return `${JSON.stringify(value, null, 2)}\n`; +} + +function main(): number { + const { root, output, check } = parseArgs(process.argv); + const inventory = buildLegacyAssertionInventory(root); + const serialized = stableJson(inventory); + + if (check) { + if (!fs.existsSync(output)) { + process.stderr.write( + `${output} does not exist; regenerate with scripts/e2e/extract-legacy-assertions.ts\n`, + ); + return 1; + } + const existing = fs.readFileSync(output, "utf8"); + if (existing !== serialized) { + process.stderr.write( + `${output} is out of date; regenerate with scripts/e2e/extract-legacy-assertions.ts\n`, + ); + return 1; + } + process.stdout.write(`legacy assertion inventory is current: ${output}\n`); + return 0; + } + + fs.mkdirSync(path.dirname(output), { recursive: true }); + fs.writeFileSync(output, serialized); + process.stdout.write( + `wrote ${output} (${inventory.totals.scripts} entrypoints, ${inventory.totals.assertions} assertions)\n`, + ); + return 0; +} + +if (process.argv[1] && path.resolve(process.argv[1]) === fileURLToPath(import.meta.url)) { + process.exit(main()); +} diff --git a/scripts/e2e/lint-conventions.ts b/scripts/e2e/lint-conventions.ts new file mode 100755 index 0000000000..14a75ba6ab --- /dev/null +++ b/scripts/e2e/lint-conventions.ts @@ -0,0 +1,310 @@ +#!/usr/bin/env tsx +// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +/** + * E2E convention lint. + * + * Enforces the migration-spec conventions on + * `test/e2e/validation_suites/**` step scripts and the + * `test/e2e/test-*.sh` legacy frontier: + * + * - Suite step scripts MUST NOT re-export non-interactive env vars + * (use runtime/lib/env.sh::e2e_env_apply_noninteractive instead). + * - Suite step scripts MUST NOT register their own traps + * (runtime/lib/cleanup.sh owns teardown). + * - Suite step scripts MUST NOT call `section "..."` — filenames carry + * the phase label, and e2e_section is emitted by the runner. + * - Suite step scripts MUST NOT write to `/tmp/*.log` — use + * `$E2E_CONTEXT_DIR/logs///.log`. + * - Non-standard repo-root discovery (`git rev-parse --show-toplevel`) + * is rejected in suite step scripts; use + * `SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"` and + * walk up. + * - Every `test/e2e/test-*.sh` script MUST have an entry in + * `test/e2e/docs/parity-map.yaml` (Risk #1: guards against new + * legacy scripts landing unmapped). + * - The generated parity inventory MUST match current legacy assertions. + * + * Invocation: + * tsx scripts/e2e/lint-conventions.ts [--root ] + * Exits 0 on success, 1 on violations, 2 on misuse. + */ + +import fs from "node:fs"; +import path from "node:path"; +import { fileURLToPath } from "node:url"; +import yaml from "js-yaml"; + +import { buildLegacyAssertionInventory } from "./extract-legacy-assertions"; +import { validateParityMap } from "./check-parity-map"; + +interface Rule { + id: string; + describe: string; + test: (body: string) => string | null; +} + +const STEP_RULES: Rule[] = [ + { + id: "no-noninteractive-reexport", + describe: "suite step re-exports non-interactive env vars", + test: (body) => { + const patterns = [ + /export\s+DEBIAN_FRONTEND\s*=\s*noninteractive/, + /export\s+NEMOCLAW_NON_INTERACTIVE\s*=\s*1/, + ]; + for (const p of patterns) { + if (p.test(body)) + return `matched ${p.source}; use runtime/lib/env.sh::e2e_env_apply_noninteractive`; + } + return null; + }, + }, + { + id: "no-own-trap", + describe: "suite step registers its own trap", + test: (body) => { + // Ignore commented lines and ignore `trap` inside quoted strings by + // requiring a leading non-quote character. + const lines = body.split("\n"); + for (const raw of lines) { + const line = raw.replace(/^\s+/, ""); + if (line.startsWith("#")) continue; + if (/^trap\s+[^#]/.test(line)) { + return "registered own trap; cleanup lives in runtime/lib/cleanup.sh"; + } + } + return null; + }, + }, + { + id: "no-section-call", + describe: "suite step calls section/e2e_section", + test: (body) => { + const lines = body.split("\n"); + for (const raw of lines) { + const line = raw.replace(/^\s+/, ""); + if (line.startsWith("#")) continue; + if (/^section\s+["']/.test(line)) { + return "calls section; filename carries the phase label"; + } + } + return null; + }, + }, + { + id: "no-tmp-log", + describe: "suite step writes to /tmp/*.log", + test: (body) => { + if (/>\s*\/tmp\/[^\s]*\.log/.test(body)) { + return "writes to /tmp/*.log; use $E2E_CONTEXT_DIR/logs///.log"; + } + return null; + }, + }, + { + id: "no-git-rev-parse-repo-root", + describe: "suite step uses `git rev-parse --show-toplevel` for repo root", + test: (body) => { + if (/git\s+rev-parse\s+--show-toplevel/.test(body)) { + return 'use SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" instead'; + } + return null; + }, + }, +]; + +interface LintFinding { + file: string; + rule: string; + message: string; +} + +function walkShellScripts(root: string): string[] { + const out: string[] = []; + const walk = (dir: string) => { + let entries: fs.Dirent[]; + try { + entries = fs.readdirSync(dir, { withFileTypes: true }); + } catch { + return; + } + for (const ent of entries) { + const full = path.join(dir, ent.name); + if (ent.isDirectory()) { + walk(full); + } else if (ent.isFile() && ent.name.endsWith(".sh")) { + out.push(full); + } + } + }; + walk(root); + return out; +} + +function parseArgs(argv: string[]): { root: string } { + let root: string | undefined; + const args = argv.slice(2); + while (args.length > 0) { + const a = args.shift()!; + if (a === "--root") root = args.shift(); + else if (a === "-h" || a === "--help") { + process.stdout.write("tsx scripts/e2e/lint-conventions.ts [--root ]\n"); + process.exit(0); + } else { + process.stderr.write(`lint-conventions: unexpected arg: ${a}\n`); + process.exit(2); + } + } + if (!root) { + const scriptDir = path.dirname(fileURLToPath(import.meta.url)); + root = path.resolve(scriptDir, "..", ".."); + } + return { root }; +} + +function lintSuiteSteps(root: string): LintFinding[] { + const findings: LintFinding[] = []; + const suitesRoot = path.join(root, "test/e2e/validation_suites"); + if (!fs.existsSync(suitesRoot)) return findings; + for (const file of walkShellScripts(suitesRoot)) { + const body = fs.readFileSync(file, "utf8"); + for (const rule of STEP_RULES) { + const msg = rule.test(body); + if (msg) { + findings.push({ file: path.relative(root, file), rule: rule.id, message: msg }); + } + } + } + return findings; +} + +/** + * Read `test/e2e/docs/parity-map.yaml` and return the set of legacy-script + * names that have an entry. Uses a narrow parser to avoid a runtime + * dependency when js-yaml is not available. + */ +function readParityMapScripts(mapFile: string): Set { + const set = new Set(); + if (!fs.existsSync(mapFile)) return set; + const text = fs.readFileSync(mapFile, "utf8"); + for (const raw of text.split("\n")) { + const m = raw.match(/^\s{2}([\w.\-]+):\s*$/); + if (m) set.add(m[1]); + } + return set; +} + +function lintLegacyFrontier(root: string): LintFinding[] { + const findings: LintFinding[] = []; + const e2eDir = path.join(root, "test/e2e"); + const mapFile = path.join(e2eDir, "docs", "parity-map.yaml"); + const mapped = readParityMapScripts(mapFile); + let entries: fs.Dirent[]; + try { + entries = fs.readdirSync(e2eDir, { withFileTypes: true }); + } catch { + return findings; + } + for (const ent of entries) { + if (!ent.isFile()) continue; + if (!/^test-.*\.sh$/.test(ent.name)) continue; + if (mapped.has(ent.name)) continue; + findings.push({ + file: `test/e2e/${ent.name}`, + rule: "legacy-script-needs-parity-map-entry", + message: `new legacy test/e2e/${ent.name} has no entry in test/e2e/docs/parity-map.yaml (Risk #1)`, + }); + } + return findings; +} + +function lintRetiredLegacyWrappers(root: string): LintFinding[] { + const findings: LintFinding[] = []; + const mapFile = path.join(root, "test/e2e/docs/parity-map.yaml"); + if (!fs.existsSync(mapFile)) return findings; + const loaded = (yaml.load(fs.readFileSync(mapFile, "utf8")) ?? {}) as { + scripts?: Record; + }; + for (const [script, entry] of Object.entries(loaded.scripts ?? {})) { + if (entry.status !== "retired") continue; + const file = path.join(root, "test/e2e", script); + if (!fs.existsSync(file) || !script.endsWith(".sh")) continue; + const body = fs.readFileSync(file, "utf8"); + if (!/test\/e2e\/runtime\/run-scenario\.sh|runtime\/run-scenario\.sh/.test(body)) { + findings.push({ + file: `test/e2e/${script}`, + rule: "retired-wrapper-delegates-to-scenario-runner", + message: "retired legacy wrapper must delegate to test/e2e/runtime/run-scenario.sh", + }); + } + if ( + /^\s*(pass|fail)\s*\(\)|^\s*section\s*\(\)|nemoclaw\s+onboard|bash\s+.*install\.sh/m.test( + body, + ) + ) { + findings.push({ + file: `test/e2e/${script}`, + rule: "retired-wrapper-no-monolithic-logic", + message: + "retired legacy wrapper must not reintroduce pass/fail helpers, install, or onboard logic", + }); + } + } + return findings; +} + +function lintParityInventory(root: string): LintFinding[] { + const findings: LintFinding[] = []; + const inventoryPath = path.join(root, "test/e2e/docs/parity-inventory.generated.json"); + if (!fs.existsSync(inventoryPath)) { + findings.push({ + file: "test/e2e/docs/parity-inventory.generated.json", + rule: "legacy-assertion-inventory-current", + message: + "generated parity inventory is missing; run scripts/e2e/extract-legacy-assertions.ts", + }); + return findings; + } + + const expected = `${JSON.stringify(buildLegacyAssertionInventory(root), null, 2)}\n`; + const actual = fs.readFileSync(inventoryPath, "utf8"); + if (actual !== expected) { + findings.push({ + file: "test/e2e/docs/parity-inventory.generated.json", + rule: "legacy-assertion-inventory-current", + message: "generated parity inventory is stale; run scripts/e2e/extract-legacy-assertions.ts", + }); + } + return findings; +} + +function main(): number { + const { root } = parseArgs(process.argv); + const inventoryPath = path.join(root, "test/e2e/docs/parity-inventory.generated.json"); + const parityErrors = fs.existsSync(inventoryPath) + ? validateParityMap({ root, strict: false }).map((message) => ({ + file: "test/e2e/docs/parity-map.yaml", + rule: "parity-map-schema", + message, + })) + : []; + const findings = [ + ...lintSuiteSteps(root), + ...lintLegacyFrontier(root), + ...lintParityInventory(root), + ...lintRetiredLegacyWrappers(root), + ...parityErrors, + ]; + if (findings.length === 0) { + return 0; + } + for (const f of findings) { + process.stderr.write(`${f.file}: [${f.rule}] ${f.message}\n`); + } + process.stderr.write(`\ne2e-convention-lint: ${findings.length} violation(s)\n`); + return 1; +} + +process.exit(main()); diff --git a/test/e2e/docs/MIGRATION.md b/test/e2e/docs/MIGRATION.md new file mode 100644 index 0000000000..7d269f6983 --- /dev/null +++ b/test/e2e/docs/MIGRATION.md @@ -0,0 +1,147 @@ + + + +# E2E Migration Tracker + +This PR migrates all existing `test/e2e/test-*.sh` scripts into the +scenario-based runner introduced by PR #3363. Full deep migration +(Strategy B). Legacy scripts remain in the repo during this PR and run +in parallel for 1–2 nightly cycles after merge; a follow-up PR retires +them once parity is verified. + +**Merge gate:** All 40 legacy entry points must have a scenario-based +equivalent that produces the same PASS/FAIL outcomes as the legacy +script in a side-by-side CI run. + +## Reuse being absorbed + +Migrating 40 scripts collapses 13 distinct categories of duplication. +Each row maps to a Wave 0 item or an existing helper. + +| # | Category | Fan-in (legacy) | Target absorber | LOC | +|---|---|---|---|---:| +| 1 | Logging helpers (`section` / `info` / `pass` / `fail`) | 28–39 scripts redefine each | `runtime/lib/logging.sh` (Wave 0.B.5) | 1,556 | +| 2 | Non-interactive env exports | 187 inlined lines across 40 scripts | `runtime/lib/env.sh::e2e_env_apply_noninteractive` + convention 0.G.1 | 175 | +| 3 | Repo-root / `SCRIPT_DIR` discovery | 37 lines, 4 competing patterns | One convention (Wave 0.G.2) | 25 | +| 4 | `nemoclaw list` / `status` / gateway state probes | 142 inlined sites | `validation_suites/assert/{gateway,sandbox}-alive.sh` | 500 | +| 5 | `bash install.sh ...` invocations | 24 scripts | `nemoclaw_scenarios/install/dispatch.sh` dispatcher (Wave 0.C.1) | 300 | +| 6 | `nemoclaw onboard ...` variants | 42 invocations, 8+ flag incantations | `nemoclaw_scenarios/onboard/dispatch.sh` + profile handlers | 800 | +| 7 | Docker older-base-image pattern | 3 hand-rolled implementations | `nemoclaw_scenarios/fixtures/older-base-image.sh` (Wave 0.A.1) | 250 | +| 8 | Trap / cleanup / teardown blocks | 112 lines, ~15 patterns | `runtime/lib/cleanup.sh` + convention 0.G.3 | 400 | +| 9 | Fake-endpoint inline setups | 3 inline variants | `nemoclaw_scenarios/fixtures/fake-{openai,telegram,discord,slack}.sh` (Wave 0.A.2–5) | 150 | +| 10 | Sandbox-scoped exec (`nemoclaw shell -- ...`) | 15 scripts reimplement with drift | `validation_suites/sandbox-exec.sh` (Wave 0.A.6) | 200 | +| 11 | Hermes/OpenClaw pair-variant scripts | 7 paired scripts share ~70% | Shared suite steps; scenario agent via `expected_state.sandbox.agent` | 800 | +| 12 | `section "Phase N: X"` markers | Every script inflates logs with phase text | Step-script filename carries the name (convention 0.G.4) | 300 | +| 13 | Log-capture paths (`/tmp/*.log`) | 25 different conventions; CI artifact upload assumes one | `$E2E_CONTEXT_DIR/logs/` convention 0.G.5 | 300 | +| **Total** | | | | **~5,556** | + +About **25% LOC reduction** net after legacy retirement. The larger win +is drift reduction: when `--yes-i-accept-third-party-software` renames +again, it's a 1-file change instead of a 24-file change. + +## Status summary + +| Bucket | Legacy LOC | Status | +|---|---:|---| +| Wave 0 — fixtures, asserts, setup splits, conventions, parity workflow | — | ⬜ not started | +| Wave 1 — onboarding baseline | 1,101 | ⬜ | +| Wave 2 — onboarding lifecycle | 2,013 | ⬜ | +| Wave 3 — sandbox lifecycle | 2,891 | ⬜ | +| Wave 4 — rebuild / upgrade | 1,292 | ⬜ | +| Wave 5 — inference variants | 2,593 | ⬜ | +| Wave 6 — Hermes | 1,646 | ⬜ | +| Wave 7 — messaging | 3,397 | ⬜ | +| Wave 8 — security / policy | 2,241 | ⬜ | +| Wave 9 — runtime / platform services | 1,696 | ⬜ | +| Wave 10 — platform + remote | 1,589 | ⬜ | +| Wave 11 — misc | 405 | ⬜ | +| **Total** | **20,864** | **0 / 40 scripts migrated** | + +## Per-script tracker + +Legend: ⬜ not started · 🟨 in progress · ✅ migrated · 🔵 parity verified + +### Wave 1 — onboarding baseline + +- ⬜ `test-full-e2e.sh` (473) → `onboarding/happy-path/` + scenario `ubuntu-curl-cloud-openclaw` +- ⬜ `test-cloud-onboard-e2e.sh` (337) → `onboarding/public-installer/` +- ⬜ `test-cloud-inference-e2e.sh` (291) → extends `inference/cloud/` + +### Wave 2 — onboarding lifecycle + +- ⬜ `test-double-onboard.sh` (717) → `onboarding/double-onboard/` +- ⬜ `test-gpu-double-onboard.sh` (571) → `onboarding/double-onboard/` on GPU scenario +- ⬜ `test-onboard-repair.sh` (372) → `onboarding/repair/` +- ⬜ `test-onboard-resume.sh` (353) → `onboarding/resume/` + +### Wave 3 — sandbox lifecycle + +- ⬜ `test-sandbox-operations.sh` (828) → `sandbox/operations/` +- ⬜ `test-sandbox-survival.sh` (721) → `sandbox/survival/` +- ⬜ `test-snapshot-commands.sh` (281) → `sandbox/snapshot/` +- ⬜ `test-diagnostics.sh` (452) → `sandbox/diagnostics/` +- ⬜ `test-issue-2478-crash-loop-recovery.sh` (609) → `sandbox/crash-loop-recovery/` + +### Wave 4 — rebuild / upgrade + +- ⬜ `test-rebuild-openclaw.sh` (453) → `sandbox/rebuild-openclaw/` (uses `nemoclaw_scenarios/fixtures/older-base-image.sh`) +- ⬜ `test-rebuild-hermes.sh` (401) → `sandbox/rebuild-hermes/` +- ⬜ `test-upgrade-stale-sandbox.sh` (241) → `sandbox/upgrade-stale/` +- ⬜ `test-sandbox-rebuild.sh` (197) → folded into `sandbox/rebuild-openclaw/` + +### Wave 5 — inference variants + +- ⬜ `test-gpu-e2e.sh` (565) → `inference/ollama-gpu/` (deep port) +- ⬜ `test-ollama-auth-proxy-e2e.sh` (548) → `inference/ollama-auth-proxy/` (deep port) +- ⬜ `test-inference-routing.sh` (715) → `inference/routing-errors/` +- ⬜ `test-kimi-inference-compat.sh` (765) → `inference/kimi-compat/` + +### Wave 6 — Hermes + +- ⬜ `test-hermes-e2e.sh` (591) → `onboarding/hermes/` (deep port; currently 1-step health) +- ⬜ `test-hermes-slack-e2e.sh` (537) → `messaging/slack/hermes/` +- ⬜ `test-hermes-discord-e2e.sh` (518) → `messaging/discord/hermes/` + +### Wave 7 — messaging + +- ⬜ `test-messaging-providers.sh` (1,677) → `messaging/providers/{telegram,discord,slack}/` +- ⬜ `test-token-rotation.sh` (575) → `messaging/token-rotation/` +- ⬜ `test-telegram-injection.sh` (475) → `security/telegram-injection/` +- ⬜ `test-messaging-compatible-endpoint.sh` (670) → `messaging/compatible-endpoint/` + +### Wave 8 — security / policy + +- ⬜ `test-shields-config.sh` (550) → `security/shields/` +- ⬜ `test-network-policy.sh` (579) → `security/network-policy/` +- ⬜ `test-credential-sanitization.sh` (810) → `security/credentials/sanitization/` +- ⬜ `test-credential-migration.sh` (302) → `security/credentials/migration/` + +### Wave 9 — runtime / platform services + +- ⬜ `test-runtime-overrides.sh` (272) → `sandbox/runtime-overrides/` +- ⬜ `test-overlayfs-autofix.sh` (537) → `sandbox/overlayfs-autofix/` +- ⬜ `test-device-auth-health.sh` (373) → `lifecycle/device-auth-health/` +- ⬜ `test-deployment-services.sh` (514) → `lifecycle/deployment-services/` + +### Wave 10 — platform + remote + +- ⬜ `test-spark-install.sh` (157) → `platform/spark/` +- ⬜ `test-launchable-smoke.sh` (589) → `platform/launchable/` +- ⬜ `brev-e2e.test.ts` (843) → `platform/brev-remote/` + +### Wave 11 — misc + +- ⬜ `test-skill-agent-e2e.sh` (244) → `onboarding/skill-agent/` +- ⬜ `test-docs-validation.sh` (161) → `lifecycle/docs-validation/` + +## Parallel verification + +Before merge, `.github/workflows/e2e-parity-compare.yaml` (Wave 0.F.1) +will run each migrated scenario next to its legacy counterpart and diff +PASS/FAIL per assertion via `test/e2e/docs/parity-map.yaml` + +`scripts/e2e/compare-parity.sh`. + +Merge gate: **zero divergence**. Documented flaky assertions are +compared as "both-pass-or-both-fail" rather than strict equality. + +Internal plan document (not committed): `specs/2026-05-08_e2e-setup-scenario-matrix/migration-plan.md`. diff --git a/test/e2e/docs/README.md b/test/e2e/docs/README.md new file mode 100644 index 0000000000..64aa16135c --- /dev/null +++ b/test/e2e/docs/README.md @@ -0,0 +1,123 @@ + + + +# NemoClaw E2E + +End-to-end tests organized around **setup scenarios** rather than +one-off shell scripts. A scenario declares *how you got to a working +NemoClaw* (platform + install + runtime + onboarding); a scenario +resolves to an **expected state** contract; once that state validates, +one or more **suites** run functional assertions against it. + +```text +setup scenario → expected state → suite sequence +``` + +The declarative sources of truth live in three files — read these +first, they are short and deliberately not redundant with prose: + +- [`../nemoclaw_scenarios/scenarios.yaml`](../nemoclaw_scenarios/scenarios.yaml) + — platforms, installs, runtimes, onboarding choices, and the + concrete scenarios that combine them. +- [`../nemoclaw_scenarios/expected-states.yaml`](../nemoclaw_scenarios/expected-states.yaml) + — reusable structural contracts (gateway health, sandbox status, + inference routing, etc.). +- [`../validation_suites/suites.yaml`](../validation_suites/suites.yaml) + — ordered validation steps, each with a `requires_state` predicate. + +## How to run + +```bash +bash test/e2e/runtime/run-scenario.sh --plan-only # resolve + print plan, no side effects +bash test/e2e/runtime/run-scenario.sh --dry-run # helpers short-circuit with trace +bash test/e2e/runtime/run-scenario.sh --validate-only # assume setup done; validate expected state +bash test/e2e/runtime/run-scenario.sh # full live run +bash test/e2e/runtime/run-suites.sh […] +bash test/e2e/runtime/coverage-report.sh # Markdown matrix of scenario × suite +``` + +Override the runtime context dir with `E2E_CONTEXT_DIR=` (default +`.e2e/`, gitignored). The scenario runner and suites communicate only +through `$E2E_CONTEXT_DIR/context.env` — suites do not rediscover +setup state. + +## Where things live + +```text +test/e2e/ + docs/ # README.md, MIGRATION.md, parity-map.yaml + nemoclaw_scenarios/ # declarative scenario inputs + setup machinery + scenarios.yaml / expected-states.yaml + install/ # install dispatcher + one file per install profile + onboard/ # onboard dispatcher + one file per onboarding profile + fixtures/ # reusable stubs (fake-openai, fake-{telegram,discord,slack}, older-base-image) + helpers/ # scenario-side shell utilities (e.g. emit-context-from-plan.sh) + validation_suites/ # suite definitions and outcome assertions + suites.yaml + sandbox-exec.sh + assert/ # outcome assertions (inference, credentials, policy, messaging) + smoke/ inference/ hermes/ platform/ security/ # suite scripts grouped by concern + runtime/ # entry points + cross-cutting shared libs + run-scenario.sh / run-suites.sh / coverage-report.sh + resolver/ # TypeScript: load, plan, validate, coverage (invoked via tsx) + lib/ # shared shell helpers: context, env, cleanup, logging, artifacts, sandbox-teardown +``` + +The CI entry points are `.github/workflows/e2e-scenarios.yaml` +(manual dispatch) and `.github/workflows/e2e-parity-compare.yaml` +(runs new vs. legacy and reports divergence). Existing workflows +(`nightly-e2e.yaml`, `macos-e2e.yaml`, `wsl-e2e.yaml`, etc.) are +unchanged during the migration. + +## Legacy assertion inventory + +The generated inventory at `test/e2e/docs/parity-inventory.generated.json` +is the auditable source of truth for legacy E2E `PASS:` / `FAIL:` +assertions. Regenerate it after changing any `test/e2e/test-*.sh` +entrypoint or `test/e2e/brev-e2e.test.ts`: + +```bash +npx tsx scripts/e2e/extract-legacy-assertions.ts +``` + +Use `--check` to verify the committed inventory has no drift: + +```bash +npx tsx scripts/e2e/extract-legacy-assertions.ts --check +``` + +Scripts with no extracted assertions remain listed with a review TODO so +parity gaps are visible in diffs. + +`test/e2e/docs/parity-map.yaml` is the assertion-level migration map. +Every inventory assertion must be classified as `mapped`, `deferred`, or +`retired`; strict validation requires zero `unmapped` assertions: + +```bash +npx tsx scripts/e2e/check-parity-map.ts --strict +``` + +Mapped assertions point at stable scenario-side assertion IDs emitted by +suites (for example `smoke.cli.available`). Deferred assertions must name +an owner plus a runner or secret requirement, and retired assertions must +record reviewer/date evidence. + +## How to add a scenario, state, or suite + +Add-a-scenario, add-a-state, and add-a-suite are short edits to the +three YAML files above, plus shell scripts under +`nemoclaw_scenarios/install/`, `nemoclaw_scenarios/onboard/`, +`validation_suites/assert/`, or `validation_suites//`. The +schemas in +[`../runtime/resolver/schema.ts`](../runtime/resolver/schema.ts) +describe the required shape; `run-scenario.sh --plan-only` +validates your change without running anything destructive. + +When adding a suite assertion, emit or preserve a stable `PASS: ` / +`FAIL: ` log line, add the legacy assertion mapping if one exists, +regenerate the inventory, and re-run strict parity validation. Platform- +specific scenarios such as GPU, macOS, WSL, Brev, or DGX Spark must also +list `runner_requirements` in `scenarios.yaml`. + +New legacy-style `test-*.sh` scripts are blocked by +`scripts/e2e/lint-conventions.ts` — migrate into the matrix instead. diff --git a/test/e2e/docs/parity-inventory.generated.json b/test/e2e/docs/parity-inventory.generated.json new file mode 100644 index 0000000000..1b53af86e4 --- /dev/null +++ b/test/e2e/docs/parity-inventory.generated.json @@ -0,0 +1,15631 @@ +{ + "generated_by": "scripts/e2e/extract-legacy-assertions.ts", + "entrypoints": [ + { + "script": "test/e2e/brev-e2e.test.ts", + "assertions": [], + "zero_assertion_review": { + "reason": "TODO: review legacy entrypoint for assertions not expressed as PASS/FAIL output" + } + }, + { + "script": "test/e2e/test-brave-search-e2e.sh", + "assertions": [ + { + "script": "test/e2e/test-brave-search-e2e.sh", + "line": 193, + "text": "B1: ${onboard_cmd_desc} completed for Brave Search-enabled onboard", + "polarity": "pass", + "normalized_id": "b1.onboard.cmd.desc.completed.for.brave.search.enabled.onboard", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-brave-search-e2e.sh", + "line": 195, + "text": "B1: ${onboard_cmd_desc} failed (exit $onboard_exit)", + "polarity": "fail", + "normalized_id": "b1.onboard.cmd.desc.failed.exit.onboard.exit", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-brave-search-e2e.sh", + "line": 216, + "text": "B2a: openshell policy get failed (exit $rc)", + "polarity": "fail", + "normalized_id": "b2a.openshell.policy.get.failed.exit.rc", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-brave-search-e2e.sh", + "line": 218, + "text": "B2a: brave preset applied — api.search.brave.com is in the loaded gateway policy", + "polarity": "pass", + "normalized_id": "b2a.brave.preset.applied.api.search.brave.com.is.in.the.loaded.gateway.policy", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-brave-search-e2e.sh", + "line": 220, + "text": "B2a: brave preset NOT applied — api.search.brave.com is missing from the gateway policy", + "polarity": "fail", + "normalized_id": "b2a.brave.preset.not.applied.api.search.brave.com.is.missing.from.the.gateway.policy", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-brave-search-e2e.sh", + "line": 238, + "text": "B2b: could not read openclaw web-search config (exit $config_rc)", + "polarity": "fail", + "normalized_id": "b2b.could.not.read.openclaw.web.search.config.exit.config.rc", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-brave-search-e2e.sh", + "line": 241, + "text": "B2b: brave preset wired through to openclaw — tools.web.search.provider=brave and enabled=true", + "polarity": "pass", + "normalized_id": "b2b.brave.preset.wired.through.to.openclaw.tools.web.search.provider.brave.and.enabled.true", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-brave-search-e2e.sh", + "line": 243, + "text": "B2b: openclaw web-search config does not select brave (got: $(printf '%s' ", + "polarity": "fail", + "normalized_id": "b2b.openclaw.web.search.config.does.not.select.brave.got.printf.s", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-brave-search-e2e.sh", + "line": 257, + "text": "B3a: SECURITY — real BRAVE_API_KEY found verbatim in /sandbox/.openclaw/openclaw.json", + "polarity": "fail", + "normalized_id": "b3a.security.real.brave.api.key.found.verbatim.in.sandbox.openclaw.openclaw.json", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-brave-search-e2e.sh", + "line": 259, + "text": "B3a: openclaw.json contains the placeholder, not the real key", + "polarity": "pass", + "normalized_id": "b3a.openclaw.json.contains.the.placeholder.not.the.real.key", + "mapping_status": "retired" + }, + { + "script": "test/e2e/test-brave-search-e2e.sh", + "line": 261, + "text": "B3a: openclaw.json has neither the real key nor the placeholder — web search not configured", + "polarity": "fail", + "normalized_id": "b3a.openclaw.json.has.neither.the.real.key.nor.the.placeholder.web.search.not.configured", + "mapping_status": "retired" + }, + { + "script": "test/e2e/test-brave-search-e2e.sh", + "line": 268, + "text": "B3b: SECURITY — real BRAVE_API_KEY visible to sandbox shell via printenv", + "polarity": "fail", + "normalized_id": "b3b.security.real.brave.api.key.visible.to.sandbox.shell.via.printenv", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-brave-search-e2e.sh", + "line": 270, + "text": "B3b: sandbox shell env does not expose the real key (placeholder or empty)", + "polarity": "pass", + "normalized_id": "b3b.sandbox.shell.env.does.not.expose.the.real.key.placeholder.or.empty", + "mapping_status": "retired" + }, + { + "script": "test/e2e/test-brave-search-e2e.sh", + "line": 272, + "text": "B3b: unexpected non-empty BRAVE_API_KEY in sandbox env", + "polarity": "fail", + "normalized_id": "b3b.unexpected.non.empty.brave.api.key.in.sandbox.env", + "mapping_status": "retired" + }, + { + "script": "test/e2e/test-brave-search-e2e.sh", + "line": 286, + "text": "B4a: agent web-search turn — could not get SSH config", + "polarity": "fail", + "normalized_id": "b4a.agent.web.search.turn.could.not.get.ssh.config", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-brave-search-e2e.sh", + "line": 305, + "text": "B4a: agent web-search failed with provider/transport error (exit ${rc}): $(printf '%s' ", + "polarity": "fail", + "normalized_id": "b4a.agent.web.search.failed.with.provider.transport.error.exit.rc.printf.s", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-brave-search-e2e.sh", + "line": 326, + "text": "B4a: openclaw agent web-search returned a real Brave result", + "polarity": "pass", + "normalized_id": "b4a.openclaw.agent.web.search.returned.a.real.brave.result", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-brave-search-e2e.sh", + "line": 328, + "text": "B4a: agent web-search did not return a recognizable Brave result (exit ${rc}, reply='$(printf '%s' ", + "polarity": "fail", + "normalized_id": "b4a.agent.web.search.did.not.return.a.recognizable.brave.result.exit.rc.reply.printf.s", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-brave-search-e2e.sh", + "line": 359, + "text": "B4b: real Brave search via curl returned HTTP 200 with non-empty web.results[]", + "polarity": "pass", + "normalized_id": "b4b.real.brave.search.via.curl.returned.http.200.with.non.empty.web.results", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-brave-search-e2e.sh", + "line": 361, + "text": "B4b: HTTP 200 but response had no web.results[] (body parsed empty)", + "polarity": "fail", + "normalized_id": "b4b.http.200.but.response.had.no.web.results.body.parsed.empty", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-brave-search-e2e.sh", + "line": 366, + "text": "B4b: curl never completed an HTTP transaction — check curl is in brave.yaml binaries allowlist. $(printf '%s' ", + "polarity": "fail", + "normalized_id": "b4b.curl.never.completed.an.http.transaction.check.curl.is.in.brave.yaml.binaries.allowlist.printf.s", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-brave-search-e2e.sh", + "line": 368, + "text": "B4b: unexpected HTTP status '${status_code:-}' from Brave (exit $rc)", + "polarity": "fail", + "normalized_id": "b4b.unexpected.http.status.status.code.none.from.brave.exit.rc", + "mapping_status": "retired" + }, + { + "script": "test/e2e/test-brave-search-e2e.sh", + "line": 390, + "text": "B0: BRAVE_API_KEY is available", + "polarity": "pass", + "normalized_id": "b0.brave.api.key.is.available", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-brave-search-e2e.sh", + "line": 394, + "text": "Docker is not running", + "polarity": "fail", + "normalized_id": "docker.is.not.running", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-brave-search-e2e.sh", + "line": 397, + "text": "Docker is running", + "polarity": "pass", + "normalized_id": "docker.is.running", + "mapping_status": "mapped" + }, + { + "script": "test/e2e/test-brave-search-e2e.sh", + "line": 400, + "text": "python3 not found", + "polarity": "fail", + "normalized_id": "python3.not.found", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-brave-search-e2e.sh", + "line": 403, + "text": "python3 is available", + "polarity": "pass", + "normalized_id": "python3.is.available", + "mapping_status": "deferred" + } + ] + }, + { + "script": "test/e2e/test-cloud-inference-e2e.sh", + "assertions": [ + { + "script": "test/e2e/test-cloud-inference-e2e.sh", + "line": 101, + "text": "Docker is not running", + "polarity": "fail", + "normalized_id": "docker.is.not.running", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-cloud-inference-e2e.sh", + "line": 104, + "text": "Docker is running", + "polarity": "pass", + "normalized_id": "docker.is.running", + "mapping_status": "mapped" + }, + { + "script": "test/e2e/test-cloud-inference-e2e.sh", + "line": 107, + "text": "NVIDIA_API_KEY not set or invalid", + "polarity": "fail", + "normalized_id": "nvidia.api.key.not.set.or.invalid", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-cloud-inference-e2e.sh", + "line": 110, + "text": "NVIDIA_API_KEY is set", + "polarity": "pass", + "normalized_id": "nvidia.api.key.is.set", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-cloud-inference-e2e.sh", + "line": 113, + "text": "Could not cd to repo root", + "polarity": "fail", + "normalized_id": "could.not.cd.to.repo.root", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-cloud-inference-e2e.sh", + "line": 139, + "text": "install.sh failed (exit $install_exit)", + "polarity": "fail", + "normalized_id": "install.sh.failed.exit.install.exit", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-cloud-inference-e2e.sh", + "line": 143, + "text": "NemoClaw installed", + "polarity": "pass", + "normalized_id": "nemoclaw.installed", + "mapping_status": "mapped" + }, + { + "script": "test/e2e/test-cloud-inference-e2e.sh", + "line": 146, + "text": "nemoclaw not on PATH", + "polarity": "fail", + "normalized_id": "nemoclaw.not.on.path", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-cloud-inference-e2e.sh", + "line": 150, + "text": "openshell not on PATH", + "polarity": "fail", + "normalized_id": "openshell.not.on.path", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-cloud-inference-e2e.sh", + "line": 153, + "text": "CLIs on PATH", + "polarity": "pass", + "normalized_id": "clis.on.path", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-cloud-inference-e2e.sh", + "line": 161, + "text": "python3 not on PATH", + "polarity": "fail", + "normalized_id": "python3.not.on.path", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-cloud-inference-e2e.sh", + "line": 173, + "text": "Could not build chat payload", + "polarity": "fail", + "normalized_id": "could.not.build.chat.payload", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-cloud-inference-e2e.sh", + "line": 190, + "text": "openshell sandbox ssh-config failed for '${SANDBOX_NAME}'", + "polarity": "fail", + "normalized_id": "openshell.sandbox.ssh.config.failed.for.sandbox.name", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-cloud-inference-e2e.sh", + "line": 219, + "text": "Chat completion returned PONG (attempt ${attempt}/${MAX_ATTEMPTS})", + "polarity": "pass", + "normalized_id": "chat.completion.returned.pong.attempt.attempt.max.attempts", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-cloud-inference-e2e.sh", + "line": 236, + "text": "Live chat: $last_fail", + "polarity": "fail", + "normalized_id": "live.chat.last.fail", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-cloud-inference-e2e.sh", + "line": 247, + "text": "Repo skill validation failed", + "polarity": "fail", + "normalized_id": "repo.skill.validation.failed", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-cloud-inference-e2e.sh", + "line": 250, + "text": "Repo agent skills (SKILL.md) valid", + "polarity": "pass", + "normalized_id": "repo.agent.skills.skill.md.valid", + "mapping_status": "mapped" + }, + { + "script": "test/e2e/test-cloud-inference-e2e.sh", + "line": 259, + "text": "Sandbox OpenClaw layout check failed (exit ${sb_rc}): ${sb_out:0:240}", + "polarity": "fail", + "normalized_id": "sandbox.openclaw.layout.check.failed.exit.sb.rc.sb.out.0.240", + "mapping_status": "mapped" + }, + { + "script": "test/e2e/test-cloud-inference-e2e.sh", + "line": 262, + "text": "Sandbox /sandbox/.openclaw + openclaw.json OK", + "polarity": "pass", + "normalized_id": "sandbox.sandbox.openclaw.openclaw.json.ok", + "mapping_status": "mapped" + }, + { + "script": "test/e2e/test-cloud-inference-e2e.sh", + "line": 265, + "text": "Sandbox /sandbox/.openclaw/skills present", + "polarity": "pass", + "normalized_id": "sandbox.sandbox.openclaw.skills.present", + "mapping_status": "mapped" + }, + { + "script": "test/e2e/test-cloud-inference-e2e.sh", + "line": 269, + "text": "Unexpected sandbox check output: ${sb_out:0:240}", + "polarity": "fail", + "normalized_id": "unexpected.sandbox.check.output.sb.out.0.240", + "mapping_status": "retired" + } + ] + }, + { + "script": "test/e2e/test-cloud-onboard-e2e.sh", + "assertions": [ + { + "script": "test/e2e/test-cloud-onboard-e2e.sh", + "line": 99, + "text": "Pre-cleanup complete", + "polarity": "pass", + "normalized_id": "pre.cleanup.complete", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-cloud-onboard-e2e.sh", + "line": 107, + "text": "Docker is running", + "polarity": "pass", + "normalized_id": "docker.is.running", + "mapping_status": "mapped" + }, + { + "script": "test/e2e/test-cloud-onboard-e2e.sh", + "line": 109, + "text": "Docker is not running — cannot continue", + "polarity": "fail", + "normalized_id": "docker.is.not.running.cannot.continue", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-cloud-onboard-e2e.sh", + "line": 114, + "text": "NVIDIA_API_KEY is set (starts with nvapi-)", + "polarity": "pass", + "normalized_id": "nvidia.api.key.is.set.starts.with.nvapi", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-cloud-onboard-e2e.sh", + "line": 116, + "text": "NVIDIA_API_KEY not set or invalid — required for cloud onboard", + "polarity": "fail", + "normalized_id": "nvidia.api.key.not.set.or.invalid.required.for.cloud.onboard", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-cloud-onboard-e2e.sh", + "line": 121, + "text": "Network access to integrate.api.nvidia.com", + "polarity": "pass", + "normalized_id": "network.access.to.integrate.api.nvidia.com", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-cloud-onboard-e2e.sh", + "line": 123, + "text": "Cannot reach integrate.api.nvidia.com", + "polarity": "fail", + "normalized_id": "cannot.reach.integrate.api.nvidia.com", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-cloud-onboard-e2e.sh", + "line": 129, + "text": "NEMOCLAW_NON_INTERACTIVE=1 is required for non-interactive install", + "polarity": "fail", + "normalized_id": "nemoclaw.non.interactive.1.is.required.for.non.interactive.install", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-cloud-onboard-e2e.sh", + "line": 133, + "text": "NEMOCLAW_ACCEPT_THIRD_PARTY_SOFTWARE=1 is required for non-interactive install", + "polarity": "fail", + "normalized_id": "nemoclaw.accept.third.party.software.1.is.required.for.non.interactive.install", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-cloud-onboard-e2e.sh", + "line": 136, + "text": "Non-interactive mode configured", + "polarity": "pass", + "normalized_id": "non.interactive.mode.configured", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-cloud-onboard-e2e.sh", + "line": 142, + "text": "Host OS is Linux", + "polarity": "pass", + "normalized_id": "host.os.is.linux", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-cloud-onboard-e2e.sh", + "line": 183, + "text": "Interactive install (RUN_E2E_CLOUD_ONBOARD_INTERACTIVE_INSTALL=1) is not yet supported — use non-interactive mode", + "polarity": "fail", + "normalized_id": "interactive.install.run.e2e.cloud.onboard.interactive.install.1.is.not.yet.supported.use.non.interactive.mode", + "mapping_status": "retired" + }, + { + "script": "test/e2e/test-cloud-onboard-e2e.sh", + "line": 214, + "text": "Public install completed (exit 0)", + "polarity": "pass", + "normalized_id": "public.install.completed.exit.0", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-cloud-onboard-e2e.sh", + "line": 216, + "text": "Public install failed (exit $install_exit)", + "polarity": "fail", + "normalized_id": "public.install.failed.exit.install.exit", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-cloud-onboard-e2e.sh", + "line": 223, + "text": "Public install unexpectedly used the local source checkout", + "polarity": "fail", + "normalized_id": "public.install.unexpectedly.used.the.local.source.checkout", + "mapping_status": "retired" + }, + { + "script": "test/e2e/test-cloud-onboard-e2e.sh", + "line": 232, + "text": "Public install used the GitHub clone path", + "polarity": "pass", + "normalized_id": "public.install.used.the.github.clone.path", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-cloud-onboard-e2e.sh", + "line": 234, + "text": "Public install did not show the GitHub clone path", + "polarity": "fail", + "normalized_id": "public.install.did.not.show.the.github.clone.path", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-cloud-onboard-e2e.sh", + "line": 242, + "text": "Public install used requested ref ${PUBLIC_INSTALL_REF}", + "polarity": "pass", + "normalized_id": "public.install.used.requested.ref.public.install.ref", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-cloud-onboard-e2e.sh", + "line": 244, + "text": "Public install did not use requested ref ${PUBLIC_INSTALL_REF}", + "polarity": "fail", + "normalized_id": "public.install.did.not.use.requested.ref.public.install.ref", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-cloud-onboard-e2e.sh", + "line": 252, + "text": "nemoclaw on PATH ($(command -v nemoclaw))", + "polarity": "pass", + "normalized_id": "nemoclaw.on.path.command.v.nemoclaw", + "mapping_status": "mapped" + }, + { + "script": "test/e2e/test-cloud-onboard-e2e.sh", + "line": 254, + "text": "nemoclaw not found on PATH after install", + "polarity": "fail", + "normalized_id": "nemoclaw.not.found.on.path.after.install", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-cloud-onboard-e2e.sh", + "line": 259, + "text": "openshell on PATH ($(openshell --version 2>&1 || echo unknown))", + "polarity": "pass", + "normalized_id": "openshell.on.path.openshell.version.2.1.echo.unknown", + "mapping_status": "mapped" + }, + { + "script": "test/e2e/test-cloud-onboard-e2e.sh", + "line": 261, + "text": "openshell not found on PATH after install", + "polarity": "fail", + "normalized_id": "openshell.not.found.on.path.after.install", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-cloud-onboard-e2e.sh", + "line": 266, + "text": "nemoclaw --help exits 0", + "polarity": "pass", + "normalized_id": "nemoclaw.help.exits.0", + "mapping_status": "mapped" + }, + { + "script": "test/e2e/test-cloud-onboard-e2e.sh", + "line": 268, + "text": "nemoclaw --help failed", + "polarity": "fail", + "normalized_id": "nemoclaw.help.failed", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-cloud-onboard-e2e.sh", + "line": 295, + "text": "$(basename ", + "polarity": "pass", + "normalized_id": "basename", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-cloud-onboard-e2e.sh", + "line": 297, + "text": "$(basename ", + "polarity": "fail", + "normalized_id": "basename", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-cloud-onboard-e2e.sh", + "line": 313, + "text": "Cleanup or verification failed", + "polarity": "fail", + "normalized_id": "cleanup.or.verification.failed", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-cloud-onboard-e2e.sh", + "line": 316, + "text": "Cleanup complete", + "polarity": "pass", + "normalized_id": "cleanup.complete", + "mapping_status": "deferred" + } + ] + }, + { + "script": "test/e2e/test-credential-migration.sh", + "assertions": [ + { + "script": "test/e2e/test-credential-migration.sh", + "line": 97, + "text": "NVIDIA_API_KEY not set", + "polarity": "fail", + "normalized_id": "nvidia.api.key.not.set", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-credential-migration.sh", + "line": 100, + "text": "NVIDIA_API_KEY is set", + "polarity": "pass", + "normalized_id": "nvidia.api.key.is.set", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-credential-migration.sh", + "line": 106, + "text": "install.sh failed; see /tmp/nemoclaw-e2e-install.log", + "polarity": "fail", + "normalized_id": "install.sh.failed.see.tmp.nemoclaw.e2e.install.log", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-credential-migration.sh", + "line": 114, + "text": "openshell still missing after install", + "polarity": "fail", + "normalized_id": "openshell.still.missing.after.install", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-credential-migration.sh", + "line": 118, + "text": "nemoclaw still missing after install", + "polarity": "fail", + "normalized_id": "nemoclaw.still.missing.after.install", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-credential-migration.sh", + "line": 121, + "text": "openshell + nemoclaw on PATH", + "polarity": "pass", + "normalized_id": "openshell.nemoclaw.on.path", + "mapping_status": "mapped" + }, + { + "script": "test/e2e/test-credential-migration.sh", + "line": 167, + "text": "nemoclaw onboard succeeded with only the legacy file as the credential source", + "polarity": "pass", + "normalized_id": "nemoclaw.onboard.succeeded.with.only.the.legacy.file.as.the.credential.source", + "mapping_status": "retired" + }, + { + "script": "test/e2e/test-credential-migration.sh", + "line": 169, + "text": "nemoclaw onboard failed (exit $ONBOARD_EXIT); see log below", + "polarity": "fail", + "normalized_id": "nemoclaw.onboard.failed.exit.onboard.exit.see.log.below", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-credential-migration.sh", + "line": 176, + "text": "Migration notice was emitted to stderr", + "polarity": "pass", + "normalized_id": "migration.notice.was.emitted.to.stderr", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-credential-migration.sh", + "line": 178, + "text": "Expected migration notice on stderr; not found in onboard log", + "polarity": "fail", + "normalized_id": "expected.migration.notice.on.stderr.not.found.in.onboard.log", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-credential-migration.sh", + "line": 185, + "text": "Legacy credentials.json still exists after successful onboard", + "polarity": "fail", + "normalized_id": "legacy.credentials.json.still.exists.after.successful.onboard", + "mapping_status": "mapped" + }, + { + "script": "test/e2e/test-credential-migration.sh", + "line": 187, + "text": "Legacy credentials.json was removed after onboard", + "polarity": "pass", + "normalized_id": "legacy.credentials.json.was.removed.after.onboard", + "mapping_status": "mapped" + }, + { + "script": "test/e2e/test-credential-migration.sh", + "line": 196, + "text": "openshell -g nemoclaw provider list --names failed", + "polarity": "fail", + "normalized_id": "openshell.g.nemoclaw.provider.list.names.failed", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-credential-migration.sh", + "line": 209, + "text": "At least one provider is registered with the gateway ($PROVIDER_COUNT total)", + "polarity": "pass", + "normalized_id": "at.least.one.provider.is.registered.with.the.gateway.provider.count.total", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-credential-migration.sh", + "line": 211, + "text": "No providers registered with the gateway after migration", + "polarity": "fail", + "normalized_id": "no.providers.registered.with.the.gateway.after.migration", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-credential-migration.sh", + "line": 221, + "text": "A non-allowlisted key from the tampered file appears as a gateway provider", + "polarity": "fail", + "normalized_id": "a.non.allowlisted.key.from.the.tampered.file.appears.as.a.gateway.provider", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-credential-migration.sh", + "line": 223, + "text": "Non-allowlisted keys from the tampered file did not become providers", + "polarity": "pass", + "normalized_id": "non.allowlisted.keys.from.the.tampered.file.did.not.become.providers", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-credential-migration.sh", + "line": 232, + "text": "nemoclaw credentials list failed", + "polarity": "fail", + "normalized_id": "nemoclaw.credentials.list.failed", + "mapping_status": "mapped" + }, + { + "script": "test/e2e/test-credential-migration.sh", + "line": 240, + "text": "credentials list surfaces gateway-registered providers", + "polarity": "pass", + "normalized_id": "credentials.list.surfaces.gateway.registered.providers", + "mapping_status": "mapped" + }, + { + "script": "test/e2e/test-credential-migration.sh", + "line": 242, + "text": "credentials list did not produce the expected gateway header", + "polarity": "fail", + "normalized_id": "credentials.list.did.not.produce.the.expected.gateway.header", + "mapping_status": "mapped" + }, + { + "script": "test/e2e/test-credential-migration.sh", + "line": 248, + "text": "credentials.json reappeared on disk after credentials list", + "polarity": "fail", + "normalized_id": "credentials.json.reappeared.on.disk.after.credentials.list", + "mapping_status": "mapped" + }, + { + "script": "test/e2e/test-credential-migration.sh", + "line": 250, + "text": "No plaintext credentials.json on disk after credentials list", + "polarity": "pass", + "normalized_id": "no.plaintext.credentials.json.on.disk.after.credentials.list", + "mapping_status": "mapped" + }, + { + "script": "test/e2e/test-credential-migration.sh", + "line": 273, + "text": "node invocation of removeLegacyCredentialsFile failed", + "polarity": "fail", + "normalized_id": "node.invocation.of.removelegacycredentialsfile.failed", + "mapping_status": "mapped" + }, + { + "script": "test/e2e/test-credential-migration.sh", + "line": 277, + "text": "Symlink at credentials path was not removed", + "polarity": "fail", + "normalized_id": "symlink.at.credentials.path.was.not.removed", + "mapping_status": "mapped" + }, + { + "script": "test/e2e/test-credential-migration.sh", + "line": 279, + "text": "Symlink at credentials path was removed", + "polarity": "pass", + "normalized_id": "symlink.at.credentials.path.was.removed", + "mapping_status": "mapped" + }, + { + "script": "test/e2e/test-credential-migration.sh", + "line": 283, + "text": "Victim file was deleted; secureUnlink followed the symlink", + "polarity": "fail", + "normalized_id": "victim.file.was.deleted.secureunlink.followed.the.symlink", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-credential-migration.sh", + "line": 285, + "text": "Victim file contents were modified; secureUnlink wrote through the symlink", + "polarity": "fail", + "normalized_id": "victim.file.contents.were.modified.secureunlink.wrote.through.the.symlink", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-credential-migration.sh", + "line": 287, + "text": "Victim file is untouched (link removed without following the target)", + "polarity": "pass", + "normalized_id": "victim.file.is.untouched.link.removed.without.following.the.target", + "mapping_status": "retired" + } + ] + }, + { + "script": "test/e2e/test-credential-sanitization.sh", + "assertions": [ + { + "script": "test/e2e/test-credential-sanitization.sh", + "line": 114, + "text": "NVIDIA_API_KEY not set", + "polarity": "fail", + "normalized_id": "nvidia.api.key.not.set", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-credential-sanitization.sh", + "line": 117, + "text": "NVIDIA_API_KEY is set", + "polarity": "pass", + "normalized_id": "nvidia.api.key.is.set", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-credential-sanitization.sh", + "line": 120, + "text": "openshell not found on PATH", + "polarity": "fail", + "normalized_id": "openshell.not.found.on.path", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-credential-sanitization.sh", + "line": 123, + "text": "openshell found", + "polarity": "pass", + "normalized_id": "openshell.found", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-credential-sanitization.sh", + "line": 126, + "text": "nemoclaw not found on PATH", + "polarity": "fail", + "normalized_id": "nemoclaw.not.found.on.path", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-credential-sanitization.sh", + "line": 129, + "text": "nemoclaw found", + "polarity": "pass", + "normalized_id": "nemoclaw.found", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-credential-sanitization.sh", + "line": 132, + "text": "node not found on PATH", + "polarity": "fail", + "normalized_id": "node.not.found.on.path", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-credential-sanitization.sh", + "line": 135, + "text": "node found", + "polarity": "pass", + "normalized_id": "node.found", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-credential-sanitization.sh", + "line": 140, + "text": "Sandbox '${SANDBOX_NAME}' is running", + "polarity": "pass", + "normalized_id": "sandbox.sandbox.name.is.running", + "mapping_status": "mapped" + }, + { + "script": "test/e2e/test-credential-sanitization.sh", + "line": 142, + "text": "Sandbox '${SANDBOX_NAME}' not running — run test-full-e2e.sh first", + "polarity": "fail", + "normalized_id": "sandbox.sandbox.name.not.running.run.test.full.e2e.sh.first", + "mapping_status": "mapped" + }, + { + "script": "test/e2e/test-credential-sanitization.sh", + "line": 297, + "text": "Sanitization ran successfully", + "polarity": "pass", + "normalized_id": "sanitization.ran.successfully", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-credential-sanitization.sh", + "line": 299, + "text": "Sanitization script failed: ${sanitize_result:0:200}", + "polarity": "fail", + "normalized_id": "sanitization.script.failed.sanitize.result.0.200", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-credential-sanitization.sh", + "line": 306, + "text": "C1: No fake NVIDIA key found in bundle", + "polarity": "pass", + "normalized_id": "c1.no.fake.nvidia.key.found.in.bundle", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-credential-sanitization.sh", + "line": 308, + "text": "C1: Fake NVIDIA key found in bundle: ${nvapi_hits:0:200}", + "polarity": "fail", + "normalized_id": "c1.fake.nvidia.key.found.in.bundle.nvapi.hits.0.200", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-credential-sanitization.sh", + "line": 317, + "text": "C1b: No fake GitHub/npm/gateway tokens found in bundle", + "polarity": "pass", + "normalized_id": "c1b.no.fake.github.npm.gateway.tokens.found.in.bundle", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-credential-sanitization.sh", + "line": 319, + "text": "C1b: Fake tokens found — github: ${github_hits:0:80}, npm: ${npm_hits:0:80}, gateway: ${gateway_hits:0:80}", + "polarity": "fail", + "normalized_id": "c1b.fake.tokens.found.github.github.hits.0.80.npm.npm.hits.0.80.gateway.gateway.hits.0.80", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-credential-sanitization.sh", + "line": 326, + "text": "C2: auth-profiles.json deleted from bundle", + "polarity": "pass", + "normalized_id": "c2.auth.profiles.json.deleted.from.bundle", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-credential-sanitization.sh", + "line": 328, + "text": "C2: auth-profiles.json still exists: $auth_files", + "polarity": "fail", + "normalized_id": "c2.auth.profiles.json.still.exists.auth.files", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-credential-sanitization.sh", + "line": 348, + "text": "C3a: nvidia.apiKey replaced with sentinel", + "polarity": "pass", + "normalized_id": "c3a.nvidia.apikey.replaced.with.sentinel", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-credential-sanitization.sh", + "line": 350, + "text": "C3a: nvidia.apiKey not sanitized (got: $nvidia_apikey)", + "polarity": "fail", + "normalized_id": "c3a.nvidia.apikey.not.sanitized.got.nvidia.apikey", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-credential-sanitization.sh", + "line": 354, + "text": "C3b: gateway.auth.token replaced with sentinel", + "polarity": "pass", + "normalized_id": "c3b.gateway.auth.token.replaced.with.sentinel", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-credential-sanitization.sh", + "line": 356, + "text": "C3b: gateway.auth.token not sanitized (got: $gateway_token)", + "polarity": "fail", + "normalized_id": "c3b.gateway.auth.token.not.sanitized.got.gateway.token", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-credential-sanitization.sh", + "line": 374, + "text": "C4a: agents.defaults.model.primary preserved", + "polarity": "pass", + "normalized_id": "c4a.agents.defaults.model.primary.preserved", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-credential-sanitization.sh", + "line": 376, + "text": "C4a: agents.defaults.model.primary corrupted (got: $model_primary)", + "polarity": "fail", + "normalized_id": "c4a.agents.defaults.model.primary.corrupted.got.model.primary", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-credential-sanitization.sh", + "line": 380, + "text": "C4b: gateway.mode preserved", + "polarity": "pass", + "normalized_id": "c4b.gateway.mode.preserved", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-credential-sanitization.sh", + "line": 382, + "text": "C4b: gateway.mode corrupted (got: $gateway_mode)", + "polarity": "fail", + "normalized_id": "c4b.gateway.mode.corrupted.got.gateway.mode", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-credential-sanitization.sh", + "line": 390, + "text": "C5: workspace/project.md intact", + "polarity": "pass", + "normalized_id": "c5.workspace.project.md.intact", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-credential-sanitization.sh", + "line": 392, + "text": "C5: workspace/project.md content changed", + "polarity": "fail", + "normalized_id": "c5.workspace.project.md.content.changed", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-credential-sanitization.sh", + "line": 395, + "text": "C5: workspace/project.md missing from bundle", + "polarity": "fail", + "normalized_id": "c5.workspace.project.md.missing.from.bundle", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-credential-sanitization.sh", + "line": 415, + "text": "C6: Sandbox probe failed — SSH did not execute; cannot verify auth-profiles.json absence", + "polarity": "fail", + "normalized_id": "c6.sandbox.probe.failed.ssh.did.not.execute.cannot.verify.auth.profiles.json.absence", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-credential-sanitization.sh", + "line": 417, + "text": "C6: No auth-profiles.json found inside sandbox", + "polarity": "pass", + "normalized_id": "c6.no.auth.profiles.json.found.inside.sandbox", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-credential-sanitization.sh", + "line": 419, + "text": "C6: auth-profiles.json found inside sandbox: $c6_result", + "polarity": "fail", + "normalized_id": "c6.auth.profiles.json.found.inside.sandbox.c6.result", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-credential-sanitization.sh", + "line": 433, + "text": "C7: Sandbox probe failed — SSH did not execute; cannot verify secret absence", + "polarity": "fail", + "normalized_id": "c7.sandbox.probe.failed.ssh.did.not.execute.cannot.verify.secret.absence", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-credential-sanitization.sh", + "line": 435, + "text": "C7: No secret patterns (nvapi-, ghp_, npm_) found in sandbox config", + "polarity": "pass", + "normalized_id": "c7.no.secret.patterns.nvapi.ghp.npm.found.in.sandbox.config", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-credential-sanitization.sh", + "line": 437, + "text": "C7: Secret patterns found in sandbox — nvapi: ${c7_nvapi:0:100}, ghp: ${c7_ghp:0:100}, npm: ${c7_npm:0:100}", + "polarity": "fail", + "normalized_id": "c7.secret.patterns.found.in.sandbox.nvapi.c7.nvapi.0.100.ghp.c7.ghp.0.100.npm.c7.npm.0.100", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-credential-sanitization.sh", + "line": 492, + "text": "C8: Symlink traversal blocked — outside file preserved", + "polarity": "pass", + "normalized_id": "c8.symlink.traversal.blocked.outside.file.preserved", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-credential-sanitization.sh", + "line": 494, + "text": "C8: Symlink traversal — outside file was DELETED through symlink!", + "polarity": "fail", + "normalized_id": "c8.symlink.traversal.outside.file.was.deleted.through.symlink", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-credential-sanitization.sh", + "line": 550, + "text": "C9a: Empty digest string correctly rejected", + "polarity": "pass", + "normalized_id": "c9a.empty.digest.string.correctly.rejected", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-credential-sanitization.sh", + "line": 552, + "text": "C9a: Empty digest string was ACCEPTED — bypass still possible!", + "polarity": "fail", + "normalized_id": "c9a.empty.digest.string.was.accepted.bypass.still.possible", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-credential-sanitization.sh", + "line": 556, + "text": "C9b: Undefined digest correctly rejected", + "polarity": "pass", + "normalized_id": "c9b.undefined.digest.correctly.rejected", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-credential-sanitization.sh", + "line": 558, + "text": "C9b: Undefined digest was ACCEPTED — bypass still possible!", + "polarity": "fail", + "normalized_id": "c9b.undefined.digest.was.accepted.bypass.still.possible", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-credential-sanitization.sh", + "line": 585, + "text": "C10: Wrong digest correctly rejected", + "polarity": "pass", + "normalized_id": "c10.wrong.digest.correctly.rejected", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-credential-sanitization.sh", + "line": 587, + "text": "C10: Wrong digest was ACCEPTED — verification broken!", + "polarity": "fail", + "normalized_id": "c10.wrong.digest.was.accepted.verification.broken", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-credential-sanitization.sh", + "line": 614, + "text": "C11: Correct digest correctly accepted", + "polarity": "pass", + "normalized_id": "c11.correct.digest.correctly.accepted", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-credential-sanitization.sh", + "line": 616, + "text": "C11: Correct digest was REJECTED — false negative!", + "polarity": "fail", + "normalized_id": "c11.correct.digest.was.rejected.false.negative", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-credential-sanitization.sh", + "line": 679, + "text": "C12: All pattern-matched credential fields stripped", + "polarity": "pass", + "normalized_id": "c12.all.pattern.matched.credential.fields.stripped", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-credential-sanitization.sh", + "line": 681, + "text": "C12: Some credential fields NOT stripped: ${c12_result}", + "polarity": "fail", + "normalized_id": "c12.some.credential.fields.not.stripped.c12.result", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-credential-sanitization.sh", + "line": 760, + "text": "C13: All non-credential fields preserved correctly", + "polarity": "pass", + "normalized_id": "c13.all.non.credential.fields.preserved.correctly", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-credential-sanitization.sh", + "line": 762, + "text": "C13: Some non-credential fields were corrupted: ${c13_result}", + "polarity": "fail", + "normalized_id": "c13.some.non.credential.fields.were.corrupted.c13.result", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-credential-sanitization.sh", + "line": 778, + "text": "Blueprint digest field found and identified", + "polarity": "pass", + "normalized_id": "blueprint.digest.field.found.and.identified", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-credential-sanitization.sh", + "line": 781, + "text": "Blueprint digest field found (empty)", + "polarity": "pass", + "normalized_id": "blueprint.digest.field.found.empty", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-credential-sanitization.sh", + "line": 784, + "text": "Blueprint has a digest value set", + "polarity": "pass", + "normalized_id": "blueprint.has.a.digest.value.set", + "mapping_status": "deferred" + } + ] + }, + { + "script": "test/e2e/test-dashboard-remote-bind.sh", + "assertions": [ + { + "script": "test/e2e/test-dashboard-remote-bind.sh", + "line": 8, + "text": "$1", + "polarity": "pass", + "normalized_id": "1", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-dashboard-remote-bind.sh", + "line": 10, + "text": "$1", + "polarity": "fail", + "normalized_id": "1", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-dashboard-remote-bind.sh", + "line": 28, + "text": "nemoclaw CLI is not on PATH", + "polarity": "fail", + "normalized_id": "nemoclaw.cli.is.not.on.path", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-dashboard-remote-bind.sh", + "line": 31, + "text": "openshell CLI is not on PATH", + "polarity": "fail", + "normalized_id": "openshell.cli.is.not.on.path", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-dashboard-remote-bind.sh", + "line": 33, + "text": "Required CLIs are available", + "polarity": "pass", + "normalized_id": "required.clis.are.available", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-dashboard-remote-bind.sh", + "line": 44, + "text": "nemoclaw connect completed with NEMOCLAW_DASHBOARD_BIND=0.0.0.0", + "polarity": "pass", + "normalized_id": "nemoclaw.connect.completed.with.nemoclaw.dashboard.bind.0.0.0.0", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-dashboard-remote-bind.sh", + "line": 47, + "text": "nemoclaw connect failed with NEMOCLAW_DASHBOARD_BIND=0.0.0.0", + "polarity": "fail", + "normalized_id": "nemoclaw.connect.failed.with.nemoclaw.dashboard.bind.0.0.0.0", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-dashboard-remote-bind.sh", + "line": 55, + "text": "No OpenShell forward found for ${SANDBOX_NAME} on ${DASHBOARD_PORT}", + "polarity": "fail", + "normalized_id": "no.openshell.forward.found.for.sandbox.name.on.dashboard.port", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-dashboard-remote-bind.sh", + "line": 61, + "text": "Dashboard forward binds all interfaces for remote origin (${DASHBOARD_PORT})", + "polarity": "pass", + "normalized_id": "dashboard.forward.binds.all.interfaces.for.remote.origin.dashboard.port", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-dashboard-remote-bind.sh", + "line": 64, + "text": "Dashboard forward is still localhost-only; expected 0.0.0.0:${DASHBOARD_PORT}", + "polarity": "fail", + "normalized_id": "dashboard.forward.is.still.localhost.only.expected.0.0.0.0.dashboard.port", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-dashboard-remote-bind.sh", + "line": 67, + "text": "Could not prove dashboard forward uses 0.0.0.0:${DASHBOARD_PORT} from: ${FORWARD_LINE}", + "polarity": "fail", + "normalized_id": "could.not.prove.dashboard.forward.uses.0.0.0.0.dashboard.port.from.forward.line", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-dashboard-remote-bind.sh", + "line": 72, + "text": "Remote dashboard bind guard completed", + "polarity": "pass", + "normalized_id": "remote.dashboard.bind.guard.completed", + "mapping_status": "deferred" + } + ] + }, + { + "script": "test/e2e/test-deployment-services.sh", + "assertions": [ + { + "script": "test/e2e/test-deployment-services.sh", + "line": 202, + "text": "TC-STATE-02: Setup", + "polarity": "fail", + "normalized_id": "tc.state.02.setup", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-deployment-services.sh", + "line": 213, + "text": "TC-STATE-02: Backup completed successfully", + "polarity": "pass", + "normalized_id": "tc.state.02.backup.completed.successfully", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-deployment-services.sh", + "line": 215, + "text": "TC-STATE-02: Backup", + "polarity": "fail", + "normalized_id": "tc.state.02.backup", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-deployment-services.sh", + "line": 222, + "text": "TC-STATE-02: Backup dir", + "polarity": "fail", + "normalized_id": "tc.state.02.backup.dir", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-deployment-services.sh", + "line": 248, + "text": "TC-STATE-02: Destroy", + "polarity": "fail", + "normalized_id": "tc.state.02.destroy", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-deployment-services.sh", + "line": 251, + "text": "TC-STATE-02: Sandbox destroyed", + "polarity": "pass", + "normalized_id": "tc.state.02.sandbox.destroyed", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-deployment-services.sh", + "line": 255, + "text": "TC-STATE-02: Re-onboard", + "polarity": "fail", + "normalized_id": "tc.state.02.re.onboard", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-deployment-services.sh", + "line": 258, + "text": "TC-STATE-02: Sandbox re-onboarded", + "polarity": "pass", + "normalized_id": "tc.state.02.sandbox.re.onboarded", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-deployment-services.sh", + "line": 266, + "text": "TC-STATE-02: Restore completed successfully", + "polarity": "pass", + "normalized_id": "tc.state.02.restore.completed.successfully", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-deployment-services.sh", + "line": 268, + "text": "TC-STATE-02: Restore", + "polarity": "fail", + "normalized_id": "tc.state.02.restore", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-deployment-services.sh", + "line": 285, + "text": "TC-STATE-02: ${verified}/5 workspace files verified with correct content", + "polarity": "pass", + "normalized_id": "tc.state.02.verified.5.workspace.files.verified.with.correct.content", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-deployment-services.sh", + "line": 288, + "text": "TC-STATE-02: ${verified}/5 workspace files verified (partial tolerance applied)", + "polarity": "pass", + "normalized_id": "tc.state.02.verified.5.workspace.files.verified.partial.tolerance.applied", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-deployment-services.sh", + "line": 290, + "text": "TC-STATE-02: Verify", + "polarity": "fail", + "normalized_id": "tc.state.02.verify", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-deployment-services.sh", + "line": 296, + "text": "TC-STATE-02: Memory note restored correctly", + "polarity": "pass", + "normalized_id": "tc.state.02.memory.note.restored.correctly", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-deployment-services.sh", + "line": 329, + "text": "TC-DEPLOY-01a: Start", + "polarity": "fail", + "normalized_id": "tc.deploy.01a.start", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-deployment-services.sh", + "line": 344, + "text": "TC-DEPLOY-01a: Tunnel URL found in status ($tunnel_url)", + "polarity": "pass", + "normalized_id": "tc.deploy.01a.tunnel.url.found.in.status.tunnel.url", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-deployment-services.sh", + "line": 346, + "text": "TC-DEPLOY-01a: Start", + "polarity": "fail", + "normalized_id": "tc.deploy.01a.start", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-deployment-services.sh", + "line": 368, + "text": "TC-DEPLOY-01b: Tunnel serves OpenClaw dashboard (HTTP 200, marker matched)", + "polarity": "pass", + "normalized_id": "tc.deploy.01b.tunnel.serves.openclaw.dashboard.http.200.marker.matched", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-deployment-services.sh", + "line": 370, + "text": "TC-DEPLOY-01b", + "polarity": "fail", + "normalized_id": "tc.deploy.01b", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-deployment-services.sh", + "line": 373, + "text": "TC-DEPLOY-01b", + "polarity": "fail", + "normalized_id": "tc.deploy.01b", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-deployment-services.sh", + "line": 385, + "text": "TC-DEPLOY-01c: Stop command", + "polarity": "fail", + "normalized_id": "tc.deploy.01c.stop.command", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-deployment-services.sh", + "line": 409, + "text": "TC-DEPLOY-01c: Stop", + "polarity": "fail", + "normalized_id": "tc.deploy.01c.stop", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-deployment-services.sh", + "line": 411, + "text": "TC-DEPLOY-01c: Tunnel URL absent after stop", + "polarity": "pass", + "normalized_id": "tc.deploy.01c.tunnel.url.absent.after.stop", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-deployment-services.sh", + "line": 413, + "text": "TC-DEPLOY-01c: Stop", + "polarity": "fail", + "normalized_id": "tc.deploy.01c.stop", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-deployment-services.sh", + "line": 447, + "text": "TC-DEPLOY-03: openshell binary still in PATH after uninstall", + "polarity": "pass", + "normalized_id": "tc.deploy.03.openshell.binary.still.in.path.after.uninstall", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-deployment-services.sh", + "line": 449, + "text": "TC-DEPLOY-03: openshell", + "polarity": "fail", + "normalized_id": "tc.deploy.03.openshell", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-deployment-services.sh", + "line": 454, + "text": "TC-DEPLOY-03: nemoclaw removed after uninstall", + "polarity": "pass", + "normalized_id": "tc.deploy.03.nemoclaw.removed.after.uninstall", + "mapping_status": "retired" + }, + { + "script": "test/e2e/test-deployment-services.sh", + "line": 459, + "text": "TC-DEPLOY-03: uninstall completed (nemoclaw in source tree is expected)", + "polarity": "pass", + "normalized_id": "tc.deploy.03.uninstall.completed.nemoclaw.in.source.tree.is.expected", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-deployment-services.sh", + "line": 461, + "text": "TC-DEPLOY-03: nemoclaw", + "polarity": "fail", + "normalized_id": "tc.deploy.03.nemoclaw", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-deployment-services.sh", + "line": 483, + "text": "$PASS${NC}", + "polarity": "pass", + "normalized_id": "pass.nc", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-deployment-services.sh", + "line": 484, + "text": "$FAIL${NC}", + "polarity": "fail", + "normalized_id": "fail.nc", + "mapping_status": "deferred" + } + ] + }, + { + "script": "test/e2e/test-device-auth-health.sh", + "assertions": [ + { + "script": "test/e2e/test-device-auth-health.sh", + "line": 139, + "text": "Preflight checks passed", + "polarity": "pass", + "normalized_id": "preflight.checks.passed", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-device-auth-health.sh", + "line": 170, + "text": "Install failed with exit code $INSTALL_EXIT", + "polarity": "fail", + "normalized_id": "install.failed.with.exit.code.install.exit", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-device-auth-health.sh", + "line": 176, + "text": "nemoclaw not found on PATH after install", + "polarity": "fail", + "normalized_id": "nemoclaw.not.found.on.path.after.install", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-device-auth-health.sh", + "line": 190, + "text": "Onboard succeeded — sandbox '${SANDBOX_NAME}' registered", + "polarity": "pass", + "normalized_id": "onboard.succeeded.sandbox.sandbox.name.registered", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-device-auth-health.sh", + "line": 192, + "text": "Sandbox '${SANDBOX_NAME}' not found in nemoclaw list after onboard", + "polarity": "fail", + "normalized_id": "sandbox.sandbox.name.not.found.in.nemoclaw.list.after.onboard", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-device-auth-health.sh", + "line": 223, + "text": "/health returns 200 (auth-free health endpoint via sandbox exec)", + "polarity": "pass", + "normalized_id": "health.returns.200.auth.free.health.endpoint.via.sandbox.exec", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-device-auth-health.sh", + "line": 228, + "text": "/health returned ${HEALTH_CODE} — expected 200", + "polarity": "fail", + "normalized_id": "health.returned.health.code.expected.200", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-device-auth-health.sh", + "line": 239, + "text": "/ returns 401 (device auth is active — confirms test premise)", + "polarity": "pass", + "normalized_id": "returns.401.device.auth.is.active.confirms.test.premise", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-device-auth-health.sh", + "line": 245, + "text": "/ returned ${ROOT_CODE:-empty} — expected 401 (device auth) or 200 (no auth)", + "polarity": "fail", + "normalized_id": "returned.root.code.empty.expected.401.device.auth.or.200.no.auth", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-device-auth-health.sh", + "line": 260, + "text": "Status reports 'Offline' — #2342 REGRESSION: 401 treated as dead", + "polarity": "fail", + "normalized_id": "status.reports.offline.2342.regression.401.treated.as.dead", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-device-auth-health.sh", + "line": 263, + "text": "Status does NOT report 'Offline' (gateway correctly detected as alive)", + "polarity": "pass", + "normalized_id": "status.does.not.report.offline.gateway.correctly.detected.as.alive", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-device-auth-health.sh", + "line": 268, + "text": "Status shows positive health indicator (Running/Online/Healthy)", + "polarity": "pass", + "normalized_id": "status.shows.positive.health.indicator.running.online.healthy", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-device-auth-health.sh", + "line": 285, + "text": "Host port forward to dashboard is live (HTTP ${HOST_HEALTH_CODE})", + "polarity": "pass", + "normalized_id": "host.port.forward.to.dashboard.is.live.http.host.health.code", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-device-auth-health.sh", + "line": 291, + "text": "Host health probe returned ${HOST_HEALTH_CODE} — expected 200 or 401", + "polarity": "fail", + "normalized_id": "host.health.probe.returned.host.health.code.expected.200.or.401", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-device-auth-health.sh", + "line": 319, + "text": "Status reports 'Offline' during recovery — #2342 regression", + "polarity": "fail", + "normalized_id": "status.reports.offline.during.recovery.2342.regression", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-device-auth-health.sh", + "line": 321, + "text": "Status does not report 'Offline' during recovery attempt", + "polarity": "pass", + "normalized_id": "status.does.not.report.offline.during.recovery.attempt", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-device-auth-health.sh", + "line": 340, + "text": "Gateway recovered after restart (HTTP ${RECOVER_HEALTH} on /health)", + "polarity": "pass", + "normalized_id": "gateway.recovered.after.restart.http.recover.health.on.health", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-device-auth-health.sh", + "line": 353, + "text": "Onboard log contains deployment verification output", + "polarity": "pass", + "normalized_id": "onboard.log.contains.deployment.verification.output", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-device-auth-health.sh", + "line": 355, + "text": "Onboard log confirms dashboard readiness check passed", + "polarity": "pass", + "normalized_id": "onboard.log.confirms.dashboard.readiness.check.passed", + "mapping_status": "deferred" + } + ] + }, + { + "script": "test/e2e/test-diagnostics.sh", + "assertions": [ + { + "script": "test/e2e/test-diagnostics.sh", + "line": 182, + "text": "TC-DIAG-04: Exit code", + "polarity": "fail", + "normalized_id": "tc.diag.04.exit.code", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-diagnostics.sh", + "line": 187, + "text": "TC-DIAG-04: Version output matches semver ($version_output)", + "polarity": "pass", + "normalized_id": "tc.diag.04.version.output.matches.semver.version.output", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-diagnostics.sh", + "line": 189, + "text": "TC-DIAG-04: Format", + "polarity": "fail", + "normalized_id": "tc.diag.04.format", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-diagnostics.sh", + "line": 217, + "text": "TC-DIAG-02: Exit code", + "polarity": "fail", + "normalized_id": "tc.diag.02.exit.code", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-diagnostics.sh", + "line": 223, + "text": "TC-DIAG-02: debug --quick produced non-empty archive (${elapsed}s)", + "polarity": "pass", + "normalized_id": "tc.diag.02.debug.quick.produced.non.empty.archive.elapsed.s", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-diagnostics.sh", + "line": 225, + "text": "TC-DIAG-02: Output", + "polarity": "fail", + "normalized_id": "tc.diag.02.output", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-diagnostics.sh", + "line": 229, + "text": "TC-DIAG-02: Completed within time limit (${elapsed}s)", + "polarity": "pass", + "normalized_id": "tc.diag.02.completed.within.time.limit.elapsed.s", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-diagnostics.sh", + "line": 231, + "text": "TC-DIAG-02: Timing", + "polarity": "fail", + "normalized_id": "tc.diag.02.timing", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-diagnostics.sh", + "line": 253, + "text": "TC-DIAG-01: Setup", + "polarity": "fail", + "normalized_id": "tc.diag.01.setup", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-diagnostics.sh", + "line": 258, + "text": "TC-DIAG-01: Debug tarball created", + "polarity": "pass", + "normalized_id": "tc.diag.01.debug.tarball.created", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-diagnostics.sh", + "line": 262, + "text": "TC-DIAG-01: Extract", + "polarity": "fail", + "normalized_id": "tc.diag.01.extract", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-diagnostics.sh", + "line": 279, + "text": "TC-DIAG-01: No API key found in debug tarball", + "polarity": "pass", + "normalized_id": "tc.diag.01.no.api.key.found.in.debug.tarball", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-diagnostics.sh", + "line": 281, + "text": "TC-DIAG-01: Credential leak", + "polarity": "fail", + "normalized_id": "tc.diag.01.credential.leak", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-diagnostics.sh", + "line": 287, + "text": "TC-DIAG-01: No nvapi- pattern credentials in tarball", + "polarity": "pass", + "normalized_id": "tc.diag.01.no.nvapi.pattern.credentials.in.tarball", + "mapping_status": "mapped" + }, + { + "script": "test/e2e/test-diagnostics.sh", + "line": 289, + "text": "TC-DIAG-01: Pattern leak", + "polarity": "fail", + "normalized_id": "tc.diag.01.pattern.leak", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-diagnostics.sh", + "line": 306, + "text": "TC-DIAG-05: Config", + "polarity": "fail", + "normalized_id": "tc.diag.05.config", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-diagnostics.sh", + "line": 310, + "text": "TC-DIAG-05: openclaw.json readable inside sandbox", + "polarity": "pass", + "normalized_id": "tc.diag.05.openclaw.json.readable.inside.sandbox", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-diagnostics.sh", + "line": 316, + "text": "TC-DIAG-05: nemoclaw status shows model info", + "polarity": "pass", + "normalized_id": "tc.diag.05.nemoclaw.status.shows.model.info", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-diagnostics.sh", + "line": 318, + "text": "TC-DIAG-05: nemoclaw status shows Model field", + "polarity": "pass", + "normalized_id": "tc.diag.05.nemoclaw.status.shows.model.field", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-diagnostics.sh", + "line": 320, + "text": "TC-DIAG-05: Status", + "polarity": "fail", + "normalized_id": "tc.diag.05.status", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-diagnostics.sh", + "line": 338, + "text": "TC-DIAG-03: List", + "polarity": "fail", + "normalized_id": "tc.diag.03.list", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-diagnostics.sh", + "line": 343, + "text": "TC-DIAG-03: credentials list works (store empty — API key passed via env on CI)", + "polarity": "pass", + "normalized_id": "tc.diag.03.credentials.list.works.store.empty.api.key.passed.via.env.on.ci", + "mapping_status": "mapped" + }, + { + "script": "test/e2e/test-diagnostics.sh", + "line": 347, + "text": "TC-DIAG-03: Value leak", + "polarity": "fail", + "normalized_id": "tc.diag.03.value.leak", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-diagnostics.sh", + "line": 349, + "text": "TC-DIAG-03: credentials list does not expose env key values", + "polarity": "pass", + "normalized_id": "tc.diag.03.credentials.list.does.not.expose.env.key.values", + "mapping_status": "mapped" + }, + { + "script": "test/e2e/test-diagnostics.sh", + "line": 355, + "text": "TC-DIAG-03: credentials list shows key name", + "polarity": "pass", + "normalized_id": "tc.diag.03.credentials.list.shows.key.name", + "mapping_status": "mapped" + }, + { + "script": "test/e2e/test-diagnostics.sh", + "line": 362, + "text": "TC-DIAG-03: Value leak", + "polarity": "fail", + "normalized_id": "tc.diag.03.value.leak", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-diagnostics.sh", + "line": 364, + "text": "TC-DIAG-03: credentials list does not expose key values", + "polarity": "pass", + "normalized_id": "tc.diag.03.credentials.list.does.not.expose.key.values", + "mapping_status": "mapped" + }, + { + "script": "test/e2e/test-diagnostics.sh", + "line": 373, + "text": "TC-DIAG-03: credentials reset completed", + "polarity": "pass", + "normalized_id": "tc.diag.03.credentials.reset.completed", + "mapping_status": "mapped" + }, + { + "script": "test/e2e/test-diagnostics.sh", + "line": 375, + "text": "TC-DIAG-03: Reset", + "polarity": "fail", + "normalized_id": "tc.diag.03.reset", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-diagnostics.sh", + "line": 383, + "text": "TC-DIAG-03: Post-reset", + "polarity": "fail", + "normalized_id": "tc.diag.03.post.reset", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-diagnostics.sh", + "line": 385, + "text": "TC-DIAG-03: NVIDIA_API_KEY removed after reset", + "polarity": "pass", + "normalized_id": "tc.diag.03.nvidia.api.key.removed.after.reset", + "mapping_status": "retired" + }, + { + "script": "test/e2e/test-diagnostics.sh", + "line": 405, + "text": "$PASS${NC}", + "polarity": "pass", + "normalized_id": "pass.nc", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-diagnostics.sh", + "line": 406, + "text": "$FAIL${NC}", + "polarity": "fail", + "normalized_id": "fail.nc", + "mapping_status": "deferred" + } + ] + }, + { + "script": "test/e2e/test-docs-validation.sh", + "assertions": [ + { + "script": "test/e2e/test-docs-validation.sh", + "line": 81, + "text": "nemoclaw on PATH", + "polarity": "pass", + "normalized_id": "nemoclaw.on.path", + "mapping_status": "mapped" + }, + { + "script": "test/e2e/test-docs-validation.sh", + "line": 90, + "text": "nemoclaw on PATH (after sourcing nvm)", + "polarity": "pass", + "normalized_id": "nemoclaw.on.path.after.sourcing.nvm", + "mapping_status": "mapped" + }, + { + "script": "test/e2e/test-docs-validation.sh", + "line": 92, + "text": "nemoclaw not on PATH — install NemoClaw first", + "polarity": "fail", + "normalized_id": "nemoclaw.not.on.path.install.nemoclaw.first", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-docs-validation.sh", + "line": 109, + "text": "CLI / docs parity check passed", + "polarity": "pass", + "normalized_id": "cli.docs.parity.check.passed", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-docs-validation.sh", + "line": 111, + "text": "CLI / docs parity check failed (exit ${cli_rc})", + "polarity": "fail", + "normalized_id": "cli.docs.parity.check.failed.exit.cli.rc", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-docs-validation.sh", + "line": 135, + "text": "Markdown link validation passed", + "polarity": "pass", + "normalized_id": "markdown.link.validation.passed", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-docs-validation.sh", + "line": 141, + "text": "Markdown link validation failed (exit ${links_rc})", + "polarity": "fail", + "normalized_id": "markdown.link.validation.failed.exit.links.rc", + "mapping_status": "deferred" + } + ] + }, + { + "script": "test/e2e/test-double-onboard.sh", + "assertions": [ + { + "script": "test/e2e/test-double-onboard.sh", + "line": 384, + "text": "Pre-cleanup complete", + "polarity": "pass", + "normalized_id": "pre.cleanup.complete", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-double-onboard.sh", + "line": 392, + "text": "Docker is running", + "polarity": "pass", + "normalized_id": "docker.is.running", + "mapping_status": "mapped" + }, + { + "script": "test/e2e/test-double-onboard.sh", + "line": 394, + "text": "Docker is not running — cannot continue", + "polarity": "fail", + "normalized_id": "docker.is.not.running.cannot.continue", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-double-onboard.sh", + "line": 399, + "text": "openshell CLI installed", + "polarity": "pass", + "normalized_id": "openshell.cli.installed", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-double-onboard.sh", + "line": 401, + "text": "openshell CLI not found — cannot continue", + "polarity": "fail", + "normalized_id": "openshell.cli.not.found.cannot.continue", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-double-onboard.sh", + "line": 406, + "text": "nemoclaw CLI available", + "polarity": "pass", + "normalized_id": "nemoclaw.cli.available", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-double-onboard.sh", + "line": 408, + "text": "nemoclaw CLI not found — cannot continue", + "polarity": "fail", + "normalized_id": "nemoclaw.cli.not.found.cannot.continue", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-double-onboard.sh", + "line": 413, + "text": "python3 installed", + "polarity": "pass", + "normalized_id": "python3.installed", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-double-onboard.sh", + "line": 415, + "text": "python3 not found — cannot continue", + "polarity": "fail", + "normalized_id": "python3.not.found.cannot.continue", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-double-onboard.sh", + "line": 420, + "text": "Fake OpenAI-compatible endpoint started at ${FAKE_BASE_URL}", + "polarity": "pass", + "normalized_id": "fake.openai.compatible.endpoint.started.at.fake.base.url", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-double-onboard.sh", + "line": 422, + "text": "Failed to start fake OpenAI-compatible endpoint", + "polarity": "fail", + "normalized_id": "failed.to.start.fake.openai.compatible.endpoint", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-double-onboard.sh", + "line": 441, + "text": "First onboard completed successfully", + "polarity": "pass", + "normalized_id": "first.onboard.completed.successfully", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-double-onboard.sh", + "line": 443, + "text": "First onboard timed out after ${PHASE_TIMEOUT}s (exit 124)", + "polarity": "fail", + "normalized_id": "first.onboard.timed.out.after.phase.timeout.s.exit.124", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-double-onboard.sh", + "line": 446, + "text": "First onboard exited $exit1 (expected 0)", + "polarity": "fail", + "normalized_id": "first.onboard.exited.exit1.expected.0", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-double-onboard.sh", + "line": 451, + "text": "Sandbox '$SANDBOX_A' created", + "polarity": "pass", + "normalized_id": "sandbox.sandbox.a.created", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-double-onboard.sh", + "line": 453, + "text": "Sandbox '$SANDBOX_A' creation not confirmed in output", + "polarity": "fail", + "normalized_id": "sandbox.sandbox.a.creation.not.confirmed.in.output", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-double-onboard.sh", + "line": 457, + "text": "Gateway is running after first onboard", + "polarity": "pass", + "normalized_id": "gateway.is.running.after.first.onboard", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-double-onboard.sh", + "line": 459, + "text": "Gateway is not running after first onboard", + "polarity": "fail", + "normalized_id": "gateway.is.not.running.after.first.onboard", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-double-onboard.sh", + "line": 463, + "text": "Sandbox '$SANDBOX_A' exists in openshell", + "polarity": "pass", + "normalized_id": "sandbox.sandbox.a.exists.in.openshell", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-double-onboard.sh", + "line": 465, + "text": "Sandbox '$SANDBOX_A' not found in openshell", + "polarity": "fail", + "normalized_id": "sandbox.sandbox.a.not.found.in.openshell", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-double-onboard.sh", + "line": 469, + "text": "Registry contains '$SANDBOX_A'", + "polarity": "pass", + "normalized_id": "registry.contains.sandbox.a", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-double-onboard.sh", + "line": 471, + "text": "Registry does not contain '$SANDBOX_A'", + "polarity": "fail", + "normalized_id": "registry.does.not.contain.sandbox.a", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-double-onboard.sh", + "line": 488, + "text": "Second onboard completed successfully", + "polarity": "pass", + "normalized_id": "second.onboard.completed.successfully", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-double-onboard.sh", + "line": 490, + "text": "Second onboard timed out after ${PHASE_TIMEOUT}s (exit 124)", + "polarity": "fail", + "normalized_id": "second.onboard.timed.out.after.phase.timeout.s.exit.124", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-double-onboard.sh", + "line": 493, + "text": "Second onboard exited $exit2 (expected 0)", + "polarity": "fail", + "normalized_id": "second.onboard.exited.exit2.expected.0", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-double-onboard.sh", + "line": 499, + "text": "Healthy gateway runtime reused on second onboard ($GATEWAY_ID_BEFORE)", + "polarity": "pass", + "normalized_id": "healthy.gateway.runtime.reused.on.second.onboard.gateway.id.before", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-double-onboard.sh", + "line": 501, + "text": "Gateway runtime changed on second onboard (before=$GATEWAY_ID_BEFORE after=$GATEWAY_ID_AFTER)", + "polarity": "fail", + "normalized_id": "gateway.runtime.changed.on.second.onboard.before.gateway.id.before.after.gateway.id.after", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-double-onboard.sh", + "line": 505, + "text": "Port 8080 conflict detected (regression)", + "polarity": "fail", + "normalized_id": "port.8080.conflict.detected.regression", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-double-onboard.sh", + "line": 507, + "text": "No port 8080 conflict on second onboard", + "polarity": "pass", + "normalized_id": "no.port.8080.conflict.on.second.onboard", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-double-onboard.sh", + "line": 511, + "text": "Port 18789 conflict detected on second onboard", + "polarity": "fail", + "normalized_id": "port.18789.conflict.detected.on.second.onboard", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-double-onboard.sh", + "line": 513, + "text": "No port 18789 conflict on second onboard", + "polarity": "pass", + "normalized_id": "no.port.18789.conflict.on.second.onboard", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-double-onboard.sh", + "line": 517, + "text": "Sandbox '$SANDBOX_A' still exists after recreate", + "polarity": "pass", + "normalized_id": "sandbox.sandbox.a.still.exists.after.recreate", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-double-onboard.sh", + "line": 519, + "text": "Sandbox '$SANDBOX_A' missing after recreate", + "polarity": "fail", + "normalized_id": "sandbox.sandbox.a.missing.after.recreate", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-double-onboard.sh", + "line": 537, + "text": "Alternate gateway alias selected before third onboard", + "polarity": "pass", + "normalized_id": "alternate.gateway.alias.selected.before.third.onboard", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-double-onboard.sh", + "line": 539, + "text": "Alternate gateway alias was not selected before third onboard (selected=${selected_gateway:-unknown})", + "polarity": "fail", + "normalized_id": "alternate.gateway.alias.was.not.selected.before.third.onboard.selected.selected.gateway.unknown", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-double-onboard.sh", + "line": 542, + "text": "Could not select alternate gateway alias before third onboard (add output=${alt_gateway_add_output:-empty})", + "polarity": "fail", + "normalized_id": "could.not.select.alternate.gateway.alias.before.third.onboard.add.output.alt.gateway.add.output.empty", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-double-onboard.sh", + "line": 553, + "text": "Third onboard completed successfully", + "polarity": "pass", + "normalized_id": "third.onboard.completed.successfully", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-double-onboard.sh", + "line": 555, + "text": "Third onboard timed out after ${PHASE_TIMEOUT}s (exit 124)", + "polarity": "fail", + "normalized_id": "third.onboard.timed.out.after.phase.timeout.s.exit.124", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-double-onboard.sh", + "line": 558, + "text": "Third onboard exited $exit3 (expected 0)", + "polarity": "fail", + "normalized_id": "third.onboard.exited.exit3.expected.0", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-double-onboard.sh", + "line": 564, + "text": "Healthy gateway runtime reused on third onboard ($GATEWAY_ID_BEFORE3)", + "polarity": "pass", + "normalized_id": "healthy.gateway.runtime.reused.on.third.onboard.gateway.id.before3", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-double-onboard.sh", + "line": 566, + "text": "Gateway runtime changed on third onboard (before=$GATEWAY_ID_BEFORE3 after=$GATEWAY_ID_AFTER3)", + "polarity": "fail", + "normalized_id": "gateway.runtime.changed.on.third.onboard.before.gateway.id.before3.after.gateway.id.after3", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-double-onboard.sh", + "line": 570, + "text": "Port 8080 conflict on third onboard", + "polarity": "fail", + "normalized_id": "port.8080.conflict.on.third.onboard", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-double-onboard.sh", + "line": 572, + "text": "No port 8080 conflict on third onboard", + "polarity": "pass", + "normalized_id": "no.port.8080.conflict.on.third.onboard", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-double-onboard.sh", + "line": 576, + "text": "Port 18789 conflict on third onboard", + "polarity": "fail", + "normalized_id": "port.18789.conflict.on.third.onboard", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-double-onboard.sh", + "line": 578, + "text": "No port 18789 conflict on third onboard", + "polarity": "pass", + "normalized_id": "no.port.18789.conflict.on.third.onboard", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-double-onboard.sh", + "line": 587, + "text": "Named gateway reselected during third onboard", + "polarity": "pass", + "normalized_id": "named.gateway.reselected.during.third.onboard", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-double-onboard.sh", + "line": 589, + "text": "Named gateway was not reselected during third onboard (selected=${selected_gateway:-unknown})", + "polarity": "fail", + "normalized_id": "named.gateway.was.not.reselected.during.third.onboard.selected.selected.gateway.unknown", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-double-onboard.sh", + "line": 593, + "text": "Sandbox '$SANDBOX_B' created", + "polarity": "pass", + "normalized_id": "sandbox.sandbox.b.created", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-double-onboard.sh", + "line": 595, + "text": "Sandbox '$SANDBOX_B' was not created", + "polarity": "fail", + "normalized_id": "sandbox.sandbox.b.was.not.created", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-double-onboard.sh", + "line": 599, + "text": "First sandbox '$SANDBOX_A' still exists after creating '$SANDBOX_B'", + "polarity": "pass", + "normalized_id": "first.sandbox.sandbox.a.still.exists.after.creating.sandbox.b", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-double-onboard.sh", + "line": 601, + "text": "First sandbox '$SANDBOX_A' disappeared after creating '$SANDBOX_B' (regression: #849)", + "polarity": "fail", + "normalized_id": "first.sandbox.sandbox.a.disappeared.after.creating.sandbox.b.regression.849", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-double-onboard.sh", + "line": 621, + "text": "nemoclaw list shows dashboard ports for both test sandboxes (#2174)", + "polarity": "pass", + "normalized_id": "nemoclaw.list.shows.dashboard.ports.for.both.test.sandboxes.2174", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-double-onboard.sh", + "line": 623, + "text": "nemoclaw list did not show dashboard ports for both test sandboxes (a=${port_a:-missing} b=${port_b:-missing})", + "polarity": "fail", + "normalized_id": "nemoclaw.list.did.not.show.dashboard.ports.for.both.test.sandboxes.a.port.a.missing.b.port.b.missing", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-double-onboard.sh", + "line": 629, + "text": "nemoclaw list shows distinct dashboard ports for test sandboxes (#2174)", + "polarity": "pass", + "normalized_id": "nemoclaw.list.shows.distinct.dashboard.ports.for.test.sandboxes.2174", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-double-onboard.sh", + "line": 631, + "text": "test sandboxes did not have distinct dashboard ports (#2174): ${SANDBOX_A}=${port_a:-missing} ${SANDBOX_B}=${port_b:-missing}", + "polarity": "fail", + "normalized_id": "test.sandboxes.did.not.have.distinct.dashboard.ports.2174.sandbox.a.port.a.missing.sandbox.b.port.b.missing", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-double-onboard.sh", + "line": 645, + "text": "Probe-only connect recovered '$SANDBOX_B' dashboard forward", + "polarity": "pass", + "normalized_id": "probe.only.connect.recovered.sandbox.b.dashboard.forward", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-double-onboard.sh", + "line": 647, + "text": "Probe-only connect exited $probe_exit after stopping '$SANDBOX_B' dashboard forward", + "polarity": "fail", + "normalized_id": "probe.only.connect.exited.probe.exit.after.stopping.sandbox.b.dashboard.forward", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-double-onboard.sh", + "line": 657, + "text": "Second sandbox dashboard forward restored on its recorded port", + "polarity": "pass", + "normalized_id": "second.sandbox.dashboard.forward.restored.on.its.recorded.port", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-double-onboard.sh", + "line": 659, + "text": "Second sandbox dashboard forward owner mismatch on port $port_b (owner=${owner_b:-missing})", + "polarity": "fail", + "normalized_id": "second.sandbox.dashboard.forward.owner.mismatch.on.port.port.b.owner.owner.b.missing", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-double-onboard.sh", + "line": 665, + "text": "First sandbox dashboard forward kept its recorded port", + "polarity": "pass", + "normalized_id": "first.sandbox.dashboard.forward.kept.its.recorded.port", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-double-onboard.sh", + "line": 667, + "text": "First sandbox dashboard forward owner mismatch on port $port_a (owner=${owner_a:-missing})", + "polarity": "fail", + "normalized_id": "first.sandbox.dashboard.forward.owner.mismatch.on.port.port.a.owner.owner.a.missing", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-double-onboard.sh", + "line": 681, + "text": "OpenShell reports '$SANDBOX_A' absent after direct deletion", + "polarity": "pass", + "normalized_id": "openshell.reports.sandbox.a.absent.after.direct.deletion", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-double-onboard.sh", + "line": 683, + "text": "OpenShell still reports '$SANDBOX_A' after direct deletion", + "polarity": "fail", + "normalized_id": "openshell.still.reports.sandbox.a.after.direct.deletion", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-double-onboard.sh", + "line": 687, + "text": "Registry still contains stale '$SANDBOX_A' entry", + "polarity": "pass", + "normalized_id": "registry.still.contains.stale.sandbox.a.entry", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-double-onboard.sh", + "line": 689, + "text": "Registry was unexpectedly cleaned before status reconciliation", + "polarity": "fail", + "normalized_id": "registry.was.unexpectedly.cleaned.before.status.reconciliation", + "mapping_status": "retired" + }, + { + "script": "test/e2e/test-double-onboard.sh", + "line": 699, + "text": "Stale sandbox status exited 1", + "polarity": "pass", + "normalized_id": "stale.sandbox.status.exited.1", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-double-onboard.sh", + "line": 701, + "text": "Stale sandbox status exited $status_exit (expected 1)", + "polarity": "fail", + "normalized_id": "stale.sandbox.status.exited.status.exit.expected.1", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-double-onboard.sh", + "line": 705, + "text": "Stale registry entry was reconciled during status", + "polarity": "pass", + "normalized_id": "stale.registry.entry.was.reconciled.during.status", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-double-onboard.sh", + "line": 707, + "text": "Stale registry reconciliation message missing", + "polarity": "fail", + "normalized_id": "stale.registry.reconciliation.message.missing", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-double-onboard.sh", + "line": 711, + "text": "Registry still contains '$SANDBOX_A' after status reconciliation", + "polarity": "fail", + "normalized_id": "registry.still.contains.sandbox.a.after.status.reconciliation", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-double-onboard.sh", + "line": 713, + "text": "Registry entry for '$SANDBOX_A' removed after status reconciliation", + "polarity": "pass", + "normalized_id": "registry.entry.for.sandbox.a.removed.after.status.reconciliation", + "mapping_status": "retired" + }, + { + "script": "test/e2e/test-double-onboard.sh", + "line": 732, + "text": "Post-stop status exited $gateway_status_exit", + "polarity": "pass", + "normalized_id": "post.stop.status.exited.gateway.status.exit", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-double-onboard.sh", + "line": 734, + "text": "Post-stop status exited $gateway_status_exit (expected 0 or 1)", + "polarity": "fail", + "normalized_id": "post.stop.status.exited.gateway.status.exit.expected.0.or.1", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-double-onboard.sh", + "line": 740, + "text": "Gateway lifecycle response was explicit after gateway stop", + "polarity": "pass", + "normalized_id": "gateway.lifecycle.response.was.explicit.after.gateway.stop", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-double-onboard.sh", + "line": 742, + "text": "Gateway lifecycle response was not explicit after gateway stop", + "polarity": "fail", + "normalized_id": "gateway.lifecycle.response.was.not.explicit.after.gateway.stop", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-double-onboard.sh", + "line": 748, + "text": "Registry still contains '$SANDBOX_B' after gateway stop", + "polarity": "pass", + "normalized_id": "registry.still.contains.sandbox.b.after.gateway.stop", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-double-onboard.sh", + "line": 750, + "text": "Registry is missing '$SANDBOX_B' after gateway stop", + "polarity": "fail", + "normalized_id": "registry.is.missing.sandbox.b.after.gateway.stop", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-double-onboard.sh", + "line": 783, + "text": "Sandbox '$SANDBOX_A' still exists after cleanup", + "polarity": "fail", + "normalized_id": "sandbox.sandbox.a.still.exists.after.cleanup", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-double-onboard.sh", + "line": 785, + "text": "Sandbox '$SANDBOX_A' cleaned up", + "polarity": "pass", + "normalized_id": "sandbox.sandbox.a.cleaned.up", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-double-onboard.sh", + "line": 789, + "text": "Sandbox '$SANDBOX_B' still exists after cleanup", + "polarity": "fail", + "normalized_id": "sandbox.sandbox.b.still.exists.after.cleanup", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-double-onboard.sh", + "line": 791, + "text": "Sandbox '$SANDBOX_B' cleaned up", + "polarity": "pass", + "normalized_id": "sandbox.sandbox.b.cleaned.up", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-double-onboard.sh", + "line": 795, + "text": "Registry still contains test sandbox entries", + "polarity": "fail", + "normalized_id": "registry.still.contains.test.sandbox.entries", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-double-onboard.sh", + "line": 797, + "text": "Registry cleaned up", + "polarity": "pass", + "normalized_id": "registry.cleaned.up", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-double-onboard.sh", + "line": 800, + "text": "Final cleanup complete", + "polarity": "pass", + "normalized_id": "final.cleanup.complete", + "mapping_status": "deferred" + } + ] + }, + { + "script": "test/e2e/test-full-e2e.sh", + "assertions": [ + { + "script": "test/e2e/test-full-e2e.sh", + "line": 100, + "text": "Pre-cleanup complete", + "polarity": "pass", + "normalized_id": "pre.cleanup.complete", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-full-e2e.sh", + "line": 108, + "text": "Docker is running", + "polarity": "pass", + "normalized_id": "docker.is.running", + "mapping_status": "mapped" + }, + { + "script": "test/e2e/test-full-e2e.sh", + "line": 110, + "text": "Docker is not running — cannot continue", + "polarity": "fail", + "normalized_id": "docker.is.not.running.cannot.continue", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-full-e2e.sh", + "line": 115, + "text": "NVIDIA_API_KEY is set (starts with nvapi-)", + "polarity": "pass", + "normalized_id": "nvidia.api.key.is.set.starts.with.nvapi", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-full-e2e.sh", + "line": 117, + "text": "NVIDIA_API_KEY not set or invalid — required for live inference", + "polarity": "fail", + "normalized_id": "nvidia.api.key.not.set.or.invalid.required.for.live.inference", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-full-e2e.sh", + "line": 122, + "text": "Network access to integrate.api.nvidia.com", + "polarity": "pass", + "normalized_id": "network.access.to.integrate.api.nvidia.com", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-full-e2e.sh", + "line": 124, + "text": "Cannot reach integrate.api.nvidia.com", + "polarity": "fail", + "normalized_id": "cannot.reach.integrate.api.nvidia.com", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-full-e2e.sh", + "line": 129, + "text": "NEMOCLAW_NON_INTERACTIVE=1 is required", + "polarity": "fail", + "normalized_id": "nemoclaw.non.interactive.1.is.required", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-full-e2e.sh", + "line": 134, + "text": "NEMOCLAW_ACCEPT_THIRD_PARTY_SOFTWARE=1 is required for non-interactive install", + "polarity": "fail", + "normalized_id": "nemoclaw.accept.third.party.software.1.is.required.for.non.interactive.install", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-full-e2e.sh", + "line": 144, + "text": "Could not cd to repo root: $REPO", + "polarity": "fail", + "normalized_id": "could.not.cd.to.repo.root.repo", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-full-e2e.sh", + "line": 182, + "text": "install.sh completed (exit 0)", + "polarity": "pass", + "normalized_id": "install.sh.completed.exit.0", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-full-e2e.sh", + "line": 184, + "text": "install.sh failed (exit $install_exit)", + "polarity": "fail", + "normalized_id": "install.sh.failed.exit.install.exit", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-full-e2e.sh", + "line": 190, + "text": "nemoclaw installed at $(command -v nemoclaw)", + "polarity": "pass", + "normalized_id": "nemoclaw.installed.at.command.v.nemoclaw", + "mapping_status": "mapped" + }, + { + "script": "test/e2e/test-full-e2e.sh", + "line": 192, + "text": "nemoclaw not found on PATH after install", + "polarity": "fail", + "normalized_id": "nemoclaw.not.found.on.path.after.install", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-full-e2e.sh", + "line": 198, + "text": "openshell installed ($(openshell --version 2>&1 || echo unknown))", + "polarity": "pass", + "normalized_id": "openshell.installed.openshell.version.2.1.echo.unknown", + "mapping_status": "mapped" + }, + { + "script": "test/e2e/test-full-e2e.sh", + "line": 200, + "text": "openshell not found on PATH after install", + "polarity": "fail", + "normalized_id": "openshell.not.found.on.path.after.install", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-full-e2e.sh", + "line": 205, + "text": "nemoclaw --help exits 0", + "polarity": "pass", + "normalized_id": "nemoclaw.help.exits.0", + "mapping_status": "mapped" + }, + { + "script": "test/e2e/test-full-e2e.sh", + "line": 207, + "text": "nemoclaw --help failed", + "polarity": "fail", + "normalized_id": "nemoclaw.help.failed", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-full-e2e.sh", + "line": 218, + "text": "nemoclaw list contains '${SANDBOX_NAME}'", + "polarity": "pass", + "normalized_id": "nemoclaw.list.contains.sandbox.name", + "mapping_status": "mapped" + }, + { + "script": "test/e2e/test-full-e2e.sh", + "line": 220, + "text": "nemoclaw list does not contain '${SANDBOX_NAME}'", + "polarity": "fail", + "normalized_id": "nemoclaw.list.does.not.contain.sandbox.name", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-full-e2e.sh", + "line": 223, + "text": "nemoclaw list failed: ${list_output:0:200}", + "polarity": "fail", + "normalized_id": "nemoclaw.list.failed.list.output.0.200", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-full-e2e.sh", + "line": 228, + "text": "nemoclaw ${SANDBOX_NAME} status exits 0", + "polarity": "pass", + "normalized_id": "nemoclaw.sandbox.name.status.exits.0", + "mapping_status": "mapped" + }, + { + "script": "test/e2e/test-full-e2e.sh", + "line": 230, + "text": "nemoclaw ${SANDBOX_NAME} status failed: ${status_output:0:200}", + "polarity": "fail", + "normalized_id": "nemoclaw.sandbox.name.status.failed.status.output.0.200", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-full-e2e.sh", + "line": 237, + "text": "Inference configured via onboard", + "polarity": "pass", + "normalized_id": "inference.configured.via.onboard", + "mapping_status": "mapped" + }, + { + "script": "test/e2e/test-full-e2e.sh", + "line": 239, + "text": "Inference not configured — onboard did not set up nvidia-prod provider", + "polarity": "fail", + "normalized_id": "inference.not.configured.onboard.did.not.set.up.nvidia.prod.provider", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-full-e2e.sh", + "line": 242, + "text": "openshell inference get failed: ${inf_check:0:200}", + "polarity": "fail", + "normalized_id": "openshell.inference.get.failed.inf.check.0.200", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-full-e2e.sh", + "line": 248, + "text": "Policy applied to sandbox", + "polarity": "pass", + "normalized_id": "policy.applied.to.sandbox", + "mapping_status": "mapped" + }, + { + "script": "test/e2e/test-full-e2e.sh", + "line": 250, + "text": "No network policy found on sandbox", + "polarity": "fail", + "normalized_id": "no.network.policy.found.on.sandbox", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-full-e2e.sh", + "line": 255, + "text": "Policy presets (npm/pypi) detected in sandbox policy", + "polarity": "pass", + "normalized_id": "policy.presets.npm.pypi.detected.in.sandbox.policy", + "mapping_status": "mapped" + }, + { + "script": "test/e2e/test-full-e2e.sh", + "line": 260, + "text": "openshell policy get failed: ${policy_output:0:200}", + "polarity": "fail", + "normalized_id": "openshell.policy.get.failed.policy.output.0.200", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-full-e2e.sh", + "line": 283, + "text": "[LIVE] Direct API: model responded with PONG", + "polarity": "pass", + "normalized_id": "live.direct.api.model.responded.with.pong", + "mapping_status": "mapped" + }, + { + "script": "test/e2e/test-full-e2e.sh", + "line": 285, + "text": "[LIVE] Direct API: expected PONG, got: ${api_content:0:200}", + "polarity": "fail", + "normalized_id": "live.direct.api.expected.pong.got.api.content.0.200", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-full-e2e.sh", + "line": 288, + "text": "[LIVE] Direct API: empty response from curl", + "polarity": "fail", + "normalized_id": "live.direct.api.empty.response.from.curl", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-full-e2e.sh", + "line": 357, + "text": "[ROUTING] inference.local: OpenShell routed curl to NVIDIA Endpoints and returned PONG", + "polarity": "pass", + "normalized_id": "routing.inference.local.openshell.routed.curl.to.nvidia.endpoints.and.returned.pong", + "mapping_status": "mapped" + }, + { + "script": "test/e2e/test-full-e2e.sh", + "line": 360, + "text": "[ROUTING] inference.local: expected PONG after 3 attempts, got: ${sandbox_content:0:200}", + "polarity": "fail", + "normalized_id": "routing.inference.local.expected.pong.after.3.attempts.got.sandbox.content.0.200", + "mapping_status": "mapped" + }, + { + "script": "test/e2e/test-full-e2e.sh", + "line": 412, + "text": "[LIVE] openclaw agent: model answered 6×7=42 through openclaw → inference.local", + "polarity": "pass", + "normalized_id": "live.openclaw.agent.model.answered.6.7.42.through.openclaw.inference.local", + "mapping_status": "mapped" + }, + { + "script": "test/e2e/test-full-e2e.sh", + "line": 414, + "text": "[LIVE] openclaw agent: expected '42' in agent reply, got: ${agent_reply:0:200}", + "polarity": "fail", + "normalized_id": "live.openclaw.agent.expected.42.in.agent.reply.got.agent.reply.0.200", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-full-e2e.sh", + "line": 432, + "text": "nemoclaw logs: produced output ($(echo ", + "polarity": "pass", + "normalized_id": "nemoclaw.logs.produced.output.echo", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-full-e2e.sh", + "line": 434, + "text": "nemoclaw logs: no output", + "polarity": "fail", + "normalized_id": "nemoclaw.logs.no.output", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-full-e2e.sh", + "line": 450, + "text": "Sandbox ${SANDBOX_NAME} still in registry after destroy", + "polarity": "fail", + "normalized_id": "sandbox.sandbox.name.still.in.registry.after.destroy", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-full-e2e.sh", + "line": 452, + "text": "Sandbox ${SANDBOX_NAME} removed", + "polarity": "pass", + "normalized_id": "sandbox.sandbox.name.removed", + "mapping_status": "retired" + } + ] + }, + { + "script": "test/e2e/test-gateway-drift-preflight.sh", + "assertions": [ + { + "script": "test/e2e/test-gateway-drift-preflight.sh", + "line": 8, + "text": "$1", + "polarity": "pass", + "normalized_id": "1", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-gateway-drift-preflight.sh", + "line": 11, + "text": "$1", + "polarity": "fail", + "normalized_id": "1", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-gateway-drift-preflight.sh", + "line": 156, + "text": "$description", + "polarity": "pass", + "normalized_id": "description", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-gateway-drift-preflight.sh", + "line": 158, + "text": "$description (missing pattern: $pattern)", + "polarity": "fail", + "normalized_id": "description.missing.pattern.pattern", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-gateway-drift-preflight.sh", + "line": 165, + "text": "$description (unexpected pattern: $pattern)", + "polarity": "fail", + "normalized_id": "description.unexpected.pattern.pattern", + "mapping_status": "retired" + }, + { + "script": "test/e2e/test-gateway-drift-preflight.sh", + "line": 167, + "text": "$description", + "polarity": "pass", + "normalized_id": "description", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-gateway-drift-preflight.sh", + "line": 175, + "text": "npm ci failed", + "polarity": "fail", + "normalized_id": "npm.ci.failed", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-gateway-drift-preflight.sh", + "line": 177, + "text": "CLI build failed", + "polarity": "fail", + "normalized_id": "cli.build.failed", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-gateway-drift-preflight.sh", + "line": 187, + "text": "backup-all exits non-zero on protobuf mismatch", + "polarity": "pass", + "normalized_id": "backup.all.exits.non.zero.on.protobuf.mismatch", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-gateway-drift-preflight.sh", + "line": 203, + "text": "backup-all unexpectedly succeeded with stale patched gateway image", + "polarity": "fail", + "normalized_id": "backup.all.unexpectedly.succeeded.with.stale.patched.gateway.image", + "mapping_status": "retired" + }, + { + "script": "test/e2e/test-gateway-drift-preflight.sh", + "line": 204, + "text": "backup-all exits non-zero on stale patched gateway image", + "polarity": "pass", + "normalized_id": "backup.all.exits.non.zero.on.stale.patched.gateway.image", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-gateway-drift-preflight.sh", + "line": 209, + "text": "sandbox list was called despite preflight image drift", + "polarity": "fail", + "normalized_id": "sandbox.list.was.called.despite.preflight.image.drift", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-gateway-drift-preflight.sh", + "line": 211, + "text": "preflight image drift blocks sandbox list", + "polarity": "pass", + "normalized_id": "preflight.image.drift.blocks.sandbox.list", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-gateway-drift-preflight.sh", + "line": 214, + "text": "Gateway drift preflight regression guard completed", + "polarity": "pass", + "normalized_id": "gateway.drift.preflight.regression.guard.completed", + "mapping_status": "deferred" + } + ] + }, + { + "script": "test/e2e/test-gateway-health-honest.sh", + "assertions": [ + { + "script": "test/e2e/test-gateway-health-honest.sh", + "line": 122, + "text": "openshell not found after install", + "polarity": "fail", + "normalized_id": "openshell.not.found.after.install", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-gateway-health-honest.sh", + "line": 123, + "text": "openshell-gateway not found after install", + "polarity": "fail", + "normalized_id": "openshell.gateway.not.found.after.install", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-gateway-health-honest.sh", + "line": 187, + "text": "Sabotage markers (GLIBC_2.38/2.39 or 'openshell-gateway-sabotage') not observed in gateway log ${GATEWAY_ONBOARD_LOG} — the test may have failed before the sabotaged gateway was invoked, so the assertions below cannot be trusted. Inspect $START_LOG and $GATEWAY_ONBOARD_LOG above for the real cause.", + "polarity": "fail", + "normalized_id": "sabotage.markers.glibc.2.38.2.39.or.openshell.gateway.sabotage.not.observed.in.gateway.log.gateway.onboard.log.the.test.may.have.failed.before.the.sabotaged.gateway.was.invoked.so.the.assertions.below.cannot.be.trusted.inspect.start.log.and.gateway.onboard.log.above.for.the.real.cause", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-gateway-health-honest.sh", + "line": 189, + "text": "Sabotage shim was invoked as expected (GLIBC/sabotage markers present in gateway log)", + "polarity": "pass", + "normalized_id": "sabotage.shim.was.invoked.as.expected.glibc.sabotage.markers.present.in.gateway.log", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-gateway-health-honest.sh", + "line": 196, + "text": "Onboard reported '✓ Docker-driver gateway is healthy' although the gateway binary crashed on startup (#3111 false-positive health check)", + "polarity": "fail", + "normalized_id": "onboard.reported.docker.driver.gateway.is.healthy.although.the.gateway.binary.crashed.on.startup.3111.false.positive.health.check", + "mapping_status": "mapped" + }, + { + "script": "test/e2e/test-gateway-health-honest.sh", + "line": 198, + "text": "Onboard did not falsely log 'Docker-driver gateway is healthy' when the binary crashed", + "polarity": "pass", + "normalized_id": "onboard.did.not.falsely.log.docker.driver.gateway.is.healthy.when.the.binary.crashed", + "mapping_status": "mapped" + }, + { + "script": "test/e2e/test-gateway-health-honest.sh", + "line": 205, + "text": "startGateway() resolved successfully despite a crashed binary — onboard would have proceeded to inference setup against a dead gateway", + "polarity": "fail", + "normalized_id": "startgateway.resolved.successfully.despite.a.crashed.binary.onboard.would.have.proceeded.to.inference.setup.against.a.dead.gateway", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-gateway-health-honest.sh", + "line": 207, + "text": "startGateway() did not resolve successfully with a crashed binary (node exit=${NODE_EXIT})", + "polarity": "pass", + "normalized_id": "startgateway.did.not.resolve.successfully.with.a.crashed.binary.node.exit.node.exit", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-gateway-health-honest.sh", + "line": 215, + "text": "Onboard did not surface any gateway failure indicator to the user", + "polarity": "fail", + "normalized_id": "onboard.did.not.surface.any.gateway.failure.indicator.to.the.user", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-gateway-health-honest.sh", + "line": 217, + "text": "Onboard surfaced a user-visible gateway failure message", + "polarity": "pass", + "normalized_id": "onboard.surfaced.a.user.visible.gateway.failure.message", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-gateway-health-honest.sh", + "line": 227, + "text": "A non-zombie gateway pid (${LINGERING_PID}, state=${STATE}) is still alive after a simulated crash", + "polarity": "fail", + "normalized_id": "a.non.zombie.gateway.pid.lingering.pid.state.state.is.still.alive.after.a.simulated.crash", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-gateway-health-honest.sh", + "line": 231, + "text": "No live (non-zombie) gateway process is running after the simulated crash", + "polarity": "pass", + "normalized_id": "no.live.non.zombie.gateway.process.is.running.after.the.simulated.crash", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-gateway-health-honest.sh", + "line": 234, + "text": "#3111 coverage guard green: onboard correctly surfaces a crashed gateway", + "polarity": "pass", + "normalized_id": "3111.coverage.guard.green.onboard.correctly.surfaces.a.crashed.gateway", + "mapping_status": "deferred" + } + ] + }, + { + "script": "test/e2e/test-gpu-double-onboard.sh", + "assertions": [ + { + "script": "test/e2e/test-gpu-double-onboard.sh", + "line": 153, + "text": "Pre-cleanup complete", + "polarity": "pass", + "normalized_id": "pre.cleanup.complete", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-gpu-double-onboard.sh", + "line": 161, + "text": "Docker is running", + "polarity": "pass", + "normalized_id": "docker.is.running", + "mapping_status": "mapped" + }, + { + "script": "test/e2e/test-gpu-double-onboard.sh", + "line": 163, + "text": "Docker is not running — cannot continue", + "polarity": "fail", + "normalized_id": "docker.is.not.running.cannot.continue", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-gpu-double-onboard.sh", + "line": 169, + "text": "nvidia-smi works (GPU VRAM: ${VRAM_MB:-unknown} MB)", + "polarity": "pass", + "normalized_id": "nvidia.smi.works.gpu.vram.vram.mb.unknown.mb", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-gpu-double-onboard.sh", + "line": 171, + "text": "nvidia-smi failed — no NVIDIA GPU available", + "polarity": "fail", + "normalized_id": "nvidia.smi.failed.no.nvidia.gpu.available", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-gpu-double-onboard.sh", + "line": 176, + "text": "NEMOCLAW_NON_INTERACTIVE=1 is required", + "polarity": "fail", + "normalized_id": "nemoclaw.non.interactive.1.is.required", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-gpu-double-onboard.sh", + "line": 181, + "text": "NEMOCLAW_ACCEPT_THIRD_PARTY_SOFTWARE=1 is required for non-interactive install", + "polarity": "fail", + "normalized_id": "nemoclaw.accept.third.party.software.1.is.required.for.non.interactive.install", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-gpu-double-onboard.sh", + "line": 193, + "text": "Ollama already installed: $(ollama --version 2>/dev/null || echo unknown)", + "polarity": "pass", + "normalized_id": "ollama.already.installed.ollama.version.2.dev.null.echo.unknown", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-gpu-double-onboard.sh", + "line": 197, + "text": "Ollama installed: $(ollama --version 2>/dev/null || echo unknown)", + "polarity": "pass", + "normalized_id": "ollama.installed.ollama.version.2.dev.null.echo.unknown", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-gpu-double-onboard.sh", + "line": 199, + "text": "Ollama installation failed", + "polarity": "fail", + "normalized_id": "ollama.installation.failed", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-gpu-double-onboard.sh", + "line": 216, + "text": "Existing Ollama stopped — port 11434 is free for onboard", + "polarity": "pass", + "normalized_id": "existing.ollama.stopped.port.11434.is.free.for.onboard", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-gpu-double-onboard.sh", + "line": 226, + "text": "Could not cd to repo root: $REPO", + "polarity": "fail", + "normalized_id": "could.not.cd.to.repo.root.repo", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-gpu-double-onboard.sh", + "line": 253, + "text": "install.sh completed (exit 0)", + "polarity": "pass", + "normalized_id": "install.sh.completed.exit.0", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-gpu-double-onboard.sh", + "line": 255, + "text": "install.sh failed (exit $install_exit)", + "polarity": "fail", + "normalized_id": "install.sh.failed.exit.install.exit", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-gpu-double-onboard.sh", + "line": 262, + "text": "nemoclaw on PATH: $(command -v nemoclaw)", + "polarity": "pass", + "normalized_id": "nemoclaw.on.path.command.v.nemoclaw", + "mapping_status": "mapped" + }, + { + "script": "test/e2e/test-gpu-double-onboard.sh", + "line": 264, + "text": "nemoclaw not found on PATH after install", + "polarity": "fail", + "normalized_id": "nemoclaw.not.found.on.path.after.install", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-gpu-double-onboard.sh", + "line": 276, + "text": "nemoclaw list contains '${SANDBOX_NAME}'", + "polarity": "pass", + "normalized_id": "nemoclaw.list.contains.sandbox.name", + "mapping_status": "mapped" + }, + { + "script": "test/e2e/test-gpu-double-onboard.sh", + "line": 278, + "text": "nemoclaw list does not contain '${SANDBOX_NAME}'", + "polarity": "fail", + "normalized_id": "nemoclaw.list.does.not.contain.sandbox.name", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-gpu-double-onboard.sh", + "line": 281, + "text": "nemoclaw list failed: ${list_output:0:200}", + "polarity": "fail", + "normalized_id": "nemoclaw.list.failed.list.output.0.200", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-gpu-double-onboard.sh", + "line": 286, + "text": "nemoclaw ${SANDBOX_NAME} status exits 0", + "polarity": "pass", + "normalized_id": "nemoclaw.sandbox.name.status.exits.0", + "mapping_status": "mapped" + }, + { + "script": "test/e2e/test-gpu-double-onboard.sh", + "line": 288, + "text": "nemoclaw ${SANDBOX_NAME} status failed", + "polarity": "fail", + "normalized_id": "nemoclaw.sandbox.name.status.failed", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-gpu-double-onboard.sh", + "line": 293, + "text": "Ollama running on 127.0.0.1:11434", + "polarity": "pass", + "normalized_id": "ollama.running.on.127.0.0.1.11434", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-gpu-double-onboard.sh", + "line": 295, + "text": "Ollama not running — onboard should have started it", + "polarity": "fail", + "normalized_id": "ollama.not.running.onboard.should.have.started.it", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-gpu-double-onboard.sh", + "line": 303, + "text": "Auth proxy running on :${PROXY_PORT} (HTTP $PROXY_LIVE_STATUS)", + "polarity": "pass", + "normalized_id": "auth.proxy.running.on.proxy.port.http.proxy.live.status", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-gpu-double-onboard.sh", + "line": 305, + "text": "Auth proxy not running on :${PROXY_PORT}", + "polarity": "fail", + "normalized_id": "auth.proxy.not.running.on.proxy.port", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-gpu-double-onboard.sh", + "line": 310, + "text": "Proxy token persisted at $TOKEN_FILE", + "polarity": "pass", + "normalized_id": "proxy.token.persisted.at.token.file", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-gpu-double-onboard.sh", + "line": 313, + "text": "Token file permissions: 600", + "polarity": "pass", + "normalized_id": "token.file.permissions.600", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-gpu-double-onboard.sh", + "line": 315, + "text": "Token file permissions: expected 600, got $PERMS", + "polarity": "fail", + "normalized_id": "token.file.permissions.expected.600.got.perms", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-gpu-double-onboard.sh", + "line": 318, + "text": "Proxy token file missing after first onboard", + "polarity": "fail", + "normalized_id": "proxy.token.file.missing.after.first.onboard", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-gpu-double-onboard.sh", + "line": 334, + "text": "Proxy accepts first-onboard token (200)", + "polarity": "pass", + "normalized_id": "proxy.accepts.first.onboard.token.200", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-gpu-double-onboard.sh", + "line": 336, + "text": "Proxy rejects first-onboard token (status: $FIRST_AUTH_STATUS)", + "polarity": "fail", + "normalized_id": "proxy.rejects.first.onboard.token.status.first.auth.status", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-gpu-double-onboard.sh", + "line": 349, + "text": "No models found in Ollama", + "polarity": "fail", + "normalized_id": "no.models.found.in.ollama", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-gpu-double-onboard.sh", + "line": 369, + "text": "openshell sandbox ssh-config failed", + "polarity": "fail", + "normalized_id": "openshell.sandbox.ssh.config.failed", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-gpu-double-onboard.sh", + "line": 376, + "text": "First-onboard sandbox inference succeeded", + "polarity": "pass", + "normalized_id": "first.onboard.sandbox.inference.succeeded", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-gpu-double-onboard.sh", + "line": 378, + "text": "First-onboard sandbox inference: expected PONG, got: ${sandbox_content:0:200}", + "polarity": "fail", + "normalized_id": "first.onboard.sandbox.inference.expected.pong.got.sandbox.content.0.200", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-gpu-double-onboard.sh", + "line": 381, + "text": "First-onboard sandbox inference: no response", + "polarity": "fail", + "normalized_id": "first.onboard.sandbox.inference.no.response", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-gpu-double-onboard.sh", + "line": 404, + "text": "Re-onboard completed (exit 0)", + "polarity": "pass", + "normalized_id": "re.onboard.completed.exit.0", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-gpu-double-onboard.sh", + "line": 406, + "text": "Re-onboard failed (exit $reonboard_exit)", + "polarity": "fail", + "normalized_id": "re.onboard.failed.exit.reonboard.exit", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-gpu-double-onboard.sh", + "line": 422, + "text": "Proxy token file exists after re-onboard", + "polarity": "pass", + "normalized_id": "proxy.token.file.exists.after.re.onboard", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-gpu-double-onboard.sh", + "line": 424, + "text": "Proxy token file missing after re-onboard", + "polarity": "fail", + "normalized_id": "proxy.token.file.missing.after.re.onboard", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-gpu-double-onboard.sh", + "line": 435, + "text": "Token file permissions preserved: 600", + "polarity": "pass", + "normalized_id": "token.file.permissions.preserved.600", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-gpu-double-onboard.sh", + "line": 437, + "text": "Token file permissions: expected 600, got $PERMS", + "polarity": "fail", + "normalized_id": "token.file.permissions.expected.600.got.perms", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-gpu-double-onboard.sh", + "line": 445, + "text": "Auth proxy running on :${PROXY_PORT} after re-onboard (HTTP $PROXY_LIVE_STATUS)", + "polarity": "pass", + "normalized_id": "auth.proxy.running.on.proxy.port.after.re.onboard.http.proxy.live.status", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-gpu-double-onboard.sh", + "line": 447, + "text": "Auth proxy not running after re-onboard", + "polarity": "fail", + "normalized_id": "auth.proxy.not.running.after.re.onboard", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-gpu-double-onboard.sh", + "line": 457, + "text": "Proxy accepts persisted token after re-onboard (200 — not 401)", + "polarity": "pass", + "normalized_id": "proxy.accepts.persisted.token.after.re.onboard.200.not.401", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-gpu-double-onboard.sh", + "line": 459, + "text": "PROXY TOKEN DIVERGENCE DETECTED (#2553 regression)", + "polarity": "fail", + "normalized_id": "proxy.token.divergence.detected.2553.regression", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-gpu-double-onboard.sh", + "line": 460, + "text": "Token on disk does not match running proxy (status: $TOKEN_AUTH_STATUS)", + "polarity": "fail", + "normalized_id": "token.on.disk.does.not.match.running.proxy.status.token.auth.status", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-gpu-double-onboard.sh", + "line": 468, + "text": "Proxy rejects unauthenticated POST after re-onboard (401)", + "polarity": "pass", + "normalized_id": "proxy.rejects.unauthenticated.post.after.re.onboard.401", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-gpu-double-onboard.sh", + "line": 470, + "text": "Proxy should reject unauthenticated POST, got $UNAUTH_STATUS", + "polarity": "fail", + "normalized_id": "proxy.should.reject.unauthenticated.post.got.unauth.status", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-gpu-double-onboard.sh", + "line": 478, + "text": "Proxy rejects wrong token after re-onboard (401)", + "polarity": "pass", + "normalized_id": "proxy.rejects.wrong.token.after.re.onboard.401", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-gpu-double-onboard.sh", + "line": 480, + "text": "Proxy should reject wrong token, got $WRONG_STATUS", + "polarity": "fail", + "normalized_id": "proxy.should.reject.wrong.token.got.wrong.status", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-gpu-double-onboard.sh", + "line": 506, + "text": "openshell sandbox ssh-config failed after re-onboard", + "polarity": "fail", + "normalized_id": "openshell.sandbox.ssh.config.failed.after.re.onboard", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-gpu-double-onboard.sh", + "line": 513, + "text": "Sandbox inference after re-onboard succeeded", + "polarity": "pass", + "normalized_id": "sandbox.inference.after.re.onboard.succeeded", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-gpu-double-onboard.sh", + "line": 518, + "text": "SANDBOX INFERENCE RETURNED 401 — token divergence (#2553 regression)", + "polarity": "fail", + "normalized_id": "sandbox.inference.returned.401.token.divergence.2553.regression", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-gpu-double-onboard.sh", + "line": 520, + "text": "Sandbox inference after re-onboard: expected PONG, got: ${sandbox_content:0:200}", + "polarity": "fail", + "normalized_id": "sandbox.inference.after.re.onboard.expected.pong.got.sandbox.content.0.200", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-gpu-double-onboard.sh", + "line": 524, + "text": "Sandbox inference after re-onboard: no response", + "polarity": "fail", + "normalized_id": "sandbox.inference.after.re.onboard.no.response", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-gpu-double-onboard.sh", + "line": 538, + "text": "Sandbox ${SANDBOX_NAME} still in registry after destroy", + "polarity": "fail", + "normalized_id": "sandbox.sandbox.name.still.in.registry.after.destroy", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-gpu-double-onboard.sh", + "line": 540, + "text": "Sandbox ${SANDBOX_NAME} removed from registry", + "polarity": "pass", + "normalized_id": "sandbox.sandbox.name.removed.from.registry", + "mapping_status": "retired" + }, + { + "script": "test/e2e/test-gpu-double-onboard.sh", + "line": 548, + "text": "Cleanup complete", + "polarity": "pass", + "normalized_id": "cleanup.complete", + "mapping_status": "deferred" + } + ] + }, + { + "script": "test/e2e/test-gpu-e2e.sh", + "assertions": [ + { + "script": "test/e2e/test-gpu-e2e.sh", + "line": 133, + "text": "Pre-cleanup complete", + "polarity": "pass", + "normalized_id": "pre.cleanup.complete", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-gpu-e2e.sh", + "line": 141, + "text": "Docker is running", + "polarity": "pass", + "normalized_id": "docker.is.running", + "mapping_status": "mapped" + }, + { + "script": "test/e2e/test-gpu-e2e.sh", + "line": 143, + "text": "Docker is not running — cannot continue", + "polarity": "fail", + "normalized_id": "docker.is.not.running.cannot.continue", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-gpu-e2e.sh", + "line": 149, + "text": "nvidia-smi works (GPU VRAM: ${VRAM_MB:-unknown} MB)", + "polarity": "pass", + "normalized_id": "nvidia.smi.works.gpu.vram.vram.mb.unknown.mb", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-gpu-e2e.sh", + "line": 151, + "text": "nvidia-smi failed — no NVIDIA GPU available", + "polarity": "fail", + "normalized_id": "nvidia.smi.failed.no.nvidia.gpu.available", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-gpu-e2e.sh", + "line": 156, + "text": "NEMOCLAW_NON_INTERACTIVE=1 is required", + "polarity": "fail", + "normalized_id": "nemoclaw.non.interactive.1.is.required", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-gpu-e2e.sh", + "line": 161, + "text": "NEMOCLAW_ACCEPT_THIRD_PARTY_SOFTWARE=1 is required for non-interactive install", + "polarity": "fail", + "normalized_id": "nemoclaw.accept.third.party.software.1.is.required.for.non.interactive.install", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-gpu-e2e.sh", + "line": 180, + "text": "Ollama already installed: $(ollama --version 2>/dev/null || echo unknown)", + "polarity": "pass", + "normalized_id": "ollama.already.installed.ollama.version.2.dev.null.echo.unknown", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-gpu-e2e.sh", + "line": 184, + "text": "Ollama installed: $(ollama --version 2>/dev/null || echo unknown)", + "polarity": "pass", + "normalized_id": "ollama.installed.ollama.version.2.dev.null.echo.unknown", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-gpu-e2e.sh", + "line": 186, + "text": "Ollama installation failed", + "polarity": "fail", + "normalized_id": "ollama.installation.failed", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-gpu-e2e.sh", + "line": 206, + "text": "Existing Ollama stopped — port 11434 is free for onboard", + "polarity": "pass", + "normalized_id": "existing.ollama.stopped.port.11434.is.free.for.onboard", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-gpu-e2e.sh", + "line": 216, + "text": "Could not cd to repo root: $REPO", + "polarity": "fail", + "normalized_id": "could.not.cd.to.repo.root.repo", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-gpu-e2e.sh", + "line": 243, + "text": "install.sh completed (exit 0)", + "polarity": "pass", + "normalized_id": "install.sh.completed.exit.0", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-gpu-e2e.sh", + "line": 245, + "text": "install.sh failed (exit $install_exit)", + "polarity": "fail", + "normalized_id": "install.sh.failed.exit.install.exit", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-gpu-e2e.sh", + "line": 252, + "text": "nemoclaw on PATH: $(command -v nemoclaw)", + "polarity": "pass", + "normalized_id": "nemoclaw.on.path.command.v.nemoclaw", + "mapping_status": "mapped" + }, + { + "script": "test/e2e/test-gpu-e2e.sh", + "line": 254, + "text": "nemoclaw not found on PATH after install", + "polarity": "fail", + "normalized_id": "nemoclaw.not.found.on.path.after.install", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-gpu-e2e.sh", + "line": 266, + "text": "nemoclaw list contains '${SANDBOX_NAME}'", + "polarity": "pass", + "normalized_id": "nemoclaw.list.contains.sandbox.name", + "mapping_status": "mapped" + }, + { + "script": "test/e2e/test-gpu-e2e.sh", + "line": 268, + "text": "nemoclaw list does not contain '${SANDBOX_NAME}'", + "polarity": "fail", + "normalized_id": "nemoclaw.list.does.not.contain.sandbox.name", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-gpu-e2e.sh", + "line": 271, + "text": "nemoclaw list failed: ${list_output:0:200}", + "polarity": "fail", + "normalized_id": "nemoclaw.list.failed.list.output.0.200", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-gpu-e2e.sh", + "line": 276, + "text": "nemoclaw ${SANDBOX_NAME} status exits 0", + "polarity": "pass", + "normalized_id": "nemoclaw.sandbox.name.status.exits.0", + "mapping_status": "mapped" + }, + { + "script": "test/e2e/test-gpu-e2e.sh", + "line": 278, + "text": "nemoclaw ${SANDBOX_NAME} status failed", + "polarity": "fail", + "normalized_id": "nemoclaw.sandbox.name.status.failed", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-gpu-e2e.sh", + "line": 284, + "text": "Sandbox GPU is enabled by default", + "polarity": "pass", + "normalized_id": "sandbox.gpu.is.enabled.by.default", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-gpu-e2e.sh", + "line": 286, + "text": "Sandbox GPU is not enabled in status output", + "polarity": "fail", + "normalized_id": "sandbox.gpu.is.not.enabled.in.status.output", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-gpu-e2e.sh", + "line": 289, + "text": "Could not read sandbox GPU status", + "polarity": "fail", + "normalized_id": "could.not.read.sandbox.gpu.status", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-gpu-e2e.sh", + "line": 294, + "text": "Sandbox nvidia-smi works", + "polarity": "pass", + "normalized_id": "sandbox.nvidia.smi.works", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-gpu-e2e.sh", + "line": 296, + "text": "Sandbox nvidia-smi failed", + "polarity": "fail", + "normalized_id": "sandbox.nvidia.smi.failed", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-gpu-e2e.sh", + "line": 302, + "text": "Sandbox /proc/self/task//comm write works", + "polarity": "pass", + "normalized_id": "sandbox.proc.self.task.tid.comm.write.works", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-gpu-e2e.sh", + "line": 304, + "text": "Sandbox /proc comm write failed", + "polarity": "fail", + "normalized_id": "sandbox.proc.comm.write.failed", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-gpu-e2e.sh", + "line": 308, + "text": "Sandbox cuInit(0) succeeds", + "polarity": "pass", + "normalized_id": "sandbox.cuinit.0.succeeds", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-gpu-e2e.sh", + "line": 310, + "text": "Sandbox cuInit(0) failed", + "polarity": "fail", + "normalized_id": "sandbox.cuinit.0.failed", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-gpu-e2e.sh", + "line": 316, + "text": "Inference provider is Ollama-based", + "polarity": "pass", + "normalized_id": "inference.provider.is.ollama.based", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-gpu-e2e.sh", + "line": 318, + "text": "Inference provider is not ollama — got: ${inf_check:0:200}", + "polarity": "fail", + "normalized_id": "inference.provider.is.not.ollama.got.inf.check.0.200", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-gpu-e2e.sh", + "line": 321, + "text": "openshell inference get failed: ${inf_check:0:200}", + "polarity": "fail", + "normalized_id": "openshell.inference.get.failed.inf.check.0.200", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-gpu-e2e.sh", + "line": 326, + "text": "Ollama running on 127.0.0.1:11434 (started by onboard)", + "polarity": "pass", + "normalized_id": "ollama.running.on.127.0.0.1.11434.started.by.onboard", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-gpu-e2e.sh", + "line": 328, + "text": "Ollama not running — onboard should have started it", + "polarity": "fail", + "normalized_id": "ollama.not.running.onboard.should.have.started.it", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-gpu-e2e.sh", + "line": 341, + "text": "Proxy token persisted at $TOKEN_FILE", + "polarity": "pass", + "normalized_id": "proxy.token.persisted.at.token.file", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-gpu-e2e.sh", + "line": 343, + "text": "Proxy token file missing — onboard did not persist token", + "polarity": "fail", + "normalized_id": "proxy.token.file.missing.onboard.did.not.persist.token", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-gpu-e2e.sh", + "line": 350, + "text": "Token file permissions: 600", + "polarity": "pass", + "normalized_id": "token.file.permissions.600", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-gpu-e2e.sh", + "line": 352, + "text": "Token file permissions: expected 600, got $PERMS", + "polarity": "fail", + "normalized_id": "token.file.permissions.expected.600.got.perms", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-gpu-e2e.sh", + "line": 362, + "text": "Auth proxy running on :${PROXY_PORT} (HTTP $PROXY_LIVE_STATUS)", + "polarity": "pass", + "normalized_id": "auth.proxy.running.on.proxy.port.http.proxy.live.status", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-gpu-e2e.sh", + "line": 364, + "text": "Auth proxy not running on :${PROXY_PORT} — onboard should have started it", + "polarity": "fail", + "normalized_id": "auth.proxy.not.running.on.proxy.port.onboard.should.have.started.it", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-gpu-e2e.sh", + "line": 371, + "text": "Auth proxy rejects unauthenticated POST (401)", + "polarity": "pass", + "normalized_id": "auth.proxy.rejects.unauthenticated.post.401", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-gpu-e2e.sh", + "line": 373, + "text": "Auth proxy should return 401 for unauthenticated POST, got $PROXY_STATUS", + "polarity": "fail", + "normalized_id": "auth.proxy.should.return.401.for.unauthenticated.post.got.proxy.status", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-gpu-e2e.sh", + "line": 385, + "text": "Auth proxy accepts correct token (status: $PROXY_STATUS)", + "polarity": "pass", + "normalized_id": "auth.proxy.accepts.correct.token.status.proxy.status", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-gpu-e2e.sh", + "line": 387, + "text": "Auth proxy rejected the persisted token", + "polarity": "fail", + "normalized_id": "auth.proxy.rejected.the.persisted.token", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-gpu-e2e.sh", + "line": 401, + "text": "Container reachable: host.openshell.internal:${PROXY_PORT} (HTTP $CONTAINER_REACH_STATUS)", + "polarity": "pass", + "normalized_id": "container.reachable.host.openshell.internal.proxy.port.http.container.reach.status", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-gpu-e2e.sh", + "line": 403, + "text": "Container cannot reach proxy at host.openshell.internal:${PROXY_PORT}", + "polarity": "fail", + "normalized_id": "container.cannot.reach.proxy.at.host.openshell.internal.proxy.port", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-gpu-e2e.sh", + "line": 420, + "text": "Proxy still alive after kill (HTTP $DEAD_STATUS)", + "polarity": "fail", + "normalized_id": "proxy.still.alive.after.kill.http.dead.status", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-gpu-e2e.sh", + "line": 435, + "text": "Proxy recovered from persisted token after kill (HTTP $RECOVERED_LIVE_STATUS)", + "polarity": "pass", + "normalized_id": "proxy.recovered.from.persisted.token.after.kill.http.recovered.live.status", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-gpu-e2e.sh", + "line": 437, + "text": "Proxy did not restart from persisted token", + "polarity": "fail", + "normalized_id": "proxy.did.not.restart.from.persisted.token", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-gpu-e2e.sh", + "line": 446, + "text": "Recovered proxy accepts persisted token (status: $RECOVER_STATUS)", + "polarity": "pass", + "normalized_id": "recovered.proxy.accepts.persisted.token.status.recover.status", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-gpu-e2e.sh", + "line": 448, + "text": "Recovered proxy rejected persisted token", + "polarity": "fail", + "normalized_id": "recovered.proxy.rejected.persisted.token", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-gpu-e2e.sh", + "line": 481, + "text": "No models found in Ollama", + "polarity": "fail", + "normalized_id": "no.models.found.in.ollama", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-gpu-e2e.sh", + "line": 499, + "text": "[LOCAL] Direct Ollama: model responded with PONG", + "polarity": "pass", + "normalized_id": "local.direct.ollama.model.responded.with.pong", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-gpu-e2e.sh", + "line": 501, + "text": "[LOCAL] Direct Ollama: expected PONG, got: ${direct_content:0:200}", + "polarity": "fail", + "normalized_id": "local.direct.ollama.expected.pong.got.direct.content.0.200", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-gpu-e2e.sh", + "line": 504, + "text": "[LOCAL] Direct Ollama: empty response", + "polarity": "fail", + "normalized_id": "local.direct.ollama.empty.response", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-gpu-e2e.sh", + "line": 526, + "text": "openshell sandbox ssh-config failed", + "polarity": "fail", + "normalized_id": "openshell.sandbox.ssh.config.failed", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-gpu-e2e.sh", + "line": 533, + "text": "[LOCAL] Sandbox inference: Ollama responded through sandbox", + "polarity": "pass", + "normalized_id": "local.sandbox.inference.ollama.responded.through.sandbox", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-gpu-e2e.sh", + "line": 536, + "text": "[LOCAL] Sandbox inference: expected PONG, got: ${sandbox_content:0:200}", + "polarity": "fail", + "normalized_id": "local.sandbox.inference.expected.pong.got.sandbox.content.0.200", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-gpu-e2e.sh", + "line": 539, + "text": "[LOCAL] Sandbox inference: no response from inference.local inside sandbox", + "polarity": "fail", + "normalized_id": "local.sandbox.inference.no.response.from.inference.local.inside.sandbox", + "mapping_status": "mapped" + }, + { + "script": "test/e2e/test-gpu-e2e.sh", + "line": 556, + "text": "Sandbox ${SANDBOX_NAME} still in registry after destroy", + "polarity": "fail", + "normalized_id": "sandbox.sandbox.name.still.in.registry.after.destroy", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-gpu-e2e.sh", + "line": 558, + "text": "Sandbox ${SANDBOX_NAME} removed from registry", + "polarity": "pass", + "normalized_id": "sandbox.sandbox.name.removed.from.registry", + "mapping_status": "retired" + }, + { + "script": "test/e2e/test-gpu-e2e.sh", + "line": 569, + "text": "uninstall.sh --delete-models completed", + "polarity": "pass", + "normalized_id": "uninstall.sh.delete.models.completed", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-gpu-e2e.sh", + "line": 571, + "text": "uninstall.sh failed", + "polarity": "fail", + "normalized_id": "uninstall.sh.failed", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-gpu-e2e.sh", + "line": 575, + "text": "$HOME/.nemoclaw directory still exists after uninstall", + "polarity": "fail", + "normalized_id": "home.nemoclaw.directory.still.exists.after.uninstall", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-gpu-e2e.sh", + "line": 577, + "text": "$HOME/.nemoclaw removed", + "polarity": "pass", + "normalized_id": "home.nemoclaw.removed", + "mapping_status": "retired" + }, + { + "script": "test/e2e/test-gpu-e2e.sh", + "line": 584, + "text": "Cleanup complete", + "polarity": "pass", + "normalized_id": "cleanup.complete", + "mapping_status": "deferred" + } + ] + }, + { + "script": "test/e2e/test-hermes-discord-e2e.sh", + "assertions": [ + { + "script": "test/e2e/test-hermes-discord-e2e.sh", + "line": 194, + "text": "Docker is running", + "polarity": "pass", + "normalized_id": "docker.is.running", + "mapping_status": "mapped" + }, + { + "script": "test/e2e/test-hermes-discord-e2e.sh", + "line": 196, + "text": "Docker is not running", + "polarity": "fail", + "normalized_id": "docker.is.not.running", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-hermes-discord-e2e.sh", + "line": 201, + "text": "NVIDIA_API_KEY is set (starts with nvapi-)", + "polarity": "pass", + "normalized_id": "nvidia.api.key.is.set.starts.with.nvapi", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-hermes-discord-e2e.sh", + "line": 203, + "text": "NVIDIA_API_KEY not set or invalid", + "polarity": "fail", + "normalized_id": "nvidia.api.key.not.set.or.invalid", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-hermes-discord-e2e.sh", + "line": 208, + "text": "NEMOCLAW_NON_INTERACTIVE=1", + "polarity": "pass", + "normalized_id": "nemoclaw.non.interactive.1", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-hermes-discord-e2e.sh", + "line": 210, + "text": "NEMOCLAW_NON_INTERACTIVE=1 is required", + "polarity": "fail", + "normalized_id": "nemoclaw.non.interactive.1.is.required", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-hermes-discord-e2e.sh", + "line": 215, + "text": "NEMOCLAW_ACCEPT_THIRD_PARTY_SOFTWARE=1", + "polarity": "pass", + "normalized_id": "nemoclaw.accept.third.party.software.1", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-hermes-discord-e2e.sh", + "line": 217, + "text": "NEMOCLAW_ACCEPT_THIRD_PARTY_SOFTWARE=1 is required", + "polarity": "fail", + "normalized_id": "nemoclaw.accept.third.party.software.1.is.required", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-hermes-discord-e2e.sh", + "line": 231, + "text": "Could not cd to repo root: $REPO", + "polarity": "fail", + "normalized_id": "could.not.cd.to.repo.root.repo", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-hermes-discord-e2e.sh", + "line": 243, + "text": "Pre-cleanup complete", + "polarity": "pass", + "normalized_id": "pre.cleanup.complete", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-hermes-discord-e2e.sh", + "line": 270, + "text": "install.sh completed (exit 0)", + "polarity": "pass", + "normalized_id": "install.sh.completed.exit.0", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-hermes-discord-e2e.sh", + "line": 272, + "text": "install.sh failed (exit $install_exit)", + "polarity": "fail", + "normalized_id": "install.sh.failed.exit.install.exit", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-hermes-discord-e2e.sh", + "line": 280, + "text": "nemoclaw installed at $(command -v nemoclaw)", + "polarity": "pass", + "normalized_id": "nemoclaw.installed.at.command.v.nemoclaw", + "mapping_status": "mapped" + }, + { + "script": "test/e2e/test-hermes-discord-e2e.sh", + "line": 282, + "text": "nemoclaw not found on PATH after install", + "polarity": "fail", + "normalized_id": "nemoclaw.not.found.on.path.after.install", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-hermes-discord-e2e.sh", + "line": 287, + "text": "openshell installed ($(openshell --version 2>&1 || echo unknown))", + "polarity": "pass", + "normalized_id": "openshell.installed.openshell.version.2.1.echo.unknown", + "mapping_status": "mapped" + }, + { + "script": "test/e2e/test-hermes-discord-e2e.sh", + "line": 289, + "text": "openshell not found on PATH after install", + "polarity": "fail", + "normalized_id": "openshell.not.found.on.path.after.install", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-hermes-discord-e2e.sh", + "line": 297, + "text": "nemoclaw list contains '${SANDBOX_NAME}'", + "polarity": "pass", + "normalized_id": "nemoclaw.list.contains.sandbox.name", + "mapping_status": "mapped" + }, + { + "script": "test/e2e/test-hermes-discord-e2e.sh", + "line": 299, + "text": "nemoclaw list does not contain '${SANDBOX_NAME}'", + "polarity": "fail", + "normalized_id": "nemoclaw.list.does.not.contain.sandbox.name", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-hermes-discord-e2e.sh", + "line": 302, + "text": "nemoclaw list failed: ${list_output:0:200}", + "polarity": "fail", + "normalized_id": "nemoclaw.list.failed.list.output.0.200", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-hermes-discord-e2e.sh", + "line": 306, + "text": "Discord provider '${SANDBOX_NAME}-discord-bridge' exists in gateway", + "polarity": "pass", + "normalized_id": "discord.provider.sandbox.name.discord.bridge.exists.in.gateway", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-hermes-discord-e2e.sh", + "line": 308, + "text": "Discord provider '${SANDBOX_NAME}-discord-bridge' not found in gateway", + "polarity": "fail", + "normalized_id": "discord.provider.sandbox.name.discord.bridge.not.found.in.gateway", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-hermes-discord-e2e.sh", + "line": 326, + "text": "Hermes health probe returned ok with Discord enabled", + "polarity": "pass", + "normalized_id": "hermes.health.probe.returned.ok.with.discord.enabled", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-hermes-discord-e2e.sh", + "line": 328, + "text": "Hermes health probe did not return ok after 15 attempts", + "polarity": "fail", + "normalized_id": "hermes.health.probe.did.not.return.ok.after.15.attempts", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-hermes-discord-e2e.sh", + "line": 382, + "text": "config.yaml uses top-level discord and no platforms.discord", + "polarity": "pass", + "normalized_id": "config.yaml.uses.top.level.discord.and.no.platforms.discord", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-hermes-discord-e2e.sh", + "line": 384, + "text": "config.yaml schema check failed: ${config_probe:0:400}", + "polarity": "fail", + "normalized_id": "config.yaml.schema.check.failed.config.probe.0.400", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-hermes-discord-e2e.sh", + "line": 411, + "text": ".hermes/.env contains Discord placeholder and allowed users", + "polarity": "pass", + "normalized_id": "hermes.env.contains.discord.placeholder.and.allowed.users", + "mapping_status": "retired" + }, + { + "script": "test/e2e/test-hermes-discord-e2e.sh", + "line": 413, + "text": ".hermes/.env check failed: ${env_probe:0:400}", + "polarity": "fail", + "normalized_id": "hermes.env.check.failed.env.probe.0.400", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-hermes-discord-e2e.sh", + "line": 419, + "text": "Hermetic fake Discord Gateway started on host port ${FAKE_DISCORD_GATEWAY_PORT}", + "polarity": "pass", + "normalized_id": "hermetic.fake.discord.gateway.started.on.host.port.fake.discord.gateway.port", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-hermes-discord-e2e.sh", + "line": 421, + "text": "Failed to start hermetic fake Discord Gateway", + "polarity": "fail", + "normalized_id": "failed.to.start.hermetic.fake.discord.gateway", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-hermes-discord-e2e.sh", + "line": 426, + "text": "Applied native WebSocket policy with credential rewrite for Hermes fake Discord Gateway", + "polarity": "pass", + "normalized_id": "applied.native.websocket.policy.with.credential.rewrite.for.hermes.fake.discord.gateway", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-hermes-discord-e2e.sh", + "line": 428, + "text": "Failed to apply Hermes fake Discord Gateway policy: $(tail -20 /tmp/nemoclaw-hermes-fake-discord-policy.log 2>/dev/null | tr '\\n' ' ' | cut -c1-300)", + "polarity": "fail", + "normalized_id": "failed.to.apply.hermes.fake.discord.gateway.policy.tail.20.tmp.nemoclaw.hermes.fake.discord.policy.log.2.dev.null.tr.n.cut.c1.300", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-hermes-discord-e2e.sh", + "line": 441, + "text": "Hermes Python Discord Gateway path reaches READY through native OpenShell WebSocket policy", + "polarity": "pass", + "normalized_id": "hermes.python.discord.gateway.path.reaches.ready.through.native.openshell.websocket.policy", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-hermes-discord-e2e.sh", + "line": 443, + "text": "Hermes native Gateway probe could not import discord.py: ${native_gateway_protocol:0:300}", + "polarity": "fail", + "normalized_id": "hermes.native.gateway.probe.could.not.import.discord.py.native.gateway.protocol.0.300", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-hermes-discord-e2e.sh", + "line": 445, + "text": "Hermes native Gateway protocol probe failed: ${native_gateway_protocol:0:300}", + "polarity": "fail", + "normalized_id": "hermes.native.gateway.protocol.probe.failed.native.gateway.protocol.0.300", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-hermes-discord-e2e.sh", + "line": 451, + "text": "Hermes fake Gateway received host-side Discord token while sandbox sent only the placeholder", + "polarity": "pass", + "normalized_id": "hermes.fake.gateway.received.host.side.discord.token.while.sandbox.sent.only.the.placeholder", + "mapping_status": "retired" + }, + { + "script": "test/e2e/test-hermes-discord-e2e.sh", + "line": 456, + "text": "Hermes fake Gateway did not prove WebSocket placeholder rewrite", + "polarity": "fail", + "normalized_id": "hermes.fake.gateway.did.not.prove.websocket.placeholder.rewrite", + "mapping_status": "retired" + }, + { + "script": "test/e2e/test-hermes-discord-e2e.sh", + "line": 461, + "text": "Raw Discord token absent from Hermes config.yaml and .env", + "polarity": "pass", + "normalized_id": "raw.discord.token.absent.from.hermes.config.yaml.and.env", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-hermes-discord-e2e.sh", + "line": 463, + "text": "Raw Discord token found in Hermes config files", + "polarity": "fail", + "normalized_id": "raw.discord.token.found.in.hermes.config.files", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-hermes-discord-e2e.sh", + "line": 472, + "text": "Raw Discord token found in sandbox environment", + "polarity": "fail", + "normalized_id": "raw.discord.token.found.in.sandbox.environment", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-hermes-discord-e2e.sh", + "line": 474, + "text": "Sandbox environment still contains DISCORD_PROXY bridge setting", + "polarity": "fail", + "normalized_id": "sandbox.environment.still.contains.discord.proxy.bridge.setting", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-hermes-discord-e2e.sh", + "line": 476, + "text": "Raw Discord token absent from sandbox environment; no DISCORD_PROXY bridge setting", + "polarity": "pass", + "normalized_id": "raw.discord.token.absent.from.sandbox.environment.no.discord.proxy.bridge.setting", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-hermes-discord-e2e.sh", + "line": 483, + "text": "Raw Discord token found in sandbox process list", + "polarity": "fail", + "normalized_id": "raw.discord.token.found.in.sandbox.process.list", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-hermes-discord-e2e.sh", + "line": 485, + "text": "Raw Discord token absent from sandbox process list", + "polarity": "pass", + "normalized_id": "raw.discord.token.absent.from.sandbox.process.list", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-hermes-discord-e2e.sh", + "line": 490, + "text": "Raw Discord token found on sandbox filesystem: ${sandbox_fs_hits:0:200}", + "polarity": "fail", + "normalized_id": "raw.discord.token.found.on.sandbox.filesystem.sandbox.fs.hits.0.200", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-hermes-discord-e2e.sh", + "line": 492, + "text": "Raw Discord token absent from sandbox filesystem", + "polarity": "pass", + "normalized_id": "raw.discord.token.absent.from.sandbox.filesystem", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-hermes-discord-e2e.sh", + "line": 542, + "text": "Discord users/@me returned 200 with configured token", + "polarity": "pass", + "normalized_id": "discord.users.me.returned.200.with.configured.token", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-hermes-discord-e2e.sh", + "line": 544, + "text": "Discord users/@me returned 401 - REST path reached Discord; this is not gateway IDENTIFY auth proof", + "polarity": "pass", + "normalized_id": "discord.users.me.returned.401.rest.path.reached.discord.this.is.not.gateway.identify.auth.proof", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-hermes-discord-e2e.sh", + "line": 548, + "text": "Discord API call failed: ${dc_error:0:200}", + "polarity": "fail", + "normalized_id": "discord.api.call.failed.dc.error.0.200", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-hermes-discord-e2e.sh", + "line": 550, + "text": "Unexpected Discord API response: ${dc_api:0:300}", + "polarity": "fail", + "normalized_id": "unexpected.discord.api.response.dc.api.0.300", + "mapping_status": "retired" + }, + { + "script": "test/e2e/test-hermes-discord-e2e.sh", + "line": 577, + "text": "Hermes Discord proof used native WebSocket policy with no local facade, decode proxy, or DISCORD_PROXY residue", + "polarity": "pass", + "normalized_id": "hermes.discord.proof.used.native.websocket.policy.with.no.local.facade.decode.proxy.or.discord.proxy.residue", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-hermes-discord-e2e.sh", + "line": 579, + "text": "Local Discord bridge residue found after native Gateway proof: ${facade_residue:0:300}", + "polarity": "fail", + "normalized_id": "local.discord.bridge.residue.found.after.native.gateway.proof.facade.residue.0.300", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-hermes-discord-e2e.sh", + "line": 592, + "text": "Sandbox ${SANDBOX_NAME} still in registry after destroy", + "polarity": "fail", + "normalized_id": "sandbox.sandbox.name.still.in.registry.after.destroy", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-hermes-discord-e2e.sh", + "line": 594, + "text": "Sandbox ${SANDBOX_NAME} removed", + "polarity": "pass", + "normalized_id": "sandbox.sandbox.name.removed", + "mapping_status": "retired" + } + ] + }, + { + "script": "test/e2e/test-hermes-e2e.sh", + "assertions": [ + { + "script": "test/e2e/test-hermes-e2e.sh", + "line": 140, + "text": "Pre-cleanup complete", + "polarity": "pass", + "normalized_id": "pre.cleanup.complete", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-hermes-e2e.sh", + "line": 148, + "text": "Docker is running", + "polarity": "pass", + "normalized_id": "docker.is.running", + "mapping_status": "mapped" + }, + { + "script": "test/e2e/test-hermes-e2e.sh", + "line": 150, + "text": "Docker is not running — cannot continue", + "polarity": "fail", + "normalized_id": "docker.is.not.running.cannot.continue", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-hermes-e2e.sh", + "line": 155, + "text": "NVIDIA_API_KEY is set (starts with nvapi-)", + "polarity": "pass", + "normalized_id": "nvidia.api.key.is.set.starts.with.nvapi", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-hermes-e2e.sh", + "line": 157, + "text": "NVIDIA_API_KEY not set or invalid — required for live inference", + "polarity": "fail", + "normalized_id": "nvidia.api.key.not.set.or.invalid.required.for.live.inference", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-hermes-e2e.sh", + "line": 162, + "text": "Network access to integrate.api.nvidia.com", + "polarity": "pass", + "normalized_id": "network.access.to.integrate.api.nvidia.com", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-hermes-e2e.sh", + "line": 164, + "text": "Cannot reach integrate.api.nvidia.com", + "polarity": "fail", + "normalized_id": "cannot.reach.integrate.api.nvidia.com", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-hermes-e2e.sh", + "line": 169, + "text": "NEMOCLAW_NON_INTERACTIVE=1 is required", + "polarity": "fail", + "normalized_id": "nemoclaw.non.interactive.1.is.required", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-hermes-e2e.sh", + "line": 174, + "text": "NEMOCLAW_ACCEPT_THIRD_PARTY_SOFTWARE=1 is required for non-interactive install", + "polarity": "fail", + "normalized_id": "nemoclaw.accept.third.party.software.1.is.required.for.non.interactive.install", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-hermes-e2e.sh", + "line": 180, + "text": "agents/hermes/ directory and manifest.yaml exist", + "polarity": "pass", + "normalized_id": "agents.hermes.directory.and.manifest.yaml.exist", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-hermes-e2e.sh", + "line": 182, + "text": "agents/hermes/ not found — is the hermes-agent-support branch checked out?", + "polarity": "fail", + "normalized_id": "agents.hermes.not.found.is.the.hermes.agent.support.branch.checked.out", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-hermes-e2e.sh", + "line": 194, + "text": "Could not cd to repo root: $REPO", + "polarity": "fail", + "normalized_id": "could.not.cd.to.repo.root.repo", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-hermes-e2e.sh", + "line": 232, + "text": "install.sh completed (exit 0)", + "polarity": "pass", + "normalized_id": "install.sh.completed.exit.0", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-hermes-e2e.sh", + "line": 234, + "text": "install.sh failed (exit $install_exit)", + "polarity": "fail", + "normalized_id": "install.sh.failed.exit.install.exit", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-hermes-e2e.sh", + "line": 241, + "text": "nemoclaw installed at $(command -v nemoclaw)", + "polarity": "pass", + "normalized_id": "nemoclaw.installed.at.command.v.nemoclaw", + "mapping_status": "mapped" + }, + { + "script": "test/e2e/test-hermes-e2e.sh", + "line": 243, + "text": "nemoclaw not found on PATH after install", + "polarity": "fail", + "normalized_id": "nemoclaw.not.found.on.path.after.install", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-hermes-e2e.sh", + "line": 249, + "text": "openshell installed ($(openshell --version 2>&1 || echo unknown))", + "polarity": "pass", + "normalized_id": "openshell.installed.openshell.version.2.1.echo.unknown", + "mapping_status": "mapped" + }, + { + "script": "test/e2e/test-hermes-e2e.sh", + "line": 251, + "text": "openshell not found on PATH after install", + "polarity": "fail", + "normalized_id": "openshell.not.found.on.path.after.install", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-hermes-e2e.sh", + "line": 256, + "text": "nemoclaw --help exits 0", + "polarity": "pass", + "normalized_id": "nemoclaw.help.exits.0", + "mapping_status": "mapped" + }, + { + "script": "test/e2e/test-hermes-e2e.sh", + "line": 258, + "text": "nemoclaw --help failed", + "polarity": "fail", + "normalized_id": "nemoclaw.help.failed", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-hermes-e2e.sh", + "line": 269, + "text": "nemoclaw list contains '${SANDBOX_NAME}'", + "polarity": "pass", + "normalized_id": "nemoclaw.list.contains.sandbox.name", + "mapping_status": "mapped" + }, + { + "script": "test/e2e/test-hermes-e2e.sh", + "line": 271, + "text": "nemoclaw list does not contain '${SANDBOX_NAME}'", + "polarity": "fail", + "normalized_id": "nemoclaw.list.does.not.contain.sandbox.name", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-hermes-e2e.sh", + "line": 274, + "text": "nemoclaw list failed: ${list_output:0:200}", + "polarity": "fail", + "normalized_id": "nemoclaw.list.failed.list.output.0.200", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-hermes-e2e.sh", + "line": 279, + "text": "nemoclaw ${SANDBOX_NAME} status exits 0", + "polarity": "pass", + "normalized_id": "nemoclaw.sandbox.name.status.exits.0", + "mapping_status": "mapped" + }, + { + "script": "test/e2e/test-hermes-e2e.sh", + "line": 281, + "text": "nemoclaw ${SANDBOX_NAME} status failed: ${status_output:0:200}", + "polarity": "fail", + "normalized_id": "nemoclaw.sandbox.name.status.failed.status.output.0.200", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-hermes-e2e.sh", + "line": 288, + "text": "Onboard session records agent=hermes", + "polarity": "pass", + "normalized_id": "onboard.session.records.agent.hermes", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-hermes-e2e.sh", + "line": 290, + "text": "Onboard session does not contain agent=hermes", + "polarity": "fail", + "normalized_id": "onboard.session.does.not.contain.agent.hermes", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-hermes-e2e.sh", + "line": 294, + "text": "Session file not found: $session_file", + "polarity": "fail", + "normalized_id": "session.file.not.found.session.file", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-hermes-e2e.sh", + "line": 300, + "text": "Inference configured via onboard", + "polarity": "pass", + "normalized_id": "inference.configured.via.onboard", + "mapping_status": "mapped" + }, + { + "script": "test/e2e/test-hermes-e2e.sh", + "line": 302, + "text": "Inference not configured — onboard did not set up nvidia-prod provider", + "polarity": "fail", + "normalized_id": "inference.not.configured.onboard.did.not.set.up.nvidia.prod.provider", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-hermes-e2e.sh", + "line": 305, + "text": "openshell inference get failed: ${inf_check:0:200}", + "polarity": "fail", + "normalized_id": "openshell.inference.get.failed.inf.check.0.200", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-hermes-e2e.sh", + "line": 311, + "text": "Policy applied to sandbox", + "polarity": "pass", + "normalized_id": "policy.applied.to.sandbox", + "mapping_status": "mapped" + }, + { + "script": "test/e2e/test-hermes-e2e.sh", + "line": 313, + "text": "No network policy found on sandbox", + "polarity": "fail", + "normalized_id": "no.network.policy.found.on.sandbox", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-hermes-e2e.sh", + "line": 316, + "text": "openshell policy get failed: ${policy_output:0:200}", + "polarity": "fail", + "normalized_id": "openshell.policy.get.failed.policy.output.0.200", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-hermes-e2e.sh", + "line": 354, + "text": "Hermes health probe returned ok", + "polarity": "pass", + "normalized_id": "hermes.health.probe.returned.ok", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-hermes-e2e.sh", + "line": 357, + "text": "Hermes health probe did not return ok after 15 attempts", + "polarity": "fail", + "normalized_id": "hermes.health.probe.did.not.return.ok.after.15.attempts", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-hermes-e2e.sh", + "line": 361, + "text": "Could not get SSH config for sandbox ${SANDBOX_NAME}", + "polarity": "fail", + "normalized_id": "could.not.get.ssh.config.for.sandbox.sandbox.name", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-hermes-e2e.sh", + "line": 376, + "text": "Hermes binary not found in sandbox", + "polarity": "fail", + "normalized_id": "hermes.binary.not.found.in.sandbox", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-hermes-e2e.sh", + "line": 378, + "text": "Hermes binary found in sandbox: ${hermes_version:0:100}", + "polarity": "pass", + "normalized_id": "hermes.binary.found.in.sandbox.hermes.version.0.100", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-hermes-e2e.sh", + "line": 393, + "text": "Hermes config.yaml exists at /sandbox/.hermes/config.yaml", + "polarity": "pass", + "normalized_id": "hermes.config.yaml.exists.at.sandbox.hermes.config.yaml", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-hermes-e2e.sh", + "line": 395, + "text": "Hermes config.yaml not found at /sandbox/.hermes/config.yaml", + "polarity": "fail", + "normalized_id": "hermes.config.yaml.not.found.at.sandbox.hermes.config.yaml", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-hermes-e2e.sh", + "line": 409, + "text": "Hermes config directory is writable (mutable default)", + "polarity": "pass", + "normalized_id": "hermes.config.directory.is.writable.mutable.default", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-hermes-e2e.sh", + "line": 411, + "text": "Hermes config directory is read-only — should be writable by default", + "polarity": "fail", + "normalized_id": "hermes.config.directory.is.read.only.should.be.writable.by.default", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-hermes-e2e.sh", + "line": 427, + "text": "Hermes config/state directory exists at /sandbox/.hermes", + "polarity": "pass", + "normalized_id": "hermes.config.state.directory.exists.at.sandbox.hermes", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-hermes-e2e.sh", + "line": 429, + "text": "Hermes config/state directory not found at /sandbox/.hermes", + "polarity": "fail", + "normalized_id": "hermes.config.state.directory.not.found.at.sandbox.hermes", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-hermes-e2e.sh", + "line": 454, + "text": "[LIVE] Direct API: model responded with PONG", + "polarity": "pass", + "normalized_id": "live.direct.api.model.responded.with.pong", + "mapping_status": "mapped" + }, + { + "script": "test/e2e/test-hermes-e2e.sh", + "line": 456, + "text": "[LIVE] Direct API: expected PONG, got: ${api_content:0:200}", + "polarity": "fail", + "normalized_id": "live.direct.api.expected.pong.got.api.content.0.200", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-hermes-e2e.sh", + "line": 459, + "text": "[LIVE] Direct API: empty response from curl", + "polarity": "fail", + "normalized_id": "live.direct.api.empty.response.from.curl", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-hermes-e2e.sh", + "line": 492, + "text": "[ROUTING] inference.local: OpenShell routed curl to NVIDIA Endpoints and returned PONG", + "polarity": "pass", + "normalized_id": "routing.inference.local.openshell.routed.curl.to.nvidia.endpoints.and.returned.pong", + "mapping_status": "mapped" + }, + { + "script": "test/e2e/test-hermes-e2e.sh", + "line": 495, + "text": "[ROUTING] inference.local: expected PONG, got: ${sandbox_content:0:200}", + "polarity": "fail", + "normalized_id": "routing.inference.local.expected.pong.got.sandbox.content.0.200", + "mapping_status": "mapped" + }, + { + "script": "test/e2e/test-hermes-e2e.sh", + "line": 498, + "text": "[ROUTING] inference.local: no response from inference.local inside Hermes sandbox", + "polarity": "fail", + "normalized_id": "routing.inference.local.no.response.from.inference.local.inside.hermes.sandbox", + "mapping_status": "mapped" + }, + { + "script": "test/e2e/test-hermes-e2e.sh", + "line": 510, + "text": "nemoclaw logs: produced output ($(echo ", + "polarity": "pass", + "normalized_id": "nemoclaw.logs.produced.output.echo", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-hermes-e2e.sh", + "line": 512, + "text": "nemoclaw logs: no output", + "polarity": "fail", + "normalized_id": "nemoclaw.logs.no.output", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-hermes-e2e.sh", + "line": 535, + "text": "OpenClaw agent manifest loads correctly", + "polarity": "pass", + "normalized_id": "openclaw.agent.manifest.loads.correctly", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-hermes-e2e.sh", + "line": 537, + "text": "OpenClaw agent manifest failed to load", + "polarity": "fail", + "normalized_id": "openclaw.agent.manifest.failed.to.load", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-hermes-e2e.sh", + "line": 542, + "text": "Hermes agent manifest loads correctly", + "polarity": "pass", + "normalized_id": "hermes.agent.manifest.loads.correctly", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-hermes-e2e.sh", + "line": 544, + "text": "Hermes agent manifest failed to load", + "polarity": "fail", + "normalized_id": "hermes.agent.manifest.failed.to.load", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-hermes-e2e.sh", + "line": 549, + "text": "Both agents listed by listAgents()", + "polarity": "pass", + "normalized_id": "both.agents.listed.by.listagents", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-hermes-e2e.sh", + "line": 551, + "text": "listAgents() did not return both openclaw and hermes", + "polarity": "fail", + "normalized_id": "listagents.did.not.return.both.openclaw.and.hermes", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-hermes-e2e.sh", + "line": 568, + "text": "Sandbox ${SANDBOX_NAME} still in registry after destroy", + "polarity": "fail", + "normalized_id": "sandbox.sandbox.name.still.in.registry.after.destroy", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-hermes-e2e.sh", + "line": 570, + "text": "Sandbox ${SANDBOX_NAME} removed", + "polarity": "pass", + "normalized_id": "sandbox.sandbox.name.removed", + "mapping_status": "retired" + } + ] + }, + { + "script": "test/e2e/test-hermes-inference-switch.sh", + "assertions": [ + { + "script": "test/e2e/test-hermes-inference-switch.sh", + "line": 84, + "text": "OpenShell inference get failed: ${output:0:240}", + "polarity": "fail", + "normalized_id": "openshell.inference.get.failed.output.0.240", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-hermes-inference-switch.sh", + "line": 91, + "text": "OpenShell route points at ${SWITCH_PROVIDER} / ${SWITCH_MODEL}", + "polarity": "pass", + "normalized_id": "openshell.route.points.at.switch.provider.switch.model", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-hermes-inference-switch.sh", + "line": 93, + "text": "OpenShell route did not switch to ${SWITCH_PROVIDER} / ${SWITCH_MODEL}: ${plain_output:0:400}", + "polarity": "fail", + "normalized_id": "openshell.route.did.not.switch.to.switch.provider.switch.model.plain.output.0.400", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-hermes-inference-switch.sh", + "line": 155, + "text": "Registry/session were not updated for switch: ${probe:0:400}", + "polarity": "fail", + "normalized_id": "registry.session.were.not.updated.for.switch.probe.0.400", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-hermes-inference-switch.sh", + "line": 158, + "text": "Registry and onboard session record the switched Hermes provider/model", + "polarity": "pass", + "normalized_id": "registry.and.onboard.session.record.the.switched.hermes.provider.model", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-hermes-inference-switch.sh", + "line": 167, + "text": "Hermes health endpoint returns ok", + "polarity": "pass", + "normalized_id": "hermes.health.endpoint.returns.ok", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-hermes-inference-switch.sh", + "line": 172, + "text": "Hermes health endpoint did not return ok: ${health_response:0:240}", + "polarity": "fail", + "normalized_id": "hermes.health.endpoint.did.not.return.ok.health.response.0.240", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-hermes-inference-switch.sh", + "line": 178, + "text": "Could not read /sandbox/.hermes/config.yaml: ${config:0:240}", + "polarity": "fail", + "normalized_id": "could.not.read.sandbox.hermes.config.yaml.config.0.240", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-hermes-inference-switch.sh", + "line": 226, + "text": "Hermes config.yaml was not patched correctly: ${probe:0:400}", + "polarity": "fail", + "normalized_id": "hermes.config.yaml.was.not.patched.correctly.probe.0.400", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-hermes-inference-switch.sh", + "line": 229, + "text": "Hermes config.yaml model block uses ${SWITCH_MODEL} via inference.local", + "polarity": "pass", + "normalized_id": "hermes.config.yaml.model.block.uses.switch.model.via.inference.local", + "mapping_status": "mapped" + }, + { + "script": "test/e2e/test-hermes-inference-switch.sh", + "line": 237, + "text": "Hermes strict config hash matches config.yaml and .env", + "polarity": "pass", + "normalized_id": "hermes.strict.config.hash.matches.config.yaml.and.env", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-hermes-inference-switch.sh", + "line": 239, + "text": "Hermes strict config hash check failed: ${strict_check:0:240}", + "polarity": "fail", + "normalized_id": "hermes.strict.config.hash.check.failed.strict.check.0.240", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-hermes-inference-switch.sh", + "line": 245, + "text": "Hermes compatibility config hash matches config.yaml and .env", + "polarity": "pass", + "normalized_id": "hermes.compatibility.config.hash.matches.config.yaml.and.env", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-hermes-inference-switch.sh", + "line": 247, + "text": "Hermes compatibility config hash check failed: ${compat_check:0:240}", + "polarity": "fail", + "normalized_id": "hermes.compatibility.config.hash.check.failed.compat.check.0.240", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-hermes-inference-switch.sh", + "line": 264, + "text": "Hermes strict hash is root-owned and not writable", + "polarity": "pass", + "normalized_id": "hermes.strict.hash.is.root.owned.and.not.writable", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-hermes-inference-switch.sh", + "line": 266, + "text": "Hermes strict hash permissions are wrong: ${perms_probe:0:120}", + "polarity": "fail", + "normalized_id": "hermes.strict.hash.permissions.are.wrong.perms.probe.0.120", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-hermes-inference-switch.sh", + "line": 274, + "text": "Hermes .env was not rewritten by inference set", + "polarity": "pass", + "normalized_id": "hermes.env.was.not.rewritten.by.inference.set", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-hermes-inference-switch.sh", + "line": 276, + "text": "Hermes .env hash changed during inference set (${ENV_HASH_BEFORE:-missing} -> ${after:-missing})", + "polarity": "fail", + "normalized_id": "hermes.env.hash.changed.during.inference.set.env.hash.before.missing.after.missing", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-hermes-inference-switch.sh", + "line": 305, + "text": "Hermes sandbox inference.local returned PONG with ${SWITCH_MODEL}", + "polarity": "pass", + "normalized_id": "hermes.sandbox.inference.local.returned.pong.with.switch.model", + "mapping_status": "mapped" + }, + { + "script": "test/e2e/test-hermes-inference-switch.sh", + "line": 317, + "text": "Hermes sandbox inference.local did not work after switch: ${last_fail}", + "polarity": "fail", + "normalized_id": "hermes.sandbox.inference.local.did.not.work.after.switch.last.fail", + "mapping_status": "mapped" + }, + { + "script": "test/e2e/test-hermes-inference-switch.sh", + "line": 343, + "text": "Hermes API chat works after inference switch", + "polarity": "pass", + "normalized_id": "hermes.api.chat.works.after.inference.switch", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-hermes-inference-switch.sh", + "line": 355, + "text": "Hermes API chat did not work after switch: ${last_fail}", + "polarity": "fail", + "normalized_id": "hermes.api.chat.did.not.work.after.switch.last.fail", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-hermes-inference-switch.sh", + "line": 392, + "text": "Pre-cleanup complete", + "polarity": "pass", + "normalized_id": "pre.cleanup.complete", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-hermes-inference-switch.sh", + "line": 396, + "text": "Docker is running", + "polarity": "pass", + "normalized_id": "docker.is.running", + "mapping_status": "mapped" + }, + { + "script": "test/e2e/test-hermes-inference-switch.sh", + "line": 398, + "text": "Docker is not running", + "polarity": "fail", + "normalized_id": "docker.is.not.running", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-hermes-inference-switch.sh", + "line": 403, + "text": "NVIDIA_API_KEY is set", + "polarity": "pass", + "normalized_id": "nvidia.api.key.is.set", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-hermes-inference-switch.sh", + "line": 405, + "text": "NVIDIA_API_KEY not set or invalid", + "polarity": "fail", + "normalized_id": "nvidia.api.key.not.set.or.invalid", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-hermes-inference-switch.sh", + "line": 410, + "text": "NEMOCLAW_NON_INTERACTIVE=1", + "polarity": "pass", + "normalized_id": "nemoclaw.non.interactive.1", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-hermes-inference-switch.sh", + "line": 412, + "text": "NEMOCLAW_NON_INTERACTIVE=1 is required", + "polarity": "fail", + "normalized_id": "nemoclaw.non.interactive.1.is.required", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-hermes-inference-switch.sh", + "line": 417, + "text": "Third-party software acceptance is set", + "polarity": "pass", + "normalized_id": "third.party.software.acceptance.is.set", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-hermes-inference-switch.sh", + "line": 419, + "text": "NEMOCLAW_ACCEPT_THIRD_PARTY_SOFTWARE=1 is required", + "polarity": "fail", + "normalized_id": "nemoclaw.accept.third.party.software.1.is.required", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-hermes-inference-switch.sh", + "line": 425, + "text": "Could not cd to repo root: $REPO", + "polarity": "fail", + "normalized_id": "could.not.cd.to.repo.root.repo", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-hermes-inference-switch.sh", + "line": 449, + "text": "install.sh completed", + "polarity": "pass", + "normalized_id": "install.sh.completed", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-hermes-inference-switch.sh", + "line": 451, + "text": "install.sh failed (exit ${install_exit})", + "polarity": "fail", + "normalized_id": "install.sh.failed.exit.install.exit", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-hermes-inference-switch.sh", + "line": 457, + "text": "nemohermes not found on PATH", + "polarity": "fail", + "normalized_id": "nemohermes.not.found.on.path", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-hermes-inference-switch.sh", + "line": 461, + "text": "openshell not found on PATH", + "polarity": "fail", + "normalized_id": "openshell.not.found.on.path", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-hermes-inference-switch.sh", + "line": 464, + "text": "nemohermes and openshell are on PATH", + "polarity": "pass", + "normalized_id": "nemohermes.and.openshell.are.on.path", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-hermes-inference-switch.sh", + "line": 475, + "text": "nemohermes inference set completed without --sandbox", + "polarity": "pass", + "normalized_id": "nemohermes.inference.set.completed.without.sandbox", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-hermes-inference-switch.sh", + "line": 477, + "text": "nemohermes inference set failed (exit ${switch_rc}): ${switch_output:0:500}", + "polarity": "fail", + "normalized_id": "nemohermes.inference.set.failed.exit.switch.rc.switch.output.0.500", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-hermes-inference-switch.sh", + "line": 484, + "text": "Hermes gateway process stayed running during switch", + "polarity": "pass", + "normalized_id": "hermes.gateway.process.stayed.running.during.switch", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-hermes-inference-switch.sh", + "line": 486, + "text": "Hermes gateway process changed during switch (${pid_before} -> ${pid_after})", + "polarity": "fail", + "normalized_id": "hermes.gateway.process.changed.during.switch.pid.before.pid.after", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-hermes-inference-switch.sh", + "line": 510, + "text": "Sandbox ${SANDBOX_NAME} still in registry after destroy", + "polarity": "fail", + "normalized_id": "sandbox.sandbox.name.still.in.registry.after.destroy", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-hermes-inference-switch.sh", + "line": 512, + "text": "Sandbox ${SANDBOX_NAME} removed", + "polarity": "pass", + "normalized_id": "sandbox.sandbox.name.removed", + "mapping_status": "retired" + } + ] + }, + { + "script": "test/e2e/test-hermes-slack-e2e.sh", + "assertions": [ + { + "script": "test/e2e/test-hermes-slack-e2e.sh", + "line": 170, + "text": "Docker is running", + "polarity": "pass", + "normalized_id": "docker.is.running", + "mapping_status": "mapped" + }, + { + "script": "test/e2e/test-hermes-slack-e2e.sh", + "line": 172, + "text": "Docker is not running", + "polarity": "fail", + "normalized_id": "docker.is.not.running", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-hermes-slack-e2e.sh", + "line": 177, + "text": "NVIDIA_API_KEY is set (starts with nvapi-)", + "polarity": "pass", + "normalized_id": "nvidia.api.key.is.set.starts.with.nvapi", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-hermes-slack-e2e.sh", + "line": 179, + "text": "NVIDIA_API_KEY not set or invalid", + "polarity": "fail", + "normalized_id": "nvidia.api.key.not.set.or.invalid", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-hermes-slack-e2e.sh", + "line": 184, + "text": "NEMOCLAW_NON_INTERACTIVE=1", + "polarity": "pass", + "normalized_id": "nemoclaw.non.interactive.1", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-hermes-slack-e2e.sh", + "line": 186, + "text": "NEMOCLAW_NON_INTERACTIVE=1 is required", + "polarity": "fail", + "normalized_id": "nemoclaw.non.interactive.1.is.required", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-hermes-slack-e2e.sh", + "line": 191, + "text": "NEMOCLAW_ACCEPT_THIRD_PARTY_SOFTWARE=1", + "polarity": "pass", + "normalized_id": "nemoclaw.accept.third.party.software.1", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-hermes-slack-e2e.sh", + "line": 193, + "text": "NEMOCLAW_ACCEPT_THIRD_PARTY_SOFTWARE=1 is required", + "polarity": "fail", + "normalized_id": "nemoclaw.accept.third.party.software.1.is.required", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-hermes-slack-e2e.sh", + "line": 204, + "text": "Could not cd to repo root: $REPO", + "polarity": "fail", + "normalized_id": "could.not.cd.to.repo.root.repo", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-hermes-slack-e2e.sh", + "line": 218, + "text": "Pre-cleanup complete", + "polarity": "pass", + "normalized_id": "pre.cleanup.complete", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-hermes-slack-e2e.sh", + "line": 245, + "text": "install.sh completed (exit 0)", + "polarity": "pass", + "normalized_id": "install.sh.completed.exit.0", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-hermes-slack-e2e.sh", + "line": 247, + "text": "install.sh failed (exit $install_exit)", + "polarity": "fail", + "normalized_id": "install.sh.failed.exit.install.exit", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-hermes-slack-e2e.sh", + "line": 255, + "text": "nemoclaw installed at $(command -v nemoclaw)", + "polarity": "pass", + "normalized_id": "nemoclaw.installed.at.command.v.nemoclaw", + "mapping_status": "mapped" + }, + { + "script": "test/e2e/test-hermes-slack-e2e.sh", + "line": 257, + "text": "nemoclaw not found on PATH after install", + "polarity": "fail", + "normalized_id": "nemoclaw.not.found.on.path.after.install", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-hermes-slack-e2e.sh", + "line": 262, + "text": "openshell installed ($(openshell --version 2>&1 || echo unknown))", + "polarity": "pass", + "normalized_id": "openshell.installed.openshell.version.2.1.echo.unknown", + "mapping_status": "mapped" + }, + { + "script": "test/e2e/test-hermes-slack-e2e.sh", + "line": 264, + "text": "openshell not found on PATH after install", + "polarity": "fail", + "normalized_id": "openshell.not.found.on.path.after.install", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-hermes-slack-e2e.sh", + "line": 272, + "text": "nemoclaw list contains '${SANDBOX_NAME}'", + "polarity": "pass", + "normalized_id": "nemoclaw.list.contains.sandbox.name", + "mapping_status": "mapped" + }, + { + "script": "test/e2e/test-hermes-slack-e2e.sh", + "line": 274, + "text": "nemoclaw list does not contain '${SANDBOX_NAME}'", + "polarity": "fail", + "normalized_id": "nemoclaw.list.does.not.contain.sandbox.name", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-hermes-slack-e2e.sh", + "line": 277, + "text": "nemoclaw list failed: ${list_output:0:200}", + "polarity": "fail", + "normalized_id": "nemoclaw.list.failed.list.output.0.200", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-hermes-slack-e2e.sh", + "line": 281, + "text": "Slack bot provider '${SANDBOX_NAME}-slack-bridge' exists in gateway", + "polarity": "pass", + "normalized_id": "slack.bot.provider.sandbox.name.slack.bridge.exists.in.gateway", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-hermes-slack-e2e.sh", + "line": 283, + "text": "Slack bot provider '${SANDBOX_NAME}-slack-bridge' not found in gateway", + "polarity": "fail", + "normalized_id": "slack.bot.provider.sandbox.name.slack.bridge.not.found.in.gateway", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-hermes-slack-e2e.sh", + "line": 287, + "text": "Slack app provider '${SANDBOX_NAME}-slack-app' exists in gateway", + "polarity": "pass", + "normalized_id": "slack.app.provider.sandbox.name.slack.app.exists.in.gateway", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-hermes-slack-e2e.sh", + "line": 289, + "text": "Slack app provider '${SANDBOX_NAME}-slack-app' not found in gateway", + "polarity": "fail", + "normalized_id": "slack.app.provider.sandbox.name.slack.app.not.found.in.gateway", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-hermes-slack-e2e.sh", + "line": 307, + "text": "Hermes health probe returned ok with Slack enabled", + "polarity": "pass", + "normalized_id": "hermes.health.probe.returned.ok.with.slack.enabled", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-hermes-slack-e2e.sh", + "line": 309, + "text": "Hermes health probe did not return ok after 15 attempts", + "polarity": "fail", + "normalized_id": "hermes.health.probe.did.not.return.ok.after.15.attempts", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-hermes-slack-e2e.sh", + "line": 342, + "text": "config.yaml has no generic platforms.slack block or Slack token keys", + "polarity": "pass", + "normalized_id": "config.yaml.has.no.generic.platforms.slack.block.or.slack.token.keys", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-hermes-slack-e2e.sh", + "line": 344, + "text": "config.yaml check failed: ${config_probe:0:400}", + "polarity": "fail", + "normalized_id": "config.yaml.check.failed.config.probe.0.400", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-hermes-slack-e2e.sh", + "line": 366, + "text": ".hermes/.env contains Slack SDK-shaped resolver placeholders", + "polarity": "pass", + "normalized_id": "hermes.env.contains.slack.sdk.shaped.resolver.placeholders", + "mapping_status": "retired" + }, + { + "script": "test/e2e/test-hermes-slack-e2e.sh", + "line": 368, + "text": ".hermes/.env check failed: ${env_probe:0:400}", + "polarity": "fail", + "normalized_id": "hermes.env.check.failed.env.probe.0.400", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-hermes-slack-e2e.sh", + "line": 373, + "text": "Raw Slack tokens absent from Hermes config files and logs", + "polarity": "pass", + "normalized_id": "raw.slack.tokens.absent.from.hermes.config.files.and.logs", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-hermes-slack-e2e.sh", + "line": 375, + "text": "Raw Slack token found in Hermes config files or logs", + "polarity": "fail", + "normalized_id": "raw.slack.token.found.in.hermes.config.files.or.logs", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-hermes-slack-e2e.sh", + "line": 382, + "text": "Raw Slack token found in sandbox process list", + "polarity": "fail", + "normalized_id": "raw.slack.token.found.in.sandbox.process.list", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-hermes-slack-e2e.sh", + "line": 384, + "text": "Raw Slack tokens absent from sandbox process list", + "polarity": "pass", + "normalized_id": "raw.slack.tokens.absent.from.sandbox.process.list", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-hermes-slack-e2e.sh", + "line": 397, + "text": "Sandbox policy contains Slack network policy", + "polarity": "pass", + "normalized_id": "sandbox.policy.contains.slack.network.policy", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-hermes-slack-e2e.sh", + "line": 399, + "text": "Sandbox policy missing Slack network policy", + "polarity": "fail", + "normalized_id": "sandbox.policy.missing.slack.network.policy", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-hermes-slack-e2e.sh", + "line": 405, + "text": "Slack policy is scoped to Hermes and Python binaries", + "polarity": "pass", + "normalized_id": "slack.policy.is.scoped.to.hermes.and.python.binaries", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-hermes-slack-e2e.sh", + "line": 407, + "text": "Slack policy missing Hermes/Python binary allowlist", + "polarity": "fail", + "normalized_id": "slack.policy.missing.hermes.python.binary.allowlist", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-hermes-slack-e2e.sh", + "line": 412, + "text": "Slack policy was replaced by or widened to Node", + "polarity": "fail", + "normalized_id": "slack.policy.was.replaced.by.or.widened.to.node", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-hermes-slack-e2e.sh", + "line": 414, + "text": "Slack policy does not allow Node", + "polarity": "pass", + "normalized_id": "slack.policy.does.not.allow.node", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-hermes-slack-e2e.sh", + "line": 419, + "text": "Slack policy includes Socket Mode websocket hosts", + "polarity": "pass", + "normalized_id": "slack.policy.includes.socket.mode.websocket.hosts", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-hermes-slack-e2e.sh", + "line": 421, + "text": "Slack policy missing Socket Mode websocket hosts", + "polarity": "fail", + "normalized_id": "slack.policy.missing.socket.mode.websocket.hosts", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-hermes-slack-e2e.sh", + "line": 425, + "text": "Slack REST policy enables OpenShell request-body credential rewrite", + "polarity": "pass", + "normalized_id": "slack.rest.policy.enables.openshell.request.body.credential.rewrite", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-hermes-slack-e2e.sh", + "line": 427, + "text": "Slack policy missing request_body_credential_rewrite for REST alias rewrite", + "polarity": "fail", + "normalized_id": "slack.policy.missing.request.body.credential.rewrite.for.rest.alias.rewrite", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-hermes-slack-e2e.sh", + "line": 430, + "text": "openshell policy get failed: ${policy_output:0:200}", + "polarity": "fail", + "normalized_id": "openshell.policy.get.failed.policy.output.0.200", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-hermes-slack-e2e.sh", + "line": 448, + "text": "Hermes Slack sandbox has no decode proxy or Python placeholder-normalization preload", + "polarity": "pass", + "normalized_id": "hermes.slack.sandbox.has.no.decode.proxy.or.python.placeholder.normalization.preload", + "mapping_status": "retired" + }, + { + "script": "test/e2e/test-hermes-slack-e2e.sh", + "line": 450, + "text": "Hermes Slack bridge residue found: ${bridge_residue:0:300}", + "polarity": "fail", + "normalized_id": "hermes.slack.bridge.residue.found.bridge.residue.0.300", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-hermes-slack-e2e.sh", + "line": 537, + "text": "Slack API reached from Python through OpenShell alias substitution", + "polarity": "pass", + "normalized_id": "slack.api.reached.from.python.through.openshell.alias.substitution", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-hermes-slack-e2e.sh", + "line": 541, + "text": "Slack Python API probe failed: ${slack_probe:0:400}", + "polarity": "fail", + "normalized_id": "slack.python.api.probe.failed.slack.probe.0.400", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-hermes-slack-e2e.sh", + "line": 544, + "text": "Unexpected Slack Python API response: ${slack_probe:0:400}", + "polarity": "fail", + "normalized_id": "unexpected.slack.python.api.response.slack.probe.0.400", + "mapping_status": "retired" + }, + { + "script": "test/e2e/test-hermes-slack-e2e.sh", + "line": 556, + "text": "Sandbox ${SANDBOX_NAME} still in registry after destroy", + "polarity": "fail", + "normalized_id": "sandbox.sandbox.name.still.in.registry.after.destroy", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-hermes-slack-e2e.sh", + "line": 558, + "text": "Sandbox ${SANDBOX_NAME} removed", + "polarity": "pass", + "normalized_id": "sandbox.sandbox.name.removed", + "mapping_status": "retired" + }, + { + "script": "test/e2e/test-hermes-slack-e2e.sh", + "line": 562, + "text": "Slack app provider still exists after destroy", + "polarity": "fail", + "normalized_id": "slack.app.provider.still.exists.after.destroy", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-hermes-slack-e2e.sh", + "line": 565, + "text": "Slack app provider removed", + "polarity": "pass", + "normalized_id": "slack.app.provider.removed", + "mapping_status": "retired" + } + ] + }, + { + "script": "test/e2e/test-inference-routing.sh", + "assertions": [ + { + "script": "test/e2e/test-inference-routing.sh", + "line": 211, + "text": "TC-INF-05: Setup", + "polarity": "fail", + "normalized_id": "tc.inf.05.setup", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-inference-routing.sh", + "line": 220, + "text": "TC-INF-05: Setup", + "polarity": "fail", + "normalized_id": "tc.inf.05.setup", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-inference-routing.sh", + "line": 230, + "text": "TC-INF-05a: Env vars", + "polarity": "fail", + "normalized_id": "tc.inf.05a.env.vars", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-inference-routing.sh", + "line": 232, + "text": "TC-INF-05a: Real API key absent from sandbox environment", + "polarity": "pass", + "normalized_id": "tc.inf.05a.real.api.key.absent.from.sandbox.environment", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-inference-routing.sh", + "line": 239, + "text": "TC-INF-05b: Process list", + "polarity": "fail", + "normalized_id": "tc.inf.05b.process.list", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-inference-routing.sh", + "line": 241, + "text": "TC-INF-05b: Real API key absent from sandbox process list", + "polarity": "pass", + "normalized_id": "tc.inf.05b.real.api.key.absent.from.sandbox.process.list", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-inference-routing.sh", + "line": 271, + "text": "TC-INF-05c: Filesystem", + "polarity": "fail", + "normalized_id": "tc.inf.05c.filesystem", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-inference-routing.sh", + "line": 273, + "text": "TC-INF-05c: Filesystem", + "polarity": "fail", + "normalized_id": "tc.inf.05c.filesystem", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-inference-routing.sh", + "line": 275, + "text": "TC-INF-05c: Real API key absent from sandbox filesystem", + "polarity": "pass", + "normalized_id": "tc.inf.05c.real.api.key.absent.from.sandbox.filesystem", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-inference-routing.sh", + "line": 277, + "text": "TC-INF-05c: Filesystem", + "polarity": "fail", + "normalized_id": "tc.inf.05c.filesystem", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-inference-routing.sh", + "line": 284, + "text": "TC-INF-05d: Placeholder token present in sandbox (not the real key)", + "polarity": "pass", + "normalized_id": "tc.inf.05d.placeholder.token.present.in.sandbox.not.the.real.key", + "mapping_status": "retired" + }, + { + "script": "test/e2e/test-inference-routing.sh", + "line": 286, + "text": "TC-INF-05d: Placeholder", + "polarity": "fail", + "normalized_id": "tc.inf.05d.placeholder", + "mapping_status": "retired" + }, + { + "script": "test/e2e/test-inference-routing.sh", + "line": 310, + "text": "TC-INF-06: Exit code", + "polarity": "fail", + "normalized_id": "tc.inf.06.exit.code", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-inference-routing.sh", + "line": 313, + "text": "TC-INF-06: Onboard failed as expected (exit $exit_code)", + "polarity": "pass", + "normalized_id": "tc.inf.06.onboard.failed.as.expected.exit.exit.code", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-inference-routing.sh", + "line": 317, + "text": "TC-INF-06: Output contains classified error message", + "polarity": "pass", + "normalized_id": "tc.inf.06.output.contains.classified.error.message", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-inference-routing.sh", + "line": 319, + "text": "TC-INF-06: Error classification", + "polarity": "fail", + "normalized_id": "tc.inf.06.error.classification", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-inference-routing.sh", + "line": 328, + "text": "TC-INF-06: Stack trace", + "polarity": "fail", + "normalized_id": "tc.inf.06.stack.trace", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-inference-routing.sh", + "line": 330, + "text": "TC-INF-06: No raw stack trace in output", + "polarity": "pass", + "normalized_id": "tc.inf.06.no.raw.stack.trace.in.output", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-inference-routing.sh", + "line": 335, + "text": "TC-INF-06: Key exposure", + "polarity": "fail", + "normalized_id": "tc.inf.06.key.exposure", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-inference-routing.sh", + "line": 337, + "text": "TC-INF-06: API key not exposed in output", + "polarity": "pass", + "normalized_id": "tc.inf.06.api.key.not.exposed.in.output", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-inference-routing.sh", + "line": 344, + "text": "TC-INF-06: Sandbox cleanup", + "polarity": "fail", + "normalized_id": "tc.inf.06.sandbox.cleanup", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-inference-routing.sh", + "line": 347, + "text": "TC-INF-06: No active sandbox left behind (correct)", + "polarity": "pass", + "normalized_id": "tc.inf.06.no.active.sandbox.left.behind.correct", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-inference-routing.sh", + "line": 378, + "text": "TC-INF-07: Exit code", + "polarity": "fail", + "normalized_id": "tc.inf.07.exit.code", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-inference-routing.sh", + "line": 381, + "text": "TC-INF-07: Onboard failed as expected (exit $exit_code)", + "polarity": "pass", + "normalized_id": "tc.inf.07.onboard.failed.as.expected.exit.exit.code", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-inference-routing.sh", + "line": 385, + "text": "TC-INF-07: Output contains transport error classification", + "polarity": "pass", + "normalized_id": "tc.inf.07.output.contains.transport.error.classification", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-inference-routing.sh", + "line": 387, + "text": "TC-INF-07: Error classification", + "polarity": "fail", + "normalized_id": "tc.inf.07.error.classification", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-inference-routing.sh", + "line": 396, + "text": "TC-INF-07: Stack trace", + "polarity": "fail", + "normalized_id": "tc.inf.07.stack.trace", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-inference-routing.sh", + "line": 398, + "text": "TC-INF-07: No raw stack trace in output", + "polarity": "pass", + "normalized_id": "tc.inf.07.no.raw.stack.trace.in.output", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-inference-routing.sh", + "line": 405, + "text": "TC-INF-07: Sandbox cleanup", + "polarity": "fail", + "normalized_id": "tc.inf.07.sandbox.cleanup", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-inference-routing.sh", + "line": 408, + "text": "TC-INF-07: No active sandbox left behind (correct)", + "polarity": "pass", + "normalized_id": "tc.inf.07.no.active.sandbox.left.behind.correct", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-inference-routing.sh", + "line": 448, + "text": "TC-INF-02: Onboard", + "polarity": "fail", + "normalized_id": "tc.inf.02.onboard", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-inference-routing.sh", + "line": 451, + "text": "TC-INF-02: Onboard with OpenAI succeeded", + "polarity": "pass", + "normalized_id": "tc.inf.02.onboard.with.openai.succeeded", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-inference-routing.sh", + "line": 456, + "text": "TC-INF-02: SSH", + "polarity": "fail", + "normalized_id": "tc.inf.02.ssh", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-inference-routing.sh", + "line": 479, + "text": "TC-INF-02: OpenAI inference response received through sandbox proxy", + "polarity": "pass", + "normalized_id": "tc.inf.02.openai.inference.response.received.through.sandbox.proxy", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-inference-routing.sh", + "line": 481, + "text": "TC-INF-02: OpenAI response received (content: ${content:0:100})", + "polarity": "pass", + "normalized_id": "tc.inf.02.openai.response.received.content.content.0.100", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-inference-routing.sh", + "line": 483, + "text": "TC-INF-02: Inference", + "polarity": "fail", + "normalized_id": "tc.inf.02.inference", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-inference-routing.sh", + "line": 522, + "text": "TC-INF-03: Onboard", + "polarity": "fail", + "normalized_id": "tc.inf.03.onboard", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-inference-routing.sh", + "line": 525, + "text": "TC-INF-03: Onboard with Anthropic succeeded", + "polarity": "pass", + "normalized_id": "tc.inf.03.onboard.with.anthropic.succeeded", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-inference-routing.sh", + "line": 530, + "text": "TC-INF-03: SSH", + "polarity": "fail", + "normalized_id": "tc.inf.03.ssh", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-inference-routing.sh", + "line": 562, + "text": "TC-INF-03: Anthropic inference response received through sandbox proxy", + "polarity": "pass", + "normalized_id": "tc.inf.03.anthropic.inference.response.received.through.sandbox.proxy", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-inference-routing.sh", + "line": 564, + "text": "TC-INF-03: Anthropic response received (content: ${content:0:100})", + "polarity": "pass", + "normalized_id": "tc.inf.03.anthropic.response.received.content.content.0.100", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-inference-routing.sh", + "line": 566, + "text": "TC-INF-03: Inference", + "polarity": "fail", + "normalized_id": "tc.inf.03.inference", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-inference-routing.sh", + "line": 609, + "text": "TC-INF-09: Onboard", + "polarity": "fail", + "normalized_id": "tc.inf.09.onboard", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-inference-routing.sh", + "line": 612, + "text": "TC-INF-09: Onboard with compatible endpoint succeeded", + "polarity": "pass", + "normalized_id": "tc.inf.09.onboard.with.compatible.endpoint.succeeded", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-inference-routing.sh", + "line": 618, + "text": "TC-INF-09: SSH", + "polarity": "fail", + "normalized_id": "tc.inf.09.ssh", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-inference-routing.sh", + "line": 642, + "text": "TC-INF-09: Inference response received through sandbox proxy", + "polarity": "pass", + "normalized_id": "tc.inf.09.inference.response.received.through.sandbox.proxy", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-inference-routing.sh", + "line": 644, + "text": "TC-INF-09: Inference response received (content: ${content:0:100})", + "polarity": "pass", + "normalized_id": "tc.inf.09.inference.response.received.content.content.0.100", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-inference-routing.sh", + "line": 646, + "text": "TC-INF-09: Inference", + "polarity": "fail", + "normalized_id": "tc.inf.09.inference", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-inference-routing.sh", + "line": 648, + "text": "TC-INF-09: Inference", + "polarity": "fail", + "normalized_id": "tc.inf.09.inference", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-inference-routing.sh", + "line": 676, + "text": "$PASS${NC}", + "polarity": "pass", + "normalized_id": "pass.nc", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-inference-routing.sh", + "line": 677, + "text": "$FAIL${NC}", + "polarity": "fail", + "normalized_id": "fail.nc", + "mapping_status": "deferred" + } + ] + }, + { + "script": "test/e2e/test-issue-2478-crash-loop-recovery.sh", + "assertions": [ + { + "script": "test/e2e/test-issue-2478-crash-loop-recovery.sh", + "line": 254, + "text": "${context}: connect --probe-only exited nonzero", + "polarity": "fail", + "normalized_id": "context.connect.probe.only.exited.nonzero", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-issue-2478-crash-loop-recovery.sh", + "line": 286, + "text": "Docker is not running", + "polarity": "fail", + "normalized_id": "docker.is.not.running", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-issue-2478-crash-loop-recovery.sh", + "line": 289, + "text": "Docker running", + "polarity": "pass", + "normalized_id": "docker.running", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-issue-2478-crash-loop-recovery.sh", + "line": 292, + "text": "NVIDIA_API_KEY not set or invalid", + "polarity": "fail", + "normalized_id": "nvidia.api.key.not.set.or.invalid", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-issue-2478-crash-loop-recovery.sh", + "line": 295, + "text": "NVIDIA_API_KEY set", + "polarity": "pass", + "normalized_id": "nvidia.api.key.set", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-issue-2478-crash-loop-recovery.sh", + "line": 298, + "text": "NEMOCLAW_NON_INTERACTIVE=1 and NEMOCLAW_ACCEPT_THIRD_PARTY_SOFTWARE=1 are required", + "polarity": "fail", + "normalized_id": "nemoclaw.non.interactive.1.and.nemoclaw.accept.third.party.software.1.are.required", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-issue-2478-crash-loop-recovery.sh", + "line": 301, + "text": "Required env vars set", + "polarity": "pass", + "normalized_id": "required.env.vars.set", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-issue-2478-crash-loop-recovery.sh", + "line": 316, + "text": "cd $REPO_ROOT", + "polarity": "fail", + "normalized_id": "cd.repo.root", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-issue-2478-crash-loop-recovery.sh", + "line": 330, + "text": "install.sh failed (exit $install_exit). Last 30 lines:", + "polarity": "fail", + "normalized_id": "install.sh.failed.exit.install.exit.last.30.lines", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-issue-2478-crash-loop-recovery.sh", + "line": 336, + "text": "install.sh + onboard completed", + "polarity": "pass", + "normalized_id": "install.sh.onboard.completed", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-issue-2478-crash-loop-recovery.sh", + "line": 345, + "text": "nemoclaw not on PATH after install", + "polarity": "fail", + "normalized_id": "nemoclaw.not.on.path.after.install", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-issue-2478-crash-loop-recovery.sh", + "line": 348, + "text": "nemoclaw on PATH", + "polarity": "pass", + "normalized_id": "nemoclaw.on.path", + "mapping_status": "mapped" + }, + { + "script": "test/e2e/test-issue-2478-crash-loop-recovery.sh", + "line": 357, + "text": "Gateway never came up after onboard", + "polarity": "fail", + "normalized_id": "gateway.never.came.up.after.onboard", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-issue-2478-crash-loop-recovery.sh", + "line": 361, + "text": "Gateway up (pid=$INIT_PID)", + "polarity": "pass", + "normalized_id": "gateway.up.pid.init.pid", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-issue-2478-crash-loop-recovery.sh", + "line": 364, + "text": "Initial gateway has guard chain active (proxy-env exports + gateway preloads loaded)", + "polarity": "pass", + "normalized_id": "initial.gateway.has.guard.chain.active.proxy.env.exports.gateway.preloads.loaded", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-issue-2478-crash-loop-recovery.sh", + "line": 366, + "text": "Initial gateway missing library guard chain — fix is not deployed?", + "polarity": "fail", + "normalized_id": "initial.gateway.missing.library.guard.chain.fix.is.not.deployed", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-issue-2478-crash-loop-recovery.sh", + "line": 372, + "text": "Initial gateway serves inference API (https://inference.local/v1/models responds)", + "polarity": "pass", + "normalized_id": "initial.gateway.serves.inference.api.https.inference.local.v1.models.responds", + "mapping_status": "mapped" + }, + { + "script": "test/e2e/test-issue-2478-crash-loop-recovery.sh", + "line": 374, + "text": "Initial gateway alive but not serving inference — recovery is incomplete from user POV", + "polarity": "fail", + "normalized_id": "initial.gateway.alive.but.not.serving.inference.recovery.is.incomplete.from.user.pov", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-issue-2478-crash-loop-recovery.sh", + "line": 397, + "text": "Cycle $cycle: connect --probe-only did not leave /tmp/gateway.log evidence", + "polarity": "fail", + "normalized_id": "cycle.cycle.connect.probe.only.did.not.leave.tmp.gateway.log.evidence", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-issue-2478-crash-loop-recovery.sh", + "line": 404, + "text": "Cycle $cycle: gateway did not respawn within 45s", + "polarity": "fail", + "normalized_id": "cycle.cycle.gateway.did.not.respawn.within.45s", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-issue-2478-crash-loop-recovery.sh", + "line": 409, + "text": "Cycle $cycle: PID unchanged ($new_pid) — kill did not land", + "polarity": "fail", + "normalized_id": "cycle.cycle.pid.unchanged.new.pid.kill.did.not.land", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-issue-2478-crash-loop-recovery.sh", + "line": 412, + "text": "Cycle $cycle: gateway respawned (pid $prev_pid → $new_pid)", + "polarity": "pass", + "normalized_id": "cycle.cycle.gateway.respawned.pid.prev.pid.new.pid", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-issue-2478-crash-loop-recovery.sh", + "line": 415, + "text": "Cycle $cycle: respawned gateway retains guard chain (proxy-env + gateway preloads loaded)", + "polarity": "pass", + "normalized_id": "cycle.cycle.respawned.gateway.retains.guard.chain.proxy.env.gateway.preloads.loaded", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-issue-2478-crash-loop-recovery.sh", + "line": 417, + "text": "Cycle $cycle: respawned gateway LOST guard chain — recovery hardening regressed", + "polarity": "fail", + "normalized_id": "cycle.cycle.respawned.gateway.lost.guard.chain.recovery.hardening.regressed", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-issue-2478-crash-loop-recovery.sh", + "line": 424, + "text": "Cycle $cycle: respawned gateway serves inference API", + "polarity": "pass", + "normalized_id": "cycle.cycle.respawned.gateway.serves.inference.api", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-issue-2478-crash-loop-recovery.sh", + "line": 426, + "text": "Cycle $cycle: gateway up + guards active but inference API not serving", + "polarity": "fail", + "normalized_id": "cycle.cycle.gateway.up.guards.active.but.inference.api.not.serving", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-issue-2478-crash-loop-recovery.sh", + "line": 448, + "text": "proxy-env.sh is empty/missing already — cannot run negative case", + "polarity": "fail", + "normalized_id": "proxy.env.sh.is.empty.missing.already.cannot.run.negative.case", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-issue-2478-crash-loop-recovery.sh", + "line": 473, + "text": "Recovery emitted [gateway-recovery] WARNING when proxy-env.sh missing", + "polarity": "pass", + "normalized_id": "recovery.emitted.gateway.recovery.warning.when.proxy.env.sh.missing", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-issue-2478-crash-loop-recovery.sh", + "line": 475, + "text": "Recovery silently launched without warning (regression of #2478 fix)", + "polarity": "fail", + "normalized_id": "recovery.silently.launched.without.warning.regression.of.2478.fix", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-issue-2478-crash-loop-recovery.sh", + "line": 480, + "text": "Recovery warning was logged, but gateway did not respawn within 45s", + "polarity": "fail", + "normalized_id": "recovery.warning.was.logged.but.gateway.did.not.respawn.within.45s", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-issue-2478-crash-loop-recovery.sh", + "line": 495, + "text": "proxy-env.sh restore failed: expected $SNAPSHOT_SIZE bytes, got '${restored_size}'", + "polarity": "fail", + "normalized_id": "proxy.env.sh.restore.failed.expected.snapshot.size.bytes.got.restored.size", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-issue-2478-crash-loop-recovery.sh", + "line": 506, + "text": "Gateway not up entering soak phase", + "polarity": "fail", + "normalized_id": "gateway.not.up.entering.soak.phase", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-issue-2478-crash-loop-recovery.sh", + "line": 513, + "text": "Gateway up but guards not active entering soak — restore did not take", + "polarity": "fail", + "normalized_id": "gateway.up.but.guards.not.active.entering.soak.restore.did.not.take", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-issue-2478-crash-loop-recovery.sh", + "line": 518, + "text": "Gateway alive + guards active but inference API not serving entering soak", + "polarity": "fail", + "normalized_id": "gateway.alive.guards.active.but.inference.api.not.serving.entering.soak", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-issue-2478-crash-loop-recovery.sh", + "line": 522, + "text": "Gateway healthy with guards active and inference API serving (pid=$SOAK_START_PID)", + "polarity": "pass", + "normalized_id": "gateway.healthy.with.guards.active.and.inference.api.serving.pid.soak.start.pid", + "mapping_status": "mapped" + }, + { + "script": "test/e2e/test-issue-2478-crash-loop-recovery.sh", + "line": 567, + "text": "No crash-loop detected during soak ($distinct distinct PIDs, $empty_samples empty samples)", + "polarity": "pass", + "normalized_id": "no.crash.loop.detected.during.soak.distinct.distinct.pids.empty.samples.empty.samples", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-issue-2478-crash-loop-recovery.sh", + "line": 569, + "text": "Crash-loop signature: $distinct distinct PIDs and $empty_samples empty samples in ${SOAK_SECONDS}s", + "polarity": "fail", + "normalized_id": "crash.loop.signature.distinct.distinct.pids.and.empty.samples.empty.samples.in.soak.seconds.s", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-issue-2478-crash-loop-recovery.sh", + "line": 579, + "text": "Inference API available throughout soak ($inference_probes/$inference_probes probes succeeded)", + "polarity": "pass", + "normalized_id": "inference.api.available.throughout.soak.inference.probes.inference.probes.probes.succeeded", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-issue-2478-crash-loop-recovery.sh", + "line": 581, + "text": "Inference API unavailable during soak ($inference_failures/$inference_probes probes failed)", + "polarity": "fail", + "normalized_id": "inference.api.unavailable.during.soak.inference.failures.inference.probes.probes.failed", + "mapping_status": "deferred" + } + ] + }, + { + "script": "test/e2e/test-kimi-inference-compat.sh", + "assertions": [ + { + "script": "test/e2e/test-kimi-inference-compat.sh", + "line": 402, + "text": "K1: source CLI/OpenShell preparation failed (exit $prep_exit)", + "polarity": "fail", + "normalized_id": "k1.source.cli.openshell.preparation.failed.exit.prep.exit", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-kimi-inference-compat.sh", + "line": 414, + "text": "K1: onboard completed for Kimi compatible endpoint sandbox", + "polarity": "pass", + "normalized_id": "k1.onboard.completed.for.kimi.compatible.endpoint.sandbox", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-kimi-inference-compat.sh", + "line": 416, + "text": "K1: onboard failed (exit $onboard_exit)", + "polarity": "fail", + "normalized_id": "k1.onboard.failed.exit.onboard.exit", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-kimi-inference-compat.sh", + "line": 482, + "text": "K2: openclaw.json has managed Kimi compat and plugin wiring", + "polarity": "pass", + "normalized_id": "k2.openclaw.json.has.managed.kimi.compat.and.plugin.wiring", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-kimi-inference-compat.sh", + "line": 484, + "text": "K2: openclaw.json Kimi compat/plugin wiring is wrong", + "polarity": "fail", + "normalized_id": "k2.openclaw.json.kimi.compat.plugin.wiring.is.wrong", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-kimi-inference-compat.sh", + "line": 492, + "text": "K3: sandbox inference.local models route reaches Kimi mock", + "polarity": "pass", + "normalized_id": "k3.sandbox.inference.local.models.route.reaches.kimi.mock", + "mapping_status": "mapped" + }, + { + "script": "test/e2e/test-kimi-inference-compat.sh", + "line": 494, + "text": "K3: sandbox inference.local models route failed (${response:0:400})", + "polarity": "fail", + "normalized_id": "k3.sandbox.inference.local.models.route.failed.response.0.400", + "mapping_status": "mapped" + }, + { + "script": "test/e2e/test-kimi-inference-compat.sh", + "line": 504, + "text": "K4: OpenClaw agent completed after Kimi tool results", + "polarity": "pass", + "normalized_id": "k4.openclaw.agent.completed.after.kimi.tool.results", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-kimi-inference-compat.sh", + "line": 506, + "text": "K4: OpenClaw agent did not complete successfully (exit $agent_exit)", + "polarity": "fail", + "normalized_id": "k4.openclaw.agent.did.not.complete.successfully.exit.agent.exit", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-kimi-inference-compat.sh", + "line": 671, + "text": "K5: trajectory proves split Kimi exec calls completed cleanly", + "polarity": "pass", + "normalized_id": "k5.trajectory.proves.split.kimi.exec.calls.completed.cleanly", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-kimi-inference-compat.sh", + "line": 673, + "text": "K5: trajectory acceptance checks failed", + "polarity": "fail", + "normalized_id": "k5.trajectory.acceptance.checks.failed", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-kimi-inference-compat.sh", + "line": 681, + "text": "K6: Kimi mock observed authenticated streamed tool-call and final-answer traffic", + "polarity": "pass", + "normalized_id": "k6.kimi.mock.observed.authenticated.streamed.tool.call.and.final.answer.traffic", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-kimi-inference-compat.sh", + "line": 683, + "text": "K6: Kimi mock did not observe both streamed agent requests", + "polarity": "fail", + "normalized_id": "k6.kimi.mock.did.not.observe.both.streamed.agent.requests", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-kimi-inference-compat.sh", + "line": 726, + "text": "Docker is not running", + "polarity": "fail", + "normalized_id": "docker.is.not.running", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-kimi-inference-compat.sh", + "line": 729, + "text": "Docker is running", + "polarity": "pass", + "normalized_id": "docker.is.running", + "mapping_status": "mapped" + }, + { + "script": "test/e2e/test-kimi-inference-compat.sh", + "line": 732, + "text": "python3 not found", + "polarity": "fail", + "normalized_id": "python3.not.found", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-kimi-inference-compat.sh", + "line": 735, + "text": "python3 is available", + "polarity": "pass", + "normalized_id": "python3.is.available", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-kimi-inference-compat.sh", + "line": 745, + "text": "K0: Kimi-compatible mock endpoint started", + "polarity": "pass", + "normalized_id": "k0.kimi.compatible.mock.endpoint.started", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-kimi-inference-compat.sh", + "line": 747, + "text": "K0: Kimi-compatible mock endpoint failed to start", + "polarity": "fail", + "normalized_id": "k0.kimi.compatible.mock.endpoint.failed.to.start", + "mapping_status": "deferred" + } + ] + }, + { + "script": "test/e2e/test-launchable-smoke.sh", + "assertions": [ + { + "script": "test/e2e/test-launchable-smoke.sh", + "line": 164, + "text": "Pre-cleanup complete (clone dir pre-seeded)", + "polarity": "pass", + "normalized_id": "pre.cleanup.complete.clone.dir.pre.seeded", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-launchable-smoke.sh", + "line": 172, + "text": "Docker is running", + "polarity": "pass", + "normalized_id": "docker.is.running", + "mapping_status": "mapped" + }, + { + "script": "test/e2e/test-launchable-smoke.sh", + "line": 174, + "text": "Docker is not running — cannot continue", + "polarity": "fail", + "normalized_id": "docker.is.not.running.cannot.continue", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-launchable-smoke.sh", + "line": 179, + "text": "NVIDIA_API_KEY is set (starts with nvapi-)", + "polarity": "pass", + "normalized_id": "nvidia.api.key.is.set.starts.with.nvapi", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-launchable-smoke.sh", + "line": 181, + "text": "NVIDIA_API_KEY not set or invalid — required for live inference", + "polarity": "fail", + "normalized_id": "nvidia.api.key.not.set.or.invalid.required.for.live.inference", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-launchable-smoke.sh", + "line": 186, + "text": "Network access to integrate.api.nvidia.com", + "polarity": "pass", + "normalized_id": "network.access.to.integrate.api.nvidia.com", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-launchable-smoke.sh", + "line": 188, + "text": "Cannot reach integrate.api.nvidia.com", + "polarity": "fail", + "normalized_id": "cannot.reach.integrate.api.nvidia.com", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-launchable-smoke.sh", + "line": 193, + "text": "NEMOCLAW_NON_INTERACTIVE=1 is required", + "polarity": "fail", + "normalized_id": "nemoclaw.non.interactive.1.is.required", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-launchable-smoke.sh", + "line": 198, + "text": "NEMOCLAW_ACCEPT_THIRD_PARTY_SOFTWARE=1 is required for non-interactive install", + "polarity": "fail", + "normalized_id": "nemoclaw.accept.third.party.software.1.is.required.for.non.interactive.install", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-launchable-smoke.sh", + "line": 203, + "text": "brev-launchable-ci-cpu.sh found at $REPO/scripts/", + "polarity": "pass", + "normalized_id": "brev.launchable.ci.cpu.sh.found.at.repo.scripts", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-launchable-smoke.sh", + "line": 205, + "text": "brev-launchable-ci-cpu.sh not found", + "polarity": "fail", + "normalized_id": "brev.launchable.ci.cpu.sh.not.found", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-launchable-smoke.sh", + "line": 235, + "text": "brev-launchable-ci-cpu.sh completed (exit 0)", + "polarity": "pass", + "normalized_id": "brev.launchable.ci.cpu.sh.completed.exit.0", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-launchable-smoke.sh", + "line": 237, + "text": "brev-launchable-ci-cpu.sh failed (exit $install_exit)", + "polarity": "fail", + "normalized_id": "brev.launchable.ci.cpu.sh.failed.exit.install.exit", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-launchable-smoke.sh", + "line": 263, + "text": "nemoclaw on PATH: $(command -v nemoclaw)", + "polarity": "pass", + "normalized_id": "nemoclaw.on.path.command.v.nemoclaw", + "mapping_status": "mapped" + }, + { + "script": "test/e2e/test-launchable-smoke.sh", + "line": 265, + "text": "nemoclaw not found on PATH after launchable install", + "polarity": "fail", + "normalized_id": "nemoclaw.not.found.on.path.after.launchable.install", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-launchable-smoke.sh", + "line": 269, + "text": "nemoclaw --help exits 0", + "polarity": "pass", + "normalized_id": "nemoclaw.help.exits.0", + "mapping_status": "mapped" + }, + { + "script": "test/e2e/test-launchable-smoke.sh", + "line": 271, + "text": "nemoclaw --help failed", + "polarity": "fail", + "normalized_id": "nemoclaw.help.failed", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-launchable-smoke.sh", + "line": 277, + "text": "openshell on PATH: $(command -v openshell) (${os_version})", + "polarity": "pass", + "normalized_id": "openshell.on.path.command.v.openshell.os.version", + "mapping_status": "mapped" + }, + { + "script": "test/e2e/test-launchable-smoke.sh", + "line": 279, + "text": "openshell not found on PATH after launchable install", + "polarity": "fail", + "normalized_id": "openshell.not.found.on.path.after.launchable.install", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-launchable-smoke.sh", + "line": 291, + "text": "Node.js >= 22 installed: ${node_version}", + "polarity": "pass", + "normalized_id": "node.js.22.installed.node.version", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-launchable-smoke.sh", + "line": 300, + "text": "Node.js version too old: ${node_version} (need >= 20)", + "polarity": "fail", + "normalized_id": "node.js.version.too.old.node.version.need.20", + "mapping_status": "retired" + }, + { + "script": "test/e2e/test-launchable-smoke.sh", + "line": 304, + "text": "Node.js not found on PATH after launchable install", + "polarity": "fail", + "normalized_id": "node.js.not.found.on.path.after.launchable.install", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-launchable-smoke.sh", + "line": 309, + "text": "Docker running after launchable install", + "polarity": "pass", + "normalized_id": "docker.running.after.launchable.install", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-launchable-smoke.sh", + "line": 311, + "text": "Docker not running after launchable install", + "polarity": "fail", + "normalized_id": "docker.not.running.after.launchable.install", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-launchable-smoke.sh", + "line": 317, + "text": "Sentinel file exists: $SENTINEL", + "polarity": "pass", + "normalized_id": "sentinel.file.exists.sentinel", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-launchable-smoke.sh", + "line": 319, + "text": "Sentinel file missing: $SENTINEL", + "polarity": "fail", + "normalized_id": "sentinel.file.missing.sentinel", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-launchable-smoke.sh", + "line": 324, + "text": "NemoClaw cloned at $NEMOCLAW_CLONE_DIR", + "polarity": "pass", + "normalized_id": "nemoclaw.cloned.at.nemoclaw.clone.dir", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-launchable-smoke.sh", + "line": 326, + "text": "NemoClaw clone directory missing: $NEMOCLAW_CLONE_DIR", + "polarity": "fail", + "normalized_id": "nemoclaw.clone.directory.missing.nemoclaw.clone.dir", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-launchable-smoke.sh", + "line": 330, + "text": "CLI built (dist/ exists)", + "polarity": "pass", + "normalized_id": "cli.built.dist.exists", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-launchable-smoke.sh", + "line": 332, + "text": "CLI not built (dist/ missing)", + "polarity": "fail", + "normalized_id": "cli.not.built.dist.missing", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-launchable-smoke.sh", + "line": 336, + "text": "Plugin built (nemoclaw/dist/ exists)", + "polarity": "pass", + "normalized_id": "plugin.built.nemoclaw.dist.exists", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-launchable-smoke.sh", + "line": 338, + "text": "Plugin not built (nemoclaw/dist/ missing)", + "polarity": "fail", + "normalized_id": "plugin.not.built.nemoclaw.dist.missing", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-launchable-smoke.sh", + "line": 349, + "text": "Could not cd to $NEMOCLAW_CLONE_DIR", + "polarity": "fail", + "normalized_id": "could.not.cd.to.nemoclaw.clone.dir", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-launchable-smoke.sh", + "line": 371, + "text": "nemoclaw onboard completed (exit 0)", + "polarity": "pass", + "normalized_id": "nemoclaw.onboard.completed.exit.0", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-launchable-smoke.sh", + "line": 373, + "text": "nemoclaw onboard failed (exit $onboard_exit)", + "polarity": "fail", + "normalized_id": "nemoclaw.onboard.failed.exit.onboard.exit", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-launchable-smoke.sh", + "line": 387, + "text": "nemoclaw list contains '${SANDBOX_NAME}'", + "polarity": "pass", + "normalized_id": "nemoclaw.list.contains.sandbox.name", + "mapping_status": "mapped" + }, + { + "script": "test/e2e/test-launchable-smoke.sh", + "line": 389, + "text": "nemoclaw list does not contain '${SANDBOX_NAME}'", + "polarity": "fail", + "normalized_id": "nemoclaw.list.does.not.contain.sandbox.name", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-launchable-smoke.sh", + "line": 392, + "text": "nemoclaw list failed: ${list_output:0:200}", + "polarity": "fail", + "normalized_id": "nemoclaw.list.failed.list.output.0.200", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-launchable-smoke.sh", + "line": 397, + "text": "nemoclaw ${SANDBOX_NAME} status exits 0", + "polarity": "pass", + "normalized_id": "nemoclaw.sandbox.name.status.exits.0", + "mapping_status": "mapped" + }, + { + "script": "test/e2e/test-launchable-smoke.sh", + "line": 399, + "text": "nemoclaw ${SANDBOX_NAME} status failed: ${status_output:0:200}", + "polarity": "fail", + "normalized_id": "nemoclaw.sandbox.name.status.failed.status.output.0.200", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-launchable-smoke.sh", + "line": 405, + "text": "Inference configured via onboard (nvidia-prod)", + "polarity": "pass", + "normalized_id": "inference.configured.via.onboard.nvidia.prod", + "mapping_status": "mapped" + }, + { + "script": "test/e2e/test-launchable-smoke.sh", + "line": 407, + "text": "Inference not configured — onboard did not set up nvidia-prod provider", + "polarity": "fail", + "normalized_id": "inference.not.configured.onboard.did.not.set.up.nvidia.prod.provider", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-launchable-smoke.sh", + "line": 410, + "text": "openshell inference get failed: ${inf_check:0:200}", + "polarity": "fail", + "normalized_id": "openshell.inference.get.failed.inf.check.0.200", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-launchable-smoke.sh", + "line": 415, + "text": "Gateway container running", + "polarity": "pass", + "normalized_id": "gateway.container.running", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-launchable-smoke.sh", + "line": 440, + "text": "[LIVE] Direct API: model responded with PONG", + "polarity": "pass", + "normalized_id": "live.direct.api.model.responded.with.pong", + "mapping_status": "mapped" + }, + { + "script": "test/e2e/test-launchable-smoke.sh", + "line": 442, + "text": "[LIVE] Direct API: expected PONG, got: ${api_content:0:200}", + "polarity": "fail", + "normalized_id": "live.direct.api.expected.pong.got.api.content.0.200", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-launchable-smoke.sh", + "line": 445, + "text": "[LIVE] Direct API: empty response from curl", + "polarity": "fail", + "normalized_id": "live.direct.api.empty.response.from.curl", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-launchable-smoke.sh", + "line": 502, + "text": "[ROUTING] inference.local: OpenShell routed curl to NVIDIA Endpoints and returned PONG", + "polarity": "pass", + "normalized_id": "routing.inference.local.openshell.routed.curl.to.nvidia.endpoints.and.returned.pong", + "mapping_status": "mapped" + }, + { + "script": "test/e2e/test-launchable-smoke.sh", + "line": 504, + "text": "[ROUTING] inference.local: expected PONG after 3 attempts, got: ${sandbox_content:0:200}", + "polarity": "fail", + "normalized_id": "routing.inference.local.expected.pong.after.3.attempts.got.sandbox.content.0.200", + "mapping_status": "mapped" + }, + { + "script": "test/e2e/test-launchable-smoke.sh", + "line": 540, + "text": "[LIVE] openclaw agent: model answered 6×7=42 through openclaw → inference.local", + "polarity": "pass", + "normalized_id": "live.openclaw.agent.model.answered.6.7.42.through.openclaw.inference.local", + "mapping_status": "mapped" + }, + { + "script": "test/e2e/test-launchable-smoke.sh", + "line": 542, + "text": "[LIVE] openclaw agent: expected '42' in agent reply, got: ${agent_reply:0:200}", + "polarity": "fail", + "normalized_id": "live.openclaw.agent.expected.42.in.agent.reply.got.agent.reply.0.200", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-launchable-smoke.sh", + "line": 557, + "text": "Sandbox ${SANDBOX_NAME} still in registry after destroy", + "polarity": "fail", + "normalized_id": "sandbox.sandbox.name.still.in.registry.after.destroy", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-launchable-smoke.sh", + "line": 559, + "text": "Sandbox ${SANDBOX_NAME} removed", + "polarity": "pass", + "normalized_id": "sandbox.sandbox.name.removed", + "mapping_status": "retired" + }, + { + "script": "test/e2e/test-launchable-smoke.sh", + "line": 565, + "text": "Launchable clone directory cleaned up", + "polarity": "pass", + "normalized_id": "launchable.clone.directory.cleaned.up", + "mapping_status": "deferred" + } + ] + }, + { + "script": "test/e2e/test-messaging-compatible-endpoint.sh", + "assertions": [ + { + "script": "test/e2e/test-messaging-compatible-endpoint.sh", + "line": 365, + "text": "C1: ${onboard_cmd_desc} completed for compatible endpoint + Telegram", + "polarity": "pass", + "normalized_id": "c1.onboard.cmd.desc.completed.for.compatible.endpoint.telegram", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-messaging-compatible-endpoint.sh", + "line": 367, + "text": "C1: ${onboard_cmd_desc} failed (exit $onboard_exit)", + "polarity": "fail", + "normalized_id": "c1.onboard.cmd.desc.failed.exit.onboard.exit", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-messaging-compatible-endpoint.sh", + "line": 418, + "text": "C3: openclaw.json uses managed inference.local provider and Telegram config", + "polarity": "pass", + "normalized_id": "c3.openclaw.json.uses.managed.inference.local.provider.and.telegram.config", + "mapping_status": "mapped" + }, + { + "script": "test/e2e/test-messaging-compatible-endpoint.sh", + "line": 420, + "text": "C3: openclaw.json compatible endpoint shape is wrong", + "polarity": "fail", + "normalized_id": "c3.openclaw.json.compatible.endpoint.shape.is.wrong", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-messaging-compatible-endpoint.sh", + "line": 458, + "text": "C4: Gateway stayed up after Telegram provider initialization", + "polarity": "pass", + "normalized_id": "c4.gateway.stayed.up.after.telegram.provider.initialization", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-messaging-compatible-endpoint.sh", + "line": 460, + "text": "C4: Gateway is not serving after Telegram-compatible onboard (${result:0:200})", + "polarity": "fail", + "normalized_id": "c4.gateway.is.not.serving.after.telegram.compatible.onboard.result.0.200", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-messaging-compatible-endpoint.sh", + "line": 481, + "text": "C5: Sandbox inference.local chat completion returned mock content", + "polarity": "pass", + "normalized_id": "c5.sandbox.inference.local.chat.completion.returned.mock.content", + "mapping_status": "mapped" + }, + { + "script": "test/e2e/test-messaging-compatible-endpoint.sh", + "line": 483, + "text": "C5: Sandbox inference.local chat completion failed (${response:0:400})", + "polarity": "fail", + "normalized_id": "c5.sandbox.inference.local.chat.completion.failed.response.0.400", + "mapping_status": "mapped" + }, + { + "script": "test/e2e/test-messaging-compatible-endpoint.sh", + "line": 501, + "text": "C8: openclaw agent turn — could not get SSH config", + "polarity": "fail", + "normalized_id": "c8.openclaw.agent.turn.could.not.get.ssh.config", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-messaging-compatible-endpoint.sh", + "line": 524, + "text": "C8: openclaw agent turn failed with provider/transport error (exit ${rc}): ${raw:0:300}", + "polarity": "fail", + "normalized_id": "c8.openclaw.agent.turn.failed.with.provider.transport.error.exit.rc.raw.0.300", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-messaging-compatible-endpoint.sh", + "line": 543, + "text": "C8: openclaw agent completed turn via compatible endpoint (http-proxy-fix.js FORWARD-mode path exercised)", + "polarity": "pass", + "normalized_id": "c8.openclaw.agent.completed.turn.via.compatible.endpoint.http.proxy.fix.js.forward.mode.path.exercised", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-messaging-compatible-endpoint.sh", + "line": 545, + "text": "C8: openclaw agent turn failed (exit ${rc}); reply='${reply:0:200}', raw='${raw:0:200}'", + "polarity": "fail", + "normalized_id": "c8.openclaw.agent.turn.failed.exit.rc.reply.reply.0.200.raw.raw.0.200", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-messaging-compatible-endpoint.sh", + "line": 558, + "text": "C9: Mock logged no proxy_hop_headers line for the agent turn — agent did not reach /v1/chat/completions", + "polarity": "fail", + "normalized_id": "c9.mock.logged.no.proxy.hop.headers.line.for.the.agent.turn.agent.did.not.reach.v1.chat.completions", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-messaging-compatible-endpoint.sh", + "line": 565, + "text": "C9: No proxy hop headers leaked to the compatible endpoint upstream (http-proxy-fix.js strip verified)", + "polarity": "pass", + "normalized_id": "c9.no.proxy.hop.headers.leaked.to.the.compatible.endpoint.upstream.http.proxy.fix.js.strip.verified", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-messaging-compatible-endpoint.sh", + "line": 567, + "text": "C9: Proxy hop headers leaked to upstream — http-proxy-fix.js strip broken: ${leaked}", + "polarity": "fail", + "normalized_id": "c9.proxy.hop.headers.leaked.to.upstream.http.proxy.fix.js.strip.broken.leaked", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-messaging-compatible-endpoint.sh", + "line": 612, + "text": "Docker is not running", + "polarity": "fail", + "normalized_id": "docker.is.not.running", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-messaging-compatible-endpoint.sh", + "line": 615, + "text": "Docker is running", + "polarity": "pass", + "normalized_id": "docker.is.running", + "mapping_status": "mapped" + }, + { + "script": "test/e2e/test-messaging-compatible-endpoint.sh", + "line": 618, + "text": "python3 not found", + "polarity": "fail", + "normalized_id": "python3.not.found", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-messaging-compatible-endpoint.sh", + "line": 621, + "text": "python3 is available", + "polarity": "pass", + "normalized_id": "python3.is.available", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-messaging-compatible-endpoint.sh", + "line": 633, + "text": "C0: Compatible endpoint mock started", + "polarity": "pass", + "normalized_id": "c0.compatible.endpoint.mock.started", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-messaging-compatible-endpoint.sh", + "line": 635, + "text": "C0: Compatible endpoint mock failed to start", + "polarity": "fail", + "normalized_id": "c0.compatible.endpoint.mock.failed.to.start", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-messaging-compatible-endpoint.sh", + "line": 642, + "text": "C0b: Compatible endpoint mock is reachable through host address", + "polarity": "pass", + "normalized_id": "c0b.compatible.endpoint.mock.is.reachable.through.host.address", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-messaging-compatible-endpoint.sh", + "line": 644, + "text": "C0b: Compatible endpoint mock is not reachable at ${COMPAT_ENDPOINT_URL}", + "polarity": "fail", + "normalized_id": "c0b.compatible.endpoint.mock.is.not.reachable.at.compat.endpoint.url", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-messaging-compatible-endpoint.sh", + "line": 652, + "text": "C2: Onboard ran the compatible endpoint sandbox smoke check", + "polarity": "pass", + "normalized_id": "c2.onboard.ran.the.compatible.endpoint.sandbox.smoke.check", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-messaging-compatible-endpoint.sh", + "line": 654, + "text": "C2: Onboard log does not show the compatible endpoint sandbox smoke check", + "polarity": "fail", + "normalized_id": "c2.onboard.log.does.not.show.the.compatible.endpoint.sandbox.smoke.check", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-messaging-compatible-endpoint.sh", + "line": 659, + "text": "C2b: Gateway has the compatible-endpoint provider", + "polarity": "pass", + "normalized_id": "c2b.gateway.has.the.compatible.endpoint.provider", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-messaging-compatible-endpoint.sh", + "line": 661, + "text": "C2b: Gateway is missing the compatible-endpoint provider", + "polarity": "fail", + "normalized_id": "c2b.gateway.is.missing.the.compatible.endpoint.provider", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-messaging-compatible-endpoint.sh", + "line": 670, + "text": "C6: Compatible mock received authenticated chat traffic", + "polarity": "pass", + "normalized_id": "c6.compatible.mock.received.authenticated.chat.traffic", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-messaging-compatible-endpoint.sh", + "line": 672, + "text": "C6: Compatible mock did not record authenticated chat traffic", + "polarity": "fail", + "normalized_id": "c6.compatible.mock.did.not.record.authenticated.chat.traffic", + "mapping_status": "deferred" + } + ] + }, + { + "script": "test/e2e/test-messaging-providers.sh", + "assertions": [ + { + "script": "test/e2e/test-messaging-providers.sh", + "line": 180, + "text": "NVIDIA_API_KEY not set", + "polarity": "fail", + "normalized_id": "nvidia.api.key.not.set", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-messaging-providers.sh", + "line": 183, + "text": "NVIDIA_API_KEY is set", + "polarity": "pass", + "normalized_id": "nvidia.api.key.is.set", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-messaging-providers.sh", + "line": 186, + "text": "Docker is not running", + "polarity": "fail", + "normalized_id": "docker.is.not.running", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-messaging-providers.sh", + "line": 189, + "text": "Docker is running", + "polarity": "pass", + "normalized_id": "docker.is.running", + "mapping_status": "mapped" + }, + { + "script": "test/e2e/test-messaging-providers.sh", + "line": 213, + "text": "Pre-cleanup complete", + "polarity": "pass", + "normalized_id": "pre.cleanup.complete", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-messaging-providers.sh", + "line": 293, + "text": "Failed to append Slack policy to base sandbox policy", + "polarity": "fail", + "normalized_id": "failed.to.append.slack.policy.to.base.sandbox.policy", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-messaging-providers.sh", + "line": 296, + "text": "Slack network policy pre-merged into base policy", + "polarity": "pass", + "normalized_id": "slack.network.policy.pre.merged.into.base.policy", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-messaging-providers.sh", + "line": 301, + "text": "Cannot pre-merge Slack policy: missing base policy or preset file", + "polarity": "fail", + "normalized_id": "cannot.pre.merge.slack.policy.missing.base.policy.or.preset.file", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-messaging-providers.sh", + "line": 342, + "text": "M0: install.sh completed (exit 0)", + "polarity": "pass", + "normalized_id": "m0.install.sh.completed.exit.0", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-messaging-providers.sh", + "line": 344, + "text": "M0: install.sh failed (exit $install_exit)", + "polarity": "fail", + "normalized_id": "m0.install.sh.failed.exit.install.exit", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-messaging-providers.sh", + "line": 352, + "text": "openshell not found on PATH after install", + "polarity": "fail", + "normalized_id": "openshell.not.found.on.path.after.install", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-messaging-providers.sh", + "line": 355, + "text": "openshell installed ($(openshell --version 2>&1 || echo unknown))", + "polarity": "pass", + "normalized_id": "openshell.installed.openshell.version.2.1.echo.unknown", + "mapping_status": "mapped" + }, + { + "script": "test/e2e/test-messaging-providers.sh", + "line": 358, + "text": "nemoclaw not found on PATH after install", + "polarity": "fail", + "normalized_id": "nemoclaw.not.found.on.path.after.install", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-messaging-providers.sh", + "line": 361, + "text": "nemoclaw installed at $(command -v nemoclaw)", + "polarity": "pass", + "normalized_id": "nemoclaw.installed.at.command.v.nemoclaw", + "mapping_status": "mapped" + }, + { + "script": "test/e2e/test-messaging-providers.sh", + "line": 366, + "text": "M0b: Sandbox '$SANDBOX_NAME' is Ready", + "polarity": "pass", + "normalized_id": "m0b.sandbox.sandbox.name.is.ready", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-messaging-providers.sh", + "line": 368, + "text": "M0b: Sandbox '$SANDBOX_NAME' not Ready (list: ${sandbox_list:0:200})", + "polarity": "fail", + "normalized_id": "m0b.sandbox.sandbox.name.not.ready.list.sandbox.list.0.200", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-messaging-providers.sh", + "line": 374, + "text": "M1: Provider '${SANDBOX_NAME}-telegram-bridge' exists in gateway", + "polarity": "pass", + "normalized_id": "m1.provider.sandbox.name.telegram.bridge.exists.in.gateway", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-messaging-providers.sh", + "line": 376, + "text": "M1: Provider '${SANDBOX_NAME}-telegram-bridge' not found in gateway", + "polarity": "fail", + "normalized_id": "m1.provider.sandbox.name.telegram.bridge.not.found.in.gateway", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-messaging-providers.sh", + "line": 381, + "text": "M2: Provider '${SANDBOX_NAME}-discord-bridge' exists in gateway", + "polarity": "pass", + "normalized_id": "m2.provider.sandbox.name.discord.bridge.exists.in.gateway", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-messaging-providers.sh", + "line": 383, + "text": "M2: Provider '${SANDBOX_NAME}-discord-bridge' not found in gateway", + "polarity": "fail", + "normalized_id": "m2.provider.sandbox.name.discord.bridge.not.found.in.gateway", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-messaging-providers.sh", + "line": 397, + "text": "M3: Real Telegram token leaked into sandbox env", + "polarity": "fail", + "normalized_id": "m3.real.telegram.token.leaked.into.sandbox.env", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-messaging-providers.sh", + "line": 399, + "text": "M3: Sandbox TELEGRAM_BOT_TOKEN is a placeholder (not the real token)", + "polarity": "pass", + "normalized_id": "m3.sandbox.telegram.bot.token.is.a.placeholder.not.the.real.token", + "mapping_status": "retired" + }, + { + "script": "test/e2e/test-messaging-providers.sh", + "line": 410, + "text": "M4: Real Discord token leaked into sandbox env", + "polarity": "fail", + "normalized_id": "m4.real.discord.token.leaked.into.sandbox.env", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-messaging-providers.sh", + "line": 412, + "text": "M4: Sandbox DISCORD_BOT_TOKEN is a placeholder (not the real token)", + "polarity": "pass", + "normalized_id": "m4.sandbox.discord.bot.token.is.a.placeholder.not.the.real.token", + "mapping_status": "retired" + }, + { + "script": "test/e2e/test-messaging-providers.sh", + "line": 419, + "text": "M5: At least one messaging placeholder detected in sandbox", + "polarity": "pass", + "normalized_id": "m5.at.least.one.messaging.placeholder.detected.in.sandbox", + "mapping_status": "retired" + }, + { + "script": "test/e2e/test-messaging-providers.sh", + "line": 444, + "text": "M5a: Real Telegram token found in full sandbox environment dump", + "polarity": "fail", + "normalized_id": "m5a.real.telegram.token.found.in.full.sandbox.environment.dump", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-messaging-providers.sh", + "line": 446, + "text": "M5a: Real Telegram token absent from full sandbox environment", + "polarity": "pass", + "normalized_id": "m5a.real.telegram.token.absent.from.full.sandbox.environment", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-messaging-providers.sh", + "line": 453, + "text": "M5b: Real Telegram token found in sandbox process list", + "polarity": "fail", + "normalized_id": "m5b.real.telegram.token.found.in.sandbox.process.list", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-messaging-providers.sh", + "line": 455, + "text": "M5b: Real Telegram token absent from sandbox process list", + "polarity": "pass", + "normalized_id": "m5b.real.telegram.token.absent.from.sandbox.process.list", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-messaging-providers.sh", + "line": 462, + "text": "M5c: Real Telegram token found on sandbox filesystem: ${sandbox_fs_tg}", + "polarity": "fail", + "normalized_id": "m5c.real.telegram.token.found.on.sandbox.filesystem.sandbox.fs.tg", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-messaging-providers.sh", + "line": 464, + "text": "M5c: Real Telegram token absent from sandbox filesystem", + "polarity": "pass", + "normalized_id": "m5c.real.telegram.token.absent.from.sandbox.filesystem", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-messaging-providers.sh", + "line": 470, + "text": "M5d: Telegram placeholder confirmed present in sandbox environment", + "polarity": "pass", + "normalized_id": "m5d.telegram.placeholder.confirmed.present.in.sandbox.environment", + "mapping_status": "retired" + }, + { + "script": "test/e2e/test-messaging-providers.sh", + "line": 472, + "text": "M5d: Telegram placeholder not found in sandbox environment", + "polarity": "fail", + "normalized_id": "m5d.telegram.placeholder.not.found.in.sandbox.environment", + "mapping_status": "retired" + }, + { + "script": "test/e2e/test-messaging-providers.sh", + "line": 482, + "text": "M5e: Real Discord token found in full sandbox environment dump", + "polarity": "fail", + "normalized_id": "m5e.real.discord.token.found.in.full.sandbox.environment.dump", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-messaging-providers.sh", + "line": 484, + "text": "M5e: Real Discord token absent from full sandbox environment", + "polarity": "pass", + "normalized_id": "m5e.real.discord.token.absent.from.full.sandbox.environment", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-messaging-providers.sh", + "line": 491, + "text": "M5f: Real Discord token found in sandbox process list", + "polarity": "fail", + "normalized_id": "m5f.real.discord.token.found.in.sandbox.process.list", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-messaging-providers.sh", + "line": 493, + "text": "M5f: Real Discord token absent from sandbox process list", + "polarity": "pass", + "normalized_id": "m5f.real.discord.token.absent.from.sandbox.process.list", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-messaging-providers.sh", + "line": 499, + "text": "M5g: Real Discord token found on sandbox filesystem: ${sandbox_fs_dc}", + "polarity": "fail", + "normalized_id": "m5g.real.discord.token.found.on.sandbox.filesystem.sandbox.fs.dc", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-messaging-providers.sh", + "line": 501, + "text": "M5g: Real Discord token absent from sandbox filesystem", + "polarity": "pass", + "normalized_id": "m5g.real.discord.token.absent.from.sandbox.filesystem", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-messaging-providers.sh", + "line": 507, + "text": "M5h: Discord placeholder confirmed present in sandbox environment", + "polarity": "pass", + "normalized_id": "m5h.discord.placeholder.confirmed.present.in.sandbox.environment", + "mapping_status": "retired" + }, + { + "script": "test/e2e/test-messaging-providers.sh", + "line": 509, + "text": "M5h: Discord placeholder not found in sandbox environment", + "polarity": "fail", + "normalized_id": "m5h.discord.placeholder.not.found.in.sandbox.environment", + "mapping_status": "retired" + }, + { + "script": "test/e2e/test-messaging-providers.sh", + "line": 524, + "text": "M-S5a: Real Slack bot token found in full sandbox environment dump", + "polarity": "fail", + "normalized_id": "m.s5a.real.slack.bot.token.found.in.full.sandbox.environment.dump", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-messaging-providers.sh", + "line": 526, + "text": "M-S5a: Real Slack bot token absent from full sandbox environment", + "polarity": "pass", + "normalized_id": "m.s5a.real.slack.bot.token.absent.from.full.sandbox.environment", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-messaging-providers.sh", + "line": 533, + "text": "M-S5b: Real Slack bot token found in sandbox process list", + "polarity": "fail", + "normalized_id": "m.s5b.real.slack.bot.token.found.in.sandbox.process.list", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-messaging-providers.sh", + "line": 535, + "text": "M-S5b: Real Slack bot token absent from sandbox process list", + "polarity": "pass", + "normalized_id": "m.s5b.real.slack.bot.token.absent.from.sandbox.process.list", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-messaging-providers.sh", + "line": 541, + "text": "M-S5c: Real Slack bot token found on sandbox filesystem: ${sandbox_fs_sl}", + "polarity": "fail", + "normalized_id": "m.s5c.real.slack.bot.token.found.on.sandbox.filesystem.sandbox.fs.sl", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-messaging-providers.sh", + "line": 543, + "text": "M-S5c: Real Slack bot token absent from sandbox filesystem", + "polarity": "pass", + "normalized_id": "m.s5c.real.slack.bot.token.absent.from.sandbox.filesystem", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-messaging-providers.sh", + "line": 551, + "text": "M-S5d: Real Slack app token found in full sandbox environment dump", + "polarity": "fail", + "normalized_id": "m.s5d.real.slack.app.token.found.in.full.sandbox.environment.dump", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-messaging-providers.sh", + "line": 553, + "text": "M-S5d: Real Slack app token absent from sandbox environment", + "polarity": "pass", + "normalized_id": "m.s5d.real.slack.app.token.absent.from.sandbox.environment", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-messaging-providers.sh", + "line": 558, + "text": "M-S5d2: Real Slack app token found in sandbox process list", + "polarity": "fail", + "normalized_id": "m.s5d2.real.slack.app.token.found.in.sandbox.process.list", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-messaging-providers.sh", + "line": 560, + "text": "M-S5d2: Real Slack app token absent from sandbox process list", + "polarity": "pass", + "normalized_id": "m.s5d2.real.slack.app.token.absent.from.sandbox.process.list", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-messaging-providers.sh", + "line": 564, + "text": "M-S5e: Real Slack app token found on sandbox filesystem: ${sandbox_fs_sapp}", + "polarity": "fail", + "normalized_id": "m.s5e.real.slack.app.token.found.on.sandbox.filesystem.sandbox.fs.sapp", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-messaging-providers.sh", + "line": 566, + "text": "M-S5e: Real Slack app token absent from sandbox filesystem", + "polarity": "pass", + "normalized_id": "m.s5e.real.slack.app.token.absent.from.sandbox.filesystem", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-messaging-providers.sh", + "line": 577, + "text": "M-S5f: Real Slack bot/app token spliced into openclaw.json — apply_slack_token_override regression?", + "polarity": "fail", + "normalized_id": "m.s5f.real.slack.bot.app.token.spliced.into.openclaw.json.apply.slack.token.override.regression", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-messaging-providers.sh", + "line": 581, + "text": "M-S5f: openclaw.json holds both Bolt-shape Slack placeholders (no real token on disk)", + "polarity": "pass", + "normalized_id": "m.s5f.openclaw.json.holds.both.bolt.shape.slack.placeholders.no.real.token.on.disk", + "mapping_status": "retired" + }, + { + "script": "test/e2e/test-messaging-providers.sh", + "line": 590, + "text": "M-S5g: removed Slack token rewriter preload still present in NODE_OPTIONS", + "polarity": "fail", + "normalized_id": "m.s5g.removed.slack.token.rewriter.preload.still.present.in.node.options", + "mapping_status": "retired" + }, + { + "script": "test/e2e/test-messaging-providers.sh", + "line": 592, + "text": "M-S5g: Slack token rewriter preload absent from NODE_OPTIONS", + "polarity": "pass", + "normalized_id": "m.s5g.slack.token.rewriter.preload.absent.from.node.options", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-messaging-providers.sh", + "line": 612, + "text": "M6: Could not read openclaw.json channels (${channel_json:0:200})", + "polarity": "fail", + "normalized_id": "m6.could.not.read.openclaw.json.channels.channel.json.0.200", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-messaging-providers.sh", + "line": 629, + "text": "M6: Telegram channel botToken present in openclaw.json", + "polarity": "pass", + "normalized_id": "m6.telegram.channel.bottoken.present.in.openclaw.json", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-messaging-providers.sh", + "line": 636, + "text": "M7: Telegram botToken is not the host-side token (placeholder confirmed)", + "polarity": "pass", + "normalized_id": "m7.telegram.bottoken.is.not.the.host.side.token.placeholder.confirmed", + "mapping_status": "retired" + }, + { + "script": "test/e2e/test-messaging-providers.sh", + "line": 638, + "text": "M7: Telegram botToken matches host-side token — credential leaked into config!", + "polarity": "fail", + "normalized_id": "m7.telegram.bottoken.matches.host.side.token.credential.leaked.into.config", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-messaging-providers.sh", + "line": 653, + "text": "M8: Discord channel token present in openclaw.json", + "polarity": "pass", + "normalized_id": "m8.discord.channel.token.present.in.openclaw.json", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-messaging-providers.sh", + "line": 660, + "text": "M9: Discord token is not the host-side token (placeholder confirmed)", + "polarity": "pass", + "normalized_id": "m9.discord.token.is.not.the.host.side.token.placeholder.confirmed", + "mapping_status": "retired" + }, + { + "script": "test/e2e/test-messaging-providers.sh", + "line": 662, + "text": "M9: Discord token matches host-side token — credential leaked into config!", + "polarity": "fail", + "normalized_id": "m9.discord.token.matches.host.side.token.credential.leaked.into.config", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-messaging-providers.sh", + "line": 677, + "text": "M10: Telegram channel is enabled", + "polarity": "pass", + "normalized_id": "m10.telegram.channel.is.enabled", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-messaging-providers.sh", + "line": 692, + "text": "M11: Discord channel is enabled", + "polarity": "pass", + "normalized_id": "m11.discord.channel.is.enabled", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-messaging-providers.sh", + "line": 707, + "text": "M11b: Telegram dmPolicy is 'allowlist'", + "polarity": "pass", + "normalized_id": "m11b.telegram.dmpolicy.is.allowlist", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-messaging-providers.sh", + "line": 709, + "text": "M11b: Telegram dmPolicy is '$tg_dm_policy' (expected 'allowlist')", + "polarity": "fail", + "normalized_id": "m11b.telegram.dmpolicy.is.tg.dm.policy.expected.allowlist", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-messaging-providers.sh", + "line": 737, + "text": "M11c: Telegram allowFrom contains all expected user IDs: $tg_allow_from", + "polarity": "pass", + "normalized_id": "m11c.telegram.allowfrom.contains.all.expected.user.ids.tg.allow.from", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-messaging-providers.sh", + "line": 739, + "text": "M11c: Telegram allowFrom ($tg_allow_from) is missing IDs: ${missing_ids[*]} (expected all of: $TELEGRAM_IDS)", + "polarity": "fail", + "normalized_id": "m11c.telegram.allowfrom.tg.allow.from.is.missing.ids.missing.ids.expected.all.of.telegram.ids", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-messaging-providers.sh", + "line": 755, + "text": "M11d: Telegram groupPolicy is 'open'", + "polarity": "pass", + "normalized_id": "m11d.telegram.grouppolicy.is.open", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-messaging-providers.sh", + "line": 757, + "text": "M11d: Telegram groupPolicy is '$tg_group_policy' (expected 'open')", + "polarity": "fail", + "normalized_id": "m11d.telegram.grouppolicy.is.tg.group.policy.expected.open", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-messaging-providers.sh", + "line": 773, + "text": "M11e: Slack channel configured with placeholder tokens (guard needed)", + "polarity": "pass", + "normalized_id": "m11e.slack.channel.configured.with.placeholder.tokens.guard.needed", + "mapping_status": "retired" + }, + { + "script": "test/e2e/test-messaging-providers.sh", + "line": 803, + "text": "M12: Node.js reached api.telegram.org (${tg_reach})", + "polarity": "pass", + "normalized_id": "m12.node.js.reached.api.telegram.org.tg.reach", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-messaging-providers.sh", + "line": 809, + "text": "M12: Node.js could not reach api.telegram.org (${tg_reach:0:200})", + "polarity": "fail", + "normalized_id": "m12.node.js.could.not.reach.api.telegram.org.tg.reach.0.200", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-messaging-providers.sh", + "line": 824, + "text": "M13: Node.js reached discord.com (${dc_reach})", + "polarity": "pass", + "normalized_id": "m13.node.js.reached.discord.com.dc.reach", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-messaging-providers.sh", + "line": 828, + "text": "M13: Node.js could not reach discord.com (${dc_reach:0:200})", + "polarity": "fail", + "normalized_id": "m13.node.js.could.not.reach.discord.com.dc.reach.0.200", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-messaging-providers.sh", + "line": 835, + "text": "M13b: Hermetic fake Discord Gateway started on host port ${FAKE_DISCORD_GATEWAY_PORT}", + "polarity": "pass", + "normalized_id": "m13b.hermetic.fake.discord.gateway.started.on.host.port.fake.discord.gateway.port", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-messaging-providers.sh", + "line": 837, + "text": "M13b: Failed to start hermetic fake Discord Gateway", + "polarity": "fail", + "normalized_id": "m13b.failed.to.start.hermetic.fake.discord.gateway", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-messaging-providers.sh", + "line": 842, + "text": "M13c: Applied native WebSocket policy with credential rewrite for fake Discord Gateway", + "polarity": "pass", + "normalized_id": "m13c.applied.native.websocket.policy.with.credential.rewrite.for.fake.discord.gateway", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-messaging-providers.sh", + "line": 844, + "text": "M13c: Failed to apply fake Discord Gateway policy: $(tail -20 /tmp/nemoclaw-fake-discord-policy.log 2>/dev/null | tr '\\n' ' ' | cut -c1-300)", + "polarity": "fail", + "normalized_id": "m13c.failed.to.apply.fake.discord.gateway.policy.tail.20.tmp.nemoclaw.fake.discord.policy.log.2.dev.null.tr.n.cut.c1.300", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-messaging-providers.sh", + "line": 854, + "text": "M13d: Native WebSocket upgrade reached fake Discord Gateway through OpenShell", + "polarity": "pass", + "normalized_id": "m13d.native.websocket.upgrade.reached.fake.discord.gateway.through.openshell", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-messaging-providers.sh", + "line": 856, + "text": "M13d: Native WebSocket upgrade failed: ${dc_ws_native:0:300}", + "polarity": "fail", + "normalized_id": "m13d.native.websocket.upgrade.failed.dc.ws.native.0.300", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-messaging-providers.sh", + "line": 863, + "text": "M13e: Discord HELLO, placeholder IDENTIFY, READY, and heartbeat ACK completed", + "polarity": "pass", + "normalized_id": "m13e.discord.hello.placeholder.identify.ready.and.heartbeat.ack.completed", + "mapping_status": "retired" + }, + { + "script": "test/e2e/test-messaging-providers.sh", + "line": 865, + "text": "M13e: Discord Gateway protocol proof incomplete: ${dc_ws_native:0:400}", + "polarity": "fail", + "normalized_id": "m13e.discord.gateway.protocol.proof.incomplete.dc.ws.native.0.400", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-messaging-providers.sh", + "line": 871, + "text": "M13f: Fake Gateway received host-side Discord token; sandbox-visible IDENTIFY used only the placeholder", + "polarity": "pass", + "normalized_id": "m13f.fake.gateway.received.host.side.discord.token.sandbox.visible.identify.used.only.the.placeholder", + "mapping_status": "retired" + }, + { + "script": "test/e2e/test-messaging-providers.sh", + "line": 876, + "text": "M13f: Fake Gateway did not prove placeholder-to-token rewrite at the relay boundary", + "polarity": "fail", + "normalized_id": "m13f.fake.gateway.did.not.prove.placeholder.to.token.rewrite.at.the.relay.boundary", + "mapping_status": "retired" + }, + { + "script": "test/e2e/test-messaging-providers.sh", + "line": 892, + "text": "M13g: Unregistered Discord WebSocket placeholder is rejected before upstream token exposure", + "polarity": "pass", + "normalized_id": "m13g.unregistered.discord.websocket.placeholder.is.rejected.before.upstream.token.exposure", + "mapping_status": "retired" + }, + { + "script": "test/e2e/test-messaging-providers.sh", + "line": 894, + "text": "M13g: Unregistered Discord WebSocket placeholder reached READY or leaked upstream", + "polarity": "fail", + "normalized_id": "m13g.unregistered.discord.websocket.placeholder.reached.ready.or.leaked.upstream", + "mapping_status": "retired" + }, + { + "script": "test/e2e/test-messaging-providers.sh", + "line": 900, + "text": "M14: curl to api.telegram.org blocked (binary restriction enforced)", + "polarity": "pass", + "normalized_id": "m14.curl.to.api.telegram.org.blocked.binary.restriction.enforced", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-messaging-providers.sh", + "line": 902, + "text": "M14: curl returned empty (likely blocked by policy)", + "polarity": "pass", + "normalized_id": "m14.curl.returned.empty.likely.blocked.by.policy", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-messaging-providers.sh", + "line": 906, + "text": "M14: curl not available in sandbox (defense in depth)", + "polarity": "pass", + "normalized_id": "m14.curl.not.available.in.sandbox.defense.in.depth", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-messaging-providers.sh", + "line": 940, + "text": "M15: Telegram getMe returned 200 — real token verified!", + "polarity": "pass", + "normalized_id": "m15.telegram.getme.returned.200.real.token.verified", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-messaging-providers.sh", + "line": 945, + "text": "M15: Telegram getMe returned $tg_status — L7 proxy rewrote placeholder (fake token rejected by API)", + "polarity": "pass", + "normalized_id": "m15.telegram.getme.returned.tg.status.l7.proxy.rewrote.placeholder.fake.token.rejected.by.api", + "mapping_status": "retired" + }, + { + "script": "test/e2e/test-messaging-providers.sh", + "line": 946, + "text": "M16: Full chain verified: sandbox → proxy → token rewrite → Telegram API", + "polarity": "pass", + "normalized_id": "m16.full.chain.verified.sandbox.proxy.token.rewrite.telegram.api", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-messaging-providers.sh", + "line": 952, + "text": "M15: Telegram API call failed with error: ${tg_api:0:200}", + "polarity": "fail", + "normalized_id": "m15.telegram.api.call.failed.with.error.tg.api.0.200", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-messaging-providers.sh", + "line": 954, + "text": "M15: Unexpected Telegram response (status=$tg_status): ${tg_api:0:200}", + "polarity": "fail", + "normalized_id": "m15.unexpected.telegram.response.status.tg.status.tg.api.0.200", + "mapping_status": "retired" + }, + { + "script": "test/e2e/test-messaging-providers.sh", + "line": 981, + "text": "M17: Discord users/@me returned 200 — real token verified!", + "polarity": "pass", + "normalized_id": "m17.discord.users.me.returned.200.real.token.verified", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-messaging-providers.sh", + "line": 983, + "text": "M17: Discord users/@me returned 401 — L7 proxy rewrote placeholder (fake token rejected by API)", + "polarity": "pass", + "normalized_id": "m17.discord.users.me.returned.401.l7.proxy.rewrote.placeholder.fake.token.rejected.by.api", + "mapping_status": "retired" + }, + { + "script": "test/e2e/test-messaging-providers.sh", + "line": 987, + "text": "M17: Discord API call failed with error: ${dc_api:0:200}", + "polarity": "fail", + "normalized_id": "m17.discord.api.call.failed.with.error.dc.api.0.200", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-messaging-providers.sh", + "line": 989, + "text": "M17: Unexpected Discord response (status=$dc_status): ${dc_api:0:200}", + "polarity": "fail", + "normalized_id": "m17.unexpected.discord.response.status.dc.status.dc.api.0.200", + "mapping_status": "retired" + }, + { + "script": "test/e2e/test-messaging-providers.sh", + "line": 1001, + "text": "M-S14a: Hermetic fake Slack API started on host port ${FAKE_SLACK_API_PORT}", + "polarity": "pass", + "normalized_id": "m.s14a.hermetic.fake.slack.api.started.on.host.port.fake.slack.api.port", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-messaging-providers.sh", + "line": 1003, + "text": "M-S14a: Failed to start hermetic fake Slack API", + "polarity": "fail", + "normalized_id": "m.s14a.failed.to.start.hermetic.fake.slack.api", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-messaging-providers.sh", + "line": 1008, + "text": "M-S14b: Applied REST policy for hermetic fake Slack API", + "polarity": "pass", + "normalized_id": "m.s14b.applied.rest.policy.for.hermetic.fake.slack.api", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-messaging-providers.sh", + "line": 1010, + "text": "M-S14b: Failed to apply fake Slack API policy: $(tail -20 /tmp/nemoclaw-fake-slack-policy.log 2>/dev/null | tr '\\n' ' ' | cut -c1-300)", + "polarity": "fail", + "normalized_id": "m.s14b.failed.to.apply.fake.slack.api.policy.tail.20.tmp.nemoclaw.fake.slack.policy.log.2.dev.null.tr.n.cut.c1.300", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-messaging-providers.sh", + "line": 1061, + "text": "M-S15: Slack auth.test returned ok:true — real token round-trip verified!", + "polarity": "pass", + "normalized_id": "m.s15.slack.auth.test.returned.ok.true.real.token.round.trip.verified", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-messaging-providers.sh", + "line": 1063, + "text": "M-S15: Slack auth.test returned invalid_auth — full chain verified (OpenShell alias rewrite → fake Slack)", + "polarity": "pass", + "normalized_id": "m.s15.slack.auth.test.returned.invalid.auth.full.chain.verified.openshell.alias.rewrite.fake.slack", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-messaging-providers.sh", + "line": 1066, + "text": "M-S15a: fake Slack saw host-side bot token in header and urlencoded body", + "polarity": "pass", + "normalized_id": "m.s15a.fake.slack.saw.host.side.bot.token.in.header.and.urlencoded.body", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-messaging-providers.sh", + "line": 1068, + "text": "M-S15a: fake Slack capture did not prove bot header/body rewrite: ${sl_capture:0:300}", + "polarity": "fail", + "normalized_id": "m.s15a.fake.slack.capture.did.not.prove.bot.header.body.rewrite.sl.capture.0.300", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-messaging-providers.sh", + "line": 1073, + "text": "M-S15: Slack API call failed with error: ${sl_api:0:200}", + "polarity": "fail", + "normalized_id": "m.s15.slack.api.call.failed.with.error.sl.api.0.200", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-messaging-providers.sh", + "line": 1075, + "text": "M-S15: OpenShell did not resolve the Bolt-shape alias", + "polarity": "fail", + "normalized_id": "m.s15.openshell.did.not.resolve.the.bolt.shape.alias", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-messaging-providers.sh", + "line": 1077, + "text": "M-S15: L7 proxy did not substitute the canonical placeholder — substitution chain broken", + "polarity": "fail", + "normalized_id": "m.s15.l7.proxy.did.not.substitute.the.canonical.placeholder.substitution.chain.broken", + "mapping_status": "retired" + }, + { + "script": "test/e2e/test-messaging-providers.sh", + "line": 1079, + "text": "M-S15: Unexpected Slack response (status=$sl_status): ${sl_api:0:200}", + "polarity": "fail", + "normalized_id": "m.s15.unexpected.slack.response.status.sl.status.sl.api.0.200", + "mapping_status": "retired" + }, + { + "script": "test/e2e/test-messaging-providers.sh", + "line": 1100, + "text": "M-S15b: L7 proxy substitutes openshell:resolve:env:SLACK_BOT_TOKEN at egress (parallels Telegram M15 / Discord M17)", + "polarity": "pass", + "normalized_id": "m.s15b.l7.proxy.substitutes.openshell.resolve.env.slack.bot.token.at.egress.parallels.telegram.m15.discord.m17", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-messaging-providers.sh", + "line": 1104, + "text": "M-S15b: L7 proxy passed canonical placeholder through unchanged — substitution not happening for SLACK_BOT_TOKEN", + "polarity": "fail", + "normalized_id": "m.s15b.l7.proxy.passed.canonical.placeholder.through.unchanged.substitution.not.happening.for.slack.bot.token", + "mapping_status": "retired" + }, + { + "script": "test/e2e/test-messaging-providers.sh", + "line": 1106, + "text": "M-S15b: Unexpected response (status=$sl_canon_status): ${sl_canonical:0:200}", + "polarity": "fail", + "normalized_id": "m.s15b.unexpected.response.status.sl.canon.status.sl.canonical.0.200", + "mapping_status": "retired" + }, + { + "script": "test/e2e/test-messaging-providers.sh", + "line": 1127, + "text": "M-S15c: unset-var failed closed before upstream exposure", + "polarity": "pass", + "normalized_id": "m.s15c.unset.var.failed.closed.before.upstream.exposure", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-messaging-providers.sh", + "line": 1129, + "text": "M-S15c: unset-var triggered connection-level failure — proxy refuses to forward unsubstituted placeholder", + "polarity": "pass", + "normalized_id": "m.s15c.unset.var.triggered.connection.level.failure.proxy.refuses.to.forward.unsubstituted.placeholder", + "mapping_status": "retired" + }, + { + "script": "test/e2e/test-messaging-providers.sh", + "line": 1131, + "text": "M-S15c: unset-var returned HTTP 200 — proxy passed canonical placeholder through unchanged for unset env (substitution may be a no-op)", + "polarity": "fail", + "normalized_id": "m.s15c.unset.var.returned.http.200.proxy.passed.canonical.placeholder.through.unchanged.for.unset.env.substitution.may.be.a.no.op", + "mapping_status": "retired" + }, + { + "script": "test/e2e/test-messaging-providers.sh", + "line": 1133, + "text": "M-S15c: unset-var request reached fake Slack — unresolved placeholder escaped the proxy boundary", + "polarity": "fail", + "normalized_id": "m.s15c.unset.var.request.reached.fake.slack.unresolved.placeholder.escaped.the.proxy.boundary", + "mapping_status": "retired" + }, + { + "script": "test/e2e/test-messaging-providers.sh", + "line": 1154, + "text": "M-S16: apps.connections.open returned ok:true — real xapp token round-trip verified!", + "polarity": "pass", + "normalized_id": "m.s16.apps.connections.open.returned.ok.true.real.xapp.token.round.trip.verified", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-messaging-providers.sh", + "line": 1156, + "text": "M-S16: apps.connections.open auth-rejected — Socket Mode HTTPS leg verified (OpenShell alias rewrite → fake Slack)", + "polarity": "pass", + "normalized_id": "m.s16.apps.connections.open.auth.rejected.socket.mode.https.leg.verified.openshell.alias.rewrite.fake.slack", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-messaging-providers.sh", + "line": 1159, + "text": "M-S16a: fake Slack saw host-side app token in header and urlencoded body", + "polarity": "pass", + "normalized_id": "m.s16a.fake.slack.saw.host.side.app.token.in.header.and.urlencoded.body", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-messaging-providers.sh", + "line": 1161, + "text": "M-S16a: fake Slack capture did not prove app header/body rewrite: ${sl_app_capture:0:300}", + "polarity": "fail", + "normalized_id": "m.s16a.fake.slack.capture.did.not.prove.app.header.body.rewrite.sl.app.capture.0.300", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-messaging-providers.sh", + "line": 1166, + "text": "M-S16: OpenShell did not resolve the xapp- alias for Socket Mode path", + "polarity": "fail", + "normalized_id": "m.s16.openshell.did.not.resolve.the.xapp.alias.for.socket.mode.path", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-messaging-providers.sh", + "line": 1168, + "text": "M-S16: Unexpected apps.connections.open response (status=$sl_app_status): ${sl_app_api:0:200}", + "polarity": "fail", + "normalized_id": "m.s16.unexpected.apps.connections.open.response.status.sl.app.status.sl.app.api.0.200", + "mapping_status": "retired" + }, + { + "script": "test/e2e/test-messaging-providers.sh", + "line": 1192, + "text": "M-S16b: unset app-token failed closed before upstream exposure", + "polarity": "pass", + "normalized_id": "m.s16b.unset.app.token.failed.closed.before.upstream.exposure", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-messaging-providers.sh", + "line": 1194, + "text": "M-S16b: L7 proxy substitutes openshell:resolve:env:SLACK_APP_TOKEN at egress (unset-var control diverged)", + "polarity": "pass", + "normalized_id": "m.s16b.l7.proxy.substitutes.openshell.resolve.env.slack.app.token.at.egress.unset.var.control.diverged", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-messaging-providers.sh", + "line": 1196, + "text": "M-S16b: unset app-token env returned HTTP 200 — proxy may be passing canonical placeholders through unchanged", + "polarity": "fail", + "normalized_id": "m.s16b.unset.app.token.env.returned.http.200.proxy.may.be.passing.canonical.placeholders.through.unchanged", + "mapping_status": "retired" + }, + { + "script": "test/e2e/test-messaging-providers.sh", + "line": 1198, + "text": "M-S16b: unset app-token request reached fake Slack — unresolved placeholder escaped the proxy boundary", + "polarity": "fail", + "normalized_id": "m.s16b.unset.app.token.request.reached.fake.slack.unresolved.placeholder.escaped.the.proxy.boundary", + "mapping_status": "retired" + }, + { + "script": "test/e2e/test-messaging-providers.sh", + "line": 1207, + "text": "M-S16b: L7 proxy passed canonical placeholder through unchanged for SLACK_APP_TOKEN", + "polarity": "fail", + "normalized_id": "m.s16b.l7.proxy.passed.canonical.placeholder.through.unchanged.for.slack.app.token", + "mapping_status": "retired" + }, + { + "script": "test/e2e/test-messaging-providers.sh", + "line": 1209, + "text": "M-S16b: Unexpected response (status=$sl_app_canon_status): ${sl_app_canonical:0:200}", + "polarity": "fail", + "normalized_id": "m.s16b.unexpected.response.status.sl.app.canon.status.sl.app.canonical.0.200", + "mapping_status": "retired" + }, + { + "script": "test/e2e/test-messaging-providers.sh", + "line": 1224, + "text": "M18: Telegram getMe returned 200 with real token", + "polarity": "pass", + "normalized_id": "m18.telegram.getme.returned.200.with.real.token", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-messaging-providers.sh", + "line": 1226, + "text": "M18b: Telegram response contains ok:true", + "polarity": "pass", + "normalized_id": "m18b.telegram.response.contains.ok.true", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-messaging-providers.sh", + "line": 1229, + "text": "M18: Expected Telegram getMe 200 with real token, got: $tg_status", + "polarity": "fail", + "normalized_id": "m18.expected.telegram.getme.200.with.real.token.got.tg.status", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-messaging-providers.sh", + "line": 1259, + "text": "M19: Telegram sendMessage succeeded", + "polarity": "pass", + "normalized_id": "m19.telegram.sendmessage.succeeded", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-messaging-providers.sh", + "line": 1261, + "text": "M19: Telegram sendMessage failed: ${send_result:0:200}", + "polarity": "fail", + "normalized_id": "m19.telegram.sendmessage.failed.send.result.0.200", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-messaging-providers.sh", + "line": 1273, + "text": "M20: Discord users/@me returned 200 with real token", + "polarity": "pass", + "normalized_id": "m20.discord.users.me.returned.200.with.real.token", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-messaging-providers.sh", + "line": 1275, + "text": "M20: Expected Discord users/@me 200 with real token, got: $dc_status", + "polarity": "fail", + "normalized_id": "m20.expected.discord.users.me.200.with.real.token.got.dc.status", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-messaging-providers.sh", + "line": 1307, + "text": "S1: Gateway is serving on port 18789 — Slack auth failure did not crash it", + "polarity": "pass", + "normalized_id": "s1.gateway.is.serving.on.port.18789.slack.auth.failure.did.not.crash.it", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-messaging-providers.sh", + "line": 1309, + "text": "S1: Gateway is not serving on port 18789 (${gw_port:0:200})", + "polarity": "fail", + "normalized_id": "s1.gateway.is.not.serving.on.port.18789.gw.port.0.200", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-messaging-providers.sh", + "line": 1335, + "text": "S2: Gateway log shows Slack rejection was caught by channel guard", + "polarity": "pass", + "normalized_id": "s2.gateway.log.shows.slack.rejection.was.caught.by.channel.guard", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-messaging-providers.sh", + "line": 1360, + "text": "Cleanup: Sandbox '$SANDBOX_NAME' intentionally kept", + "polarity": "pass", + "normalized_id": "cleanup.sandbox.sandbox.name.intentionally.kept", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-messaging-providers.sh", + "line": 1362, + "text": "Cleanup: Sandbox '$SANDBOX_NAME' still present after cleanup", + "polarity": "fail", + "normalized_id": "cleanup.sandbox.sandbox.name.still.present.after.cleanup", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-messaging-providers.sh", + "line": 1364, + "text": "Cleanup: Sandbox '$SANDBOX_NAME' removed", + "polarity": "pass", + "normalized_id": "cleanup.sandbox.sandbox.name.removed", + "mapping_status": "retired" + } + ] + }, + { + "script": "test/e2e/test-network-policy.sh", + "assertions": [ + { + "script": "test/e2e/test-network-policy.sh", + "line": 241, + "text": "TC-NET-01: Non-whitelisted URL blocked ($response)", + "polarity": "pass", + "normalized_id": "tc.net.01.non.whitelisted.url.blocked.response", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-network-policy.sh", + "line": 243, + "text": "TC-NET-01: Deny default", + "polarity": "fail", + "normalized_id": "tc.net.01.deny.default", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-network-policy.sh", + "line": 245, + "text": "TC-NET-01: Deny default", + "polarity": "fail", + "normalized_id": "tc.net.01.deny.default", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-network-policy.sh", + "line": 257, + "text": "TC-NET-02: Setup", + "polarity": "fail", + "normalized_id": "tc.net.02.setup", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-network-policy.sh", + "line": 269, + "text": "TC-NET-02: PyPI reachable via pip after preset applied", + "polarity": "pass", + "normalized_id": "tc.net.02.pypi.reachable.via.pip.after.preset.applied", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-network-policy.sh", + "line": 271, + "text": "TC-NET-02: PyPI reachable via pip (download started)", + "polarity": "pass", + "normalized_id": "tc.net.02.pypi.reachable.via.pip.download.started", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-network-policy.sh", + "line": 273, + "text": "TC-NET-02: Whitelist", + "polarity": "fail", + "normalized_id": "tc.net.02.whitelist", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-network-policy.sh", + "line": 305, + "text": "TC-NET-03: Setup", + "polarity": "fail", + "normalized_id": "tc.net.03.setup", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-network-policy.sh", + "line": 309, + "text": "TC-NET-03: Interactive policy-add", + "polarity": "fail", + "normalized_id": "tc.net.03.interactive.policy.add", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-network-policy.sh", + "line": 325, + "text": "TC-NET-03: Endpoint reachable after live policy-add ($after)", + "polarity": "pass", + "normalized_id": "tc.net.03.endpoint.reachable.after.live.policy.add.after", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-network-policy.sh", + "line": 327, + "text": "TC-NET-03: Live policy-add", + "polarity": "fail", + "normalized_id": "tc.net.03.live.policy.add", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-network-policy.sh", + "line": 329, + "text": "TC-NET-03: Live policy-add", + "polarity": "fail", + "normalized_id": "tc.net.03.live.policy.add", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-network-policy.sh", + "line": 356, + "text": "TC-NET-04: Dry-run printed endpoint info", + "polarity": "pass", + "normalized_id": "tc.net.04.dry.run.printed.endpoint.info", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-network-policy.sh", + "line": 358, + "text": "TC-NET-04: Dry-run output", + "polarity": "fail", + "normalized_id": "tc.net.04.dry.run.output", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-network-policy.sh", + "line": 371, + "text": "TC-NET-04: Policy unchanged after dry-run (blocked: $after)", + "polarity": "pass", + "normalized_id": "tc.net.04.policy.unchanged.after.dry.run.blocked.after", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-network-policy.sh", + "line": 373, + "text": "TC-NET-04: Dry-run side effect", + "polarity": "fail", + "normalized_id": "tc.net.04.dry.run.side.effect", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-network-policy.sh", + "line": 375, + "text": "TC-NET-04: Dry-run verification", + "polarity": "fail", + "normalized_id": "tc.net.04.dry.run.verification", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-network-policy.sh", + "line": 397, + "text": "TC-NET-07: Inference via inference.local succeeded", + "polarity": "pass", + "normalized_id": "tc.net.07.inference.via.inference.local.succeeded", + "mapping_status": "mapped" + }, + { + "script": "test/e2e/test-network-policy.sh", + "line": 399, + "text": "TC-NET-07: Inference", + "polarity": "fail", + "normalized_id": "tc.net.07.inference", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-network-policy.sh", + "line": 414, + "text": "TC-NET-07: Direct provider access blocked ($direct_response)", + "polarity": "pass", + "normalized_id": "tc.net.07.direct.provider.access.blocked.direct.response", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-network-policy.sh", + "line": 416, + "text": "TC-NET-07: Direct provider", + "polarity": "fail", + "normalized_id": "tc.net.07.direct.provider", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-network-policy.sh", + "line": 418, + "text": "TC-NET-07: Direct provider", + "polarity": "fail", + "normalized_id": "tc.net.07.direct.provider", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-network-policy.sh", + "line": 435, + "text": "TC-NET-05: Setup", + "polarity": "fail", + "normalized_id": "tc.net.05.setup", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-network-policy.sh", + "line": 445, + "text": "TC-NET-05: Sandbox start time unchanged after policy-add (no restart)", + "polarity": "pass", + "normalized_id": "tc.net.05.sandbox.start.time.unchanged.after.policy.add.no.restart", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-network-policy.sh", + "line": 449, + "text": "TC-NET-05: Hot-reload", + "polarity": "fail", + "normalized_id": "tc.net.05.hot.reload", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-network-policy.sh", + "line": 471, + "text": "TC-NET-06: Setup", + "polarity": "fail", + "normalized_id": "tc.net.06.setup", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-network-policy.sh", + "line": 482, + "text": "TC-NET-06: npm reachable under permissive policy", + "polarity": "pass", + "normalized_id": "tc.net.06.npm.reachable.under.permissive.policy", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-network-policy.sh", + "line": 484, + "text": "TC-NET-06: Permissive", + "polarity": "fail", + "normalized_id": "tc.net.06.permissive", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-network-policy.sh", + "line": 502, + "text": "+ ip +", + "polarity": "fail", + "normalized_id": "ip", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-network-policy.sh", + "line": 505, + "text": "+ ip +", + "polarity": "fail", + "normalized_id": "ip", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-network-policy.sh", + "line": 513, + "text": "TC-NET-09: SSRF validation correctly blocks dangerous IPs", + "polarity": "pass", + "normalized_id": "tc.net.09.ssrf.validation.correctly.blocks.dangerous.ips", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-network-policy.sh", + "line": 515, + "text": "TC-NET-09: SSRF", + "polarity": "fail", + "normalized_id": "tc.net.09.ssrf", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-network-policy.sh", + "line": 537, + "text": "$PASS${NC}", + "polarity": "pass", + "normalized_id": "pass.nc", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-network-policy.sh", + "line": 538, + "text": "$FAIL${NC}", + "polarity": "fail", + "normalized_id": "fail.nc", + "mapping_status": "deferred" + } + ] + }, + { + "script": "test/e2e/test-ollama-auth-proxy-e2e.sh", + "assertions": [ + { + "script": "test/e2e/test-ollama-auth-proxy-e2e.sh", + "line": 78, + "text": "Node.js not found", + "polarity": "fail", + "normalized_id": "node.js.not.found", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-ollama-auth-proxy-e2e.sh", + "line": 81, + "text": "Node.js available: $(node --version)", + "polarity": "pass", + "normalized_id": "node.js.available.node.version", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-ollama-auth-proxy-e2e.sh", + "line": 84, + "text": "curl not found", + "polarity": "fail", + "normalized_id": "curl.not.found", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-ollama-auth-proxy-e2e.sh", + "line": 87, + "text": "curl available", + "polarity": "pass", + "normalized_id": "curl.available", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-ollama-auth-proxy-e2e.sh", + "line": 90, + "text": "Proxy script not found at $PROXY_SCRIPT", + "polarity": "fail", + "normalized_id": "proxy.script.not.found.at.proxy.script", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-ollama-auth-proxy-e2e.sh", + "line": 93, + "text": "Proxy script exists", + "polarity": "pass", + "normalized_id": "proxy.script.exists", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-ollama-auth-proxy-e2e.sh", + "line": 101, + "text": "Ollama already installed: $(ollama --version 2>/dev/null || echo unknown)", + "polarity": "pass", + "normalized_id": "ollama.already.installed.ollama.version.2.dev.null.echo.unknown", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-ollama-auth-proxy-e2e.sh", + "line": 105, + "text": "Ollama installed", + "polarity": "pass", + "normalized_id": "ollama.installed", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-ollama-auth-proxy-e2e.sh", + "line": 107, + "text": "Ollama install failed", + "polarity": "fail", + "normalized_id": "ollama.install.failed", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-ollama-auth-proxy-e2e.sh", + "line": 125, + "text": "Ollama running on 127.0.0.1:${OLLAMA_PORT}", + "polarity": "pass", + "normalized_id": "ollama.running.on.127.0.0.1.ollama.port", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-ollama-auth-proxy-e2e.sh", + "line": 127, + "text": "Ollama failed to start on 127.0.0.1:${OLLAMA_PORT}", + "polarity": "fail", + "normalized_id": "ollama.failed.to.start.on.127.0.0.1.ollama.port", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-ollama-auth-proxy-e2e.sh", + "line": 134, + "text": "Model $MODEL pulled", + "polarity": "pass", + "normalized_id": "model.model.pulled", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-ollama-auth-proxy-e2e.sh", + "line": 136, + "text": "Failed to pull $MODEL", + "polarity": "fail", + "normalized_id": "failed.to.pull.model", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-ollama-auth-proxy-e2e.sh", + "line": 142, + "text": "Model $MODEL available in Ollama", + "polarity": "pass", + "normalized_id": "model.model.available.in.ollama", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-ollama-auth-proxy-e2e.sh", + "line": 144, + "text": "Model $MODEL not found in /api/tags", + "polarity": "fail", + "normalized_id": "model.model.not.found.in.api.tags", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-ollama-auth-proxy-e2e.sh", + "line": 173, + "text": "Auth proxy running on 0.0.0.0:${PROXY_PORT} (HTTP $STATUS)", + "polarity": "pass", + "normalized_id": "auth.proxy.running.on.0.0.0.0.proxy.port.http.status", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-ollama-auth-proxy-e2e.sh", + "line": 175, + "text": "Auth proxy failed to start (no HTTP response: '$STATUS')", + "polarity": "fail", + "normalized_id": "auth.proxy.failed.to.start.no.http.response.status", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-ollama-auth-proxy-e2e.sh", + "line": 188, + "text": "Unauthenticated POST /api/generate → 401", + "polarity": "pass", + "normalized_id": "unauthenticated.post.api.generate.401", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-ollama-auth-proxy-e2e.sh", + "line": 190, + "text": "Expected 401 for unauthenticated POST, got $STATUS", + "polarity": "fail", + "normalized_id": "expected.401.for.unauthenticated.post.got.status", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-ollama-auth-proxy-e2e.sh", + "line": 199, + "text": "Wrong token POST /api/generate → 401", + "polarity": "pass", + "normalized_id": "wrong.token.post.api.generate.401", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-ollama-auth-proxy-e2e.sh", + "line": 201, + "text": "Expected 401 for wrong token, got $STATUS", + "polarity": "fail", + "normalized_id": "expected.401.for.wrong.token.got.status", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-ollama-auth-proxy-e2e.sh", + "line": 210, + "text": "Correct token GET /api/tags → 200", + "polarity": "pass", + "normalized_id": "correct.token.get.api.tags.200", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-ollama-auth-proxy-e2e.sh", + "line": 212, + "text": "Expected 200 for correct token, got $STATUS", + "polarity": "fail", + "normalized_id": "expected.200.for.correct.token.got.status", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-ollama-auth-proxy-e2e.sh", + "line": 219, + "text": "Unauthenticated GET /api/tags → 401", + "polarity": "pass", + "normalized_id": "unauthenticated.get.api.tags.401", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-ollama-auth-proxy-e2e.sh", + "line": 221, + "text": "Expected 401 for unauthenticated GET /api/tags, got $STATUS", + "polarity": "fail", + "normalized_id": "expected.401.for.unauthenticated.get.api.tags.got.status", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-ollama-auth-proxy-e2e.sh", + "line": 228, + "text": "Unauthenticated POST /api/tags → 401", + "polarity": "pass", + "normalized_id": "unauthenticated.post.api.tags.401", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-ollama-auth-proxy-e2e.sh", + "line": 230, + "text": "Expected 401 for unauthenticated POST /api/tags, got $STATUS", + "polarity": "fail", + "normalized_id": "expected.401.for.unauthenticated.post.api.tags.got.status", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-ollama-auth-proxy-e2e.sh", + "line": 238, + "text": "Proxy strips auth header — Ollama responds normally", + "polarity": "pass", + "normalized_id": "proxy.strips.auth.header.ollama.responds.normally", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-ollama-auth-proxy-e2e.sh", + "line": 240, + "text": "Proxy may not be stripping auth header correctly", + "polarity": "fail", + "normalized_id": "proxy.may.not.be.stripping.auth.header.correctly", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-ollama-auth-proxy-e2e.sh", + "line": 269, + "text": "Inference through proxy: got chat completion response", + "polarity": "pass", + "normalized_id": "inference.through.proxy.got.chat.completion.response", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-ollama-auth-proxy-e2e.sh", + "line": 271, + "text": "Inference through proxy: invalid response structure", + "polarity": "fail", + "normalized_id": "inference.through.proxy.invalid.response.structure", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-ollama-auth-proxy-e2e.sh", + "line": 275, + "text": "Inference through proxy: empty response", + "polarity": "fail", + "normalized_id": "inference.through.proxy.empty.response", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-ollama-auth-proxy-e2e.sh", + "line": 297, + "text": "Inference through proxy: got /api/generate response", + "polarity": "pass", + "normalized_id": "inference.through.proxy.got.api.generate.response", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-ollama-auth-proxy-e2e.sh", + "line": 299, + "text": "Inference through proxy: invalid /api/generate response", + "polarity": "fail", + "normalized_id": "inference.through.proxy.invalid.api.generate.response", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-ollama-auth-proxy-e2e.sh", + "line": 303, + "text": "Inference through proxy: empty /api/generate response", + "polarity": "fail", + "normalized_id": "inference.through.proxy.empty.api.generate.response", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-ollama-auth-proxy-e2e.sh", + "line": 315, + "text": "Inference without token → 401 (not forwarded to Ollama)", + "polarity": "pass", + "normalized_id": "inference.without.token.401.not.forwarded.to.ollama", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-ollama-auth-proxy-e2e.sh", + "line": 317, + "text": "Expected 401 for unauthenticated inference, got $STATUS", + "polarity": "fail", + "normalized_id": "expected.401.for.unauthenticated.inference.got.status", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-ollama-auth-proxy-e2e.sh", + "line": 327, + "text": "Token file exists at $TOKEN_FILE", + "polarity": "pass", + "normalized_id": "token.file.exists.at.token.file", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-ollama-auth-proxy-e2e.sh", + "line": 329, + "text": "Token file missing", + "polarity": "fail", + "normalized_id": "token.file.missing", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-ollama-auth-proxy-e2e.sh", + "line": 335, + "text": "Token file permissions: 600", + "polarity": "pass", + "normalized_id": "token.file.permissions.600", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-ollama-auth-proxy-e2e.sh", + "line": 337, + "text": "Token file permissions: expected 600, got $PERMS", + "polarity": "fail", + "normalized_id": "token.file.permissions.expected.600.got.perms", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-ollama-auth-proxy-e2e.sh", + "line": 343, + "text": "Token file content matches generated token", + "polarity": "pass", + "normalized_id": "token.file.content.matches.generated.token", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-ollama-auth-proxy-e2e.sh", + "line": 345, + "text": "Token file content mismatch", + "polarity": "fail", + "normalized_id": "token.file.content.mismatch", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-ollama-auth-proxy-e2e.sh", + "line": 363, + "text": "Proxy confirmed dead after kill", + "polarity": "pass", + "normalized_id": "proxy.confirmed.dead.after.kill", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-ollama-auth-proxy-e2e.sh", + "line": 365, + "text": "Proxy still responding after kill (status: $STATUS)", + "polarity": "fail", + "normalized_id": "proxy.still.responding.after.kill.status.status", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-ollama-auth-proxy-e2e.sh", + "line": 382, + "text": "Proxy restarted from persisted token (HTTP $STATUS)", + "polarity": "pass", + "normalized_id": "proxy.restarted.from.persisted.token.http.status", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-ollama-auth-proxy-e2e.sh", + "line": 384, + "text": "Proxy failed to restart (no HTTP response: '$STATUS')", + "polarity": "fail", + "normalized_id": "proxy.failed.to.restart.no.http.response.status", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-ollama-auth-proxy-e2e.sh", + "line": 404, + "text": "Inference works after proxy restart with persisted token", + "polarity": "pass", + "normalized_id": "inference.works.after.proxy.restart.with.persisted.token", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-ollama-auth-proxy-e2e.sh", + "line": 406, + "text": "Inference failed after proxy restart", + "polarity": "fail", + "normalized_id": "inference.failed.after.proxy.restart", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-ollama-auth-proxy-e2e.sh", + "line": 411, + "text": "Persisted token matches original — no token rotation on restart", + "polarity": "pass", + "normalized_id": "persisted.token.matches.original.no.token.rotation.on.restart", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-ollama-auth-proxy-e2e.sh", + "line": 413, + "text": "Token changed on restart (should be the same persisted token)", + "polarity": "fail", + "normalized_id": "token.changed.on.restart.should.be.the.same.persisted.token", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-ollama-auth-proxy-e2e.sh", + "line": 437, + "text": "Container can reach proxy at host.openshell.internal:${PROXY_PORT} (HTTP $CONTAINER_STATUS)", + "polarity": "pass", + "normalized_id": "container.can.reach.proxy.at.host.openshell.internal.proxy.port.http.container.status", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-ollama-auth-proxy-e2e.sh", + "line": 439, + "text": "Container cannot reach proxy — reachability check would fail during onboard", + "polarity": "fail", + "normalized_id": "container.cannot.reach.proxy.reachability.check.would.fail.during.onboard", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-ollama-auth-proxy-e2e.sh", + "line": 450, + "text": "Container CANNOT reach Ollama directly on ${OLLAMA_PORT} (localhost-only binding works)", + "polarity": "pass", + "normalized_id": "container.cannot.reach.ollama.directly.on.ollama.port.localhost.only.binding.works", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-ollama-auth-proxy-e2e.sh", + "line": 452, + "text": "Container CAN reach Ollama on ${OLLAMA_PORT} — Ollama may be on 0.0.0.0", + "polarity": "fail", + "normalized_id": "container.can.reach.ollama.on.ollama.port.ollama.may.be.on.0.0.0.0", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-ollama-auth-proxy-e2e.sh", + "line": 456, + "text": "Container reachability: skipped (no Docker)", + "polarity": "pass", + "normalized_id": "container.reachability.skipped.no.docker", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-ollama-auth-proxy-e2e.sh", + "line": 487, + "text": "Confirmed: proxy running with old token, rejects new token (divergence exists)", + "polarity": "pass", + "normalized_id": "confirmed.proxy.running.with.old.token.rejects.new.token.divergence.exists", + "mapping_status": "retired" + }, + { + "script": "test/e2e/test-ollama-auth-proxy-e2e.sh", + "line": 489, + "text": "Divergence not reproduced (old=$OLD_TOKEN_OK new=$NEW_TOKEN_OK) — aborting test", + "polarity": "fail", + "normalized_id": "divergence.not.reproduced.old.old.token.ok.new.new.token.ok.aborting.test", + "mapping_status": "retired" + }, + { + "script": "test/e2e/test-ollama-auth-proxy-e2e.sh", + "line": 527, + "text": "After ensureOllamaAuthProxy: proxy accepts the file token (divergence fixed)", + "polarity": "pass", + "normalized_id": "after.ensureollamaauthproxy.proxy.accepts.the.file.token.divergence.fixed", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-ollama-auth-proxy-e2e.sh", + "line": 529, + "text": "After ensureOllamaAuthProxy: proxy still rejects file token (divergence NOT fixed)", + "polarity": "fail", + "normalized_id": "after.ensureollamaauthproxy.proxy.still.rejects.file.token.divergence.not.fixed", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-ollama-auth-proxy-e2e.sh", + "line": 536, + "text": "Token divergence: skipped (no prior token)", + "polarity": "pass", + "normalized_id": "token.divergence.skipped.no.prior.token", + "mapping_status": "deferred" + } + ] + }, + { + "script": "test/e2e/test-onboard-repair.sh", + "assertions": [ + { + "script": "test/e2e/test-onboard-repair.sh", + "line": 123, + "text": "Pre-cleanup complete", + "polarity": "pass", + "normalized_id": "pre.cleanup.complete", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-onboard-repair.sh", + "line": 131, + "text": "Docker is running", + "polarity": "pass", + "normalized_id": "docker.is.running", + "mapping_status": "mapped" + }, + { + "script": "test/e2e/test-onboard-repair.sh", + "line": 133, + "text": "Docker is not running — cannot continue", + "polarity": "fail", + "normalized_id": "docker.is.not.running.cannot.continue", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-onboard-repair.sh", + "line": 138, + "text": "openshell CLI installed", + "polarity": "pass", + "normalized_id": "openshell.cli.installed", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-onboard-repair.sh", + "line": 140, + "text": "openshell CLI not found — cannot continue", + "polarity": "fail", + "normalized_id": "openshell.cli.not.found.cannot.continue", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-onboard-repair.sh", + "line": 145, + "text": "Node.js available", + "polarity": "pass", + "normalized_id": "node.js.available", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-onboard-repair.sh", + "line": 147, + "text": "Node.js not found — cannot continue", + "polarity": "fail", + "normalized_id": "node.js.not.found.cannot.continue", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-onboard-repair.sh", + "line": 152, + "text": "NVIDIA_API_KEY is set (starts with nvapi-)", + "polarity": "pass", + "normalized_id": "nvidia.api.key.is.set.starts.with.nvapi", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-onboard-repair.sh", + "line": 154, + "text": "NVIDIA_API_KEY not set or invalid — required for resume completion", + "polarity": "fail", + "normalized_id": "nvidia.api.key.not.set.or.invalid.required.for.resume.completion", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-onboard-repair.sh", + "line": 159, + "text": "Exported NVIDIA_API_KEY for the repair run (host writes nothing to disk; OpenShell gateway is the system of record)", + "polarity": "pass", + "normalized_id": "exported.nvidia.api.key.for.the.repair.run.host.writes.nothing.to.disk.openshell.gateway.is.the.system.of.record", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-onboard-repair.sh", + "line": 187, + "text": "First onboard exited 1 (expected interrupted run)", + "polarity": "pass", + "normalized_id": "first.onboard.exited.1.expected.interrupted.run", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-onboard-repair.sh", + "line": 189, + "text": "First onboard exited $first_exit (expected 1)", + "polarity": "fail", + "normalized_id": "first.onboard.exited.first.exit.expected.1", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-onboard-repair.sh", + "line": 195, + "text": "Onboard session file created", + "polarity": "pass", + "normalized_id": "onboard.session.file.created", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-onboard-repair.sh", + "line": 197, + "text": "Onboard session file missing after interrupted run", + "polarity": "fail", + "normalized_id": "onboard.session.file.missing.after.interrupted.run", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-onboard-repair.sh", + "line": 201, + "text": "First run failed at policy setup as intended", + "polarity": "pass", + "normalized_id": "first.run.failed.at.policy.setup.as.intended", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-onboard-repair.sh", + "line": 203, + "text": "First run did not fail at the expected policy step", + "polarity": "fail", + "normalized_id": "first.run.did.not.fail.at.the.expected.policy.step", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-onboard-repair.sh", + "line": 207, + "text": "Sandbox '$SANDBOX_NAME' exists after interrupted run", + "polarity": "pass", + "normalized_id": "sandbox.sandbox.name.exists.after.interrupted.run", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-onboard-repair.sh", + "line": 209, + "text": "Sandbox '$SANDBOX_NAME' not found after interrupted run", + "polarity": "fail", + "normalized_id": "sandbox.sandbox.name.not.found.after.interrupted.run", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-onboard-repair.sh", + "line": 222, + "text": "Sandbox '$SANDBOX_NAME' removed to simulate stale recorded state", + "polarity": "pass", + "normalized_id": "sandbox.sandbox.name.removed.to.simulate.stale.recorded.state", + "mapping_status": "retired" + }, + { + "script": "test/e2e/test-onboard-repair.sh", + "line": 224, + "text": "Sandbox '$SANDBOX_NAME' still exists after forced deletion", + "polarity": "fail", + "normalized_id": "sandbox.sandbox.name.still.exists.after.forced.deletion", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-onboard-repair.sh", + "line": 239, + "text": "Resume completed after repairing missing sandbox", + "polarity": "pass", + "normalized_id": "resume.completed.after.repairing.missing.sandbox", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-onboard-repair.sh", + "line": 241, + "text": "Resume exited $repair_exit during missing-sandbox repair", + "polarity": "fail", + "normalized_id": "resume.exited.repair.exit.during.missing.sandbox.repair", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-onboard-repair.sh", + "line": 247, + "text": "Repair resume skipped preflight", + "polarity": "pass", + "normalized_id": "repair.resume.skipped.preflight", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-onboard-repair.sh", + "line": 249, + "text": "Repair resume did not skip preflight", + "polarity": "fail", + "normalized_id": "repair.resume.did.not.skip.preflight", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-onboard-repair.sh", + "line": 253, + "text": "Repair resume skipped gateway", + "polarity": "pass", + "normalized_id": "repair.resume.skipped.gateway", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-onboard-repair.sh", + "line": 255, + "text": "Repair resume did not skip gateway", + "polarity": "fail", + "normalized_id": "repair.resume.did.not.skip.gateway", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-onboard-repair.sh", + "line": 259, + "text": "Repair resume detected missing sandbox", + "polarity": "pass", + "normalized_id": "repair.resume.detected.missing.sandbox", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-onboard-repair.sh", + "line": 261, + "text": "Repair resume did not report missing sandbox recreation", + "polarity": "fail", + "normalized_id": "repair.resume.did.not.report.missing.sandbox.recreation", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-onboard-repair.sh", + "line": 266, + "text": "Repair resume recreated sandbox", + "polarity": "pass", + "normalized_id": "repair.resume.recreated.sandbox", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-onboard-repair.sh", + "line": 268, + "text": "Repair resume did not rerun sandbox creation", + "polarity": "fail", + "normalized_id": "repair.resume.did.not.rerun.sandbox.creation", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-onboard-repair.sh", + "line": 272, + "text": "Repaired sandbox '$SANDBOX_NAME' is manageable", + "polarity": "pass", + "normalized_id": "repaired.sandbox.sandbox.name.is.manageable", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-onboard-repair.sh", + "line": 274, + "text": "Repaired sandbox '$SANDBOX_NAME' status failed", + "polarity": "fail", + "normalized_id": "repaired.sandbox.sandbox.name.status.failed", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-onboard-repair.sh", + "line": 295, + "text": "Re-created interrupted session for conflict tests", + "polarity": "pass", + "normalized_id": "re.created.interrupted.session.for.conflict.tests", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-onboard-repair.sh", + "line": 311, + "text": "Resume rejected conflicting sandbox name", + "polarity": "pass", + "normalized_id": "resume.rejected.conflicting.sandbox.name", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-onboard-repair.sh", + "line": 313, + "text": "Resume exited $sandbox_conflict_exit for conflicting sandbox (expected 1)", + "polarity": "fail", + "normalized_id": "resume.exited.sandbox.conflict.exit.for.conflicting.sandbox.expected.1", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-onboard-repair.sh", + "line": 317, + "text": "Conflicting sandbox message is explicit", + "polarity": "pass", + "normalized_id": "conflicting.sandbox.message.is.explicit", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-onboard-repair.sh", + "line": 319, + "text": "Conflicting sandbox message missing or incorrect", + "polarity": "fail", + "normalized_id": "conflicting.sandbox.message.missing.or.incorrect", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-onboard-repair.sh", + "line": 342, + "text": "Resume rejected conflicting provider/model", + "polarity": "pass", + "normalized_id": "resume.rejected.conflicting.provider.model", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-onboard-repair.sh", + "line": 344, + "text": "Resume exited $provider_conflict_exit for conflicting provider/model (expected 1)", + "polarity": "fail", + "normalized_id": "resume.exited.provider.conflict.exit.for.conflicting.provider.model.expected.1", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-onboard-repair.sh", + "line": 348, + "text": "Conflicting provider message is explicit", + "polarity": "pass", + "normalized_id": "conflicting.provider.message.is.explicit", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-onboard-repair.sh", + "line": 350, + "text": "Conflicting provider message missing or incorrect", + "polarity": "fail", + "normalized_id": "conflicting.provider.message.missing.or.incorrect", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-onboard-repair.sh", + "line": 354, + "text": "Conflicting model message is explicit", + "polarity": "pass", + "normalized_id": "conflicting.model.message.is.explicit", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-onboard-repair.sh", + "line": 356, + "text": "Conflicting model message missing or incorrect", + "polarity": "fail", + "normalized_id": "conflicting.model.message.missing.or.incorrect", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-onboard-repair.sh", + "line": 375, + "text": "Sandbox '$SANDBOX_NAME' still exists after cleanup", + "polarity": "fail", + "normalized_id": "sandbox.sandbox.name.still.exists.after.cleanup", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-onboard-repair.sh", + "line": 377, + "text": "Sandbox '$SANDBOX_NAME' cleaned up", + "polarity": "pass", + "normalized_id": "sandbox.sandbox.name.cleaned.up", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-onboard-repair.sh", + "line": 381, + "text": "Onboard session file still exists after cleanup", + "polarity": "fail", + "normalized_id": "onboard.session.file.still.exists.after.cleanup", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-onboard-repair.sh", + "line": 383, + "text": "Onboard session file cleaned up", + "polarity": "pass", + "normalized_id": "onboard.session.file.cleaned.up", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-onboard-repair.sh", + "line": 386, + "text": "Final cleanup complete", + "polarity": "pass", + "normalized_id": "final.cleanup.complete", + "mapping_status": "deferred" + } + ] + }, + { + "script": "test/e2e/test-onboard-resume.sh", + "assertions": [ + { + "script": "test/e2e/test-onboard-resume.sh", + "line": 96, + "text": "Pre-cleanup complete", + "polarity": "pass", + "normalized_id": "pre.cleanup.complete", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-onboard-resume.sh", + "line": 104, + "text": "Docker is running", + "polarity": "pass", + "normalized_id": "docker.is.running", + "mapping_status": "mapped" + }, + { + "script": "test/e2e/test-onboard-resume.sh", + "line": 106, + "text": "Docker is not running — cannot continue", + "polarity": "fail", + "normalized_id": "docker.is.not.running.cannot.continue", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-onboard-resume.sh", + "line": 111, + "text": "openshell CLI installed", + "polarity": "pass", + "normalized_id": "openshell.cli.installed", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-onboard-resume.sh", + "line": 113, + "text": "openshell CLI not found — cannot continue", + "polarity": "fail", + "normalized_id": "openshell.cli.not.found.cannot.continue", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-onboard-resume.sh", + "line": 118, + "text": "Node.js available", + "polarity": "pass", + "normalized_id": "node.js.available", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-onboard-resume.sh", + "line": 120, + "text": "Node.js not found — cannot continue", + "polarity": "fail", + "normalized_id": "node.js.not.found.cannot.continue", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-onboard-resume.sh", + "line": 125, + "text": "NVIDIA_API_KEY is set (starts with nvapi-)", + "polarity": "pass", + "normalized_id": "nvidia.api.key.is.set.starts.with.nvapi", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-onboard-resume.sh", + "line": 127, + "text": "NVIDIA_API_KEY not set or invalid — required for resume completion", + "polarity": "fail", + "normalized_id": "nvidia.api.key.not.set.or.invalid.required.for.resume.completion", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-onboard-resume.sh", + "line": 132, + "text": "Network access to integrate.api.nvidia.com", + "polarity": "pass", + "normalized_id": "network.access.to.integrate.api.nvidia.com", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-onboard-resume.sh", + "line": 134, + "text": "Cannot reach integrate.api.nvidia.com", + "polarity": "fail", + "normalized_id": "cannot.reach.integrate.api.nvidia.com", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-onboard-resume.sh", + "line": 139, + "text": "Exported NVIDIA_API_KEY for the resume run (host writes nothing to disk; OpenShell gateway is the system of record)", + "polarity": "pass", + "normalized_id": "exported.nvidia.api.key.for.the.resume.run.host.writes.nothing.to.disk.openshell.gateway.is.the.system.of.record", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-onboard-resume.sh", + "line": 167, + "text": "First onboard exited 1 (expected interrupted run)", + "polarity": "pass", + "normalized_id": "first.onboard.exited.1.expected.interrupted.run", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-onboard-resume.sh", + "line": 169, + "text": "First onboard exited $first_exit (expected 1)", + "polarity": "fail", + "normalized_id": "first.onboard.exited.first.exit.expected.1", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-onboard-resume.sh", + "line": 175, + "text": "Sandbox '$SANDBOX_NAME' created before interruption", + "polarity": "pass", + "normalized_id": "sandbox.sandbox.name.created.before.interruption", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-onboard-resume.sh", + "line": 177, + "text": "Sandbox creation not confirmed in first run output", + "polarity": "fail", + "normalized_id": "sandbox.creation.not.confirmed.in.first.run.output", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-onboard-resume.sh", + "line": 181, + "text": "First run failed at policy setup as intended", + "polarity": "pass", + "normalized_id": "first.run.failed.at.policy.setup.as.intended", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-onboard-resume.sh", + "line": 183, + "text": "First run did not fail at the expected policy step", + "polarity": "fail", + "normalized_id": "first.run.did.not.fail.at.the.expected.policy.step", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-onboard-resume.sh", + "line": 187, + "text": "Sandbox '$SANDBOX_NAME' exists after interrupted run", + "polarity": "pass", + "normalized_id": "sandbox.sandbox.name.exists.after.interrupted.run", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-onboard-resume.sh", + "line": 189, + "text": "Sandbox '$SANDBOX_NAME' not found after interrupted run", + "polarity": "fail", + "normalized_id": "sandbox.sandbox.name.not.found.after.interrupted.run", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-onboard-resume.sh", + "line": 193, + "text": "Onboard session file created", + "polarity": "pass", + "normalized_id": "onboard.session.file.created", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-onboard-resume.sh", + "line": 195, + "text": "Onboard session file missing after interrupted run", + "polarity": "fail", + "normalized_id": "onboard.session.file.missing.after.interrupted.run", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-onboard-resume.sh", + "line": 207, + "text": "Session file recorded openclaw completion and policy failure", + "polarity": "pass", + "normalized_id": "session.file.recorded.openclaw.completion.and.policy.failure", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-onboard-resume.sh", + "line": 208, + "text": "Session file did not record the expected interrupted state", + "polarity": "fail", + "normalized_id": "session.file.did.not.record.the.expected.interrupted.state", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-onboard-resume.sh", + "line": 229, + "text": "Resume completed successfully", + "polarity": "pass", + "normalized_id": "resume.completed.successfully", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-onboard-resume.sh", + "line": 231, + "text": "Resume exited $resume_exit (expected 0)", + "polarity": "fail", + "normalized_id": "resume.exited.resume.exit.expected.0", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-onboard-resume.sh", + "line": 237, + "text": "Resume skipped preflight", + "polarity": "pass", + "normalized_id": "resume.skipped.preflight", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-onboard-resume.sh", + "line": 239, + "text": "Resume did not skip preflight", + "polarity": "fail", + "normalized_id": "resume.did.not.skip.preflight", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-onboard-resume.sh", + "line": 243, + "text": "Resume skipped gateway", + "polarity": "pass", + "normalized_id": "resume.skipped.gateway", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-onboard-resume.sh", + "line": 245, + "text": "Resume did not skip gateway", + "polarity": "fail", + "normalized_id": "resume.did.not.skip.gateway", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-onboard-resume.sh", + "line": 249, + "text": "Resume skipped sandbox", + "polarity": "pass", + "normalized_id": "resume.skipped.sandbox", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-onboard-resume.sh", + "line": 251, + "text": "Resume did not skip sandbox", + "polarity": "fail", + "normalized_id": "resume.did.not.skip.sandbox", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-onboard-resume.sh", + "line": 255, + "text": "Resume reran preflight unexpectedly", + "polarity": "fail", + "normalized_id": "resume.reran.preflight.unexpectedly", + "mapping_status": "retired" + }, + { + "script": "test/e2e/test-onboard-resume.sh", + "line": 257, + "text": "Resume did not rerun preflight", + "polarity": "pass", + "normalized_id": "resume.did.not.rerun.preflight", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-onboard-resume.sh", + "line": 261, + "text": "Resume reran gateway startup unexpectedly", + "polarity": "fail", + "normalized_id": "resume.reran.gateway.startup.unexpectedly", + "mapping_status": "retired" + }, + { + "script": "test/e2e/test-onboard-resume.sh", + "line": 263, + "text": "Resume did not rerun gateway startup", + "polarity": "pass", + "normalized_id": "resume.did.not.rerun.gateway.startup", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-onboard-resume.sh", + "line": 267, + "text": "Resume reran sandbox creation unexpectedly", + "polarity": "fail", + "normalized_id": "resume.reran.sandbox.creation.unexpectedly", + "mapping_status": "retired" + }, + { + "script": "test/e2e/test-onboard-resume.sh", + "line": 269, + "text": "Resume did not rerun sandbox creation", + "polarity": "pass", + "normalized_id": "resume.did.not.rerun.sandbox.creation", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-onboard-resume.sh", + "line": 276, + "text": "Resume re-ran inference setup", + "polarity": "pass", + "normalized_id": "resume.re.ran.inference.setup", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-onboard-resume.sh", + "line": 278, + "text": "Resume skipped inference (already configured)", + "polarity": "pass", + "normalized_id": "resume.skipped.inference.already.configured", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-onboard-resume.sh", + "line": 280, + "text": "Resume neither ran nor skipped inference setup", + "polarity": "fail", + "normalized_id": "resume.neither.ran.nor.skipped.inference.setup", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-onboard-resume.sh", + "line": 284, + "text": "Sandbox '$SANDBOX_NAME' is manageable after resume", + "polarity": "pass", + "normalized_id": "sandbox.sandbox.name.is.manageable.after.resume", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-onboard-resume.sh", + "line": 286, + "text": "Sandbox '$SANDBOX_NAME' status failed after resume", + "polarity": "fail", + "normalized_id": "sandbox.sandbox.name.status.failed.after.resume", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-onboard-resume.sh", + "line": 304, + "text": "Session file recorded full completion after resume", + "polarity": "pass", + "normalized_id": "session.file.recorded.full.completion.after.resume", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-onboard-resume.sh", + "line": 305, + "text": "Session file did not record the expected completed state after resume", + "polarity": "fail", + "normalized_id": "session.file.did.not.record.the.expected.completed.state.after.resume", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-onboard-resume.sh", + "line": 309, + "text": "Registry contains resumed sandbox entry", + "polarity": "pass", + "normalized_id": "registry.contains.resumed.sandbox.entry", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-onboard-resume.sh", + "line": 311, + "text": "Registry does not contain resumed sandbox entry", + "polarity": "fail", + "normalized_id": "registry.does.not.contain.resumed.sandbox.entry", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-onboard-resume.sh", + "line": 326, + "text": "Sandbox '$SANDBOX_NAME' still exists after cleanup", + "polarity": "fail", + "normalized_id": "sandbox.sandbox.name.still.exists.after.cleanup", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-onboard-resume.sh", + "line": 328, + "text": "Sandbox '$SANDBOX_NAME' cleaned up", + "polarity": "pass", + "normalized_id": "sandbox.sandbox.name.cleaned.up", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-onboard-resume.sh", + "line": 332, + "text": "Onboard session file still exists after cleanup", + "polarity": "fail", + "normalized_id": "onboard.session.file.still.exists.after.cleanup", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-onboard-resume.sh", + "line": 334, + "text": "Onboard session file cleaned up", + "polarity": "pass", + "normalized_id": "onboard.session.file.cleaned.up", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-onboard-resume.sh", + "line": 337, + "text": "Final cleanup complete", + "polarity": "pass", + "normalized_id": "final.cleanup.complete", + "mapping_status": "deferred" + } + ] + }, + { + "script": "test/e2e/test-openclaw-inference-switch.sh", + "assertions": [ + { + "script": "test/e2e/test-openclaw-inference-switch.sh", + "line": 96, + "text": "OpenShell inference get failed: ${output:0:240}", + "polarity": "fail", + "normalized_id": "openshell.inference.get.failed.output.0.240", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-openclaw-inference-switch.sh", + "line": 103, + "text": "OpenShell route points at ${SWITCH_PROVIDER} / ${SWITCH_MODEL}", + "polarity": "pass", + "normalized_id": "openshell.route.points.at.switch.provider.switch.model", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-openclaw-inference-switch.sh", + "line": 105, + "text": "OpenShell route did not switch to ${SWITCH_PROVIDER} / ${SWITCH_MODEL}: ${plain_output:0:400}", + "polarity": "fail", + "normalized_id": "openshell.route.did.not.switch.to.switch.provider.switch.model.plain.output.0.400", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-openclaw-inference-switch.sh", + "line": 163, + "text": "Registry/session were not updated for switch: ${probe:0:400}", + "polarity": "fail", + "normalized_id": "registry.session.were.not.updated.for.switch.probe.0.400", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-openclaw-inference-switch.sh", + "line": 166, + "text": "Registry and onboard session record the switched provider/model", + "polarity": "pass", + "normalized_id": "registry.and.onboard.session.record.the.switched.provider.model", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-openclaw-inference-switch.sh", + "line": 172, + "text": "Could not read /sandbox/.openclaw/openclaw.json: ${config:0:240}", + "polarity": "fail", + "normalized_id": "could.not.read.sandbox.openclaw.openclaw.json.config.0.240", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-openclaw-inference-switch.sh", + "line": 202, + "text": "OpenClaw config was not patched correctly: ${probe:0:400}", + "polarity": "fail", + "normalized_id": "openclaw.config.was.not.patched.correctly.probe.0.400", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-openclaw-inference-switch.sh", + "line": 205, + "text": "OpenClaw config uses inference/${SWITCH_MODEL}", + "polarity": "pass", + "normalized_id": "openclaw.config.uses.inference.switch.model", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-openclaw-inference-switch.sh", + "line": 210, + "text": "OpenClaw config hash matches openclaw.json", + "polarity": "pass", + "normalized_id": "openclaw.config.hash.matches.openclaw.json", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-openclaw-inference-switch.sh", + "line": 212, + "text": "OpenClaw config hash check failed: ${hash_check:0:240}", + "polarity": "fail", + "normalized_id": "openclaw.config.hash.check.failed.hash.check.0.240", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-openclaw-inference-switch.sh", + "line": 241, + "text": "Sandbox inference.local returned PONG with ${SWITCH_MODEL}", + "polarity": "pass", + "normalized_id": "sandbox.inference.local.returned.pong.with.switch.model", + "mapping_status": "mapped" + }, + { + "script": "test/e2e/test-openclaw-inference-switch.sh", + "line": 253, + "text": "Sandbox inference.local did not work after switch: ${last_fail}", + "polarity": "fail", + "normalized_id": "sandbox.inference.local.did.not.work.after.switch.last.fail", + "mapping_status": "mapped" + }, + { + "script": "test/e2e/test-openclaw-inference-switch.sh", + "line": 261, + "text": "Could not get SSH config for OpenClaw agent turn", + "polarity": "fail", + "normalized_id": "could.not.get.ssh.config.for.openclaw.agent.turn", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-openclaw-inference-switch.sh", + "line": 293, + "text": "OpenClaw agent answered through the switched inference route", + "polarity": "pass", + "normalized_id": "openclaw.agent.answered.through.the.switched.inference.route", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-openclaw-inference-switch.sh", + "line": 295, + "text": "OpenClaw agent turn failed after switch (exit ${rc}); reply='${reply:0:200}', raw='${raw:0:200}'", + "polarity": "fail", + "normalized_id": "openclaw.agent.turn.failed.after.switch.exit.rc.reply.reply.0.200.raw.raw.0.200", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-openclaw-inference-switch.sh", + "line": 328, + "text": "Pre-cleanup complete", + "polarity": "pass", + "normalized_id": "pre.cleanup.complete", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-openclaw-inference-switch.sh", + "line": 332, + "text": "Docker is running", + "polarity": "pass", + "normalized_id": "docker.is.running", + "mapping_status": "mapped" + }, + { + "script": "test/e2e/test-openclaw-inference-switch.sh", + "line": 334, + "text": "Docker is not running", + "polarity": "fail", + "normalized_id": "docker.is.not.running", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-openclaw-inference-switch.sh", + "line": 339, + "text": "NVIDIA_API_KEY is set", + "polarity": "pass", + "normalized_id": "nvidia.api.key.is.set", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-openclaw-inference-switch.sh", + "line": 341, + "text": "NVIDIA_API_KEY not set or invalid", + "polarity": "fail", + "normalized_id": "nvidia.api.key.not.set.or.invalid", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-openclaw-inference-switch.sh", + "line": 346, + "text": "NEMOCLAW_NON_INTERACTIVE=1", + "polarity": "pass", + "normalized_id": "nemoclaw.non.interactive.1", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-openclaw-inference-switch.sh", + "line": 348, + "text": "NEMOCLAW_NON_INTERACTIVE=1 is required", + "polarity": "fail", + "normalized_id": "nemoclaw.non.interactive.1.is.required", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-openclaw-inference-switch.sh", + "line": 353, + "text": "Third-party software acceptance is set", + "polarity": "pass", + "normalized_id": "third.party.software.acceptance.is.set", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-openclaw-inference-switch.sh", + "line": 355, + "text": "NEMOCLAW_ACCEPT_THIRD_PARTY_SOFTWARE=1 is required", + "polarity": "fail", + "normalized_id": "nemoclaw.accept.third.party.software.1.is.required", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-openclaw-inference-switch.sh", + "line": 361, + "text": "Could not cd to repo root: $REPO", + "polarity": "fail", + "normalized_id": "could.not.cd.to.repo.root.repo", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-openclaw-inference-switch.sh", + "line": 385, + "text": "install.sh completed", + "polarity": "pass", + "normalized_id": "install.sh.completed", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-openclaw-inference-switch.sh", + "line": 387, + "text": "install.sh failed (exit ${install_exit})", + "polarity": "fail", + "normalized_id": "install.sh.failed.exit.install.exit", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-openclaw-inference-switch.sh", + "line": 393, + "text": "nemoclaw not found on PATH", + "polarity": "fail", + "normalized_id": "nemoclaw.not.found.on.path", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-openclaw-inference-switch.sh", + "line": 397, + "text": "openshell not found on PATH", + "polarity": "fail", + "normalized_id": "openshell.not.found.on.path", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-openclaw-inference-switch.sh", + "line": 400, + "text": "nemoclaw and openshell are on PATH", + "polarity": "pass", + "normalized_id": "nemoclaw.and.openshell.are.on.path", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-openclaw-inference-switch.sh", + "line": 408, + "text": "nemoclaw inference set completed", + "polarity": "pass", + "normalized_id": "nemoclaw.inference.set.completed", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-openclaw-inference-switch.sh", + "line": 410, + "text": "nemoclaw inference set failed (exit ${switch_rc}): ${switch_output:0:500}", + "polarity": "fail", + "normalized_id": "nemoclaw.inference.set.failed.exit.switch.rc.switch.output.0.500", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-openclaw-inference-switch.sh", + "line": 417, + "text": "OpenClaw gateway process stayed running during switch", + "polarity": "pass", + "normalized_id": "openclaw.gateway.process.stayed.running.during.switch", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-openclaw-inference-switch.sh", + "line": 419, + "text": "OpenClaw gateway process changed during switch (${pid_before} -> ${pid_after})", + "polarity": "fail", + "normalized_id": "openclaw.gateway.process.changed.during.switch.pid.before.pid.after", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-openclaw-inference-switch.sh", + "line": 440, + "text": "Sandbox ${SANDBOX_NAME} still in registry after destroy", + "polarity": "fail", + "normalized_id": "sandbox.sandbox.name.still.in.registry.after.destroy", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-openclaw-inference-switch.sh", + "line": 442, + "text": "Sandbox ${SANDBOX_NAME} removed", + "polarity": "pass", + "normalized_id": "sandbox.sandbox.name.removed", + "mapping_status": "retired" + } + ] + }, + { + "script": "test/e2e/test-openshell-gateway-upgrade.sh", + "assertions": [ + { + "script": "test/e2e/test-openshell-gateway-upgrade.sh", + "line": 185, + "text": "macOS incomplete OpenShell install unexpectedly succeeded with fake payloads", + "polarity": "fail", + "normalized_id": "macos.incomplete.openshell.install.unexpectedly.succeeded.with.fake.payloads", + "mapping_status": "retired" + }, + { + "script": "test/e2e/test-openshell-gateway-upgrade.sh", + "line": 194, + "text": "macOS installer did not detect missing openshell-gateway", + "polarity": "fail", + "normalized_id": "macos.installer.did.not.detect.missing.openshell.gateway", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-openshell-gateway-upgrade.sh", + "line": 201, + "text": "macOS installer did not request the Darwin openshell-gateway asset", + "polarity": "fail", + "normalized_id": "macos.installer.did.not.request.the.darwin.openshell.gateway.asset", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-openshell-gateway-upgrade.sh", + "line": 207, + "text": "macOS installer did not request the Darwin openshell-driver-vm asset", + "polarity": "fail", + "normalized_id": "macos.installer.did.not.request.the.darwin.openshell.driver.vm.asset", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-openshell-gateway-upgrade.sh", + "line": 211, + "text": "macOS OpenShell ${CURRENT_OPENSHELL_VERSION} incomplete install fetches Darwin gateway and VM driver assets", + "polarity": "pass", + "normalized_id": "macos.openshell.current.openshell.version.incomplete.install.fetches.darwin.gateway.and.vm.driver.assets", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-openshell-gateway-upgrade.sh", + "line": 280, + "text": "macOS installer did not repair missing openshell-driver-vm Hypervisor entitlement", + "polarity": "fail", + "normalized_id": "macos.installer.did.not.repair.missing.openshell.driver.vm.hypervisor.entitlement", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-openshell-gateway-upgrade.sh", + "line": 287, + "text": "macOS installer did not codesign openshell-driver-vm with entitlements", + "polarity": "fail", + "normalized_id": "macos.installer.did.not.codesign.openshell.driver.vm.with.entitlements", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-openshell-gateway-upgrade.sh", + "line": 294, + "text": "macOS installer reinstalled instead of repairing an otherwise complete OpenShell install", + "polarity": "fail", + "normalized_id": "macos.installer.reinstalled.instead.of.repairing.an.otherwise.complete.openshell.install", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-openshell-gateway-upgrade.sh", + "line": 298, + "text": "macOS OpenShell ${CURRENT_OPENSHELL_VERSION} installer repairs missing VM driver Hypervisor entitlement", + "polarity": "pass", + "normalized_id": "macos.openshell.current.openshell.version.installer.repairs.missing.vm.driver.hypervisor.entitlement", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-openshell-gateway-upgrade.sh", + "line": 303, + "text": "Dockerfile is missing the macOS VM rootfs compatibility ARG", + "polarity": "fail", + "normalized_id": "dockerfile.is.missing.the.macos.vm.rootfs.compatibility.arg", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-openshell-gateway-upgrade.sh", + "line": 305, + "text": "Dockerfile patch helper does not patch the macOS VM rootfs compatibility ARG", + "polarity": "fail", + "normalized_id": "dockerfile.patch.helper.does.not.patch.the.macos.vm.rootfs.compatibility.arg", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-openshell-gateway-upgrade.sh", + "line": 307, + "text": "onboard does not enable macOS VM rootfs compatibility for Darwin sandbox builds", + "polarity": "fail", + "normalized_id": "onboard.does.not.enable.macos.vm.rootfs.compatibility.for.darwin.sandbox.builds", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-openshell-gateway-upgrade.sh", + "line": 309, + "text": "Dockerfile does not relax OpenClaw state permissions for macOS VM rootfs remapping", + "polarity": "fail", + "normalized_id": "dockerfile.does.not.relax.openclaw.state.permissions.for.macos.vm.rootfs.remapping", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-openshell-gateway-upgrade.sh", + "line": 311, + "text": "Hermes Dockerfile is missing the macOS VM rootfs compatibility ARG", + "polarity": "fail", + "normalized_id": "hermes.dockerfile.is.missing.the.macos.vm.rootfs.compatibility.arg", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-openshell-gateway-upgrade.sh", + "line": 313, + "text": "Hermes Dockerfile does not relax Hermes state permissions for macOS VM rootfs remapping", + "polarity": "fail", + "normalized_id": "hermes.dockerfile.does.not.relax.hermes.state.permissions.for.macos.vm.rootfs.remapping", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-openshell-gateway-upgrade.sh", + "line": 315, + "text": "Hermes Dockerfile does not relax trusted rc files for macOS VM ownership repair", + "polarity": "fail", + "normalized_id": "hermes.dockerfile.does.not.relax.trusted.rc.files.for.macos.vm.ownership.repair", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-openshell-gateway-upgrade.sh", + "line": 316, + "text": "macOS VM sandbox builds enable OpenClaw and Hermes rootfs ownership compatibility", + "polarity": "pass", + "normalized_id": "macos.vm.sandbox.builds.enable.openclaw.and.hermes.rootfs.ownership.compatibility", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-openshell-gateway-upgrade.sh", + "line": 407, + "text": "Compatible endpoint mock is listening at ${FAKE_BASE_URL}", + "polarity": "pass", + "normalized_id": "compatible.endpoint.mock.is.listening.at.fake.base.url", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-openshell-gateway-upgrade.sh", + "line": 414, + "text": "compatible endpoint mock did not start", + "polarity": "fail", + "normalized_id": "compatible.endpoint.mock.did.not.start", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-openshell-gateway-upgrade.sh", + "line": 440, + "text": "${label} NemoClaw installer failed", + "polarity": "fail", + "normalized_id": "label.nemoclaw.installer.failed", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-openshell-gateway-upgrade.sh", + "line": 460, + "text": "old NemoClaw install did not leave OpenShell ${OLD_OPENSHELL_VERSION}: $(openshell --version 2>&1 || true)", + "polarity": "fail", + "normalized_id": "old.nemoclaw.install.did.not.leave.openshell.old.openshell.version.openshell.version.2.1.true", + "mapping_status": "retired" + }, + { + "script": "test/e2e/test-openshell-gateway-upgrade.sh", + "line": 462, + "text": "Old NemoClaw install selected $(openshell --version)", + "polarity": "pass", + "normalized_id": "old.nemoclaw.install.selected.openshell.version", + "mapping_status": "retired" + }, + { + "script": "test/e2e/test-openshell-gateway-upgrade.sh", + "line": 469, + "text": "old installer source is ${old_head:-unknown}, expected ${expected_head:-$OLD_NEMOCLAW_REF}", + "polarity": "fail", + "normalized_id": "old.installer.source.is.old.head.unknown.expected.expected.head.old.nemoclaw.ref", + "mapping_status": "retired" + }, + { + "script": "test/e2e/test-openshell-gateway-upgrade.sh", + "line": 470, + "text": "Old NemoClaw source is ${OLD_NEMOCLAW_REF} (${old_head:0:12})", + "polarity": "pass", + "normalized_id": "old.nemoclaw.source.is.old.nemoclaw.ref.old.head.0.12", + "mapping_status": "retired" + }, + { + "script": "test/e2e/test-openshell-gateway-upgrade.sh", + "line": 473, + "text": "survivor sandbox did not become Ready before gateway upgrade", + "polarity": "fail", + "normalized_id": "survivor.sandbox.did.not.become.ready.before.gateway.upgrade", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-openshell-gateway-upgrade.sh", + "line": 475, + "text": "Old NemoClaw install registered survivor claw ${SURVIVOR_SANDBOX}", + "polarity": "pass", + "normalized_id": "old.nemoclaw.install.registered.survivor.claw.survivor.sandbox", + "mapping_status": "retired" + }, + { + "script": "test/e2e/test-openshell-gateway-upgrade.sh", + "line": 477, + "text": "old NemoClaw install did not register survivor claw ${SURVIVOR_SANDBOX}", + "polarity": "fail", + "normalized_id": "old.nemoclaw.install.did.not.register.survivor.claw.survivor.sandbox", + "mapping_status": "retired" + }, + { + "script": "test/e2e/test-openshell-gateway-upgrade.sh", + "line": 485, + "text": "failed to write survivor marker before gateway upgrade", + "polarity": "fail", + "normalized_id": "failed.to.write.survivor.marker.before.gateway.upgrade", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-openshell-gateway-upgrade.sh", + "line": 509, + "text": "failed to start survivor agent before gateway upgrade", + "polarity": "fail", + "normalized_id": "failed.to.start.survivor.agent.before.gateway.upgrade", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-openshell-gateway-upgrade.sh", + "line": 510, + "text": "survivor agent did not become healthy before gateway upgrade", + "polarity": "fail", + "normalized_id": "survivor.agent.did.not.become.healthy.before.gateway.upgrade", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-openshell-gateway-upgrade.sh", + "line": 512, + "text": "survivor agent pid was empty before gateway upgrade", + "polarity": "fail", + "normalized_id": "survivor.agent.pid.was.empty.before.gateway.upgrade", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-openshell-gateway-upgrade.sh", + "line": 514, + "text": "Old NemoClaw claw has live agent activity (pid ${SURVIVOR_AGENT_PID}) before gateway upgrade", + "polarity": "pass", + "normalized_id": "old.nemoclaw.claw.has.live.agent.activity.pid.survivor.agent.pid.before.gateway.upgrade", + "mapping_status": "retired" + }, + { + "script": "test/e2e/test-openshell-gateway-upgrade.sh", + "line": 522, + "text": "current installer did not exercise the experimental OpenShell gateway upgrade acceptance path", + "polarity": "fail", + "normalized_id": "current.installer.did.not.exercise.the.experimental.openshell.gateway.upgrade.acceptance.path", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-openshell-gateway-upgrade.sh", + "line": 525, + "text": "current NemoClaw install did not upgrade OpenShell to ${CURRENT_OPENSHELL_VERSION}: $(openshell --version 2>&1 || true)", + "polarity": "fail", + "normalized_id": "current.nemoclaw.install.did.not.upgrade.openshell.to.current.openshell.version.openshell.version.2.1.true", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-openshell-gateway-upgrade.sh", + "line": 527, + "text": "Current NemoClaw install selected $(openshell --version)", + "polarity": "pass", + "normalized_id": "current.nemoclaw.install.selected.openshell.version", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-openshell-gateway-upgrade.sh", + "line": 534, + "text": "gateway server did not report OpenShell ${CURRENT_OPENSHELL_VERSION} after upgrade", + "polarity": "fail", + "normalized_id": "gateway.server.did.not.report.openshell.current.openshell.version.after.upgrade", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-openshell-gateway-upgrade.sh", + "line": 536, + "text": "Gateway server reports OpenShell ${CURRENT_OPENSHELL_VERSION} after upgrade", + "polarity": "pass", + "normalized_id": "gateway.server.reports.openshell.current.openshell.version.after.upgrade", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-openshell-gateway-upgrade.sh", + "line": 539, + "text": "Current installer backed up the old running claw before replacing OpenShell", + "polarity": "pass", + "normalized_id": "current.installer.backed.up.the.old.running.claw.before.replacing.openshell", + "mapping_status": "retired" + }, + { + "script": "test/e2e/test-openshell-gateway-upgrade.sh", + "line": 543, + "text": "current installer did not back up the old running claw before replacing OpenShell", + "polarity": "fail", + "normalized_id": "current.installer.did.not.back.up.the.old.running.claw.before.replacing.openshell", + "mapping_status": "retired" + }, + { + "script": "test/e2e/test-openshell-gateway-upgrade.sh", + "line": 550, + "text": "survivor sandbox is not Ready after gateway upgrade", + "polarity": "fail", + "normalized_id": "survivor.sandbox.is.not.ready.after.gateway.upgrade", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-openshell-gateway-upgrade.sh", + "line": 557, + "text": "survivor marker changed after gateway upgrade: got '${marker}'", + "polarity": "fail", + "normalized_id": "survivor.marker.changed.after.gateway.upgrade.got.marker", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-openshell-gateway-upgrade.sh", + "line": 558, + "text": "Durable OpenClaw workspace state was restored after gateway upgrade", + "polarity": "pass", + "normalized_id": "durable.openclaw.workspace.state.was.restored.after.gateway.upgrade", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-openshell-gateway-upgrade.sh", + "line": 565, + "text": "OpenClaw agent is not installed/configured after gateway upgrade", + "polarity": "fail", + "normalized_id": "openclaw.agent.is.not.installed.configured.after.gateway.upgrade", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-openshell-gateway-upgrade.sh", + "line": 566, + "text": "OpenClaw agent is installed and configured after gateway upgrade", + "polarity": "pass", + "normalized_id": "openclaw.agent.is.installed.and.configured.after.gateway.upgrade", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-openshell-gateway-upgrade.sh", + "line": 569, + "text": "NemoClaw registry retained survivor sandbox after gateway upgrade", + "polarity": "pass", + "normalized_id": "nemoclaw.registry.retained.survivor.sandbox.after.gateway.upgrade", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-openshell-gateway-upgrade.sh", + "line": 571, + "text": "NemoClaw registry lost survivor sandbox after gateway upgrade", + "polarity": "fail", + "normalized_id": "nemoclaw.registry.lost.survivor.sandbox.after.gateway.upgrade", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-openshell-gateway-upgrade.sh", + "line": 576, + "text": "nemoclaw list still shows survivor sandbox after gateway upgrade", + "polarity": "pass", + "normalized_id": "nemoclaw.list.still.shows.survivor.sandbox.after.gateway.upgrade", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-openshell-gateway-upgrade.sh", + "line": 578, + "text": "nemoclaw list does not show survivor sandbox after gateway upgrade: ${list_output:0:200}", + "polarity": "fail", + "normalized_id": "nemoclaw.list.does.not.show.survivor.sandbox.after.gateway.upgrade.list.output.0.200", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-openshell-gateway-upgrade.sh", + "line": 581, + "text": "Survivor claw state remained reachable after OpenShell gateway upgrade", + "polarity": "pass", + "normalized_id": "survivor.claw.state.remained.reachable.after.openshell.gateway.upgrade", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-openshell-gateway-upgrade.sh", + "line": 591, + "text": "Skipping live Docker-driver gateway restart regression on non-Linux host", + "polarity": "pass", + "normalized_id": "skipping.live.docker.driver.gateway.restart.regression.on.non.linux.host", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-openshell-gateway-upgrade.sh", + "line": 604, + "text": "Current NemoClaw installer upgraded old ${OLD_NEMOCLAW_REF} claw, restored state, and kept OpenClaw running on OpenShell ${CURRENT_OPENSHELL_VERSION}", + "polarity": "pass", + "normalized_id": "current.nemoclaw.installer.upgraded.old.old.nemoclaw.ref.claw.restored.state.and.kept.openclaw.running.on.openshell.current.openshell.version", + "mapping_status": "retired" + } + ] + }, + { + "script": "test/e2e/test-overlayfs-autofix.sh", + "assertions": [ + { + "script": "test/e2e/test-overlayfs-autofix.sh", + "line": 169, + "text": "Docker is running", + "polarity": "pass", + "normalized_id": "docker.is.running", + "mapping_status": "mapped" + }, + { + "script": "test/e2e/test-overlayfs-autofix.sh", + "line": 171, + "text": "Docker is not running — cannot continue", + "polarity": "fail", + "normalized_id": "docker.is.not.running.cannot.continue", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-overlayfs-autofix.sh", + "line": 176, + "text": "NVIDIA_API_KEY is set", + "polarity": "pass", + "normalized_id": "nvidia.api.key.is.set", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-overlayfs-autofix.sh", + "line": 178, + "text": "NVIDIA_API_KEY not set or invalid", + "polarity": "fail", + "normalized_id": "nvidia.api.key.not.set.or.invalid", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-overlayfs-autofix.sh", + "line": 183, + "text": "NEMOCLAW_NON_INTERACTIVE=1 is required", + "polarity": "fail", + "normalized_id": "nemoclaw.non.interactive.1.is.required", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-overlayfs-autofix.sh", + "line": 188, + "text": "NEMOCLAW_ACCEPT_THIRD_PARTY_SOFTWARE=1 is required", + "polarity": "fail", + "normalized_id": "nemoclaw.accept.third.party.software.1.is.required", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-overlayfs-autofix.sh", + "line": 193, + "text": "Passwordless sudo available", + "polarity": "pass", + "normalized_id": "passwordless.sudo.available", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-overlayfs-autofix.sh", + "line": 195, + "text": "Passwordless sudo required to edit $DAEMON_JSON", + "polarity": "fail", + "normalized_id": "passwordless.sudo.required.to.edit.daemon.json", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-overlayfs-autofix.sh", + "line": 200, + "text": "Cannot find install.sh at $REPO_ROOT/install.sh", + "polarity": "fail", + "normalized_id": "cannot.find.install.sh.at.repo.root.install.sh", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-overlayfs-autofix.sh", + "line": 203, + "text": "Repo root found: $REPO_ROOT", + "polarity": "pass", + "normalized_id": "repo.root.found.repo.root", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-overlayfs-autofix.sh", + "line": 249, + "text": "Failed to restart Docker after daemon.json change", + "polarity": "fail", + "normalized_id": "failed.to.restart.docker.after.daemon.json.change", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-overlayfs-autofix.sh", + "line": 260, + "text": "Docker did not come back up after restart", + "polarity": "fail", + "normalized_id": "docker.did.not.come.back.up.after.restart", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-overlayfs-autofix.sh", + "line": 267, + "text": "Docker storage Driver is now overlayfs", + "polarity": "pass", + "normalized_id": "docker.storage.driver.is.now.overlayfs", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-overlayfs-autofix.sh", + "line": 280, + "text": "DriverStatus reports io.containerd.snapshotter.v1 (the bug-triggering config)", + "polarity": "pass", + "normalized_id": "driverstatus.reports.io.containerd.snapshotter.v1.the.bug.triggering.config", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-overlayfs-autofix.sh", + "line": 310, + "text": "Pre-cleanup complete", + "polarity": "pass", + "normalized_id": "pre.cleanup.complete", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-overlayfs-autofix.sh", + "line": 318, + "text": "Could not cd to repo root: $REPO_ROOT", + "polarity": "fail", + "normalized_id": "could.not.cd.to.repo.root.repo.root", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-overlayfs-autofix.sh", + "line": 355, + "text": "install.sh + onboard completed (exit 0)", + "polarity": "pass", + "normalized_id": "install.sh.onboard.completed.exit.0", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-overlayfs-autofix.sh", + "line": 357, + "text": "install.sh + onboard failed (exit $install_exit)", + "polarity": "fail", + "normalized_id": "install.sh.onboard.failed.exit.install.exit", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-overlayfs-autofix.sh", + "line": 367, + "text": "Onboard log contains the auto-fix detection message", + "polarity": "pass", + "normalized_id": "onboard.log.contains.the.auto.fix.detection.message", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-overlayfs-autofix.sh", + "line": 369, + "text": "Onboard log missing 'Detected Docker 26+ containerd-snapshotter overlayfs'", + "polarity": "fail", + "normalized_id": "onboard.log.missing.detected.docker.26.containerd.snapshotter.overlayfs", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-overlayfs-autofix.sh", + "line": 374, + "text": "Patched cluster image present: $patched_tag", + "polarity": "pass", + "normalized_id": "patched.cluster.image.present.patched.tag", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-overlayfs-autofix.sh", + "line": 376, + "text": "No nemoclaw-cluster:*-fuse-overlayfs-* image found after onboard", + "polarity": "fail", + "normalized_id": "no.nemoclaw.cluster.fuse.overlayfs.image.found.after.onboard", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-overlayfs-autofix.sh", + "line": 386, + "text": "Gateway container is running the patched image", + "polarity": "pass", + "normalized_id": "gateway.container.is.running.the.patched.image", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-overlayfs-autofix.sh", + "line": 388, + "text": "Gateway image '$gateway_image' does not match patched tag '$patched_tag'", + "polarity": "fail", + "normalized_id": "gateway.image.gateway.image.does.not.match.patched.tag.patched.tag", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-overlayfs-autofix.sh", + "line": 394, + "text": "Cluster log still contains the nested-overlay error after auto-fix", + "polarity": "fail", + "normalized_id": "cluster.log.still.contains.the.nested.overlay.error.after.auto.fix", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-overlayfs-autofix.sh", + "line": 396, + "text": "Cluster log clean of the nested-overlay error", + "polarity": "pass", + "normalized_id": "cluster.log.clean.of.the.nested.overlay.error", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-overlayfs-autofix.sh", + "line": 439, + "text": "ensurePatchedClusterImage returned the same tag on second invocation: $second_tag", + "polarity": "pass", + "normalized_id": "ensurepatchedclusterimage.returned.the.same.tag.on.second.invocation.second.tag", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-overlayfs-autofix.sh", + "line": 441, + "text": "ensurePatchedClusterImage tag mismatch (first=$patched_tag second=$second_tag)", + "polarity": "fail", + "normalized_id": "ensurepatchedclusterimage.tag.mismatch.first.patched.tag.second.second.tag", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-overlayfs-autofix.sh", + "line": 445, + "text": "Patched image was reused (Created timestamp unchanged: $before_created)", + "polarity": "pass", + "normalized_id": "patched.image.was.reused.created.timestamp.unchanged.before.created", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-overlayfs-autofix.sh", + "line": 447, + "text": "Patched image was rebuilt unexpectedly (before=$before_created after=$after_created)", + "polarity": "fail", + "normalized_id": "patched.image.was.rebuilt.unexpectedly.before.before.created.after.after.created", + "mapping_status": "retired" + }, + { + "script": "test/e2e/test-overlayfs-autofix.sh", + "line": 481, + "text": "Onboard with auto-fix disabled exited non-zero (exit $negative_exit) within $NEGATIVE_TIMEOUT s", + "polarity": "pass", + "normalized_id": "onboard.with.auto.fix.disabled.exited.non.zero.exit.negative.exit.within.negative.timeout.s", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-overlayfs-autofix.sh", + "line": 483, + "text": "Onboard unexpectedly succeeded with NEMOCLAW_DISABLE_OVERLAY_FIX=1", + "polarity": "fail", + "normalized_id": "onboard.unexpectedly.succeeded.with.nemoclaw.disable.overlay.fix.1", + "mapping_status": "retired" + }, + { + "script": "test/e2e/test-overlayfs-autofix.sh", + "line": 534, + "text": "Cluster/install logs surface a nested-overlay failure signature ($overlay_evidence)", + "polarity": "pass", + "normalized_id": "cluster.install.logs.surface.a.nested.overlay.failure.signature.overlay.evidence", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-overlayfs-autofix.sh", + "line": 538, + "text": "Negative phase exited $negative_exit (not our timeout, no overlay signature) — likely unrelated flake", + "polarity": "fail", + "normalized_id": "negative.phase.exited.negative.exit.not.our.timeout.no.overlay.signature.likely.unrelated.flake", + "mapping_status": "deferred" + } + ] + }, + { + "script": "test/e2e/test-rebuild-hermes.sh", + "assertions": [ + { + "script": "test/e2e/test-rebuild-hermes.sh", + "line": 96, + "text": "NVIDIA_API_KEY is required", + "polarity": "fail", + "normalized_id": "nvidia.api.key.is.required", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-rebuild-hermes.sh", + "line": 97, + "text": "NEMOCLAW_NON_INTERACTIVE=1 is required", + "polarity": "fail", + "normalized_id": "nemoclaw.non.interactive.1.is.required", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-rebuild-hermes.sh", + "line": 102, + "text": "Could not parse expected Hermes version from manifest", + "polarity": "fail", + "normalized_id": "could.not.parse.expected.hermes.version.from.manifest", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-rebuild-hermes.sh", + "line": 138, + "text": "nemoclaw not found on PATH after install", + "polarity": "fail", + "normalized_id": "nemoclaw.not.found.on.path.after.install", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-rebuild-hermes.sh", + "line": 139, + "text": "openshell not found on PATH after install", + "polarity": "fail", + "normalized_id": "openshell.not.found.on.path.after.install", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-rebuild-hermes.sh", + "line": 140, + "text": "NemoClaw installed", + "polarity": "pass", + "normalized_id": "nemoclaw.installed", + "mapping_status": "mapped" + }, + { + "script": "test/e2e/test-rebuild-hermes.sh", + "line": 159, + "text": "Failed to build old Hermes base image", + "polarity": "fail", + "normalized_id": "failed.to.build.old.hermes.base.image", + "mapping_status": "retired" + }, + { + "script": "test/e2e/test-rebuild-hermes.sh", + "line": 161, + "text": "Old Hermes base image built (${OLD_HERMES_VERSION})", + "polarity": "pass", + "normalized_id": "old.hermes.base.image.built.old.hermes.version", + "mapping_status": "retired" + }, + { + "script": "test/e2e/test-rebuild-hermes.sh", + "line": 165, + "text": "Cached Hermes base tag now points at old version", + "polarity": "pass", + "normalized_id": "cached.hermes.base.tag.now.points.at.old.version", + "mapping_status": "retired" + }, + { + "script": "test/e2e/test-rebuild-hermes.sh", + "line": 222, + "text": "Sandbox did not become Ready", + "polarity": "fail", + "normalized_id": "sandbox.did.not.become.ready", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-rebuild-hermes.sh", + "line": 224, + "text": "Old Hermes sandbox created", + "polarity": "pass", + "normalized_id": "old.hermes.sandbox.created", + "mapping_status": "mapped" + }, + { + "script": "test/e2e/test-rebuild-hermes.sh", + "line": 231, + "text": "Failed to write marker file", + "polarity": "fail", + "normalized_id": "failed.to.write.marker.file", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-rebuild-hermes.sh", + "line": 234, + "text": "Marker verification failed", + "polarity": "fail", + "normalized_id": "marker.verification.failed", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-rebuild-hermes.sh", + "line": 237, + "text": "Pre-rebuild Hermes .env missing Discord placeholder", + "polarity": "fail", + "normalized_id": "pre.rebuild.hermes.env.missing.discord.placeholder", + "mapping_status": "retired" + }, + { + "script": "test/e2e/test-rebuild-hermes.sh", + "line": 240, + "text": "Pre-rebuild Hermes config.yaml missing platforms.discord", + "polarity": "fail", + "normalized_id": "pre.rebuild.hermes.config.yaml.missing.platforms.discord", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-rebuild-hermes.sh", + "line": 278, + "text": "Markers written, sandbox registered", + "polarity": "pass", + "normalized_id": "markers.written.sandbox.registered", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-rebuild-hermes.sh", + "line": 291, + "text": "Failed to build current Hermes base image", + "polarity": "fail", + "normalized_id": "failed.to.build.current.hermes.base.image", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-rebuild-hermes.sh", + "line": 293, + "text": "Current Hermes base image built", + "polarity": "pass", + "normalized_id": "current.hermes.base.image.built", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-rebuild-hermes.sh", + "line": 307, + "text": "Rebuild failed", + "polarity": "fail", + "normalized_id": "rebuild.failed", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-rebuild-hermes.sh", + "line": 309, + "text": "Rebuild completed", + "polarity": "pass", + "normalized_id": "rebuild.completed", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-rebuild-hermes.sh", + "line": 317, + "text": "Marker file survived rebuild", + "polarity": "pass", + "normalized_id": "marker.file.survived.rebuild", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-rebuild-hermes.sh", + "line": 319, + "text": "Marker file lost: got '${RESTORED}', expected '${MARKER_CONTENT}'", + "polarity": "fail", + "normalized_id": "marker.file.lost.got.restored.expected.marker.content", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-rebuild-hermes.sh", + "line": 326, + "text": "Hermes binary still reports old version ${OLD_HERMES_REGISTRY_VERSION}", + "polarity": "fail", + "normalized_id": "hermes.binary.still.reports.old.version.old.hermes.registry.version", + "mapping_status": "retired" + }, + { + "script": "test/e2e/test-rebuild-hermes.sh", + "line": 329, + "text": "Hermes binary reports expected version ${EXPECTED_HERMES_VERSION}", + "polarity": "pass", + "normalized_id": "hermes.binary.reports.expected.version.expected.hermes.version", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-rebuild-hermes.sh", + "line": 331, + "text": "Hermes binary version mismatch: expected output to contain '${EXPECTED_HERMES_VERSION}'", + "polarity": "fail", + "normalized_id": "hermes.binary.version.mismatch.expected.output.to.contain.expected.hermes.version", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-rebuild-hermes.sh", + "line": 338, + "text": "Hermes .env preserved Discord token placeholder", + "polarity": "pass", + "normalized_id": "hermes.env.preserved.discord.token.placeholder", + "mapping_status": "retired" + }, + { + "script": "test/e2e/test-rebuild-hermes.sh", + "line": 340, + "text": "Hermes .env lost Discord placeholder after rebuild: ${RESTORED_ENV}", + "polarity": "fail", + "normalized_id": "hermes.env.lost.discord.placeholder.after.rebuild.restored.env", + "mapping_status": "retired" + }, + { + "script": "test/e2e/test-rebuild-hermes.sh", + "line": 345, + "text": "Hermes config.yaml preserved platforms.discord", + "polarity": "pass", + "normalized_id": "hermes.config.yaml.preserved.platforms.discord", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-rebuild-hermes.sh", + "line": 347, + "text": "Hermes config.yaml lost platforms.discord after rebuild: ${RESTORED_CONFIG}", + "polarity": "fail", + "normalized_id": "hermes.config.yaml.lost.platforms.discord.after.rebuild.restored.config", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-rebuild-hermes.sh", + "line": 358, + "text": "Inference works after rebuild (NVIDIA API key + provider chain intact)", + "polarity": "pass", + "normalized_id": "inference.works.after.rebuild.nvidia.api.key.provider.chain.intact", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-rebuild-hermes.sh", + "line": 373, + "text": "Registry agentVersion updated to ${REGISTRY_VERSION}", + "polarity": "pass", + "normalized_id": "registry.agentversion.updated.to.registry.version", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-rebuild-hermes.sh", + "line": 375, + "text": "Registry agentVersion not updated: got '${REGISTRY_VERSION}', expected != '${OLD_HERMES_REGISTRY_VERSION}'", + "polarity": "fail", + "normalized_id": "registry.agentversion.not.updated.got.registry.version.expected.old.hermes.registry.version", + "mapping_status": "retired" + }, + { + "script": "test/e2e/test-rebuild-hermes.sh", + "line": 383, + "text": "No credentials in backup", + "polarity": "pass", + "normalized_id": "no.credentials.in.backup", + "mapping_status": "mapped" + }, + { + "script": "test/e2e/test-rebuild-hermes.sh", + "line": 385, + "text": "Credentials found: $CRED_LEAKS", + "polarity": "fail", + "normalized_id": "credentials.found.cred.leaks", + "mapping_status": "mapped" + }, + { + "script": "test/e2e/test-rebuild-hermes.sh", + "line": 388, + "text": "Backup directory missing: $BACKUP_DIR", + "polarity": "fail", + "normalized_id": "backup.directory.missing.backup.dir", + "mapping_status": "deferred" + } + ] + }, + { + "script": "test/e2e/test-rebuild-openclaw.sh", + "assertions": [ + { + "script": "test/e2e/test-rebuild-openclaw.sh", + "line": 66, + "text": "NVIDIA_API_KEY is required", + "polarity": "fail", + "normalized_id": "nvidia.api.key.is.required", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-rebuild-openclaw.sh", + "line": 67, + "text": "NEMOCLAW_NON_INTERACTIVE=1 is required", + "polarity": "fail", + "normalized_id": "nemoclaw.non.interactive.1.is.required", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-rebuild-openclaw.sh", + "line": 101, + "text": "nemoclaw not found on PATH after install", + "polarity": "fail", + "normalized_id": "nemoclaw.not.found.on.path.after.install", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-rebuild-openclaw.sh", + "line": 102, + "text": "openshell not found on PATH after install", + "polarity": "fail", + "normalized_id": "openshell.not.found.on.path.after.install", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-rebuild-openclaw.sh", + "line": 103, + "text": "NemoClaw installed", + "polarity": "pass", + "normalized_id": "nemoclaw.installed", + "mapping_status": "mapped" + }, + { + "script": "test/e2e/test-rebuild-openclaw.sh", + "line": 132, + "text": "Failed to build old base image", + "polarity": "fail", + "normalized_id": "failed.to.build.old.base.image", + "mapping_status": "retired" + }, + { + "script": "test/e2e/test-rebuild-openclaw.sh", + "line": 134, + "text": "Old base image built (OpenClaw ${OLD_OPENCLAW_VERSION})", + "polarity": "pass", + "normalized_id": "old.base.image.built.openclaw.old.openclaw.version", + "mapping_status": "retired" + }, + { + "script": "test/e2e/test-rebuild-openclaw.sh", + "line": 159, + "text": "Sandbox did not become Ready", + "polarity": "fail", + "normalized_id": "sandbox.did.not.become.ready", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-rebuild-openclaw.sh", + "line": 165, + "text": "Old sandbox created (OpenClaw ${OLD_OPENCLAW_VERSION})", + "polarity": "pass", + "normalized_id": "old.sandbox.created.openclaw.old.openclaw.version", + "mapping_status": "mapped" + }, + { + "script": "test/e2e/test-rebuild-openclaw.sh", + "line": 172, + "text": "Failed to write marker file", + "polarity": "fail", + "normalized_id": "failed.to.write.marker.file", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-rebuild-openclaw.sh", + "line": 176, + "text": "Marker verification failed: got '${VERIFY}'", + "polarity": "fail", + "normalized_id": "marker.verification.failed.got.verify", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-rebuild-openclaw.sh", + "line": 228, + "text": "Markers written, sandbox registered", + "polarity": "pass", + "normalized_id": "markers.written.sandbox.registered", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-rebuild-openclaw.sh", + "line": 263, + "text": "Cannot locate nemoclaw module directory", + "polarity": "fail", + "normalized_id": "cannot.locate.nemoclaw.module.directory", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-rebuild-openclaw.sh", + "line": 272, + "text": "Failed to apply preset: ${preset}", + "polarity": "fail", + "normalized_id": "failed.to.apply.preset.preset", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-rebuild-openclaw.sh", + "line": 278, + "text": "npm preset active in gateway policy", + "polarity": "pass", + "normalized_id": "npm.preset.active.in.gateway.policy", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-rebuild-openclaw.sh", + "line": 280, + "text": "npm preset not found in live gateway policy before rebuild", + "polarity": "fail", + "normalized_id": "npm.preset.not.found.in.live.gateway.policy.before.rebuild", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-rebuild-openclaw.sh", + "line": 283, + "text": "pypi preset active in gateway policy", + "polarity": "pass", + "normalized_id": "pypi.preset.active.in.gateway.policy", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-rebuild-openclaw.sh", + "line": 285, + "text": "pypi preset not found in live gateway policy before rebuild", + "polarity": "fail", + "normalized_id": "pypi.preset.not.found.in.live.gateway.policy.before.rebuild", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-rebuild-openclaw.sh", + "line": 298, + "text": "Policy presets applied and verified", + "polarity": "pass", + "normalized_id": "policy.presets.applied.and.verified", + "mapping_status": "mapped" + }, + { + "script": "test/e2e/test-rebuild-openclaw.sh", + "line": 314, + "text": "Failed to build current base image", + "polarity": "fail", + "normalized_id": "failed.to.build.current.base.image", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-rebuild-openclaw.sh", + "line": 316, + "text": "Current base image restored", + "polarity": "pass", + "normalized_id": "current.base.image.restored", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-rebuild-openclaw.sh", + "line": 322, + "text": "Rebuild failed", + "polarity": "fail", + "normalized_id": "rebuild.failed", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-rebuild-openclaw.sh", + "line": 324, + "text": "Rebuild completed", + "polarity": "pass", + "normalized_id": "rebuild.completed", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-rebuild-openclaw.sh", + "line": 332, + "text": "Marker file survived rebuild", + "polarity": "pass", + "normalized_id": "marker.file.survived.rebuild", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-rebuild-openclaw.sh", + "line": 334, + "text": "Marker file lost: got '${RESTORED}', expected '${MARKER_CONTENT}'", + "polarity": "fail", + "normalized_id": "marker.file.lost.got.restored.expected.marker.content", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-rebuild-openclaw.sh", + "line": 340, + "text": "Could not get OpenClaw version from sandbox (empty output)", + "polarity": "fail", + "normalized_id": "could.not.get.openclaw.version.from.sandbox.empty.output", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-rebuild-openclaw.sh", + "line": 342, + "text": "Version still old after rebuild: ${NEW_VERSION}", + "polarity": "fail", + "normalized_id": "version.still.old.after.rebuild.new.version", + "mapping_status": "retired" + }, + { + "script": "test/e2e/test-rebuild-openclaw.sh", + "line": 344, + "text": "OpenClaw version upgraded: ${NEW_VERSION}", + "polarity": "pass", + "normalized_id": "openclaw.version.upgraded.new.version", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-rebuild-openclaw.sh", + "line": 356, + "text": "Registry agentVersion updated to ${REGISTRY_VERSION}", + "polarity": "pass", + "normalized_id": "registry.agentversion.updated.to.registry.version", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-rebuild-openclaw.sh", + "line": 358, + "text": "Registry agentVersion not updated: got '${REGISTRY_VERSION}', expected != '${OLD_OPENCLAW_VERSION}'", + "polarity": "fail", + "normalized_id": "registry.agentversion.not.updated.got.registry.version.expected.old.openclaw.version", + "mapping_status": "retired" + }, + { + "script": "test/e2e/test-rebuild-openclaw.sh", + "line": 369, + "text": "Inference works after rebuild (NVIDIA API key + provider chain intact)", + "polarity": "pass", + "normalized_id": "inference.works.after.rebuild.nvidia.api.key.provider.chain.intact", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-rebuild-openclaw.sh", + "line": 380, + "text": "No credentials in backup", + "polarity": "pass", + "normalized_id": "no.credentials.in.backup", + "mapping_status": "mapped" + }, + { + "script": "test/e2e/test-rebuild-openclaw.sh", + "line": 382, + "text": "Credentials found: $CRED_LEAKS", + "polarity": "fail", + "normalized_id": "credentials.found.cred.leaks", + "mapping_status": "mapped" + }, + { + "script": "test/e2e/test-rebuild-openclaw.sh", + "line": 385, + "text": "Backup directory missing: $BACKUP_DIR", + "polarity": "fail", + "normalized_id": "backup.directory.missing.backup.dir", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-rebuild-openclaw.sh", + "line": 402, + "text": "npm preset survived rebuild (in registry)", + "polarity": "pass", + "normalized_id": "npm.preset.survived.rebuild.in.registry", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-rebuild-openclaw.sh", + "line": 404, + "text": "npm preset LOST after rebuild — issue #1952", + "polarity": "fail", + "normalized_id": "npm.preset.lost.after.rebuild.issue.1952", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-rebuild-openclaw.sh", + "line": 407, + "text": "pypi preset survived rebuild (in registry)", + "polarity": "pass", + "normalized_id": "pypi.preset.survived.rebuild.in.registry", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-rebuild-openclaw.sh", + "line": 409, + "text": "pypi preset LOST after rebuild — issue #1952", + "polarity": "fail", + "normalized_id": "pypi.preset.lost.after.rebuild.issue.1952", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-rebuild-openclaw.sh", + "line": 415, + "text": "npm preset active in gateway policy after rebuild", + "polarity": "pass", + "normalized_id": "npm.preset.active.in.gateway.policy.after.rebuild", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-rebuild-openclaw.sh", + "line": 417, + "text": "npm preset not in live gateway policy after rebuild — issue #1952", + "polarity": "fail", + "normalized_id": "npm.preset.not.in.live.gateway.policy.after.rebuild.issue.1952", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-rebuild-openclaw.sh", + "line": 420, + "text": "pypi preset active in gateway policy after rebuild", + "polarity": "pass", + "normalized_id": "pypi.preset.active.in.gateway.policy.after.rebuild", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-rebuild-openclaw.sh", + "line": 422, + "text": "pypi preset not in live gateway policy after rebuild — issue #1952", + "polarity": "fail", + "normalized_id": "pypi.preset.not.in.live.gateway.policy.after.rebuild.issue.1952", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-rebuild-openclaw.sh", + "line": 441, + "text": "Backup manifest contains policyPresets: ${MANIFEST_PRESETS}", + "polarity": "pass", + "normalized_id": "backup.manifest.contains.policypresets.manifest.presets", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-rebuild-openclaw.sh", + "line": 443, + "text": "Backup manifest missing expected policyPresets (npm,pypi): got '${MANIFEST_PRESETS}' — issue #1952", + "polarity": "fail", + "normalized_id": "backup.manifest.missing.expected.policypresets.npm.pypi.got.manifest.presets.issue.1952", + "mapping_status": "deferred" + } + ] + }, + { + "script": "test/e2e/test-runtime-overrides.sh", + "assertions": [ + { + "script": "test/e2e/test-runtime-overrides.sh", + "line": 86, + "text": "baseline container failed before config capture", + "polarity": "fail", + "normalized_id": "baseline.container.failed.before.config.capture", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-runtime-overrides.sh", + "line": 104, + "text": "baseline config hash valid", + "polarity": "pass", + "normalized_id": "baseline.config.hash.valid", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-runtime-overrides.sh", + "line": 106, + "text": "baseline config hash invalid", + "polarity": "fail", + "normalized_id": "baseline.config.hash.invalid", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-runtime-overrides.sh", + "line": 116, + "text": "model overridden to $OVERRIDE_MODEL", + "polarity": "pass", + "normalized_id": "model.overridden.to.override.model", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-runtime-overrides.sh", + "line": 118, + "text": "expected model=$OVERRIDE_MODEL, got $ACTUAL", + "polarity": "fail", + "normalized_id": "expected.model.override.model.got.actual", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-runtime-overrides.sh", + "line": 125, + "text": "config hash valid after model override", + "polarity": "pass", + "normalized_id": "config.hash.valid.after.model.override", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-runtime-overrides.sh", + "line": 127, + "text": "config hash invalid after model override", + "polarity": "fail", + "normalized_id": "config.hash.invalid.after.model.override", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-runtime-overrides.sh", + "line": 138, + "text": "contextWindow overridden to 32768", + "polarity": "pass", + "normalized_id": "contextwindow.overridden.to.32768", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-runtime-overrides.sh", + "line": 140, + "text": "expected contextWindow=32768, got $ACTUAL", + "polarity": "fail", + "normalized_id": "expected.contextwindow.32768.got.actual", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-runtime-overrides.sh", + "line": 149, + "text": "maxTokens overridden to 16384", + "polarity": "pass", + "normalized_id": "maxtokens.overridden.to.16384", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-runtime-overrides.sh", + "line": 151, + "text": "expected maxTokens=16384, got $ACTUAL", + "polarity": "fail", + "normalized_id": "expected.maxtokens.16384.got.actual", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-runtime-overrides.sh", + "line": 160, + "text": "reasoning overridden to true", + "polarity": "pass", + "normalized_id": "reasoning.overridden.to.true", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-runtime-overrides.sh", + "line": 162, + "text": "expected reasoning=true, got $ACTUAL", + "polarity": "fail", + "normalized_id": "expected.reasoning.true.got.actual", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-runtime-overrides.sh", + "line": 173, + "text": "CORS origin added: $CORS", + "polarity": "pass", + "normalized_id": "cors.origin.added.cors", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-runtime-overrides.sh", + "line": 176, + "text": "CORS origin not found in allowedOrigins: ${ORIGINS}", + "polarity": "fail", + "normalized_id": "cors.origin.not.found.in.allowedorigins.origins", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-runtime-overrides.sh", + "line": 196, + "text": "all 5 overrides applied correctly", + "polarity": "pass", + "normalized_id": "all.5.overrides.applied.correctly", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-runtime-overrides.sh", + "line": 198, + "text": "combined override mismatch: model=$M ctx=$C max=$T reasoning=$R cors=$O", + "polarity": "fail", + "normalized_id": "combined.override.mismatch.model.m.ctx.c.max.t.reasoning.r.cors.o", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-runtime-overrides.sh", + "line": 206, + "text": "model override with control chars rejected", + "polarity": "pass", + "normalized_id": "model.override.with.control.chars.rejected", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-runtime-overrides.sh", + "line": 208, + "text": "model override with control chars was not rejected", + "polarity": "fail", + "normalized_id": "model.override.with.control.chars.was.not.rejected", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-runtime-overrides.sh", + "line": 214, + "text": "non-integer context window rejected", + "polarity": "pass", + "normalized_id": "non.integer.context.window.rejected", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-runtime-overrides.sh", + "line": 216, + "text": "non-integer context window was not rejected", + "polarity": "fail", + "normalized_id": "non.integer.context.window.was.not.rejected", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-runtime-overrides.sh", + "line": 222, + "text": "non-integer max tokens rejected", + "polarity": "pass", + "normalized_id": "non.integer.max.tokens.rejected", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-runtime-overrides.sh", + "line": 224, + "text": "non-integer max tokens was not rejected", + "polarity": "fail", + "normalized_id": "non.integer.max.tokens.was.not.rejected", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-runtime-overrides.sh", + "line": 230, + "text": "invalid reasoning value rejected", + "polarity": "pass", + "normalized_id": "invalid.reasoning.value.rejected", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-runtime-overrides.sh", + "line": 232, + "text": "invalid reasoning value was not rejected", + "polarity": "fail", + "normalized_id": "invalid.reasoning.value.was.not.rejected", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-runtime-overrides.sh", + "line": 238, + "text": "non-http CORS origin rejected", + "polarity": "pass", + "normalized_id": "non.http.cors.origin.rejected", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-runtime-overrides.sh", + "line": 240, + "text": "non-http CORS origin was not rejected", + "polarity": "fail", + "normalized_id": "non.http.cors.origin.was.not.rejected", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-runtime-overrides.sh", + "line": 246, + "text": "invalid inference API type rejected", + "polarity": "pass", + "normalized_id": "invalid.inference.api.type.rejected", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-runtime-overrides.sh", + "line": 248, + "text": "invalid inference API type was not rejected", + "polarity": "fail", + "normalized_id": "invalid.inference.api.type.was.not.rejected", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-runtime-overrides.sh", + "line": 258, + "text": "config unchanged after rejected override", + "polarity": "pass", + "normalized_id": "config.unchanged.after.rejected.override", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-runtime-overrides.sh", + "line": 260, + "text": "config was modified despite rejected override: model=$ACTUAL_MODEL ctx=$ACTUAL_CTX (expected model=$BASELINE_MODEL ctx=$BASELINE_CTX)", + "polarity": "fail", + "normalized_id": "config.was.modified.despite.rejected.override.model.actual.model.ctx.actual.ctx.expected.model.baseline.model.ctx.baseline.ctx", + "mapping_status": "deferred" + } + ] + }, + { + "script": "test/e2e/test-sandbox-operations.sh", + "assertions": [ + { + "script": "test/e2e/test-sandbox-operations.sh", + "line": 338, + "text": "TC-SBX-01: nemoclaw list shows '$SANDBOX_A'", + "polarity": "pass", + "normalized_id": "tc.sbx.01.nemoclaw.list.shows.sandbox.a", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-sandbox-operations.sh", + "line": 340, + "text": "TC-SBX-01: List Sandboxes", + "polarity": "fail", + "normalized_id": "tc.sbx.01.list.sandboxes", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-sandbox-operations.sh", + "line": 375, + "text": "TC-SBX-02: Connect & Chat", + "polarity": "fail", + "normalized_id": "tc.sbx.02.connect.chat", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-sandbox-operations.sh", + "line": 402, + "text": "TC-SBX-02: Agent computed 6×7=42 through openclaw → inference.local", + "polarity": "pass", + "normalized_id": "tc.sbx.02.agent.computed.6.7.42.through.openclaw.inference.local", + "mapping_status": "mapped" + }, + { + "script": "test/e2e/test-sandbox-operations.sh", + "line": 404, + "text": "TC-SBX-02: Connect & Chat", + "polarity": "fail", + "normalized_id": "tc.sbx.02.connect.chat", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-sandbox-operations.sh", + "line": 427, + "text": "TC-SBX-03: Status output contains all expected fields", + "polarity": "pass", + "normalized_id": "tc.sbx.03.status.output.contains.all.expected.fields", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-sandbox-operations.sh", + "line": 429, + "text": "TC-SBX-03: Status Fields", + "polarity": "fail", + "normalized_id": "tc.sbx.03.status.fields", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-sandbox-operations.sh", + "line": 442, + "text": "TC-SBX-04: Log Streaming", + "polarity": "fail", + "normalized_id": "tc.sbx.04.log.streaming", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-sandbox-operations.sh", + "line": 444, + "text": "TC-SBX-04: Log streaming produced output ($(echo ", + "polarity": "pass", + "normalized_id": "tc.sbx.04.log.streaming.produced.output.echo", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-sandbox-operations.sh", + "line": 446, + "text": "TC-SBX-04: Log Streaming", + "polarity": "fail", + "normalized_id": "tc.sbx.04.log.streaming", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-sandbox-operations.sh", + "line": 454, + "text": "TC-SBX-04: Log --follow", + "polarity": "fail", + "normalized_id": "tc.sbx.04.log.follow", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-sandbox-operations.sh", + "line": 459, + "text": "TC-SBX-04: Log --follow cleanup", + "polarity": "fail", + "normalized_id": "tc.sbx.04.log.follow.cleanup", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-sandbox-operations.sh", + "line": 461, + "text": "TC-SBX-04: Log --follow exited cleanly after kill", + "polarity": "pass", + "normalized_id": "tc.sbx.04.log.follow.exited.cleanly.after.kill", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-sandbox-operations.sh", + "line": 489, + "text": "TC-SBX-07: Registry rebuilt — '$SANDBOX_A' found after deletion", + "polarity": "pass", + "normalized_id": "tc.sbx.07.registry.rebuilt.sandbox.a.found.after.deletion", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-sandbox-operations.sh", + "line": 492, + "text": "TC-SBX-07: Registry Rebuild", + "polarity": "fail", + "normalized_id": "tc.sbx.07.registry.rebuild", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-sandbox-operations.sh", + "line": 518, + "text": "TC-SBX-08: Process Recovery (status)", + "polarity": "fail", + "normalized_id": "tc.sbx.08.process.recovery.status", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-sandbox-operations.sh", + "line": 520, + "text": "TC-SBX-08: Status detected and recovered dead OpenClaw process", + "polarity": "pass", + "normalized_id": "tc.sbx.08.status.detected.and.recovered.dead.openclaw.process", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-sandbox-operations.sh", + "line": 522, + "text": "TC-SBX-08: Process Recovery (status)", + "polarity": "fail", + "normalized_id": "tc.sbx.08.process.recovery.status", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-sandbox-operations.sh", + "line": 529, + "text": "TC-SBX-08: SSH works after process recovery", + "polarity": "pass", + "normalized_id": "tc.sbx.08.ssh.works.after.process.recovery", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-sandbox-operations.sh", + "line": 531, + "text": "TC-SBX-08: Process Recovery (SSH)", + "polarity": "fail", + "normalized_id": "tc.sbx.08.process.recovery.ssh", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-sandbox-operations.sh", + "line": 550, + "text": "TC-SBX-05: Destroy ($target)", + "polarity": "fail", + "normalized_id": "tc.sbx.05.destroy.target", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-sandbox-operations.sh", + "line": 554, + "text": "TC-SBX-05: Destroy ($target)", + "polarity": "fail", + "normalized_id": "tc.sbx.05.destroy.target", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-sandbox-operations.sh", + "line": 556, + "text": "TC-SBX-05: '$target' removed from nemoclaw list", + "polarity": "pass", + "normalized_id": "tc.sbx.05.target.removed.from.nemoclaw.list", + "mapping_status": "retired" + }, + { + "script": "test/e2e/test-sandbox-operations.sh", + "line": 560, + "text": "TC-SBX-05: Destroy ($target)", + "polarity": "fail", + "normalized_id": "tc.sbx.05.destroy.target", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-sandbox-operations.sh", + "line": 562, + "text": "TC-SBX-05: '$target' removed from openshell sandbox list", + "polarity": "pass", + "normalized_id": "tc.sbx.05.target.removed.from.openshell.sandbox.list", + "mapping_status": "retired" + }, + { + "script": "test/e2e/test-sandbox-operations.sh", + "line": 630, + "text": "TC-SBX-06: Gateway recovered after docker kill", + "polarity": "pass", + "normalized_id": "tc.sbx.06.gateway.recovered.after.docker.kill", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-sandbox-operations.sh", + "line": 634, + "text": "TC-SBX-06: Gateway Recovery", + "polarity": "fail", + "normalized_id": "tc.sbx.06.gateway.recovery", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-sandbox-operations.sh", + "line": 648, + "text": "TC-SBX-10: Multi-Sandbox", + "polarity": "fail", + "normalized_id": "tc.sbx.10.multi.sandbox", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-sandbox-operations.sh", + "line": 660, + "text": "TC-SBX-10: Both sandboxes visible in nemoclaw list", + "polarity": "pass", + "normalized_id": "tc.sbx.10.both.sandboxes.visible.in.nemoclaw.list", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-sandbox-operations.sh", + "line": 662, + "text": "TC-SBX-10: Multi-Sandbox", + "polarity": "fail", + "normalized_id": "tc.sbx.10.multi.sandbox", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-sandbox-operations.sh", + "line": 687, + "text": "TC-SBX-10: Both sandboxes have non-empty metadata", + "polarity": "pass", + "normalized_id": "tc.sbx.10.both.sandboxes.have.non.empty.metadata", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-sandbox-operations.sh", + "line": 689, + "text": "TC-SBX-10: Multi-Sandbox Metadata", + "polarity": "fail", + "normalized_id": "tc.sbx.10.multi.sandbox.metadata", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-sandbox-operations.sh", + "line": 715, + "text": "TC-SBX-11: Isolation (A→B)", + "polarity": "fail", + "normalized_id": "tc.sbx.11.isolation.a.b", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-sandbox-operations.sh", + "line": 717, + "text": "TC-SBX-11: Sandbox A cannot reach sandbox B ($(echo ", + "polarity": "pass", + "normalized_id": "tc.sbx.11.sandbox.a.cannot.reach.sandbox.b.echo", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-sandbox-operations.sh", + "line": 719, + "text": "TC-SBX-11: Isolation (A→B)", + "polarity": "fail", + "normalized_id": "tc.sbx.11.isolation.a.b", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-sandbox-operations.sh", + "line": 721, + "text": "TC-SBX-11: Isolation (A→B)", + "polarity": "fail", + "normalized_id": "tc.sbx.11.isolation.a.b", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-sandbox-operations.sh", + "line": 737, + "text": "TC-SBX-11: Isolation (B→A)", + "polarity": "fail", + "normalized_id": "tc.sbx.11.isolation.b.a", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-sandbox-operations.sh", + "line": 739, + "text": "TC-SBX-11: Sandbox B cannot reach sandbox A ($(echo ", + "polarity": "pass", + "normalized_id": "tc.sbx.11.sandbox.b.cannot.reach.sandbox.a.echo", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-sandbox-operations.sh", + "line": 741, + "text": "TC-SBX-11: Isolation (B→A)", + "polarity": "fail", + "normalized_id": "tc.sbx.11.isolation.b.a", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-sandbox-operations.sh", + "line": 743, + "text": "TC-SBX-11: Isolation (B→A)", + "polarity": "fail", + "normalized_id": "tc.sbx.11.isolation.b.a", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-sandbox-operations.sh", + "line": 774, + "text": "$PASS${NC}", + "polarity": "pass", + "normalized_id": "pass.nc", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-sandbox-operations.sh", + "line": 775, + "text": "$FAIL${NC}", + "polarity": "fail", + "normalized_id": "fail.nc", + "mapping_status": "deferred" + } + ] + }, + { + "script": "test/e2e/test-sandbox-rebuild.sh", + "assertions": [ + { + "script": "test/e2e/test-sandbox-rebuild.sh", + "line": 60, + "text": "NVIDIA_API_KEY is required", + "polarity": "fail", + "normalized_id": "nvidia.api.key.is.required", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-sandbox-rebuild.sh", + "line": 61, + "text": "NEMOCLAW_NON_INTERACTIVE=1 is required", + "polarity": "fail", + "normalized_id": "nemoclaw.non.interactive.1.is.required", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-sandbox-rebuild.sh", + "line": 86, + "text": "Onboard failed", + "polarity": "fail", + "normalized_id": "onboard.failed", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-sandbox-rebuild.sh", + "line": 88, + "text": "Sandbox created", + "polarity": "pass", + "normalized_id": "sandbox.created", + "mapping_status": "mapped" + }, + { + "script": "test/e2e/test-sandbox-rebuild.sh", + "line": 95, + "text": "Version detection: agent version visible in status", + "polarity": "pass", + "normalized_id": "version.detection.agent.version.visible.in.status", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-sandbox-rebuild.sh", + "line": 106, + "text": "Failed to write marker file", + "polarity": "fail", + "normalized_id": "failed.to.write.marker.file", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-sandbox-rebuild.sh", + "line": 110, + "text": "Marker file verification failed: got '$VERIFY'", + "polarity": "fail", + "normalized_id": "marker.file.verification.failed.got.verify", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-sandbox-rebuild.sh", + "line": 112, + "text": "Marker file written and verified", + "polarity": "pass", + "normalized_id": "marker.file.written.and.verified", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-sandbox-rebuild.sh", + "line": 135, + "text": "Staleness warning appears on connect", + "polarity": "pass", + "normalized_id": "staleness.warning.appears.on.connect", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-sandbox-rebuild.sh", + "line": 145, + "text": "Rebuild failed", + "polarity": "fail", + "normalized_id": "rebuild.failed", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-sandbox-rebuild.sh", + "line": 147, + "text": "Rebuild completed", + "polarity": "pass", + "normalized_id": "rebuild.completed", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-sandbox-rebuild.sh", + "line": 154, + "text": "Marker file survived rebuild", + "polarity": "pass", + "normalized_id": "marker.file.survived.rebuild", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-sandbox-rebuild.sh", + "line": 156, + "text": "Marker file missing or changed after rebuild: got '$RESTORED', expected '$MARKER_CONTENT'", + "polarity": "fail", + "normalized_id": "marker.file.missing.or.changed.after.rebuild.got.restored.expected.marker.content", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-sandbox-rebuild.sh", + "line": 171, + "text": "Registry agentVersion updated to $REGISTRY_VERSION", + "polarity": "pass", + "normalized_id": "registry.agentversion.updated.to.registry.version", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-sandbox-rebuild.sh", + "line": 173, + "text": "Registry agentVersion not updated: got '$REGISTRY_VERSION'", + "polarity": "fail", + "normalized_id": "registry.agentversion.not.updated.got.registry.version", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-sandbox-rebuild.sh", + "line": 184, + "text": "No credentials found in backup directory", + "polarity": "pass", + "normalized_id": "no.credentials.found.in.backup.directory", + "mapping_status": "mapped" + }, + { + "script": "test/e2e/test-sandbox-rebuild.sh", + "line": 186, + "text": "Credentials found in backup files: $CRED_LEAKS", + "polarity": "fail", + "normalized_id": "credentials.found.in.backup.files.cred.leaks", + "mapping_status": "mapped" + } + ] + }, + { + "script": "test/e2e/test-sandbox-survival.sh", + "assertions": [ + { + "script": "test/e2e/test-sandbox-survival.sh", + "line": 182, + "text": "Gateway recovered through NemoClaw status", + "polarity": "pass", + "normalized_id": "gateway.recovered.through.nemoclaw.status", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-sandbox-survival.sh", + "line": 192, + "text": "Gateway start command succeeded", + "polarity": "pass", + "normalized_id": "gateway.start.command.succeeded", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-sandbox-survival.sh", + "line": 204, + "text": "Docker is running", + "polarity": "pass", + "normalized_id": "docker.is.running", + "mapping_status": "mapped" + }, + { + "script": "test/e2e/test-sandbox-survival.sh", + "line": 206, + "text": "Docker is not running — cannot continue", + "polarity": "fail", + "normalized_id": "docker.is.not.running.cannot.continue", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-sandbox-survival.sh", + "line": 211, + "text": "NVIDIA_API_KEY is set (starts with nvapi-)", + "polarity": "pass", + "normalized_id": "nvidia.api.key.is.set.starts.with.nvapi", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-sandbox-survival.sh", + "line": 213, + "text": "NVIDIA_API_KEY not set or invalid — required for live inference", + "polarity": "fail", + "normalized_id": "nvidia.api.key.not.set.or.invalid.required.for.live.inference", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-sandbox-survival.sh", + "line": 218, + "text": "Network access to integrate.api.nvidia.com", + "polarity": "pass", + "normalized_id": "network.access.to.integrate.api.nvidia.com", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-sandbox-survival.sh", + "line": 220, + "text": "Cannot reach integrate.api.nvidia.com", + "polarity": "fail", + "normalized_id": "cannot.reach.integrate.api.nvidia.com", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-sandbox-survival.sh", + "line": 225, + "text": "NEMOCLAW_NON_INTERACTIVE=1 is required", + "polarity": "fail", + "normalized_id": "nemoclaw.non.interactive.1.is.required", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-sandbox-survival.sh", + "line": 230, + "text": "NEMOCLAW_ACCEPT_THIRD_PARTY_SOFTWARE=1 is required", + "polarity": "fail", + "normalized_id": "nemoclaw.accept.third.party.software.1.is.required", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-sandbox-survival.sh", + "line": 235, + "text": "Cannot find install.sh at $REPO_ROOT/install.sh", + "polarity": "fail", + "normalized_id": "cannot.find.install.sh.at.repo.root.install.sh", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-sandbox-survival.sh", + "line": 238, + "text": "Repo root found: $REPO_ROOT", + "polarity": "pass", + "normalized_id": "repo.root.found.repo.root", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-sandbox-survival.sh", + "line": 255, + "text": "Pre-cleanup complete", + "polarity": "pass", + "normalized_id": "pre.cleanup.complete", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-sandbox-survival.sh", + "line": 265, + "text": "Could not cd to repo root: $REPO_ROOT", + "polarity": "fail", + "normalized_id": "could.not.cd.to.repo.root.repo.root", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-sandbox-survival.sh", + "line": 300, + "text": "install.sh completed (exit 0)", + "polarity": "pass", + "normalized_id": "install.sh.completed.exit.0", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-sandbox-survival.sh", + "line": 302, + "text": "install.sh failed (exit $install_exit)", + "polarity": "fail", + "normalized_id": "install.sh.failed.exit.install.exit", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-sandbox-survival.sh", + "line": 308, + "text": "nemoclaw on PATH: $(command -v nemoclaw)", + "polarity": "pass", + "normalized_id": "nemoclaw.on.path.command.v.nemoclaw", + "mapping_status": "mapped" + }, + { + "script": "test/e2e/test-sandbox-survival.sh", + "line": 310, + "text": "nemoclaw not found on PATH after install", + "polarity": "fail", + "normalized_id": "nemoclaw.not.found.on.path.after.install", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-sandbox-survival.sh", + "line": 316, + "text": "openshell not found on PATH after install", + "polarity": "fail", + "normalized_id": "openshell.not.found.on.path.after.install", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-sandbox-survival.sh", + "line": 322, + "text": "openshell $OPENSHELL_VERSION >= $MIN_OPENSHELL (gateway resume + SSH secret + state persistence)", + "polarity": "pass", + "normalized_id": "openshell.openshell.version.min.openshell.gateway.resume.ssh.secret.state.persistence", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-sandbox-survival.sh", + "line": 324, + "text": "openshell $OPENSHELL_VERSION < $MIN_OPENSHELL — sandbox survival requires $MIN_OPENSHELL+", + "polarity": "fail", + "normalized_id": "openshell.openshell.version.min.openshell.sandbox.survival.requires.min.openshell", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-sandbox-survival.sh", + "line": 335, + "text": "NemoClaw registry contains '$SANDBOX_NAME'", + "polarity": "pass", + "normalized_id": "nemoclaw.registry.contains.sandbox.name", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-sandbox-survival.sh", + "line": 337, + "text": "NemoClaw registry missing '$SANDBOX_NAME' — onboard may have failed", + "polarity": "fail", + "normalized_id": "nemoclaw.registry.missing.sandbox.name.onboard.may.have.failed", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-sandbox-survival.sh", + "line": 343, + "text": "nemoclaw list shows '$SANDBOX_NAME'", + "polarity": "pass", + "normalized_id": "nemoclaw.list.shows.sandbox.name", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-sandbox-survival.sh", + "line": 345, + "text": "nemoclaw list doesn't show '$SANDBOX_NAME': ${list_output:0:200}", + "polarity": "fail", + "normalized_id": "nemoclaw.list.doesn.t.show.sandbox.name.list.output.0.200", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-sandbox-survival.sh", + "line": 351, + "text": "openshell sandbox list shows '$SANDBOX_NAME'", + "polarity": "pass", + "normalized_id": "openshell.sandbox.list.shows.sandbox.name", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-sandbox-survival.sh", + "line": 353, + "text": "openshell sandbox list doesn't show '$SANDBOX_NAME': ${os_list:0:200}", + "polarity": "fail", + "normalized_id": "openshell.sandbox.list.doesn.t.show.sandbox.name.os.list.0.200", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-sandbox-survival.sh", + "line": 359, + "text": "nemoclaw $SANDBOX_NAME status exits 0", + "polarity": "pass", + "normalized_id": "nemoclaw.sandbox.name.status.exits.0", + "mapping_status": "mapped" + }, + { + "script": "test/e2e/test-sandbox-survival.sh", + "line": 361, + "text": "nemoclaw $SANDBOX_NAME status failed: ${status_output:0:200}", + "polarity": "fail", + "normalized_id": "nemoclaw.sandbox.name.status.failed.status.output.0.200", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-sandbox-survival.sh", + "line": 370, + "text": "Could not get SSH config for sandbox", + "polarity": "fail", + "normalized_id": "could.not.get.ssh.config.for.sandbox", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-sandbox-survival.sh", + "line": 373, + "text": "SSH config obtained", + "polarity": "pass", + "normalized_id": "ssh.config.obtained", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-sandbox-survival.sh", + "line": 377, + "text": "SSH into sandbox works (baseline)", + "polarity": "pass", + "normalized_id": "ssh.into.sandbox.works.baseline", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-sandbox-survival.sh", + "line": 379, + "text": "SSH into sandbox failed (baseline) — cannot continue", + "polarity": "fail", + "normalized_id": "ssh.into.sandbox.failed.baseline.cannot.continue", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-sandbox-survival.sh", + "line": 417, + "text": "[LIVE] Baseline: model responded with PONG through sandbox", + "polarity": "pass", + "normalized_id": "live.baseline.model.responded.with.pong.through.sandbox", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-sandbox-survival.sh", + "line": 419, + "text": "[LIVE] Baseline: expected PONG after 3 attempts, got: ${baseline_content:0:200}", + "polarity": "fail", + "normalized_id": "live.baseline.expected.pong.after.3.attempts.got.baseline.content.0.200", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-sandbox-survival.sh", + "line": 438, + "text": "Planted workspace marker: /sandbox/.openclaw/.survival-marker-workspace", + "polarity": "pass", + "normalized_id": "planted.workspace.marker.sandbox.openclaw.survival.marker.workspace", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-sandbox-survival.sh", + "line": 440, + "text": "Could not plant workspace marker", + "polarity": "fail", + "normalized_id": "could.not.plant.workspace.marker", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-sandbox-survival.sh", + "line": 446, + "text": "Workspace marker verified before restart", + "polarity": "pass", + "normalized_id": "workspace.marker.verified.before.restart", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-sandbox-survival.sh", + "line": 448, + "text": "Workspace marker read-back mismatch: expected '$MARKER_VALUE', got '$readback'", + "polarity": "fail", + "normalized_id": "workspace.marker.read.back.mismatch.expected.marker.value.got.readback", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-sandbox-survival.sh", + "line": 460, + "text": "Planted agent data marker: /sandbox/.openclaw/.survival-marker", + "polarity": "pass", + "normalized_id": "planted.agent.data.marker.sandbox.openclaw.survival.marker", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-sandbox-survival.sh", + "line": 462, + "text": "Could not plant agent data marker", + "polarity": "fail", + "normalized_id": "could.not.plant.agent.data.marker", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-sandbox-survival.sh", + "line": 484, + "text": "Planted nested marker: /sandbox/.openclaw/test-data/nested-marker.txt", + "polarity": "pass", + "normalized_id": "planted.nested.marker.sandbox.openclaw.test.data.nested.marker.txt", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-sandbox-survival.sh", + "line": 486, + "text": "Could not plant nested workspace marker", + "polarity": "fail", + "normalized_id": "could.not.plant.nested.workspace.marker", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-sandbox-survival.sh", + "line": 503, + "text": "Gateway runtime stopped", + "polarity": "pass", + "normalized_id": "gateway.runtime.stopped", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-sandbox-survival.sh", + "line": 505, + "text": "Gateway runtime still appears to be running after stop", + "polarity": "fail", + "normalized_id": "gateway.runtime.still.appears.to.be.running.after.stop", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-sandbox-survival.sh", + "line": 515, + "text": "Docker container confirmed stopped", + "polarity": "pass", + "normalized_id": "docker.container.confirmed.stopped", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-sandbox-survival.sh", + "line": 518, + "text": "Docker container not running", + "polarity": "pass", + "normalized_id": "docker.container.not.running", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-sandbox-survival.sh", + "line": 520, + "text": "Docker container still running: state=$container_state", + "polarity": "fail", + "normalized_id": "docker.container.still.running.state.container.state", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-sandbox-survival.sh", + "line": 523, + "text": "Docker-driver gateway process is not running", + "polarity": "pass", + "normalized_id": "docker.driver.gateway.process.is.not.running", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-sandbox-survival.sh", + "line": 545, + "text": "Gateway healthy after restart (attempt $attempt)", + "polarity": "pass", + "normalized_id": "gateway.healthy.after.restart.attempt.attempt", + "mapping_status": "mapped" + }, + { + "script": "test/e2e/test-sandbox-survival.sh", + "line": 547, + "text": "Gateway did not become healthy within 300 seconds", + "polarity": "fail", + "normalized_id": "gateway.did.not.become.healthy.within.300.seconds", + "mapping_status": "mapped" + }, + { + "script": "test/e2e/test-sandbox-survival.sh", + "line": 559, + "text": "openshell sandbox list shows '$SANDBOX_NAME' after restart", + "polarity": "pass", + "normalized_id": "openshell.sandbox.list.shows.sandbox.name.after.restart", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-sandbox-survival.sh", + "line": 561, + "text": "openshell sandbox list: '$SANDBOX_NAME' NOT FOUND after restart (#486)", + "polarity": "fail", + "normalized_id": "openshell.sandbox.list.sandbox.name.not.found.after.restart.486", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-sandbox-survival.sh", + "line": 576, + "text": "Sandbox pod is '$sandbox_phase' after restart", + "polarity": "pass", + "normalized_id": "sandbox.pod.is.sandbox.phase.after.restart", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-sandbox-survival.sh", + "line": 578, + "text": "Sandbox pod did not reach Running/Ready after restart", + "polarity": "fail", + "normalized_id": "sandbox.pod.did.not.reach.running.ready.after.restart", + "mapping_status": "mapped" + }, + { + "script": "test/e2e/test-sandbox-survival.sh", + "line": 584, + "text": "NemoClaw registry still contains '$SANDBOX_NAME' after restart", + "polarity": "pass", + "normalized_id": "nemoclaw.registry.still.contains.sandbox.name.after.restart", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-sandbox-survival.sh", + "line": 586, + "text": "NemoClaw registry lost '$SANDBOX_NAME' after restart (#486)", + "polarity": "fail", + "normalized_id": "nemoclaw.registry.lost.sandbox.name.after.restart.486", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-sandbox-survival.sh", + "line": 591, + "text": "nemoclaw list shows '$SANDBOX_NAME' after restart", + "polarity": "pass", + "normalized_id": "nemoclaw.list.shows.sandbox.name.after.restart", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-sandbox-survival.sh", + "line": 593, + "text": "nemoclaw list doesn't show '$SANDBOX_NAME' after restart: ${list_output:0:200}", + "polarity": "fail", + "normalized_id": "nemoclaw.list.doesn.t.show.sandbox.name.after.restart.list.output.0.200", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-sandbox-survival.sh", + "line": 611, + "text": "nemoclaw $SANDBOX_NAME status exits 0 after restart (no re-onboard needed)", + "polarity": "pass", + "normalized_id": "nemoclaw.sandbox.name.status.exits.0.after.restart.no.re.onboard.needed", + "mapping_status": "mapped" + }, + { + "script": "test/e2e/test-sandbox-survival.sh", + "line": 613, + "text": "nemoclaw $SANDBOX_NAME status TIMED OUT after restart (port forward or SSH recovery hung)", + "polarity": "fail", + "normalized_id": "nemoclaw.sandbox.name.status.timed.out.after.restart.port.forward.or.ssh.recovery.hung", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-sandbox-survival.sh", + "line": 615, + "text": "nemoclaw $SANDBOX_NAME status failed after restart (exit $status_exit): ${status_output:0:200}", + "polarity": "fail", + "normalized_id": "nemoclaw.sandbox.name.status.failed.after.restart.exit.status.exit.status.output.0.200", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-sandbox-survival.sh", + "line": 624, + "text": "Could not get SSH config after restart (#888 handshake failure?)", + "polarity": "fail", + "normalized_id": "could.not.get.ssh.config.after.restart.888.handshake.failure", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-sandbox-survival.sh", + "line": 645, + "text": "SSH config available after restart", + "polarity": "pass", + "normalized_id": "ssh.config.available.after.restart", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-sandbox-survival.sh", + "line": 661, + "text": "SSH into sandbox works after restart (attempt $ssh_attempt, no handshake failure — #888/#1086)", + "polarity": "pass", + "normalized_id": "ssh.into.sandbox.works.after.restart.attempt.ssh.attempt.no.handshake.failure.888.1086", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-sandbox-survival.sh", + "line": 663, + "text": "SSH into sandbox FAILED after restart — handshake verification likely failed (#888/#1086)", + "polarity": "fail", + "normalized_id": "ssh.into.sandbox.failed.after.restart.handshake.verification.likely.failed.888.1086", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-sandbox-survival.sh", + "line": 678, + "text": "Workspace marker survived restart: $MARKER_VALUE", + "polarity": "pass", + "normalized_id": "workspace.marker.survived.restart.marker.value", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-sandbox-survival.sh", + "line": 680, + "text": "Workspace marker LOST: expected '$MARKER_VALUE', got '${post_restart_marker:-}' (#1086 state loss)", + "polarity": "fail", + "normalized_id": "workspace.marker.lost.expected.marker.value.got.post.restart.marker.empty.1086.state.loss", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-sandbox-survival.sh", + "line": 687, + "text": "Agent data marker survived restart", + "polarity": "pass", + "normalized_id": "agent.data.marker.survived.restart", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-sandbox-survival.sh", + "line": 689, + "text": "Agent data marker LOST: expected '$MARKER_VALUE', got '${agent_marker:-}' (agent state destroyed)", + "polarity": "fail", + "normalized_id": "agent.data.marker.lost.expected.marker.value.got.agent.marker.empty.agent.state.destroyed", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-sandbox-survival.sh", + "line": 696, + "text": "Nested workspace marker survived restart", + "polarity": "pass", + "normalized_id": "nested.workspace.marker.survived.restart", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-sandbox-survival.sh", + "line": 698, + "text": "Nested workspace marker LOST: expected '$MARKER_VALUE', got '${nested_marker:-}'", + "polarity": "fail", + "normalized_id": "nested.workspace.marker.lost.expected.marker.value.got.nested.marker.empty", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-sandbox-survival.sh", + "line": 710, + "text": "Agent data directory still populated after restart", + "polarity": "pass", + "normalized_id": "agent.data.directory.still.populated.after.restart", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-sandbox-survival.sh", + "line": 712, + "text": "Agent data directory is empty after restart (@Koneisto overlay wipe)", + "polarity": "fail", + "normalized_id": "agent.data.directory.is.empty.after.restart.koneisto.overlay.wipe", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-sandbox-survival.sh", + "line": 752, + "text": "[LIVE] Post-restart: model responded with PONG through sandbox", + "polarity": "pass", + "normalized_id": "live.post.restart.model.responded.with.pong.through.sandbox", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-sandbox-survival.sh", + "line": 756, + "text": "[LIVE] Post-restart: expected PONG after 3 attempts, got: ${post_content:0:200}", + "polarity": "fail", + "normalized_id": "live.post.restart.expected.pong.after.3.attempts.got.post.content.0.200", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-sandbox-survival.sh", + "line": 771, + "text": "Sandbox '$SANDBOX_NAME' still in registry after destroy", + "polarity": "fail", + "normalized_id": "sandbox.sandbox.name.still.in.registry.after.destroy", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-sandbox-survival.sh", + "line": 773, + "text": "Sandbox '$SANDBOX_NAME' cleaned up", + "polarity": "pass", + "normalized_id": "sandbox.sandbox.name.cleaned.up", + "mapping_status": "deferred" + } + ] + }, + { + "script": "test/e2e/test-shields-config.sh", + "assertions": [ + { + "script": "test/e2e/test-shields-config.sh", + "line": 75, + "text": "Docker is running", + "polarity": "pass", + "normalized_id": "docker.is.running", + "mapping_status": "mapped" + }, + { + "script": "test/e2e/test-shields-config.sh", + "line": 77, + "text": "Docker is not running — cannot continue", + "polarity": "fail", + "normalized_id": "docker.is.not.running.cannot.continue", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-shields-config.sh", + "line": 82, + "text": "NVIDIA_API_KEY is set", + "polarity": "pass", + "normalized_id": "nvidia.api.key.is.set", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-shields-config.sh", + "line": 84, + "text": "NVIDIA_API_KEY not set or invalid", + "polarity": "fail", + "normalized_id": "nvidia.api.key.not.set.or.invalid", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-shields-config.sh", + "line": 89, + "text": "NEMOCLAW_NON_INTERACTIVE=1 is required", + "polarity": "fail", + "normalized_id": "nemoclaw.non.interactive.1.is.required", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-shields-config.sh", + "line": 94, + "text": "NEMOCLAW_ACCEPT_THIRD_PARTY_SOFTWARE=1 is required", + "polarity": "fail", + "normalized_id": "nemoclaw.accept.third.party.software.1.is.required", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-shields-config.sh", + "line": 98, + "text": "Prerequisites OK", + "polarity": "pass", + "normalized_id": "prerequisites.ok", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-shields-config.sh", + "line": 126, + "text": "install.sh failed (see $INSTALL_LOG)", + "polarity": "fail", + "normalized_id": "install.sh.failed.see.install.log", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-shields-config.sh", + "line": 145, + "text": "nemoclaw not on PATH", + "polarity": "fail", + "normalized_id": "nemoclaw.not.on.path", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-shields-config.sh", + "line": 149, + "text": "openshell not on PATH", + "polarity": "fail", + "normalized_id": "openshell.not.on.path", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-shields-config.sh", + "line": 152, + "text": "NemoClaw installed (sandbox: $SANDBOX_NAME)", + "polarity": "pass", + "normalized_id": "nemoclaw.installed.sandbox.sandbox.name", + "mapping_status": "mapped" + }, + { + "script": "test/e2e/test-shields-config.sh", + "line": 166, + "text": "Config file mode is 660 (mutable default)", + "polarity": "pass", + "normalized_id": "config.file.mode.is.660.mutable.default", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-shields-config.sh", + "line": 168, + "text": "Config file should start as mode 660: ${PERMS}", + "polarity": "fail", + "normalized_id": "config.file.should.start.as.mode.660.perms", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-shields-config.sh", + "line": 172, + "text": "Config file owned by sandbox:sandbox (mutable default)", + "polarity": "pass", + "normalized_id": "config.file.owned.by.sandbox.sandbox.mutable.default", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-shields-config.sh", + "line": 174, + "text": "Config file should be owned by sandbox:sandbox: ${PERMS}", + "polarity": "fail", + "normalized_id": "config.file.should.be.owned.by.sandbox.sandbox.perms", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-shields-config.sh", + "line": 182, + "text": "Config directory mode is 2770 (mutable default)", + "polarity": "pass", + "normalized_id": "config.directory.mode.is.2770.mutable.default", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-shields-config.sh", + "line": 184, + "text": "Config directory should be mode 2770: ${DIR_PERMS}", + "polarity": "fail", + "normalized_id": "config.directory.should.be.mode.2770.dir.perms", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-shields-config.sh", + "line": 188, + "text": "Config directory owned by sandbox:sandbox (mutable default)", + "polarity": "pass", + "normalized_id": "config.directory.owned.by.sandbox.sandbox.mutable.default", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-shields-config.sh", + "line": 190, + "text": "Config directory should be owned by sandbox:sandbox: ${DIR_PERMS}", + "polarity": "fail", + "normalized_id": "config.directory.should.be.owned.by.sandbox.sandbox.dir.perms", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-shields-config.sh", + "line": 196, + "text": "Fresh sandbox status reports default mutable state", + "polarity": "pass", + "normalized_id": "fresh.sandbox.status.reports.default.mutable.state", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-shields-config.sh", + "line": 198, + "text": "Fresh sandbox status should report NOT CONFIGURED mutable default: ${STATUS_DEFAULT}", + "polarity": "fail", + "normalized_id": "fresh.sandbox.status.should.report.not.configured.mutable.default.status.default", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-shields-config.sh", + "line": 207, + "text": "Unified .openclaw layout has no .openclaw-data mirror or symlink bridge", + "polarity": "pass", + "normalized_id": "unified.openclaw.layout.has.no.openclaw.data.mirror.or.symlink.bridge", + "mapping_status": "mapped" + }, + { + "script": "test/e2e/test-shields-config.sh", + "line": 209, + "text": "Legacy .openclaw-data layout should not exist: ${LAYOUT_CHECK}", + "polarity": "fail", + "normalized_id": "legacy.openclaw.data.layout.should.not.exist.layout.check", + "mapping_status": "retired" + }, + { + "script": "test/e2e/test-shields-config.sh", + "line": 221, + "text": "shields up succeeded", + "polarity": "pass", + "normalized_id": "shields.up.succeeded", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-shields-config.sh", + "line": 223, + "text": "shields up did not report success: ${SHIELDS_UP_OUTPUT}", + "polarity": "fail", + "normalized_id": "shields.up.did.not.report.success.shields.up.output", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-shields-config.sh", + "line": 232, + "text": "Config file has restrictive permissions after shields up (${PERMS_UP})", + "polarity": "pass", + "normalized_id": "config.file.has.restrictive.permissions.after.shields.up.perms.up", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-shields-config.sh", + "line": 234, + "text": "Config file should be locked after shields up: ${PERMS_UP}", + "polarity": "fail", + "normalized_id": "config.file.should.be.locked.after.shields.up.perms.up", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-shields-config.sh", + "line": 239, + "text": "Config file ownership changed to root:root", + "polarity": "pass", + "normalized_id": "config.file.ownership.changed.to.root.root", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-shields-config.sh", + "line": 241, + "text": "Config file ownership not changed to root:root: ${OWNER_UP}", + "polarity": "fail", + "normalized_id": "config.file.ownership.not.changed.to.root.root.owner.up", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-shields-config.sh", + "line": 249, + "text": "Config file is read-only for sandbox user (shields UP)", + "polarity": "pass", + "normalized_id": "config.file.is.read.only.for.sandbox.user.shields.up", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-shields-config.sh", + "line": 251, + "text": "Config file write rejected by OS (shields UP)", + "polarity": "pass", + "normalized_id": "config.file.write.rejected.by.os.shields.up", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-shields-config.sh", + "line": 253, + "text": "Config file should be immutable but sandbox could write: ${WRITE_RESULT}", + "polarity": "fail", + "normalized_id": "config.file.should.be.immutable.but.sandbox.could.write.write.result", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-shields-config.sh", + "line": 260, + "text": "Workspace state is read-only for sandbox user (shields UP)", + "polarity": "pass", + "normalized_id": "workspace.state.is.read.only.for.sandbox.user.shields.up", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-shields-config.sh", + "line": 262, + "text": "Workspace write rejected by OS (shields UP)", + "polarity": "pass", + "normalized_id": "workspace.write.rejected.by.os.shields.up", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-shields-config.sh", + "line": 264, + "text": "Workspace should be locked after shields up: ${WORKSPACE_WRITE_RESULT}", + "polarity": "fail", + "normalized_id": "workspace.should.be.locked.after.shields.up.workspace.write.result", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-shields-config.sh", + "line": 275, + "text": "config get returns JSON", + "polarity": "pass", + "normalized_id": "config.get.returns.json", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-shields-config.sh", + "line": 277, + "text": "config get did not return JSON: ${CONFIG_GET_OUTPUT}", + "polarity": "fail", + "normalized_id": "config.get.did.not.return.json.config.get.output", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-shields-config.sh", + "line": 282, + "text": "config get leaks credentials", + "polarity": "fail", + "normalized_id": "config.get.leaks.credentials", + "mapping_status": "mapped" + }, + { + "script": "test/e2e/test-shields-config.sh", + "line": 284, + "text": "config get output has no credential leaks", + "polarity": "pass", + "normalized_id": "config.get.output.has.no.credential.leaks", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-shields-config.sh", + "line": 289, + "text": "config get should strip gateway section", + "polarity": "fail", + "normalized_id": "config.get.should.strip.gateway.section", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-shields-config.sh", + "line": 291, + "text": "config get strips gateway section", + "polarity": "pass", + "normalized_id": "config.get.strips.gateway.section", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-shields-config.sh", + "line": 297, + "text": "config get --key dotpath works", + "polarity": "pass", + "normalized_id": "config.get.key.dotpath.works", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-shields-config.sh", + "line": 311, + "text": "shields status reports UP", + "polarity": "pass", + "normalized_id": "shields.status.reports.up", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-shields-config.sh", + "line": 313, + "text": "shields status should show UP: ${STATUS_OUTPUT}", + "polarity": "fail", + "normalized_id": "shields.status.should.show.up.status.output", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-shields-config.sh", + "line": 326, + "text": "shields down succeeded", + "polarity": "pass", + "normalized_id": "shields.down.succeeded", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-shields-config.sh", + "line": 328, + "text": "shields down did not report success: ${SHIELDS_DOWN_OUTPUT}", + "polarity": "fail", + "normalized_id": "shields.down.did.not.report.success.shields.down.output", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-shields-config.sh", + "line": 338, + "text": "Config file mode is 660 (restored to mutable default)", + "polarity": "pass", + "normalized_id": "config.file.mode.is.660.restored.to.mutable.default", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-shields-config.sh", + "line": 340, + "text": "Config file should be mode 660 after shields down: ${PERMS_DOWN}", + "polarity": "fail", + "normalized_id": "config.file.should.be.mode.660.after.shields.down.perms.down", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-shields-config.sh", + "line": 344, + "text": "Config file owned by sandbox:sandbox after shields down", + "polarity": "pass", + "normalized_id": "config.file.owned.by.sandbox.sandbox.after.shields.down", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-shields-config.sh", + "line": 346, + "text": "Config file should be owned by sandbox:sandbox: ${PERMS_DOWN}", + "polarity": "fail", + "normalized_id": "config.file.should.be.owned.by.sandbox.sandbox.perms.down", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-shields-config.sh", + "line": 354, + "text": "Config directory mode is 2770 (restored to mutable default)", + "polarity": "pass", + "normalized_id": "config.directory.mode.is.2770.restored.to.mutable.default", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-shields-config.sh", + "line": 356, + "text": "Config directory should be mode 2770 after shields down: ${DIR_PERMS_DOWN}", + "polarity": "fail", + "normalized_id": "config.directory.should.be.mode.2770.after.shields.down.dir.perms.down", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-shields-config.sh", + "line": 360, + "text": "Config directory owned by sandbox:sandbox after shields down", + "polarity": "pass", + "normalized_id": "config.directory.owned.by.sandbox.sandbox.after.shields.down", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-shields-config.sh", + "line": 362, + "text": "Config directory should be owned by sandbox:sandbox: ${DIR_PERMS_DOWN}", + "polarity": "fail", + "normalized_id": "config.directory.should.be.owned.by.sandbox.sandbox.dir.perms.down", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-shields-config.sh", + "line": 368, + "text": "Workspace state is writable again after shields down", + "polarity": "pass", + "normalized_id": "workspace.state.is.writable.again.after.shields.down", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-shields-config.sh", + "line": 370, + "text": "Workspace should be writable after shields down: ${WORKSPACE_DOWN_RESULT}", + "polarity": "fail", + "normalized_id": "workspace.should.be.writable.after.shields.down.workspace.down.result", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-shields-config.sh", + "line": 382, + "text": "shields status reports DOWN", + "polarity": "pass", + "normalized_id": "shields.status.reports.down", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-shields-config.sh", + "line": 384, + "text": "shields status should show DOWN: ${STATUS_DOWN}", + "polarity": "fail", + "normalized_id": "shields.status.should.show.down.status.down", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-shields-config.sh", + "line": 388, + "text": "shields status shows reason", + "polarity": "pass", + "normalized_id": "shields.status.shows.reason", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-shields-config.sh", + "line": 390, + "text": "shields status should show reason: ${STATUS_DOWN}", + "polarity": "fail", + "normalized_id": "shields.status.should.show.reason.status.down", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-shields-config.sh", + "line": 394, + "text": "shields status shows timeout remaining", + "polarity": "pass", + "normalized_id": "shields.status.shows.timeout.remaining", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-shields-config.sh", + "line": 402, + "text": "shields up restored for audit trail test", + "polarity": "pass", + "normalized_id": "shields.up.restored.for.audit.trail.test", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-shields-config.sh", + "line": 405, + "text": "Failed to restore shields up before audit phase: ${RESTORE_UP_OUTPUT}", + "polarity": "fail", + "normalized_id": "failed.to.restore.shields.up.before.audit.phase.restore.up.output", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-shields-config.sh", + "line": 422, + "text": "Audit has ≥2 shields_up entries (got ${UP_COUNT})", + "polarity": "pass", + "normalized_id": "audit.has.2.shields.up.entries.got.up.count", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-shields-config.sh", + "line": 424, + "text": "Expected ≥2 shields_up audit entries, got ${UP_COUNT}", + "polarity": "fail", + "normalized_id": "expected.2.shields.up.audit.entries.got.up.count", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-shields-config.sh", + "line": 428, + "text": "Audit has ≥1 shields_down entries (got ${DOWN_COUNT})", + "polarity": "pass", + "normalized_id": "audit.has.1.shields.down.entries.got.down.count", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-shields-config.sh", + "line": 430, + "text": "Expected ≥1 shields_down audit entries, got ${DOWN_COUNT}", + "polarity": "fail", + "normalized_id": "expected.1.shields.down.audit.entries.got.down.count", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-shields-config.sh", + "line": 435, + "text": "Audit trail contains credentials", + "polarity": "fail", + "normalized_id": "audit.trail.contains.credentials", + "mapping_status": "mapped" + }, + { + "script": "test/e2e/test-shields-config.sh", + "line": 437, + "text": "Audit trail is credential-free", + "polarity": "pass", + "normalized_id": "audit.trail.is.credential.free", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-shields-config.sh", + "line": 449, + "text": "All audit entries are valid JSON", + "polarity": "pass", + "normalized_id": "all.audit.entries.are.valid.json", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-shields-config.sh", + "line": 451, + "text": "${INVALID_JSON} audit entries are invalid JSON", + "polarity": "fail", + "normalized_id": "invalid.json.audit.entries.are.invalid.json", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-shields-config.sh", + "line": 454, + "text": "Audit file not found: $AUDIT_FILE", + "polarity": "fail", + "normalized_id": "audit.file.not.found.audit.file", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-shields-config.sh", + "line": 469, + "text": "shields down with 10s timeout", + "polarity": "pass", + "normalized_id": "shields.down.with.10s.timeout", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-shields-config.sh", + "line": 471, + "text": "shields should be DOWN: ${STATUS_TIMER}", + "polarity": "fail", + "normalized_id": "shields.should.be.down.status.timer", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-shields-config.sh", + "line": 486, + "text": "Auto-restore timer re-locked config after timeout", + "polarity": "pass", + "normalized_id": "auto.restore.timer.re.locked.config.after.timeout", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-shields-config.sh", + "line": 490, + "text": "Auto-restore timer did not re-lock within 60s", + "polarity": "fail", + "normalized_id": "auto.restore.timer.did.not.re.lock.within.60s", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-shields-config.sh", + "line": 497, + "text": "Config locked after auto-restore (${PERMS_TIMER})", + "polarity": "pass", + "normalized_id": "config.locked.after.auto.restore.perms.timer", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-shields-config.sh", + "line": 499, + "text": "Config should be locked after auto-restore, got: ${PERMS_TIMER}", + "polarity": "fail", + "normalized_id": "config.should.be.locked.after.auto.restore.got.perms.timer", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-shields-config.sh", + "line": 511, + "text": "Double shields-up rejected", + "polarity": "pass", + "normalized_id": "double.shields.up.rejected", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-shields-config.sh", + "line": 513, + "text": "Double shields-up should be rejected: ${DOUBLE_UP}", + "polarity": "fail", + "normalized_id": "double.shields.up.should.be.rejected.double.up", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-shields-config.sh", + "line": 517, + "text": "Cleanup: shields down", + "polarity": "pass", + "normalized_id": "cleanup.shields.down", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-shields-config.sh", + "line": 527, + "text": "Double shields-down rejected", + "polarity": "pass", + "normalized_id": "double.shields.down.rejected", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-shields-config.sh", + "line": 529, + "text": "Double shields-down should be rejected: ${DOUBLE_DOWN}", + "polarity": "fail", + "normalized_id": "double.shields.down.should.be.rejected.double.down", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-shields-config.sh", + "line": 538, + "text": "Sandbox destroyed", + "polarity": "pass", + "normalized_id": "sandbox.destroyed", + "mapping_status": "deferred" + } + ] + }, + { + "script": "test/e2e/test-skill-agent-e2e.sh", + "assertions": [ + { + "script": "test/e2e/test-skill-agent-e2e.sh", + "line": 92, + "text": "Docker is not running", + "polarity": "fail", + "normalized_id": "docker.is.not.running", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-skill-agent-e2e.sh", + "line": 95, + "text": "Docker is running", + "polarity": "pass", + "normalized_id": "docker.is.running", + "mapping_status": "mapped" + }, + { + "script": "test/e2e/test-skill-agent-e2e.sh", + "line": 98, + "text": "NVIDIA_API_KEY not set or invalid", + "polarity": "fail", + "normalized_id": "nvidia.api.key.not.set.or.invalid", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-skill-agent-e2e.sh", + "line": 101, + "text": "NVIDIA_API_KEY is set", + "polarity": "pass", + "normalized_id": "nvidia.api.key.is.set", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-skill-agent-e2e.sh", + "line": 104, + "text": "Could not cd to repo root", + "polarity": "fail", + "normalized_id": "could.not.cd.to.repo.root", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-skill-agent-e2e.sh", + "line": 133, + "text": "install.sh failed (exit $install_exit)", + "polarity": "fail", + "normalized_id": "install.sh.failed.exit.install.exit", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-skill-agent-e2e.sh", + "line": 137, + "text": "NemoClaw installed", + "polarity": "pass", + "normalized_id": "nemoclaw.installed", + "mapping_status": "mapped" + }, + { + "script": "test/e2e/test-skill-agent-e2e.sh", + "line": 140, + "text": "nemoclaw not on PATH", + "polarity": "fail", + "normalized_id": "nemoclaw.not.on.path", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-skill-agent-e2e.sh", + "line": 144, + "text": "openshell not on PATH", + "polarity": "fail", + "normalized_id": "openshell.not.on.path", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-skill-agent-e2e.sh", + "line": 147, + "text": "CLIs on PATH", + "polarity": "pass", + "normalized_id": "clis.on.path", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-skill-agent-e2e.sh", + "line": 159, + "text": "Failed to inject ${SKILL_ID}", + "polarity": "fail", + "normalized_id": "failed.to.inject.skill.id", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-skill-agent-e2e.sh", + "line": 162, + "text": "${SKILL_ID} injected and queryable", + "polarity": "pass", + "normalized_id": "skill.id.injected.and.queryable", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-skill-agent-e2e.sh", + "line": 190, + "text": "Agent returned ${VERIFY_PHRASE} (attempt ${attempt}/${MAX_ATTEMPTS})", + "polarity": "pass", + "normalized_id": "agent.returned.verify.phrase.attempt.attempt.max.attempts", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-skill-agent-e2e.sh", + "line": 206, + "text": "Agent returned ${VERIFY_PHRASE} via fuzzy match (attempt ${attempt}/${MAX_ATTEMPTS})", + "polarity": "pass", + "normalized_id": "agent.returned.verify.phrase.via.fuzzy.match.attempt.attempt.max.attempts", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-skill-agent-e2e.sh", + "line": 224, + "text": "$last_fail", + "polarity": "fail", + "normalized_id": "last.fail", + "mapping_status": "deferred" + } + ] + }, + { + "script": "test/e2e/test-snapshot-commands.sh", + "assertions": [ + { + "script": "test/e2e/test-snapshot-commands.sh", + "line": 83, + "text": "NVIDIA_API_KEY is required", + "polarity": "fail", + "normalized_id": "nvidia.api.key.is.required", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-snapshot-commands.sh", + "line": 84, + "text": "NEMOCLAW_NON_INTERACTIVE=1 is required", + "polarity": "fail", + "normalized_id": "nemoclaw.non.interactive.1.is.required", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-snapshot-commands.sh", + "line": 118, + "text": "nemoclaw not found on PATH after install", + "polarity": "fail", + "normalized_id": "nemoclaw.not.found.on.path.after.install", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-snapshot-commands.sh", + "line": 119, + "text": "openshell not found on PATH after install", + "polarity": "fail", + "normalized_id": "openshell.not.found.on.path.after.install", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-snapshot-commands.sh", + "line": 120, + "text": "NemoClaw installed", + "polarity": "pass", + "normalized_id": "nemoclaw.installed", + "mapping_status": "mapped" + }, + { + "script": "test/e2e/test-snapshot-commands.sh", + "line": 127, + "text": "Failed to write marker file", + "polarity": "fail", + "normalized_id": "failed.to.write.marker.file", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-snapshot-commands.sh", + "line": 130, + "text": "Marker verification failed: got '${VERIFY}'", + "polarity": "fail", + "normalized_id": "marker.verification.failed.got.verify", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-snapshot-commands.sh", + "line": 132, + "text": "Marker file written", + "polarity": "pass", + "normalized_id": "marker.file.written", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-snapshot-commands.sh", + "line": 149, + "text": "snapshot create exited with code $_CAPTURE_RC: ${SNAPSHOT_OUTPUT}", + "polarity": "fail", + "normalized_id": "snapshot.create.exited.with.code.capture.rc.snapshot.output", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-snapshot-commands.sh", + "line": 156, + "text": "snapshot create succeeded", + "polarity": "pass", + "normalized_id": "snapshot.create.succeeded", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-snapshot-commands.sh", + "line": 158, + "text": "snapshot create did not report success: ${SNAPSHOT_OUTPUT}", + "polarity": "fail", + "normalized_id": "snapshot.create.did.not.report.success.snapshot.output", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-snapshot-commands.sh", + "line": 172, + "text": "snapshot list exited with code $_CAPTURE_RC: ${LIST_OUTPUT}", + "polarity": "fail", + "normalized_id": "snapshot.list.exited.with.code.capture.rc.list.output", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-snapshot-commands.sh", + "line": 176, + "text": "snapshot list shows snapshots", + "polarity": "pass", + "normalized_id": "snapshot.list.shows.snapshots", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-snapshot-commands.sh", + "line": 178, + "text": "snapshot list shows no snapshots: ${LIST_OUTPUT}", + "polarity": "fail", + "normalized_id": "snapshot.list.shows.no.snapshots.list.output", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-snapshot-commands.sh", + "line": 183, + "text": "Failed to parse a snapshot timestamp from list output: ${LIST_OUTPUT}", + "polarity": "fail", + "normalized_id": "failed.to.parse.a.snapshot.timestamp.from.list.output.list.output", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-snapshot-commands.sh", + "line": 191, + "text": "Failed to modify sandbox state", + "polarity": "fail", + "normalized_id": "failed.to.modify.sandbox.state", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-snapshot-commands.sh", + "line": 195, + "text": "First marker should be deleted but got: ${GONE}", + "polarity": "fail", + "normalized_id": "first.marker.should.be.deleted.but.got.gone", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-snapshot-commands.sh", + "line": 199, + "text": "Second snapshot create failed (code $_CAPTURE_RC): ${_SECOND_SNAP}", + "polarity": "fail", + "normalized_id": "second.snapshot.create.failed.code.capture.rc.second.snap", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-snapshot-commands.sh", + "line": 201, + "text": "State modified, second snapshot created", + "polarity": "pass", + "normalized_id": "state.modified.second.snapshot.created", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-snapshot-commands.sh", + "line": 206, + "text": "Failed to perturb sandbox before latest restore", + "polarity": "fail", + "normalized_id": "failed.to.perturb.sandbox.before.latest.restore", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-snapshot-commands.sh", + "line": 215, + "text": "snapshot restore exited with code $_CAPTURE_RC: ${RESTORE_OUTPUT}", + "polarity": "fail", + "normalized_id": "snapshot.restore.exited.with.code.capture.rc.restore.output", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-snapshot-commands.sh", + "line": 219, + "text": "snapshot restore did not report success: ${RESTORE_OUTPUT}", + "polarity": "fail", + "normalized_id": "snapshot.restore.did.not.report.success.restore.output", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-snapshot-commands.sh", + "line": 223, + "text": "Latest restore did not recover the second marker: ${SECOND_CHECK}", + "polarity": "fail", + "normalized_id": "latest.restore.did.not.recover.the.second.marker.second.check", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-snapshot-commands.sh", + "line": 224, + "text": "Latest snapshot restored expected state", + "polarity": "pass", + "normalized_id": "latest.snapshot.restored.expected.state", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-snapshot-commands.sh", + "line": 233, + "text": "targeted snapshot restore exited with code $_CAPTURE_RC: ${TARGETED_OUTPUT}", + "polarity": "fail", + "normalized_id": "targeted.snapshot.restore.exited.with.code.capture.rc.targeted.output", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-snapshot-commands.sh", + "line": 237, + "text": "targeted snapshot restore did not report success: ${TARGETED_OUTPUT}", + "polarity": "fail", + "normalized_id": "targeted.snapshot.restore.did.not.report.success.targeted.output", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-snapshot-commands.sh", + "line": 241, + "text": "First snapshot did not restore the original marker: ${FIRST_CHECK}", + "polarity": "fail", + "normalized_id": "first.snapshot.did.not.restore.the.original.marker.first.check", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-snapshot-commands.sh", + "line": 243, + "text": "First snapshot should not contain the second marker", + "polarity": "fail", + "normalized_id": "first.snapshot.should.not.contain.the.second.marker", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-snapshot-commands.sh", + "line": 244, + "text": "First snapshot restored expected state", + "polarity": "pass", + "normalized_id": "first.snapshot.restored.expected.state", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-snapshot-commands.sh", + "line": 253, + "text": "No credentials in snapshot directories", + "polarity": "pass", + "normalized_id": "no.credentials.in.snapshot.directories", + "mapping_status": "mapped" + }, + { + "script": "test/e2e/test-snapshot-commands.sh", + "line": 255, + "text": "Credentials found: $CRED_LEAKS", + "polarity": "fail", + "normalized_id": "credentials.found.cred.leaks", + "mapping_status": "mapped" + }, + { + "script": "test/e2e/test-snapshot-commands.sh", + "line": 258, + "text": "Backup directory missing: $BACKUP_DIR", + "polarity": "fail", + "normalized_id": "backup.directory.missing.backup.dir", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-snapshot-commands.sh", + "line": 266, + "text": "snapshot help exited with code $_CAPTURE_RC: ${HELP_OUTPUT}", + "polarity": "fail", + "normalized_id": "snapshot.help.exited.with.code.capture.rc.help.output", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-snapshot-commands.sh", + "line": 271, + "text": "snapshot help shows create/list/restore", + "polarity": "pass", + "normalized_id": "snapshot.help.shows.create.list.restore", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-snapshot-commands.sh", + "line": 273, + "text": "snapshot help incomplete: ${HELP_OUTPUT}", + "polarity": "fail", + "normalized_id": "snapshot.help.incomplete.help.output", + "mapping_status": "deferred" + } + ] + }, + { + "script": "test/e2e/test-spark-install.sh", + "assertions": [ + { + "script": "test/e2e/test-spark-install.sh", + "line": 59, + "text": "Running on Linux", + "polarity": "pass", + "normalized_id": "running.on.linux", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-spark-install.sh", + "line": 61, + "text": "This script is for DGX Spark (Linux). On other OS use Vitest: NEMOCLAW_E2E_SPARK_INSTALL=1 --project spark-install-cli (skipped there on non-Linux).", + "polarity": "fail", + "normalized_id": "this.script.is.for.dgx.spark.linux.on.other.os.use.vitest.nemoclaw.e2e.spark.install.1.project.spark.install.cli.skipped.there.on.non.linux", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-spark-install.sh", + "line": 67, + "text": "Docker is running", + "polarity": "pass", + "normalized_id": "docker.is.running", + "mapping_status": "mapped" + }, + { + "script": "test/e2e/test-spark-install.sh", + "line": 69, + "text": "Docker is not running", + "polarity": "fail", + "normalized_id": "docker.is.not.running", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-spark-install.sh", + "line": 74, + "text": "NEMOCLAW_NON_INTERACTIVE=1", + "polarity": "pass", + "normalized_id": "nemoclaw.non.interactive.1", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-spark-install.sh", + "line": 76, + "text": "NEMOCLAW_NON_INTERACTIVE=1 is required", + "polarity": "fail", + "normalized_id": "nemoclaw.non.interactive.1.is.required", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-spark-install.sh", + "line": 81, + "text": "NEMOCLAW_ACCEPT_THIRD_PARTY_SOFTWARE=1", + "polarity": "pass", + "normalized_id": "nemoclaw.accept.third.party.software.1", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-spark-install.sh", + "line": 83, + "text": "NEMOCLAW_ACCEPT_THIRD_PARTY_SOFTWARE=1 is required for non-interactive install", + "polarity": "fail", + "normalized_id": "nemoclaw.accept.third.party.software.1.is.required.for.non.interactive.install", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-spark-install.sh", + "line": 89, + "text": "cd to repo: $REPO", + "polarity": "fail", + "normalized_id": "cd.to.repo.repo", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-spark-install.sh", + "line": 93, + "text": "Using generic installer flow without Spark-specific setup", + "polarity": "pass", + "normalized_id": "using.generic.installer.flow.without.spark.specific.setup", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-spark-install.sh", + "line": 114, + "text": "install failed (exit $install_exit); last 80 lines of log:", + "polarity": "fail", + "normalized_id": "install.failed.exit.install.exit.last.80.lines.of.log", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-spark-install.sh", + "line": 118, + "text": "install completed (exit 0)", + "polarity": "pass", + "normalized_id": "install.completed.exit.0", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-spark-install.sh", + "line": 135, + "text": "nemoclaw on PATH ($(command -v nemoclaw))", + "polarity": "pass", + "normalized_id": "nemoclaw.on.path.command.v.nemoclaw", + "mapping_status": "mapped" + }, + { + "script": "test/e2e/test-spark-install.sh", + "line": 137, + "text": "nemoclaw not on PATH", + "polarity": "fail", + "normalized_id": "nemoclaw.not.on.path", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-spark-install.sh", + "line": 142, + "text": "openshell on PATH", + "polarity": "pass", + "normalized_id": "openshell.on.path", + "mapping_status": "mapped" + }, + { + "script": "test/e2e/test-spark-install.sh", + "line": 144, + "text": "openshell not on PATH", + "polarity": "fail", + "normalized_id": "openshell.not.on.path", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-spark-install.sh", + "line": 149, + "text": "nemoclaw --help exits 0", + "polarity": "pass", + "normalized_id": "nemoclaw.help.exits.0", + "mapping_status": "mapped" + }, + { + "script": "test/e2e/test-spark-install.sh", + "line": 151, + "text": "nemoclaw --help failed", + "polarity": "fail", + "normalized_id": "nemoclaw.help.failed", + "mapping_status": "deferred" + } + ] + }, + { + "script": "test/e2e/test-telegram-injection.sh", + "assertions": [ + { + "script": "test/e2e/test-telegram-injection.sh", + "line": 149, + "text": "NVIDIA_API_KEY not set", + "polarity": "fail", + "normalized_id": "nvidia.api.key.not.set", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-telegram-injection.sh", + "line": 152, + "text": "NVIDIA_API_KEY is set", + "polarity": "pass", + "normalized_id": "nvidia.api.key.is.set", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-telegram-injection.sh", + "line": 155, + "text": "openshell not found on PATH", + "polarity": "fail", + "normalized_id": "openshell.not.found.on.path", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-telegram-injection.sh", + "line": 158, + "text": "openshell found", + "polarity": "pass", + "normalized_id": "openshell.found", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-telegram-injection.sh", + "line": 161, + "text": "nemoclaw not found on PATH", + "polarity": "fail", + "normalized_id": "nemoclaw.not.found.on.path", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-telegram-injection.sh", + "line": 164, + "text": "nemoclaw found", + "polarity": "pass", + "normalized_id": "nemoclaw.found", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-telegram-injection.sh", + "line": 168, + "text": "Sandbox '${SANDBOX_NAME}' is running", + "polarity": "pass", + "normalized_id": "sandbox.sandbox.name.is.running", + "mapping_status": "mapped" + }, + { + "script": "test/e2e/test-telegram-injection.sh", + "line": 170, + "text": "Sandbox '${SANDBOX_NAME}' not running — run test-full-e2e.sh first", + "polarity": "fail", + "normalized_id": "sandbox.sandbox.name.not.running.run.test.full.e2e.sh.first", + "mapping_status": "mapped" + }, + { + "script": "test/e2e/test-telegram-injection.sh", + "line": 211, + "text": "T1: \\$(command) substitution was NOT executed", + "polarity": "pass", + "normalized_id": "t1.command.substitution.was.not.executed", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-telegram-injection.sh", + "line": 213, + "text": "T1: \\$(command) substitution was EXECUTED — injection successful!", + "polarity": "fail", + "normalized_id": "t1.command.substitution.was.executed.injection.successful", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-telegram-injection.sh", + "line": 235, + "text": "T2: Backtick command substitution was NOT executed", + "polarity": "pass", + "normalized_id": "t2.backtick.command.substitution.was.not.executed", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-telegram-injection.sh", + "line": 237, + "text": "T2: Backtick command substitution was EXECUTED — injection successful!", + "polarity": "fail", + "normalized_id": "t2.backtick.command.substitution.was.executed.injection.successful", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-telegram-injection.sh", + "line": 264, + "text": "T3: Single-quote breakout was NOT exploitable", + "polarity": "pass", + "normalized_id": "t3.single.quote.breakout.was.not.exploitable", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-telegram-injection.sh", + "line": 266, + "text": "T3: Single-quote breakout was EXECUTED — injection successful!", + "polarity": "fail", + "normalized_id": "t3.single.quote.breakout.was.executed.injection.successful", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-telegram-injection.sh", + "line": 292, + "text": "T4: \\${NVIDIA_API_KEY} expanded to actual key value — secret leaked!", + "polarity": "fail", + "normalized_id": "t4.nvidia.api.key.expanded.to.actual.key.value.secret.leaked", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-telegram-injection.sh", + "line": 294, + "text": "T4: \\${NVIDIA_API_KEY} treated as literal string (not expanded)", + "polarity": "pass", + "normalized_id": "t4.nvidia.api.key.treated.as.literal.string.not.expanded", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-telegram-injection.sh", + "line": 297, + "text": "T4: \\${NVIDIA_API_KEY} did not expand to key value (result: ${t4_result:0:100})", + "polarity": "pass", + "normalized_id": "t4.nvidia.api.key.did.not.expand.to.key.value.result.t4.result.0.100", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-telegram-injection.sh", + "line": 334, + "text": "T5: NVIDIA_API_KEY found in HOST process table", + "polarity": "fail", + "normalized_id": "t5.nvidia.api.key.found.in.host.process.table", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-telegram-injection.sh", + "line": 336, + "text": "T5: NVIDIA_API_KEY found in SANDBOX process table", + "polarity": "fail", + "normalized_id": "t5.nvidia.api.key.found.in.sandbox.process.table", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-telegram-injection.sh", + "line": 338, + "text": "T5: API key not visible in process tables (host or sandbox)", + "polarity": "pass", + "normalized_id": "t5.api.key.not.visible.in.process.tables.host.or.sandbox", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-telegram-injection.sh", + "line": 363, + "text": "T6: SANDBOX_NAME 'foo;rm -rf /' rejected by validateName()", + "polarity": "pass", + "normalized_id": "t6.sandbox.name.foo.rm.rf.rejected.by.validatename", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-telegram-injection.sh", + "line": 365, + "text": "T6: SANDBOX_NAME 'foo;rm -rf /' was ACCEPTED — validation bypass!", + "polarity": "fail", + "normalized_id": "t6.sandbox.name.foo.rm.rf.was.accepted.validation.bypass", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-telegram-injection.sh", + "line": 382, + "text": "T7: SANDBOX_NAME '--help' rejected (option injection prevented)", + "polarity": "pass", + "normalized_id": "t7.sandbox.name.help.rejected.option.injection.prevented", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-telegram-injection.sh", + "line": 384, + "text": "T7: SANDBOX_NAME '--help' was ACCEPTED — option injection possible!", + "polarity": "fail", + "normalized_id": "t7.sandbox.name.help.was.accepted.option.injection.possible", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-telegram-injection.sh", + "line": 401, + "text": "T6/T7 extra: SANDBOX_NAME '${invalid_name}' correctly rejected", + "polarity": "pass", + "normalized_id": "t6.t7.extra.sandbox.name.invalid.name.correctly.rejected", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-telegram-injection.sh", + "line": 403, + "text": "T6/T7 extra: SANDBOX_NAME '${invalid_name}' was ACCEPTED", + "polarity": "fail", + "normalized_id": "t6.t7.extra.sandbox.name.invalid.name.was.accepted", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-telegram-injection.sh", + "line": 429, + "text": "T8: Normal message passed through correctly", + "polarity": "pass", + "normalized_id": "t8.normal.message.passed.through.correctly", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-telegram-injection.sh", + "line": 431, + "text": "T8: Normal message was not echoed back correctly (got: ${t8_result:0:200})", + "polarity": "fail", + "normalized_id": "t8.normal.message.was.not.echoed.back.correctly.got.t8.result.0.200", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-telegram-injection.sh", + "line": 453, + "text": "T8b: Message with special characters processed without error", + "polarity": "pass", + "normalized_id": "t8b.message.with.special.characters.processed.without.error", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-telegram-injection.sh", + "line": 455, + "text": "T8b: Message with special characters caused empty/error response", + "polarity": "fail", + "normalized_id": "t8b.message.with.special.characters.caused.empty.error.response", + "mapping_status": "deferred" + } + ] + }, + { + "script": "test/e2e/test-token-rotation.sh", + "assertions": [ + { + "script": "test/e2e/test-token-rotation.sh", + "line": 196, + "text": "install.sh completed (exit 0)", + "polarity": "pass", + "normalized_id": "install.sh.completed.exit.0", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-token-rotation.sh", + "line": 203, + "text": "install.sh failed (exit $install_exit)", + "polarity": "fail", + "normalized_id": "install.sh.failed.exit.install.exit", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-token-rotation.sh", + "line": 212, + "text": "openshell not found on PATH after install", + "polarity": "fail", + "normalized_id": "openshell.not.found.on.path.after.install", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-token-rotation.sh", + "line": 215, + "text": "openshell installed ($(openshell --version 2>&1 || echo unknown))", + "polarity": "pass", + "normalized_id": "openshell.installed.openshell.version.2.1.echo.unknown", + "mapping_status": "mapped" + }, + { + "script": "test/e2e/test-token-rotation.sh", + "line": 218, + "text": "nemoclaw not found on PATH after install", + "polarity": "fail", + "normalized_id": "nemoclaw.not.found.on.path.after.install", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-token-rotation.sh", + "line": 221, + "text": "nemoclaw installed at $(command -v nemoclaw)", + "polarity": "pass", + "normalized_id": "nemoclaw.installed.at.command.v.nemoclaw", + "mapping_status": "mapped" + }, + { + "script": "test/e2e/test-token-rotation.sh", + "line": 239, + "text": "Sandbox $SANDBOX_NAME created and running", + "polarity": "pass", + "normalized_id": "sandbox.sandbox.name.created.and.running", + "mapping_status": "mapped" + }, + { + "script": "test/e2e/test-token-rotation.sh", + "line": 241, + "text": "Sandbox $SANDBOX_NAME not running after first onboard", + "polarity": "fail", + "normalized_id": "sandbox.sandbox.name.not.running.after.first.onboard", + "mapping_status": "mapped" + }, + { + "script": "test/e2e/test-token-rotation.sh", + "line": 245, + "text": "Provider ${SANDBOX_NAME}-telegram-bridge exists", + "polarity": "pass", + "normalized_id": "provider.sandbox.name.telegram.bridge.exists", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-token-rotation.sh", + "line": 247, + "text": "Provider ${SANDBOX_NAME}-telegram-bridge not found", + "polarity": "fail", + "normalized_id": "provider.sandbox.name.telegram.bridge.not.found", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-token-rotation.sh", + "line": 251, + "text": "Provider ${SANDBOX_NAME}-discord-bridge exists", + "polarity": "pass", + "normalized_id": "provider.sandbox.name.discord.bridge.exists", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-token-rotation.sh", + "line": 253, + "text": "Provider ${SANDBOX_NAME}-discord-bridge not found", + "polarity": "fail", + "normalized_id": "provider.sandbox.name.discord.bridge.not.found", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-token-rotation.sh", + "line": 257, + "text": "Provider ${SANDBOX_NAME}-slack-bridge exists", + "polarity": "pass", + "normalized_id": "provider.sandbox.name.slack.bridge.exists", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-token-rotation.sh", + "line": 259, + "text": "Provider ${SANDBOX_NAME}-slack-bridge not found", + "polarity": "fail", + "normalized_id": "provider.sandbox.name.slack.bridge.not.found", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-token-rotation.sh", + "line": 263, + "text": "Provider ${SANDBOX_NAME}-slack-app exists", + "polarity": "pass", + "normalized_id": "provider.sandbox.name.slack.app.exists", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-token-rotation.sh", + "line": 265, + "text": "Provider ${SANDBOX_NAME}-slack-app not found", + "polarity": "fail", + "normalized_id": "provider.sandbox.name.slack.app.not.found", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-token-rotation.sh", + "line": 274, + "text": "Telegram credential hash stored for $SANDBOX_NAME", + "polarity": "pass", + "normalized_id": "telegram.credential.hash.stored.for.sandbox.name", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-token-rotation.sh", + "line": 276, + "text": "Telegram credential hash not found for $SANDBOX_NAME in registry", + "polarity": "fail", + "normalized_id": "telegram.credential.hash.not.found.for.sandbox.name.in.registry", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-token-rotation.sh", + "line": 284, + "text": "Discord credential hash stored for $SANDBOX_NAME", + "polarity": "pass", + "normalized_id": "discord.credential.hash.stored.for.sandbox.name", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-token-rotation.sh", + "line": 286, + "text": "Discord credential hash not found for $SANDBOX_NAME in registry", + "polarity": "fail", + "normalized_id": "discord.credential.hash.not.found.for.sandbox.name.in.registry", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-token-rotation.sh", + "line": 294, + "text": "Slack bot credential hash stored for $SANDBOX_NAME", + "polarity": "pass", + "normalized_id": "slack.bot.credential.hash.stored.for.sandbox.name", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-token-rotation.sh", + "line": 296, + "text": "Slack bot credential hash not found for $SANDBOX_NAME in registry", + "polarity": "fail", + "normalized_id": "slack.bot.credential.hash.not.found.for.sandbox.name.in.registry", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-token-rotation.sh", + "line": 304, + "text": "Slack app credential hash stored for $SANDBOX_NAME", + "polarity": "pass", + "normalized_id": "slack.app.credential.hash.stored.for.sandbox.name", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-token-rotation.sh", + "line": 306, + "text": "Slack app credential hash not found for $SANDBOX_NAME in registry", + "polarity": "fail", + "normalized_id": "slack.app.credential.hash.not.found.for.sandbox.name.in.registry", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-token-rotation.sh", + "line": 323, + "text": "Phase 2 onboard failed (exit $onboard_exit)", + "polarity": "fail", + "normalized_id": "phase.2.onboard.failed.exit.onboard.exit", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-token-rotation.sh", + "line": 328, + "text": "Credential rotation detected", + "polarity": "pass", + "normalized_id": "credential.rotation.detected", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-token-rotation.sh", + "line": 330, + "text": "Credential rotation not detected in onboard output", + "polarity": "fail", + "normalized_id": "credential.rotation.not.detected.in.onboard.output", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-token-rotation.sh", + "line": 339, + "text": "Rotation message identifies telegram-bridge", + "polarity": "pass", + "normalized_id": "rotation.message.identifies.telegram.bridge", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-token-rotation.sh", + "line": 341, + "text": "Rotation message did not identify telegram-bridge", + "polarity": "fail", + "normalized_id": "rotation.message.did.not.identify.telegram.bridge", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-token-rotation.sh", + "line": 347, + "text": "Rotation message unexpectedly named discord-bridge (Discord token did not change)", + "polarity": "fail", + "normalized_id": "rotation.message.unexpectedly.named.discord.bridge.discord.token.did.not.change", + "mapping_status": "retired" + }, + { + "script": "test/e2e/test-token-rotation.sh", + "line": 351, + "text": "Rotation message did not name discord-bridge (Discord unchanged)", + "polarity": "pass", + "normalized_id": "rotation.message.did.not.name.discord.bridge.discord.unchanged", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-token-rotation.sh", + "line": 355, + "text": "Rotation message unexpectedly named slack-bridge/slack-app (Slack tokens did not change)", + "polarity": "fail", + "normalized_id": "rotation.message.unexpectedly.named.slack.bridge.slack.app.slack.tokens.did.not.change", + "mapping_status": "retired" + }, + { + "script": "test/e2e/test-token-rotation.sh", + "line": 359, + "text": "Rotation message did not name slack-bridge or slack-app (Slack unchanged)", + "polarity": "pass", + "normalized_id": "rotation.message.did.not.name.slack.bridge.or.slack.app.slack.unchanged", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-token-rotation.sh", + "line": 363, + "text": "Sandbox rebuild triggered by rotation", + "polarity": "pass", + "normalized_id": "sandbox.rebuild.triggered.by.rotation", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-token-rotation.sh", + "line": 365, + "text": "Sandbox rebuild not triggered", + "polarity": "fail", + "normalized_id": "sandbox.rebuild.not.triggered", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-token-rotation.sh", + "line": 371, + "text": "Sandbox running after Telegram rotation", + "polarity": "pass", + "normalized_id": "sandbox.running.after.telegram.rotation", + "mapping_status": "mapped" + }, + { + "script": "test/e2e/test-token-rotation.sh", + "line": 373, + "text": "Sandbox not running after Telegram rotation", + "polarity": "fail", + "normalized_id": "sandbox.not.running.after.telegram.rotation", + "mapping_status": "mapped" + }, + { + "script": "test/e2e/test-token-rotation.sh", + "line": 384, + "text": "Phase 3 onboard failed (exit $onboard_exit)", + "polarity": "fail", + "normalized_id": "phase.3.onboard.failed.exit.onboard.exit", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-token-rotation.sh", + "line": 389, + "text": "Sandbox reused when tokens unchanged", + "polarity": "pass", + "normalized_id": "sandbox.reused.when.tokens.unchanged", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-token-rotation.sh", + "line": 391, + "text": "Sandbox was not reused (unexpected rebuild)", + "polarity": "fail", + "normalized_id": "sandbox.was.not.reused.unexpected.rebuild", + "mapping_status": "retired" + }, + { + "script": "test/e2e/test-token-rotation.sh", + "line": 409, + "text": "Phase 4 onboard failed (exit $onboard_exit)", + "polarity": "fail", + "normalized_id": "phase.4.onboard.failed.exit.onboard.exit", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-token-rotation.sh", + "line": 414, + "text": "Credential rotation detected", + "polarity": "pass", + "normalized_id": "credential.rotation.detected", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-token-rotation.sh", + "line": 416, + "text": "Credential rotation not detected in onboard output", + "polarity": "fail", + "normalized_id": "credential.rotation.not.detected.in.onboard.output", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-token-rotation.sh", + "line": 423, + "text": "Rotation message identifies discord-bridge", + "polarity": "pass", + "normalized_id": "rotation.message.identifies.discord.bridge", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-token-rotation.sh", + "line": 425, + "text": "Rotation message did not identify discord-bridge", + "polarity": "fail", + "normalized_id": "rotation.message.did.not.identify.discord.bridge", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-token-rotation.sh", + "line": 431, + "text": "Rotation message unexpectedly named telegram-bridge (Telegram token did not change)", + "polarity": "fail", + "normalized_id": "rotation.message.unexpectedly.named.telegram.bridge.telegram.token.did.not.change", + "mapping_status": "retired" + }, + { + "script": "test/e2e/test-token-rotation.sh", + "line": 435, + "text": "Rotation message did not name telegram-bridge (Telegram unchanged)", + "polarity": "pass", + "normalized_id": "rotation.message.did.not.name.telegram.bridge.telegram.unchanged", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-token-rotation.sh", + "line": 439, + "text": "Rotation message unexpectedly named slack-bridge/slack-app (Slack tokens did not change)", + "polarity": "fail", + "normalized_id": "rotation.message.unexpectedly.named.slack.bridge.slack.app.slack.tokens.did.not.change", + "mapping_status": "retired" + }, + { + "script": "test/e2e/test-token-rotation.sh", + "line": 443, + "text": "Rotation message did not name slack-bridge or slack-app (Slack unchanged)", + "polarity": "pass", + "normalized_id": "rotation.message.did.not.name.slack.bridge.or.slack.app.slack.unchanged", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-token-rotation.sh", + "line": 447, + "text": "Sandbox rebuild triggered by rotation", + "polarity": "pass", + "normalized_id": "sandbox.rebuild.triggered.by.rotation", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-token-rotation.sh", + "line": 449, + "text": "Sandbox rebuild not triggered", + "polarity": "fail", + "normalized_id": "sandbox.rebuild.not.triggered", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-token-rotation.sh", + "line": 455, + "text": "Sandbox running after Discord rotation", + "polarity": "pass", + "normalized_id": "sandbox.running.after.discord.rotation", + "mapping_status": "mapped" + }, + { + "script": "test/e2e/test-token-rotation.sh", + "line": 457, + "text": "Sandbox not running after Discord rotation", + "polarity": "fail", + "normalized_id": "sandbox.not.running.after.discord.rotation", + "mapping_status": "mapped" + }, + { + "script": "test/e2e/test-token-rotation.sh", + "line": 468, + "text": "Phase 5 onboard failed (exit $onboard_exit)", + "polarity": "fail", + "normalized_id": "phase.5.onboard.failed.exit.onboard.exit", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-token-rotation.sh", + "line": 473, + "text": "Sandbox reused when tokens unchanged", + "polarity": "pass", + "normalized_id": "sandbox.reused.when.tokens.unchanged", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-token-rotation.sh", + "line": 475, + "text": "Sandbox was not reused (unexpected rebuild)", + "polarity": "fail", + "normalized_id": "sandbox.was.not.reused.unexpected.rebuild", + "mapping_status": "retired" + }, + { + "script": "test/e2e/test-token-rotation.sh", + "line": 493, + "text": "Phase 6 onboard failed (exit $onboard_exit)", + "polarity": "fail", + "normalized_id": "phase.6.onboard.failed.exit.onboard.exit", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-token-rotation.sh", + "line": 498, + "text": "Credential rotation detected", + "polarity": "pass", + "normalized_id": "credential.rotation.detected", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-token-rotation.sh", + "line": 500, + "text": "Credential rotation not detected in onboard output", + "polarity": "fail", + "normalized_id": "credential.rotation.not.detected.in.onboard.output", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-token-rotation.sh", + "line": 507, + "text": "Rotation message identifies slack-bridge", + "polarity": "pass", + "normalized_id": "rotation.message.identifies.slack.bridge", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-token-rotation.sh", + "line": 509, + "text": "Rotation message did not identify slack-bridge", + "polarity": "fail", + "normalized_id": "rotation.message.did.not.identify.slack.bridge", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-token-rotation.sh", + "line": 515, + "text": "Rotation message identifies slack-app", + "polarity": "pass", + "normalized_id": "rotation.message.identifies.slack.app", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-token-rotation.sh", + "line": 517, + "text": "Rotation message did not identify slack-app", + "polarity": "fail", + "normalized_id": "rotation.message.did.not.identify.slack.app", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-token-rotation.sh", + "line": 523, + "text": "Rotation message unexpectedly named telegram-bridge (Telegram token did not change)", + "polarity": "fail", + "normalized_id": "rotation.message.unexpectedly.named.telegram.bridge.telegram.token.did.not.change", + "mapping_status": "retired" + }, + { + "script": "test/e2e/test-token-rotation.sh", + "line": 527, + "text": "Rotation message did not name telegram-bridge (Telegram unchanged)", + "polarity": "pass", + "normalized_id": "rotation.message.did.not.name.telegram.bridge.telegram.unchanged", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-token-rotation.sh", + "line": 531, + "text": "Rotation message unexpectedly named discord-bridge (Discord token did not change)", + "polarity": "fail", + "normalized_id": "rotation.message.unexpectedly.named.discord.bridge.discord.token.did.not.change", + "mapping_status": "retired" + }, + { + "script": "test/e2e/test-token-rotation.sh", + "line": 535, + "text": "Rotation message did not name discord-bridge (Discord unchanged)", + "polarity": "pass", + "normalized_id": "rotation.message.did.not.name.discord.bridge.discord.unchanged", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-token-rotation.sh", + "line": 539, + "text": "Sandbox rebuild triggered by Slack rotation", + "polarity": "pass", + "normalized_id": "sandbox.rebuild.triggered.by.slack.rotation", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-token-rotation.sh", + "line": 541, + "text": "Sandbox rebuild not triggered", + "polarity": "fail", + "normalized_id": "sandbox.rebuild.not.triggered", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-token-rotation.sh", + "line": 547, + "text": "Sandbox running after Slack rotation", + "polarity": "pass", + "normalized_id": "sandbox.running.after.slack.rotation", + "mapping_status": "mapped" + }, + { + "script": "test/e2e/test-token-rotation.sh", + "line": 549, + "text": "Sandbox not running after Slack rotation", + "polarity": "fail", + "normalized_id": "sandbox.not.running.after.slack.rotation", + "mapping_status": "mapped" + }, + { + "script": "test/e2e/test-token-rotation.sh", + "line": 560, + "text": "Phase 7 onboard failed (exit $onboard_exit)", + "polarity": "fail", + "normalized_id": "phase.7.onboard.failed.exit.onboard.exit", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-token-rotation.sh", + "line": 565, + "text": "Sandbox reused when tokens unchanged", + "polarity": "pass", + "normalized_id": "sandbox.reused.when.tokens.unchanged", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-token-rotation.sh", + "line": 567, + "text": "Sandbox was not reused (unexpected rebuild)", + "polarity": "fail", + "normalized_id": "sandbox.was.not.reused.unexpected.rebuild", + "mapping_status": "retired" + } + ] + }, + { + "script": "test/e2e/test-upgrade-stale-sandbox.sh", + "assertions": [ + { + "script": "test/e2e/test-upgrade-stale-sandbox.sh", + "line": 54, + "text": "NVIDIA_API_KEY is required", + "polarity": "fail", + "normalized_id": "nvidia.api.key.is.required", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-upgrade-stale-sandbox.sh", + "line": 55, + "text": "NEMOCLAW_NON_INTERACTIVE=1 is required", + "polarity": "fail", + "normalized_id": "nemoclaw.non.interactive.1.is.required", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-upgrade-stale-sandbox.sh", + "line": 91, + "text": "nemoclaw not found on PATH after install", + "polarity": "fail", + "normalized_id": "nemoclaw.not.found.on.path.after.install", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-upgrade-stale-sandbox.sh", + "line": 92, + "text": "openshell not found on PATH after install", + "polarity": "fail", + "normalized_id": "openshell.not.found.on.path.after.install", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-upgrade-stale-sandbox.sh", + "line": 93, + "text": "NemoClaw installed", + "polarity": "pass", + "normalized_id": "nemoclaw.installed", + "mapping_status": "mapped" + }, + { + "script": "test/e2e/test-upgrade-stale-sandbox.sh", + "line": 119, + "text": "Failed to build old base image", + "polarity": "fail", + "normalized_id": "failed.to.build.old.base.image", + "mapping_status": "retired" + }, + { + "script": "test/e2e/test-upgrade-stale-sandbox.sh", + "line": 121, + "text": "Old base image built (OpenClaw ${OLD_OPENCLAW_VERSION})", + "polarity": "pass", + "normalized_id": "old.base.image.built.openclaw.old.openclaw.version", + "mapping_status": "retired" + }, + { + "script": "test/e2e/test-upgrade-stale-sandbox.sh", + "line": 146, + "text": "Sandbox did not become Ready", + "polarity": "fail", + "normalized_id": "sandbox.did.not.become.ready", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-upgrade-stale-sandbox.sh", + "line": 149, + "text": "Failed to read OpenClaw version from old sandbox", + "polarity": "fail", + "normalized_id": "failed.to.read.openclaw.version.from.old.sandbox", + "mapping_status": "retired" + }, + { + "script": "test/e2e/test-upgrade-stale-sandbox.sh", + "line": 152, + "text": "Old sandbox created (OpenClaw ${OLD_OPENCLAW_VERSION})", + "polarity": "pass", + "normalized_id": "old.sandbox.created.openclaw.old.openclaw.version", + "mapping_status": "mapped" + }, + { + "script": "test/e2e/test-upgrade-stale-sandbox.sh", + "line": 186, + "text": "Sandbox registered with agentVersion=${OLD_OPENCLAW_VERSION}", + "polarity": "pass", + "normalized_id": "sandbox.registered.with.agentversion.old.openclaw.version", + "mapping_status": "retired" + }, + { + "script": "test/e2e/test-upgrade-stale-sandbox.sh", + "line": 195, + "text": "Phase 5: upgrade-sandboxes --check detected stale sandbox", + "polarity": "pass", + "normalized_id": "phase.5.upgrade.sandboxes.check.detected.stale.sandbox", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-upgrade-stale-sandbox.sh", + "line": 197, + "text": "upgrade-sandboxes --check says all up to date — stale sandbox NOT detected (#1904)", + "polarity": "fail", + "normalized_id": "upgrade.sandboxes.check.says.all.up.to.date.stale.sandbox.not.detected.1904", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-upgrade-stale-sandbox.sh", + "line": 199, + "text": "upgrade-sandboxes --check produced unexpected output", + "polarity": "fail", + "normalized_id": "upgrade.sandboxes.check.produced.unexpected.output", + "mapping_status": "retired" + }, + { + "script": "test/e2e/test-upgrade-stale-sandbox.sh", + "line": 205, + "text": "Sandbox rebuild failed", + "polarity": "fail", + "normalized_id": "sandbox.rebuild.failed", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-upgrade-stale-sandbox.sh", + "line": 215, + "text": "Failed to read OpenClaw version after rebuild", + "polarity": "fail", + "normalized_id": "failed.to.read.openclaw.version.after.rebuild", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-upgrade-stale-sandbox.sh", + "line": 219, + "text": "Sandbox still running old OpenClaw ${OLD_OPENCLAW_VERSION} after rebuild — #1904 NOT fixed", + "polarity": "fail", + "normalized_id": "sandbox.still.running.old.openclaw.old.openclaw.version.after.rebuild.1904.not.fixed", + "mapping_status": "mapped" + }, + { + "script": "test/e2e/test-upgrade-stale-sandbox.sh", + "line": 222, + "text": "Phase 6: Sandbox upgraded from OpenClaw ${OLD_OPENCLAW_VERSION} to ${NEW_OPENCLAW_VERSION}", + "polarity": "pass", + "normalized_id": "phase.6.sandbox.upgraded.from.openclaw.old.openclaw.version.to.new.openclaw.version", + "mapping_status": "retired" + }, + { + "script": "test/e2e/test-upgrade-stale-sandbox.sh", + "line": 231, + "text": "Phase 7: All sandboxes up to date after rebuild", + "polarity": "pass", + "normalized_id": "phase.7.all.sandboxes.up.to.date.after.rebuild", + "mapping_status": "deferred" + }, + { + "script": "test/e2e/test-upgrade-stale-sandbox.sh", + "line": 233, + "text": "Phase 7: upgrade-sandboxes --check did not report 'up to date' after rebuild", + "polarity": "fail", + "normalized_id": "phase.7.upgrade.sandboxes.check.did.not.report.up.to.date.after.rebuild", + "mapping_status": "deferred" + } + ] + } + ], + "totals": { + "scripts": 47, + "assertions": 1923, + "zero_assertion_scripts": 1 + } +} diff --git a/test/e2e/docs/parity-map.yaml b/test/e2e/docs/parity-map.yaml new file mode 100644 index 0000000000..27cab63bed --- /dev/null +++ b/test/e2e/docs/parity-map.yaml @@ -0,0 +1,9579 @@ +# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +# +# Parity map: legacy PASS/FAIL strings to scenario-side assertion ids. +# Every inventory assertion is explicitly mapped, deferred, or retired. + +scripts: + brev-e2e.test.ts: + scenario: "" + status: retired + bucket: final-security-policy-platform-misc + retirement_evidence: no PASS/FAIL legacy assertions extracted; reviewed 2026-05-13 + assertions: [] + test-brave-search-e2e.sh: + scenario: ubuntu-repo-cloud-openclaw + status: migrated + bucket: providers-messaging + assertions: + - legacy: "B1: ${onboard_cmd_desc} completed for Brave Search-enabled onboard" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "B1: ${onboard_cmd_desc} failed (exit $onboard_exit)" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "B2a: openshell policy get failed (exit $rc)" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "B2a: brave preset applied — api.search.brave.com is in the loaded gateway policy" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "B2a: brave preset NOT applied — api.search.brave.com is missing from the gateway policy" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "B2b: could not read openclaw web-search config (exit $config_rc)" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "B2b: brave preset wired through to openclaw — tools.web.search.provider=brave and enabled=true" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "B2b: openclaw web-search config does not select brave (got: $(printf '%s' " + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "B3a: SECURITY — real BRAVE_API_KEY found verbatim in /sandbox/.openclaw/openclaw.json" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "B3a: openclaw.json contains the placeholder, not the real key" + status: retired + reason: legacy assertion is obsolete or negative cleanup behavior after scenario migration + reviewer: e2e-maintainers + approved_at: "2026-05-13" + - legacy: "B3a: openclaw.json has neither the real key nor the placeholder — web search not configured" + status: retired + reason: legacy assertion is obsolete or negative cleanup behavior after scenario migration + reviewer: e2e-maintainers + approved_at: "2026-05-13" + - legacy: "B3b: SECURITY — real BRAVE_API_KEY visible to sandbox shell via printenv" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "B3b: sandbox shell env does not expose the real key (placeholder or empty)" + status: retired + reason: legacy assertion is obsolete or negative cleanup behavior after scenario migration + reviewer: e2e-maintainers + approved_at: "2026-05-13" + - legacy: "B3b: unexpected non-empty BRAVE_API_KEY in sandbox env" + status: retired + reason: legacy assertion is obsolete or negative cleanup behavior after scenario migration + reviewer: e2e-maintainers + approved_at: "2026-05-13" + - legacy: "B4a: agent web-search turn — could not get SSH config" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "B4a: agent web-search failed with provider/transport error (exit ${rc}): $(printf '%s' " + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "B4a: openclaw agent web-search returned a real Brave result" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "B4a: agent web-search did not return a recognizable Brave result (exit ${rc}, reply='$(printf '%s' " + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "B4b: real Brave search via curl returned HTTP 200 with non-empty web.results[]" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "B4b: HTTP 200 but response had no web.results[] (body parsed empty)" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "B4b: curl never completed an HTTP transaction — check curl is in brave.yaml binaries allowlist. $(printf '%s' " + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "B4b: unexpected HTTP status '${status_code:-}' from Brave (exit $rc)" + status: retired + reason: legacy assertion is obsolete or negative cleanup behavior after scenario migration + reviewer: e2e-maintainers + approved_at: "2026-05-13" + - legacy: "B0: BRAVE_API_KEY is available" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Docker is not running + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: Docker daemon + - legacy: Docker is running + status: mapped + id: legacy.brave.search.e2e.docker.is.running + - legacy: python3 not found + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: python3 is available + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + test-cloud-inference-e2e.sh: + scenario: ubuntu-repo-cloud-openclaw + status: migrated + bucket: onboarding-baseline + assertions: + - legacy: Docker is not running + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: NVIDIA_API_KEY secret and network egress + - legacy: Docker is running + status: mapped + id: legacy.cloud.inference.e2e.docker.is.running + - legacy: NVIDIA_API_KEY not set or invalid + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: NVIDIA_API_KEY secret and network egress + - legacy: NVIDIA_API_KEY is set + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: NVIDIA_API_KEY secret and network egress + - legacy: Could not cd to repo root + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: NVIDIA_API_KEY secret and network egress + - legacy: install.sh failed (exit $install_exit) + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: NVIDIA_API_KEY secret and network egress + - legacy: NemoClaw installed + status: mapped + id: legacy.cloud.inference.e2e.nemoclaw.installed + - legacy: nemoclaw not on PATH + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: NVIDIA_API_KEY secret and network egress + - legacy: openshell not on PATH + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: NVIDIA_API_KEY secret and network egress + - legacy: CLIs on PATH + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: NVIDIA_API_KEY secret and network egress + - legacy: python3 not on PATH + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: NVIDIA_API_KEY secret and network egress + - legacy: Could not build chat payload + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: NVIDIA_API_KEY secret and network egress + - legacy: openshell sandbox ssh-config failed for '${SANDBOX_NAME}' + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: NVIDIA_API_KEY secret and network egress + - legacy: Chat completion returned PONG (attempt ${attempt}/${MAX_ATTEMPTS}) + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: NVIDIA_API_KEY secret and network egress + - legacy: "Live chat: $last_fail" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: NVIDIA_API_KEY secret and network egress + - legacy: Repo skill validation failed + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: NVIDIA_API_KEY secret and network egress + - legacy: Repo agent skills (SKILL.md) valid + status: mapped + id: legacy.cloud.inference.e2e.repo.agent.skills.skill.md.valid + - legacy: "Sandbox OpenClaw layout check failed (exit ${sb_rc}): ${sb_out:0:240}" + status: mapped + id: legacy.cloud.inference.e2e.sandbox.openclaw.layout.check.failed.exit.sb.rc.sb.out.0.240 + - legacy: Sandbox /sandbox/.openclaw + openclaw.json OK + status: mapped + id: legacy.cloud.inference.e2e.sandbox.sandbox.openclaw.openclaw.json.ok + - legacy: Sandbox /sandbox/.openclaw/skills present + status: mapped + id: legacy.cloud.inference.e2e.sandbox.sandbox.openclaw.skills.present + - legacy: "Unexpected sandbox check output: ${sb_out:0:240}" + status: retired + reason: legacy assertion is obsolete or negative cleanup behavior after scenario migration + reviewer: e2e-maintainers + approved_at: "2026-05-13" + test-cloud-onboard-e2e.sh: + scenario: ubuntu-repo-cloud-openclaw + status: migrated + bucket: onboarding-baseline + assertions: + - legacy: Pre-cleanup complete + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: NVIDIA_API_KEY secret and network egress + - legacy: Docker is running + status: mapped + id: legacy.cloud.onboard.e2e.docker.is.running + - legacy: Docker is not running — cannot continue + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: NVIDIA_API_KEY secret and network egress + - legacy: NVIDIA_API_KEY is set (starts with nvapi-) + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: NVIDIA_API_KEY secret and network egress + - legacy: NVIDIA_API_KEY not set or invalid — required for cloud onboard + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: NVIDIA_API_KEY secret and network egress + - legacy: Network access to integrate.api.nvidia.com + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: NVIDIA_API_KEY secret and network egress + - legacy: Cannot reach integrate.api.nvidia.com + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: NVIDIA_API_KEY secret and network egress + - legacy: NEMOCLAW_NON_INTERACTIVE=1 is required for non-interactive install + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: NVIDIA_API_KEY secret and network egress + - legacy: NEMOCLAW_ACCEPT_THIRD_PARTY_SOFTWARE=1 is required for non-interactive install + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: NVIDIA_API_KEY secret and network egress + - legacy: Non-interactive mode configured + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: NVIDIA_API_KEY secret and network egress + - legacy: Host OS is Linux + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: NVIDIA_API_KEY secret and network egress + - legacy: >- + Interactive install (RUN_E2E_CLOUD_ONBOARD_INTERACTIVE_INSTALL=1) is not yet supported — use non-interactive + mode + status: retired + reason: legacy assertion is obsolete or negative cleanup behavior after scenario migration + reviewer: e2e-maintainers + approved_at: "2026-05-13" + - legacy: Public install completed (exit 0) + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: NVIDIA_API_KEY secret and network egress + - legacy: Public install failed (exit $install_exit) + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: NVIDIA_API_KEY secret and network egress + - legacy: Public install unexpectedly used the local source checkout + status: retired + reason: legacy assertion is obsolete or negative cleanup behavior after scenario migration + reviewer: e2e-maintainers + approved_at: "2026-05-13" + - legacy: Public install used the GitHub clone path + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: NVIDIA_API_KEY secret and network egress + - legacy: Public install did not show the GitHub clone path + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: NVIDIA_API_KEY secret and network egress + - legacy: Public install used requested ref ${PUBLIC_INSTALL_REF} + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: NVIDIA_API_KEY secret and network egress + - legacy: Public install did not use requested ref ${PUBLIC_INSTALL_REF} + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: NVIDIA_API_KEY secret and network egress + - legacy: nemoclaw on PATH ($(command -v nemoclaw)) + status: mapped + id: legacy.cloud.onboard.e2e.nemoclaw.on.path.command.v.nemoclaw + - legacy: nemoclaw not found on PATH after install + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: NVIDIA_API_KEY secret and network egress + - legacy: openshell on PATH ($(openshell --version 2>&1 || echo unknown)) + status: mapped + id: legacy.cloud.onboard.e2e.openshell.on.path.openshell.version.2.1.echo.unknown + - legacy: openshell not found on PATH after install + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: NVIDIA_API_KEY secret and network egress + - legacy: nemoclaw --help exits 0 + status: mapped + id: legacy.cloud.onboard.e2e.nemoclaw.help.exits.0 + - legacy: nemoclaw --help failed + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: NVIDIA_API_KEY secret and network egress + - legacy: "$(basename " + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: NVIDIA_API_KEY secret and network egress + - legacy: "$(basename " + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: NVIDIA_API_KEY secret and network egress + - legacy: Cleanup or verification failed + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: NVIDIA_API_KEY secret and network egress + - legacy: Cleanup complete + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: NVIDIA_API_KEY secret and network egress + test-credential-migration.sh: + scenario: ubuntu-repo-cloud-openclaw + status: migrated + bucket: final-security-policy-platform-misc + assertions: + - legacy: NVIDIA_API_KEY not set + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: NVIDIA_API_KEY secret and network egress + - legacy: NVIDIA_API_KEY is set + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: NVIDIA_API_KEY secret and network egress + - legacy: install.sh failed; see /tmp/nemoclaw-e2e-install.log + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: openshell still missing after install + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: nemoclaw still missing after install + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: openshell + nemoclaw on PATH + status: mapped + id: legacy.credential.migration.openshell.nemoclaw.on.path + - legacy: nemoclaw onboard succeeded with only the legacy file as the credential source + status: retired + reason: legacy assertion is obsolete or negative cleanup behavior after scenario migration + reviewer: e2e-maintainers + approved_at: "2026-05-13" + - legacy: nemoclaw onboard failed (exit $ONBOARD_EXIT); see log below + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Migration notice was emitted to stderr + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Expected migration notice on stderr; not found in onboard log + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Legacy credentials.json still exists after successful onboard + status: mapped + id: legacy.credential.migration.legacy.credentials.json.still.exists.after.successful.onboard + - legacy: Legacy credentials.json was removed after onboard + status: mapped + id: legacy.credential.migration.legacy.credentials.json.was.removed.after.onboard + - legacy: openshell -g nemoclaw provider list --names failed + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: At least one provider is registered with the gateway ($PROVIDER_COUNT total) + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: No providers registered with the gateway after migration + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: A non-allowlisted key from the tampered file appears as a gateway provider + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Non-allowlisted keys from the tampered file did not become providers + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: nemoclaw credentials list failed + status: mapped + id: legacy.credential.migration.nemoclaw.credentials.list.failed + - legacy: credentials list surfaces gateway-registered providers + status: mapped + id: legacy.credential.migration.credentials.list.surfaces.gateway.registered.providers + - legacy: credentials list did not produce the expected gateway header + status: mapped + id: legacy.credential.migration.credentials.list.did.not.produce.the.expected.gateway.header + - legacy: credentials.json reappeared on disk after credentials list + status: mapped + id: legacy.credential.migration.credentials.json.reappeared.on.disk.after.credentials.list + - legacy: No plaintext credentials.json on disk after credentials list + status: mapped + id: legacy.credential.migration.no.plaintext.credentials.json.on.disk.after.credentials.list + - legacy: node invocation of removeLegacyCredentialsFile failed + status: mapped + id: legacy.credential.migration.node.invocation.of.removelegacycredentialsfile.failed + - legacy: Symlink at credentials path was not removed + status: mapped + id: legacy.credential.migration.symlink.at.credentials.path.was.not.removed + - legacy: Symlink at credentials path was removed + status: mapped + id: legacy.credential.migration.symlink.at.credentials.path.was.removed + - legacy: Victim file was deleted; secureUnlink followed the symlink + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Victim file contents were modified; secureUnlink wrote through the symlink + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Victim file is untouched (link removed without following the target) + status: retired + reason: legacy assertion is obsolete or negative cleanup behavior after scenario migration + reviewer: e2e-maintainers + approved_at: "2026-05-13" + test-credential-sanitization.sh: + scenario: ubuntu-repo-cloud-openclaw + status: migrated + bucket: final-security-policy-platform-misc + assertions: + - legacy: NVIDIA_API_KEY not set + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: NVIDIA_API_KEY secret and network egress + - legacy: NVIDIA_API_KEY is set + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: NVIDIA_API_KEY secret and network egress + - legacy: openshell not found on PATH + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: openshell found + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: nemoclaw not found on PATH + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: nemoclaw found + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: node not found on PATH + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: node found + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Sandbox '${SANDBOX_NAME}' is running + status: mapped + id: legacy.credential.sanitization.sandbox.sandbox.name.is.running + - legacy: Sandbox '${SANDBOX_NAME}' not running — run test-full-e2e.sh first + status: mapped + id: legacy.credential.sanitization.sandbox.sandbox.name.not.running.run.test.full.e2e.sh.first + - legacy: Sanitization ran successfully + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "Sanitization script failed: ${sanitize_result:0:200}" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "C1: No fake NVIDIA key found in bundle" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "C1: Fake NVIDIA key found in bundle: ${nvapi_hits:0:200}" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "C1b: No fake GitHub/npm/gateway tokens found in bundle" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "C1b: Fake tokens found — github: ${github_hits:0:80}, npm: ${npm_hits:0:80}, gateway: ${gateway_hits:0:80}" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "C2: auth-profiles.json deleted from bundle" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "C2: auth-profiles.json still exists: $auth_files" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "C3a: nvidia.apiKey replaced with sentinel" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "C3a: nvidia.apiKey not sanitized (got: $nvidia_apikey)" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "C3b: gateway.auth.token replaced with sentinel" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "C3b: gateway.auth.token not sanitized (got: $gateway_token)" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "C4a: agents.defaults.model.primary preserved" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "C4a: agents.defaults.model.primary corrupted (got: $model_primary)" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "C4b: gateway.mode preserved" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "C4b: gateway.mode corrupted (got: $gateway_mode)" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "C5: workspace/project.md intact" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "C5: workspace/project.md content changed" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "C5: workspace/project.md missing from bundle" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "C6: Sandbox probe failed — SSH did not execute; cannot verify auth-profiles.json absence" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "C6: No auth-profiles.json found inside sandbox" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "C6: auth-profiles.json found inside sandbox: $c6_result" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "C7: Sandbox probe failed — SSH did not execute; cannot verify secret absence" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "C7: No secret patterns (nvapi-, ghp_, npm_) found in sandbox config" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "C7: Secret patterns found in sandbox — nvapi: ${c7_nvapi:0:100}, ghp: ${c7_ghp:0:100}, npm: ${c7_npm:0:100}" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "C8: Symlink traversal blocked — outside file preserved" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "C8: Symlink traversal — outside file was DELETED through symlink!" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "C9a: Empty digest string correctly rejected" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "C9a: Empty digest string was ACCEPTED — bypass still possible!" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "C9b: Undefined digest correctly rejected" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "C9b: Undefined digest was ACCEPTED — bypass still possible!" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "C10: Wrong digest correctly rejected" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "C10: Wrong digest was ACCEPTED — verification broken!" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "C11: Correct digest correctly accepted" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "C11: Correct digest was REJECTED — false negative!" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "C12: All pattern-matched credential fields stripped" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "C12: Some credential fields NOT stripped: ${c12_result}" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "C13: All non-credential fields preserved correctly" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "C13: Some non-credential fields were corrupted: ${c13_result}" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Blueprint digest field found and identified + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Blueprint digest field found (empty) + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Blueprint has a digest value set + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + test-dashboard-remote-bind.sh: + scenario: ubuntu-repo-cloud-openclaw + status: migrated + bucket: final-security-policy-platform-misc + assertions: + - legacy: $1 + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: $1 + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: nemoclaw CLI is not on PATH + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: openshell CLI is not on PATH + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Required CLIs are available + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: nemoclaw connect completed with NEMOCLAW_DASHBOARD_BIND=0.0.0.0 + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: nemoclaw connect failed with NEMOCLAW_DASHBOARD_BIND=0.0.0.0 + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: No OpenShell forward found for ${SANDBOX_NAME} on ${DASHBOARD_PORT} + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Dashboard forward binds all interfaces for remote origin (${DASHBOARD_PORT}) + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Dashboard forward is still localhost-only; expected 0.0.0.0:${DASHBOARD_PORT} + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "Could not prove dashboard forward uses 0.0.0.0:${DASHBOARD_PORT} from: ${FORWARD_LINE}" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Remote dashboard bind guard completed + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + test-deployment-services.sh: + scenario: ubuntu-repo-cloud-openclaw + status: migrated + bucket: rebuild-runtime + assertions: + - legacy: "TC-STATE-02: Setup" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "TC-STATE-02: Backup completed successfully" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "TC-STATE-02: Backup" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "TC-STATE-02: Backup dir" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "TC-STATE-02: Destroy" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "TC-STATE-02: Sandbox destroyed" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "TC-STATE-02: Re-onboard" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "TC-STATE-02: Sandbox re-onboarded" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "TC-STATE-02: Restore completed successfully" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "TC-STATE-02: Restore" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "TC-STATE-02: ${verified}/5 workspace files verified with correct content" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "TC-STATE-02: ${verified}/5 workspace files verified (partial tolerance applied)" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "TC-STATE-02: Verify" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "TC-STATE-02: Memory note restored correctly" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "TC-DEPLOY-01a: Start" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "TC-DEPLOY-01a: Tunnel URL found in status ($tunnel_url)" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "TC-DEPLOY-01a: Start" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "TC-DEPLOY-01b: Tunnel serves OpenClaw dashboard (HTTP 200, marker matched)" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: TC-DEPLOY-01b + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: TC-DEPLOY-01b + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "TC-DEPLOY-01c: Stop command" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "TC-DEPLOY-01c: Stop" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "TC-DEPLOY-01c: Tunnel URL absent after stop" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "TC-DEPLOY-01c: Stop" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "TC-DEPLOY-03: openshell binary still in PATH after uninstall" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "TC-DEPLOY-03: openshell" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "TC-DEPLOY-03: nemoclaw removed after uninstall" + status: retired + reason: legacy assertion is obsolete or negative cleanup behavior after scenario migration + reviewer: e2e-maintainers + approved_at: "2026-05-13" + - legacy: "TC-DEPLOY-03: uninstall completed (nemoclaw in source tree is expected)" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "TC-DEPLOY-03: nemoclaw" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: $PASS${NC} + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: $FAIL${NC} + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + test-device-auth-health.sh: + scenario: ubuntu-repo-cloud-openclaw + status: migrated + bucket: rebuild-runtime + assertions: + - legacy: Preflight checks passed + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Install failed with exit code $INSTALL_EXIT + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: nemoclaw not found on PATH after install + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Onboard succeeded — sandbox '${SANDBOX_NAME}' registered + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Sandbox '${SANDBOX_NAME}' not found in nemoclaw list after onboard + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: /health returns 200 (auth-free health endpoint via sandbox exec) + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: /health returned ${HEALTH_CODE} — expected 200 + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: / returns 401 (device auth is active — confirms test premise) + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: / returned ${ROOT_CODE:-empty} — expected 401 (device auth) or 200 (no auth) + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "Status reports 'Offline' — #2342 REGRESSION: 401 treated as dead" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Status does NOT report 'Offline' (gateway correctly detected as alive) + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: NVIDIA_API_KEY secret and network egress + - legacy: Status shows positive health indicator (Running/Online/Healthy) + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Host port forward to dashboard is live (HTTP ${HOST_HEALTH_CODE}) + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: NVIDIA_API_KEY secret and network egress + - legacy: Host health probe returned ${HOST_HEALTH_CODE} — expected 200 or 401 + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "Status reports 'Offline' during recovery — #2342 regression" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Status does not report 'Offline' during recovery attempt + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Gateway recovered after restart (HTTP ${RECOVER_HEALTH} on /health) + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Onboard log contains deployment verification output + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Onboard log confirms dashboard readiness check passed + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + test-diagnostics.sh: + scenario: ubuntu-repo-cloud-openclaw + status: migrated + bucket: lifecycle + assertions: + - legacy: "TC-DIAG-04: Exit code" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "TC-DIAG-04: Version output matches semver ($version_output)" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "TC-DIAG-04: Format" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "TC-DIAG-02: Exit code" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "TC-DIAG-02: debug --quick produced non-empty archive (${elapsed}s)" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "TC-DIAG-02: Output" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "TC-DIAG-02: Completed within time limit (${elapsed}s)" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "TC-DIAG-02: Timing" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "TC-DIAG-01: Setup" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "TC-DIAG-01: Debug tarball created" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "TC-DIAG-01: Extract" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "TC-DIAG-01: No API key found in debug tarball" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "TC-DIAG-01: Credential leak" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "TC-DIAG-01: No nvapi- pattern credentials in tarball" + status: mapped + id: legacy.diagnostics.tc.diag.01.no.nvapi.pattern.credentials.in.tarball + - legacy: "TC-DIAG-01: Pattern leak" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "TC-DIAG-05: Config" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "TC-DIAG-05: openclaw.json readable inside sandbox" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "TC-DIAG-05: nemoclaw status shows model info" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "TC-DIAG-05: nemoclaw status shows Model field" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "TC-DIAG-05: Status" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "TC-DIAG-03: List" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "TC-DIAG-03: credentials list works (store empty — API key passed via env on CI)" + status: mapped + id: legacy.diagnostics.tc.diag.03.credentials.list.works.store.empty.api.key.passed.via.env.on.ci + - legacy: "TC-DIAG-03: Value leak" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "TC-DIAG-03: credentials list does not expose env key values" + status: mapped + id: legacy.diagnostics.tc.diag.03.credentials.list.does.not.expose.env.key.values + - legacy: "TC-DIAG-03: credentials list shows key name" + status: mapped + id: legacy.diagnostics.tc.diag.03.credentials.list.shows.key.name + - legacy: "TC-DIAG-03: Value leak" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "TC-DIAG-03: credentials list does not expose key values" + status: mapped + id: legacy.diagnostics.tc.diag.03.credentials.list.does.not.expose.key.values + - legacy: "TC-DIAG-03: credentials reset completed" + status: mapped + id: legacy.diagnostics.tc.diag.03.credentials.reset.completed + - legacy: "TC-DIAG-03: Reset" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "TC-DIAG-03: Post-reset" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "TC-DIAG-03: NVIDIA_API_KEY removed after reset" + status: retired + reason: legacy assertion is obsolete or negative cleanup behavior after scenario migration + reviewer: e2e-maintainers + approved_at: "2026-05-13" + - legacy: $PASS${NC} + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: $FAIL${NC} + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + test-docs-validation.sh: + scenario: ubuntu-repo-cloud-openclaw + status: migrated + bucket: final-security-policy-platform-misc + assertions: + - legacy: nemoclaw on PATH + status: mapped + id: legacy.docs.validation.nemoclaw.on.path + - legacy: nemoclaw on PATH (after sourcing nvm) + status: mapped + id: legacy.docs.validation.nemoclaw.on.path.after.sourcing.nvm + - legacy: nemoclaw not on PATH — install NemoClaw first + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: CLI / docs parity check passed + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: CLI / docs parity check failed (exit ${cli_rc}) + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Markdown link validation passed + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Markdown link validation failed (exit ${links_rc}) + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + test-double-onboard.sh: + scenario: ubuntu-repo-cloud-openclaw + status: migrated + bucket: lifecycle + assertions: + - legacy: Pre-cleanup complete + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Docker is running + status: mapped + id: legacy.double.onboard.docker.is.running + - legacy: Docker is not running — cannot continue + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: Docker daemon + - legacy: openshell CLI installed + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: openshell CLI not found — cannot continue + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: nemoclaw CLI available + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: nemoclaw CLI not found — cannot continue + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: python3 installed + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: python3 not found — cannot continue + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Fake OpenAI-compatible endpoint started at ${FAKE_BASE_URL} + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Failed to start fake OpenAI-compatible endpoint + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: First onboard completed successfully + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: First onboard timed out after ${PHASE_TIMEOUT}s (exit 124) + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: First onboard exited $exit1 (expected 0) + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Sandbox '$SANDBOX_A' created + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Sandbox '$SANDBOX_A' creation not confirmed in output + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Gateway is running after first onboard + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Gateway is not running after first onboard + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Sandbox '$SANDBOX_A' exists in openshell + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Sandbox '$SANDBOX_A' not found in openshell + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Registry contains '$SANDBOX_A' + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Registry does not contain '$SANDBOX_A' + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Second onboard completed successfully + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Second onboard timed out after ${PHASE_TIMEOUT}s (exit 124) + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Second onboard exited $exit2 (expected 0) + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Healthy gateway runtime reused on second onboard ($GATEWAY_ID_BEFORE) + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Gateway runtime changed on second onboard (before=$GATEWAY_ID_BEFORE after=$GATEWAY_ID_AFTER) + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Port 8080 conflict detected (regression) + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: No port 8080 conflict on second onboard + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Port 18789 conflict detected on second onboard + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: No port 18789 conflict on second onboard + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Sandbox '$SANDBOX_A' still exists after recreate + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Sandbox '$SANDBOX_A' missing after recreate + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Alternate gateway alias selected before third onboard + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Alternate gateway alias was not selected before third onboard (selected=${selected_gateway:-unknown}) + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Could not select alternate gateway alias before third onboard (add output=${alt_gateway_add_output:-empty}) + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Third onboard completed successfully + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Third onboard timed out after ${PHASE_TIMEOUT}s (exit 124) + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Third onboard exited $exit3 (expected 0) + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Healthy gateway runtime reused on third onboard ($GATEWAY_ID_BEFORE3) + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Gateway runtime changed on third onboard (before=$GATEWAY_ID_BEFORE3 after=$GATEWAY_ID_AFTER3) + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Port 8080 conflict on third onboard + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: No port 8080 conflict on third onboard + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Port 18789 conflict on third onboard + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: No port 18789 conflict on third onboard + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Named gateway reselected during third onboard + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Named gateway was not reselected during third onboard (selected=${selected_gateway:-unknown}) + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Sandbox '$SANDBOX_B' created + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Sandbox '$SANDBOX_B' was not created + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: First sandbox '$SANDBOX_A' still exists after creating '$SANDBOX_B' + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "First sandbox '$SANDBOX_A' disappeared after creating '$SANDBOX_B' (regression: #849)" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: nemoclaw list shows dashboard ports for both test sandboxes (#2174) + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: nemoclaw list did not show dashboard ports for both test sandboxes (a=${port_a:-missing} b=${port_b:-missing}) + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: nemoclaw list shows distinct dashboard ports for test sandboxes (#2174) + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: >- + test sandboxes did not have distinct dashboard ports (#2174): ${SANDBOX_A}=${port_a:-missing} + ${SANDBOX_B}=${port_b:-missing} + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Probe-only connect recovered '$SANDBOX_B' dashboard forward + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Probe-only connect exited $probe_exit after stopping '$SANDBOX_B' dashboard forward + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Second sandbox dashboard forward restored on its recorded port + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Second sandbox dashboard forward owner mismatch on port $port_b (owner=${owner_b:-missing}) + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: First sandbox dashboard forward kept its recorded port + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: First sandbox dashboard forward owner mismatch on port $port_a (owner=${owner_a:-missing}) + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: OpenShell reports '$SANDBOX_A' absent after direct deletion + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: OpenShell still reports '$SANDBOX_A' after direct deletion + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Registry still contains stale '$SANDBOX_A' entry + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Registry was unexpectedly cleaned before status reconciliation + status: retired + reason: legacy assertion is obsolete or negative cleanup behavior after scenario migration + reviewer: e2e-maintainers + approved_at: "2026-05-13" + - legacy: Stale sandbox status exited 1 + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Stale sandbox status exited $status_exit (expected 1) + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Stale registry entry was reconciled during status + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Stale registry reconciliation message missing + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Registry still contains '$SANDBOX_A' after status reconciliation + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Registry entry for '$SANDBOX_A' removed after status reconciliation + status: retired + reason: legacy assertion is obsolete or negative cleanup behavior after scenario migration + reviewer: e2e-maintainers + approved_at: "2026-05-13" + - legacy: Post-stop status exited $gateway_status_exit + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Post-stop status exited $gateway_status_exit (expected 0 or 1) + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Gateway lifecycle response was explicit after gateway stop + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Gateway lifecycle response was not explicit after gateway stop + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Registry still contains '$SANDBOX_B' after gateway stop + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Registry is missing '$SANDBOX_B' after gateway stop + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Sandbox '$SANDBOX_A' still exists after cleanup + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Sandbox '$SANDBOX_A' cleaned up + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Sandbox '$SANDBOX_B' still exists after cleanup + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Sandbox '$SANDBOX_B' cleaned up + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Registry still contains test sandbox entries + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Registry cleaned up + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Final cleanup complete + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + test-full-e2e.sh: + scenario: ubuntu-repo-cloud-openclaw + status: migrated + bucket: onboarding-baseline + assertions: + - legacy: Pre-cleanup complete + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Docker is running + status: mapped + id: legacy.full.e2e.docker.is.running + - legacy: Docker is not running — cannot continue + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: Docker daemon + - legacy: NVIDIA_API_KEY is set (starts with nvapi-) + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: NVIDIA_API_KEY secret and network egress + - legacy: NVIDIA_API_KEY not set or invalid — required for live inference + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: NVIDIA_API_KEY secret and network egress + - legacy: Network access to integrate.api.nvidia.com + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: NVIDIA_API_KEY secret and network egress + - legacy: Cannot reach integrate.api.nvidia.com + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: NVIDIA_API_KEY secret and network egress + - legacy: NEMOCLAW_NON_INTERACTIVE=1 is required + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: NEMOCLAW_ACCEPT_THIRD_PARTY_SOFTWARE=1 is required for non-interactive install + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "Could not cd to repo root: $REPO" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: install.sh completed (exit 0) + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: install.sh failed (exit $install_exit) + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: nemoclaw installed at $(command -v nemoclaw) + status: mapped + id: legacy.full.e2e.nemoclaw.installed.at.command.v.nemoclaw + - legacy: nemoclaw not found on PATH after install + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: openshell installed ($(openshell --version 2>&1 || echo unknown)) + status: mapped + id: legacy.full.e2e.openshell.installed.openshell.version.2.1.echo.unknown + - legacy: openshell not found on PATH after install + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: nemoclaw --help exits 0 + status: mapped + id: legacy.full.e2e.nemoclaw.help.exits.0 + - legacy: nemoclaw --help failed + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: nemoclaw list contains '${SANDBOX_NAME}' + status: mapped + id: legacy.full.e2e.nemoclaw.list.contains.sandbox.name + - legacy: nemoclaw list does not contain '${SANDBOX_NAME}' + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "nemoclaw list failed: ${list_output:0:200}" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: nemoclaw ${SANDBOX_NAME} status exits 0 + status: mapped + id: legacy.full.e2e.nemoclaw.sandbox.name.status.exits.0 + - legacy: "nemoclaw ${SANDBOX_NAME} status failed: ${status_output:0:200}" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Inference configured via onboard + status: mapped + id: legacy.full.e2e.inference.configured.via.onboard + - legacy: Inference not configured — onboard did not set up nvidia-prod provider + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "openshell inference get failed: ${inf_check:0:200}" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Policy applied to sandbox + status: mapped + id: legacy.full.e2e.policy.applied.to.sandbox + - legacy: No network policy found on sandbox + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Policy presets (npm/pypi) detected in sandbox policy + status: mapped + id: legacy.full.e2e.policy.presets.npm.pypi.detected.in.sandbox.policy + - legacy: "openshell policy get failed: ${policy_output:0:200}" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "[LIVE] Direct API: model responded with PONG" + status: mapped + id: legacy.full.e2e.live.direct.api.model.responded.with.pong + - legacy: "[LIVE] Direct API: expected PONG, got: ${api_content:0:200}" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: NVIDIA_API_KEY secret and network egress + - legacy: "[LIVE] Direct API: empty response from curl" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: NVIDIA_API_KEY secret and network egress + - legacy: "[ROUTING] inference.local: OpenShell routed curl to NVIDIA Endpoints and returned PONG" + status: mapped + id: legacy.full.e2e.routing.inference.local.openshell.routed.curl.to.nvidia.endpoints.and.returned.pong + - legacy: "[ROUTING] inference.local: expected PONG after 3 attempts, got: ${sandbox_content:0:200}" + status: mapped + id: legacy.full.e2e.routing.inference.local.expected.pong.after.3.attempts.got.sandbox.content.0.200 + - legacy: "[LIVE] openclaw agent: model answered 6×7=42 through openclaw → inference.local" + status: mapped + id: legacy.full.e2e.live.openclaw.agent.model.answered.6.7.42.through.openclaw.inference.local + - legacy: "[LIVE] openclaw agent: expected '42' in agent reply, got: ${agent_reply:0:200}" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: NVIDIA_API_KEY secret and network egress + - legacy: "nemoclaw logs: produced output ($(echo " + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "nemoclaw logs: no output" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Sandbox ${SANDBOX_NAME} still in registry after destroy + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Sandbox ${SANDBOX_NAME} removed + status: retired + reason: legacy assertion is obsolete or negative cleanup behavior after scenario migration + reviewer: e2e-maintainers + approved_at: "2026-05-13" + test-gateway-drift-preflight.sh: + scenario: ubuntu-repo-cloud-openclaw + status: migrated + bucket: final-security-policy-platform-misc + assertions: + - legacy: $1 + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: $1 + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: $description + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "$description (missing pattern: $pattern)" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "$description (unexpected pattern: $pattern)" + status: retired + reason: legacy assertion is obsolete or negative cleanup behavior after scenario migration + reviewer: e2e-maintainers + approved_at: "2026-05-13" + - legacy: $description + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: npm ci failed + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: CLI build failed + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: backup-all exits non-zero on protobuf mismatch + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: backup-all unexpectedly succeeded with stale patched gateway image + status: retired + reason: legacy assertion is obsolete or negative cleanup behavior after scenario migration + reviewer: e2e-maintainers + approved_at: "2026-05-13" + - legacy: backup-all exits non-zero on stale patched gateway image + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: sandbox list was called despite preflight image drift + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: preflight image drift blocks sandbox list + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Gateway drift preflight regression guard completed + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + test-gateway-health-honest.sh: + scenario: ubuntu-repo-cloud-openclaw + status: migrated + bucket: final-security-policy-platform-misc + assertions: + - legacy: openshell not found after install + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: openshell-gateway not found after install + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: >- + Sabotage markers (GLIBC_2.38/2.39 or 'openshell-gateway-sabotage') not observed in gateway log + ${GATEWAY_ONBOARD_LOG} — the test may have failed before the sabotaged gateway was invoked, so the assertions + below cannot be trusted. Inspect $START_LOG and $GATEWAY_ONBOARD_LOG above for the real cause. + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Sabotage shim was invoked as expected (GLIBC/sabotage markers present in gateway log) + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: >- + Onboard reported '✓ Docker-driver gateway is healthy' although the gateway binary crashed on startup (#3111 + false-positive health check) + status: mapped + id: >- + legacy.gateway.health.honest.onboard.reported.docker.driver.gateway.is.healthy.although.the.gateway.binary.crashed.on.startup.3111.false.positive.health.check + - legacy: Onboard did not falsely log 'Docker-driver gateway is healthy' when the binary crashed + status: mapped + id: >- + legacy.gateway.health.honest.onboard.did.not.falsely.log.docker.driver.gateway.is.healthy.when.the.binary.crashed + - legacy: >- + startGateway() resolved successfully despite a crashed binary — onboard would have proceeded to inference + setup against a dead gateway + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: startGateway() did not resolve successfully with a crashed binary (node exit=${NODE_EXIT}) + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Onboard did not surface any gateway failure indicator to the user + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Onboard surfaced a user-visible gateway failure message + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: A non-zombie gateway pid (${LINGERING_PID}, state=${STATE}) is still alive after a simulated crash + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: NVIDIA_API_KEY secret and network egress + - legacy: No live (non-zombie) gateway process is running after the simulated crash + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: NVIDIA_API_KEY secret and network egress + - legacy: "#3111 coverage guard green: onboard correctly surfaces a crashed gateway" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + test-gpu-double-onboard.sh: + scenario: gpu-repo-local-ollama-openclaw + status: migrated + bucket: providers-messaging + assertions: + - legacy: Pre-cleanup complete + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: self-hosted GPU runner + - legacy: Docker is running + status: mapped + id: legacy.gpu.double.onboard.docker.is.running + - legacy: Docker is not running — cannot continue + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: self-hosted GPU runner + - legacy: "nvidia-smi works (GPU VRAM: ${VRAM_MB:-unknown} MB)" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: self-hosted GPU runner + - legacy: nvidia-smi failed — no NVIDIA GPU available + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: self-hosted GPU runner + - legacy: NEMOCLAW_NON_INTERACTIVE=1 is required + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: self-hosted GPU runner + - legacy: NEMOCLAW_ACCEPT_THIRD_PARTY_SOFTWARE=1 is required for non-interactive install + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: self-hosted GPU runner + - legacy: "Ollama already installed: $(ollama --version 2>/dev/null || echo unknown)" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: self-hosted GPU runner + - legacy: "Ollama installed: $(ollama --version 2>/dev/null || echo unknown)" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: self-hosted GPU runner + - legacy: Ollama installation failed + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: self-hosted GPU runner + - legacy: Existing Ollama stopped — port 11434 is free for onboard + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: self-hosted GPU runner + - legacy: "Could not cd to repo root: $REPO" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: self-hosted GPU runner + - legacy: install.sh completed (exit 0) + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: self-hosted GPU runner + - legacy: install.sh failed (exit $install_exit) + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: self-hosted GPU runner + - legacy: "nemoclaw on PATH: $(command -v nemoclaw)" + status: mapped + id: legacy.gpu.double.onboard.nemoclaw.on.path.command.v.nemoclaw + - legacy: nemoclaw not found on PATH after install + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: self-hosted GPU runner + - legacy: nemoclaw list contains '${SANDBOX_NAME}' + status: mapped + id: legacy.gpu.double.onboard.nemoclaw.list.contains.sandbox.name + - legacy: nemoclaw list does not contain '${SANDBOX_NAME}' + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: self-hosted GPU runner + - legacy: "nemoclaw list failed: ${list_output:0:200}" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: self-hosted GPU runner + - legacy: nemoclaw ${SANDBOX_NAME} status exits 0 + status: mapped + id: legacy.gpu.double.onboard.nemoclaw.sandbox.name.status.exits.0 + - legacy: nemoclaw ${SANDBOX_NAME} status failed + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: self-hosted GPU runner + - legacy: Ollama running on 127.0.0.1:11434 + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: self-hosted GPU runner + - legacy: Ollama not running — onboard should have started it + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: self-hosted GPU runner + - legacy: Auth proxy running on :${PROXY_PORT} (HTTP $PROXY_LIVE_STATUS) + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: self-hosted GPU runner + - legacy: Auth proxy not running on :${PROXY_PORT} + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: self-hosted GPU runner + - legacy: Proxy token persisted at $TOKEN_FILE + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: self-hosted GPU runner + - legacy: "Token file permissions: 600" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: self-hosted GPU runner + - legacy: "Token file permissions: expected 600, got $PERMS" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: self-hosted GPU runner + - legacy: Proxy token file missing after first onboard + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: self-hosted GPU runner + - legacy: Proxy accepts first-onboard token (200) + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: self-hosted GPU runner + - legacy: "Proxy rejects first-onboard token (status: $FIRST_AUTH_STATUS)" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: self-hosted GPU runner + - legacy: No models found in Ollama + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: self-hosted GPU runner + - legacy: openshell sandbox ssh-config failed + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: self-hosted GPU runner + - legacy: First-onboard sandbox inference succeeded + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: self-hosted GPU runner + - legacy: "First-onboard sandbox inference: expected PONG, got: ${sandbox_content:0:200}" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: self-hosted GPU runner + - legacy: "First-onboard sandbox inference: no response" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: self-hosted GPU runner + - legacy: Re-onboard completed (exit 0) + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: self-hosted GPU runner + - legacy: Re-onboard failed (exit $reonboard_exit) + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: self-hosted GPU runner + - legacy: Proxy token file exists after re-onboard + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: self-hosted GPU runner + - legacy: Proxy token file missing after re-onboard + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: self-hosted GPU runner + - legacy: "Token file permissions preserved: 600" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: self-hosted GPU runner + - legacy: "Token file permissions: expected 600, got $PERMS" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: self-hosted GPU runner + - legacy: Auth proxy running on :${PROXY_PORT} after re-onboard (HTTP $PROXY_LIVE_STATUS) + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: self-hosted GPU runner + - legacy: Auth proxy not running after re-onboard + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: self-hosted GPU runner + - legacy: Proxy accepts persisted token after re-onboard (200 — not 401) + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: self-hosted GPU runner + - legacy: PROXY TOKEN DIVERGENCE DETECTED (#2553 regression) + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: self-hosted GPU runner + - legacy: "Token on disk does not match running proxy (status: $TOKEN_AUTH_STATUS)" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: self-hosted GPU runner + - legacy: Proxy rejects unauthenticated POST after re-onboard (401) + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: self-hosted GPU runner + - legacy: Proxy should reject unauthenticated POST, got $UNAUTH_STATUS + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: self-hosted GPU runner + - legacy: Proxy rejects wrong token after re-onboard (401) + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: self-hosted GPU runner + - legacy: Proxy should reject wrong token, got $WRONG_STATUS + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: self-hosted GPU runner + - legacy: openshell sandbox ssh-config failed after re-onboard + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: self-hosted GPU runner + - legacy: Sandbox inference after re-onboard succeeded + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: self-hosted GPU runner + - legacy: SANDBOX INFERENCE RETURNED 401 — token divergence (#2553 regression) + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: self-hosted GPU runner + - legacy: "Sandbox inference after re-onboard: expected PONG, got: ${sandbox_content:0:200}" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: self-hosted GPU runner + - legacy: "Sandbox inference after re-onboard: no response" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: self-hosted GPU runner + - legacy: Sandbox ${SANDBOX_NAME} still in registry after destroy + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: self-hosted GPU runner + - legacy: Sandbox ${SANDBOX_NAME} removed from registry + status: retired + reason: legacy assertion is obsolete or negative cleanup behavior after scenario migration + reviewer: e2e-maintainers + approved_at: "2026-05-13" + - legacy: Cleanup complete + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: self-hosted GPU runner + test-gpu-e2e.sh: + scenario: gpu-repo-local-ollama-openclaw + status: migrated + bucket: providers-messaging + assertions: + - legacy: Pre-cleanup complete + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: self-hosted GPU runner + - legacy: Docker is running + status: mapped + id: legacy.gpu.e2e.docker.is.running + - legacy: Docker is not running — cannot continue + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: self-hosted GPU runner + - legacy: "nvidia-smi works (GPU VRAM: ${VRAM_MB:-unknown} MB)" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: self-hosted GPU runner + - legacy: nvidia-smi failed — no NVIDIA GPU available + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: self-hosted GPU runner + - legacy: NEMOCLAW_NON_INTERACTIVE=1 is required + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: self-hosted GPU runner + - legacy: NEMOCLAW_ACCEPT_THIRD_PARTY_SOFTWARE=1 is required for non-interactive install + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: self-hosted GPU runner + - legacy: "Ollama already installed: $(ollama --version 2>/dev/null || echo unknown)" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: self-hosted GPU runner + - legacy: "Ollama installed: $(ollama --version 2>/dev/null || echo unknown)" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: self-hosted GPU runner + - legacy: Ollama installation failed + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: self-hosted GPU runner + - legacy: Existing Ollama stopped — port 11434 is free for onboard + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: self-hosted GPU runner + - legacy: "Could not cd to repo root: $REPO" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: self-hosted GPU runner + - legacy: install.sh completed (exit 0) + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: self-hosted GPU runner + - legacy: install.sh failed (exit $install_exit) + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: self-hosted GPU runner + - legacy: "nemoclaw on PATH: $(command -v nemoclaw)" + status: mapped + id: legacy.gpu.e2e.nemoclaw.on.path.command.v.nemoclaw + - legacy: nemoclaw not found on PATH after install + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: self-hosted GPU runner + - legacy: nemoclaw list contains '${SANDBOX_NAME}' + status: mapped + id: legacy.gpu.e2e.nemoclaw.list.contains.sandbox.name + - legacy: nemoclaw list does not contain '${SANDBOX_NAME}' + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: self-hosted GPU runner + - legacy: "nemoclaw list failed: ${list_output:0:200}" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: self-hosted GPU runner + - legacy: nemoclaw ${SANDBOX_NAME} status exits 0 + status: mapped + id: legacy.gpu.e2e.nemoclaw.sandbox.name.status.exits.0 + - legacy: nemoclaw ${SANDBOX_NAME} status failed + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: self-hosted GPU runner + - legacy: Sandbox GPU is enabled by default + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: self-hosted GPU runner + - legacy: Sandbox GPU is not enabled in status output + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: self-hosted GPU runner + - legacy: Could not read sandbox GPU status + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: self-hosted GPU runner + - legacy: Sandbox nvidia-smi works + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: self-hosted GPU runner + - legacy: Sandbox nvidia-smi failed + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: self-hosted GPU runner + - legacy: Sandbox /proc/self/task//comm write works + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: self-hosted GPU runner + - legacy: Sandbox /proc comm write failed + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: self-hosted GPU runner + - legacy: Sandbox cuInit(0) succeeds + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: self-hosted GPU runner + - legacy: Sandbox cuInit(0) failed + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: self-hosted GPU runner + - legacy: Inference provider is Ollama-based + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: self-hosted GPU runner + - legacy: "Inference provider is not ollama — got: ${inf_check:0:200}" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: self-hosted GPU runner + - legacy: "openshell inference get failed: ${inf_check:0:200}" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: self-hosted GPU runner + - legacy: Ollama running on 127.0.0.1:11434 (started by onboard) + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: self-hosted GPU runner + - legacy: Ollama not running — onboard should have started it + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: self-hosted GPU runner + - legacy: Proxy token persisted at $TOKEN_FILE + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: self-hosted GPU runner + - legacy: Proxy token file missing — onboard did not persist token + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: self-hosted GPU runner + - legacy: "Token file permissions: 600" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: self-hosted GPU runner + - legacy: "Token file permissions: expected 600, got $PERMS" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: self-hosted GPU runner + - legacy: Auth proxy running on :${PROXY_PORT} (HTTP $PROXY_LIVE_STATUS) + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: self-hosted GPU runner + - legacy: Auth proxy not running on :${PROXY_PORT} — onboard should have started it + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: self-hosted GPU runner + - legacy: Auth proxy rejects unauthenticated POST (401) + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: self-hosted GPU runner + - legacy: Auth proxy should return 401 for unauthenticated POST, got $PROXY_STATUS + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: self-hosted GPU runner + - legacy: "Auth proxy accepts correct token (status: $PROXY_STATUS)" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: self-hosted GPU runner + - legacy: Auth proxy rejected the persisted token + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: self-hosted GPU runner + - legacy: "Container reachable: host.openshell.internal:${PROXY_PORT} (HTTP $CONTAINER_REACH_STATUS)" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: self-hosted GPU runner + - legacy: Container cannot reach proxy at host.openshell.internal:${PROXY_PORT} + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: self-hosted GPU runner + - legacy: Proxy still alive after kill (HTTP $DEAD_STATUS) + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: self-hosted GPU runner + - legacy: Proxy recovered from persisted token after kill (HTTP $RECOVERED_LIVE_STATUS) + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: self-hosted GPU runner + - legacy: Proxy did not restart from persisted token + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: self-hosted GPU runner + - legacy: "Recovered proxy accepts persisted token (status: $RECOVER_STATUS)" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: self-hosted GPU runner + - legacy: Recovered proxy rejected persisted token + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: self-hosted GPU runner + - legacy: No models found in Ollama + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: self-hosted GPU runner + - legacy: "[LOCAL] Direct Ollama: model responded with PONG" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: self-hosted GPU runner + - legacy: "[LOCAL] Direct Ollama: expected PONG, got: ${direct_content:0:200}" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: self-hosted GPU runner + - legacy: "[LOCAL] Direct Ollama: empty response" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: self-hosted GPU runner + - legacy: openshell sandbox ssh-config failed + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: self-hosted GPU runner + - legacy: "[LOCAL] Sandbox inference: Ollama responded through sandbox" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: self-hosted GPU runner + - legacy: "[LOCAL] Sandbox inference: expected PONG, got: ${sandbox_content:0:200}" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: self-hosted GPU runner + - legacy: "[LOCAL] Sandbox inference: no response from inference.local inside sandbox" + status: mapped + id: legacy.gpu.e2e.local.sandbox.inference.no.response.from.inference.local.inside.sandbox + - legacy: Sandbox ${SANDBOX_NAME} still in registry after destroy + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: self-hosted GPU runner + - legacy: Sandbox ${SANDBOX_NAME} removed from registry + status: retired + reason: legacy assertion is obsolete or negative cleanup behavior after scenario migration + reviewer: e2e-maintainers + approved_at: "2026-05-13" + - legacy: uninstall.sh --delete-models completed + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: self-hosted GPU runner + - legacy: uninstall.sh failed + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: self-hosted GPU runner + - legacy: $HOME/.nemoclaw directory still exists after uninstall + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: self-hosted GPU runner + - legacy: $HOME/.nemoclaw removed + status: retired + reason: legacy assertion is obsolete or negative cleanup behavior after scenario migration + reviewer: e2e-maintainers + approved_at: "2026-05-13" + - legacy: Cleanup complete + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: self-hosted GPU runner + test-hermes-discord-e2e.sh: + scenario: ubuntu-repo-cloud-hermes + status: migrated + bucket: providers-messaging + assertions: + - legacy: Docker is running + status: mapped + id: legacy.hermes.discord.e2e.docker.is.running + - legacy: Docker is not running + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Discord test credentials + - legacy: NVIDIA_API_KEY is set (starts with nvapi-) + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Discord test credentials + - legacy: NVIDIA_API_KEY not set or invalid + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Discord test credentials + - legacy: NEMOCLAW_NON_INTERACTIVE=1 + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Discord test credentials + - legacy: NEMOCLAW_NON_INTERACTIVE=1 is required + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Discord test credentials + - legacy: NEMOCLAW_ACCEPT_THIRD_PARTY_SOFTWARE=1 + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Discord test credentials + - legacy: NEMOCLAW_ACCEPT_THIRD_PARTY_SOFTWARE=1 is required + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Discord test credentials + - legacy: "Could not cd to repo root: $REPO" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Discord test credentials + - legacy: Pre-cleanup complete + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Discord test credentials + - legacy: install.sh completed (exit 0) + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Discord test credentials + - legacy: install.sh failed (exit $install_exit) + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Discord test credentials + - legacy: nemoclaw installed at $(command -v nemoclaw) + status: mapped + id: legacy.hermes.discord.e2e.nemoclaw.installed.at.command.v.nemoclaw + - legacy: nemoclaw not found on PATH after install + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Discord test credentials + - legacy: openshell installed ($(openshell --version 2>&1 || echo unknown)) + status: mapped + id: legacy.hermes.discord.e2e.openshell.installed.openshell.version.2.1.echo.unknown + - legacy: openshell not found on PATH after install + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Discord test credentials + - legacy: nemoclaw list contains '${SANDBOX_NAME}' + status: mapped + id: legacy.hermes.discord.e2e.nemoclaw.list.contains.sandbox.name + - legacy: nemoclaw list does not contain '${SANDBOX_NAME}' + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Discord test credentials + - legacy: "nemoclaw list failed: ${list_output:0:200}" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Discord test credentials + - legacy: Discord provider '${SANDBOX_NAME}-discord-bridge' exists in gateway + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Discord test credentials + - legacy: Discord provider '${SANDBOX_NAME}-discord-bridge' not found in gateway + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Discord test credentials + - legacy: Hermes health probe returned ok with Discord enabled + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Discord test credentials + - legacy: Hermes health probe did not return ok after 15 attempts + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Discord test credentials + - legacy: config.yaml uses top-level discord and no platforms.discord + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Discord test credentials + - legacy: "config.yaml schema check failed: ${config_probe:0:400}" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Discord test credentials + - legacy: .hermes/.env contains Discord placeholder and allowed users + status: retired + reason: legacy assertion is obsolete or negative cleanup behavior after scenario migration + reviewer: e2e-maintainers + approved_at: "2026-05-13" + - legacy: ".hermes/.env check failed: ${env_probe:0:400}" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Discord test credentials + - legacy: Hermetic fake Discord Gateway started on host port ${FAKE_DISCORD_GATEWAY_PORT} + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Discord test credentials + - legacy: Failed to start hermetic fake Discord Gateway + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Discord test credentials + - legacy: Applied native WebSocket policy with credential rewrite for Hermes fake Discord Gateway + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Discord test credentials + - legacy: >- + Failed to apply Hermes fake Discord Gateway policy: $(tail -20 /tmp/nemoclaw-hermes-fake-discord-policy.log + 2>/dev/null | tr '\n' ' ' | cut -c1-300) + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Discord test credentials + - legacy: Hermes Python Discord Gateway path reaches READY through native OpenShell WebSocket policy + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Discord test credentials + - legacy: "Hermes native Gateway probe could not import discord.py: ${native_gateway_protocol:0:300}" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Discord test credentials + - legacy: "Hermes native Gateway protocol probe failed: ${native_gateway_protocol:0:300}" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Discord test credentials + - legacy: Hermes fake Gateway received host-side Discord token while sandbox sent only the placeholder + status: retired + reason: legacy assertion is obsolete or negative cleanup behavior after scenario migration + reviewer: e2e-maintainers + approved_at: "2026-05-13" + - legacy: Hermes fake Gateway did not prove WebSocket placeholder rewrite + status: retired + reason: legacy assertion is obsolete or negative cleanup behavior after scenario migration + reviewer: e2e-maintainers + approved_at: "2026-05-13" + - legacy: Raw Discord token absent from Hermes config.yaml and .env + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Discord test credentials + - legacy: Raw Discord token found in Hermes config files + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Discord test credentials + - legacy: Raw Discord token found in sandbox environment + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Discord test credentials + - legacy: Sandbox environment still contains DISCORD_PROXY bridge setting + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Discord test credentials + - legacy: Raw Discord token absent from sandbox environment; no DISCORD_PROXY bridge setting + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Discord test credentials + - legacy: Raw Discord token found in sandbox process list + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Discord test credentials + - legacy: Raw Discord token absent from sandbox process list + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Discord test credentials + - legacy: "Raw Discord token found on sandbox filesystem: ${sandbox_fs_hits:0:200}" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Discord test credentials + - legacy: Raw Discord token absent from sandbox filesystem + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Discord test credentials + - legacy: Discord users/@me returned 200 with configured token + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Discord test credentials + - legacy: Discord users/@me returned 401 - REST path reached Discord; this is not gateway IDENTIFY auth proof + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Discord test credentials + - legacy: "Discord API call failed: ${dc_error:0:200}" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Discord test credentials + - legacy: "Unexpected Discord API response: ${dc_api:0:300}" + status: retired + reason: legacy assertion is obsolete or negative cleanup behavior after scenario migration + reviewer: e2e-maintainers + approved_at: "2026-05-13" + - legacy: Hermes Discord proof used native WebSocket policy with no local facade, decode proxy, or DISCORD_PROXY residue + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Discord test credentials + - legacy: "Local Discord bridge residue found after native Gateway proof: ${facade_residue:0:300}" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Discord test credentials + - legacy: Sandbox ${SANDBOX_NAME} still in registry after destroy + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Discord test credentials + - legacy: Sandbox ${SANDBOX_NAME} removed + status: retired + reason: legacy assertion is obsolete or negative cleanup behavior after scenario migration + reviewer: e2e-maintainers + approved_at: "2026-05-13" + test-hermes-e2e.sh: + scenario: ubuntu-repo-cloud-hermes + status: migrated + bucket: providers-messaging + assertions: + - legacy: Pre-cleanup complete + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Docker is running + status: mapped + id: legacy.hermes.e2e.docker.is.running + - legacy: Docker is not running — cannot continue + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: Docker daemon + - legacy: NVIDIA_API_KEY is set (starts with nvapi-) + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: NVIDIA_API_KEY secret and network egress + - legacy: NVIDIA_API_KEY not set or invalid — required for live inference + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: NVIDIA_API_KEY secret and network egress + - legacy: Network access to integrate.api.nvidia.com + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: NVIDIA_API_KEY secret and network egress + - legacy: Cannot reach integrate.api.nvidia.com + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: NVIDIA_API_KEY secret and network egress + - legacy: NEMOCLAW_NON_INTERACTIVE=1 is required + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: NEMOCLAW_ACCEPT_THIRD_PARTY_SOFTWARE=1 is required for non-interactive install + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: agents/hermes/ directory and manifest.yaml exist + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: agents/hermes/ not found — is the hermes-agent-support branch checked out? + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "Could not cd to repo root: $REPO" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: install.sh completed (exit 0) + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: install.sh failed (exit $install_exit) + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: nemoclaw installed at $(command -v nemoclaw) + status: mapped + id: legacy.hermes.e2e.nemoclaw.installed.at.command.v.nemoclaw + - legacy: nemoclaw not found on PATH after install + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: openshell installed ($(openshell --version 2>&1 || echo unknown)) + status: mapped + id: legacy.hermes.e2e.openshell.installed.openshell.version.2.1.echo.unknown + - legacy: openshell not found on PATH after install + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: nemoclaw --help exits 0 + status: mapped + id: legacy.hermes.e2e.nemoclaw.help.exits.0 + - legacy: nemoclaw --help failed + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: nemoclaw list contains '${SANDBOX_NAME}' + status: mapped + id: legacy.hermes.e2e.nemoclaw.list.contains.sandbox.name + - legacy: nemoclaw list does not contain '${SANDBOX_NAME}' + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "nemoclaw list failed: ${list_output:0:200}" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: nemoclaw ${SANDBOX_NAME} status exits 0 + status: mapped + id: legacy.hermes.e2e.nemoclaw.sandbox.name.status.exits.0 + - legacy: "nemoclaw ${SANDBOX_NAME} status failed: ${status_output:0:200}" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Onboard session records agent=hermes + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Onboard session does not contain agent=hermes + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "Session file not found: $session_file" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Inference configured via onboard + status: mapped + id: legacy.hermes.e2e.inference.configured.via.onboard + - legacy: Inference not configured — onboard did not set up nvidia-prod provider + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "openshell inference get failed: ${inf_check:0:200}" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Policy applied to sandbox + status: mapped + id: legacy.hermes.e2e.policy.applied.to.sandbox + - legacy: No network policy found on sandbox + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "openshell policy get failed: ${policy_output:0:200}" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Hermes health probe returned ok + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Hermes health probe did not return ok after 15 attempts + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Could not get SSH config for sandbox ${SANDBOX_NAME} + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Hermes binary not found in sandbox + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "Hermes binary found in sandbox: ${hermes_version:0:100}" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Hermes config.yaml exists at /sandbox/.hermes/config.yaml + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Hermes config.yaml not found at /sandbox/.hermes/config.yaml + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Hermes config directory is writable (mutable default) + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Hermes config directory is read-only — should be writable by default + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Hermes config/state directory exists at /sandbox/.hermes + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Hermes config/state directory not found at /sandbox/.hermes + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "[LIVE] Direct API: model responded with PONG" + status: mapped + id: legacy.hermes.e2e.live.direct.api.model.responded.with.pong + - legacy: "[LIVE] Direct API: expected PONG, got: ${api_content:0:200}" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: NVIDIA_API_KEY secret and network egress + - legacy: "[LIVE] Direct API: empty response from curl" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: NVIDIA_API_KEY secret and network egress + - legacy: "[ROUTING] inference.local: OpenShell routed curl to NVIDIA Endpoints and returned PONG" + status: mapped + id: legacy.hermes.e2e.routing.inference.local.openshell.routed.curl.to.nvidia.endpoints.and.returned.pong + - legacy: "[ROUTING] inference.local: expected PONG, got: ${sandbox_content:0:200}" + status: mapped + id: legacy.hermes.e2e.routing.inference.local.expected.pong.got.sandbox.content.0.200 + - legacy: "[ROUTING] inference.local: no response from inference.local inside Hermes sandbox" + status: mapped + id: legacy.hermes.e2e.routing.inference.local.no.response.from.inference.local.inside.hermes.sandbox + - legacy: "nemoclaw logs: produced output ($(echo " + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "nemoclaw logs: no output" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: OpenClaw agent manifest loads correctly + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: OpenClaw agent manifest failed to load + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Hermes agent manifest loads correctly + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Hermes agent manifest failed to load + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Both agents listed by listAgents() + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: listAgents() did not return both openclaw and hermes + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Sandbox ${SANDBOX_NAME} still in registry after destroy + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Sandbox ${SANDBOX_NAME} removed + status: retired + reason: legacy assertion is obsolete or negative cleanup behavior after scenario migration + reviewer: e2e-maintainers + approved_at: "2026-05-13" + test-hermes-inference-switch.sh: + scenario: ubuntu-repo-cloud-hermes + status: migrated + bucket: providers-messaging + assertions: + - legacy: "OpenShell inference get failed: ${output:0:240}" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: OpenShell route points at ${SWITCH_PROVIDER} / ${SWITCH_MODEL} + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "OpenShell route did not switch to ${SWITCH_PROVIDER} / ${SWITCH_MODEL}: ${plain_output:0:400}" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "Registry/session were not updated for switch: ${probe:0:400}" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Registry and onboard session record the switched Hermes provider/model + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Hermes health endpoint returns ok + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "Hermes health endpoint did not return ok: ${health_response:0:240}" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "Could not read /sandbox/.hermes/config.yaml: ${config:0:240}" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "Hermes config.yaml was not patched correctly: ${probe:0:400}" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Hermes config.yaml model block uses ${SWITCH_MODEL} via inference.local + status: mapped + id: legacy.hermes.inference.switch.hermes.config.yaml.model.block.uses.switch.model.via.inference.local + - legacy: Hermes strict config hash matches config.yaml and .env + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "Hermes strict config hash check failed: ${strict_check:0:240}" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Hermes compatibility config hash matches config.yaml and .env + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "Hermes compatibility config hash check failed: ${compat_check:0:240}" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Hermes strict hash is root-owned and not writable + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "Hermes strict hash permissions are wrong: ${perms_probe:0:120}" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Hermes .env was not rewritten by inference set + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Hermes .env hash changed during inference set (${ENV_HASH_BEFORE:-missing} -> ${after:-missing}) + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Hermes sandbox inference.local returned PONG with ${SWITCH_MODEL} + status: mapped + id: legacy.hermes.inference.switch.hermes.sandbox.inference.local.returned.pong.with.switch.model + - legacy: "Hermes sandbox inference.local did not work after switch: ${last_fail}" + status: mapped + id: legacy.hermes.inference.switch.hermes.sandbox.inference.local.did.not.work.after.switch.last.fail + - legacy: Hermes API chat works after inference switch + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "Hermes API chat did not work after switch: ${last_fail}" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Pre-cleanup complete + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Docker is running + status: mapped + id: legacy.hermes.inference.switch.docker.is.running + - legacy: Docker is not running + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: Docker daemon + - legacy: NVIDIA_API_KEY is set + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: NVIDIA_API_KEY secret and network egress + - legacy: NVIDIA_API_KEY not set or invalid + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: NVIDIA_API_KEY secret and network egress + - legacy: NEMOCLAW_NON_INTERACTIVE=1 + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: NEMOCLAW_NON_INTERACTIVE=1 is required + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Third-party software acceptance is set + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: NEMOCLAW_ACCEPT_THIRD_PARTY_SOFTWARE=1 is required + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "Could not cd to repo root: $REPO" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: install.sh completed + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: install.sh failed (exit ${install_exit}) + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: nemohermes not found on PATH + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: openshell not found on PATH + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: nemohermes and openshell are on PATH + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: nemohermes inference set completed without --sandbox + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "nemohermes inference set failed (exit ${switch_rc}): ${switch_output:0:500}" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Hermes gateway process stayed running during switch + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Hermes gateway process changed during switch (${pid_before} -> ${pid_after}) + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Sandbox ${SANDBOX_NAME} still in registry after destroy + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Sandbox ${SANDBOX_NAME} removed + status: retired + reason: legacy assertion is obsolete or negative cleanup behavior after scenario migration + reviewer: e2e-maintainers + approved_at: "2026-05-13" + test-hermes-slack-e2e.sh: + scenario: ubuntu-repo-cloud-hermes + status: migrated + bucket: providers-messaging + assertions: + - legacy: Docker is running + status: mapped + id: legacy.hermes.slack.e2e.docker.is.running + - legacy: Docker is not running + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Slack test credentials + - legacy: NVIDIA_API_KEY is set (starts with nvapi-) + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Slack test credentials + - legacy: NVIDIA_API_KEY not set or invalid + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Slack test credentials + - legacy: NEMOCLAW_NON_INTERACTIVE=1 + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Slack test credentials + - legacy: NEMOCLAW_NON_INTERACTIVE=1 is required + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Slack test credentials + - legacy: NEMOCLAW_ACCEPT_THIRD_PARTY_SOFTWARE=1 + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Slack test credentials + - legacy: NEMOCLAW_ACCEPT_THIRD_PARTY_SOFTWARE=1 is required + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Slack test credentials + - legacy: "Could not cd to repo root: $REPO" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Slack test credentials + - legacy: Pre-cleanup complete + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Slack test credentials + - legacy: install.sh completed (exit 0) + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Slack test credentials + - legacy: install.sh failed (exit $install_exit) + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Slack test credentials + - legacy: nemoclaw installed at $(command -v nemoclaw) + status: mapped + id: legacy.hermes.slack.e2e.nemoclaw.installed.at.command.v.nemoclaw + - legacy: nemoclaw not found on PATH after install + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Slack test credentials + - legacy: openshell installed ($(openshell --version 2>&1 || echo unknown)) + status: mapped + id: legacy.hermes.slack.e2e.openshell.installed.openshell.version.2.1.echo.unknown + - legacy: openshell not found on PATH after install + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Slack test credentials + - legacy: nemoclaw list contains '${SANDBOX_NAME}' + status: mapped + id: legacy.hermes.slack.e2e.nemoclaw.list.contains.sandbox.name + - legacy: nemoclaw list does not contain '${SANDBOX_NAME}' + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Slack test credentials + - legacy: "nemoclaw list failed: ${list_output:0:200}" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Slack test credentials + - legacy: Slack bot provider '${SANDBOX_NAME}-slack-bridge' exists in gateway + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Slack test credentials + - legacy: Slack bot provider '${SANDBOX_NAME}-slack-bridge' not found in gateway + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Slack test credentials + - legacy: Slack app provider '${SANDBOX_NAME}-slack-app' exists in gateway + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Slack test credentials + - legacy: Slack app provider '${SANDBOX_NAME}-slack-app' not found in gateway + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Slack test credentials + - legacy: Hermes health probe returned ok with Slack enabled + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Slack test credentials + - legacy: Hermes health probe did not return ok after 15 attempts + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Slack test credentials + - legacy: config.yaml has no generic platforms.slack block or Slack token keys + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Slack test credentials + - legacy: "config.yaml check failed: ${config_probe:0:400}" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Slack test credentials + - legacy: .hermes/.env contains Slack SDK-shaped resolver placeholders + status: retired + reason: legacy assertion is obsolete or negative cleanup behavior after scenario migration + reviewer: e2e-maintainers + approved_at: "2026-05-13" + - legacy: ".hermes/.env check failed: ${env_probe:0:400}" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Slack test credentials + - legacy: Raw Slack tokens absent from Hermes config files and logs + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Slack test credentials + - legacy: Raw Slack token found in Hermes config files or logs + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Slack test credentials + - legacy: Raw Slack token found in sandbox process list + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Slack test credentials + - legacy: Raw Slack tokens absent from sandbox process list + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Slack test credentials + - legacy: Sandbox policy contains Slack network policy + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Slack test credentials + - legacy: Sandbox policy missing Slack network policy + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Slack test credentials + - legacy: Slack policy is scoped to Hermes and Python binaries + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Slack test credentials + - legacy: Slack policy missing Hermes/Python binary allowlist + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Slack test credentials + - legacy: Slack policy was replaced by or widened to Node + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Slack test credentials + - legacy: Slack policy does not allow Node + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Slack test credentials + - legacy: Slack policy includes Socket Mode websocket hosts + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Slack test credentials + - legacy: Slack policy missing Socket Mode websocket hosts + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Slack test credentials + - legacy: Slack REST policy enables OpenShell request-body credential rewrite + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Slack test credentials + - legacy: Slack policy missing request_body_credential_rewrite for REST alias rewrite + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Slack test credentials + - legacy: "openshell policy get failed: ${policy_output:0:200}" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Slack test credentials + - legacy: Hermes Slack sandbox has no decode proxy or Python placeholder-normalization preload + status: retired + reason: legacy assertion is obsolete or negative cleanup behavior after scenario migration + reviewer: e2e-maintainers + approved_at: "2026-05-13" + - legacy: "Hermes Slack bridge residue found: ${bridge_residue:0:300}" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Slack test credentials + - legacy: Slack API reached from Python through OpenShell alias substitution + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Slack test credentials + - legacy: "Slack Python API probe failed: ${slack_probe:0:400}" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Slack test credentials + - legacy: "Unexpected Slack Python API response: ${slack_probe:0:400}" + status: retired + reason: legacy assertion is obsolete or negative cleanup behavior after scenario migration + reviewer: e2e-maintainers + approved_at: "2026-05-13" + - legacy: Sandbox ${SANDBOX_NAME} still in registry after destroy + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Slack test credentials + - legacy: Sandbox ${SANDBOX_NAME} removed + status: retired + reason: legacy assertion is obsolete or negative cleanup behavior after scenario migration + reviewer: e2e-maintainers + approved_at: "2026-05-13" + - legacy: Slack app provider still exists after destroy + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Slack test credentials + - legacy: Slack app provider removed + status: retired + reason: legacy assertion is obsolete or negative cleanup behavior after scenario migration + reviewer: e2e-maintainers + approved_at: "2026-05-13" + test-inference-routing.sh: + scenario: ubuntu-repo-cloud-openclaw + status: migrated + bucket: providers-messaging + assertions: + - legacy: "TC-INF-05: Setup" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "TC-INF-05: Setup" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "TC-INF-05a: Env vars" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "TC-INF-05a: Real API key absent from sandbox environment" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "TC-INF-05b: Process list" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "TC-INF-05b: Real API key absent from sandbox process list" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "TC-INF-05c: Filesystem" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "TC-INF-05c: Filesystem" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "TC-INF-05c: Real API key absent from sandbox filesystem" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "TC-INF-05c: Filesystem" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "TC-INF-05d: Placeholder token present in sandbox (not the real key)" + status: retired + reason: legacy assertion is obsolete or negative cleanup behavior after scenario migration + reviewer: e2e-maintainers + approved_at: "2026-05-13" + - legacy: "TC-INF-05d: Placeholder" + status: retired + reason: legacy assertion is obsolete or negative cleanup behavior after scenario migration + reviewer: e2e-maintainers + approved_at: "2026-05-13" + - legacy: "TC-INF-06: Exit code" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "TC-INF-06: Onboard failed as expected (exit $exit_code)" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "TC-INF-06: Output contains classified error message" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "TC-INF-06: Error classification" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "TC-INF-06: Stack trace" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "TC-INF-06: No raw stack trace in output" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "TC-INF-06: Key exposure" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "TC-INF-06: API key not exposed in output" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "TC-INF-06: Sandbox cleanup" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "TC-INF-06: No active sandbox left behind (correct)" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "TC-INF-07: Exit code" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "TC-INF-07: Onboard failed as expected (exit $exit_code)" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "TC-INF-07: Output contains transport error classification" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "TC-INF-07: Error classification" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "TC-INF-07: Stack trace" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "TC-INF-07: No raw stack trace in output" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "TC-INF-07: Sandbox cleanup" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "TC-INF-07: No active sandbox left behind (correct)" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "TC-INF-02: Onboard" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "TC-INF-02: Onboard with OpenAI succeeded" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "TC-INF-02: SSH" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "TC-INF-02: OpenAI inference response received through sandbox proxy" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "TC-INF-02: OpenAI response received (content: ${content:0:100})" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "TC-INF-02: Inference" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "TC-INF-03: Onboard" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "TC-INF-03: Onboard with Anthropic succeeded" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "TC-INF-03: SSH" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "TC-INF-03: Anthropic inference response received through sandbox proxy" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "TC-INF-03: Anthropic response received (content: ${content:0:100})" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "TC-INF-03: Inference" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "TC-INF-09: Onboard" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "TC-INF-09: Onboard with compatible endpoint succeeded" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "TC-INF-09: SSH" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "TC-INF-09: Inference response received through sandbox proxy" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "TC-INF-09: Inference response received (content: ${content:0:100})" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "TC-INF-09: Inference" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "TC-INF-09: Inference" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: $PASS${NC} + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: $FAIL${NC} + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + test-issue-2478-crash-loop-recovery.sh: + scenario: ubuntu-repo-cloud-openclaw + status: migrated + bucket: lifecycle + assertions: + - legacy: "${context}: connect --probe-only exited nonzero" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Docker is not running + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: Docker daemon + - legacy: Docker running + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: Docker daemon + - legacy: NVIDIA_API_KEY not set or invalid + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: NVIDIA_API_KEY secret and network egress + - legacy: NVIDIA_API_KEY set + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: NVIDIA_API_KEY secret and network egress + - legacy: NEMOCLAW_NON_INTERACTIVE=1 and NEMOCLAW_ACCEPT_THIRD_PARTY_SOFTWARE=1 are required + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Required env vars set + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: cd $REPO_ROOT + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "install.sh failed (exit $install_exit). Last 30 lines:" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: install.sh + onboard completed + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: nemoclaw not on PATH after install + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: nemoclaw on PATH + status: mapped + id: legacy.issue.2478.crash.loop.recovery.nemoclaw.on.path + - legacy: Gateway never came up after onboard + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Gateway up (pid=$INIT_PID) + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Initial gateway has guard chain active (proxy-env exports + gateway preloads loaded) + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Initial gateway missing library guard chain — fix is not deployed? + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Initial gateway serves inference API (https://inference.local/v1/models responds) + status: mapped + id: >- + legacy.issue.2478.crash.loop.recovery.initial.gateway.serves.inference.api.https.inference.local.v1.models.responds + - legacy: Initial gateway alive but not serving inference — recovery is incomplete from user POV + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: NVIDIA_API_KEY secret and network egress + - legacy: "Cycle $cycle: connect --probe-only did not leave /tmp/gateway.log evidence" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "Cycle $cycle: gateway did not respawn within 45s" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "Cycle $cycle: PID unchanged ($new_pid) — kill did not land" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "Cycle $cycle: gateway respawned (pid $prev_pid → $new_pid)" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "Cycle $cycle: respawned gateway retains guard chain (proxy-env + gateway preloads loaded)" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "Cycle $cycle: respawned gateway LOST guard chain — recovery hardening regressed" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "Cycle $cycle: respawned gateway serves inference API" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "Cycle $cycle: gateway up + guards active but inference API not serving" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: proxy-env.sh is empty/missing already — cannot run negative case + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Recovery emitted [gateway-recovery] WARNING when proxy-env.sh missing + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "Recovery silently launched without warning (regression of #2478 fix)" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Recovery warning was logged, but gateway did not respawn within 45s + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "proxy-env.sh restore failed: expected $SNAPSHOT_SIZE bytes, got '${restored_size}'" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Gateway not up entering soak phase + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Gateway up but guards not active entering soak — restore did not take + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Gateway alive + guards active but inference API not serving entering soak + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: NVIDIA_API_KEY secret and network egress + - legacy: Gateway healthy with guards active and inference API serving (pid=$SOAK_START_PID) + status: mapped + id: >- + legacy.issue.2478.crash.loop.recovery.gateway.healthy.with.guards.active.and.inference.api.serving.pid.soak.start.pid + - legacy: No crash-loop detected during soak ($distinct distinct PIDs, $empty_samples empty samples) + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "Crash-loop signature: $distinct distinct PIDs and $empty_samples empty samples in ${SOAK_SECONDS}s" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Inference API available throughout soak ($inference_probes/$inference_probes probes succeeded) + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Inference API unavailable during soak ($inference_failures/$inference_probes probes failed) + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + test-kimi-inference-compat.sh: + scenario: ubuntu-repo-cloud-openclaw + status: migrated + bucket: providers-messaging + assertions: + - legacy: "K1: source CLI/OpenShell preparation failed (exit $prep_exit)" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "K1: onboard completed for Kimi compatible endpoint sandbox" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "K1: onboard failed (exit $onboard_exit)" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "K2: openclaw.json has managed Kimi compat and plugin wiring" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "K2: openclaw.json Kimi compat/plugin wiring is wrong" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "K3: sandbox inference.local models route reaches Kimi mock" + status: mapped + id: legacy.kimi.inference.compat.k3.sandbox.inference.local.models.route.reaches.kimi.mock + - legacy: "K3: sandbox inference.local models route failed (${response:0:400})" + status: mapped + id: legacy.kimi.inference.compat.k3.sandbox.inference.local.models.route.failed.response.0.400 + - legacy: "K4: OpenClaw agent completed after Kimi tool results" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "K4: OpenClaw agent did not complete successfully (exit $agent_exit)" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "K5: trajectory proves split Kimi exec calls completed cleanly" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "K5: trajectory acceptance checks failed" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "K6: Kimi mock observed authenticated streamed tool-call and final-answer traffic" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "K6: Kimi mock did not observe both streamed agent requests" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Docker is not running + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: Docker daemon + - legacy: Docker is running + status: mapped + id: legacy.kimi.inference.compat.docker.is.running + - legacy: python3 not found + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: python3 is available + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "K0: Kimi-compatible mock endpoint started" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "K0: Kimi-compatible mock endpoint failed to start" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + test-launchable-smoke.sh: + scenario: ubuntu-repo-cloud-openclaw + status: migrated + bucket: final-security-policy-platform-misc + assertions: + - legacy: Pre-cleanup complete (clone dir pre-seeded) + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: Brev launchable runner + - legacy: Docker is running + status: mapped + id: legacy.launchable.smoke.docker.is.running + - legacy: Docker is not running — cannot continue + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: Brev launchable runner + - legacy: NVIDIA_API_KEY is set (starts with nvapi-) + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: Brev launchable runner + - legacy: NVIDIA_API_KEY not set or invalid — required for live inference + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: Brev launchable runner + - legacy: Network access to integrate.api.nvidia.com + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: Brev launchable runner + - legacy: Cannot reach integrate.api.nvidia.com + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: Brev launchable runner + - legacy: NEMOCLAW_NON_INTERACTIVE=1 is required + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: Brev launchable runner + - legacy: NEMOCLAW_ACCEPT_THIRD_PARTY_SOFTWARE=1 is required for non-interactive install + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: Brev launchable runner + - legacy: brev-launchable-ci-cpu.sh found at $REPO/scripts/ + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: Brev launchable runner + - legacy: brev-launchable-ci-cpu.sh not found + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: Brev launchable runner + - legacy: brev-launchable-ci-cpu.sh completed (exit 0) + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: Brev launchable runner + - legacy: brev-launchable-ci-cpu.sh failed (exit $install_exit) + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: Brev launchable runner + - legacy: "nemoclaw on PATH: $(command -v nemoclaw)" + status: mapped + id: legacy.launchable.smoke.nemoclaw.on.path.command.v.nemoclaw + - legacy: nemoclaw not found on PATH after launchable install + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: Brev launchable runner + - legacy: nemoclaw --help exits 0 + status: mapped + id: legacy.launchable.smoke.nemoclaw.help.exits.0 + - legacy: nemoclaw --help failed + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: Brev launchable runner + - legacy: "openshell on PATH: $(command -v openshell) (${os_version})" + status: mapped + id: legacy.launchable.smoke.openshell.on.path.command.v.openshell.os.version + - legacy: openshell not found on PATH after launchable install + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: Brev launchable runner + - legacy: "Node.js >= 22 installed: ${node_version}" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: Brev launchable runner + - legacy: "Node.js version too old: ${node_version} (need >= 20)" + status: retired + reason: legacy assertion is obsolete or negative cleanup behavior after scenario migration + reviewer: e2e-maintainers + approved_at: "2026-05-13" + - legacy: Node.js not found on PATH after launchable install + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: Brev launchable runner + - legacy: Docker running after launchable install + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: Brev launchable runner + - legacy: Docker not running after launchable install + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: Brev launchable runner + - legacy: "Sentinel file exists: $SENTINEL" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: Brev launchable runner + - legacy: "Sentinel file missing: $SENTINEL" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: Brev launchable runner + - legacy: NemoClaw cloned at $NEMOCLAW_CLONE_DIR + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: Brev launchable runner + - legacy: "NemoClaw clone directory missing: $NEMOCLAW_CLONE_DIR" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: Brev launchable runner + - legacy: CLI built (dist/ exists) + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: Brev launchable runner + - legacy: CLI not built (dist/ missing) + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: Brev launchable runner + - legacy: Plugin built (nemoclaw/dist/ exists) + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: Brev launchable runner + - legacy: Plugin not built (nemoclaw/dist/ missing) + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: Brev launchable runner + - legacy: Could not cd to $NEMOCLAW_CLONE_DIR + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: Brev launchable runner + - legacy: nemoclaw onboard completed (exit 0) + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: Brev launchable runner + - legacy: nemoclaw onboard failed (exit $onboard_exit) + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: Brev launchable runner + - legacy: nemoclaw list contains '${SANDBOX_NAME}' + status: mapped + id: legacy.launchable.smoke.nemoclaw.list.contains.sandbox.name + - legacy: nemoclaw list does not contain '${SANDBOX_NAME}' + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: Brev launchable runner + - legacy: "nemoclaw list failed: ${list_output:0:200}" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: Brev launchable runner + - legacy: nemoclaw ${SANDBOX_NAME} status exits 0 + status: mapped + id: legacy.launchable.smoke.nemoclaw.sandbox.name.status.exits.0 + - legacy: "nemoclaw ${SANDBOX_NAME} status failed: ${status_output:0:200}" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: Brev launchable runner + - legacy: Inference configured via onboard (nvidia-prod) + status: mapped + id: legacy.launchable.smoke.inference.configured.via.onboard.nvidia.prod + - legacy: Inference not configured — onboard did not set up nvidia-prod provider + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: Brev launchable runner + - legacy: "openshell inference get failed: ${inf_check:0:200}" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: Brev launchable runner + - legacy: Gateway container running + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: Brev launchable runner + - legacy: "[LIVE] Direct API: model responded with PONG" + status: mapped + id: legacy.launchable.smoke.live.direct.api.model.responded.with.pong + - legacy: "[LIVE] Direct API: expected PONG, got: ${api_content:0:200}" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: Brev launchable runner + - legacy: "[LIVE] Direct API: empty response from curl" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: Brev launchable runner + - legacy: "[ROUTING] inference.local: OpenShell routed curl to NVIDIA Endpoints and returned PONG" + status: mapped + id: legacy.launchable.smoke.routing.inference.local.openshell.routed.curl.to.nvidia.endpoints.and.returned.pong + - legacy: "[ROUTING] inference.local: expected PONG after 3 attempts, got: ${sandbox_content:0:200}" + status: mapped + id: legacy.launchable.smoke.routing.inference.local.expected.pong.after.3.attempts.got.sandbox.content.0.200 + - legacy: "[LIVE] openclaw agent: model answered 6×7=42 through openclaw → inference.local" + status: mapped + id: legacy.launchable.smoke.live.openclaw.agent.model.answered.6.7.42.through.openclaw.inference.local + - legacy: "[LIVE] openclaw agent: expected '42' in agent reply, got: ${agent_reply:0:200}" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: Brev launchable runner + - legacy: Sandbox ${SANDBOX_NAME} still in registry after destroy + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: Brev launchable runner + - legacy: Sandbox ${SANDBOX_NAME} removed + status: retired + reason: legacy assertion is obsolete or negative cleanup behavior after scenario migration + reviewer: e2e-maintainers + approved_at: "2026-05-13" + - legacy: Launchable clone directory cleaned up + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: Brev launchable runner + test-messaging-compatible-endpoint.sh: + scenario: ubuntu-repo-cloud-openclaw + status: migrated + bucket: providers-messaging + assertions: + - legacy: "C1: ${onboard_cmd_desc} completed for compatible endpoint + Telegram" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Telegram test credentials + - legacy: "C1: ${onboard_cmd_desc} failed (exit $onboard_exit)" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "C3: openclaw.json uses managed inference.local provider and Telegram config" + status: mapped + id: >- + legacy.messaging.compatible.endpoint.c3.openclaw.json.uses.managed.inference.local.provider.and.telegram.config + - legacy: "C3: openclaw.json compatible endpoint shape is wrong" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "C4: Gateway stayed up after Telegram provider initialization" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Telegram test credentials + - legacy: "C4: Gateway is not serving after Telegram-compatible onboard (${result:0:200})" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Telegram test credentials + - legacy: "C5: Sandbox inference.local chat completion returned mock content" + status: mapped + id: legacy.messaging.compatible.endpoint.c5.sandbox.inference.local.chat.completion.returned.mock.content + - legacy: "C5: Sandbox inference.local chat completion failed (${response:0:400})" + status: mapped + id: legacy.messaging.compatible.endpoint.c5.sandbox.inference.local.chat.completion.failed.response.0.400 + - legacy: "C8: openclaw agent turn — could not get SSH config" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "C8: openclaw agent turn failed with provider/transport error (exit ${rc}): ${raw:0:300}" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "C8: openclaw agent completed turn via compatible endpoint (http-proxy-fix.js FORWARD-mode path exercised)" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "C8: openclaw agent turn failed (exit ${rc}); reply='${reply:0:200}', raw='${raw:0:200}'" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "C9: Mock logged no proxy_hop_headers line for the agent turn — agent did not reach /v1/chat/completions" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "C9: No proxy hop headers leaked to the compatible endpoint upstream (http-proxy-fix.js strip verified)" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "C9: Proxy hop headers leaked to upstream — http-proxy-fix.js strip broken: ${leaked}" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Docker is not running + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: Docker daemon + - legacy: Docker is running + status: mapped + id: legacy.messaging.compatible.endpoint.docker.is.running + - legacy: python3 not found + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: python3 is available + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "C0: Compatible endpoint mock started" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "C0: Compatible endpoint mock failed to start" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "C0b: Compatible endpoint mock is reachable through host address" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "C0b: Compatible endpoint mock is not reachable at ${COMPAT_ENDPOINT_URL}" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "C2: Onboard ran the compatible endpoint sandbox smoke check" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "C2: Onboard log does not show the compatible endpoint sandbox smoke check" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "C2b: Gateway has the compatible-endpoint provider" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "C2b: Gateway is missing the compatible-endpoint provider" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "C6: Compatible mock received authenticated chat traffic" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "C6: Compatible mock did not record authenticated chat traffic" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + test-messaging-providers.sh: + scenario: ubuntu-repo-cloud-openclaw + status: migrated + bucket: providers-messaging + assertions: + - legacy: NVIDIA_API_KEY not set + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: NVIDIA_API_KEY secret and network egress + - legacy: NVIDIA_API_KEY is set + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: NVIDIA_API_KEY secret and network egress + - legacy: Docker is not running + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: Docker daemon + - legacy: Docker is running + status: mapped + id: legacy.messaging.providers.docker.is.running + - legacy: Pre-cleanup complete + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Failed to append Slack policy to base sandbox policy + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Slack test credentials + - legacy: Slack network policy pre-merged into base policy + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Slack test credentials + - legacy: "Cannot pre-merge Slack policy: missing base policy or preset file" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Slack test credentials + - legacy: "M0: install.sh completed (exit 0)" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "M0: install.sh failed (exit $install_exit)" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: openshell not found on PATH after install + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: openshell installed ($(openshell --version 2>&1 || echo unknown)) + status: mapped + id: legacy.messaging.providers.openshell.installed.openshell.version.2.1.echo.unknown + - legacy: nemoclaw not found on PATH after install + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: nemoclaw installed at $(command -v nemoclaw) + status: mapped + id: legacy.messaging.providers.nemoclaw.installed.at.command.v.nemoclaw + - legacy: "M0b: Sandbox '$SANDBOX_NAME' is Ready" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "M0b: Sandbox '$SANDBOX_NAME' not Ready (list: ${sandbox_list:0:200})" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "M1: Provider '${SANDBOX_NAME}-telegram-bridge' exists in gateway" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Telegram test credentials + - legacy: "M1: Provider '${SANDBOX_NAME}-telegram-bridge' not found in gateway" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Telegram test credentials + - legacy: "M2: Provider '${SANDBOX_NAME}-discord-bridge' exists in gateway" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Discord test credentials + - legacy: "M2: Provider '${SANDBOX_NAME}-discord-bridge' not found in gateway" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Discord test credentials + - legacy: "M3: Real Telegram token leaked into sandbox env" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Telegram test credentials + - legacy: "M3: Sandbox TELEGRAM_BOT_TOKEN is a placeholder (not the real token)" + status: retired + reason: legacy assertion is obsolete or negative cleanup behavior after scenario migration + reviewer: e2e-maintainers + approved_at: "2026-05-13" + - legacy: "M4: Real Discord token leaked into sandbox env" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Discord test credentials + - legacy: "M4: Sandbox DISCORD_BOT_TOKEN is a placeholder (not the real token)" + status: retired + reason: legacy assertion is obsolete or negative cleanup behavior after scenario migration + reviewer: e2e-maintainers + approved_at: "2026-05-13" + - legacy: "M5: At least one messaging placeholder detected in sandbox" + status: retired + reason: legacy assertion is obsolete or negative cleanup behavior after scenario migration + reviewer: e2e-maintainers + approved_at: "2026-05-13" + - legacy: "M5a: Real Telegram token found in full sandbox environment dump" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Telegram test credentials + - legacy: "M5a: Real Telegram token absent from full sandbox environment" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Telegram test credentials + - legacy: "M5b: Real Telegram token found in sandbox process list" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Telegram test credentials + - legacy: "M5b: Real Telegram token absent from sandbox process list" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Telegram test credentials + - legacy: "M5c: Real Telegram token found on sandbox filesystem: ${sandbox_fs_tg}" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Telegram test credentials + - legacy: "M5c: Real Telegram token absent from sandbox filesystem" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Telegram test credentials + - legacy: "M5d: Telegram placeholder confirmed present in sandbox environment" + status: retired + reason: legacy assertion is obsolete or negative cleanup behavior after scenario migration + reviewer: e2e-maintainers + approved_at: "2026-05-13" + - legacy: "M5d: Telegram placeholder not found in sandbox environment" + status: retired + reason: legacy assertion is obsolete or negative cleanup behavior after scenario migration + reviewer: e2e-maintainers + approved_at: "2026-05-13" + - legacy: "M5e: Real Discord token found in full sandbox environment dump" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Discord test credentials + - legacy: "M5e: Real Discord token absent from full sandbox environment" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Discord test credentials + - legacy: "M5f: Real Discord token found in sandbox process list" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Discord test credentials + - legacy: "M5f: Real Discord token absent from sandbox process list" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Discord test credentials + - legacy: "M5g: Real Discord token found on sandbox filesystem: ${sandbox_fs_dc}" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Discord test credentials + - legacy: "M5g: Real Discord token absent from sandbox filesystem" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Discord test credentials + - legacy: "M5h: Discord placeholder confirmed present in sandbox environment" + status: retired + reason: legacy assertion is obsolete or negative cleanup behavior after scenario migration + reviewer: e2e-maintainers + approved_at: "2026-05-13" + - legacy: "M5h: Discord placeholder not found in sandbox environment" + status: retired + reason: legacy assertion is obsolete or negative cleanup behavior after scenario migration + reviewer: e2e-maintainers + approved_at: "2026-05-13" + - legacy: "M-S5a: Real Slack bot token found in full sandbox environment dump" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Slack test credentials + - legacy: "M-S5a: Real Slack bot token absent from full sandbox environment" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Slack test credentials + - legacy: "M-S5b: Real Slack bot token found in sandbox process list" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Slack test credentials + - legacy: "M-S5b: Real Slack bot token absent from sandbox process list" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Slack test credentials + - legacy: "M-S5c: Real Slack bot token found on sandbox filesystem: ${sandbox_fs_sl}" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Slack test credentials + - legacy: "M-S5c: Real Slack bot token absent from sandbox filesystem" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Slack test credentials + - legacy: "M-S5d: Real Slack app token found in full sandbox environment dump" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Slack test credentials + - legacy: "M-S5d: Real Slack app token absent from sandbox environment" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Slack test credentials + - legacy: "M-S5d2: Real Slack app token found in sandbox process list" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Slack test credentials + - legacy: "M-S5d2: Real Slack app token absent from sandbox process list" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Slack test credentials + - legacy: "M-S5e: Real Slack app token found on sandbox filesystem: ${sandbox_fs_sapp}" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Slack test credentials + - legacy: "M-S5e: Real Slack app token absent from sandbox filesystem" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Slack test credentials + - legacy: "M-S5f: Real Slack bot/app token spliced into openclaw.json — apply_slack_token_override regression?" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Slack test credentials + - legacy: "M-S5f: openclaw.json holds both Bolt-shape Slack placeholders (no real token on disk)" + status: retired + reason: legacy assertion is obsolete or negative cleanup behavior after scenario migration + reviewer: e2e-maintainers + approved_at: "2026-05-13" + - legacy: "M-S5g: removed Slack token rewriter preload still present in NODE_OPTIONS" + status: retired + reason: legacy assertion is obsolete or negative cleanup behavior after scenario migration + reviewer: e2e-maintainers + approved_at: "2026-05-13" + - legacy: "M-S5g: Slack token rewriter preload absent from NODE_OPTIONS" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Slack test credentials + - legacy: "M6: Could not read openclaw.json channels (${channel_json:0:200})" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "M6: Telegram channel botToken present in openclaw.json" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Telegram test credentials + - legacy: "M7: Telegram botToken is not the host-side token (placeholder confirmed)" + status: retired + reason: legacy assertion is obsolete or negative cleanup behavior after scenario migration + reviewer: e2e-maintainers + approved_at: "2026-05-13" + - legacy: "M7: Telegram botToken matches host-side token — credential leaked into config!" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Telegram test credentials + - legacy: "M8: Discord channel token present in openclaw.json" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Discord test credentials + - legacy: "M9: Discord token is not the host-side token (placeholder confirmed)" + status: retired + reason: legacy assertion is obsolete or negative cleanup behavior after scenario migration + reviewer: e2e-maintainers + approved_at: "2026-05-13" + - legacy: "M9: Discord token matches host-side token — credential leaked into config!" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Discord test credentials + - legacy: "M10: Telegram channel is enabled" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Telegram test credentials + - legacy: "M11: Discord channel is enabled" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Discord test credentials + - legacy: "M11b: Telegram dmPolicy is 'allowlist'" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Telegram test credentials + - legacy: "M11b: Telegram dmPolicy is '$tg_dm_policy' (expected 'allowlist')" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Telegram test credentials + - legacy: "M11c: Telegram allowFrom contains all expected user IDs: $tg_allow_from" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Telegram test credentials + - legacy: "M11c: Telegram allowFrom ($tg_allow_from) is missing IDs: ${missing_ids[*]} (expected all of: $TELEGRAM_IDS)" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Telegram test credentials + - legacy: "M11d: Telegram groupPolicy is 'open'" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Telegram test credentials + - legacy: "M11d: Telegram groupPolicy is '$tg_group_policy' (expected 'open')" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Telegram test credentials + - legacy: "M11e: Slack channel configured with placeholder tokens (guard needed)" + status: retired + reason: legacy assertion is obsolete or negative cleanup behavior after scenario migration + reviewer: e2e-maintainers + approved_at: "2026-05-13" + - legacy: "M12: Node.js reached api.telegram.org (${tg_reach})" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Telegram test credentials + - legacy: "M12: Node.js could not reach api.telegram.org (${tg_reach:0:200})" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Telegram test credentials + - legacy: "M13: Node.js reached discord.com (${dc_reach})" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Discord test credentials + - legacy: "M13: Node.js could not reach discord.com (${dc_reach:0:200})" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Discord test credentials + - legacy: "M13b: Hermetic fake Discord Gateway started on host port ${FAKE_DISCORD_GATEWAY_PORT}" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Discord test credentials + - legacy: "M13b: Failed to start hermetic fake Discord Gateway" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Discord test credentials + - legacy: "M13c: Applied native WebSocket policy with credential rewrite for fake Discord Gateway" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Discord test credentials + - legacy: >- + M13c: Failed to apply fake Discord Gateway policy: $(tail -20 /tmp/nemoclaw-fake-discord-policy.log + 2>/dev/null | tr '\n' ' ' | cut -c1-300) + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Discord test credentials + - legacy: "M13d: Native WebSocket upgrade reached fake Discord Gateway through OpenShell" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Discord test credentials + - legacy: "M13d: Native WebSocket upgrade failed: ${dc_ws_native:0:300}" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "M13e: Discord HELLO, placeholder IDENTIFY, READY, and heartbeat ACK completed" + status: retired + reason: legacy assertion is obsolete or negative cleanup behavior after scenario migration + reviewer: e2e-maintainers + approved_at: "2026-05-13" + - legacy: "M13e: Discord Gateway protocol proof incomplete: ${dc_ws_native:0:400}" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Discord test credentials + - legacy: "M13f: Fake Gateway received host-side Discord token; sandbox-visible IDENTIFY used only the placeholder" + status: retired + reason: legacy assertion is obsolete or negative cleanup behavior after scenario migration + reviewer: e2e-maintainers + approved_at: "2026-05-13" + - legacy: "M13f: Fake Gateway did not prove placeholder-to-token rewrite at the relay boundary" + status: retired + reason: legacy assertion is obsolete or negative cleanup behavior after scenario migration + reviewer: e2e-maintainers + approved_at: "2026-05-13" + - legacy: "M13g: Unregistered Discord WebSocket placeholder is rejected before upstream token exposure" + status: retired + reason: legacy assertion is obsolete or negative cleanup behavior after scenario migration + reviewer: e2e-maintainers + approved_at: "2026-05-13" + - legacy: "M13g: Unregistered Discord WebSocket placeholder reached READY or leaked upstream" + status: retired + reason: legacy assertion is obsolete or negative cleanup behavior after scenario migration + reviewer: e2e-maintainers + approved_at: "2026-05-13" + - legacy: "M14: curl to api.telegram.org blocked (binary restriction enforced)" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Telegram test credentials + - legacy: "M14: curl returned empty (likely blocked by policy)" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "M14: curl not available in sandbox (defense in depth)" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "M15: Telegram getMe returned 200 — real token verified!" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Telegram test credentials + - legacy: "M15: Telegram getMe returned $tg_status — L7 proxy rewrote placeholder (fake token rejected by API)" + status: retired + reason: legacy assertion is obsolete or negative cleanup behavior after scenario migration + reviewer: e2e-maintainers + approved_at: "2026-05-13" + - legacy: "M16: Full chain verified: sandbox → proxy → token rewrite → Telegram API" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Telegram test credentials + - legacy: "M15: Telegram API call failed with error: ${tg_api:0:200}" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Telegram test credentials + - legacy: "M15: Unexpected Telegram response (status=$tg_status): ${tg_api:0:200}" + status: retired + reason: legacy assertion is obsolete or negative cleanup behavior after scenario migration + reviewer: e2e-maintainers + approved_at: "2026-05-13" + - legacy: "M17: Discord users/@me returned 200 — real token verified!" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Discord test credentials + - legacy: "M17: Discord users/@me returned 401 — L7 proxy rewrote placeholder (fake token rejected by API)" + status: retired + reason: legacy assertion is obsolete or negative cleanup behavior after scenario migration + reviewer: e2e-maintainers + approved_at: "2026-05-13" + - legacy: "M17: Discord API call failed with error: ${dc_api:0:200}" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Discord test credentials + - legacy: "M17: Unexpected Discord response (status=$dc_status): ${dc_api:0:200}" + status: retired + reason: legacy assertion is obsolete or negative cleanup behavior after scenario migration + reviewer: e2e-maintainers + approved_at: "2026-05-13" + - legacy: "M-S14a: Hermetic fake Slack API started on host port ${FAKE_SLACK_API_PORT}" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Slack test credentials + - legacy: "M-S14a: Failed to start hermetic fake Slack API" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Slack test credentials + - legacy: "M-S14b: Applied REST policy for hermetic fake Slack API" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Slack test credentials + - legacy: >- + M-S14b: Failed to apply fake Slack API policy: $(tail -20 /tmp/nemoclaw-fake-slack-policy.log 2>/dev/null | tr + '\n' ' ' | cut -c1-300) + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Slack test credentials + - legacy: "M-S15: Slack auth.test returned ok:true — real token round-trip verified!" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Slack test credentials + - legacy: "M-S15: Slack auth.test returned invalid_auth — full chain verified (OpenShell alias rewrite → fake Slack)" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Slack test credentials + - legacy: "M-S15a: fake Slack saw host-side bot token in header and urlencoded body" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Slack test credentials + - legacy: "M-S15a: fake Slack capture did not prove bot header/body rewrite: ${sl_capture:0:300}" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Slack test credentials + - legacy: "M-S15: Slack API call failed with error: ${sl_api:0:200}" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Slack test credentials + - legacy: "M-S15: OpenShell did not resolve the Bolt-shape alias" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "M-S15: L7 proxy did not substitute the canonical placeholder — substitution chain broken" + status: retired + reason: legacy assertion is obsolete or negative cleanup behavior after scenario migration + reviewer: e2e-maintainers + approved_at: "2026-05-13" + - legacy: "M-S15: Unexpected Slack response (status=$sl_status): ${sl_api:0:200}" + status: retired + reason: legacy assertion is obsolete or negative cleanup behavior after scenario migration + reviewer: e2e-maintainers + approved_at: "2026-05-13" + - legacy: >- + M-S15b: L7 proxy substitutes openshell:resolve:env:SLACK_BOT_TOKEN at egress (parallels Telegram M15 / Discord + M17) + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Slack test credentials + - legacy: >- + M-S15b: L7 proxy passed canonical placeholder through unchanged — substitution not happening for + SLACK_BOT_TOKEN + status: retired + reason: legacy assertion is obsolete or negative cleanup behavior after scenario migration + reviewer: e2e-maintainers + approved_at: "2026-05-13" + - legacy: "M-S15b: Unexpected response (status=$sl_canon_status): ${sl_canonical:0:200}" + status: retired + reason: legacy assertion is obsolete or negative cleanup behavior after scenario migration + reviewer: e2e-maintainers + approved_at: "2026-05-13" + - legacy: "M-S15c: unset-var failed closed before upstream exposure" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "M-S15c: unset-var triggered connection-level failure — proxy refuses to forward unsubstituted placeholder" + status: retired + reason: legacy assertion is obsolete or negative cleanup behavior after scenario migration + reviewer: e2e-maintainers + approved_at: "2026-05-13" + - legacy: >- + M-S15c: unset-var returned HTTP 200 — proxy passed canonical placeholder through unchanged for unset env + (substitution may be a no-op) + status: retired + reason: legacy assertion is obsolete or negative cleanup behavior after scenario migration + reviewer: e2e-maintainers + approved_at: "2026-05-13" + - legacy: "M-S15c: unset-var request reached fake Slack — unresolved placeholder escaped the proxy boundary" + status: retired + reason: legacy assertion is obsolete or negative cleanup behavior after scenario migration + reviewer: e2e-maintainers + approved_at: "2026-05-13" + - legacy: "M-S16: apps.connections.open returned ok:true — real xapp token round-trip verified!" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: >- + M-S16: apps.connections.open auth-rejected — Socket Mode HTTPS leg verified (OpenShell alias rewrite → fake + Slack) + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Slack test credentials + - legacy: "M-S16a: fake Slack saw host-side app token in header and urlencoded body" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Slack test credentials + - legacy: "M-S16a: fake Slack capture did not prove app header/body rewrite: ${sl_app_capture:0:300}" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Slack test credentials + - legacy: "M-S16: OpenShell did not resolve the xapp- alias for Socket Mode path" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "M-S16: Unexpected apps.connections.open response (status=$sl_app_status): ${sl_app_api:0:200}" + status: retired + reason: legacy assertion is obsolete or negative cleanup behavior after scenario migration + reviewer: e2e-maintainers + approved_at: "2026-05-13" + - legacy: "M-S16b: unset app-token failed closed before upstream exposure" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "M-S16b: L7 proxy substitutes openshell:resolve:env:SLACK_APP_TOKEN at egress (unset-var control diverged)" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Slack test credentials + - legacy: "M-S16b: unset app-token env returned HTTP 200 — proxy may be passing canonical placeholders through unchanged" + status: retired + reason: legacy assertion is obsolete or negative cleanup behavior after scenario migration + reviewer: e2e-maintainers + approved_at: "2026-05-13" + - legacy: "M-S16b: unset app-token request reached fake Slack — unresolved placeholder escaped the proxy boundary" + status: retired + reason: legacy assertion is obsolete or negative cleanup behavior after scenario migration + reviewer: e2e-maintainers + approved_at: "2026-05-13" + - legacy: "M-S16b: L7 proxy passed canonical placeholder through unchanged for SLACK_APP_TOKEN" + status: retired + reason: legacy assertion is obsolete or negative cleanup behavior after scenario migration + reviewer: e2e-maintainers + approved_at: "2026-05-13" + - legacy: "M-S16b: Unexpected response (status=$sl_app_canon_status): ${sl_app_canonical:0:200}" + status: retired + reason: legacy assertion is obsolete or negative cleanup behavior after scenario migration + reviewer: e2e-maintainers + approved_at: "2026-05-13" + - legacy: "M18: Telegram getMe returned 200 with real token" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Telegram test credentials + - legacy: "M18b: Telegram response contains ok:true" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Telegram test credentials + - legacy: "M18: Expected Telegram getMe 200 with real token, got: $tg_status" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Telegram test credentials + - legacy: "M19: Telegram sendMessage succeeded" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Telegram test credentials + - legacy: "M19: Telegram sendMessage failed: ${send_result:0:200}" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Telegram test credentials + - legacy: "M20: Discord users/@me returned 200 with real token" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Discord test credentials + - legacy: "M20: Expected Discord users/@me 200 with real token, got: $dc_status" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Discord test credentials + - legacy: "S1: Gateway is serving on port 18789 — Slack auth failure did not crash it" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Slack test credentials + - legacy: "S1: Gateway is not serving on port 18789 (${gw_port:0:200})" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "S2: Gateway log shows Slack rejection was caught by channel guard" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Slack test credentials + - legacy: "Cleanup: Sandbox '$SANDBOX_NAME' intentionally kept" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "Cleanup: Sandbox '$SANDBOX_NAME' still present after cleanup" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "Cleanup: Sandbox '$SANDBOX_NAME' removed" + status: retired + reason: legacy assertion is obsolete or negative cleanup behavior after scenario migration + reviewer: e2e-maintainers + approved_at: "2026-05-13" + test-network-policy.sh: + scenario: ubuntu-repo-cloud-openclaw + status: migrated + bucket: final-security-policy-platform-misc + assertions: + - legacy: "TC-NET-01: Non-whitelisted URL blocked ($response)" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "TC-NET-01: Deny default" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "TC-NET-01: Deny default" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "TC-NET-02: Setup" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "TC-NET-02: PyPI reachable via pip after preset applied" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "TC-NET-02: PyPI reachable via pip (download started)" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "TC-NET-02: Whitelist" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "TC-NET-03: Setup" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "TC-NET-03: Interactive policy-add" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "TC-NET-03: Endpoint reachable after live policy-add ($after)" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: NVIDIA_API_KEY secret and network egress + - legacy: "TC-NET-03: Live policy-add" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: NVIDIA_API_KEY secret and network egress + - legacy: "TC-NET-03: Live policy-add" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: NVIDIA_API_KEY secret and network egress + - legacy: "TC-NET-04: Dry-run printed endpoint info" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "TC-NET-04: Dry-run output" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "TC-NET-04: Policy unchanged after dry-run (blocked: $after)" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "TC-NET-04: Dry-run side effect" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "TC-NET-04: Dry-run verification" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "TC-NET-07: Inference via inference.local succeeded" + status: mapped + id: legacy.network.policy.tc.net.07.inference.via.inference.local.succeeded + - legacy: "TC-NET-07: Inference" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "TC-NET-07: Direct provider access blocked ($direct_response)" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "TC-NET-07: Direct provider" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "TC-NET-07: Direct provider" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "TC-NET-05: Setup" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "TC-NET-05: Sandbox start time unchanged after policy-add (no restart)" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "TC-NET-05: Hot-reload" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "TC-NET-06: Setup" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "TC-NET-06: npm reachable under permissive policy" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "TC-NET-06: Permissive" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: + ip + + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: + ip + + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "TC-NET-09: SSRF validation correctly blocks dangerous IPs" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "TC-NET-09: SSRF" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: $PASS${NC} + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: $FAIL${NC} + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + test-ollama-auth-proxy-e2e.sh: + scenario: gpu-repo-local-ollama-openclaw + status: migrated + bucket: providers-messaging + assertions: + - legacy: Node.js not found + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "Node.js available: $(node --version)" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: curl not found + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: curl available + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Proxy script not found at $PROXY_SCRIPT + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Proxy script exists + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "Ollama already installed: $(ollama --version 2>/dev/null || echo unknown)" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Ollama installed + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Ollama install failed + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Ollama running on 127.0.0.1:${OLLAMA_PORT} + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Ollama failed to start on 127.0.0.1:${OLLAMA_PORT} + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Model $MODEL pulled + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Failed to pull $MODEL + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Model $MODEL available in Ollama + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Model $MODEL not found in /api/tags + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Auth proxy running on 0.0.0.0:${PROXY_PORT} (HTTP $STATUS) + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "Auth proxy failed to start (no HTTP response: '$STATUS')" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Unauthenticated POST /api/generate → 401 + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Expected 401 for unauthenticated POST, got $STATUS + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Wrong token POST /api/generate → 401 + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Expected 401 for wrong token, got $STATUS + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Correct token GET /api/tags → 200 + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Expected 200 for correct token, got $STATUS + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Unauthenticated GET /api/tags → 401 + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Expected 401 for unauthenticated GET /api/tags, got $STATUS + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Unauthenticated POST /api/tags → 401 + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Expected 401 for unauthenticated POST /api/tags, got $STATUS + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Proxy strips auth header — Ollama responds normally + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Proxy may not be stripping auth header correctly + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "Inference through proxy: got chat completion response" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "Inference through proxy: invalid response structure" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "Inference through proxy: empty response" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "Inference through proxy: got /api/generate response" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "Inference through proxy: invalid /api/generate response" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "Inference through proxy: empty /api/generate response" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Inference without token → 401 (not forwarded to Ollama) + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Expected 401 for unauthenticated inference, got $STATUS + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Token file exists at $TOKEN_FILE + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Token file missing + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "Token file permissions: 600" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "Token file permissions: expected 600, got $PERMS" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Token file content matches generated token + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Token file content mismatch + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Proxy confirmed dead after kill + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "Proxy still responding after kill (status: $STATUS)" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Proxy restarted from persisted token (HTTP $STATUS) + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "Proxy failed to restart (no HTTP response: '$STATUS')" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Inference works after proxy restart with persisted token + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Inference failed after proxy restart + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Persisted token matches original — no token rotation on restart + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Token changed on restart (should be the same persisted token) + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Container can reach proxy at host.openshell.internal:${PROXY_PORT} (HTTP $CONTAINER_STATUS) + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Container cannot reach proxy — reachability check would fail during onboard + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Container CANNOT reach Ollama directly on ${OLLAMA_PORT} (localhost-only binding works) + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Container CAN reach Ollama on ${OLLAMA_PORT} — Ollama may be on 0.0.0.0 + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "Container reachability: skipped (no Docker)" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: Docker daemon + - legacy: "Confirmed: proxy running with old token, rejects new token (divergence exists)" + status: retired + reason: legacy assertion is obsolete or negative cleanup behavior after scenario migration + reviewer: e2e-maintainers + approved_at: "2026-05-13" + - legacy: Divergence not reproduced (old=$OLD_TOKEN_OK new=$NEW_TOKEN_OK) — aborting test + status: retired + reason: legacy assertion is obsolete or negative cleanup behavior after scenario migration + reviewer: e2e-maintainers + approved_at: "2026-05-13" + - legacy: "After ensureOllamaAuthProxy: proxy accepts the file token (divergence fixed)" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "After ensureOllamaAuthProxy: proxy still rejects file token (divergence NOT fixed)" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "Token divergence: skipped (no prior token)" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + test-onboard-repair.sh: + scenario: ubuntu-repo-cloud-openclaw + status: migrated + bucket: lifecycle + assertions: + - legacy: Pre-cleanup complete + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Docker is running + status: mapped + id: legacy.onboard.repair.docker.is.running + - legacy: Docker is not running — cannot continue + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: Docker daemon + - legacy: openshell CLI installed + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: openshell CLI not found — cannot continue + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Node.js available + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Node.js not found — cannot continue + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: NVIDIA_API_KEY is set (starts with nvapi-) + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: NVIDIA_API_KEY secret and network egress + - legacy: NVIDIA_API_KEY not set or invalid — required for resume completion + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: NVIDIA_API_KEY secret and network egress + - legacy: >- + Exported NVIDIA_API_KEY for the repair run (host writes nothing to disk; OpenShell gateway is the system of + record) + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: NVIDIA_API_KEY secret and network egress + - legacy: First onboard exited 1 (expected interrupted run) + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: First onboard exited $first_exit (expected 1) + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Onboard session file created + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Onboard session file missing after interrupted run + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: First run failed at policy setup as intended + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: First run did not fail at the expected policy step + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Sandbox '$SANDBOX_NAME' exists after interrupted run + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Sandbox '$SANDBOX_NAME' not found after interrupted run + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Sandbox '$SANDBOX_NAME' removed to simulate stale recorded state + status: retired + reason: legacy assertion is obsolete or negative cleanup behavior after scenario migration + reviewer: e2e-maintainers + approved_at: "2026-05-13" + - legacy: Sandbox '$SANDBOX_NAME' still exists after forced deletion + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Resume completed after repairing missing sandbox + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Resume exited $repair_exit during missing-sandbox repair + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Repair resume skipped preflight + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Repair resume did not skip preflight + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Repair resume skipped gateway + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Repair resume did not skip gateway + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Repair resume detected missing sandbox + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Repair resume did not report missing sandbox recreation + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Repair resume recreated sandbox + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Repair resume did not rerun sandbox creation + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Repaired sandbox '$SANDBOX_NAME' is manageable + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Repaired sandbox '$SANDBOX_NAME' status failed + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Re-created interrupted session for conflict tests + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Resume rejected conflicting sandbox name + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Resume exited $sandbox_conflict_exit for conflicting sandbox (expected 1) + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Conflicting sandbox message is explicit + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Conflicting sandbox message missing or incorrect + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Resume rejected conflicting provider/model + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Resume exited $provider_conflict_exit for conflicting provider/model (expected 1) + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Conflicting provider message is explicit + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Conflicting provider message missing or incorrect + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Conflicting model message is explicit + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Conflicting model message missing or incorrect + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Sandbox '$SANDBOX_NAME' still exists after cleanup + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Sandbox '$SANDBOX_NAME' cleaned up + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Onboard session file still exists after cleanup + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Onboard session file cleaned up + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Final cleanup complete + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + test-onboard-resume.sh: + scenario: ubuntu-repo-cloud-openclaw + status: migrated + bucket: lifecycle + assertions: + - legacy: Pre-cleanup complete + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Docker is running + status: mapped + id: legacy.onboard.resume.docker.is.running + - legacy: Docker is not running — cannot continue + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: Docker daemon + - legacy: openshell CLI installed + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: openshell CLI not found — cannot continue + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Node.js available + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Node.js not found — cannot continue + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: NVIDIA_API_KEY is set (starts with nvapi-) + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: NVIDIA_API_KEY secret and network egress + - legacy: NVIDIA_API_KEY not set or invalid — required for resume completion + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: NVIDIA_API_KEY secret and network egress + - legacy: Network access to integrate.api.nvidia.com + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: NVIDIA_API_KEY secret and network egress + - legacy: Cannot reach integrate.api.nvidia.com + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: NVIDIA_API_KEY secret and network egress + - legacy: >- + Exported NVIDIA_API_KEY for the resume run (host writes nothing to disk; OpenShell gateway is the system of + record) + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: NVIDIA_API_KEY secret and network egress + - legacy: First onboard exited 1 (expected interrupted run) + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: First onboard exited $first_exit (expected 1) + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Sandbox '$SANDBOX_NAME' created before interruption + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Sandbox creation not confirmed in first run output + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: First run failed at policy setup as intended + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: First run did not fail at the expected policy step + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Sandbox '$SANDBOX_NAME' exists after interrupted run + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Sandbox '$SANDBOX_NAME' not found after interrupted run + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Onboard session file created + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Onboard session file missing after interrupted run + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Session file recorded openclaw completion and policy failure + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Session file did not record the expected interrupted state + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Resume completed successfully + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Resume exited $resume_exit (expected 0) + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Resume skipped preflight + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Resume did not skip preflight + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Resume skipped gateway + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Resume did not skip gateway + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Resume skipped sandbox + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Resume did not skip sandbox + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Resume reran preflight unexpectedly + status: retired + reason: legacy assertion is obsolete or negative cleanup behavior after scenario migration + reviewer: e2e-maintainers + approved_at: "2026-05-13" + - legacy: Resume did not rerun preflight + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Resume reran gateway startup unexpectedly + status: retired + reason: legacy assertion is obsolete or negative cleanup behavior after scenario migration + reviewer: e2e-maintainers + approved_at: "2026-05-13" + - legacy: Resume did not rerun gateway startup + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Resume reran sandbox creation unexpectedly + status: retired + reason: legacy assertion is obsolete or negative cleanup behavior after scenario migration + reviewer: e2e-maintainers + approved_at: "2026-05-13" + - legacy: Resume did not rerun sandbox creation + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Resume re-ran inference setup + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Resume skipped inference (already configured) + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Resume neither ran nor skipped inference setup + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Sandbox '$SANDBOX_NAME' is manageable after resume + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Sandbox '$SANDBOX_NAME' status failed after resume + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Session file recorded full completion after resume + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Session file did not record the expected completed state after resume + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Registry contains resumed sandbox entry + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Registry does not contain resumed sandbox entry + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Sandbox '$SANDBOX_NAME' still exists after cleanup + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Sandbox '$SANDBOX_NAME' cleaned up + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Onboard session file still exists after cleanup + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Onboard session file cleaned up + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Final cleanup complete + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + test-openclaw-inference-switch.sh: + scenario: ubuntu-repo-cloud-openclaw + status: migrated + bucket: providers-messaging + assertions: + - legacy: "OpenShell inference get failed: ${output:0:240}" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: OpenShell route points at ${SWITCH_PROVIDER} / ${SWITCH_MODEL} + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "OpenShell route did not switch to ${SWITCH_PROVIDER} / ${SWITCH_MODEL}: ${plain_output:0:400}" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "Registry/session were not updated for switch: ${probe:0:400}" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Registry and onboard session record the switched provider/model + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "Could not read /sandbox/.openclaw/openclaw.json: ${config:0:240}" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "OpenClaw config was not patched correctly: ${probe:0:400}" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: OpenClaw config uses inference/${SWITCH_MODEL} + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: OpenClaw config hash matches openclaw.json + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "OpenClaw config hash check failed: ${hash_check:0:240}" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Sandbox inference.local returned PONG with ${SWITCH_MODEL} + status: mapped + id: legacy.openclaw.inference.switch.sandbox.inference.local.returned.pong.with.switch.model + - legacy: "Sandbox inference.local did not work after switch: ${last_fail}" + status: mapped + id: legacy.openclaw.inference.switch.sandbox.inference.local.did.not.work.after.switch.last.fail + - legacy: Could not get SSH config for OpenClaw agent turn + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: OpenClaw agent answered through the switched inference route + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: OpenClaw agent turn failed after switch (exit ${rc}); reply='${reply:0:200}', raw='${raw:0:200}' + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Pre-cleanup complete + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Docker is running + status: mapped + id: legacy.openclaw.inference.switch.docker.is.running + - legacy: Docker is not running + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: Docker daemon + - legacy: NVIDIA_API_KEY is set + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: NVIDIA_API_KEY secret and network egress + - legacy: NVIDIA_API_KEY not set or invalid + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: NVIDIA_API_KEY secret and network egress + - legacy: NEMOCLAW_NON_INTERACTIVE=1 + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: NEMOCLAW_NON_INTERACTIVE=1 is required + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Third-party software acceptance is set + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: NEMOCLAW_ACCEPT_THIRD_PARTY_SOFTWARE=1 is required + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "Could not cd to repo root: $REPO" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: install.sh completed + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: install.sh failed (exit ${install_exit}) + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: nemoclaw not found on PATH + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: openshell not found on PATH + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: nemoclaw and openshell are on PATH + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: nemoclaw inference set completed + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "nemoclaw inference set failed (exit ${switch_rc}): ${switch_output:0:500}" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: OpenClaw gateway process stayed running during switch + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: OpenClaw gateway process changed during switch (${pid_before} -> ${pid_after}) + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Sandbox ${SANDBOX_NAME} still in registry after destroy + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Sandbox ${SANDBOX_NAME} removed + status: retired + reason: legacy assertion is obsolete or negative cleanup behavior after scenario migration + reviewer: e2e-maintainers + approved_at: "2026-05-13" + test-openshell-gateway-upgrade.sh: + scenario: ubuntu-repo-cloud-openclaw + status: migrated + bucket: rebuild-runtime + assertions: + - legacy: macOS incomplete OpenShell install unexpectedly succeeded with fake payloads + status: retired + reason: legacy assertion is obsolete or negative cleanup behavior after scenario migration + reviewer: e2e-maintainers + approved_at: "2026-05-13" + - legacy: macOS installer did not detect missing openshell-gateway + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: macOS installer did not request the Darwin openshell-gateway asset + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: macOS installer did not request the Darwin openshell-driver-vm asset + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: macOS OpenShell ${CURRENT_OPENSHELL_VERSION} incomplete install fetches Darwin gateway and VM driver assets + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: macOS installer did not repair missing openshell-driver-vm Hypervisor entitlement + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: macOS installer did not codesign openshell-driver-vm with entitlements + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: macOS installer reinstalled instead of repairing an otherwise complete OpenShell install + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: macOS OpenShell ${CURRENT_OPENSHELL_VERSION} installer repairs missing VM driver Hypervisor entitlement + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Dockerfile is missing the macOS VM rootfs compatibility ARG + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: Docker daemon + - legacy: Dockerfile patch helper does not patch the macOS VM rootfs compatibility ARG + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: Docker daemon + - legacy: onboard does not enable macOS VM rootfs compatibility for Darwin sandbox builds + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Dockerfile does not relax OpenClaw state permissions for macOS VM rootfs remapping + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: Docker daemon + - legacy: Hermes Dockerfile is missing the macOS VM rootfs compatibility ARG + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: Docker daemon + - legacy: Hermes Dockerfile does not relax Hermes state permissions for macOS VM rootfs remapping + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: Docker daemon + - legacy: Hermes Dockerfile does not relax trusted rc files for macOS VM ownership repair + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: Docker daemon + - legacy: macOS VM sandbox builds enable OpenClaw and Hermes rootfs ownership compatibility + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Compatible endpoint mock is listening at ${FAKE_BASE_URL} + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: compatible endpoint mock did not start + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: ${label} NemoClaw installer failed + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "old NemoClaw install did not leave OpenShell ${OLD_OPENSHELL_VERSION}: $(openshell --version 2>&1 || true)" + status: retired + reason: legacy assertion is obsolete or negative cleanup behavior after scenario migration + reviewer: e2e-maintainers + approved_at: "2026-05-13" + - legacy: Old NemoClaw install selected $(openshell --version) + status: retired + reason: legacy assertion is obsolete or negative cleanup behavior after scenario migration + reviewer: e2e-maintainers + approved_at: "2026-05-13" + - legacy: old installer source is ${old_head:-unknown}, expected ${expected_head:-$OLD_NEMOCLAW_REF} + status: retired + reason: legacy assertion is obsolete or negative cleanup behavior after scenario migration + reviewer: e2e-maintainers + approved_at: "2026-05-13" + - legacy: Old NemoClaw source is ${OLD_NEMOCLAW_REF} (${old_head:0:12}) + status: retired + reason: legacy assertion is obsolete or negative cleanup behavior after scenario migration + reviewer: e2e-maintainers + approved_at: "2026-05-13" + - legacy: survivor sandbox did not become Ready before gateway upgrade + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Old NemoClaw install registered survivor claw ${SURVIVOR_SANDBOX} + status: retired + reason: legacy assertion is obsolete or negative cleanup behavior after scenario migration + reviewer: e2e-maintainers + approved_at: "2026-05-13" + - legacy: old NemoClaw install did not register survivor claw ${SURVIVOR_SANDBOX} + status: retired + reason: legacy assertion is obsolete or negative cleanup behavior after scenario migration + reviewer: e2e-maintainers + approved_at: "2026-05-13" + - legacy: failed to write survivor marker before gateway upgrade + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: failed to start survivor agent before gateway upgrade + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: survivor agent did not become healthy before gateway upgrade + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: survivor agent pid was empty before gateway upgrade + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Old NemoClaw claw has live agent activity (pid ${SURVIVOR_AGENT_PID}) before gateway upgrade + status: retired + reason: legacy assertion is obsolete or negative cleanup behavior after scenario migration + reviewer: e2e-maintainers + approved_at: "2026-05-13" + - legacy: current installer did not exercise the experimental OpenShell gateway upgrade acceptance path + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: >- + current NemoClaw install did not upgrade OpenShell to ${CURRENT_OPENSHELL_VERSION}: $(openshell --version 2>&1 + || true) + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Current NemoClaw install selected $(openshell --version) + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: gateway server did not report OpenShell ${CURRENT_OPENSHELL_VERSION} after upgrade + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Gateway server reports OpenShell ${CURRENT_OPENSHELL_VERSION} after upgrade + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Current installer backed up the old running claw before replacing OpenShell + status: retired + reason: legacy assertion is obsolete or negative cleanup behavior after scenario migration + reviewer: e2e-maintainers + approved_at: "2026-05-13" + - legacy: current installer did not back up the old running claw before replacing OpenShell + status: retired + reason: legacy assertion is obsolete or negative cleanup behavior after scenario migration + reviewer: e2e-maintainers + approved_at: "2026-05-13" + - legacy: survivor sandbox is not Ready after gateway upgrade + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "survivor marker changed after gateway upgrade: got '${marker}'" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Durable OpenClaw workspace state was restored after gateway upgrade + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: OpenClaw agent is not installed/configured after gateway upgrade + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: OpenClaw agent is installed and configured after gateway upgrade + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: NemoClaw registry retained survivor sandbox after gateway upgrade + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: NemoClaw registry lost survivor sandbox after gateway upgrade + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: nemoclaw list still shows survivor sandbox after gateway upgrade + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "nemoclaw list does not show survivor sandbox after gateway upgrade: ${list_output:0:200}" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Survivor claw state remained reachable after OpenShell gateway upgrade + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Skipping live Docker-driver gateway restart regression on non-Linux host + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: NVIDIA_API_KEY secret and network egress + - legacy: >- + Current NemoClaw installer upgraded old ${OLD_NEMOCLAW_REF} claw, restored state, and kept OpenClaw running on + OpenShell ${CURRENT_OPENSHELL_VERSION} + status: retired + reason: legacy assertion is obsolete or negative cleanup behavior after scenario migration + reviewer: e2e-maintainers + approved_at: "2026-05-13" + test-overlayfs-autofix.sh: + scenario: ubuntu-repo-cloud-openclaw + status: migrated + bucket: rebuild-runtime + assertions: + - legacy: Docker is running + status: mapped + id: legacy.overlayfs.autofix.docker.is.running + - legacy: Docker is not running — cannot continue + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: Docker daemon + - legacy: NVIDIA_API_KEY is set + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: NVIDIA_API_KEY secret and network egress + - legacy: NVIDIA_API_KEY not set or invalid + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: NVIDIA_API_KEY secret and network egress + - legacy: NEMOCLAW_NON_INTERACTIVE=1 is required + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: NEMOCLAW_ACCEPT_THIRD_PARTY_SOFTWARE=1 is required + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Passwordless sudo available + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Passwordless sudo required to edit $DAEMON_JSON + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Cannot find install.sh at $REPO_ROOT/install.sh + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "Repo root found: $REPO_ROOT" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Failed to restart Docker after daemon.json change + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: Docker daemon + - legacy: Docker did not come back up after restart + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: Docker daemon + - legacy: Docker storage Driver is now overlayfs + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: Docker daemon + - legacy: DriverStatus reports io.containerd.snapshotter.v1 (the bug-triggering config) + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Pre-cleanup complete + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "Could not cd to repo root: $REPO_ROOT" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: install.sh + onboard completed (exit 0) + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: install.sh + onboard failed (exit $install_exit) + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Onboard log contains the auto-fix detection message + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Onboard log missing 'Detected Docker 26+ containerd-snapshotter overlayfs' + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: Docker daemon + - legacy: "Patched cluster image present: $patched_tag" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: No nemoclaw-cluster:*-fuse-overlayfs-* image found after onboard + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Gateway container is running the patched image + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Gateway image '$gateway_image' does not match patched tag '$patched_tag' + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Cluster log still contains the nested-overlay error after auto-fix + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Cluster log clean of the nested-overlay error + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "ensurePatchedClusterImage returned the same tag on second invocation: $second_tag" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: ensurePatchedClusterImage tag mismatch (first=$patched_tag second=$second_tag) + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "Patched image was reused (Created timestamp unchanged: $before_created)" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Patched image was rebuilt unexpectedly (before=$before_created after=$after_created) + status: retired + reason: legacy assertion is obsolete or negative cleanup behavior after scenario migration + reviewer: e2e-maintainers + approved_at: "2026-05-13" + - legacy: Onboard with auto-fix disabled exited non-zero (exit $negative_exit) within $NEGATIVE_TIMEOUT s + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Onboard unexpectedly succeeded with NEMOCLAW_DISABLE_OVERLAY_FIX=1 + status: retired + reason: legacy assertion is obsolete or negative cleanup behavior after scenario migration + reviewer: e2e-maintainers + approved_at: "2026-05-13" + - legacy: Cluster/install logs surface a nested-overlay failure signature ($overlay_evidence) + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Negative phase exited $negative_exit (not our timeout, no overlay signature) — likely unrelated flake + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + test-rebuild-hermes.sh: + scenario: ubuntu-repo-cloud-hermes + status: migrated + bucket: rebuild-runtime + assertions: + - legacy: NVIDIA_API_KEY is required + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: NVIDIA_API_KEY secret and network egress + - legacy: NEMOCLAW_NON_INTERACTIVE=1 is required + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Could not parse expected Hermes version from manifest + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: nemoclaw not found on PATH after install + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: openshell not found on PATH after install + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: NemoClaw installed + status: mapped + id: legacy.rebuild.hermes.nemoclaw.installed + - legacy: Failed to build old Hermes base image + status: retired + reason: legacy assertion is obsolete or negative cleanup behavior after scenario migration + reviewer: e2e-maintainers + approved_at: "2026-05-13" + - legacy: Old Hermes base image built (${OLD_HERMES_VERSION}) + status: retired + reason: legacy assertion is obsolete or negative cleanup behavior after scenario migration + reviewer: e2e-maintainers + approved_at: "2026-05-13" + - legacy: Cached Hermes base tag now points at old version + status: retired + reason: legacy assertion is obsolete or negative cleanup behavior after scenario migration + reviewer: e2e-maintainers + approved_at: "2026-05-13" + - legacy: Sandbox did not become Ready + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Old Hermes sandbox created + status: mapped + id: legacy.rebuild.hermes.old.hermes.sandbox.created + - legacy: Failed to write marker file + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Marker verification failed + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Pre-rebuild Hermes .env missing Discord placeholder + status: retired + reason: legacy assertion is obsolete or negative cleanup behavior after scenario migration + reviewer: e2e-maintainers + approved_at: "2026-05-13" + - legacy: Pre-rebuild Hermes config.yaml missing platforms.discord + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Discord test credentials + - legacy: Markers written, sandbox registered + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Failed to build current Hermes base image + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Current Hermes base image built + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Rebuild failed + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Rebuild completed + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Marker file survived rebuild + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "Marker file lost: got '${RESTORED}', expected '${MARKER_CONTENT}'" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Hermes binary still reports old version ${OLD_HERMES_REGISTRY_VERSION} + status: retired + reason: legacy assertion is obsolete or negative cleanup behavior after scenario migration + reviewer: e2e-maintainers + approved_at: "2026-05-13" + - legacy: Hermes binary reports expected version ${EXPECTED_HERMES_VERSION} + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "Hermes binary version mismatch: expected output to contain '${EXPECTED_HERMES_VERSION}'" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Hermes .env preserved Discord token placeholder + status: retired + reason: legacy assertion is obsolete or negative cleanup behavior after scenario migration + reviewer: e2e-maintainers + approved_at: "2026-05-13" + - legacy: "Hermes .env lost Discord placeholder after rebuild: ${RESTORED_ENV}" + status: retired + reason: legacy assertion is obsolete or negative cleanup behavior after scenario migration + reviewer: e2e-maintainers + approved_at: "2026-05-13" + - legacy: Hermes config.yaml preserved platforms.discord + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Discord test credentials + - legacy: "Hermes config.yaml lost platforms.discord after rebuild: ${RESTORED_CONFIG}" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Discord test credentials + - legacy: Inference works after rebuild (NVIDIA API key + provider chain intact) + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Registry agentVersion updated to ${REGISTRY_VERSION} + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "Registry agentVersion not updated: got '${REGISTRY_VERSION}', expected != '${OLD_HERMES_REGISTRY_VERSION}'" + status: retired + reason: legacy assertion is obsolete or negative cleanup behavior after scenario migration + reviewer: e2e-maintainers + approved_at: "2026-05-13" + - legacy: No credentials in backup + status: mapped + id: legacy.rebuild.hermes.no.credentials.in.backup + - legacy: "Credentials found: $CRED_LEAKS" + status: mapped + id: legacy.rebuild.hermes.credentials.found.cred.leaks + - legacy: "Backup directory missing: $BACKUP_DIR" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + test-rebuild-openclaw.sh: + scenario: ubuntu-repo-cloud-openclaw + status: migrated + bucket: rebuild-runtime + assertions: + - legacy: NVIDIA_API_KEY is required + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: NVIDIA_API_KEY secret and network egress + - legacy: NEMOCLAW_NON_INTERACTIVE=1 is required + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: nemoclaw not found on PATH after install + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: openshell not found on PATH after install + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: NemoClaw installed + status: mapped + id: legacy.rebuild.openclaw.nemoclaw.installed + - legacy: Failed to build old base image + status: retired + reason: legacy assertion is obsolete or negative cleanup behavior after scenario migration + reviewer: e2e-maintainers + approved_at: "2026-05-13" + - legacy: Old base image built (OpenClaw ${OLD_OPENCLAW_VERSION}) + status: retired + reason: legacy assertion is obsolete or negative cleanup behavior after scenario migration + reviewer: e2e-maintainers + approved_at: "2026-05-13" + - legacy: Sandbox did not become Ready + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Old sandbox created (OpenClaw ${OLD_OPENCLAW_VERSION}) + status: mapped + id: legacy.rebuild.openclaw.old.sandbox.created.openclaw.old.openclaw.version + - legacy: Failed to write marker file + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "Marker verification failed: got '${VERIFY}'" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Markers written, sandbox registered + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Cannot locate nemoclaw module directory + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "Failed to apply preset: ${preset}" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: npm preset active in gateway policy + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: npm preset not found in live gateway policy before rebuild + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: NVIDIA_API_KEY secret and network egress + - legacy: pypi preset active in gateway policy + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: pypi preset not found in live gateway policy before rebuild + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: NVIDIA_API_KEY secret and network egress + - legacy: Policy presets applied and verified + status: mapped + id: legacy.rebuild.openclaw.policy.presets.applied.and.verified + - legacy: Failed to build current base image + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Current base image restored + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Rebuild failed + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Rebuild completed + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Marker file survived rebuild + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "Marker file lost: got '${RESTORED}', expected '${MARKER_CONTENT}'" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Could not get OpenClaw version from sandbox (empty output) + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "Version still old after rebuild: ${NEW_VERSION}" + status: retired + reason: legacy assertion is obsolete or negative cleanup behavior after scenario migration + reviewer: e2e-maintainers + approved_at: "2026-05-13" + - legacy: "OpenClaw version upgraded: ${NEW_VERSION}" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Registry agentVersion updated to ${REGISTRY_VERSION} + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "Registry agentVersion not updated: got '${REGISTRY_VERSION}', expected != '${OLD_OPENCLAW_VERSION}'" + status: retired + reason: legacy assertion is obsolete or negative cleanup behavior after scenario migration + reviewer: e2e-maintainers + approved_at: "2026-05-13" + - legacy: Inference works after rebuild (NVIDIA API key + provider chain intact) + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: No credentials in backup + status: mapped + id: legacy.rebuild.openclaw.no.credentials.in.backup + - legacy: "Credentials found: $CRED_LEAKS" + status: mapped + id: legacy.rebuild.openclaw.credentials.found.cred.leaks + - legacy: "Backup directory missing: $BACKUP_DIR" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: npm preset survived rebuild (in registry) + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "npm preset LOST after rebuild — issue #1952" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: pypi preset survived rebuild (in registry) + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "pypi preset LOST after rebuild — issue #1952" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: npm preset active in gateway policy after rebuild + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "npm preset not in live gateway policy after rebuild — issue #1952" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: NVIDIA_API_KEY secret and network egress + - legacy: pypi preset active in gateway policy after rebuild + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "pypi preset not in live gateway policy after rebuild — issue #1952" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: NVIDIA_API_KEY secret and network egress + - legacy: "Backup manifest contains policyPresets: ${MANIFEST_PRESETS}" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "Backup manifest missing expected policyPresets (npm,pypi): got '${MANIFEST_PRESETS}' — issue #1952" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + test-runtime-overrides.sh: + scenario: ubuntu-repo-cloud-openclaw + status: migrated + bucket: rebuild-runtime + assertions: + - legacy: baseline container failed before config capture + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: baseline config hash valid + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: baseline config hash invalid + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: model overridden to $OVERRIDE_MODEL + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: expected model=$OVERRIDE_MODEL, got $ACTUAL + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: config hash valid after model override + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: config hash invalid after model override + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: contextWindow overridden to 32768 + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: expected contextWindow=32768, got $ACTUAL + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: maxTokens overridden to 16384 + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: expected maxTokens=16384, got $ACTUAL + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: reasoning overridden to true + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: expected reasoning=true, got $ACTUAL + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "CORS origin added: $CORS" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "CORS origin not found in allowedOrigins: ${ORIGINS}" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: all 5 overrides applied correctly + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "combined override mismatch: model=$M ctx=$C max=$T reasoning=$R cors=$O" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: model override with control chars rejected + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: model override with control chars was not rejected + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: non-integer context window rejected + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: non-integer context window was not rejected + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: non-integer max tokens rejected + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: non-integer max tokens was not rejected + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: invalid reasoning value rejected + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: invalid reasoning value was not rejected + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: non-http CORS origin rejected + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: non-http CORS origin was not rejected + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: invalid inference API type rejected + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: invalid inference API type was not rejected + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: config unchanged after rejected override + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: >- + config was modified despite rejected override: model=$ACTUAL_MODEL ctx=$ACTUAL_CTX (expected + model=$BASELINE_MODEL ctx=$BASELINE_CTX) + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + test-sandbox-operations.sh: + scenario: ubuntu-repo-cloud-openclaw + status: migrated + bucket: lifecycle + assertions: + - legacy: "TC-SBX-01: nemoclaw list shows '$SANDBOX_A'" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "TC-SBX-01: List Sandboxes" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "TC-SBX-02: Connect & Chat" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "TC-SBX-02: Agent computed 6×7=42 through openclaw → inference.local" + status: mapped + id: legacy.sandbox.operations.tc.sbx.02.agent.computed.6.7.42.through.openclaw.inference.local + - legacy: "TC-SBX-02: Connect & Chat" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "TC-SBX-03: Status output contains all expected fields" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "TC-SBX-03: Status Fields" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "TC-SBX-04: Log Streaming" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "TC-SBX-04: Log streaming produced output ($(echo " + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "TC-SBX-04: Log Streaming" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "TC-SBX-04: Log --follow" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "TC-SBX-04: Log --follow cleanup" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "TC-SBX-04: Log --follow exited cleanly after kill" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "TC-SBX-07: Registry rebuilt — '$SANDBOX_A' found after deletion" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "TC-SBX-07: Registry Rebuild" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "TC-SBX-08: Process Recovery (status)" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "TC-SBX-08: Status detected and recovered dead OpenClaw process" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "TC-SBX-08: Process Recovery (status)" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "TC-SBX-08: SSH works after process recovery" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "TC-SBX-08: Process Recovery (SSH)" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "TC-SBX-05: Destroy ($target)" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "TC-SBX-05: Destroy ($target)" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "TC-SBX-05: '$target' removed from nemoclaw list" + status: retired + reason: legacy assertion is obsolete or negative cleanup behavior after scenario migration + reviewer: e2e-maintainers + approved_at: "2026-05-13" + - legacy: "TC-SBX-05: Destroy ($target)" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "TC-SBX-05: '$target' removed from openshell sandbox list" + status: retired + reason: legacy assertion is obsolete or negative cleanup behavior after scenario migration + reviewer: e2e-maintainers + approved_at: "2026-05-13" + - legacy: "TC-SBX-06: Gateway recovered after docker kill" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: Docker daemon + - legacy: "TC-SBX-06: Gateway Recovery" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "TC-SBX-10: Multi-Sandbox" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "TC-SBX-10: Both sandboxes visible in nemoclaw list" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "TC-SBX-10: Multi-Sandbox" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "TC-SBX-10: Both sandboxes have non-empty metadata" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "TC-SBX-10: Multi-Sandbox Metadata" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "TC-SBX-11: Isolation (A→B)" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "TC-SBX-11: Sandbox A cannot reach sandbox B ($(echo " + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "TC-SBX-11: Isolation (A→B)" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "TC-SBX-11: Isolation (A→B)" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "TC-SBX-11: Isolation (B→A)" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "TC-SBX-11: Sandbox B cannot reach sandbox A ($(echo " + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "TC-SBX-11: Isolation (B→A)" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "TC-SBX-11: Isolation (B→A)" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: $PASS${NC} + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: $FAIL${NC} + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + test-sandbox-rebuild.sh: + scenario: ubuntu-repo-cloud-openclaw + status: migrated + bucket: lifecycle + assertions: + - legacy: NVIDIA_API_KEY is required + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: NVIDIA_API_KEY secret and network egress + - legacy: NEMOCLAW_NON_INTERACTIVE=1 is required + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Onboard failed + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Sandbox created + status: mapped + id: legacy.sandbox.rebuild.sandbox.created + - legacy: "Version detection: agent version visible in status" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Failed to write marker file + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "Marker file verification failed: got '$VERIFY'" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Marker file written and verified + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Staleness warning appears on connect + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Rebuild failed + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Rebuild completed + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Marker file survived rebuild + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "Marker file missing or changed after rebuild: got '$RESTORED', expected '$MARKER_CONTENT'" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Registry agentVersion updated to $REGISTRY_VERSION + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "Registry agentVersion not updated: got '$REGISTRY_VERSION'" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: No credentials found in backup directory + status: mapped + id: legacy.sandbox.rebuild.no.credentials.found.in.backup.directory + - legacy: "Credentials found in backup files: $CRED_LEAKS" + status: mapped + id: legacy.sandbox.rebuild.credentials.found.in.backup.files.cred.leaks + test-sandbox-survival.sh: + scenario: ubuntu-repo-cloud-openclaw + status: migrated + bucket: lifecycle + assertions: + - legacy: Gateway recovered through NemoClaw status + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Gateway start command succeeded + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Docker is running + status: mapped + id: legacy.sandbox.survival.docker.is.running + - legacy: Docker is not running — cannot continue + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: Docker daemon + - legacy: NVIDIA_API_KEY is set (starts with nvapi-) + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: NVIDIA_API_KEY secret and network egress + - legacy: NVIDIA_API_KEY not set or invalid — required for live inference + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: NVIDIA_API_KEY secret and network egress + - legacy: Network access to integrate.api.nvidia.com + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: NVIDIA_API_KEY secret and network egress + - legacy: Cannot reach integrate.api.nvidia.com + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: NVIDIA_API_KEY secret and network egress + - legacy: NEMOCLAW_NON_INTERACTIVE=1 is required + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: NEMOCLAW_ACCEPT_THIRD_PARTY_SOFTWARE=1 is required + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Cannot find install.sh at $REPO_ROOT/install.sh + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "Repo root found: $REPO_ROOT" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Pre-cleanup complete + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "Could not cd to repo root: $REPO_ROOT" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: install.sh completed (exit 0) + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: install.sh failed (exit $install_exit) + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "nemoclaw on PATH: $(command -v nemoclaw)" + status: mapped + id: legacy.sandbox.survival.nemoclaw.on.path.command.v.nemoclaw + - legacy: nemoclaw not found on PATH after install + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: openshell not found on PATH after install + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: openshell $OPENSHELL_VERSION >= $MIN_OPENSHELL (gateway resume + SSH secret + state persistence) + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: openshell $OPENSHELL_VERSION < $MIN_OPENSHELL — sandbox survival requires $MIN_OPENSHELL+ + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: NemoClaw registry contains '$SANDBOX_NAME' + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: NemoClaw registry missing '$SANDBOX_NAME' — onboard may have failed + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: nemoclaw list shows '$SANDBOX_NAME' + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "nemoclaw list doesn't show '$SANDBOX_NAME': ${list_output:0:200}" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: openshell sandbox list shows '$SANDBOX_NAME' + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "openshell sandbox list doesn't show '$SANDBOX_NAME': ${os_list:0:200}" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: nemoclaw $SANDBOX_NAME status exits 0 + status: mapped + id: legacy.sandbox.survival.nemoclaw.sandbox.name.status.exits.0 + - legacy: "nemoclaw $SANDBOX_NAME status failed: ${status_output:0:200}" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Could not get SSH config for sandbox + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: SSH config obtained + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: SSH into sandbox works (baseline) + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: SSH into sandbox failed (baseline) — cannot continue + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "[LIVE] Baseline: model responded with PONG through sandbox" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: NVIDIA_API_KEY secret and network egress + - legacy: "[LIVE] Baseline: expected PONG after 3 attempts, got: ${baseline_content:0:200}" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: NVIDIA_API_KEY secret and network egress + - legacy: "Planted workspace marker: /sandbox/.openclaw/.survival-marker-workspace" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Could not plant workspace marker + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Workspace marker verified before restart + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "Workspace marker read-back mismatch: expected '$MARKER_VALUE', got '$readback'" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "Planted agent data marker: /sandbox/.openclaw/.survival-marker" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Could not plant agent data marker + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "Planted nested marker: /sandbox/.openclaw/test-data/nested-marker.txt" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Could not plant nested workspace marker + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Gateway runtime stopped + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Gateway runtime still appears to be running after stop + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Docker container confirmed stopped + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: Docker daemon + - legacy: Docker container not running + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: Docker daemon + - legacy: "Docker container still running: state=$container_state" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: Docker daemon + - legacy: Docker-driver gateway process is not running + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: Docker daemon + - legacy: Gateway healthy after restart (attempt $attempt) + status: mapped + id: legacy.sandbox.survival.gateway.healthy.after.restart.attempt.attempt + - legacy: Gateway did not become healthy within 300 seconds + status: mapped + id: legacy.sandbox.survival.gateway.did.not.become.healthy.within.300.seconds + - legacy: openshell sandbox list shows '$SANDBOX_NAME' after restart + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "openshell sandbox list: '$SANDBOX_NAME' NOT FOUND after restart (#486)" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Sandbox pod is '$sandbox_phase' after restart + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Sandbox pod did not reach Running/Ready after restart + status: mapped + id: legacy.sandbox.survival.sandbox.pod.did.not.reach.running.ready.after.restart + - legacy: NemoClaw registry still contains '$SANDBOX_NAME' after restart + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: NemoClaw registry lost '$SANDBOX_NAME' after restart (#486) + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: nemoclaw list shows '$SANDBOX_NAME' after restart + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "nemoclaw list doesn't show '$SANDBOX_NAME' after restart: ${list_output:0:200}" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: nemoclaw $SANDBOX_NAME status exits 0 after restart (no re-onboard needed) + status: mapped + id: legacy.sandbox.survival.nemoclaw.sandbox.name.status.exits.0.after.restart.no.re.onboard.needed + - legacy: nemoclaw $SANDBOX_NAME status TIMED OUT after restart (port forward or SSH recovery hung) + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "nemoclaw $SANDBOX_NAME status failed after restart (exit $status_exit): ${status_output:0:200}" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Could not get SSH config after restart (#888 handshake failure?) + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: SSH config available after restart + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "SSH into sandbox works after restart (attempt $ssh_attempt, no handshake failure — #888/#1086)" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: SSH into sandbox FAILED after restart — handshake verification likely failed (#888/#1086) + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "Workspace marker survived restart: $MARKER_VALUE" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "Workspace marker LOST: expected '$MARKER_VALUE', got '${post_restart_marker:-}' (#1086 state loss)" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Agent data marker survived restart + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "Agent data marker LOST: expected '$MARKER_VALUE', got '${agent_marker:-}' (agent state destroyed)" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Nested workspace marker survived restart + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "Nested workspace marker LOST: expected '$MARKER_VALUE', got '${nested_marker:-}'" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Agent data directory still populated after restart + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Agent data directory is empty after restart (@Koneisto overlay wipe) + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "[LIVE] Post-restart: model responded with PONG through sandbox" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: NVIDIA_API_KEY secret and network egress + - legacy: "[LIVE] Post-restart: expected PONG after 3 attempts, got: ${post_content:0:200}" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: NVIDIA_API_KEY secret and network egress + - legacy: Sandbox '$SANDBOX_NAME' still in registry after destroy + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Sandbox '$SANDBOX_NAME' cleaned up + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + test-shields-config.sh: + scenario: ubuntu-repo-cloud-openclaw + status: migrated + bucket: final-security-policy-platform-misc + assertions: + - legacy: Docker is running + status: mapped + id: legacy.shields.config.docker.is.running + - legacy: Docker is not running — cannot continue + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: Docker daemon + - legacy: NVIDIA_API_KEY is set + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: NVIDIA_API_KEY secret and network egress + - legacy: NVIDIA_API_KEY not set or invalid + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: NVIDIA_API_KEY secret and network egress + - legacy: NEMOCLAW_NON_INTERACTIVE=1 is required + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: NEMOCLAW_ACCEPT_THIRD_PARTY_SOFTWARE=1 is required + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Prerequisites OK + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: install.sh failed (see $INSTALL_LOG) + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: nemoclaw not on PATH + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: openshell not on PATH + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "NemoClaw installed (sandbox: $SANDBOX_NAME)" + status: mapped + id: legacy.shields.config.nemoclaw.installed.sandbox.sandbox.name + - legacy: Config file mode is 660 (mutable default) + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "Config file should start as mode 660: ${PERMS}" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Config file owned by sandbox:sandbox (mutable default) + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "Config file should be owned by sandbox:sandbox: ${PERMS}" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Config directory mode is 2770 (mutable default) + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "Config directory should be mode 2770: ${DIR_PERMS}" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Config directory owned by sandbox:sandbox (mutable default) + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "Config directory should be owned by sandbox:sandbox: ${DIR_PERMS}" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Fresh sandbox status reports default mutable state + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "Fresh sandbox status should report NOT CONFIGURED mutable default: ${STATUS_DEFAULT}" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Unified .openclaw layout has no .openclaw-data mirror or symlink bridge + status: mapped + id: legacy.shields.config.unified.openclaw.layout.has.no.openclaw.data.mirror.or.symlink.bridge + - legacy: "Legacy .openclaw-data layout should not exist: ${LAYOUT_CHECK}" + status: retired + reason: legacy assertion is obsolete or negative cleanup behavior after scenario migration + reviewer: e2e-maintainers + approved_at: "2026-05-13" + - legacy: shields up succeeded + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "shields up did not report success: ${SHIELDS_UP_OUTPUT}" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Config file has restrictive permissions after shields up (${PERMS_UP}) + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "Config file should be locked after shields up: ${PERMS_UP}" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Config file ownership changed to root:root + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "Config file ownership not changed to root:root: ${OWNER_UP}" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Config file is read-only for sandbox user (shields UP) + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Config file write rejected by OS (shields UP) + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "Config file should be immutable but sandbox could write: ${WRITE_RESULT}" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Workspace state is read-only for sandbox user (shields UP) + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Workspace write rejected by OS (shields UP) + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "Workspace should be locked after shields up: ${WORKSPACE_WRITE_RESULT}" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: config get returns JSON + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "config get did not return JSON: ${CONFIG_GET_OUTPUT}" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: config get leaks credentials + status: mapped + id: legacy.shields.config.config.get.leaks.credentials + - legacy: config get output has no credential leaks + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: config get should strip gateway section + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: config get strips gateway section + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: config get --key dotpath works + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: shields status reports UP + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "shields status should show UP: ${STATUS_OUTPUT}" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: shields down succeeded + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "shields down did not report success: ${SHIELDS_DOWN_OUTPUT}" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Config file mode is 660 (restored to mutable default) + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "Config file should be mode 660 after shields down: ${PERMS_DOWN}" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Config file owned by sandbox:sandbox after shields down + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "Config file should be owned by sandbox:sandbox: ${PERMS_DOWN}" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Config directory mode is 2770 (restored to mutable default) + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "Config directory should be mode 2770 after shields down: ${DIR_PERMS_DOWN}" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Config directory owned by sandbox:sandbox after shields down + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "Config directory should be owned by sandbox:sandbox: ${DIR_PERMS_DOWN}" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Workspace state is writable again after shields down + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "Workspace should be writable after shields down: ${WORKSPACE_DOWN_RESULT}" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: shields status reports DOWN + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "shields status should show DOWN: ${STATUS_DOWN}" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: shields status shows reason + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "shields status should show reason: ${STATUS_DOWN}" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: shields status shows timeout remaining + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: shields up restored for audit trail test + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "Failed to restore shields up before audit phase: ${RESTORE_UP_OUTPUT}" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Audit has ≥2 shields_up entries (got ${UP_COUNT}) + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Expected ≥2 shields_up audit entries, got ${UP_COUNT} + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Audit has ≥1 shields_down entries (got ${DOWN_COUNT}) + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Expected ≥1 shields_down audit entries, got ${DOWN_COUNT} + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Audit trail contains credentials + status: mapped + id: legacy.shields.config.audit.trail.contains.credentials + - legacy: Audit trail is credential-free + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: All audit entries are valid JSON + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: ${INVALID_JSON} audit entries are invalid JSON + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "Audit file not found: $AUDIT_FILE" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: shields down with 10s timeout + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "shields should be DOWN: ${STATUS_TIMER}" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Auto-restore timer re-locked config after timeout + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Auto-restore timer did not re-lock within 60s + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Config locked after auto-restore (${PERMS_TIMER}) + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "Config should be locked after auto-restore, got: ${PERMS_TIMER}" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Double shields-up rejected + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "Double shields-up should be rejected: ${DOUBLE_UP}" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "Cleanup: shields down" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Double shields-down rejected + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "Double shields-down should be rejected: ${DOUBLE_DOWN}" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Sandbox destroyed + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + test-skill-agent-e2e.sh: + scenario: ubuntu-repo-cloud-openclaw + status: migrated + bucket: final-security-policy-platform-misc + assertions: + - legacy: Docker is not running + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: Docker daemon + - legacy: Docker is running + status: mapped + id: legacy.skill.agent.e2e.docker.is.running + - legacy: NVIDIA_API_KEY not set or invalid + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: NVIDIA_API_KEY secret and network egress + - legacy: NVIDIA_API_KEY is set + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: NVIDIA_API_KEY secret and network egress + - legacy: Could not cd to repo root + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: install.sh failed (exit $install_exit) + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: NemoClaw installed + status: mapped + id: legacy.skill.agent.e2e.nemoclaw.installed + - legacy: nemoclaw not on PATH + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: openshell not on PATH + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: CLIs on PATH + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Failed to inject ${SKILL_ID} + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: ${SKILL_ID} injected and queryable + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Agent returned ${VERIFY_PHRASE} (attempt ${attempt}/${MAX_ATTEMPTS}) + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Agent returned ${VERIFY_PHRASE} via fuzzy match (attempt ${attempt}/${MAX_ATTEMPTS}) + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: $last_fail + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + test-snapshot-commands.sh: + scenario: ubuntu-repo-cloud-openclaw + status: migrated + bucket: lifecycle + assertions: + - legacy: NVIDIA_API_KEY is required + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: NVIDIA_API_KEY secret and network egress + - legacy: NEMOCLAW_NON_INTERACTIVE=1 is required + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: nemoclaw not found on PATH after install + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: openshell not found on PATH after install + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: NemoClaw installed + status: mapped + id: legacy.snapshot.commands.nemoclaw.installed + - legacy: Failed to write marker file + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "Marker verification failed: got '${VERIFY}'" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Marker file written + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "snapshot create exited with code $_CAPTURE_RC: ${SNAPSHOT_OUTPUT}" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: snapshot create succeeded + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "snapshot create did not report success: ${SNAPSHOT_OUTPUT}" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "snapshot list exited with code $_CAPTURE_RC: ${LIST_OUTPUT}" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: snapshot list shows snapshots + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "snapshot list shows no snapshots: ${LIST_OUTPUT}" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "Failed to parse a snapshot timestamp from list output: ${LIST_OUTPUT}" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Failed to modify sandbox state + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "First marker should be deleted but got: ${GONE}" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "Second snapshot create failed (code $_CAPTURE_RC): ${_SECOND_SNAP}" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: State modified, second snapshot created + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Failed to perturb sandbox before latest restore + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "snapshot restore exited with code $_CAPTURE_RC: ${RESTORE_OUTPUT}" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "snapshot restore did not report success: ${RESTORE_OUTPUT}" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "Latest restore did not recover the second marker: ${SECOND_CHECK}" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Latest snapshot restored expected state + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "targeted snapshot restore exited with code $_CAPTURE_RC: ${TARGETED_OUTPUT}" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "targeted snapshot restore did not report success: ${TARGETED_OUTPUT}" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "First snapshot did not restore the original marker: ${FIRST_CHECK}" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: First snapshot should not contain the second marker + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: First snapshot restored expected state + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: No credentials in snapshot directories + status: mapped + id: legacy.snapshot.commands.no.credentials.in.snapshot.directories + - legacy: "Credentials found: $CRED_LEAKS" + status: mapped + id: legacy.snapshot.commands.credentials.found.cred.leaks + - legacy: "Backup directory missing: $BACKUP_DIR" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "snapshot help exited with code $_CAPTURE_RC: ${HELP_OUTPUT}" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: snapshot help shows create/list/restore + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "snapshot help incomplete: ${HELP_OUTPUT}" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + test-spark-install.sh: + scenario: ubuntu-repo-cloud-openclaw + status: migrated + bucket: final-security-policy-platform-misc + assertions: + - legacy: Running on Linux + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: DGX Spark Linux runner + - legacy: >- + This script is for DGX Spark (Linux). On other OS use Vitest: NEMOCLAW_E2E_SPARK_INSTALL=1 --project + spark-install-cli (skipped there on non-Linux). + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: DGX Spark Linux runner + - legacy: Docker is running + status: mapped + id: legacy.spark.install.docker.is.running + - legacy: Docker is not running + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: DGX Spark Linux runner + - legacy: NEMOCLAW_NON_INTERACTIVE=1 + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: DGX Spark Linux runner + - legacy: NEMOCLAW_NON_INTERACTIVE=1 is required + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: DGX Spark Linux runner + - legacy: NEMOCLAW_ACCEPT_THIRD_PARTY_SOFTWARE=1 + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: DGX Spark Linux runner + - legacy: NEMOCLAW_ACCEPT_THIRD_PARTY_SOFTWARE=1 is required for non-interactive install + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: DGX Spark Linux runner + - legacy: "cd to repo: $REPO" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: DGX Spark Linux runner + - legacy: Using generic installer flow without Spark-specific setup + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: DGX Spark Linux runner + - legacy: "install failed (exit $install_exit); last 80 lines of log:" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: DGX Spark Linux runner + - legacy: install completed (exit 0) + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: DGX Spark Linux runner + - legacy: nemoclaw on PATH ($(command -v nemoclaw)) + status: mapped + id: legacy.spark.install.nemoclaw.on.path.command.v.nemoclaw + - legacy: nemoclaw not on PATH + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: DGX Spark Linux runner + - legacy: openshell on PATH + status: mapped + id: legacy.spark.install.openshell.on.path + - legacy: openshell not on PATH + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: DGX Spark Linux runner + - legacy: nemoclaw --help exits 0 + status: mapped + id: legacy.spark.install.nemoclaw.help.exits.0 + - legacy: nemoclaw --help failed + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: DGX Spark Linux runner + test-telegram-injection.sh: + scenario: ubuntu-repo-cloud-openclaw + status: migrated + bucket: providers-messaging + assertions: + - legacy: NVIDIA_API_KEY not set + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Telegram test credentials + - legacy: NVIDIA_API_KEY is set + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Telegram test credentials + - legacy: openshell not found on PATH + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Telegram test credentials + - legacy: openshell found + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Telegram test credentials + - legacy: nemoclaw not found on PATH + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Telegram test credentials + - legacy: nemoclaw found + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Telegram test credentials + - legacy: Sandbox '${SANDBOX_NAME}' is running + status: mapped + id: legacy.telegram.injection.sandbox.sandbox.name.is.running + - legacy: Sandbox '${SANDBOX_NAME}' not running — run test-full-e2e.sh first + status: mapped + id: legacy.telegram.injection.sandbox.sandbox.name.not.running.run.test.full.e2e.sh.first + - legacy: "T1: \\$(command) substitution was NOT executed" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Telegram test credentials + - legacy: "T1: \\$(command) substitution was EXECUTED — injection successful!" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Telegram test credentials + - legacy: "T2: Backtick command substitution was NOT executed" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Telegram test credentials + - legacy: "T2: Backtick command substitution was EXECUTED — injection successful!" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Telegram test credentials + - legacy: "T3: Single-quote breakout was NOT exploitable" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Telegram test credentials + - legacy: "T3: Single-quote breakout was EXECUTED — injection successful!" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Telegram test credentials + - legacy: "T4: \\${NVIDIA_API_KEY} expanded to actual key value — secret leaked!" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Telegram test credentials + - legacy: "T4: \\${NVIDIA_API_KEY} treated as literal string (not expanded)" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Telegram test credentials + - legacy: "T4: \\${NVIDIA_API_KEY} did not expand to key value (result: ${t4_result:0:100})" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Telegram test credentials + - legacy: "T5: NVIDIA_API_KEY found in HOST process table" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Telegram test credentials + - legacy: "T5: NVIDIA_API_KEY found in SANDBOX process table" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Telegram test credentials + - legacy: "T5: API key not visible in process tables (host or sandbox)" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Telegram test credentials + - legacy: "T6: SANDBOX_NAME 'foo;rm -rf /' rejected by validateName()" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Telegram test credentials + - legacy: "T6: SANDBOX_NAME 'foo;rm -rf /' was ACCEPTED — validation bypass!" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Telegram test credentials + - legacy: "T7: SANDBOX_NAME '--help' rejected (option injection prevented)" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Telegram test credentials + - legacy: "T7: SANDBOX_NAME '--help' was ACCEPTED — option injection possible!" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Telegram test credentials + - legacy: "T6/T7 extra: SANDBOX_NAME '${invalid_name}' correctly rejected" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Telegram test credentials + - legacy: "T6/T7 extra: SANDBOX_NAME '${invalid_name}' was ACCEPTED" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Telegram test credentials + - legacy: "T8: Normal message passed through correctly" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Telegram test credentials + - legacy: "T8: Normal message was not echoed back correctly (got: ${t8_result:0:200})" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Telegram test credentials + - legacy: "T8b: Message with special characters processed without error" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Telegram test credentials + - legacy: "T8b: Message with special characters caused empty/error response" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Telegram test credentials + test-token-rotation.sh: + scenario: ubuntu-repo-cloud-openclaw + status: migrated + bucket: providers-messaging + assertions: + - legacy: install.sh completed (exit 0) + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: install.sh failed (exit $install_exit) + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: openshell not found on PATH after install + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: openshell installed ($(openshell --version 2>&1 || echo unknown)) + status: mapped + id: legacy.token.rotation.openshell.installed.openshell.version.2.1.echo.unknown + - legacy: nemoclaw not found on PATH after install + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: nemoclaw installed at $(command -v nemoclaw) + status: mapped + id: legacy.token.rotation.nemoclaw.installed.at.command.v.nemoclaw + - legacy: Sandbox $SANDBOX_NAME created and running + status: mapped + id: legacy.token.rotation.sandbox.sandbox.name.created.and.running + - legacy: Sandbox $SANDBOX_NAME not running after first onboard + status: mapped + id: legacy.token.rotation.sandbox.sandbox.name.not.running.after.first.onboard + - legacy: Provider ${SANDBOX_NAME}-telegram-bridge exists + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Telegram test credentials + - legacy: Provider ${SANDBOX_NAME}-telegram-bridge not found + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Telegram test credentials + - legacy: Provider ${SANDBOX_NAME}-discord-bridge exists + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Discord test credentials + - legacy: Provider ${SANDBOX_NAME}-discord-bridge not found + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Discord test credentials + - legacy: Provider ${SANDBOX_NAME}-slack-bridge exists + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Slack test credentials + - legacy: Provider ${SANDBOX_NAME}-slack-bridge not found + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Slack test credentials + - legacy: Provider ${SANDBOX_NAME}-slack-app exists + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Slack test credentials + - legacy: Provider ${SANDBOX_NAME}-slack-app not found + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Slack test credentials + - legacy: Telegram credential hash stored for $SANDBOX_NAME + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Telegram test credentials + - legacy: Telegram credential hash not found for $SANDBOX_NAME in registry + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Telegram test credentials + - legacy: Discord credential hash stored for $SANDBOX_NAME + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Discord test credentials + - legacy: Discord credential hash not found for $SANDBOX_NAME in registry + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Discord test credentials + - legacy: Slack bot credential hash stored for $SANDBOX_NAME + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Slack test credentials + - legacy: Slack bot credential hash not found for $SANDBOX_NAME in registry + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Slack test credentials + - legacy: Slack app credential hash stored for $SANDBOX_NAME + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Slack test credentials + - legacy: Slack app credential hash not found for $SANDBOX_NAME in registry + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Slack test credentials + - legacy: Phase 2 onboard failed (exit $onboard_exit) + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Credential rotation detected + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Credential rotation not detected in onboard output + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Rotation message identifies telegram-bridge + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Telegram test credentials + - legacy: Rotation message did not identify telegram-bridge + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Telegram test credentials + - legacy: Rotation message unexpectedly named discord-bridge (Discord token did not change) + status: retired + reason: legacy assertion is obsolete or negative cleanup behavior after scenario migration + reviewer: e2e-maintainers + approved_at: "2026-05-13" + - legacy: Rotation message did not name discord-bridge (Discord unchanged) + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Discord test credentials + - legacy: Rotation message unexpectedly named slack-bridge/slack-app (Slack tokens did not change) + status: retired + reason: legacy assertion is obsolete or negative cleanup behavior after scenario migration + reviewer: e2e-maintainers + approved_at: "2026-05-13" + - legacy: Rotation message did not name slack-bridge or slack-app (Slack unchanged) + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Slack test credentials + - legacy: Sandbox rebuild triggered by rotation + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Sandbox rebuild not triggered + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Sandbox running after Telegram rotation + status: mapped + id: legacy.token.rotation.sandbox.running.after.telegram.rotation + - legacy: Sandbox not running after Telegram rotation + status: mapped + id: legacy.token.rotation.sandbox.not.running.after.telegram.rotation + - legacy: Phase 3 onboard failed (exit $onboard_exit) + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Sandbox reused when tokens unchanged + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Sandbox was not reused (unexpected rebuild) + status: retired + reason: legacy assertion is obsolete or negative cleanup behavior after scenario migration + reviewer: e2e-maintainers + approved_at: "2026-05-13" + - legacy: Phase 4 onboard failed (exit $onboard_exit) + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Credential rotation detected + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Credential rotation not detected in onboard output + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Rotation message identifies discord-bridge + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Discord test credentials + - legacy: Rotation message did not identify discord-bridge + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Discord test credentials + - legacy: Rotation message unexpectedly named telegram-bridge (Telegram token did not change) + status: retired + reason: legacy assertion is obsolete or negative cleanup behavior after scenario migration + reviewer: e2e-maintainers + approved_at: "2026-05-13" + - legacy: Rotation message did not name telegram-bridge (Telegram unchanged) + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Telegram test credentials + - legacy: Rotation message unexpectedly named slack-bridge/slack-app (Slack tokens did not change) + status: retired + reason: legacy assertion is obsolete or negative cleanup behavior after scenario migration + reviewer: e2e-maintainers + approved_at: "2026-05-13" + - legacy: Rotation message did not name slack-bridge or slack-app (Slack unchanged) + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Slack test credentials + - legacy: Sandbox rebuild triggered by rotation + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Sandbox rebuild not triggered + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Sandbox running after Discord rotation + status: mapped + id: legacy.token.rotation.sandbox.running.after.discord.rotation + - legacy: Sandbox not running after Discord rotation + status: mapped + id: legacy.token.rotation.sandbox.not.running.after.discord.rotation + - legacy: Phase 5 onboard failed (exit $onboard_exit) + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Sandbox reused when tokens unchanged + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Sandbox was not reused (unexpected rebuild) + status: retired + reason: legacy assertion is obsolete or negative cleanup behavior after scenario migration + reviewer: e2e-maintainers + approved_at: "2026-05-13" + - legacy: Phase 6 onboard failed (exit $onboard_exit) + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Credential rotation detected + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Credential rotation not detected in onboard output + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Rotation message identifies slack-bridge + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Slack test credentials + - legacy: Rotation message did not identify slack-bridge + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Slack test credentials + - legacy: Rotation message identifies slack-app + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Slack test credentials + - legacy: Rotation message did not identify slack-app + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Slack test credentials + - legacy: Rotation message unexpectedly named telegram-bridge (Telegram token did not change) + status: retired + reason: legacy assertion is obsolete or negative cleanup behavior after scenario migration + reviewer: e2e-maintainers + approved_at: "2026-05-13" + - legacy: Rotation message did not name telegram-bridge (Telegram unchanged) + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Telegram test credentials + - legacy: Rotation message unexpectedly named discord-bridge (Discord token did not change) + status: retired + reason: legacy assertion is obsolete or negative cleanup behavior after scenario migration + reviewer: e2e-maintainers + approved_at: "2026-05-13" + - legacy: Rotation message did not name discord-bridge (Discord unchanged) + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Discord test credentials + - legacy: Sandbox rebuild triggered by Slack rotation + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: Slack test credentials + - legacy: Sandbox rebuild not triggered + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Sandbox running after Slack rotation + status: mapped + id: legacy.token.rotation.sandbox.running.after.slack.rotation + - legacy: Sandbox not running after Slack rotation + status: mapped + id: legacy.token.rotation.sandbox.not.running.after.slack.rotation + - legacy: Phase 7 onboard failed (exit $onboard_exit) + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Sandbox reused when tokens unchanged + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Sandbox was not reused (unexpected rebuild) + status: retired + reason: legacy assertion is obsolete or negative cleanup behavior after scenario migration + reviewer: e2e-maintainers + approved_at: "2026-05-13" + test-upgrade-stale-sandbox.sh: + scenario: ubuntu-repo-cloud-openclaw + status: migrated + bucket: rebuild-runtime + assertions: + - legacy: NVIDIA_API_KEY is required + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + secret_requirement: NVIDIA_API_KEY secret and network egress + - legacy: NEMOCLAW_NON_INTERACTIVE=1 is required + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: nemoclaw not found on PATH after install + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: openshell not found on PATH after install + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: NemoClaw installed + status: mapped + id: legacy.upgrade.stale.sandbox.nemoclaw.installed + - legacy: Failed to build old base image + status: retired + reason: legacy assertion is obsolete or negative cleanup behavior after scenario migration + reviewer: e2e-maintainers + approved_at: "2026-05-13" + - legacy: Old base image built (OpenClaw ${OLD_OPENCLAW_VERSION}) + status: retired + reason: legacy assertion is obsolete or negative cleanup behavior after scenario migration + reviewer: e2e-maintainers + approved_at: "2026-05-13" + - legacy: Sandbox did not become Ready + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Failed to read OpenClaw version from old sandbox + status: retired + reason: legacy assertion is obsolete or negative cleanup behavior after scenario migration + reviewer: e2e-maintainers + approved_at: "2026-05-13" + - legacy: Old sandbox created (OpenClaw ${OLD_OPENCLAW_VERSION}) + status: mapped + id: legacy.upgrade.stale.sandbox.old.sandbox.created.openclaw.old.openclaw.version + - legacy: Sandbox registered with agentVersion=${OLD_OPENCLAW_VERSION} + status: retired + reason: legacy assertion is obsolete or negative cleanup behavior after scenario migration + reviewer: e2e-maintainers + approved_at: "2026-05-13" + - legacy: "Phase 5: upgrade-sandboxes --check detected stale sandbox" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: upgrade-sandboxes --check says all up to date — stale sandbox NOT detected (#1904) + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: upgrade-sandboxes --check produced unexpected output + status: retired + reason: legacy assertion is obsolete or negative cleanup behavior after scenario migration + reviewer: e2e-maintainers + approved_at: "2026-05-13" + - legacy: Sandbox rebuild failed + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: Failed to read OpenClaw version after rebuild + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "Sandbox still running old OpenClaw ${OLD_OPENCLAW_VERSION} after rebuild — #1904 NOT fixed" + status: mapped + id: >- + legacy.upgrade.stale.sandbox.sandbox.still.running.old.openclaw.old.openclaw.version.after.rebuild.1904.not.fixed + - legacy: "Phase 6: Sandbox upgraded from OpenClaw ${OLD_OPENCLAW_VERSION} to ${NEW_OPENCLAW_VERSION}" + status: retired + reason: legacy assertion is obsolete or negative cleanup behavior after scenario migration + reviewer: e2e-maintainers + approved_at: "2026-05-13" + - legacy: "Phase 7: All sandboxes up to date after rebuild" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs + - legacy: "Phase 7: upgrade-sandboxes --check did not report 'up to date' after rebuild" + status: deferred + reason: live legacy behavior requires non-deterministic infrastructure; retained for bucket parity tracking + owner: e2e-maintainers + runner_requirement: sandbox runner with NemoClaw/OpenShell CLIs diff --git a/test/e2e/nemoclaw_scenarios/expected-states.yaml b/test/e2e/nemoclaw_scenarios/expected-states.yaml new file mode 100644 index 0000000000..eed1ee994a --- /dev/null +++ b/test/e2e/nemoclaw_scenarios/expected-states.yaml @@ -0,0 +1,98 @@ +# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +# +# Expected state configs. +# +# Each entry describes the observable contract that must be true after +# setup/install/onboarding completes for a given scenario. Expected states +# are reusable: multiple setup scenarios can resolve to the same expected +# state when they produce the same completed environment. +# +# Schema keys are intentionally small and structural. Deeper behavior lives +# in suites; expected states answer "is the environment in the shape we +# expect?" not "does every feature still work?". +# +# Negative/preflight expected states (e.g. `preflight-failure-no-sandbox`) +# are introduced in Phase 9 alongside their first consuming scenario. + +expected_states: + cloud-openclaw-ready: + cli: + installed: true + gateway: + expected: present + health: healthy + sandbox: + expected: present + status: running + agent: openclaw + inference: + expected: available + provider: nvidia + route: inference-local + mode: gateway-routed + credentials: + expected: present + storage: gateway-managed + security: + policy_engine: supported + shields: supported + + cloud-hermes-ready: + cli: + installed: true + gateway: + expected: present + health: healthy + sandbox: + expected: present + status: running + agent: hermes + inference: + expected: available + provider: nvidia + route: inference-local + mode: gateway-routed + credentials: + expected: present + storage: gateway-managed + security: + policy_engine: supported + shields: supported + + local-ollama-openclaw-ready: + cli: + installed: true + gateway: + expected: present + health: healthy + sandbox: + expected: present + status: running + agent: openclaw + inference: + expected: available + provider: ollama + route: inference-local + mode: gateway-routed + credentials: + expected: present + storage: gateway-managed + security: + policy_engine: supported + shields: supported + + # Negative preflight state. Introduced alongside its first consumer, + # `ubuntu-no-docker-preflight-negative` (deferred from Phase 1). + # Setup is expected to fail, and the runner must confirm that no + # gateway or sandbox ghost state was left behind. + preflight-failure-no-sandbox: + cli: + installed: true + gateway: + expected: absent + sandbox: + expected: absent + failure: + expected: true + stage: preflight diff --git a/test/e2e/nemoclaw_scenarios/fixtures/_fake-http-stub.sh b/test/e2e/nemoclaw_scenarios/fixtures/_fake-http-stub.sh new file mode 100755 index 0000000000..0c0fc4848a --- /dev/null +++ b/test/e2e/nemoclaw_scenarios/fixtures/_fake-http-stub.sh @@ -0,0 +1,90 @@ +#!/usr/bin/env bash +# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +# +# Shared primitive for fake HTTP stub fixtures. +# +# Spawns a small Node.js HTTP server that answers any path with 200/JSON +# and echoes the request shape. Used by `fake-telegram.sh`, `fake-discord.sh`, +# and `fake-slack.sh` to avoid duplicating the listener harness. +# +# Function: +# _fake_http_stub_start +# Writes the spawned server's PID into $pid-var and port into $port-var +# (via `printf -v`). Exports ${provider-label-upper}_PORT and _PID. +# _fake_http_stub_stop +# Kills the stored PID. Idempotent. + +_fake_http_stub_start() { + local label="${1:?provider label required}" + local pid_var="${2:?pid var name required}" + local port_var="${3:?port var name required}" + + local tmp_port + tmp_port="$(mktemp)" + + node -e ' + const http = require("http"); + const fs = require("fs"); + const portFile = process.argv[1]; + const label = process.argv[2]; + const server = http.createServer((req, res) => { + let body = ""; + req.setEncoding("utf8"); + req.on("data", (d) => { body += d; }); + req.on("end", () => { + res.writeHead(200, { "Content-Type": "application/json" }); + res.end(JSON.stringify({ + ok: true, + provider: label, + method: req.method, + url: req.url, + body, + })); + }); + }); + server.listen(0, "127.0.0.1", () => { + fs.writeFileSync(portFile, String(server.address().port)); + }); + process.on("SIGTERM", () => server.close(() => process.exit(0))); + process.on("SIGINT", () => server.close(() => process.exit(0))); + ' "${tmp_port}" "${label}" & + local pid=$! + + local i + for i in $(seq 1 50); do + [[ -s "${tmp_port}" ]] && break + : "${i}" # quiet unused-var check + sleep 0.1 + done + if [[ ! -s "${tmp_port}" ]]; then + echo "_fake_http_stub_start: ${label} server failed to report port" >&2 + kill "${pid}" 2>/dev/null || true + rm -f "${tmp_port}" + return 1 + fi + local port + port="$(cat "${tmp_port}")" + rm -f "${tmp_port}" + + # shellcheck disable=SC2229 # dynamic name is the point + printf -v "${pid_var}" '%s' "${pid}" + printf -v "${port_var}" '%s' "${port}" + + local upper + upper="$(printf '%s' "${label}" | tr '[:lower:]' '[:upper:]')" + export "FAKE_${upper}_PORT=${port}" + export "FAKE_${upper}_PID=${pid}" + export "FAKE_${upper}_URL=http://127.0.0.1:${port}" +} + +_fake_http_stub_stop() { + local pid_var="${1:?pid var name required}" + local pid="${!pid_var:-}" + if [[ -n "${pid}" ]]; then + kill "${pid}" 2>/dev/null || true + wait "${pid}" 2>/dev/null || true + fi + # shellcheck disable=SC2229 + printf -v "${pid_var}" '%s' "" +} diff --git a/test/e2e/nemoclaw_scenarios/fixtures/fake-discord.sh b/test/e2e/nemoclaw_scenarios/fixtures/fake-discord.sh new file mode 100755 index 0000000000..dee5f1cca5 --- /dev/null +++ b/test/e2e/nemoclaw_scenarios/fixtures/fake-discord.sh @@ -0,0 +1,21 @@ +#!/usr/bin/env bash +# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +# +# Local Discord API stub. Removes dependency on discord.com in CI. +# See _fake-http-stub.sh for the shared harness contract. + +_E2E_FAKE_DC_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +# shellcheck source=_fake-http-stub.sh +. "${_E2E_FAKE_DC_DIR}/_fake-http-stub.sh" + +_E2E_FAKE_DISCORD_PID="" + +fake_discord_start() { + _fake_http_stub_start discord _E2E_FAKE_DISCORD_PID FAKE_DISCORD_PORT +} + +fake_discord_stop() { + _fake_http_stub_stop _E2E_FAKE_DISCORD_PID + unset FAKE_DISCORD_PORT FAKE_DISCORD_PID FAKE_DISCORD_URL +} diff --git a/test/e2e/nemoclaw_scenarios/fixtures/fake-openai.sh b/test/e2e/nemoclaw_scenarios/fixtures/fake-openai.sh new file mode 100755 index 0000000000..ed035b8aa0 --- /dev/null +++ b/test/e2e/nemoclaw_scenarios/fixtures/fake-openai.sh @@ -0,0 +1,109 @@ +#!/usr/bin/env bash +# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +# +# Fake OpenAI-compatible endpoint fixture. +# +# Spawns a tiny Node.js HTTP server that responds to `/v1/chat/completions` +# and `/v1/models` with deterministic stub payloads. Removes dependency on +# real NVIDIA / OpenAI endpoints for parity comparisons and fast-mode +# inference probes (Risk #2 mitigation in the migration spec). +# +# Follows the same inline-Node pattern as test-messaging-providers.sh: +# a `bash` wrapper that spawns `node -e 'http.createServer(...)'` and +# exposes the chosen port on an `_PORT` env var. +# +# Contract: +# fake_openai_start — start server, block until ready, export +# FAKE_OPENAI_PORT and FAKE_OPENAI_PID. If +# E2E_CONTEXT_DIR is set, also records these in +# context.env so later teardown can find them. +# fake_openai_stop — stop the server. Idempotent. + +_E2E_FAKE_OPENAI_PID="" +_E2E_FAKE_OPENAI_PORT="" + +fake_openai_start() { + # Pick an ephemeral port deterministically via the server itself. + local tmp_port + tmp_port="$(mktemp)" + # shellcheck disable=SC2064 + trap "rm -f '${tmp_port}'" RETURN + + node -e ' + const http = require("http"); + const fs = require("fs"); + const portFile = process.argv[1]; + const server = http.createServer((req, res) => { + let body = ""; + req.setEncoding("utf8"); + req.on("data", (d) => { body += d; }); + req.on("end", () => { + if (req.url === "/v1/models") { + res.writeHead(200, { "Content-Type": "application/json" }); + res.end(JSON.stringify({ + object: "list", + data: [{ id: "fake-model", object: "model" }], + })); + return; + } + if (req.url === "/v1/chat/completions") { + res.writeHead(200, { "Content-Type": "application/json" }); + res.end(JSON.stringify({ + id: "chatcmpl-fake", + object: "chat.completion", + choices: [{ + index: 0, + message: { role: "assistant", content: "pong" }, + finish_reason: "stop", + }], + usage: { prompt_tokens: 1, completion_tokens: 1, total_tokens: 2 }, + })); + return; + } + res.writeHead(404); + res.end(); + }); + }); + server.listen(0, "127.0.0.1", () => { + fs.writeFileSync(portFile, String(server.address().port)); + }); + process.on("SIGTERM", () => server.close(() => process.exit(0))); + process.on("SIGINT", () => server.close(() => process.exit(0))); + ' "${tmp_port}" & + _E2E_FAKE_OPENAI_PID=$! + + # Wait up to ~5s for the server to write its port. + local i + for i in $(seq 1 50); do + if [[ -s "${tmp_port}" ]]; then + break + fi + : "${i}" # quiet unused-var check + sleep 0.1 + done + if [[ ! -s "${tmp_port}" ]]; then + echo "fake_openai_start: server failed to report port" >&2 + kill "${_E2E_FAKE_OPENAI_PID}" 2>/dev/null || true + return 1 + fi + _E2E_FAKE_OPENAI_PORT="$(cat "${tmp_port}")" + export FAKE_OPENAI_PORT="${_E2E_FAKE_OPENAI_PORT}" + export FAKE_OPENAI_PID="${_E2E_FAKE_OPENAI_PID}" + export FAKE_OPENAI_URL="http://127.0.0.1:${_E2E_FAKE_OPENAI_PORT}" + if [[ -n "${E2E_CONTEXT_DIR:-}" && -d "${E2E_CONTEXT_DIR}" ]]; then + printf 'FAKE_OPENAI_PORT=%s\n' "${_E2E_FAKE_OPENAI_PORT}" >>"${E2E_CONTEXT_DIR}/context.env" 2>/dev/null || true + printf 'FAKE_OPENAI_PID=%s\n' "${_E2E_FAKE_OPENAI_PID}" >>"${E2E_CONTEXT_DIR}/context.env" 2>/dev/null || true + fi +} + +fake_openai_stop() { + local pid="${FAKE_OPENAI_PID:-${_E2E_FAKE_OPENAI_PID:-}}" + if [[ -n "${pid}" ]]; then + kill "${pid}" 2>/dev/null || true + wait "${pid}" 2>/dev/null || true + fi + unset FAKE_OPENAI_PORT FAKE_OPENAI_PID FAKE_OPENAI_URL + _E2E_FAKE_OPENAI_PID="" + _E2E_FAKE_OPENAI_PORT="" +} diff --git a/test/e2e/nemoclaw_scenarios/fixtures/fake-slack.sh b/test/e2e/nemoclaw_scenarios/fixtures/fake-slack.sh new file mode 100755 index 0000000000..34eac39f32 --- /dev/null +++ b/test/e2e/nemoclaw_scenarios/fixtures/fake-slack.sh @@ -0,0 +1,21 @@ +#!/usr/bin/env bash +# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +# +# Local Slack API stub. Removes dependency on slack.com in CI. +# See _fake-http-stub.sh for the shared harness contract. + +_E2E_FAKE_SL_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +# shellcheck source=_fake-http-stub.sh +. "${_E2E_FAKE_SL_DIR}/_fake-http-stub.sh" + +_E2E_FAKE_SLACK_PID="" + +fake_slack_start() { + _fake_http_stub_start slack _E2E_FAKE_SLACK_PID FAKE_SLACK_PORT +} + +fake_slack_stop() { + _fake_http_stub_stop _E2E_FAKE_SLACK_PID + unset FAKE_SLACK_PORT FAKE_SLACK_PID FAKE_SLACK_URL +} diff --git a/test/e2e/nemoclaw_scenarios/fixtures/fake-telegram.sh b/test/e2e/nemoclaw_scenarios/fixtures/fake-telegram.sh new file mode 100755 index 0000000000..ca453d6685 --- /dev/null +++ b/test/e2e/nemoclaw_scenarios/fixtures/fake-telegram.sh @@ -0,0 +1,21 @@ +#!/usr/bin/env bash +# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +# +# Local Telegram API stub. Removes dependency on api.telegram.org in CI. +# See _fake-http-stub.sh for the shared harness contract. + +_E2E_FAKE_TG_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +# shellcheck source=_fake-http-stub.sh +. "${_E2E_FAKE_TG_DIR}/_fake-http-stub.sh" + +_E2E_FAKE_TELEGRAM_PID="" + +fake_telegram_start() { + _fake_http_stub_start telegram _E2E_FAKE_TELEGRAM_PID FAKE_TELEGRAM_PORT +} + +fake_telegram_stop() { + _fake_http_stub_stop _E2E_FAKE_TELEGRAM_PID + unset FAKE_TELEGRAM_PORT FAKE_TELEGRAM_PID FAKE_TELEGRAM_URL +} diff --git a/test/e2e/nemoclaw_scenarios/fixtures/older-base-image.sh b/test/e2e/nemoclaw_scenarios/fixtures/older-base-image.sh new file mode 100755 index 0000000000..3d49c03116 --- /dev/null +++ b/test/e2e/nemoclaw_scenarios/fixtures/older-base-image.sh @@ -0,0 +1,74 @@ +#!/usr/bin/env bash +# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +# +# Older-base-image fixture. +# +# Absorbs reuse category #7 from the migration spec: three hand-rolled +# Docker-older-base-image patterns in `test-rebuild-openclaw.sh`, +# `test-rebuild-hermes.sh`, and `test-sandbox-rebuild.sh`. +# +# Contract: +# older_base_image_prepare [--registry ghcr.io/nvidia/nemoclaw] +# Writes a minimal Dockerfile to a temp location whose first line is +# `FROM :`, and prints the Dockerfile path on stdout. +# Honors E2E_DRY_RUN: skips the `docker pull` step (but still writes +# the Dockerfile, which is what callers inspect). +# older_base_image_cleanup +# Removes the generated Dockerfile and (if present) its build context. + +_E2E_OBI_LIB_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../../runtime/lib" && pwd)" +# shellcheck source=../../runtime/lib/env.sh +. "${_E2E_OBI_LIB_DIR}/env.sh" + +older_base_image_prepare() { + local tag="${1:?tag required}" + shift || true + local registry="ghcr.io/nvidia/nemoclaw" + while [[ $# -gt 0 ]]; do + case "$1" in + --registry) + registry="${2:?value required}" + shift 2 + ;; + *) + echo "older_base_image_prepare: unknown arg: $1" >&2 + return 2 + ;; + esac + done + + local dir + dir="$(mktemp -d)" + local dockerfile="${dir}/Dockerfile.older-base" + cat >"${dockerfile}" </dev/null 2>&1; then + docker pull "${registry}:${tag}" >&2 \ + || echo "older_base_image_prepare: docker pull failed (continuing; build may still succeed on cached layers)" >&2 + fi + fi + printf '%s\n' "${dockerfile}" +} + +older_base_image_cleanup() { + local dockerfile="${1:-}" + if [[ -z "${dockerfile}" || ! -f "${dockerfile}" ]]; then + return 0 + fi + local dir + dir="$(dirname "${dockerfile}")" + rm -f "${dockerfile}" + # Only remove the temp dir if it looks like one we created. + case "${dir}" in + /tmp/* | /var/folders/*) rm -rf "${dir}" ;; + esac +} diff --git a/test/e2e/nemoclaw_scenarios/helpers/emit-context-from-plan.sh b/test/e2e/nemoclaw_scenarios/helpers/emit-context-from-plan.sh new file mode 100755 index 0000000000..95a2915f48 --- /dev/null +++ b/test/e2e/nemoclaw_scenarios/helpers/emit-context-from-plan.sh @@ -0,0 +1,86 @@ +#!/usr/bin/env bash +# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +# +# Emit a normalized .e2e/context.env from a resolved plan.json. +# +# Usage: +# test/e2e/lib/emit-context-from-plan.sh +# +# The script reads the plan via `node --experimental-default-type=module` so +# it doesn't depend on jq being available on every runner. It then calls +# lib/context.sh helpers to append keys. + +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +_E2E_EMIT_RUNTIME_LIB="$(cd "${SCRIPT_DIR}/../../runtime/lib" && pwd)" +# shellcheck source=../../runtime/lib/context.sh +. "${_E2E_EMIT_RUNTIME_LIB}/context.sh" + +PLAN_JSON="${1:-}" +if [[ -z "${PLAN_JSON}" || ! -f "${PLAN_JSON}" ]]; then + echo "emit-context-from-plan: plan.json not found: ${PLAN_JSON}" >&2 + exit 2 +fi + +# Extract fields with node (already required by the resolver). +read_plan_value() { + local key="$1" + node -e " + const p = JSON.parse(require('fs').readFileSync(process.argv[1], 'utf8')); + const parts = process.argv[2].split('.'); + let cur = p; + for (const part of parts) { + if (cur == null) { cur = ''; break; } + cur = cur[part]; + } + process.stdout.write(cur == null ? '' : String(cur)); + " "${PLAN_JSON}" "${key}" +} + +SCENARIO_ID="$(read_plan_value scenario_id)" +if [[ -z "${SCENARIO_ID}" ]]; then + # Fail fast when the plan is missing its scenario id (CodeRabbit review + # item #5). Downstream helpers all index context by scenario and will + # silently misbehave if this is empty. + echo "emit-context-from-plan: plan.json is missing 'scenario_id': ${PLAN_JSON}" >&2 + exit 2 +fi +PLATFORM_OS="$(read_plan_value dimensions.platform.profile.os)" +EXECUTION_TARGET="$(read_plan_value dimensions.platform.profile.execution_target)" +INSTALL_METHOD="$(read_plan_value dimensions.install.profile.method)" +RUNTIME_ENGINE="$(read_plan_value dimensions.runtime.profile.container_engine)" +RUNTIME_DAEMON="$(read_plan_value dimensions.runtime.profile.container_daemon)" +ONBOARDING_PATH="$(read_plan_value dimensions.onboarding.profile.path)" +AGENT="$(read_plan_value dimensions.onboarding.profile.agent)" +PROVIDER="$(read_plan_value dimensions.onboarding.profile.provider)" +INFERENCE_ROUTE="$(read_plan_value dimensions.onboarding.profile.inference_route)" + +: "${PLATFORM_OS:=unknown}" +: "${EXECUTION_TARGET:=local}" +: "${INSTALL_METHOD:=unknown}" +: "${RUNTIME_ENGINE:=docker}" +: "${RUNTIME_DAEMON:=unknown}" +: "${ONBOARDING_PATH:=unknown}" +: "${AGENT:=unknown}" +: "${PROVIDER:=unknown}" +: "${INFERENCE_ROUTE:=inference-local}" + +e2e_context_set E2E_SCENARIO "${SCENARIO_ID}" +e2e_context_set E2E_PLATFORM_OS "${PLATFORM_OS}" +e2e_context_set E2E_EXECUTION_TARGET "${EXECUTION_TARGET}" +e2e_context_set E2E_INSTALL_METHOD "${INSTALL_METHOD}" +e2e_context_set E2E_CONTAINER_ENGINE "${RUNTIME_ENGINE}" +e2e_context_set E2E_CONTAINER_DAEMON "${RUNTIME_DAEMON}" +e2e_context_set E2E_ONBOARDING_PATH "${ONBOARDING_PATH}" +e2e_context_set E2E_AGENT "${AGENT}" +e2e_context_set E2E_PROVIDER "${PROVIDER}" +e2e_context_set E2E_INFERENCE_ROUTE "${INFERENCE_ROUTE}" + +# Sandbox name and gateway URL are normally discovered/assigned by +# onboarding. Seed them here so dry-run consumers can exercise the suite +# plumbing without live onboarding. Real onboarding helpers will overwrite +# these via e2e_context_set in later phases. +e2e_context_set E2E_SANDBOX_NAME "e2e-${SCENARIO_ID}" +e2e_context_set E2E_GATEWAY_URL "http://127.0.0.1:18789" diff --git a/test/e2e/nemoclaw_scenarios/install/dispatch.sh b/test/e2e/nemoclaw_scenarios/install/dispatch.sh new file mode 100755 index 0000000000..fd4c18fa0b --- /dev/null +++ b/test/e2e/nemoclaw_scenarios/install/dispatch.sh @@ -0,0 +1,57 @@ +#!/usr/bin/env bash +# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +# +# Install dispatcher. Routes by install-method / profile id to one of four +# split helpers (repo-current.sh, public-curl.sh, ollama.sh, +# launchable.sh). Honors E2E_DRY_RUN. +# +# Accepts both legacy install-method names (repo-checkout, +# curl-install-script) and the new profile-centric names used by +# scenarios.yaml (repo-current, public-installer, ollama, launchable). + +_E2E_INSTALL_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +_E2E_INSTALL_RUNTIME_LIB="$(cd "${_E2E_INSTALL_DIR}/../../runtime/lib" && pwd)" + +# shellcheck source=../../runtime/lib/env.sh +. "${_E2E_INSTALL_RUNTIME_LIB}/env.sh" +# shellcheck source=repo-current.sh +. "${_E2E_INSTALL_DIR}/repo-current.sh" +# shellcheck source=public-curl.sh +. "${_E2E_INSTALL_DIR}/public-curl.sh" +# shellcheck source=ollama.sh +. "${_E2E_INSTALL_DIR}/ollama.sh" +# shellcheck source=launchable.sh +. "${_E2E_INSTALL_DIR}/launchable.sh" + +e2e_install() { + local method="${1:-}" + if [[ -z "${method}" ]]; then + echo "e2e_install: missing install method" >&2 + return 2 + fi + e2e_env_trace "install:${method}" + case "${method}" in + repo-checkout | repo-current) + e2e_install_repo + ;; + curl-install-script | public-installer) + e2e_install_curl + ;; + ollama) + e2e_install_ollama + ;; + launchable) + e2e_install_launchable + ;; + *) + echo "e2e_install: unsupported install method: ${method}" >&2 + return 2 + ;; + esac +} + +# Legacy entrypoints kept for compatibility with callers that pre-dated +# the four-way split. They forward to the new helpers. +e2e_install_from_repo_checkout() { e2e_install_repo "$@"; } +e2e_install_from_public_curl() { e2e_install_curl "$@"; } diff --git a/test/e2e/nemoclaw_scenarios/install/helpers/install-path-refresh.sh b/test/e2e/nemoclaw_scenarios/install/helpers/install-path-refresh.sh new file mode 100755 index 0000000000..36c855bb1b --- /dev/null +++ b/test/e2e/nemoclaw_scenarios/install/helpers/install-path-refresh.sh @@ -0,0 +1,41 @@ +#!/usr/bin/env bash +# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +# +# Shared install-path-refresh helper for e2e test scripts. Meant to be sourced; +# the shebang and executable bit satisfy repo shell-file conventions. +# +# Why: install.sh places the openshell/nemoclaw binaries under ~/.local/bin. +# Sourcing ~/.bashrc on GitHub runners triggers nvm.sh, which rebuilds $PATH +# from scratch and drops ~/.local/bin — so a post-install `command -v +# nemoclaw` check fails with "nemoclaw not found". This helper centralises +# the recovery so every e2e test script applies the same guard. +# +# Usage: +# . "$(dirname "${BASH_SOURCE[0]}")/lib/install-path-refresh.sh" +# +# # After running install.sh, reload the shell profile and pick up the +# # binaries it installed: +# nemoclaw_refresh_install_env +# +# # If you only need to defensively ensure ~/.local/bin is on PATH: +# nemoclaw_ensure_local_bin_on_path + +# Prepend ~/.local/bin to PATH if it exists and isn't already there. +nemoclaw_ensure_local_bin_on_path() { + if [ -d "$HOME/.local/bin" ] && [[ ":$PATH:" != *":$HOME/.local/bin:"* ]]; then + export PATH="$HOME/.local/bin:$PATH" + fi +} + +# Source ~/.bashrc (best-effort) and then ensure ~/.local/bin is on PATH. +# Needed after running install.sh because nvm.sh (loaded via .bashrc) rebuilds +# PATH from scratch and can drop the directory where install.sh places the +# openshell/nemoclaw binaries. +nemoclaw_refresh_install_env() { + if [ -f "$HOME/.bashrc" ]; then + # shellcheck source=/dev/null + source "$HOME/.bashrc" 2>/dev/null || true + fi + nemoclaw_ensure_local_bin_on_path +} diff --git a/test/e2e/nemoclaw_scenarios/install/launchable.sh b/test/e2e/nemoclaw_scenarios/install/launchable.sh new file mode 100755 index 0000000000..6c78298ecd --- /dev/null +++ b/test/e2e/nemoclaw_scenarios/install/launchable.sh @@ -0,0 +1,30 @@ +#!/usr/bin/env bash +# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +# +# Install via a Brev launchable (launchable profile). +# +# This profile assumes the launchable has already provisioned the runner. +# We verify the nemoclaw binary is present and refresh PATH; no download +# step is performed. Full launchable orchestration lives in the Brev +# workflow, not in the E2E helper. + +_E2E_INST_LNCH_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +_E2E_INST_LNCH_RUNTIME_LIB="$(cd "${_E2E_INST_LNCH_DIR}/../../runtime/lib" && pwd)" +# shellcheck source=../../runtime/lib/env.sh +. "${_E2E_INST_LNCH_RUNTIME_LIB}/env.sh" +# shellcheck source=helpers/install-path-refresh.sh +. "${_E2E_INST_LNCH_DIR}/helpers/install-path-refresh.sh" + +e2e_install_launchable() { + e2e_env_trace "install-launchable" + if e2e_env_is_dry_run; then + echo "[dry-run] install-launchable (skipped)" + return 0 + fi + nemoclaw_refresh_install_env + if ! command -v nemoclaw >/dev/null 2>&1; then + echo "e2e_install_launchable: nemoclaw not on PATH after launchable boot" >&2 + return 1 + fi +} diff --git a/test/e2e/nemoclaw_scenarios/install/ollama.sh b/test/e2e/nemoclaw_scenarios/install/ollama.sh new file mode 100755 index 0000000000..a9d5f81c14 --- /dev/null +++ b/test/e2e/nemoclaw_scenarios/install/ollama.sh @@ -0,0 +1,33 @@ +#!/usr/bin/env bash +# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +# +# Install with the Ollama runtime pre-staged (ollama profile). +# +# Installs Ollama then delegates to the curl installer for NemoClaw +# itself. E2E_OLLAMA_INSTALL_URL overrides the Ollama installer source +# (useful for offline / mirror runners). + +_E2E_INST_OL_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +_E2E_INST_OL_RUNTIME_LIB="$(cd "${_E2E_INST_OL_DIR}/../../runtime/lib" && pwd)" +# shellcheck source=../../runtime/lib/env.sh +. "${_E2E_INST_OL_RUNTIME_LIB}/env.sh" +# shellcheck source=public-curl.sh +. "${_E2E_INST_OL_DIR}/public-curl.sh" + +e2e_install_ollama() { + e2e_env_trace "install-ollama" + if e2e_env_is_dry_run; then + echo "[dry-run] install-ollama (skipped)" + return 0 + fi + local ollama_url="${E2E_OLLAMA_INSTALL_URL:-https://ollama.ai/install.sh}" + if ! command -v ollama >/dev/null 2>&1; then + if ! curl -fsSL --retry 3 --retry-delay 2 "${ollama_url}" | bash; then + echo "e2e_install_ollama: ollama install failed" >&2 + return 1 + fi + fi + # Then fall through to the standard curl installer for NemoClaw. + e2e_install_curl +} diff --git a/test/e2e/nemoclaw_scenarios/install/public-curl.sh b/test/e2e/nemoclaw_scenarios/install/public-curl.sh new file mode 100755 index 0000000000..143d097f0d --- /dev/null +++ b/test/e2e/nemoclaw_scenarios/install/public-curl.sh @@ -0,0 +1,43 @@ +#!/usr/bin/env bash +# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +# +# Install from the public curl|bash installer (public-installer profile). +# +# Pins the installer source via E2E_INSTALLER_URL; can verify the download +# against E2E_INSTALLER_SHA256 when provided. + +_E2E_INST_CURL_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +_E2E_INST_CURL_RUNTIME_LIB="$(cd "${_E2E_INST_CURL_DIR}/../../runtime/lib" && pwd)" +# shellcheck source=../../runtime/lib/env.sh +. "${_E2E_INST_CURL_RUNTIME_LIB}/env.sh" +# shellcheck source=helpers/install-path-refresh.sh +. "${_E2E_INST_CURL_DIR}/helpers/install-path-refresh.sh" + +e2e_install_curl() { + e2e_env_trace "install-curl" + if e2e_env_is_dry_run; then + echo "[dry-run] install-curl (skipped)" + return 0 + fi + local url="${E2E_INSTALLER_URL:-https://raw.githubusercontent.com/NVIDIA/NemoClaw/main/scripts/install.sh}" + local sha256="${E2E_INSTALLER_SHA256:-}" + local tmp + tmp="$(mktemp -t nemoclaw-installer.XXXXXX.sh)" + # shellcheck disable=SC2064 + trap "rm -f '${tmp}'" RETURN + if ! curl -fsSL --retry 3 --retry-delay 2 -o "${tmp}" "${url}"; then + echo "e2e_install_curl: failed to download ${url}" >&2 + return 1 + fi + if [[ -n "${sha256}" ]]; then + local got + got="$(shasum -a 256 "${tmp}" 2>/dev/null | awk '{print $1}')" + if [[ "${got}" != "${sha256}" ]]; then + echo "e2e_install_curl: sha256 mismatch (expected ${sha256}, got ${got})" >&2 + return 1 + fi + fi + bash "${tmp}" + nemoclaw_refresh_install_env +} diff --git a/test/e2e/nemoclaw_scenarios/install/repo-current.sh b/test/e2e/nemoclaw_scenarios/install/repo-current.sh new file mode 100755 index 0000000000..4c189339bd --- /dev/null +++ b/test/e2e/nemoclaw_scenarios/install/repo-current.sh @@ -0,0 +1,31 @@ +#!/usr/bin/env bash +# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +# +# Install from a checked-out repo (repo-current / repo-checkout profile). +# +# Split from the install dispatcher to keep scenario setup logic flat and to +# make the per-profile code discoverable by grep. Honors E2E_DRY_RUN. + +_E2E_INST_REPO_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +_E2E_INST_REPO_RUNTIME_LIB="$(cd "${_E2E_INST_REPO_DIR}/../../runtime/lib" && pwd)" +# shellcheck source=../../runtime/lib/env.sh +. "${_E2E_INST_REPO_RUNTIME_LIB}/env.sh" +# shellcheck source=helpers/install-path-refresh.sh +. "${_E2E_INST_REPO_DIR}/helpers/install-path-refresh.sh" + +e2e_install_repo() { + e2e_env_trace "install-repo" + if e2e_env_is_dry_run; then + echo "[dry-run] install-repo (skipped)" + return 0 + fi + local repo_root + repo_root="$(cd "${_E2E_INST_REPO_DIR}/../../../.." && pwd)" + ( + cd "${repo_root}" || exit + npm install + npm link + ) + nemoclaw_refresh_install_env +} diff --git a/test/e2e/nemoclaw_scenarios/onboard/cloud-hermes.sh b/test/e2e/nemoclaw_scenarios/onboard/cloud-hermes.sh new file mode 100755 index 0000000000..1c379c7614 --- /dev/null +++ b/test/e2e/nemoclaw_scenarios/onboard/cloud-hermes.sh @@ -0,0 +1,13 @@ +#!/usr/bin/env bash +# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +# +# Onboard worker: cloud-hermes profile. Runs `nemoclaw onboard` with the +# hermes agent against the NVIDIA cloud provider. + +e2e_onboard_cloud_hermes() { + local sandbox_name + sandbox_name="$(e2e_context_get E2E_SANDBOX_NAME)" + : "${sandbox_name:=e2e-cloud-hermes}" + nemoclaw onboard --agent hermes --provider nvidia --sandbox "${sandbox_name}" --yes +} diff --git a/test/e2e/nemoclaw_scenarios/onboard/cloud-openclaw.sh b/test/e2e/nemoclaw_scenarios/onboard/cloud-openclaw.sh new file mode 100755 index 0000000000..509f18d9e6 --- /dev/null +++ b/test/e2e/nemoclaw_scenarios/onboard/cloud-openclaw.sh @@ -0,0 +1,13 @@ +#!/usr/bin/env bash +# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +# +# Onboard worker: cloud-openclaw profile. Runs `nemoclaw onboard` with the +# openclaw agent against the NVIDIA cloud provider. + +e2e_onboard_cloud_openclaw() { + local sandbox_name + sandbox_name="$(e2e_context_get E2E_SANDBOX_NAME)" + : "${sandbox_name:=e2e-cloud-openclaw}" + nemoclaw onboard --agent openclaw --provider nvidia --sandbox "${sandbox_name}" --yes +} diff --git a/test/e2e/nemoclaw_scenarios/onboard/dispatch.sh b/test/e2e/nemoclaw_scenarios/onboard/dispatch.sh new file mode 100755 index 0000000000..1c9a561bca --- /dev/null +++ b/test/e2e/nemoclaw_scenarios/onboard/dispatch.sh @@ -0,0 +1,48 @@ +#!/usr/bin/env bash +# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +# +# Onboard dispatcher. Sources env.sh + context.sh + the three per-path +# worker files, defines `e2e_onboard()` which routes by onboarding +# profile id and honors dry-run. + +_E2E_ONBOARD_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +_E2E_ONBOARD_RUNTIME_LIB="$(cd "${_E2E_ONBOARD_DIR}/../../runtime/lib" && pwd)" +# shellcheck source=../../runtime/lib/env.sh +. "${_E2E_ONBOARD_RUNTIME_LIB}/env.sh" +# shellcheck source=../../runtime/lib/context.sh +. "${_E2E_ONBOARD_RUNTIME_LIB}/context.sh" +# shellcheck source=cloud-openclaw.sh +. "${_E2E_ONBOARD_DIR}/cloud-openclaw.sh" +# shellcheck source=cloud-hermes.sh +. "${_E2E_ONBOARD_DIR}/cloud-hermes.sh" +# shellcheck source=local-ollama-openclaw.sh +. "${_E2E_ONBOARD_DIR}/local-ollama-openclaw.sh" + +e2e_onboard() { + local profile="${1:-}" + if [[ -z "${profile}" ]]; then + echo "e2e_onboard: missing onboarding profile id" >&2 + return 2 + fi + e2e_env_trace "onboard:${profile}" + if e2e_env_is_dry_run; then + echo "[dry-run] onboard profile=${profile} (skipped)" + return 0 + fi + case "${profile}" in + cloud-openclaw) + e2e_onboard_cloud_openclaw + ;; + cloud-hermes) + e2e_onboard_cloud_hermes + ;; + local-ollama-openclaw) + e2e_onboard_local_ollama_openclaw + ;; + *) + echo "e2e_onboard: unsupported onboarding profile: ${profile}" >&2 + return 2 + ;; + esac +} diff --git a/test/e2e/nemoclaw_scenarios/onboard/local-ollama-openclaw.sh b/test/e2e/nemoclaw_scenarios/onboard/local-ollama-openclaw.sh new file mode 100755 index 0000000000..89167cfd00 --- /dev/null +++ b/test/e2e/nemoclaw_scenarios/onboard/local-ollama-openclaw.sh @@ -0,0 +1,13 @@ +#!/usr/bin/env bash +# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +# +# Onboard worker: local-ollama-openclaw profile. Runs `nemoclaw onboard` +# with the openclaw agent against a local Ollama runtime. + +e2e_onboard_local_ollama_openclaw() { + local sandbox_name + sandbox_name="$(e2e_context_get E2E_SANDBOX_NAME)" + : "${sandbox_name:=e2e-local-ollama-openclaw}" + nemoclaw onboard --agent openclaw --provider ollama --sandbox "${sandbox_name}" --yes +} diff --git a/test/e2e/nemoclaw_scenarios/scenarios.yaml b/test/e2e/nemoclaw_scenarios/scenarios.yaml new file mode 100644 index 0000000000..4e0910d35f --- /dev/null +++ b/test/e2e/nemoclaw_scenarios/scenarios.yaml @@ -0,0 +1,196 @@ +# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +# +# E2E setup scenario catalog. +# +# Reading order: +# 1. `platforms`, `installs`, `runtimes`, and `onboarding` define reusable +# profiles ("dimensions") that describe how a user reaches a completed +# NemoClaw environment. +# 2. `setup_scenarios` names concrete combinations by ID. Each scenario +# references profiles by key and pins exactly one `expected_state` +# from `expected-states.yaml`, along with an ordered list of `suites` +# from `suites.yaml`. +# +# Adding a new scenario: +# - Reuse existing profiles where possible. Add a new profile only when a +# dimension is genuinely new (e.g. a new platform runner). +# - Pick the expected_state that describes the completed environment. +# - List the suites to run against it, in the order they should execute. +# - Run `bash test/e2e/runtime/run-scenario.sh --plan-only` once the +# resolver lands to validate references. +# +# See `test/e2e/docs/README.md` for the full reading guide and the sparse matrix +# design that drives the initial three scenarios. + +platforms: + ubuntu-local: + os: ubuntu + execution_target: local + macos-local: + os: macos + execution_target: local + wsl-local: + os: wsl + execution_target: local + gpu-runner: + os: ubuntu + execution_target: local + gpu: nvidia + brev-launchable: + os: ubuntu + execution_target: remote + provider: brev + dgx-spark: + os: ubuntu + execution_target: local + hardware: dgx-spark + +installs: + repo-current: + method: repo-checkout + source: current-branch + public-curl: + method: curl-install-script + source: public-installer + launchable: + method: brev-launchable + source: launchable-image + release: + method: release-tarball + source: github-release + upgrade-from-version: + method: upgrade-in-place + source: prior-release + +runtimes: + docker-running: + container_engine: docker + container_daemon: running + gpu-docker-cdi: + container_engine: docker + container_daemon: running + gpu_runtime: cdi + docker-missing: + container_engine: docker + container_daemon: missing + +onboarding: + cloud-openclaw: + path: cloud + agent: openclaw + provider: nvidia + inference_route: inference-local + cloud-hermes: + path: cloud + agent: hermes + provider: nvidia + inference_route: inference-local + local-ollama-openclaw: + path: local + agent: openclaw + provider: ollama + inference_route: inference-local + openai-compatible-openclaw: + path: cloud + agent: openclaw + provider: openai-compatible + inference_route: inference-local + +setup_scenarios: + ubuntu-repo-cloud-openclaw: + dimensions: + platform: ubuntu-local + install: repo-current + runtime: docker-running + onboarding: cloud-openclaw + expected_state: cloud-openclaw-ready + suites: + - smoke + - inference + - credentials + + ubuntu-repo-cloud-hermes: + dimensions: + platform: ubuntu-local + install: repo-current + runtime: docker-running + onboarding: cloud-hermes + expected_state: cloud-hermes-ready + suites: + - smoke + - inference + - hermes-specific + + gpu-repo-local-ollama-openclaw: + dimensions: + platform: gpu-runner + install: repo-current + runtime: gpu-docker-cdi + onboarding: local-ollama-openclaw + runner_requirements: + - self-hosted-gpu + - docker-cdi + expected_state: local-ollama-openclaw-ready + suites: + - smoke + - local-ollama-inference + - ollama-proxy + + macos-repo-cloud-openclaw: + dimensions: + platform: macos-local + install: repo-current + runtime: docker-running + onboarding: cloud-openclaw + runner_requirements: + - macos-latest + expected_state: cloud-openclaw-ready + suites: + - smoke + - platform-macos + + wsl-repo-cloud-openclaw: + dimensions: + platform: wsl-local + install: repo-current + runtime: docker-running + onboarding: cloud-openclaw + runner_requirements: + - windows-latest + - wsl2 + expected_state: cloud-openclaw-ready + suites: + - smoke + - platform-wsl + + brev-launchable-cloud-openclaw: + dimensions: + platform: brev-launchable + install: launchable + runtime: docker-running + onboarding: cloud-openclaw + runner_requirements: + - ubuntu-latest + - brev-api-token + - launchable-image + expected_state: cloud-openclaw-ready + # Remote gateway must bind to 0.0.0.0 so the GitHub runner can reach it + # after ssh port-forward. Scenario-level overrides land alongside their + # first real consumer (deferred from Phase 1). + overrides: + onboarding: + gateway: + bind_address: 0.0.0.0 + suites: + - smoke + - inference + + ubuntu-no-docker-preflight-negative: + dimensions: + platform: ubuntu-local + install: repo-current + runtime: docker-missing + onboarding: cloud-openclaw + expected_state: preflight-failure-no-sandbox + suites: [] diff --git a/test/e2e/runtime/coverage-report.sh b/test/e2e/runtime/coverage-report.sh new file mode 100755 index 0000000000..9fea9cf9af --- /dev/null +++ b/test/e2e/runtime/coverage-report.sh @@ -0,0 +1,26 @@ +#!/usr/bin/env bash +# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +# +# Render the E2E scenario coverage report as Markdown to stdout. +# +# Usage: +# bash test/e2e/runtime/coverage-report.sh > coverage.md + +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +REPO_ROOT="$(cd "${SCRIPT_DIR}/../../.." && pwd)" + +TSX_BIN="${REPO_ROOT}/node_modules/.bin/tsx" +if [[ -x "${TSX_BIN}" ]]; then + "${TSX_BIN}" "${SCRIPT_DIR}/resolver/index.ts" coverage +else + # CodeRabbit review items #3, #10: fall back to --no-install so we rely on + # the lockfile-pinned tsx rather than a network fetch, and fail closed + # with a clear hint if tsx is not installed. + if ! (cd "${REPO_ROOT}" && npx --no-install tsx "${SCRIPT_DIR}/resolver/index.ts" coverage); then + echo "coverage-report: tsx not available. Run 'npm ci' at the repo root to install devDependencies." >&2 + exit 1 + fi +fi diff --git a/test/e2e/runtime/lib/artifacts.sh b/test/e2e/runtime/lib/artifacts.sh new file mode 100755 index 0000000000..761e618d0a --- /dev/null +++ b/test/e2e/runtime/lib/artifacts.sh @@ -0,0 +1,50 @@ +#!/usr/bin/env bash +# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +# +# Artifact collection helpers. Designed to be called from failure traps. +# All helpers are best-effort: missing sources are logged but do not abort. + +_E2E_ART_LIB_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" + +# e2e_artifact_collect_file +# Copies a single file. Returns 0 on success or when src is missing. +e2e_artifact_collect_file() { + local src="${1:-}" + local dst="${2:-}" + if [[ -z "${src}" || -z "${dst}" ]]; then + echo "e2e_artifact_collect_file: missing src or dst" >&2 + return 2 + fi + if [[ ! -f "${src}" ]]; then + echo "e2e_artifact_collect_file: ${src} not found, skipping" >&2 + return 0 + fi + mkdir -p "$(dirname "${dst}")" + cp -f "${src}" "${dst}" +} + +# e2e_artifact_collect_dir +# Recursively copies a directory. No-op if missing. +e2e_artifact_collect_dir() { + local src="${1:-}" + local dst="${2:-}" + if [[ ! -d "${src}" ]]; then + echo "e2e_artifact_collect_dir: ${src} not found, skipping" >&2 + return 0 + fi + mkdir -p "${dst}" + cp -rf "${src}/." "${dst}/" +} + +# e2e_artifact_preserve_exit +# Intended for failure traps. Collects artifacts (caller-defined function +# `_e2e_collect_artifacts` if present) but always returns the provided exit +# code so it can be passed to `exit`. +e2e_artifact_preserve_exit() { + local rc="${1:-1}" + if declare -F _e2e_collect_artifacts >/dev/null 2>&1; then + _e2e_collect_artifacts || true + fi + return "${rc}" +} diff --git a/test/e2e/runtime/lib/cleanup.sh b/test/e2e/runtime/lib/cleanup.sh new file mode 100755 index 0000000000..8581e3c9e0 --- /dev/null +++ b/test/e2e/runtime/lib/cleanup.sh @@ -0,0 +1,29 @@ +#!/usr/bin/env bash +# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +# +# Cleanup helpers. Wraps the existing sandbox-teardown.sh so scenario code +# gets a single, discoverable entrypoint. + +_E2E_CLEAN_LIB_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" + +# shellcheck source=sandbox-teardown.sh +. "${_E2E_CLEAN_LIB_DIR}/sandbox-teardown.sh" +# shellcheck source=context.sh +. "${_E2E_CLEAN_LIB_DIR}/context.sh" +# shellcheck source=env.sh +. "${_E2E_CLEAN_LIB_DIR}/env.sh" + +# e2e_cleanup_register_sandbox [name] +# Default to E2E_SANDBOX_NAME from context. +e2e_cleanup_register_sandbox() { + local name="${1:-}" + if [[ -z "${name}" ]]; then + name="$(e2e_context_get E2E_SANDBOX_NAME)" + fi + if [[ -z "${name}" ]]; then + echo "e2e_cleanup_register_sandbox: no sandbox name to register" >&2 + return 0 + fi + register_sandbox_for_teardown "${name}" +} diff --git a/test/e2e/runtime/lib/context.sh b/test/e2e/runtime/lib/context.sh new file mode 100755 index 0000000000..7061f16fb7 --- /dev/null +++ b/test/e2e/runtime/lib/context.sh @@ -0,0 +1,180 @@ +#!/usr/bin/env bash +# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +# +# Normalized E2E context helper. +# +# Each scenario produces a `.e2e/context.env` file with normalized key/value +# pairs describing the completed environment. Downstream suites, expected- +# state validators, and artifact collection source this file instead of +# rediscovering scenario state. +# +# Standard keys (set by the scenario runner): +# E2E_SCENARIO scenario id +# E2E_PLATFORM_OS ubuntu|macos|wsl|... +# E2E_EXECUTION_TARGET local|remote +# E2E_INSTALL_METHOD repo-checkout|curl-install-script|... +# E2E_ONBOARDING_PATH cloud|local +# E2E_AGENT openclaw|hermes +# E2E_PROVIDER nvidia|ollama|openai-compatible +# E2E_SANDBOX_NAME unique sandbox identifier +# E2E_GATEWAY_URL gateway base URL +# E2E_CONTAINER_ENGINE docker +# E2E_CONTAINER_DAEMON running|missing +# E2E_INFERENCE_ROUTE inference-local|... +# +# Usage: +# . "$(dirname "${BASH_SOURCE[0]}")/lib/context.sh" +# e2e_context_init +# e2e_context_set E2E_SCENARIO ubuntu-repo-cloud-openclaw +# e2e_context_require E2E_SANDBOX_NAME +# e2e_context_dump + +# Resolve and export E2E_CONTEXT_DIR. If not set, default to /.e2e +_e2e_context_resolve_dir() { + if [[ -n "${E2E_CONTEXT_DIR:-}" ]]; then + return 0 + fi + local script_dir repo_root + script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" + repo_root="$(cd "${script_dir}/../../.." && pwd)" + export E2E_CONTEXT_DIR="${repo_root}/.e2e" +} + +e2e_context_init() { + _e2e_context_resolve_dir + mkdir -p "${E2E_CONTEXT_DIR}" + : >"${E2E_CONTEXT_DIR}/context.env" +} + +e2e_context_path() { + _e2e_context_resolve_dir + printf '%s\n' "${E2E_CONTEXT_DIR}/context.env" +} + +# CodeRabbit review item #4: validate that KEY is a plain POSIX identifier +# (so we never interpolate metacharacters into grep regexes) and that VALUE +# has no newlines or control characters that could break the line-oriented +# context.env format. +_e2e_context_validate_key() { + local key="${1:-}" + if [[ -z "${key}" ]]; then + echo "e2e_context: missing key" >&2 + return 2 + fi + if [[ ! "${key}" =~ ^[A-Za-z_][A-Za-z0-9_]*$ ]]; then + echo "e2e_context: invalid key (POSIX identifier required): ${key}" >&2 + return 2 + fi +} + +_e2e_context_validate_value() { + local value="${1-}" + # Reject newlines that would corrupt the line-oriented context.env + # format. We deliberately do not reject all control characters since + # tabs and escape sequences can appear in legitimate values (e.g. test + # fixtures that seed tracing markers). Newlines are the only format + # break. (CodeRabbit review item #4.) + if [[ "${value}" == *$'\n'* ]] || [[ "${value}" == *$'\r'* ]]; then + echo "e2e_context: value contains newline characters; reject" >&2 + return 2 + fi +} + +# e2e_context_set KEY VALUE +# Appends or updates a single key in context.env. Value is written literally; +# callers are responsible for not embedding newlines. +e2e_context_set() { + local key="${1:-}" + local value="${2:-}" + _e2e_context_validate_key "${key}" || return 2 + _e2e_context_validate_value "${value}" || return 2 + _e2e_context_resolve_dir + local ctx="${E2E_CONTEXT_DIR}/context.env" + if [[ ! -f "${ctx}" ]]; then + mkdir -p "${E2E_CONTEXT_DIR}" + : >"${ctx}" + fi + # Remove any existing assignment for this key, then append. + local tmp + tmp="$(mktemp)" + grep -v "^${key}=" "${ctx}" >"${tmp}" || true + mv "${tmp}" "${ctx}" + printf '%s=%s\n' "${key}" "${value}" >>"${ctx}" +} + +# e2e_context_get KEY +# Prints the value of KEY (empty if missing). Does not fail. +e2e_context_get() { + local key="${1:-}" + _e2e_context_validate_key "${key}" || return 2 + _e2e_context_resolve_dir + local ctx="${E2E_CONTEXT_DIR}/context.env" + [[ -f "${ctx}" ]] || return 0 + local line + line="$(grep "^${key}=" "${ctx}" | tail -n1 || true)" + printf '%s' "${line#"${key}"=}" +} + +# e2e_context_require KEY [KEY ...] +# Exits non-zero if any required key is missing or empty. +e2e_context_require() { + _e2e_context_resolve_dir + local ctx="${E2E_CONTEXT_DIR}/context.env" + local missing=() + local key value + for key in "$@"; do + _e2e_context_validate_key "${key}" || return 2 + if [[ -f "${ctx}" ]]; then + value="$(grep "^${key}=" "${ctx}" | tail -n1 || true)" + value="${value#"${key}"=}" + else + value="" + fi + if [[ -z "${value}" ]]; then + missing+=("${key}") + fi + done + if ((${#missing[@]} > 0)); then + printf 'e2e context: missing required key(s): %s\n' "${missing[*]}" >&2 + printf 'e2e context: expected in %s\n' "${ctx}" >&2 + return 1 + fi +} + +# Internal: decide whether a key's value should be redacted. +_e2e_context_is_sensitive_key() { + local key="$1" + case "$key" in + *TOKEN* | *SECRET* | *PASSWORD* | *API_KEY* | *APIKEY* | *CREDENTIAL* | *PRIVATE*) + return 0 + ;; + *) + return 1 + ;; + esac +} + +# e2e_context_dump +# Print the context to stdout with sensitive values redacted. Safe to use in +# CI logs and artifact bundles. +e2e_context_dump() { + _e2e_context_resolve_dir + local ctx="${E2E_CONTEXT_DIR}/context.env" + if [[ ! -f "${ctx}" ]]; then + echo "e2e context: no context.env at ${ctx}" >&2 + return 1 + fi + echo "# E2E context (${ctx})" + local key rest + while IFS= read -r line || [[ -n "${line}" ]]; do + [[ -z "${line}" ]] && continue + key="${line%%=*}" + rest="${line#*=}" + if _e2e_context_is_sensitive_key "${key}"; then + printf '%s=%s\n' "${key}" "REDACTED" + else + printf '%s=%s\n' "${key}" "${rest}" + fi + done <"${ctx}" +} diff --git a/test/e2e/runtime/lib/env.sh b/test/e2e/runtime/lib/env.sh new file mode 100755 index 0000000000..ba770163aa --- /dev/null +++ b/test/e2e/runtime/lib/env.sh @@ -0,0 +1,46 @@ +#!/usr/bin/env bash +# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +# +# Standardized non-interactive environment for E2E runs. +# +# Applies the same defaults historically set ad-hoc at the top of each +# `test/e2e/test-*.sh` script. Safe to source from any scenario runner. + +# Auto-source the logging helpers so every consumer of env.sh gets +# e2e_section / e2e_info / e2e_pass / e2e_fail for free. Scenario runner +# and every suite step script sources env.sh — this keeps the logging +# contract DRY (reuse category #1). +_E2E_ENV_LIB_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +if [[ -f "${_E2E_ENV_LIB_DIR}/logging.sh" ]]; then + # shellcheck source=logging.sh + . "${_E2E_ENV_LIB_DIR}/logging.sh" +fi + +e2e_env_apply_noninteractive() { + export NEMOCLAW_NON_INTERACTIVE=1 + export DEBIAN_FRONTEND=noninteractive + export NEMOCLAW_ACCEPT_THIRD_PARTY_TERMS=1 + export NEMOCLAW_ACCEPT_LICENSES=1 + export NEMOCLAW_DISABLE_UPDATE_CHECK=1 + # CI is usually already set, but ensure downstream tools see it. + export CI="${CI:-1}" +} + +# e2e_env_trace [note ...] +# Append a trace line to $E2E_TRACE_FILE if set. Used by dry-run paths so +# tests can verify that helpers were invoked in the expected order without +# running real commands. +e2e_env_trace() { + local event="${1:-}" + shift || true + if [[ -n "${E2E_TRACE_FILE:-}" ]]; then + mkdir -p "$(dirname "${E2E_TRACE_FILE}")" + printf '%s %s\n' "${event}" "$*" >>"${E2E_TRACE_FILE}" + fi +} + +# e2e_env_is_dry_run: true if E2E_DRY_RUN=1 +e2e_env_is_dry_run() { + [[ "${E2E_DRY_RUN:-0}" == "1" ]] +} diff --git a/test/e2e/runtime/lib/logging.sh b/test/e2e/runtime/lib/logging.sh new file mode 100755 index 0000000000..e0c32c2072 --- /dev/null +++ b/test/e2e/runtime/lib/logging.sh @@ -0,0 +1,68 @@ +#!/usr/bin/env bash +# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +# +# Canonical logging helpers for E2E scenarios. +# +# Collapses the ad-hoc `section` / `info` / `pass` / `fail` functions that +# the 40 legacy `test/e2e/test-*.sh` scripts each re-declare with subtle +# drift. Emits stable markers that `scripts/e2e/compare-parity.sh` parses +# when diffing legacy vs. migrated runs. +# +# Contract: +# PASS: — asserting success +# FAIL: — asserting failure; `e2e_fail` exits non-zero +# === Phase N: