# Verify a host

## For humans

**Run this on** a first setup, a fresh clone, a new machine, or after somebody changed the deploy.
**Skip it as** a daily ritual. It does not replace your own tests.

### Do this

1. Start at [step 1, the CLI can see your project](#1-the-cli-can-see-your-project).
2. Work down. Eight commands, in order.
3. Stop at the first red result and read the page that step names.

### The order matters

- **Each step assumes the ones above it passed.** A confusing failure near the bottom is usually a
  quiet failure near the top that nobody looked at.
- **Do not jump to the step that resembles your symptom.** Starting from the top costs two minutes
  and saves an hour.

### The two that pay for the page

- **[Step 1](#1-the-cli-can-see-your-project)** tells you which project the CLI is talking to. That
  is the difference between a sync and an accident.
- **[Step 4](#4-every-java-unit-compiles-against-the-packaged-application)** compiles every Java unit
  against the real packaged application, before anything boots.

### If a step fails

- [If something failed](#if-something-failed) hands you the full [Failure catalogue](/failures).

## For robots

The commands that prove a host is wired correctly, in order. Run them top to bottom. Each one
checks a single thing and tells you which page explains the failure.

Do not skip ahead. Every step assumes the ones above it passed, and a failure three steps down is
usually a failure one step up that nobody checked.

## 1. The CLI can see your project

```bash
interlock whoami
```

Prints the account, the project and the server the CLI is pointed at. If the project is not the one
you expect, you are about to sync into somebody else's tree. Stop and read
[Operating a project](/operating#interlock-key-binds-a-tree-to-a-project).

Confirm the key file is where you think it is:

```bash
ls -la .interlock-key && head -c 8 .interlock-key && echo
```

Never print more than the first 8 characters. The whole file is a credential.

## 2. The tree and the server agree

```bash
interlock sync code --dry
```

A dry run lists what WOULD change and touches nothing. On a clean tree it should report no changes.
If it proposes deleting every unit you have, the CLI is authenticated against a different project.
That is the failure described in
[Operating a project](/operating#interlock-key-binds-a-tree-to-a-project).

## 3. No unresolved conflicts

```bash
find code -name '*.conflict-server'
```

Empty output, or you have unresolved conflicts. Resolve them deliberately with `--ours <id>` or
`--theirs <id>`. If you are an agent: do not resolve these on the human's behalf without being
asked.

## 4. Every Java unit compiles against the PACKAGED application

This is the two-second gate, and it is the highest-value check on the page. It compiles every unit
against the real packaged classpath, transformed jar first, before anything boots.

```bash
./scripts/check-units-compile.sh
```

The script is on the [Testing page](/testing#the-two-second-gate), ready to copy. Run it in CI and
as a pre-commit hook.

Failures here are almost always the entity rule:

```
error: status has protected access in Presence
```

That means the entity has no hand-written accessor. `Presence` is the entity of the real host
application this was measured on (Team Lakes); yours will name your own class. See
[the entity rule](/quarkus#the-entity-rule).

## 5. Package the host and boot it

```bash
./gradlew build -x test
```

Package before checking anything entity-related. `quarkusDev` transforms bytecode in memory and
writes no jar, so a unit that touches an entity behaves differently there. The SDK logs a one-time
boot WARN saying so. See [Quarkus](/quarkus#quarkusdev-is-unsupported-for-entity-touching-units).

## 6. A unit actually runs

```bash
interlock run <unit-id>
```

Runs it server-side and streams the logs back. If the unit has no handler you get the library-unit
refusal, which is correct behaviour for a library and explained on [The model](/units#library-units).

## 7. Assert an EFFECT, not a status code

The single most valuable test you can write against a host. A 200 proves the request was accepted,
not that it did anything:

```bash
curl -s -X POST "$HOST/app/reminders/mute" -H 'content-type: application/json' -d '{"minutes":30}'
curl -s "$HOST/app/reminders/state" | grep -q '"muted":true' && echo OK || echo FAILED
```

The second line is the test. The first one passed even when `req.str()` ignored request bodies
entirely, which is exactly how that bug survived. See
[Testing](/testing#assert-effects-not-status-codes).

## 8. Refusals answer with a status

```bash
curl -s -o /dev/null -w '%{http_code}\n' -X POST "$HOST/app/reminders/touch"
```

A unit that can only answer 200 turns every "no" into an apparent success. A refusal should come
back as its real status with `{"ok":false,"reason":...}`. See
[Refusal](/host#resultstatus-and-refusal).

## If something failed

Go to the [Failure catalogue](/failures) and search for your literal error text. Every entry is
symptom first.
