Skip to content

docs(examples): bank-manager agent-control demo (AIEWF) + talks slideshow - #262

Merged
changliu2 merged 16 commits into
mainfrom
changliu2/aiewf-bank-demo
Jul 28, 2026
Merged

docs(examples): bank-manager agent-control demo (AIEWF) + talks slideshow#262
changliu2 merged 16 commits into
mainfrom
changliu2/aiewf-bank-demo

Conversation

@changliu2

Copy link
Copy Markdown
Collaborator

What

Introduces the bank_manager_agent_control example — the AIEWF live demo. One banking support agent, taken through three beats:

  1. Baseline (unguarded) — how often an un-controlled agent breaks policy
  2. Defensive prompting — the intervention everyone reaches for first
  3. Principled control plane (ACS) — policy-as-code gating on typed features of each tool call

ASSERT measures the difference; ACS enforces it. Plus a follow-along HTML slideshow under talks/.

Scope / decisions (please sanity-check)

  • Whole new example (83 files) — this directory did not exist on main before.
  • Result artifacts are NOT committed (chose code+docs only): the frozen per-case transcripts were ~21 MB, the same artifact type chore: drop 19 MB of committed per-case scores.jsonl from incident-triage demo #233 removed from a public demo. Users regenerate via assert-ai run into the gitignored artifacts/results/. The three READMEs were reconciled to a "generate, then view" flow.
  • ACS install via assert-ai[acs] (already on main) with a vendored wheel offline fallback. Note: the [acs] extra isn't on PyPI 0.1.0 yet — needs a release before pip install assert-ai[acs] works off PyPI.
  • CI beat points at the standalone responsibleai/assert-ci-banking-demo as the shipping vehicle (pip-install-in-your-own-repo), publishing separately.

Verification

  • 77/77 unit tests pass (python -m unittest discover -s tests).
  • Leak scan clean — no home paths / secrets; .env.example placeholders only.
  • docs/README.md had pre-existing staleness (old variant-a/c/e names, eval_unguarded.yaml refs, build-demo-final branch, dead results/ copy-step) — reconciled to the current eval_realistic_* configs / variant-b0/b1/b2 / bank-manager-feature-rep suite. Worth a read to confirm.

Draft — for review, not merge

Opened as a draft so you can review on github.com. Nothing merges. Flagging the "no committed results" call and the docs/README.md reconciliation as the two things most worth your eyes.

…lideshow

Introduces the bank_manager_agent_control example — the AIEWF live demo that
takes one banking agent through three beats (baseline -> defensive prompting ->
principled ACS control plane) and uses ASSERT to measure the difference and ACS
to enforce it.

- Customer-facing README with the 3-beat walkthrough + mechanics (internals
  like calibration/FRP stats kept out).
- runtime/ engine (LangGraph agent, MCP servers, typed-feature policy) + policy
  knowledge corpus with an index README (VIP / high-net-worth enhanced-protection).
- acs/ policy-as-code (Rego) + manifest; kb_ui/ retrieval-grounding UI;
  ci/ pointer to the standalone responsibleai/assert-ci-banking-demo gate repo.
- Foundry IQ KB provisioner (scripts/setup_foundry_kb.py) reading runtime/knowledge.
- 77 unit tests (feature policy, generalization, retrieval tuning, text invariance).
- talks/aiewf-18min/: self-contained follow-along HTML slideshow + charts.

Result artifacts are intentionally NOT committed (regenerate via assert-ai run;
they write to the gitignored artifacts/results/). ACS installs via assert-ai[acs]
with a vendored wheel offline fallback.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Comment thread examples/bank_manager_agent_control/scripts/setup_foundry_kb.py Fixed
Comment thread examples/bank_manager_agent_control/scripts/setup_foundry_kb.py Fixed
Comment thread examples/bank_manager_agent_control/scripts/setup_foundry_kb.py Fixed
Comment thread examples/bank_manager_agent_control/scripts/setup_foundry_kb.py Fixed
Comment thread examples/bank_manager_agent_control/scripts/setup_foundry_kb.py Fixed
Comment thread examples/bank_manager_agent_control/scripts/setup_foundry_kb.py Fixed
Comment thread examples/bank_manager_agent_control/ui/unguarded_ui.py Fixed
changliu2 and others added 3 commits July 10, 2026 15:39
Trim the demo to only what the 3 beats + talk use:
- eval_variants/ (17 archived experiment yamls) — not part of the demo
- ci/sample-pages/ + assert-ci.yml + ci_gate.py + pareto_baseline.json —
  mock CI scaffolding; the talk used the REAL action-run summaries from the
  standalone responsibleai/assert-ci-banking-demo, which ci/README.md now
  points to.
