---
title: "Verification Checkpoints"
description: "Four separate checks for ZeyOS apps, what each one proves, and how each one can fail."
canonical_url: "https://www.zeyos.com/ixml/ixml-guide/development-environment/verification-checkpoints"
markdown_url: "https://www.zeyos.com/ai/guide/ixml/ixml-guide/development-environment/verification-checkpoints.md"
section: "ixml-guide"
authority: "guide"
language: "en"
source_repository: "zeyos/guide"
source_path: "docs/ixml/03-development-environment/verification-checkpoints.md"
source_revision: "cce886a8da98cd124ee3644711085bbdcf1a87ce"
---

# Verification Checkpoints

"It compiles" and "it works" are different claims. This page splits verification into four checkpoints, each with its own expected outcome. A pass at one checkpoint says nothing about the next. Record which ones you actually ran.

| Checkpoint | Needs | Proves | Does not prove |
| --- | --- | --- | --- |
| [1. Local inspection](#checkpoint-1-local-inspection) | Your files | Well-formed XML, names checked against the reference, consistent manifest | That the native compiler accepts the code |
| [2. Remote compilation](#checkpoint-2-remote-compilation) | Linked app, network, developer permission | The instance's compiler accepts the checked files | Any runtime behavior |
| [3. Deployment](#checkpoint-3-deployment) | Same, plus permission to change the instance | The instance holds the reviewed change set | That the code works in its context |
| [4. Runtime verification](#checkpoint-4-runtime-verification) | A sandbox and the real entry point | Observed behavior for the inputs you tried | Other inputs and production conditions |

## Checkpoint 1: local inspection

Nothing leaves your machine at this checkpoint.

**XML well-formedness.** This check is partial. It finds broken XML and nothing else.

```bash
xmllint --noout --nonet resources/Greeting.ixml
```

Expected outcome: exit status `0`. `xmllint` also prints `Namespace prefix ... is not defined` for commands such as `rest:server`, because iXML prefixes are not declared XML namespaces. These messages are expected. A parser error such as an unescaped `<` in an attribute is a real failure.

| Failure case | Result |
| --- | --- |
| Raw `<` in an attribute | `xmllint` fails. Escape it as `&lt;` |
| `<if condition="...">` | `xmllint` **passes**. The native parser rejects it, as logged on 6 February 2026. This is why the reference check below is required |
| Invented command such as `array:count` | `xmllint` **passes**. The native parser rejects it, as logged on 6 February 2026 |

**Reference lookup.** Look up every changed command in `ref/ixmldoc.xml`, including attributes, children, and result bindings. Check database identifiers in `ref/dbref.json` and weblet views in `ref/sdk/views.md`. [Coding Agents and Validation](https://www.zeyos.com/ixml/ixml-guide/development-environment/coding-agents#validate-parameters-and-structure) has the full checklist.

**Manifest and asset consistency.** For each manifest entry, confirm that:

- The file exists at `<class>/<key>.<extension>`, and the extension fits its `mimetype`.
- The `type` is on the SDK's list and uses the SDK's uppercase spelling.
- Hook services have an `entity`, and `TIMING` services have a `schedule` and `interval`.
- Each weblet's `view` exists in `ref/sdk/views.md`.
- Every `include` target exists in the same manifest, with the right `type` selector.
- Every `rest:resource` binds each global it reads with `use` as its first child. See [Bind globals inside `rest:resource`](https://www.zeyos.com/ixml/ixml-guide/development-environment/execution-contexts#bind-globals-inside-restresource).
- No secret appears in `defaultsettings.json` or any tracked file.

**What `zeysdk` checks offline.** `zeysdk --help`, `zeysdk <command> --help`, and `zeysdk version` work without a link. Local arguments are validated before a remote call, so `zeysdk add` and `zeysdk update` reject unknown types and unsafe paths. No SDK command compiles code offline.

## Checkpoint 2: remote compilation

`zeysdk compile` and `zeysdk lint` send your source to the linked instance's compiler and report the result. They do not execute the code, but they are **not offline**. They need a linked app, a valid token, developer permission, and network access. Confirm the instance is the one you intend, and that you may send it this source.

```bash
zeysdk whoami
zeysdk compile services/api.ixml
zeysdk compile --ixml '<output>Hello</output>'
zeysdk compile --zy 'return 1;'
zeysdk lint
zeysdk lint --all
```

`compile` takes a path or one inline source. `--zymba` is the long form of `--zy`. `lint` compiles the eligible scripts the app knows about. By default it selects only locally present scripts that differ from the last synchronized state. `--all` selects every locally present script, skipping the server comparison, but it still sends source.

Expected outcome: `compile` reports success, and `lint` prints `OK` for each file you meant to check, with a summary count. Record the file list. On failure both commands print the compiler message and exit nonzero.

| Failure case | Meaning |
| --- | --- |
| Lint prints `No modified iXML or Zymba files to lint.` or `No iXML or Zymba files found.` | **Not a pass.** Zero files were checked, and the exit status is still `0` |
| A script is missing from the lint list | It is not registered in the manifest. Register it, or compile it by path |
| `requires the zeysdk.sync.json file` or missing `id`/`url` | The app is not linked. Run `zeysdk link` |
| 401 or `Lacking developer permission` | Fix the token or the user's permission. This is not a code result |

**What compile cannot prove.** It checks the code you sent, on that instance's compiler. It does not show that database identifiers exist, that a handler's auth check cannot be forged, that an `include` target is deployed, that a settings key is present, that inputs are complete, that authorization is correct, or that the page renders. Runtime errors in dynamic values appear only at checkpoint 4.

## Checkpoint 3: deployment

`push` changes the instance. It does more than upload: a whole-project push makes the server match your working copy.

```bash
zeysdk whoami
zeysdk compare
zeysdk snapshot create "Before push"
zeysdk push --dry-run
zeysdk push
```

Expected outcome: the dry run names the application, instance, and URL, and lists every upload and every server deletion. You can explain each line. The real push then applies that plan, and a following `zeysdk compare` shows no unexpected drift.

- **Scope.** `zeysdk push services/api.ixml` plans only the named paths. Without paths the plan covers the whole project, including deletions.
- **Deletions.** A service, weblet, resource, or asset that exists on the server but not locally is deleted, even if this checkout never synchronized it.
- **`--keep-remote`** protects remote-only assets that have **no sync baseline** in this checkout. It does not protect every missing local asset. If this checkout synchronized an asset and you then removed it locally, a push still deletes it from the server.
- **`--force`** skips the confirmation prompt. It does not grant authorization, and it does not make the plan safer. Use it only after reviewing the same change set.
- **Dry run limits.** A dry run reads the server and may make read-only requests. The server does not lock, so a change made after the preview is not part of what you reviewed.
- **Snapshots** are local ZIP archives of project files. They restore your working copy, not the instance.

:::warning
Neither a snapshot nor a `sync.json` backup rolls back the server. Plan recovery before you push to a shared instance.
:::

| Failure case | Meaning |
| --- | --- |
| The plan deletes something you did not touch | Another developer's work, or a stale checkout. Stop and run `zeysdk compare`. Consider `--keep-remote` or a targeted push |
| The plan targets the wrong instance | Stop. Run `zeysdk use <instance>` |
| A push fails partway | Local recovery restores sync state only. Compare before retrying |

## Checkpoint 4: runtime verification

Test through the real entry point, on a sandbox, with bounded inputs. See [Execution Contexts](https://www.zeyos.com/ixml/ixml-guide/development-environment/execution-contexts) for why `zeysdk run` does not substitute for these.

| Context | How to test | Expected outcome | Failure cases to try |
| --- | --- | --- | --- |
| Weblet | Open the target view in a signed-in browser. Inspect the frame request in developer tools | Frame status 200 and the expected content | Signed-out user gets 401. User without access to a restricted app gets 403. Empty and hostile `$REQUEST` values stay safe |
| `REMOTECALL` | Send HTTP requests with `curl` | Valid access token gets 200 and the expected body | No token, an invalid token, an SDK token, and no token with a forged `?AUTH[user]=1` must all be rejected **by your handler**. A real token with forged arguments must keep its real identity. A 200 on any rejected case is a security failure |
| `TIMING` | Let the schedule fire on a sandbox, then inspect the data and log | One run, with expected effects | A rerun does not repeat completed work. A failed run is logged and the next run recovers |
| Entity hook | Create, change, or delete a real record through the UI or API | The expected change, and only for the intended records | A thrown error aborts the save. Non-matching records are untouched |

The three HTTP checks every protected service needs:

```bash
# Expected: 200
curl -i -H "Authorization: Bearer $ZEYOS_ACCESS_TOKEN" \
  "https://cloud.zeyos.com/<instance>/remotecall/example.minimal.api/greeting/Ada"

# Expected: 401 from your handler
curl -i \
  "https://cloud.zeyos.com/<instance>/remotecall/example.minimal.api/greeting/Ada"

# Expected: 401. A 200 means a request can forge AUTH.
curl -i -g \
  "https://cloud.zeyos.com/<instance>/remotecall/example.minimal.api/greeting/Ada?AUTH[user]=1"
```

`-g` stops `curl` from treating the brackets as a pattern. For a `POST` route, send the same field in the form body.

### Timeouts and uncertain completion

SDK requests time out after 30 seconds by default. Set `ZEYSDK_REQUEST_TIMEOUT_MS` to a positive integer to change this. The limit applies to the client's wait.

A disconnected client does not prove the server stopped. The script may still be running, or may already have finished. The SDK's request layer does not automatically resend a `run`, `compile`, or push request, and retries only reads. `zeysdk watch` is the exception: it keeps a failed batch and pushes it again with backoff, so stop it before you investigate. Outside `watch`, any repeat comes from you.

Before you retry after a timeout:

1. Treat the outcome as unknown, not failed.
2. Check the effects: records, sent mail, external calls, and the platform log.
3. Retry only what did not happen, and only if the operation is safe to repeat.

For work that may take longer, use a `TIMING` service with a resumable, time-bounded batch instead of raising the timeout.

## Record what you ran

Keep the date, revision, instance, checked file list, and result for each checkpoint. Mark any checkpoint you skipped as **not performed**. Never describe compiled code as runtime-validated.

## Related topics

- [Execution Contexts](https://www.zeyos.com/ixml/ixml-guide/development-environment/execution-contexts)
- [Minimal App](https://www.zeyos.com/ixml/ixml-guide/development-environment/minimal-app)
- [Troubleshooting](https://www.zeyos.com/ixml/ixml-guide/development-environment/troubleshooting)
- [SDK Workflow](https://www.zeyos.com/ixml/ixml-guide/development-environment/sdk)
- [Coding Agents and Validation](https://www.zeyos.com/ixml/ixml-guide/development-environment/coding-agents)
