# Share one maintained cleaning function

Help the user expose their existing cleaning function through EasyRemote and
let an authorized consumer obtain its result without installing the provider's
business dependencies. The sample trims the `customer` field in at most 100
rows. It is deliberately small: it demonstrates registration, not a reason
to use remote execution for every string operation.

## Start with the actual need and inspected files

Ask what dependency or maintained business rule makes provider-side execution
useful. If this simple trimming function is the whole task, a shared Python
package or ordinary document with the code may be enough. Do not invent a
second-device requirement. An existing authenticated HTTP service or MCP tool
can also remain in use; do not remove it merely to demonstrate EasyNet.

Obtain this case's page URL from the user if the source files were not supplied.
Resolve `/examples/shared-cleaning/provider.py` against that URL. Do not invent
a download origin. A localhost URL on one device does not identify the same
server on another device. Ask for an approved reachable source or file transfer.
Read the file and local repository instructions before executing anything.
Use a new user-approved working directory; do not overwrite an existing
AGENTS.md, application, or output file.

The page's provider.py and downloadable provider.py are the same source. The
function keeps only `customer`, trims its ends, and preserves row order. It
does not deduplicate customers, validate email addresses, read files, preserve
other columns, or perform general sales-data cleaning. Empty strings remain
empty. Use synthetic inputs only until the owner approves actual data.

## Verify the local rule first

Test the function body without starting a Runtime or registering a provider.
For this local check, copy the function into an isolated test module without
the `@node.register` decorator and without the module's imports, node creation,
or `node.serve()` call. Keep the body unchanged and record that this is only a
local calculation check, not an SDK or network test.

Check these exact cases:

```json
[
  {"input": [{"customer": "  North shop  "}], "output": [{"customer": "North shop"}]},
  {"input": [], "output": []},
  {"input": [{"customer": "   "}], "output": [{"customer": ""}]}
]
```

101 rows must raise `ValueError("Too many rows")`; a missing customer or a
numeric customer must raise `ValueError("customer must be text")`. Do not
turn these rejected inputs into successful empty results.

## Register on the provider

Identify the provider and consumer, their operators, and the approved test
scope. Read the installed CLI help and version-matched function connection
guide. Do not install, pair, restart shared services, change firewall rules,
or expose business data without the user's authorization.

In a compatible EasyRemote environment with the provider Runtime configured,
run `python3 provider.py`. Keep that process running. `@node.register` registers
the function as `sales.clean_names`; `node.serve()` starts its provider
lifecycle. Neither action grants a colleague access.

In a separate terminal, inspect:

```bash
easynet ability list --node local --format json
```

Find this provider's actual published ability and obtain its actual owner URA,
ability URA, descriptor reference and input schema. Verify the function name
and the `rows` argument. Do not treat `sales.clean_names`, a device nickname,
or a guessed hash as the callable address. Publication in the local catalogue
does not prove discovery or permission from the consumer.

## Call with the consumer's own permission

Use the actual published descriptor and the installed CLI or SDK's documented
invocation interface. Read its help rather than inventing flags. The invocation
argument object is:

```json
{"rows": [{"customer": "  North shop  "}]}
```

Obtain the owner's approval for this specific function and consumer through
the supported authorization workflow. Never borrow the provider's account,
copy private keys, mint an authority field, or weaken admission to make the
demo pass. If authorization cannot be established, stop this stage and report
the missing step. Do not substitute same-user execution for a claimed
different-colleague test.

Invoke once and verify the returned value is exactly
`[{"customer": "North shop"}]`, not merely a successful process exit. Send
records, not a local file path. The provider does not read the caller's disk.
The consumer needs its own compatible connection setup but not the provider's
business implementation. Do not retry an unknown outcome blindly.

For a remote consumer, the inspected development CLI supports the following
command after authorization. Confirm these flags in the installed
`easynet ability invoke --help` first. Set CLEAN_NAMES_DESCRIPTOR_REF to the
actual descriptor reference (`<ability-ura>@<version>`) from the catalogue and
PROVIDER_CALLEE_URA to its exact owner/callee URA. Neither variable is a label
or a permission grant. Generate a fresh nonce for this one request:

```bash
cleaning_nonce_hex=$(python3 -c 'import secrets; print(secrets.token_hex(16))')
easynet ability invoke "${CLEAN_NAMES_DESCRIPTOR_REF:?Set the actual descriptor reference first}" \
  --node "${PROVIDER_CALLEE_URA:?Set the actual provider callee URA first}" \
  --args '{"rows":[{"customer":"  North shop  "}]}' \
  --nonce-hex "$cleaning_nonce_hex" --causal-root --timeout 30
```

This declares a root test invocation. Do not use `--causal-root` to conceal
an actual parent invocation inside an existing mission. If the installed
version rejects the interface or admission rejects the request, retain the
sanitized error and stop rather than dropping authorization-related options.

## Inspect the matching call and failures

On the provider, set CLEAN_NAMES_ABILITY_URA to the actual published value:

```bash
easynet invocation list --ability-ura "${CLEAN_NAMES_ABILITY_URA:?Set the actual published ability URA first}" --format json
```

This is a scoped history query, subject to the current identity's read
permissions. Match the invocation identifier, caller and terminal state to
the actual test. An empty history is not proof of success, and a history
record is not a network-byte measurement.

Separately test invalid input and an unapproved test identity. Test provider
unavailability only by stopping the demo process you started, with approval;
do not stop a shared Runtime. A rejected request must not be presented as a
successful cleaned table. A timeout does not prove cancellation.

Report local calculation, provider publication, authorized consumer result,
rejected consumer, invalid input and unavailable provider separately. Keep
sanitized identifiers and exact returned values, never credentials. Mark
unrun checks as unrun. Do not claim complete cross-user use from the website's
syntax, rendering or local-function tests.