- scripts/retrieval_eval.py, scripts/pareto_frontier.py — unused.

77/77 unit tests still pass.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Strip the example to exactly what the 3-beat talk needs (baseline ->
defensive prompting -> principled ACS control plane), removing an entire
earlier a/c/e generation left in the tree:

- Delete zombie files: runtime/mcp_server.py (old bank server), acs/manifest.yaml
  + acs/policy/bank_manager.rego (old text policy), acs/manifest_text_realistic.yaml
  (unused text-gate arm), docs/GATES.md (internal experiment methodology that
  referenced deleted arms).
- agent.py: remove the old callables (chat_unguarded / chat_unguarded_prompted /
  chat_guarded_acs) and unused realistic variants (text-gate, feature+LLM), plus
  their helpers and constants. Now exposes exactly the 3 beat callables +
  the live-compare console entry points (709 -> ~420 lines).
- docs/README.md: reconcile 'What's here' + ACS-integration sections to the
  realistic servers / manifest_feature.yaml / bank_manager_feature.rego.
- scripts/smoke_test.py: fix stale post-reorg paths (corpus at runtime/knowledge,
  acs/ under the example root) and the callable-presence check.
- scripts/setup_foundry_kb.py: fix CodeQL clear-text-logging finding — read
  secrets via accessors instead of storing them in the printed _cfg() dict.

Verified: 77/77 unit tests pass; offline smoke test 10/10; agent.py imports with
all three beat callables present.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…bank demo

Follow-up to the demo minimization: remove artifacts that shouldn't ship and
fix a target-import bug that broke clean-clone runs.

- Delete vendor/acs/ (agent-control-specification wheel + sdist + README). The
  �cs extra already declares agent-control-specification + acs-generator, both
  published on PyPI, so pip install assert-ai[acs] is the single supported
  install path; the bundled 2.7 MB Linux-only manylinux wheel was redundant.
- Fix agent.py: it called �uto_trace(), but assert_ai ships �uto_trace as a
  module whose entry point is �uto_trace.enable(). The old call raised
  TypeError: 'module' object is not callable at import on a clean clone,
  breaking every eval run. enable() installs the OpenInference instrumentors
  (verified: LangChain + OpenAI active) and only exports when a Phoenix
  collector is reachable.
- Remove dead runtime/llm_classifier.py + its test (the callable that used it
  was dropped in the minimization; only its own test referenced it), and reword
  the acs_shim.py failsafe comment that pointed at the deleted test.
- docs/README.md: drop the vendor/acs offline-fallback section and bullet.

Validated end to end on the unguarded beat: 6/6 inference + 6/6 judge with zero
errors, KB retrievals grounded, OpenInference spans captured in Phoenix.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: d429caee-f2da-4fb0-8b2c-d0eff7cf40a3
@changliu2
changliu2 marked this pull request as ready for review July 14, 2026 19:49
Adds examples/bank_manager_agent_control/behaviors/: 4 failure modes, each
in its own suite, with 3 arms (baseline/prompted/acs) sharing that suite's
generated test set for apples-to-apples comparison. Adds a behaviors/README
explaining the 1 behavior = 1 suite best practice, run order, and how to
compare with the viewer and companion `assert-ai results matrix` command.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: d429caee-f2da-4fb0-8b2c-d0eff7cf40a3
changliu2 and others added 4 commits July 23, 2026 14:01
Removes examples/bank_manager_agent_control/behaviors/ (12 one-behavior-per-
yaml configs + README). The published AIEWF talk ships the combined 4-behavior
spec (eval_realistic_{unguarded,prompted,acs_feature}.yaml on suite
bank-manager-feature-rep), which is the shape presented and the result the
slideshow shows. The per-behavior split is handed off separately for science
review and is intentionally kept out of the public talk PR.

