Merge feat/deid-round-trip-t1-t7 into main

Brings the post-PR#1 commits into main: seed Conan Scott persona, the doc
refactor (separate .mmd files), and the ASCII heading relabel.
This commit is contained in:
2026-07-01 18:09:18 +10:00
4 changed files with 125 additions and 114 deletions

44
docs/Flow Diagram.mmd Normal file
View File

@@ -0,0 +1,44 @@
## Flow diagram
```mermaid
flowchart TB
advisor(["Advisor (browser)"])
ui["Advisor UI<br/>S3 + CloudFront<br/>(split view)"]
subgraph entry["Entry / orchestration"]
fusion["Fusion SaaS (prod)<br/>— or —<br/>/demo Lambda (Fusion-less dry run)"]
end
subgraph cloudzone["CLOUD zone (Zone=cloud-VPC-B) — sees TOKENS only"]
runtime["AgentCore Runtime<br/>Strands agent + Bedrock<br/>apac Claude 3.5 Sonnet v2"]
gateway["AgentCore Gateway<br/>MCP · AWS_IAM / SigV4"]
end
subgraph onprem["ON-PREM zone (Zone=on-prem-VPC-A) — holds the reversible map + PII"]
tokenize["/tokenize Lambda (in-VPC)<br/>detect → mint → vault → splice"]
presidio["Presidio detector<br/>Fargate (PRIVATE, SG-locked :5001)"]
vault[("DynamoDB VAULT<br/>token &lt;-&gt; PII (+customer_id)")]
customers[("DynamoDB CUSTOMERS<br/>raw records — never leave")]
rag["RAG tool Lambda<br/>token -> evidence (no PII out)"]
restore["/restore Lambda<br/>re-attach identity"]
end
advisor -- "1 query: 王小明 + A123456789" --> ui
ui -- "POST {query}" --> fusion
fusion -- "2 {query}" --> tokenize
tokenize -- "POST /analyze" --> presidio
presidio -- "typed findings" --> tokenize
tokenize -- "write {token,type,value,session}" --> vault
tokenize -- "3 deidentified_prompt (CUST_*)" --> runtime
runtime -- "4 tools/call get_customer_activity_summary(CUST_*)" --> gateway
gateway -- "5 invoke (SigV4)" --> rag
rag -- "6 resolve token" --> vault
rag -- "read record" --> customers
rag -- "7 evidence package (token-keyed, no PII)" --> runtime
runtime -- "talking points (tokens only)" --> fusion
fusion -- "8 {session_id, text}" --> restore
restore -- "lookup session tokens" --> vault
restore -- "final: (客戶:王小明)…" --> fusion
fusion -- "{final, deidentified_prompt, agent_tokenized}" --> ui
ui -- "split view: restored vs tokenized" --> advisor
```

34
docs/Sequence Diagram.mmd Normal file
View File

@@ -0,0 +1,34 @@
─```mermaid
sequenceDiagram
autonumber
actor A as Advisor
participant UI as UI (S3/CloudFront)
participant F as Fusion
participant TK as tokenize (on-prem)
participant PR as Presidio (private)
participant V as Vault (DynamoDB)
participant RT as AgentCore Runtime + Bedrock (cloud)
participant GW as AgentCore Gateway (cloud)
participant RG as RAG Lambda (on-prem)
participant RS as restore (on-prem)
A->>UI: query with 王小明 + A123456789
UI->>F: POST {query}
F->>TK: {query}
TK->>PR: POST /analyze
PR-->>TK: typed findings
TK->>V: write token to PII map (session)
TK-->>F: deidentified_prompt (CUST_*)
F->>RT: {prompt: CUST_*}
Note over RT,GW: cloud sees TOKENS only
RT->>GW: tools/call get_customer_activity_summary(CUST_*)
GW->>RG: invoke (SigV4)
RG->>V: resolve token to customer_id
RG-->>RT: de-identified evidence package
RT-->>F: talking points (tokens only)
F->>RS: {session_id, text}
RS->>V: lookup session tokens
RS-->>F: final (王小明 restored)
F-->>UI: {final, deidentified_prompt, agent_tokenized}
UI-->>A: split view (restored vs tokenized)
```

View File

