You are helping with a small deployment config rollout for a service named “orders-api”. The current deployment metadata is split between an old JSON file and a new schema directory. Your job is to migrate the active rollout manifest to the new source of truth, validate it with JSON Schema, and produce a jq-generated summary artifact.

All work should happen under `/home/user/deploy-rollout`.

Initial files will already exist:

- `/home/user/deploy-rollout/legacy/deployment.json`
- `/home/user/deploy-rollout/schemas/deployment.schema.json`
- `/home/user/deploy-rollout/archive/`
- `/home/user/deploy-rollout/out/`

The old file `/home/user/deploy-rollout/legacy/deployment.json` is no longer supposed to be the active source of truth after this rollout. Create the new active manifest at:

- `/home/user/deploy-rollout/current/deployment.json`

The new manifest must preserve the deployment semantics from the legacy manifest, but update the rollout target for the new environment:

- Set `environment` to `prod-eu`
- Set `service.endpoint` to use the new production EU endpoint already implied by the rollout context
- Keep the same service name, image, version, replica count, feature flags, and health check settings from the legacy manifest
- Add or update a top-level field named `sourceOfTruth` with the exact value `current/deployment.json`

After creating the new active manifest, retire the old path by moving the legacy file into the archive directory as:

- `/home/user/deploy-rollout/archive/deployment.legacy-retired.json`

There should no longer be a file at:

- `/home/user/deploy-rollout/legacy/deployment.json`

Validate the new active manifest against the schema at:

- `/home/user/deploy-rollout/schemas/deployment.schema.json`

Use the new active manifest as the validation target, not the archived legacy file. If you install or use a validator, keep everything inside `/home/user/deploy-rollout` or use already available tooling; do not require root access.

Finally, generate a jq-produced rollout summary file at:

- `/home/user/deploy-rollout/out/rollout-summary.json`

The summary file must be valid pretty-printed JSON and must be derived from `/home/user/deploy-rollout/current/deployment.json`, not from the archived legacy file. It must contain exactly these top-level keys in this order:

1. `service`
2. `version`
3. `environment`
4. `endpoint`
5. `replicas`
6. `enabledFeatures`
7. `healthPath`
8. `sourceOfTruth`

The values must come from the final active manifest. `enabledFeatures` must be an array containing only the names of feature flags whose value is `true`, sorted alphabetically.

Also create a verification log at:

- `/home/user/deploy-rollout/out/verification.log`

The log must contain exactly four lines, in this order:

1. `schema_validation=passed`
2. `active_manifest=/home/user/deploy-rollout/current/deployment.json`
3. `legacy_manifest=retired`
4. `summary_source=current`

Before finishing, verify the active manifest, not the archived copy or old path. The final state should make it clear that `/home/user/deploy-rollout/current/deployment.json` is the only active source of truth for the rollout.

schema_version = "1.1"

[task]
name = "endless-terminals/task_000000_9bcf23e1"
description = "You are helping with a small deployment config rollout for a service named \u201corders-api\u201d. The current deployment metadata is split between an old JSON file and a new schema directory. Your job is to migrate the active rollout manifest to the"
authors = [{ name = "Endless Terminals / Jarrod Barnes" }]
keywords = ["agentic-rl", "endless-terminals", "old_state_new_state_confusion", "stateful_migration_verification", "terminal-bench-2"]

[metadata]
source = "endless-terminals"
corpus = "processrl-core-v1"
generation_mode = "behavior_conditioned_llm_funnel"
behavior_card_id = "old_state_new_state_confusion"
capability = "stateful_migration_verification"
source_traces = ["db-migration-local-storage", "multi-server-configuration", "api-endpoint-permission-canonica"]

[verifier]
timeout_sec = 300.0
user = "root"

[agent]
timeout_sec = 900.0
user = "user"

[environment]
build_timeout_sec = 900.0
os = "linux"
cpus = 2
memory_mb = 4096
storage_mb = 10240
gpus = 0
allow_internet = true