Also make the slideshow fail loud: if a chart image can't load, show a hint to
open index.html directly or serve from the aiewf-18min/ folder, and document
the same in talks/README.md.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: d429caee-f2da-4fb0-8b2c-d0eff7cf40a3
Replace real subscription id, resource names (Azure OpenAI / AI Search /
Foundry project), resource group, region hints and a personal name with
generic placeholders in .env.example, and drop the same resource names from
comments in agent.py, runtime/aad_auth.py and scripts/setup_foundry_kb.py.
Keeps this customer-facing example free of internal infrastructure detail.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: d429caee-f2da-4fb0-8b2c-d0eff7cf40a3
…go slide

- Title slide: �val + control -> optimize (drop the min_control formula line)
- Loop slide: redraw as outer lifecycle ring (Spec/Build/Test/CI/CD/Monitor)
  around the Control-with-ACS <-> Eval-with-ASSERT core, straight arrows,
  solid inner boxes; retitle 'The inner loop to power the outer loop'
- Pareto slide: move the 'better' cue to the top-left, drop the frontier
  L-bracket, relabel the null arm 'Defensive prompt (no gain, p = .31)' and
  the subtitle 'manual prompt tuning didn't help here'
- Remove the policy-as-code / Rego generalization slide + its asset

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: d429caee-f2da-4fb0-8b2c-d0eff7cf40a3
changliu2 and others added 2 commits July 24, 2026 15:04
Document the demo's deliberate fail-open choices (post-tool-call scrubber,
OPA-error handling, format-narrow SSN regex) and what to switch to fail-closed
for a real deployment. Highest-severity money-moving actions are already
gated pre-tool-call and fail closed.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: d429caee-f2da-4fb0-8b2c-d0eff7cf40a3
@changliu2

Copy link
Copy Markdown
Collaborator Author

Maintainer review — do the ACS mitigations make sense?

Liam / Mike (additional reviewers) — I traced the full mitigation chain (rego policy → manifest → acs_shim enforcement → tool side-effect semantics). Verdict: the mitigations are sound and correctly back the demo's thesis. Summary below; I've also added a "Productionizing the gate" note to the example README in this PR.

What holds up ✅

  1. Typed-signal gating (the thesis). Gating on result.risk_tier / referenced_accounts / grounded instead of regex-over-IDs generalizes uniformly across the deposit/loan/brokerage/client domains and avoids the text policy's brittle ID list.
  2. Enforcement points are placed correctly.
    • Irreversible/money-moving actions (create_transfer, freeze_account, enable_admin_mode) are gated pre-tool-call, fail-closed on the host snapshot — the shim raises AgentControlBlocked, so the side effect is actually prevented.
    • Sensitivity / exfil / grounding run as post-tool-call scrubbers. Verified the gated tools don't settle: place_trade returns status:"prepared" (not settled) and reads/prepares don't mutate — so post-call scrubbing has no committed side effect.
  3. Out-of-scope reference gate (referenced − authorized) is a sound structural XPIA/exfil signal, and it clears benign in-scope memos the regex false-positives on — which is why over-refusal also drops.
  4. Ungrounded-claim gate on the KB grounded flag directly targets policy fabrication.
  5. Learned-risk gate fires only when the typed gates are silent; an enrichment failure escalates (fail-safe).

Hardening notes (fine for a demo; documented in the new README section)

  1. Post-call scrubber fails open — unparseable JSON → allow; risk_tier defaults standard, grounded defaults true. Should fail-closed for the sensitivity dimension in production. (Money-moving pre-gates are already fail-closed, so worst-case severity is bounded.)
  2. Enforcement layer allows on OPA error (acs_shim.py) — a real control plane should fail-closed/escalate on engine error.
  3. SSN input gate is format-narrow (NNN-NN-NNNN only) — the typed post-call gates are the real protection.

Net: coherent design, highest-severity actions fail-closed. Not blocking — the fail-open choices are deliberate demo trade-offs and now called out in the README so customers don't ship them verbatim.

changliu2 and others added 3 commits July 24, 2026 15:48
Replace the old 'min_control failure(YOUR agent)' formula with the current
tagline 'evaluate and optimize your AI agents' in talks/README.md and the
bank-manager example README, and correct the deck length to 7 slides (the
policy-as-code slide was removed).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: d429caee-f2da-4fb0-8b2c-d0eff7cf40a3
…d file