@@ -27,89 +27,11 @@ demo proves data-flow behaviour, not physical residency.
| 4-6 | RAG tool | `lambda_rag/` | Lambda | on-prem | ✅ resolves token, returns none | | 4-6 | RAG tool | `lambda_rag/` | Lambda | on-prem | ✅ resolves token, returns none |
| 8 | `/restore` | `gateway_api/restore/` | Lambda + API Gateway | on-prem | ✅ re-attaches identity | | 8 | `/restore` | `gateway_api/restore/` | Lambda + API Gateway | on-prem | ✅ re-attaches identity |
## Flow diagram
```mermaid
flowchart TB
advisor(["Advisor (browser)"])
ui["Advisor UI<br/>S3 + CloudFront<br/>(split view)"]
subgraph entry["Entry / orchestration"] ## Flow (ASCII fallback)
fusion["Fusion SaaS (prod)<br/>— or —<br/>/demo Lambda (Fusion-less dry run)"]
end
subgraph cloudzone["CLOUD zone (Zone=cloud-VPC-B) — sees TOKENS only"]
runtime["AgentCore Runtime<br/>Strands agent + Bedrock<br/>apac Claude 3.5 Sonnet v2"]
gateway["AgentCore Gateway<br/>MCP · AWS_IAM / SigV4"]
end
subgraph onprem["ON-PREM zone (Zone=on-prem-VPC-A) — holds the reversible map + PII"]
tokenize["/tokenize Lambda (in-VPC)<br/>detect → mint → vault → splice"]
presidio["Presidio detector<br/>Fargate (PRIVATE, SG-locked :5001)"]
vault[("DynamoDB VAULT<br/>token &lt;-&gt; PII (+customer_id)")]
customers[("DynamoDB CUSTOMERS<br/>raw records — never leave")]
rag["RAG tool Lambda<br/>token -> evidence (no PII out)"]
restore["/restore Lambda<br/>re-attach identity"]
end
advisor -- "1 query: 王小明 + A123456789" --> ui
ui -- "POST {query}" --> fusion
fusion -- "2 {query}" --> tokenize
tokenize -- "POST /analyze" --> presidio
presidio -- "typed findings" --> tokenize
tokenize -- "write {token,type,value,session}" --> vault
tokenize -- "3 deidentified_prompt (CUST_*)" --> runtime
runtime -- "4 tools/call get_customer_activity_summary(CUST_*)" --> gateway
gateway -- "5 invoke (SigV4)" --> rag
rag -- "6 resolve token" --> vault
rag -- "read record" --> customers
rag -- "7 evidence package (token-keyed, no PII)" --> runtime
runtime -- "talking points (tokens only)" --> fusion
fusion -- "8 {session_id, text}" --> restore
restore -- "lookup session tokens" --> vault
restore -- "final: (客戶:王小明)…" --> fusion
fusion -- "{final, deidentified_prompt, agent_tokenized}" --> ui
ui -- "split view: restored vs tokenized" --> advisor
```
## Sequence (the 8-step round trip)
```mermaid
sequenceDiagram
autonumber
actor A as Advisor
participant UI as UI (S3/CloudFront)
participant F as Fusion or demo
participant TK as tokenize (on-prem)
participant PR as Presidio (private)
participant V as Vault (DynamoDB)
participant RT as AgentCore Runtime + Bedrock (cloud)
participant GW as AgentCore Gateway (cloud)
participant RG as RAG Lambda (on-prem)
participant RS as restore (on-prem)
A->>UI: query with 王小明 + A123456789
UI->>F: POST {query}
F->>TK: {query}
TK->>PR: POST /analyze
PR-->>TK: typed findings
TK->>V: write token to PII map (session)
TK-->>F: deidentified_prompt (CUST_*)
F->>RT: {prompt: CUST_*}
Note over RT,GW: cloud sees TOKENS only
RT->>GW: tools/call get_customer_activity_summary(CUST_*)
GW->>RG: invoke (SigV4)
RG->>V: resolve token to customer_id
RG-->>RT: de-identified evidence package
RT-->>F: talking points (tokens only)
F->>RS: {session_id, text}
RS->>V: lookup session tokens
RS-->>F: final (王小明 restored)
F-->>UI: {final, deidentified_prompt, agent_tokenized}
UI-->>A: split view (restored vs tokenized)
```
## ASCII fallback
``` ```
┌──────────────────────────────────────────────┐ ┌──────────────────────────────────────────────┐
@@ -123,16 +45,16 @@ sequenceDiagram
│ S3 + CloudFront │──POST─────▶│ • Fusion SaaS (prod) │ stands in for Fusion │ S3 + CloudFront │──POST─────▶│ • Fusion SaaS (prod) │ stands in for Fusion
│ (split view) │ {query} │ • /demo Lambda (dry run) │ only, in the demo │ (split view) │ {query} │ • /demo Lambda (dry run) │ only, in the demo
└─────────────────┘◀───────────│ tokenize→agent→restore │ └─────────────────┘◀───────────│ tokenize→agent→restore │
▲ {final, └──────────────────────────┘ ▲ {final, └──────────────────────────┘
│ deidentified, │ │ deidentified, │
│ agent_tokenized} │ 2 {query} │ agent_tokenized} │ 2 {query}
════════╪════════════════════════════════════╪════════ TRUST BOUNDARY (public HTTPS + x-api-key) ════════╪════════════════════════════════════╪════════ TRUST BOUNDARY (public HTTPS + x-api-key)
ON-PREM│ (Zone=on-prem-VPC-A) ▼ ON-PREM│ (Zone=on-prem-VPC-A) ▼
│ ┌───────────────────────┐ findings ┌────────────────────┐ │ ┌───────────────────────┐ findings ┌────────────────────┐
│ │/tokenize Lambda │────────────▶│ Presidio detector │ │ │/tokenize Lambda │────────────▶│ Presidio detector │
│ │(in VPC) │◀────────────│ Fargate (PRIVATE, │ │ │(in VPC) │◀────────────│ Fargate (PRIVATE, │
│ │detect→mint→vault→splice│ │ SG-locked :5001) │ │ │detect→mint→vault→splice│ │ SG-locked :5001) │
│ └───────┬───────────────┘ └────────────────────┘ │ └───────┬───────────────┘ └────────────────────┘
│ │ write {token,type,value,session} │ │ write {token,type,value,session}
│ ▼ │ ▼
│ ┌───────────────────────┐ (VPC gateway endpoint) │ ┌───────────────────────┐ (VPC gateway endpoint)
@@ -140,14 +62,14 @@ sequenceDiagram
│ │ token ⇄ PII (+cust_id)│ │ │ │ token ⇄ PII (+cust_id)│ │
│ └───────────────────────┘ │ │ └───────────────────────┘ │
│ deidentified_prompt = "…CUST_317499…" ← TOKENS ONLY │ │ deidentified_prompt = "…CUST_317499…" ← TOKENS ONLY │
════════╪═════════════════════════════════│════════════════════════════════╪══════════════ ════════╪═════════════════════════════════│════════════════════════════════╪══════════════
CLOUD │ (Zone=cloud-VPC-B) │ 3 │ resolve token CLOUD │ (Zone=cloud-VPC-B) │ 3 │ resolve token
│ ▼ │ │ ▼ │
│ ┌────────────────────────┐ │ ┌────────────────────────┐ │
│ │ AgentCore RUNTIME │ │ │ │ AgentCore RUNTIME │ │
│ │ Strands agent + Bedrock│ │ │ │ Strands agent + Bedrock│ │
│ │ (apac Claude 3.5 Sonnet)│ │ │ (Claude 3.5 Sonnet). │ │
│ └───────────┬────────────┘ │ └───────────┬────────────┘ │
│ │ 4 tools/call (MCP, SigV4) │ │ │ 4 tools/call (MCP, SigV4) │
│ ▼ get_customer_activity_summary│ │ ▼ get_customer_activity_summary│
│ ┌────────────────────────┐ │ │ ┌────────────────────────┐ │
@@ -155,10 +77,10 @@ sequenceDiagram
│ │ AWS_IAM auth │ │ │ │ AWS_IAM auth │ │
│ └───────────┬────────────┘ │ │ └───────────┬────────────┘ │
│ ← trace shows ONLY tokens │ 5 invoke │ │ ← trace shows ONLY tokens │ 5 invoke │
════════╪══(王小明: 0 hits, CUST_: 13)═══│═════════════════════════════════════╪══════════════ ════════╪══(王小明: 0 hits, CUST_: 13)═════════════════════════════════════╪══════════════
ON-PREM│ ▼ │ ON-PREM│ ▼ │
│ ┌────────────────────────┐ 6 reads │ │ ┌────────────────────────┐ 6 reads │
│ │ RAG tool Lambda │─────────────────────┘ │ │ RAG tool Lambda ────────────────────┘
│ │ token→customer_id→ │ ┌────────────────────┐ │ │ token→customer_id→ │ ┌────────────────────┐
│ │ de-identified evidence │─────▶│ DynamoDB CUSTOMERS │ ← raw PII │ │ de-identified evidence │─────▶│ DynamoDB CUSTOMERS │ ← raw PII
│ │ (raw record stays here)│ read │ (never leaves zone)│ stays put │ │ (raw record stays here)│ read │ (never leaves zone)│ stays put
@@ -190,3 +112,4 @@ Notes:
orchestrator only stands in for Fusion's orchestration in the Fusion-less dry run. orchestrator only stands in for Fusion's orchestration in the Fusion-less dry run.
- Tokens are **random per request** (`CUST_<rand>` for a PERSON, `TW_<rand>` for a - Tokens are **random per request** (`CUST_<rand>` for a PERSON, `TW_<rand>` for a
Taiwan ROC ID); the reversible map lives only in the on-prem vault. Taiwan ROC ID); the reversible map lives only in the on-prem vault.

View File

@@ -8,5 +8,15 @@
"product_type": "funds, income-generating products", "product_type": "funds, income-generating products",
"risk_profile": "conservative", "risk_profile": "conservative",
"sales_constraints": "avoid high-volatility products" "sales_constraints": "avoid high-volatility products"
},
{
"customer_id": "cust-0002",
"name": "Conan Scott",
"national_id": "F225793148",
"activity_summary": "compulsive day-trading, 200+ speculative trades/week, 90 days",
"amount_band": "leveraged well beyond net worth (>10x margin)",
"product_type": "0DTE options, leveraged crypto, meme stocks, junk bonds",
"risk_profile": "recklessly aggressive; ignores every suitability warning",
"sales_constraints": "none observed; chases volatility, doubles down on losses"
} }
] ]