# First tool boundary: valid arguments are not permission

LockedIn Labs · Edition 2026-10-30.1 · Separate 45-minute foundation route

Use the existing [identity companion](https://training.lockedinlabs.ai/templates/fde-identity-boundary-lab.py)
in a disposable folder with Python 3.11+. Its standard library and an in-memory
SQLite database are enough; no package, account, model or network is needed.
The five reads and grant-removal fixture do not write files. Optional token,
HTTP, context-selection and row-policy workshops are separate from this route.

The trusted principal is supplied by the fixture. The program executes its local
SQL access check, but does not verify a login, operate an MCP connection or read
any real equipment. Keep unexecuted work and assistance visible.

## 1. Map the boundary — 10 minutes

The business task is to read a permitted maintenance procedure. Define these
parts before choosing a model or exposing a tool:

| Part | Question to answer | Your own example |
| --- | --- | --- |
| Operation | What precise read is implemented? | |
| Arguments | Which fields and types may be requested? | |
| Trusted context | How would the host verify the caller and active workspace? | |
| Resource permission | May that caller perform that action on this resource now? | |
| Result | Which fields or bounded error may be returned? | |

The script uses `document_id` to select a procedure. The original equipment-lookup
tutorial uses `equipmentId`; those are different proposed interfaces, not fields
to rename silently in the existing program. Record the mapping if you build a
separate example. The fixture's optional `tenant` argument is deliberately
untrusted. It cannot select the verified workspace or expand a read grant.

Draw the inputs separately: `Principal("U-7", "north")` comes from the supplied
host fixture, while `{"document_id":"P-7","tenant":"south"}` is proposed
request data. Ask the receiving owner what evidence would establish the actual
host context in a deployment. Do not treat the constructor as authentication.

My narrow operation / arguments:
Trusted host verification still to be established:
Resource/action permission and responsible owner:
My contribution / prior reading / help:

## 2. Predict and run five reads — 15 minutes

Download the companion from the free Identity 101 guide and retain its original
filename. Predict query execution and returned content separately, then run:

```sh
python3 --version
python3 fde-identity-boundary-lab.py allowed > allowed.json
python3 fde-identity-boundary-lab.py anonymous > anonymous.json
python3 fde-identity-boundary-lab.py claim-tenant > claim.json
python3 fde-identity-boundary-lab.py restricted > restricted.json
python3 fde-identity-boundary-lab.py revoked > revoked.json
```

Each command creates a fresh fictional database. `revoked` includes its own two
sequential observations. The local fixture's setup and grant deletion are not
actions available through the document-read function.

| Case / observation | My predicted query and rows | Actual fields / unexecuted |
| --- | --- | --- |
| allowed | | |
| anonymous | | |
| claim-tenant | | |
| restricted | | |
| revoked — first read | | |
| revoked — after grant removal | | |

Inspect `trusted_context_fixture`, `untrusted_request`, `query_executed`,
`rows_returned`, `state` and `response`. Compare after preserving your predictions:
allowed returns one North procedure. Anonymous and claimed-South requests do not
query documents. Restricted queries but returns zero permitted rows. Revoked
first returns one row, then zero after the grant is removed.

The safe result `not_available` does not prove a document is absent. Here P-8
exists but has no matching grant. The fuller state and trace are teaching
diagnostics, not a recommended public error or logging contract. A prior allowed
read remains recorded after revocation; access removal cannot erase delivered
information. Concurrent requests, cached results and distributed revocation have
not been tested by these sequential reads.

My actual file / revision / command / runtime:
The predicate that refuses the requested workspace switch:
The difference between no query and no permitted row:
The first observation retained after grant removal:

## 3. Check the whole resource relationship — 10 minutes

```sh
python3 fde-identity-boundary-lab.py compare-joins > joins.json
```

North/P-7 and South/P-7 are different resources. The guarded SQL binds both
document ID and tenant between the grant and document. The deliberately broken
comparison retains bound parameters and a North document filter but omits
`g.tenant = d.tenant`. A South grant can then match a North document. This does
not switch the active workspace or return South's document.

Predict and locate all four comparisons:

| Case | Guarded rows | Missing-tenant rows | My actual evidence |
| --- | --- | --- | --- |
| both-read-grants | 1 | 2 | |
| south-grant-only | 0 | 1 | |
| south-workspace | 1 | 1 | |
| no-read-grants | 0 | 0 | |

A refusal with no grants is insufficient: even the broken comparison refuses it.
Keep the useful South control and the discriminating South-only grant case.
As an optional repair, restore only the missing tenant relationship in a separate
copy; the comparison counts should become 1, 0, 1, 0 without changing fixtures.
Bound parameters protect SQL syntax; they cannot supply a missing permission
relationship. Use the guide's existing diagram to trace both paths.

My source location for the complete grant predicate:
Why one returned row or a repeated label would hide the defect:
Useful permitted behavior retained:

## 4. Receive the read, then specify a different write — 10 minutes

Give a receiver the original file and your reports. Ask them to run allowed and
restricted and locate the trusted principal, proposed arguments, current grant
and fixed read action without the author navigating. Record their own command,
explanation, hints and any takeover; solo work is self-review. Keep each person's
evidence separate from the pod's answer.

Write a proposed safe result contract with invalid input, unavailable access and
an untested remote-failure case. Include only permitted data and a safe request
reference when an implementation can provide one. Never use a credential or raw
database exception as the troubleshooting response. The companion implements
neither a remote outage nor request-reference logging; leave these unexecuted
and give the receiving service owner an answerable test requirement.

Now propose an equipment update without implementing it. A read grant and a
read-only annotation do not authorize the new action. Specify a separate write
permission, current resource-version comparison, scoped operation/payload
identity for duplicate handling and reconciliation of an uncertain effect.
Name the access owner, data owner and delivery lead responsible for reviewing
that contract. Keep the original read tests; none of these local reports enables
a write in the platform or a client system.

Receiver's actual read / source location / explanation:
Help, author takeover and unrun work:
Safe result fields / untested failure / receiving owner:
Proposed write permission / version conflict / duplicate and unknown outcome:
Scope/date dependency made visible by the delivery lead:
Next evidence and responsible role:

Continue in **AI architecture foundations → Tool boundaries: valid arguments
are not permission**, under existing Academy access. The
[free Identity 101 guide](https://training.lockedinlabs.ai/training/guides/identity)
contains the full companion walkthrough. Completed local practice does not
establish independent delivery, placement or qualification.
