# Task: use an office sales-report function from a second device

The user wants to submit a small sales CSV from their caller device and receive
a Markdown report produced by the provider device. Keep the business code on
the provider. Do not replace this with remote desktop or arbitrary shell access.
The requested handoff is a Mission.eal created on the provider and executed
by the caller's own Runtime. A Python smoke test alone does not finish this task.

## Files and the result to reproduce

If the user supplied the example files with these instructions, inspect them
locally. Otherwise ask for the case-page URL; copied instructions alone do not
identify a download origin. Resolve `/examples/office-report/` against that
user-provided URL to obtain `report.py`, `provider.py`, `caller.py`, `input.csv`,
`output.md`, `test_report.py`, `prepare_mission.py` and `test_prepare_mission.py`.
Do not guess a production domain. A localhost
preview URL on one device is not reachable from another device as localhost;
ask for an approved reachable source or transfer the inspected example files.
Use a new user-approved working directory; do not overwrite an existing
AGENTS.md or existing report. Inspect files before running.

The synthetic input has Notebook (3 × 1250 cents), Pen (10 × 250 cents), and
Folder (4 × 500 cents). The expected total is USD 82.50. Prices are already in
USD cents; this example does not calculate tax, refunds or currency conversion.
Product labels use ASCII letters, digits, spaces and `. _ -`, start with a
letter or digit, and have at most 60 characters. Quantity must be 1–10000 and
unit_price_cents 1–100000000. Reject extra columns, zero or negative values;
do not silently sanitize the user's data. Replacing Notebook's quantity with
0 must produce `quantity must be an integer between 1 and 10000` locally.

## Establish which device you are on

Ask whether this is the provider or caller if it is not known. Confirm the other
device, its operator and allowed test network. Never copy private keys, bearer
tokens or personal credentials between devices. Do not deploy to an unapproved
host, change firewalls, or expose real sales records without explicit permission.

Read local repository instructions and the installed CLI help. Use compatible
EasyRemote, EasyNet-Cli and EasyNet-Axon versions. Do not assume the installed
package exposes the same interfaces as an arbitrary source checkout.

## Provider device

1. In an isolated directory run
   `PYTHONDONTWRITEBYTECODE=1 python3 -m unittest test_report.py test_prepare_mission.py`.
   This verifies local calculation and file generation, not a remote connection.
2. Configure and pair the local Runtime using the version-matched official
   guide. Ask for missing user decisions; do not invent device IDs or authorities.
3. In the compatible EasyRemote environment run `python3 provider.py`. It
   registers `build_sales_report` under namespace `office_report`.
4. Keep the terminal open. Its `Local active` line contains the actual Ability
   URA; this does not yet prove the caller can discover it. In another terminal,
   read the provider's public identity with `easynet runtime status --json`
   (`pairing.device_ura`). Use these actual values, not a friendly device name:

   ```sh
   easynet ability show "$ABILITY_URA" --node "$PROVIDER_DEVICE_URA" --format json > descriptor.json
   ```

   Run this in the new working directory only. Inspect `name`, `owner_ura`,
   `ability_ura`, `descriptor_ref` and `input_schema` in the result. The name
   must be `office_report.build_sales_report`. Establish the permitted caller
   through the Runtime's authorization workflow; a descriptor is not permission.
   Share only public metadata, never credentials.
5. Keep the provider and its Runtime running for the test. State clearly who
   maintains them afterwards. This sample does not wake a sleeping computer.

## Optional Python smoke test on the caller

1. Configure the caller's own Runtime and identity; obtain permission for the
   specific published function. Verify the source/owner of the descriptor.
2. Inspect `caller.py`. It reads at most 32 KiB locally, sends CSV text, and saves
   the returned text into a new local file. It does not ask the provider to open
   a path on the caller's filesystem.
3. Run `python3 caller.py --help`, then invoke it with the actual owner URA and
   descriptor reference, `--input input.csv`, and a new `--output report.md`.
   Do not literally substitute guessed identifiers or reuse provider credentials.
4. Compare the returned report with `output.md`. Record provider and caller
   device identities, revisions, request/receipt identifiers and output, without
   secrets. Test invalid input, denied caller and provider offline separately.
5. A timeout is not proof that execution was cancelled. Do not blindly retry or
   report success without receiving and checking the output.

## Generate on the provider, execute on the caller

The intended deliverable is a Mission.eal file generated on one device, copied
to the caller device, compiled there, and executed against this provider.
As inspected on 2026-09-07, the current CLI supports:

```sh
easynet mission compile Mission.eal --emit-ir
easynet mission run Mission.eal --format json
easynet mission show <actual-run-id> --trace
```

There is no verified `mission add` or `mission install` command. Do not pass an
EAL file to `ability deploy`; that expects a different package structure.

The development source now supports an explicit remote Agent member call with
a separate `descriptor_ref` constraint. Do not assume an installed or published
Runtime contains this change. The caller's compiler and the Runtime executing
the Mission must both support it. The owner and method remain separate fields;
do not use a full Ability URA as the method name or guess the descriptor hash.

With the actual descriptor.json and inspected input.csv on the provider, run:

```sh
python3 prepare_mission.py --descriptor descriptor.json --input input.csv --output Mission.eal
```

The generator refuses to overwrite a file. It records the actual owner, method
and descriptor reference, embeds the CSV text, and sets a 30-second timeout
with no retries. Generation does not contact a Runtime or grant permission.
Transfer Mission.eal using the user's approved file-sharing method. The file
contains the CSV data: inspect it before sharing. Do not copy the provider's
environment, private keys or credentials.

On the caller, inspect the file and compile it with the command above. Check
that the IR targets the expected remote Agent and descriptor, uses exactly
the sample CSV, and has zero retries. If the compiler rejects this syntax,
stop and report the version and error. Do not turn it into a shell-command
wrapper and label that native EAL.

After approval, run the file once, take the actual run_id from the response,
and read its trace. Compare the emitted report byte-for-byte with output.md,
not just the displayed total. Match the child invocation and its terminal
receipt with the provider's invocation record. A failed step, missing output
or mismatched receipt is not completion. Never treat a successful compile as evidence of remote execution.

The website example's cross-Runtime Mission path is still being tested; do not
promise it works on the user's installed release. If execution fails, retain
the sanitized error and do not retry blindly. Test denied-caller and provider
offline behavior separately before using real data.

## Completion report

Distinguish: local report test; provider publication; real caller invocation;
EAL compilation; real two-device EAL execution. Mark only what was observed.
Do not present two processes on one computer as two physical devices. List any
remaining dependency, and leave user files and shared services intact.