FROM ubuntu:22.04
SHELL ["/bin/bash", "-lc"]
RUN <<'__ENDLESS_DOCKER_POST__'
    set -eu

    apt-get update
    DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
        ca-certificates \
        jq \
        python3 \
        python3-pip \
        python3-jsonschema \
        python3-pytest
    rm -rf /var/lib/apt/lists/*

    if ! id -u user >/dev/null 2>&1; then
        useradd -m -s /bin/bash user
    fi

    BASE=/home/user/deploy-rollout

    mkdir -p "$BASE/legacy" "$BASE/schemas" "$BASE/archive" "$BASE/out"

    cat > "$BASE/legacy/deployment.json" <<'EOF'
{
  "service": {
    "name": "orders-api",
    "image": "registry.internal.example/orders-api",
    "endpoint": "https://orders.staging.internal.example"
  },
  "version": "2.8.4",
  "environment": "staging",
  "replicas": 3,
  "featureFlags": {
    "asyncPayments": true,
    "bulkCancel": false,
    "euTaxRules": true,
    "legacyRefundFlow": false,
    "orderTimelineV2": true
  },
  "healthCheck": {
    "path": "/healthz",
    "intervalSeconds": 15,
    "timeoutSeconds": 3
  }
}
EOF

    cat > "$BASE/schemas/deployment.schema.json" <<'EOF'
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "title": "orders-api deployment manifest",
  "type": "object",
  "required": [
    "service",
    "version",
    "environment",
    "replicas",
    "featureFlags",
    "healthCheck",
    "sourceOfTruth"
  ],
  "additionalProperties": false,
  "properties": {
    "service": {
      "type": "object",
      "required": [
        "name",
        "image",
        "endpoint"
      ],
      "additionalProperties": false,
      "properties": {
        "name": {
          "const": "orders-api"
        },
        "image": {
          "type": "string",
          "minLength": 1
        },
        "endpoint": {
          "const": "https://orders.prod-eu.internal.example"
        }
      }
    },
    "version": {
      "type": "string",
      "pattern": "^2\\.8\\.4$"
    },
    "environment": {
      "const": "prod-eu"
    },
    "replicas": {
      "type": "integer",
      "minimum": 3,
      "maximum": 3
    },
    "featureFlags": {
      "type": "object",
      "required": [
        "asyncPayments",
        "bulkCancel",
        "euTaxRules",
        "legacyRefundFlow",
        "orderTimelineV2"
      ],
      "additionalProperties": false,
      "properties": {
        "asyncPayments": {
          "type": "boolean"
        },
        "bulkCancel": {
          "type": "boolean"
        },
        "euTaxRules": {
          "type": "boolean"
        },
        "legacyRefundFlow": {
          "type": "boolean"
        },
        "orderTimelineV2": {
          "type": "boolean"
        }
      }
    },
    "healthCheck": {
      "type": "object",
      "required": [
        "path",
        "intervalSeconds",
        "timeoutSeconds"
      ],
      "additionalProperties": false,
      "properties": {
        "path": {
          "const": "/healthz"
        },
        "intervalSeconds": {
          "type": "integer",
          "minimum": 15,
          "maximum": 15
        },
        "timeoutSeconds": {
          "type": "integer",
          "minimum": 3,
          "maximum": 3
        }
      }
    },
    "sourceOfTruth": {
      "const": "current/deployment.json"
    }
  }
}
EOF

    chown -R user:user /home/user/deploy-rollout
    chmod -R u+rwX,go+rX /home/user/deploy-rollout
    chmod 755 /home/user
    chmod 755 /home/user/deploy-rollout /home/user/deploy-rollout/legacy /home/user/deploy-rollout/schemas /home/user/deploy-rollout/archive /home/user/deploy-rollout/out

chmod -R a+rwX /home/user
__ENDLESS_DOCKER_POST__
WORKDIR /home/user

# test_final_state.py
from pathlib import Path
import json
import re

BASE = Path("/home/user/deploy-rollout")

CURRENT_FILE = Path("/home/user/deploy-rollout/current/deployment.json")
LEGACY_FILE = Path("/home/user/deploy-rollout/legacy/deployment.json")
ARCHIVED_LEGACY_FILE = Path("/home/user/deploy-rollout/archive/deployment.legacy-retired.json")
SCHEMA_FILE = Path("/home/user/deploy-rollout/schemas/deployment.schema.json")
SUMMARY_FILE = Path("/home/user/deploy-rollout/out/rollout-summary.json")
VERIFICATION_LOG = Path("/home/user/deploy-rollout/out/verification.log")

EXPECTED_CURRENT = {
    "service": {
        "name": "orders-api",
        "image": "registry.internal.example/orders-api",
        "endpoint": "https://orders.prod-eu.internal.example",
    },
    "version": "2.8.4",
    "environment": "prod-eu",
    "replicas": 3,
    "featureFlags": {
        "asyncPayments": True,
        "bulkCancel": False,
        "euTaxRules": True,
        "legacyRefundFlow": False,
        "orderTimelineV2": True,
    },
    "healthCheck": {
        "path": "/healthz",
        "intervalSeconds": 15,
        "timeoutSeconds": 3,
    },
    "sourceOfTruth": "current/deployment.json",
}

EXPECTED_ARCHIVED_LEGACY = {
    "service": {
        "name": "orders-api",
        "image": "registry.internal.example/orders-api",
        "endpoint": "https://orders.staging.internal.example",
    },
    "version": "2.8.4",
    "environment": "staging",
    "replicas": 3,
    "featureFlags": {
        "asyncPayments": True,
        "bulkCancel": False,
        "euTaxRules": True,
        "legacyRefundFlow": False,
        "orderTimelineV2": True,
    },
    "healthCheck": {
        "path": "/healthz",
        "intervalSeconds": 15,
        "timeoutSeconds": 3,
    },
}

EXPECTED_SCHEMA = {
    "$schema": "https://json-schema.org/draft/2020-12/schema",
    "title": "orders-api deployment manifest",
    "type": "object",
    "required": [
        "service",
        "version",
        "environment",
        "replicas",
        "featureFlags",
        "healthCheck",
        "sourceOfTruth",
    ],
    "additionalProperties": False,
    "properties": {
        "service": {
            "type": "object",
            "required": [
                "name",
                "image",
                "endpoint",
            ],
            "additionalProperties": False,
            "properties": {
                "name": {
                    "const": "orders-api",
                },
                "image": {
                    "type": "string",
                    "minLength": 1,
                },
                "endpoint": {
                    "const": "https://orders.prod-eu.internal.example",
                },
            },
        },
        "version": {
            "type": "string",
            "pattern": r"^2\.8\.4$",
        },
        "environment": {
            "const": "prod-eu",
        },
        "replicas": {
            "type": "integer",
            "minimum": 3,
            "maximum": 3,
        },
        "featureFlags": {
            "type": "object",
            "required": [
                "asyncPayments",
                "bulkCancel",
                "euTaxRules",
                "legacyRefundFlow",
                "orderTimelineV2",
            ],
            "additionalProperties": False,
            "properties": {
                "asyncPayments": {
                    "type": "boolean",
                },
                "bulkCancel": {
                    "type": "boolean",
                },
                "euTaxRules": {
                    "type": "boolean",
                },
                "legacyRefundFlow": {
                    "type": "boolean",
                },
                "orderTimelineV2": {
                    "type": "boolean",
                },
            },
        },
        "healthCheck": {
            "type": "object",
            "required": [
                "path",
                "intervalSeconds",
                "timeoutSeconds",
            ],
            "additionalProperties": False,
            "properties": {
                "path": {
                    "const": "/healthz",
                },
                "intervalSeconds": {
                    "type": "integer",
                    "minimum": 15,
                    "maximum": 15,
                },
                "timeoutSeconds": {
                    "type": "integer",
                    "minimum": 3,
                    "maximum": 3,
                },
            },
        },
        "sourceOfTruth": {
            "const": "current/deployment.json",
        },
    },
}

EXPECTED_SUMMARY_KEYS = [
    "service",
    "version",
    "environment",
    "endpoint",
    "replicas",
    "enabledFeatures",
    "healthPath",
    "sourceOfTruth",
]

EXPECTED_SUMMARY = {
    "service": "orders-api",
    "version": "2.8.4",
    "environment": "prod-eu",
    "endpoint": "https://orders.prod-eu.internal.example",
    "replicas": 3,
    "enabledFeatures": [
        "asyncPayments",
        "euTaxRules",
        "orderTimelineV2",
    ],
    "healthPath": "/healthz",
    "sourceOfTruth": "current/deployment.json",
}

EXPECTED_VERIFICATION_LOG = (
    "schema_validation=passed\n"
    "active_manifest=/home/user/deploy-rollout/current/deployment.json\n"
    "legacy_manifest=retired\n"
    "summary_source=current\n"
)

def read_json(path: Path):
    try:
        return json.loads(path.read_text(encoding="utf-8"))
    except FileNotFoundError as exc:
        raise AssertionError(f"Required JSON file is missing: {path}") from exc
    except json.JSONDecodeError as exc:
        raise AssertionError(f"File is not valid JSON: {path}: {exc}") from exc

def assert_regular_json_file(path: Path, description: str):
    assert path.exists(), f"{description} is missing: {path}"
    assert path.is_file(), f"{description} exists but is not a regular file: {path}"

def validate_expected_schema_subset(instance, schema, location="$"):
    """
    Minimal validator for the schema features used by this task:
    type, required, additionalProperties=false, properties, const,
    minLength, minimum, maximum, and pattern.
    """
    if "type" in schema:
        expected_type = schema["type"]
        if expected_type == "object":
            assert isinstance(instance, dict), f"{location} must be an object according to the schema."
        elif expected_type == "string":
            assert isinstance(instance, str), f"{location} must be a string according to the schema."
        elif expected_type == "integer":
            assert isinstance(instance, int) and not isinstance(instance, bool), (
                f"{location} must be an integer according to the schema."
            )
        elif expected_type == "boolean":
            assert isinstance(instance, bool), f"{location} must be a boolean according to the schema."
        else:
            raise AssertionError(f"Test validator does not support schema type {expected_type!r} at {location}.")

    if "const" in schema:
        assert instance == schema["const"], (
            f"{location} must equal schema const {schema['const']!r}, but found {instance!r}."
        )

    if "minLength" in schema:
        assert isinstance(instance, str), f"{location} must be a string for minLength validation."
        assert len(instance) >= schema["minLength"], (
            f"{location} must have length at least {schema['minLength']}, but found {len(instance)}."
        )

    if "minimum" in schema:
        assert instance >= schema["minimum"], (
            f"{location} must be >= {schema['minimum']}, but found {instance!r}."
        )

    if "maximum" in schema:
        assert instance <= schema["maximum"], (
            f"{location} must be <= {schema['maximum']}, but found {instance!r}."
        )

    if "pattern" in schema:
        assert isinstance(instance, str), f"{location} must be a string for pattern validation."
        assert re.search(schema["pattern"], instance), (
            f"{location} value {instance!r} does not match schema pattern {schema['pattern']!r}."
        )

    if isinstance(instance, dict):
        required = schema.get("required", [])
        for key in required:
            assert key in instance, f"{location} is missing required schema key {key!r}."

        properties = schema.get("properties", {})
        if schema.get("additionalProperties") is False:
            extra = set(instance) - set(properties)
            assert not extra, f"{location} has additional properties forbidden by schema: {sorted(extra)!r}."

        for key, subschema in properties.items():
            if key in instance:
                validate_expected_schema_subset(instance[key], subschema, f"{location}.{key}")

def test_required_final_paths_and_legacy_retirement_state():
    assert BASE.exists(), f"Base deployment directory is missing: {BASE}"
    assert BASE.is_dir(), f"Base deployment path exists but is not a directory: {BASE}"

    assert_regular_json_file(CURRENT_FILE, "New active current manifest")
    assert not LEGACY_FILE.exists(), (
        f"Legacy manifest must be retired and absent, but it still exists at: {LEGACY_FILE}"
    )
    assert_regular_json_file(ARCHIVED_LEGACY_FILE, "Archived retired legacy manifest")

    assert not CURRENT_FILE.is_symlink(), (
        f"Current manifest must be a real active file, not a symlink: {CURRENT_FILE}"
    )
    if ARCHIVED_LEGACY_FILE.exists():
        assert CURRENT_FILE.resolve() != ARCHIVED_LEGACY_FILE.resolve(), (
            f"Current manifest must not point to or be the same file as archived legacy manifest: "
            f"{CURRENT_FILE} -> {ARCHIVED_LEGACY_FILE}"
        )

def test_current_manifest_matches_required_prod_eu_source_of_truth():
    current = read_json(CURRENT_FILE)

    assert current == EXPECTED_CURRENT, (
        f"Current manifest at {CURRENT_FILE} does not match the required final prod-eu deployment. "
        "It must preserve service name/image/version/replicas/feature flags/health check from legacy, "
        "set environment to 'prod-eu', set endpoint to "
        "'https://orders.prod-eu.internal.example', and set "
        "sourceOfTruth to 'current/deployment.json'."
    )

    assert current["environment"] != "staging", (
        f"Current manifest at {CURRENT_FILE} still uses the old staging environment."
    )
    assert current["service"]["endpoint"] != "https://orders.staging.internal.example", (
        f"Current manifest at {CURRENT_FILE} still uses the old staging endpoint."
    )

def test_archived_legacy_manifest_preserves_original_staging_state():
    archived = read_json(ARCHIVED_LEGACY_FILE)

    assert archived == EXPECTED_ARCHIVED_LEGACY, (
        f"Archived legacy manifest at {ARCHIVED_LEGACY_FILE} must preserve the original staging JSON "
        "semantics exactly: staging environment, staging endpoint, original replicas/features/healthCheck, "
        "and no sourceOfTruth field."
    )
    assert "sourceOfTruth" not in archived, (
        f"Archived legacy manifest at {ARCHIVED_LEGACY_FILE} should not have sourceOfTruth added to it."
    )

def test_schema_file_matches_required_schema_and_current_manifest_validates_against_it():
    assert_regular_json_file(SCHEMA_FILE, "Deployment schema")
    schema = read_json(SCHEMA_FILE)
    current = read_json(CURRENT_FILE)

    assert schema == EXPECTED_SCHEMA, (
        f"Schema at {SCHEMA_FILE} has been changed from the required rollout schema. "
        "It must require prod-eu, the prod-eu endpoint, sourceOfTruth=current/deployment.json, "
        "and the specified orders-api manifest structure."
    )

    validate_expected_schema_subset(current, schema)

def test_rollout_summary_exists_is_pretty_json_and_matches_current_manifest_with_key_order():
    assert_regular_json_file(SUMMARY_FILE, "Rollout summary")
    raw = SUMMARY_FILE.read_text(encoding="utf-8")

    assert raw.endswith("\n"), (
        f"Rollout summary at {SUMMARY_FILE} should be pretty-printed JSON ending with a newline."
    )
    assert "\n" in raw.strip(), (
        f"Rollout summary at {SUMMARY_FILE} should be pretty-printed across multiple lines, not minified."
    )

    summary = read_json(SUMMARY_FILE)
    current = read_json(CURRENT_FILE)

    assert list(summary.keys()) == EXPECTED_SUMMARY_KEYS, (
        f"Rollout summary at {SUMMARY_FILE} must contain exactly these top-level keys in order: "
        f"{EXPECTED_SUMMARY_KEYS!r}. Found: {list(summary.keys())!r}."
    )

    assert summary == EXPECTED_SUMMARY, (
        f"Rollout summary at {SUMMARY_FILE} does not match the required final summary derived from "
        f"{CURRENT_FILE}. It must show prod-eu values, not staging or archived legacy values."
    )

    expected_from_current = {
        "service": current["service"]["name"],
        "version": current["version"],
        "environment": current["environment"],
        "endpoint": current["service"]["endpoint"],
        "replicas": current["replicas"],
        "enabledFeatures": sorted(
            name for name, enabled in current["featureFlags"].items() if enabled is True
        ),
        "healthPath": current["healthCheck"]["path"],
        "sourceOfTruth": current["sourceOfTruth"],
    }
    assert summary == expected_from_current, (
        f"Rollout summary at {SUMMARY_FILE} is not derived from the final active manifest at "
        f"{CURRENT_FILE}."
    )

    assert summary["environment"] != "staging", (
        f"Rollout summary at {SUMMARY_FILE} still reports staging environment."
    )
    assert summary["endpoint"] != "https://orders.staging.internal.example", (
        f"Rollout summary at {SUMMARY_FILE} still reports the staging endpoint."
    )

def test_verification_log_has_exact_required_four_lines_with_trailing_newline():
    assert VERIFICATION_LOG.exists(), f"Verification log is missing: {VERIFICATION_LOG}"
    assert VERIFICATION_LOG.is_file(), f"Verification log path is not a regular file: {VERIFICATION_LOG}"

    actual = VERIFICATION_LOG.read_text(encoding="utf-8")
    assert actual == EXPECTED_VERIFICATION_LOG, (
        f"Verification log at {VERIFICATION_LOG} must contain exactly four required lines with a "
        "trailing newline:\n"
        f"{EXPECTED_VERIFICATION_LOG!r}\n"
        f"Found:\n{actual!r}"
    )


You’re helping an edge computing engineer do a quick connectivity diagnostic for an IoT deployment workspace.

There is a small inventory file at `/home/user/edge_diagnostics/device_inventory.txt`. It lists IoT device names and their management endpoints. Some commands you run may produce little or no terminal output, so do not assume the task is complete just because the shell is quiet.

Please create exactly one diagnostic report file at:

`/home/user/edge_diagnostics/reports/connectivity_report.txt`

The report must be plain UTF-8 text and must contain exactly 5 lines, in this exact order and format:

1. `EDGE CONNECTIVITY REPORT`
2. `Inventory: /home/user/edge_diagnostics/device_inventory.txt`
3. `Devices checked: N`
4. `Reachable: R`
5. `Unreachable: U`

Where:
- `N` is the total number of non-comment, non-blank device entries in `/home/user/edge_diagnostics/device_inventory.txt`.
- `R` is the number of those devices whose endpoint is reachable from the container.
- `U` is the number of those devices whose endpoint is not reachable from the container.
- `R + U` must equal `N`.

Inventory file format:
- Blank lines may appear and must be ignored.
- Lines beginning with `#` must be ignored.
- Valid device lines use this format: `device_name endpoint`
- The endpoint may be a hostname, IPv4 address, or loopback address.

Use a network diagnostic appropriate for checking whether each endpoint is reachable from this environment. After writing the report, run a verification step that confirms the file exists and that the three counts are internally consistent. The final answer should only be a brief confirmation that the report was created and verified; do not include command transcripts.

schema_version = "1.1"

[task]
name = "endless-terminals/task_000000_9feaaa5a"
description = "You\u2019re helping an edge computing engineer do a quick connectivity diagnostic for an IoT deployment workspace."
authors = [{ name = "Endless Terminals / Jarrod Barnes" }]
keywords = ["agentic-rl", "endless-terminals", "premature_stop_on_sparse_feedback", "stop_continue_calibration", "terminal-bench-2"]

[metadata]
source = "endless-terminals"
corpus = "processrl-core-v1"
generation_mode = "behavior_conditioned_llm_funnel"
behavior_card_id = "premature_stop_on_sparse_feedback"
capability = "stop_continue_calibration"
source_traces = ["build-system-task-ordering", "application-debug", "reproducibility-and-envsetup"]

[verifier]
timeout_sec = 300.0
user = "root"

[agent]
timeout_sec = 900.0
user = "user"

[environment]
build_timeout_sec = 900.0
os = "linux"
cpus = 2
memory_mb = 4096
storage_mb = 10240
gpus = 0
allow_internet = true

FROM ubuntu:22.04
SHELL ["/bin/bash", "-lc"]
RUN <<'__ENDLESS_DOCKER_POST__'
    set -eux

    apt-get update
    DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
        python3 \
        python3-pytest \
        iputils-ping \
        ca-certificates \
        netbase

    rm -rf /var/lib/apt/lists/*

    if ! id -u user >/dev/null 2>&1; then
        useradd -m -s /bin/bash user
    fi

    mkdir -p /home/user/edge_diagnostics/reports

    cat > /home/user/edge_diagnostics/device_inventory.txt <<'EOF'
# Edge IoT rollout inventory for lab pod B
# Format: device_name endpoint

gateway-alpha 127.0.0.1
sensor-temp-01 localhost
camera-yard-03 192.0.2.77

# Spare node currently offline
meter-east-09 198.51.100.42
EOF

    chown -R user:user /home/user/edge_diagnostics
    chmod 755 /home/user
    chmod 755 /home/user/edge_diagnostics
    chmod 755 /home/user/edge_diagnostics/reports
    chmod 644 /home/user/edge_diagnostics/device_inventory.txt

    if ! grep -Eq '^[[:space:]]*127\.0\.0\.1[[:space:]].*\blocalhost\b' /etc/hosts; then
        printf '127.0.0.1 localhost\n' >> /etc/hosts
    fi

chmod -R a+rwX /home/user
__ENDLESS_DOCKER_POST__
WORKDIR /home/user

# test_final_state.py
from pathlib import Path
import os
import re

REPORT_FILE = Path("/home/user/edge_diagnostics/reports/connectivity_report.txt")
INVENTORY_FILE = Path("/home/user/edge_diagnostics/device_inventory.txt")
REPORTS_DIR = Path("/home/user/edge_diagnostics/reports")

EXPECTED_LINES = [
    "EDGE CONNECTIVITY REPORT",
    "Inventory: /home/user/edge_diagnostics/device_inventory.txt",
    "Devices checked: 4",
    "Reachable: 2",
    "Unreachable: 2",
]

EXPECTED_CONTENT = "\n".join(EXPECTED_LINES) + "\n"

def _read_report_bytes():
    assert REPORT_FILE.exists(), (
        "Diagnostic report was not created. "
        f"Expected file at exactly: {REPORT_FILE}"
    )
    assert REPORT_FILE.is_file(), (
        "Diagnostic report path exists but is not a regular file. "
        f"Path checked: {REPORT_FILE}"
    )
    return REPORT_FILE.read_bytes()

def _read_report_text():
    data = _read_report_bytes()
    try:
        return data.decode("utf-8")
    except UnicodeDecodeError as exc:
        raise AssertionError(
            "Diagnostic report is not valid plain UTF-8 text. "
            f"Path checked: {REPORT_FILE}"
        ) from exc

def _parse_count_line(line, label):
    prefix = f"{label}: "
    assert line.startswith(prefix), (
        f"Report line for {label!r} has the wrong format. "
        f"Expected prefix {prefix!r}, got line {line!r}."
    )
    value_text = line[len(prefix):]
    assert re.fullmatch(r"\d+", value_text), (
        f"Report count for {label!r} must be a non-negative integer, "
        f"got {value_text!r} in line {line!r}."
    )
    return int(value_text)

def test_report_file_exists_at_exact_required_path():
    assert REPORTS_DIR.exists(), (
        f"Reports directory is missing: {REPORTS_DIR}. "
        "The final report cannot be considered complete without this directory."
    )
    assert REPORTS_DIR.is_dir(), (
        f"Reports path exists but is not a directory: {REPORTS_DIR}"
    )

    assert REPORT_FILE.exists(), (
        "The agent appears to have stopped before creating the required diagnostic report. "
        f"Missing file: {REPORT_FILE}"
    )
    assert REPORT_FILE.is_file(), (
        f"The required report path exists but is not a regular file: {REPORT_FILE}"
    )

def test_report_is_valid_utf8_plain_text_with_exactly_five_lines():
    text = _read_report_text()

    assert "\x00" not in text, (
        "Diagnostic report contains NUL bytes, so it is not plain text as required. "
        f"Path checked: {REPORT_FILE}"
    )

    lines = text.splitlines()
    assert len(lines) == 5, (
        "Diagnostic report must contain exactly 5 lines and no additional lines. "
        f"Found {len(lines)} line(s) in {REPORT_FILE}: {lines!r}"
    )

    assert text.endswith("\n") or text == "\n".join(EXPECTED_LINES), (
        "Diagnostic report must be plain text with exactly the required five logical lines; "
        "unexpected trailing data or line termination was found."
    )

def test_report_contents_match_required_final_deliverable_exactly():
    text = _read_report_text()
    lines = text.splitlines()

    assert lines == EXPECTED_LINES, (
        "Diagnostic report contents do not match the required final state exactly.\n"
        f"Path checked: {REPORT_FILE}\n"
        f"Expected lines: {EXPECTED_LINES!r}\n"
        f"Actual lines:   {lines!r}"
    )

def test_report_has_no_extra_leading_or_trailing_spaces_on_any_line():
    text = _read_report_text()
    lines = text.splitlines()

    for line_number, line in enumerate(lines, start=1):
        assert line == line.strip(" \t\r"), (
            f"Report line {line_number} has extra leading or trailing whitespace: {line!r}"
        )

def test_report_individual_lines_are_exactly_correct():
    text = _read_report_text()
    lines = text.splitlines()

    assert len(lines) == 5, (
        f"Cannot validate individual report lines because expected 5 lines, found {len(lines)}."
    )

    for index, expected in enumerate(EXPECTED_LINES, start=1):
        actual = lines[index - 1]
        assert actual == expected, (
            f"Report line {index} is incorrect.\n"
            f"Expected: {expected!r}\n"
            f"Actual:   {actual!r}"
        )

def test_report_counts_are_internally_consistent():
    text = _read_report_text()
    lines = text.splitlines()

    assert len(lines) == 5, (
        f"Cannot check count consistency because report must have exactly 5 lines, found {len(lines)}."
    )

    devices_checked = _parse_count_line(lines[2], "Devices checked")
    reachable = _parse_count_line(lines[3], "Reachable")
    unreachable = _parse_count_line(lines[4], "Unreachable")

    assert reachable + unreachable == devices_checked, (
        "Report counts are internally inconsistent: "
        f"Reachable ({reachable}) + Unreachable ({unreachable}) "
        f"does not equal Devices checked ({devices_checked})."
    )

    assert devices_checked == 4, (
        f"Devices checked count is wrong. Expected 4 valid inventory entries, got {devices_checked}."
    )
    assert reachable == 2, (
        f"Reachable count is wrong. Expected 2 reachable endpoints, got {reachable}."
    )
    assert unreachable == 2, (
        f"Unreachable count is wrong. Expected 2 unreachable endpoints, got {unreachable}."
    )

def test_inventory_still_exists_and_supports_expected_counts():
    assert INVENTORY_FILE.exists(), (
        f"Inventory file is missing after task completion: {INVENTORY_FILE}"
    )
    assert INVENTORY_FILE.is_file(), (
        f"Inventory path is not a regular file after task completion: {INVENTORY_FILE}"
    )
    assert os.access(INVENTORY_FILE, os.R_OK), (
        f"Inventory file is not readable after task completion: {INVENTORY_FILE}"
    )

    try:
        inventory_text = INVENTORY_FILE.read_text(encoding="utf-8")
    except UnicodeDecodeError as exc:
        raise AssertionError(
            f"Inventory file is not valid UTF-8 after task completion: {INVENTORY_FILE}"
        ) from exc

    entries = [
        line.split()
        for line in inventory_text.splitlines()
        if line.strip() and not line.lstrip().startswith("#")
    ]

    expected_entries = [
        ["gateway-alpha", "127.0.0.1"],
        ["sensor-temp-01", "localhost"],
        ["camera-yard-03", "192.0.2.77"],
        ["meter-east-09", "198.51.100.42"],
    ]

    assert entries == expected_entries, (
        "Inventory entries do not match the truth data used to compute the required report. "
        f"Expected {expected_entries!r}, found {entries!r}."
    )

#!/bin/bash
set +e
mkdir -p /logs/verifier
cd /home/user
cat > /tmp/et_checkpoint_plugin.py <<'PY'
import json
import os

_items = []
_outcomes = {}

def pytest_collection_modifyitems(session, config, items):
    global _items
    _items = [item.nodeid for item in items]

def pytest_runtest_logreport(report):
    if report.when not in ("setup", "call", "teardown"):
        return
    current = _outcomes.get(report.nodeid)
    if current == "failed":
        return
    if report.failed:
        _outcomes[report.nodeid] = "failed"
    elif report.skipped and current is None:
        _outcomes[report.nodeid] = "skipped"
    elif report.when == "call" and report.passed and current is None:
        _outcomes[report.nodeid] = "passed"

def pytest_sessionfinish(session, exitstatus):
    os.makedirs("/logs/verifier", exist_ok=True)
    tests = [
        {"nodeid": nodeid, "outcome": _outcomes.get(nodeid, "notrun")}
        for nodeid in _items
    ]
    with open("/logs/verifier/checkpoints.json", "w", encoding="utf-8") as handle:
        json.dump({"exitstatus": int(exitstatus), "tests": tests}, handle, sort_keys=True)
PY
PYTHONPATH=/tmp python3 -m pytest -q -p et_checkpoint_plugin /tests/test_final_state.py
rc=$?
printf '\n__ET_CHECKPOINTS__\n'
cat /logs/verifier/checkpoints.json 2>/dev/null || true
printf '\n__ET_CHECKPOINTS_END__\n'
if [ "$rc" -eq 0 ]; then
  echo 1 > /logs/verifier/reward.txt
else
  echo 0 > /logs/verifier/reward.txt
fi
exit 0

#!/bin/bash
# Oracle solution intentionally omitted for RL/eval packaging.
exit 1


You’re helping me set up a tiny Python utility project in `/home/user/dev/wordtools` using the standard library `venv` module. Please finish the project so it can be run from its virtual environment and so its output artifact is correct.

The project directory `/home/user/dev/wordtools` already exists and contains an input file at `/home/user/dev/wordtools/data/phrases.txt` plus a starter script at `/home/user/dev/wordtools/build_report.py`. Your job is to:

1. Create a Python virtual environment at exactly `/home/user/dev/wordtools/.venv`.
2. Use that virtual environment’s Python interpreter to run `/home/user/dev/wordtools/build_report.py`.
3. If the script’s run completes but the generated report is not semantically correct, fix `/home/user/dev/wordtools/build_report.py` and run it again with the virtual environment’s Python interpreter.
4. Create a verification log at exactly `/home/user/dev/wordtools/verification.log`.

The script must generate `/home/user/dev/wordtools/out/phrase_report.txt`.

The required report format is plain UTF-8 text with exactly these sections and line formats:

- First line: `Phrase Utility Report`
- Second line: `=====================`
- Third line: blank
- Then one line per non-empty input phrase, sorted alphabetically by the normalized phrase.
- Each phrase line must use exactly this format:
  `N. normalized phrase | words=W | chars=C`
  where:
  - `N` starts at 1 and increments by 1.
  - `normalized phrase` is the input phrase after trimming leading/trailing whitespace, converting to lowercase, and collapsing any internal run of whitespace to a single ASCII space.
  - `W` is the number of whitespace-separated words in the normalized phrase.
  - `C` is the number of characters in the normalized phrase, including single spaces between words.
- After the phrase lines, add one blank line.
- Then add exactly these summary lines:
  - `Total phrases: X`
  - `Total words: Y`
  - `Longest phrase: Z`
  where `X` is the number of non-empty normalized phrases, `Y` is the sum of the word counts, and `Z` is the normalized phrase with the greatest character count. If there is a tie, choose the alphabetically first normalized phrase among the tied phrases.
- The file must end with exactly one trailing newline.

Important: a clean exit from the script is not enough. Before you stop, inspect the generated `/home/user/dev/wordtools/out/phrase_report.txt` and confirm that it follows the rules above for the actual contents of `/home/user/dev/wordtools/data/phrases.txt`.

The verification log at `/home/user/dev/wordtools/verification.log` must be plain UTF-8 text and contain exactly four lines in this format:

1. `venv_python=/home/user/dev/wordtools/.venv/bin/python`
2. `report_path=/home/user/dev/wordtools/out/phrase_report.txt`
3. `report_valid=yes`
4. `verified_with=artifact_inspection`

Do not write anything else to the verification log.

schema_version = "1.1"

[task]
name = "endless-terminals/task_000000_c5466378"
description = "You\u2019re helping me set up a tiny Python utility project in `/home/user/dev/wordtools` using the standard library `venv` module. Please finish the project so it can be run from its virtual environment and so its output artifact is correct."
authors = [{ name = "Endless Terminals / Jarrod Barnes" }]
keywords = ["agentic-rl", "endless-terminals", "exit_code_false_success", "terminal-bench-2", "verification_directed_action"]

[metadata]
source = "endless-terminals"
corpus = "processrl-core-v1"
generation_mode = "behavior_conditioned_llm_funnel"
behavior_card_id = "exit_code_false_success"
capability = "verification_directed_action"
source_traces = ["book-portfolio-analysis", "pandas-numpy-data-analysis", "jsonl-aggregator", "csv-json-jsonl-merger"]

[verifier]
timeout_sec = 300.0
user = "root"

[agent]
timeout_sec = 900.0
user = "user"

[environment]
build_timeout_sec = 900.0
os = "linux"
cpus = 2
memory_mb = 4096
storage_mb = 10240
gpus = 0
allow_internet = true

FROM ubuntu:22.04
SHELL ["/bin/bash", "-lc"]
RUN <<'__ENDLESS_DOCKER_POST__'
    set -eux

    apt-get update
    DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
        python3 \
        python3-venv \
        python3-pip \
        python3-pytest \
        ca-certificates

    python3 -m pip install --no-cache-dir --upgrade pip
    python3 -m pip install --no-cache-dir pytest

    useradd -m -s /bin/bash user || true

    mkdir -p /home/user/dev/wordtools/data

    cat > /home/user/dev/wordtools/data/phrases.txt <<'EOF'
  Quick   brown   fox
alpha beta
Gamma    rays
one
two  spaces
ALPHA   beta

quiet night sky
EOF

    cat > /home/user/dev/wordtools/build_report.py <<'EOF'
from pathlib import Path

BASE = Path(__file__).resolve().parent
INPUT = BASE / "data" / "phrases.txt"
OUTPUT = BASE / "out" / "phrase_report.txt"

def normalize(line: str) -> str:
    # Starter implementation: trims and lowercases, but does not collapse
    # internal whitespace. It also keeps blank lines out by caller logic.
    return line.strip().lower()

def main() -> None:
    OUTPUT.parent.mkdir(parents=True, exist_ok=True)

    phrases = []
    for raw in INPUT.read_text(encoding="utf-8").splitlines():
        phrase = normalize(raw)
        if phrase:
            phrases.append(phrase)

    phrases.sort()

    lines = [
        "Phrase Utility Report",
        "=====================",
        "",
    ]

    total_words = 0
    longest_phrase = ""

    for index, phrase in enumerate(phrases, start=1):
        words = len(phrase.split())
        chars = len(phrase)
        total_words += words
        if chars > len(longest_phrase):
            longest_phrase = phrase
        lines.append(f"{index}. {phrase} | words={words} | chars={chars}")

    lines.append("")
    lines.append(f"Total phrases: {len(phrases)}")
    lines.append(f"Total words: {total_words}")
    lines.append(f"Longest phrase: {longest_phrase}")

    OUTPUT.write_text("\n".join(lines) + "\n", encoding="utf-8")

if __name__ == "__main__":
    main()
EOF

    chown -R user:user /home/user/dev
    chmod -R u+rwX,go+rwX /home/user/dev/wordtools

    apt-get clean
    rm -rf /var/lib/apt/lists/*

chmod -R a+rwX /home/user
__ENDLESS_DOCKER_POST__
WORKDIR /home/user

# test_final_state.py
from pathlib import Path
import os
import stat
import subprocess
import sys

PROJECT = Path("/home/user/dev/wordtools")
VENV_DIR = Path("/home/user/dev/wordtools/.venv")
VENV_PYTHON = Path("/home/user/dev/wordtools/.venv/bin/python")
PHRASES = Path("/home/user/dev/wordtools/data/phrases.txt")
SCRIPT = Path("/home/user/dev/wordtools/build_report.py")
REPORT = Path("/home/user/dev/wordtools/out/phrase_report.txt")
VERIFICATION_LOG = Path("/home/user/dev/wordtools/verification.log")

EXPECTED_REPORT_BYTES = (
    b"Phrase Utility Report\n"
    b"=====================\n"
    b"\n"
    b"1. alpha beta | words=2 | chars=10\n"
    b"2. alpha beta | words=2 | chars=10\n"
    b"3. gamma rays | words=2 | chars=10\n"
    b"4. one | words=1 | chars=3\n"
    b"5. quick brown fox | words=3 | chars=15\n"
    b"6. quiet night sky | words=3 | chars=15\n"
    b"7. two spaces | words=2 | chars=10\n"
    b"\n"
    b"Total phrases: 7\n"
    b"Total words: 15\n"
    b"Longest phrase: quick brown fox\n"
)

EXPECTED_VERIFICATION_LOG_BYTES = (
    b"venv_python=/home/user/dev/wordtools/.venv/bin/python\n"
    b"report_path=/home/user/dev/wordtools/out/phrase_report.txt\n"
    b"report_valid=yes\n"
    b"verified_with=artifact_inspection\n"
)

EXPECTED_PHRASES_CONTENT = (
    "  Quick   brown   fox\n"
    "alpha beta\n"
    "Gamma    rays\n"
    "one\n"
    "two  spaces\n"
    "ALPHA   beta\n"
    "\n"
    "quiet night sky\n"
)

def read_bytes(path: Path) -> bytes:
    try:
        return path.read_bytes()
    except OSError as exc:
        raise AssertionError(f"Could not read required file {path}: {exc}") from exc

def assert_valid_utf8(path: Path) -> str:
    data = read_bytes(path)
    try:
        return data.decode("utf-8")
    except UnicodeDecodeError as exc:
        raise AssertionError(f"File is not valid UTF-8: {path}") from exc

def explain_byte_difference(actual: bytes, expected: bytes, path: Path) -> str:
    try:
        actual_text = actual.decode("utf-8")
    except UnicodeDecodeError:
        actual_text = repr(actual)

    try:
        expected_text = expected.decode("utf-8")
    except UnicodeDecodeError:
        expected_text = repr(expected)

    return (
        f"{path} does not match the exact expected final content.\n"
        f"Expected bytes length: {len(expected)}; actual bytes length: {len(actual)}.\n"
        f"Expected content:\n{expected_text!r}\n"
        f"Actual content:\n{actual_text!r}"
    )

def test_virtual_environment_exists_with_executable_python():
    assert VENV_DIR.exists(), (
        f"Virtual environment directory is missing: {VENV_DIR}. "
        "Create it with the standard library venv module at exactly this path."
    )
    assert VENV_DIR.is_dir(), (
        f"Virtual environment path exists but is not a directory: {VENV_DIR}"
    )

    assert VENV_PYTHON.exists(), (
        f"Virtual environment Python interpreter is missing: {VENV_PYTHON}"
    )
    assert VENV_PYTHON.is_file(), (
        f"Virtual environment Python path exists but is not a file: {VENV_PYTHON}"
    )
    assert os.access(VENV_PYTHON, os.X_OK), (
        f"Virtual environment Python interpreter is not executable: {VENV_PYTHON}"
    )

    mode = VENV_PYTHON.stat().st_mode
    assert mode & (stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH), (
        f"Virtual environment Python lacks executable permission bits: {VENV_PYTHON}"
    )

def test_venv_python_can_run_basic_python_code():
    assert VENV_PYTHON.exists(), f"Cannot run missing venv Python: {VENV_PYTHON}"
    assert os.access(VENV_PYTHON, os.X_OK), f"Cannot execute venv Python: {VENV_PYTHON}"

    result = subprocess.run(
        [str(VENV_PYTHON), "-c", "import sys; print(sys.prefix); print(sys.executable)"],
        text=True,
        stdout=subprocess.PIPE,
        stderr=subprocess.PIPE,
        timeout=10,
    )

    assert result.returncode == 0, (
        f"The virtual environment Python failed to execute a simple command.\n"
        f"Command: {VENV_PYTHON} -c 'import sys; ...'\n"
        f"stdout:\n{result.stdout}\n"
        f"stderr:\n{result.stderr}"
    )
    assert str(VENV_DIR) in result.stdout, (
        "The Python interpreter at .venv/bin/python does not appear to use the "
        f"expected virtual environment prefix {VENV_DIR}.\nstdout:\n{result.stdout}"
    )

def test_original_input_file_still_has_expected_content():
    assert PHRASES.exists(), f"Required input file is missing: {PHRASES}"
    assert PHRASES.is_file(), f"Required input path exists but is not a file: {PHRASES}"

    actual = assert_valid_utf8(PHRASES)
    assert actual == EXPECTED_PHRASES_CONTENT, (
        "The input phrases file was changed, but the task required generating the "
        f"report from the existing input data. Wrong file: {PHRASES}"
    )

def test_build_report_script_exists_and_contains_normalization_fix():
    assert SCRIPT.exists(), f"Required script is missing: {SCRIPT}"
    assert SCRIPT.is_file(), f"Required script path exists but is not a file: {SCRIPT}"

    script_text = assert_valid_utf8(SCRIPT)

    assert "split()" in script_text and "join" in script_text, (
        "build_report.py does not appear to collapse internal whitespace runs. "
        "The normalization/data-processing logic must trim, lowercase, and collapse "
        "whitespace, e.g. using ' '.join(...split())."
    )
    assert ".lower()" in script_text, (
        "build_report.py does not appear to lowercase phrases during normalization."
    )
    assert "phrase_report.txt" in script_text, (
        "build_report.py should generate /home/user/dev/wordtools/out/phrase_report.txt."
    )

def test_generated_report_exists_as_file_and_is_utf8():
    assert REPORT.exists(), (
        f"Generated report is missing: {REPORT}. "
        "Run build_report.py with /home/user/dev/wordtools/.venv/bin/python."
    )
    assert REPORT.is_file(), f"Report path exists but is not a file: {REPORT}"
    assert_valid_utf8(REPORT)

def test_generated_report_matches_expected_content_byte_for_byte():
    assert REPORT.exists(), f"Generated report is missing: {REPORT}"
    actual = read_bytes(REPORT)

    assert actual == EXPECTED_REPORT_BYTES, explain_byte_difference(
        actual, EXPECTED_REPORT_BYTES, REPORT
    )

    assert actual.endswith(b"\n"), f"Report must end with exactly one trailing newline: {REPORT}"
    assert not actual.endswith(b"\n\n"), (
        f"Report must end with exactly one trailing newline, not extra blank lines: {REPORT}"
    )

def test_report_does_not_have_starter_script_uncollapsed_whitespace_failures():
    assert REPORT.exists(), f"Generated report is missing: {REPORT}"
    report_text = assert_valid_utf8(REPORT)

    forbidden_fragments = [
        "quick   brown   fox",
        "gamma    rays",
        "two  spaces",
        "alpha   beta",
        "chars=19",
        "chars=14",
        "chars=11",
        "chars=12",
    ]
    for fragment in forbidden_fragments:
        assert fragment not in report_text, (
            "Report still contains evidence of the starter script's incorrect "
            f"uncollapsed-whitespace behavior: found {fragment!r} in {REPORT}"
        )

def test_report_semantics_are_correct_for_actual_input_file():
    assert PHRASES.exists(), f"Input file is missing: {PHRASES}"
    assert REPORT.exists(), f"Report file is missing: {REPORT}"

    raw_lines = assert_valid_utf8(PHRASES).splitlines()
    normalized = [" ".join(line.strip().lower().split()) for line in raw_lines]
    phrases = sorted(phrase for phrase in normalized if phrase)

    expected_phrase_lines = [
        f"{index}. {phrase} | words={len(phrase.split())} | chars={len(phrase)}"
        for index, phrase in enumerate(phrases, start=1)
    ]
    total_words = sum(len(phrase.split()) for phrase in phrases)
    longest_phrase = min(
        (phrase for phrase in phrases if len(phrase) == max(map(len, phrases))),
        default="",
    )

    report_lines = assert_valid_utf8(REPORT).splitlines()
    expected_lines = (
        ["Phrase Utility Report", "=====================", ""]
        + expected_phrase_lines
        + [
            "",
            f"Total phrases: {len(phrases)}",
            f"Total words: {total_words}",
            f"Longest phrase: {longest_phrase}",
        ]
    )

    assert report_lines == expected_lines, (
        "Report is not semantically correct for the actual contents of "
        f"{PHRASES}. It must normalize whitespace, preserve duplicates, sort after "
        "normalization, compute word/character counts, and choose the longest phrase "
        "with alphabetical tie-breaking."
    )

def test_verification_log_exists_as_exact_utf8_file():
    assert VERIFICATION_LOG.exists(), (
        f"Verification log is missing: {VERIFICATION_LOG}"
    )
    assert VERIFICATION_LOG.is_file(), (
        f"Verification log path exists but is not a file: {VERIFICATION_LOG}"
    )
    assert_valid_utf8(VERIFICATION_LOG)

    actual = read_bytes(VERIFICATION_LOG)
    assert actual == EXPECTED_VERIFICATION_LOG_BYTES, explain_byte_difference(
        actual, EXPECTED_VERIFICATION_LOG_BYTES, VERIFICATION_LOG
    )

    assert actual.endswith(b"\n"), (
        f"Verification log must end with exactly one trailing newline: {VERIFICATION_LOG}"
    )
    assert not actual.endswith(b"\n\n"), (
        "Verification log must contain exactly four lines and one final newline, "
        f"with no extra blank lines: {VERIFICATION_LOG}"
    )

def test_verification_log_declares_artifact_inspection_success():
    assert VERIFICATION_LOG.exists(), f"Verification log is missing: {VERIFICATION_LOG}"
    lines = assert_valid_utf8(VERIFICATION_LOG).splitlines()

    assert lines == [
        "venv_python=/home/user/dev/wordtools/.venv/bin/python",
        "report_path=/home/user/dev/wordtools/out/phrase_report.txt",
        "report_valid=yes",
        "verified_with=artifact_inspection",
    ], (
        "verification.log must contain exactly the four required lines and must "
        "record report_valid=yes and verified_with=artifact_inspection."
    )


You are helping a technical writer organize a small SQLite-backed documentation inventory.

The database already exists at:

`/home/user/docs_work/docs.sqlite`

It contains a table named `doc_pages` with these columns:

- `slug`
- `title`
- `section`
- `status`
- `word_count`
- `updated_at`

Please do the following using terminal database operations:

1. Inspect the database enough to determine which documentation pages are publishable. A page is publishable when its `status` value means `ready`, but the database may contain inconsistent capitalization or surrounding whitespace in that field. Do not rely on only one exact spelling.

2. Normalize the database so that every publishable page has `status` stored exactly as:

`ready`

3. Create a tab-separated manifest file at:

`/home/user/docs_work/publish_manifest.tsv`

The file must have this exact header line:

`section	slug	title	word_count`

After the header, include one row for each publishable page only. The columns must be in this exact order:

`section`, `slug`, `title`, `word_count`

The rows must be sorted by `section` ascending, then `slug` ascending. Use literal tab characters between fields. Do not quote fields.

4. Create a verification log at:

`/home/user/docs_work/manifest_check.log`

The log must contain exactly three lines in this format:

`manifest_rows=<number of data rows in /home/user/docs_work/publish_manifest.tsv, excluding the header>`
`normalized_ready_rows=<number of rows in doc_pages whose status is exactly ready after normalization>`
`generated_at=<UTC timestamp in ISO-8601 format ending with Z>`

Example timestamp format:

`2026-05-30T14:25:00Z`

Before finishing, verify that the manifest row count and the normalized database row count agree. If an update or export appears to change nothing, do not keep retrying the same operation; inspect the unchanged state and use a different database condition or query formulation that accounts for the dirty status values.

schema_version = "1.1"

[task]
name = "endless-terminals/task_000000_f921854f"
description = "You are helping a technical writer organize a small SQLite-backed documentation inventory."
authors = [{ name = "Endless Terminals / Jarrod Barnes" }]
keywords = ["agentic-rl", "endless-terminals", "recognition_to_action_coupling", "repeat_loop_after_dead_end", "terminal-bench-2"]

[metadata]
source = "endless-terminals"
corpus = "processrl-core-v1"
generation_mode = "behavior_conditioned_llm_funnel"
behavior_card_id = "repeat_loop_after_dead_end"
capability = "recognition_to_action_coupling"
source_traces = ["pgn-chess-repair-puzzles", "book-portfolio-analysis", "bash-log-processor-fix"]

[verifier]
timeout_sec = 300.0
user = "root"

[agent]
timeout_sec = 900.0
user = "user"

[environment]
build_timeout_sec = 900.0
os = "linux"
cpus = 2
memory_mb = 4096
storage_mb = 10240
gpus = 0
allow_internet = true

FROM ubuntu:22.04
SHELL ["/bin/bash", "-lc"]
RUN <<'__ENDLESS_DOCKER_POST__'
    set -eux

    apt-get update
    DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
        python3 \
        python3-pip \
        sqlite3 \
        ca-certificates

    python3 -m pip install --no-cache-dir pytest

    mkdir -p /home/user/docs_work

    python3 - <<'PY'
import sqlite3
from pathlib import Path

db_path = Path("/home/user/docs_work/docs.sqlite")
if db_path.exists():
    db_path.unlink()

conn = sqlite3.connect(str(db_path))
cur = conn.cursor()

cur.execute("""
CREATE TABLE doc_pages (
    slug TEXT PRIMARY KEY,
    title TEXT NOT NULL,
    section TEXT NOT NULL,
    status TEXT NOT NULL,
    word_count INTEGER NOT NULL,
    updated_at TEXT NOT NULL
);
""")

rows = [
    ('api-authentication', 'Authentication API', 'API', ' Ready', 1240, '2026-02-03'),
    ('api-errors', 'Error Handling', 'API', 'READY', 860, '2026-02-11'),
    ('api-pagination', 'Pagination Parameters', 'API', 'ready ', 730, '2026-02-15'),
    ('cli-install', 'Installing the CLI', 'CLI', 'draft', 910, '2026-01-22'),
    ('cli-quickstart', 'CLI Quickstart', 'CLI', 'ready', 680, '2026-02-01'),
    ('concepts-indexing', 'Indexing Concepts', 'Concepts', 'review', 1180, '2026-01-29'),
    ('concepts-search', 'Search Concepts', 'Concepts', ' ready ', 1430, '2026-02-07'),
    ('tutorial-first-project', 'Create Your First Project', 'Tutorials', 'Ready', 1560, '2026-02-10'),
]

cur.executemany("""
INSERT INTO doc_pages (slug, title, section, status, word_count, updated_at)
VALUES (?, ?, ?, ?, ?, ?)
""", rows)

conn.commit()
conn.close()
PY

    rm -f /home/user/docs_work/publish_manifest.tsv
    rm -f /home/user/docs_work/manifest_check.log

    chmod 777 /home/user
    chmod 777 /home/user/docs_work
    chmod 666 /home/user/docs_work/docs.sqlite

chmod -R a+rwX /home/user
__ENDLESS_DOCKER_POST__
WORKDIR /home/user

# test_final_state.py
import re
import sqlite3
from pathlib import Path

import pytest

DOCS_WORK = Path("/home/user/docs_work")
DB_PATH = Path("/home/user/docs_work/docs.sqlite")
MANIFEST_PATH = Path("/home/user/docs_work/publish_manifest.tsv")
LOG_PATH = Path("/home/user/docs_work/manifest_check.log")

EXPECTED_READY_SLUGS = [
    "api-authentication",
    "api-errors",
    "api-pagination",
    "cli-quickstart",
    "concepts-search",
    "tutorial-first-project",
]

EXPECTED_NON_READY = [
    ("cli-install", "draft"),
    ("concepts-indexing", "review"),
]

EXPECTED_MANIFEST_TEXT = (
    "section\tslug\ttitle\tword_count\n"
    "API\tapi-authentication\tAuthentication API\t1240\n"
    "API\tapi-errors\tError Handling\t860\n"
    "API\tapi-pagination\tPagination Parameters\t730\n"
    "CLI\tcli-quickstart\tCLI Quickstart\t680\n"
    "Concepts\tconcepts-search\tSearch Concepts\t1430\n"
    "Tutorials\ttutorial-first-project\tCreate Your First Project\t1560\n"
)

EXPECTED_MANIFEST_ROWS = [
    ("API", "api-authentication", "Authentication API", "1240"),
    ("API", "api-errors", "Error Handling", "860"),
    ("API", "api-pagination", "Pagination Parameters", "730"),
    ("CLI", "cli-quickstart", "CLI Quickstart", "680"),
    ("Concepts", "concepts-search", "Search Concepts", "1430"),
    ("Tutorials", "tutorial-first-project", "Create Your First Project", "1560"),
]

def connect_db():
    assert DB_PATH.exists(), f"Required SQLite database is missing: {DB_PATH}"
    assert DB_PATH.is_file(), f"Database path exists but is not a regular file: {DB_PATH}"
    try:
        return sqlite3.connect(str(DB_PATH))
    except sqlite3.Error as exc:
        pytest.fail(f"Could not open SQLite database at {DB_PATH}: {exc}")

def read_bytes(path: Path) -> bytes:
    assert path.exists(), f"Required file is missing: {path}"
    assert path.is_file(), f"Required path exists but is not a regular file: {path}"
    try:
        return path.read_bytes()
    except OSError as exc:
        pytest.fail(f"Could not read required file {path}: {exc}")

def test_database_publishable_rows_are_normalized_to_exact_ready():
    with connect_db() as conn:
        rows = conn.execute(
            """
            SELECT slug, status
            FROM doc_pages
            ORDER BY slug
            """
        ).fetchall()

    status_by_slug = dict(rows)

    missing_slugs = [slug for slug in EXPECTED_READY_SLUGS if slug not in status_by_slug]
    assert not missing_slugs, (
        "The database is missing expected publishable doc_pages rows: "
        f"{missing_slugs!r}"
    )

    wrong_ready_statuses = [
        (slug, status_by_slug[slug])
        for slug in EXPECTED_READY_SLUGS
        if status_by_slug[slug] != "ready"
    ]
    assert wrong_ready_statuses == [], (
        "All publishable pages must have status stored exactly as 'ready' after "
        "normalization. These publishable rows are still wrong: "
        f"{wrong_ready_statuses!r}"
    )

    ready_count = sum(1 for _slug, status in rows if status == "ready")
    assert ready_count == 6, (
        "The database must contain exactly six rows with status exactly 'ready' "
        f"after normalization; found {ready_count}."
    )

def test_database_non_publishable_rows_remain_draft_and_review():
    with connect_db() as conn:
        non_ready_rows = conn.execute(
            """
            SELECT slug, status
            FROM doc_pages
            WHERE status <> 'ready'
            ORDER BY slug
            """
        ).fetchall()
        total_count = conn.execute("SELECT COUNT(*) FROM doc_pages").fetchone()[0]

    assert total_count == 8, (
        "The doc_pages table should still contain exactly the original eight rows; "
        f"found {total_count}. Rows should not be deleted to make the manifest pass."
    )
    assert non_ready_rows == EXPECTED_NON_READY, (
        "Only the two non-publishable pages should remain non-ready, with their "
        "original statuses. Expected cli-install='draft' and "
        f"concepts-indexing='review'; found {non_ready_rows!r}."
    )

def test_no_dirty_publishable_status_values_remain():
    with connect_db() as conn:
        dirty_ready_rows = conn.execute(
            """
            SELECT slug, status
            FROM doc_pages
            WHERE lower(trim(status)) = 'ready'
              AND status <> 'ready'
            ORDER BY slug
            """
        ).fetchall()
        normalized_ready_count = conn.execute(
            """
            SELECT COUNT(*)
            FROM doc_pages
            WHERE lower(trim(status)) = 'ready'
            """
        ).fetchone()[0]

    assert dirty_ready_rows == [], (
        "Publishable rows were identified by normalized matching, but some still "
        "have dirty capitalization or surrounding whitespace instead of exact "
        f"'ready': {dirty_ready_rows!r}"
    )
    assert normalized_ready_count == 6, (
        "There must be exactly six publishable rows according to "
        "lower(trim(status)) = 'ready'; found "
        f"{normalized_ready_count}."
    )

def test_manifest_file_exists_is_utf8_uses_unix_newlines_and_matches_exact_contents():
    data = read_bytes(MANIFEST_PATH)

    assert b"\r" not in data, (
        f"{MANIFEST_PATH} must use Unix newlines only; carriage return bytes were found."
    )

    try:
        text = data.decode("utf-8")
    except UnicodeDecodeError as exc:
        pytest.fail(f"{MANIFEST_PATH} is not valid UTF-8 text: {exc}")

    assert text == EXPECTED_MANIFEST_TEXT, (
        f"{MANIFEST_PATH} contents are not exactly the required tab-separated "
        "manifest sorted by section ascending, then slug ascending. Expected:\n"
        f"{EXPECTED_MANIFEST_TEXT!r}\nFound:\n{text!r}"
    )

def test_manifest_has_exact_header_rows_tabs_and_no_extra_or_missing_rows():
    text = read_bytes(MANIFEST_PATH).decode("utf-8")
    lines = text.splitlines()

    assert len(lines) == 7, (
        f"{MANIFEST_PATH} must contain exactly 7 lines: one header plus six data "
        f"rows. Found {len(lines)} lines: {lines!r}"
    )

    assert lines[0] == "section\tslug\ttitle\tword_count", (
        "Manifest header must be exactly "
        "'section<TAB>slug<TAB>title<TAB>word_count'; "
        f"found {lines[0]!r}."
    )

    parsed_rows = [tuple(line.split("\t")) for line in lines[1:]]
    malformed_rows = [
        (index + 2, line)
        for index, line in enumerate(lines[1:])
        if len(line.split("\t")) != 4
    ]
    assert malformed_rows == [], (
        "Each manifest data row must contain exactly four unquoted tab-separated "
        f"fields. Malformed rows: {malformed_rows!r}"
    )

    assert parsed_rows == EXPECTED_MANIFEST_ROWS, (
        "Manifest data rows must include only publishable pages, in columns "
        "section, slug, title, word_count, sorted by section then slug. "
        f"Expected {EXPECTED_MANIFEST_ROWS!r}; found {parsed_rows!r}."
    )

    manifest_slugs = [row[1] for row in parsed_rows]
    forbidden = {"cli-install", "concepts-indexing"} & set(manifest_slugs)
    assert not forbidden, (
        "Manifest must not include draft/review non-publishable pages; found "
        f"forbidden slugs {sorted(forbidden)!r}."
    )

def test_manifest_matches_database_ready_rows_exactly():
    text = read_bytes(MANIFEST_PATH).decode("utf-8")
    manifest_rows = [tuple(line.split("\t")) for line in text.splitlines()[1:]]

    with connect_db() as conn:
        db_rows = conn.execute(
            """
            SELECT section, slug, title, CAST(word_count AS TEXT)
            FROM doc_pages
            WHERE status = 'ready'
            ORDER BY section ASC, slug ASC
            """
        ).fetchall()

    assert manifest_rows == db_rows, (
        "The manifest rows must exactly match the database rows whose status is "
        "exactly 'ready', ordered by section ascending then slug ascending. "
        f"Manifest rows: {manifest_rows!r}; database ready rows: {db_rows!r}."
    )

def test_verification_log_exists_has_three_lines_and_required_format():
    data = read_bytes(LOG_PATH)

    assert b"\r" not in data, (
        f"{LOG_PATH} must use Unix newlines only; carriage return bytes were found."
    )

    try:
        text = data.decode("utf-8")
    except UnicodeDecodeError as exc:
        pytest.fail(f"{LOG_PATH} is not valid UTF-8 text: {exc}")

    assert text.endswith("\n"), f"{LOG_PATH} should end with a Unix newline."
    lines = text.splitlines()

    assert len(lines) == 3, (
        f"{LOG_PATH} must contain exactly three lines; found {len(lines)} lines: "
        f"{lines!r}"
    )
    assert lines[0] == "manifest_rows=6", (
        "First log line must be exactly 'manifest_rows=6'; "
        f"found {lines[0]!r}."
    )
    assert lines[1] == "normalized_ready_rows=6", (
        "Second log line must be exactly 'normalized_ready_rows=6'; "
        f"found {lines[1]!r}."
    )
    assert re.fullmatch(
        r"generated_at=[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}Z",
        lines[2],
    ), (
        "Third log line must be a UTC ISO-8601 timestamp in the form "
        "'generated_at=YYYY-MM-DDTHH:MM:SSZ'; "
        f"found {lines[2]!r}."
    )

def test_log_counts_agree_with_manifest_and_database_final_state():
    log_text = read_bytes(LOG_PATH).decode("utf-8")
    log_lines = log_text.splitlines()

    manifest_text = read_bytes(MANIFEST_PATH).decode("utf-8")
    manifest_lines = manifest_text.splitlines()
    manifest_data_row_count = max(len(manifest_lines) - 1, 0)

    with connect_db() as conn:
        exact_ready_count = conn.execute(
            "SELECT COUNT(*) FROM doc_pages WHERE status = 'ready'"
        ).fetchone()[0]
        normalized_ready_count = conn.execute(
            "SELECT COUNT(*) FROM doc_pages WHERE lower(trim(status)) = 'ready'"
        ).fetchone()[0]

    assert log_lines[0] == f"manifest_rows={manifest_data_row_count}", (
        "The verification log's manifest_rows value must equal the number of "
        "manifest data rows excluding the header. "
        f"Log line: {log_lines[0]!r}; actual manifest data rows: "
        f"{manifest_data_row_count}."
    )
    assert log_lines[1] == f"normalized_ready_rows={normalized_ready_count}", (
        "The verification log's normalized_ready_rows value must equal the number "
        "of database rows satisfying lower(trim(status)) = 'ready'. "
        f"Log line: {log_lines[1]!r}; actual normalized ready rows: "
        f"{normalized_ready_count}."
    )
    assert manifest_data_row_count == exact_ready_count == normalized_ready_count == 6, (
        "Final database, manifest, and log must all agree that there are exactly "
        "six publishable pages. Found manifest data rows="
        f"{manifest_data_row_count}, exact ready rows={exact_ready_count}, "
        f"normalized ready rows={normalized_ready_count}."
    )