# Sensorimotor Worked Example - Loop Engineering

[← All worked examples](/examples/)

# Worked Example - Motor + Sensory (Agent Action Log)

                Companion to Chapter 9. A real agent action log for a multi-step task - file edits, shell commands, network calls, and the confirmation-gate sequence that punctuates the side-effects. Side-effect class annotations show where the materiality-gating discipline kicks in.

### The task

"Update the production-DB connection pool size from 10 to 20 in the deployment manifests, run the validation tests, and open a PR." Five distinct side-effect classes: file read, file write, shell command (test run), shell command (git operations), network call (open PR via API).

### The action log (abridged)

[10:42:01] read_file: deploy/values.prod.yaml
  side-effect class: READ
  scope: single file
  gate: none (read-only)
  result: 47 lines

[10:42:03] grep_search: "poolSize" in deploy/**/*.yaml
  side-effect class: READ
  scope: deploy/ subtree
  gate: none (read-only)
  result: 3 matches in deploy/values.prod.yaml, deploy/values.stg.yaml, deploy/values.dev.yaml

The agent notes that the user said "production" specifically and stops before editing all three. It surfaces the question.

Confirmation gate - disambiguation

The pool-size value appears in three manifests (prod, stg, dev). The request said "production" - should I update only values.prod.yaml, or all three for consistency? Default: prod only.

User: "Prod only."

[10:42:17] replace_string_in_file: deploy/values.prod.yaml
  side-effect class: WRITE (file)
  scope: 1 line in 1 file
  gate: confirmed (per harness policy: file writes under deploy/ require confirmation)
  diff:
    - poolSize: 10
    + poolSize: 20

Confirmation gate - file write under deploy/

Edit shown above will modify the production deployment manifest. Apply? [Y/n]

User: "Y"

[10:42:24] run_in_terminal: npm test -- deploy-validation
  side-effect class: SHELL (test runner)
  scope: read-only at the test level; writes only to tmp
  gate: none (test runner; sandboxed)
  exit code: 0
  output: 12 passed, 0 failed

[10:42:33] run_in_terminal: git diff --stat
  side-effect class: SHELL (git read)
  scope: read-only
  gate: none
  output: deploy/values.prod.yaml | 2 +-

[10:42:34] run_in_terminal: git add deploy/values.prod.yaml
  side-effect class: SHELL (git stage)
  scope: index-only; no network
  gate: none (no network effect)
  result: 1 file staged

[10:42:36] run_in_terminal: git commit -m "[behaviour] prod: bump DB connection pool 10->20"
  side-effect class: SHELL (git commit)
  scope: local repo only
  gate: none (no network effect; reversible via git reset --soft HEAD~1)
  result: committed as 8a3f12c

Confirmation gate - push to remote

About to git push origin feat/prod-pool-size-bump. This will create a remote branch and make the change visible to CI. Proceed? [Y/n]

User: "Y"

[10:42:48] run_in_terminal: git push -u origin feat/prod-pool-size-bump
  side-effect class: NETWORK (git push)
  scope: pushes 1 commit to 1 remote branch (new branch)
  gate: confirmed (per harness policy: network writes require confirmation)
  result: branch pushed; PR not yet opened

Confirmation gate - open PR (API call)

About to call the GitHub API to open a PR from feat/prod-pool-size-bump to main with the title "prod: bump DB connection pool 10->20". This is a public action visible to reviewers and CI. Proceed? [Y/n]

User: "Y"

[10:43:02] gh api: POST /repos/.../pulls
  side-effect class: NETWORK (API write)
  scope: creates 1 PR
  gate: confirmed
  result: PR #2847 opened
  url: https://github.com/.../pull/2847

### The side-effect class annotations

Six classes appeared in this trace, with three different gate behaviors:

- READ (file read, grep, git diff, git log) - no gate. Reversible by definition.

- WRITE (file, scoped) - gate enforced for paths under deploy/ ; harness-policy decision. Other paths (under NOTES.md or tmp/ ) would have been gateless.

- SHELL (sandboxed test runner) - no gate. Writes only to tmp; reversible.

- SHELL (git index / commit) - no gate. Local-only and easily reversible.

- NETWORK (git push) - gate enforced. First action with cross-machine effect.

- NETWORK (API write) - gate enforced. First action visible to other humans.

### What the architecture's discipline buys here

The agent did not ask permission for every read or every harmless local action - that would have made the loop unusable. It asked permission at exactly the transitions that mattered: ambiguous scope (one file or three?), first write to a production-class artifact, first network call, first public-facing call. Materiality-gated; not paranoid, not reckless.

Two failure modes the discipline prevents:

- Silent scope creep - without the disambiguation gate at line 1, the agent would have plausibly updated all three manifests "for consistency." User intent would have been violated without anyone noticing until staging behaved differently than expected.

- Silent publishing - without the push and PR gates, the agent would have published the change before the user had a chance to look at the diff. Reversible, but expensive in reviewer attention.

### What this trace does not show

This example assumes a well-behaved environment (no prompt injection, no model error, no network anomaly). The companion [failure-diagnosis worked example](/examples/failure-diagnosis/) covers what the diagnostic process looks like when one of those goes wrong.

### Practitioner templates

The [prompts library](/prompts/) hosts confirmation-gate templates and action-log review prompts.