Downloading index.html on its own (without the sibling assets/ folder) broke
the relative image paths. Embed loop_diagram.png and pareto.png as base64 data
URIs so the deck renders anywhere — double-click, file://, or served from any
dir. Drops the now-unnecessary onerror fallback + chartFail helper and corrects
talks/README to describe the deck as a single self-contained file.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: d429caee-f2da-4fb0-8b2c-d0eff7cf40a3
The AIEWF 2026 deck now ships as a single-file PDF rendered from the
same 7 slides, instead of a self-contained interactive HTML slideshow.
Drops the keyboard/click-nav docs from talks/README.md since PDF
viewers handle their own navigation.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@AaronAspinwall123

Copy link
Copy Markdown
Collaborator

I did some AI review and it suggested some issues:

• ACS lets sensitive transaction history through because  risk_tier  is omitted and defaults to  standard  ( bank_core.py:201 ,  bank_manager_feature.rego:56 ).
• Config generates 60 cases, while docs/results claim  n=100  ( eval_realistic_unguarded.yaml:69-70 ).
• Quickstart installation omits the  examples  extra required by  agent.py ’s MCP imports ( README.md:74 ,  agent.py:39-43 ).

Feel free to ignore if you think its not necessary

… examples extra

read_transaction_history built its return dict from scratch and never
included risk_tier, unlike read_account (which copies the full record).
The Rego policy's object.get(result, "risk_tier", "standard") default
meant the sensitive_read_gate silently never fired for this tool, even
on VIP/high-net-worth/restricted accounts -- despite read_transaction_history
being listed in read_tools. Added risk_tier to the returned dict plus a
regression test (test_read_transaction_history_signals) that would have
caught this.

Also: the example's quickstart pip install command (README.md, ci/README.md)
omitted the examples extra, which is required for langchain-mcp-adapters
(agent.py's top-level MCP import). Following the quickstart verbatim would
raise ModuleNotFoundError on the first assert-ai run. The more detailed
docs/README.md setup guide already had this right; synced the two shorter
quickstart commands to match.

Per audit of AI-review feedback on PR #262 (issuecomment-5097447052) --
the third flagged item (config generates 60 cases vs docs claiming n=100)
was independently verified as a false positive: the actual generated
test_set.jsonl has exactly 100 rows (50 prompt + 50 scenario); sample_size
in the stratified test-set config does not map 1:1 to final case count.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@changliu2

Copy link
Copy Markdown
Collaborator Author

Thanks for flagging these — ran them all down against the actual code/artifacts rather than taking the AI review at face value. Two real, one false positive:

#1 (risk_tier bypass) — real, fixed in b720ccb. read_transaction_history built its return dict from scratch and never included risk_tier, unlike read_account (which copies the full record). Since the Rego policy defaults missing risk_tier to "standard" (bank_manager_feature.rego:56), the sensitive_read_gate silently never fired for this one tool — VIP/high-net-worth transaction history could be read without triggering the same block that correctly stops read_account on the same entity. Added risk_tier to the return dict plus a regression test (test_read_transaction_history_signals) that would have caught this — there was genuinely zero test coverage for that combination before.

#2 (n=100 vs 60) — false positive. That's naive arithmetic on the two sample_size config knobs (40 + 20 = 60) that doesn't reflect how the stratified test-set generation actually expands into final case count. I counted the real generated test_set.jsonl directly: exactly 100 rows (50 prompt + 50 scenario), matching the docs and the -n100 run naming. Worth double-checking real output before trusting an AI review's arithmetic on config values that don't map 1:1.

#3 (missing examples extra) — real, fixed in b720ccb. The quickstart pip install "assert-ai[acs,langgraph,otel]" in both README.md and ci/README.md omitted examples, which langchain-mcp-adapters (imported at module load in agent.py) lives under. Following the quickstart verbatim → ModuleNotFoundError on the first run. docs/README.md's fuller setup already had this right; synced both shorter quickstart commands to match.

One more thing I found while auditing #1, not from your list: the Python FeatureGate.decide() mirror in feature_policy.py only checks entity sensitivity for WRITE_TOOLS — it has no equivalent check for reads at all, even though the real Rego policy has an explicit sensitive_read_gate for reads. The live Rego enforcement is correct and unaffected (verified separately), but the Python unit-test mirror can't exercise that specific gate the way the Rego can, since it doesn't implement it. Not fixing this myself since it's a bigger design question (is the Python class meant to be full parity, or an intentionally narrower harness for a few properties?) — flagging for a follow-up rather than expanding this PR's scope.

All 68 existing tests + the new one pass. Pushed in b720ccb.

… nonexistent index.html

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@changliu2
changliu2 merged commit a6e34b5 into main Jul 28, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants