How Much of the Maintenance Record Does Botie Need?
A manual lookup needs an asset and a symptom, but the original record also contains private contact details. Build the smaller payload and control where it can go.
16 sections · 4 questions · 1 coding challenge
The arrow keys move between sections too.
Managing Data Meant Following It Beyond the Database
BOTIE
Tools such as Presidio address a narrower part of that problem by identifying and transforming sensitive entities in text and other data. Its documentation explicitly warns that automated detection cannot find every sensitive item. Our workshop begins earlier, with a new record containing only the fields this lookup needs.
The Lookup Works Without the Technician’s Phone Number
Botie needs the pump model and reported symptom to find the right inspection notes. Our application has those fields, but they live in a larger maintenance record alongside a technician’s contact details and a building access code. Passing the whole record to the model would be convenient. What would the extra fields help it do?
If they do not help with this job, we can leave them out before making a request. That is easier to reason about than sending everything and hoping the model never repeats the wrong part. We also need to control the destination, because a small payload can still be sent to the wrong service.
All records are invented. The construction produces a local value; it sends nothing to a service.
Step 1 of 2
Give each field a reason to travel
The manual lookup has a narrow purpose. Classify and select its inputs before serialization.
| Field | Example value | Needed by this lookup? |
|---|---|---|
| asset | P7 | Yes |
| symptomCode | VIBRATION | Yes |
| contact | Private technician contact | No |
| accessCode | Private credential | No |
asset
- Example value
- P7
- Needed by this lookup?
- Yes
symptomCode
- Example value
- VIBRATION
- Needed by this lookup?
- Yes
contact
- Example value
- Private technician contact
- Needed by this lookup?
- No
accessCode
- Example value
- Private credential
- Needed by this lookup?
- No
Step 2 of 2
A destination is another independent decision
The selected fields must be approved for release and sent only to a configured service.
- 1
Source record
All maintenance fields - 2
Projection
Only requested fields - 3
Release labels
Every selected field approved - 4
Destination check
Exact configured service identity - 5
Release
The checked payload or an empty withheld result
A useful context is smaller than the source database row
Selection determines what the payload contains; classification and destination checks determine whether it may leave this boundary.
What actually leaves the maintenance record?
Project the necessary fields, inspect their application-owned release labels, and check the configured destination before releasing the payload.
BOTIE
Release route and payload
{
"route": "ready for configured service",
"payload": {
"asset": "P7",
"symptomCode": "VIBRATION"
}
}Follow the operations
1. Original maintenance record
{ "asset": "P7", "symptomCode": "VIBRATION", "contact": "Private technician contact" }2. Field names needed for this lookup
- 0asset
- 1symptomCode
3. Keep only the needed fields
{ "asset": "P7", "symptomCode": "VIBRATION" }4. Server field classifications
{ "asset": "approved", "symptomCode": "approved", "contact": "restricted" }5. Check each field's release label
true
6. Destination service ID
manual-index
7. Approved service IDs
- 0manual-index
8. Check the configured destination
true
9. Release the checked payload
{ "route": "ready for configured service", "payload": { "asset": "P7", "symptomCode": "VIBRATION" } }10. Result
{ "route": "ready for configured service", "payload": { "asset": "P7", "symptomCode": "VIBRATION" } }
The fixture assumes trusted classifications and controlled field values. It does not detect hidden personal data, enforce a network sandbox or make a request.
1. Choose inputs from the job backwards
Start with the lookup we want to perform. It needs an asset identifier and a controlled symptom code. A controlled code is a value from a vocabulary the application defines, such as VIBRATION. It is not an unrestricted note field.
Now create a new payload containing those fields. This operation is often called projection: select named columns or fields from a larger record. Keeping the source record intact is useful because another authorised operation may need its contact field later. It does not follow that this model request needs it now.
Ask what each field helps this particular request accomplish.
2. Separate the right to read from the right to send
The technician may be permitted to view a contact number inside the maintenance system. That does not automatically permit sending it to an external model provider or logging platform. Destination, purpose and retention matter independently of the original read permission.
For the exercise we use a deliberately simple release label: approved. Every selected field needs that exact label. An unknown label or missing classification withholds the payload. Real classifications may depend on the tenant, destination, jurisdiction or contractual arrangement, and the application must resolve that policy before release.
Our label is trusted metadata for this teaching example. A model-generated approved field would have no authority.
3. Inspect the smaller record before encoding it
A dictionary comprehension can select fields into a new dictionary. We iterate over the fields chosen by the application, rather than copying every key and trying to remember what to remove afterwards.
Do not silently ignore a requested field that does not exist. The resulting payload might still look valid while missing the information needed for the task. The workshop stops on that configuration error. A field added to the source record, however, stays excluded unless the application deliberately selects it.
An allowlist of needed fields survives an unrelated source-schema addition more predictably than a list of known secret fields.
A new internal field stays out of a summary payload
The source contains an internal note, but this summary only needs two named fields. The comprehension creates a separate dictionary.
record = {"asset":"P2", "symptomCode":"NOISE", "internalNote":"Private scheduling note"}
needed = ["asset", "symptomCode"]
payload = {key: record[key] for key in needed}
print(sorted(payload))
print("internalNote" in record)['asset', 'symptomCode']
TrueThe payload has the selected keys. The original record still retains the internal note for authorised uses.
4. Constrain the destination before any network request
Our workshop chooses a service ID such as manual-index from an application allowlist. Server configuration resolves that ID to a known connection. Letting the model supply an arbitrary URL would introduce more decisions: scheme, hostname, port, resolved address and redirect behaviour.
A request to a permitted-looking hostname can redirect elsewhere, and DNS resolution can produce an address the service must not reach. Server-side request forgery is the problem of making a server request a destination it should not access. Use a narrow egress policy and a network client that enforces it. Revalidate redirects or disable them, and block inappropriate internal and metadata endpoints.
An exact service-ID comparison is only one part of controlling egress. The workshop intentionally does not claim to validate URLs.
Check yourself
Questions on Parts 1 to 4
Question 1 of 2
Which payload follows the stated purpose?
Use the information below.
The source has asset, symptomCode and contact. This manual lookup needs only asset and symptomCode.5. Treat a sandbox as a set of enforced limits
If Botie can run code, ask what that process can read, write and contact. Giving it a separate working directory is useful but does not establish isolation from the host, environment variables or network. A sandbox needs an actual enforcement mechanism and a defined threat model.
Restrict filesystem mounts, avoid inherited credentials, run without unnecessary privileges, and place limits on execution time, memory and output. Network access should follow the task’s egress policy. Review the isolation technology’s documented guarantees and patch it. A container can help package these controls, but its default settings are not a complete policy.
The coding worksheet here is for learning. It is not a template for executing arbitrary model-written code inside your production service.
6. Use PII detection where the source really is free text
Sometimes a technician’s note is needed, and personal information can appear inside a sentence rather than a dedicated field. Presidio separates identification from transformation: recognizers locate possible sensitive entities, then an anonymisation step can replace, mask or otherwise transform the detected spans.
Evaluate recognizers on the languages and formats your application sees. A missed entity remains in the text; an incorrect detection can remove useful maintenance information. NeMo also exposes integrations for detecting or masking sensitive information at different points in a conversation. Choose where the check runs by following the actual data flow, including retrieved material and final answers.
Redaction after a provider request cannot undo data already sent to that provider. Minimise and inspect before the relevant boundary.
7. Check logs, traces and saved conversations too
The model request is only one copy. Debug traces may store prompts, responses and tool results. Checkpoint storage can preserve the same fields for later runs. An error report may include an entire failed payload.
Define what each store needs, who can read it and when it should be deleted. Prefer identifiers and decision categories when full content is unnecessary. Apply redaction before export to a telemetry service. If you need protected sample traces for investigations, make that a controlled collection with its own access and retention policy rather than the default for every run.
A redacted user interface tells us nothing about whether a raw request was copied into an observability tool.
8. Make the unknown case visibly withhold
The changed workshop case adds contact to the selected fields but leaves its release label restricted. The destination is still approved. Only the field-classification branch should explain why the result is withheld.
Then try an approved payload with an unapproved destination. This exposes a construction that checks only the fields. An empty result here is intentional: the output does not carry the disallowed payload along with a warning that a downstream component might ignore. A production audit record can separately retain a protected reason code.
Do not let a convenient fallback resend the full original record after the minimised request fails.
9. Keep the teaching boundary honest
This construction checks field names and trusted classifications. It does not inspect the meaning of values. If a free-text symptom contains a password, labelling its field approved will not remove that password. If an asset identifier is itself sensitive, it also needs an appropriate policy.
Use realistic test fixtures for those cases in the actual application. The controlled symptom codes here let us study selection and routing without pretending to have built a complete privacy classifier. Keep that assumption in the test description when comparing implementations.
A passing release test means this stated policy passed for these records. It is not a general privacy guarantee.
Check yourself
Questions on Parts 1 to 9
Question 1 of 2
Where did this protection arrive too late?
Use the information below.
The prompt is redacted before the model call, but the tracing middleware exported the raw prompt first.Try it with Botie
Build with Botie
Write and run Python