agenttwin 0.3.13 → 0.3.14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. package/dist/api.js +11 -1
  2. package/dist/cli.js +113 -18
  3. package/dist/dashboard/assets/next/static/chunks/app/account/password/{page-aaee6711085b485d.js → page-ebb8ab25df1b808e.js} +1 -1
  4. package/dist/dashboard/assets/next/static/chunks/app/dashboard/{layout-09cb13657f62384f.js → layout-f7cd10740b90145d.js} +1 -1
  5. package/dist/dashboard/assets/next/static/chunks/app/dashboard/{page-945c916b24f48675.js → page-a5ad912a1f481008.js} +1 -1
  6. package/dist/dashboard/assets/next/static/chunks/app/demo/{page-3cba0aab460c8677.js → page-5495d9cb9a3e1431.js} +1 -1
  7. package/dist/dashboard/assets/next/static/chunks/app/docs/[[...slug]]/{page-9f7b8dca8b973b15.js → page-9130f219b4b02112.js} +1 -1
  8. package/dist/dashboard/assets/next/static/chunks/app/enterprise/{page-4986698442bddc6b.js → page-b7e323d45eaf4952.js} +1 -1
  9. package/dist/dashboard/assets/next/static/chunks/app/{layout-09868e53e4f0541f.js → layout-ed5b209cd1b17365.js} +1 -1
  10. package/dist/dashboard/assets/next/static/chunks/app/login/page-3887863343ffce8c.js +1 -0
  11. package/dist/dashboard/assets/next/static/chunks/app/onboarding/{page-af2c4768dc34ec92.js → page-35795509a58cbc9c.js} +1 -1
  12. package/dist/dashboard/assets/next/static/chunks/app/{page-507229409812cedd.js → page-4d150b91a7a1abcc.js} +1 -1
  13. package/dist/dashboard/assets/next/static/chunks/app/pricing/page-388c0afb0ac51384.js +1 -0
  14. package/dist/dashboard/assets/next/static/chunks/app/signup/page-3887863343ffce8c.js +1 -0
  15. package/dist/dashboard/assets/next/static/chunks/app/v2/dashboard/{layout-77a57cd622171076.js → layout-1430f20bea23253f.js} +1 -1
  16. package/dist/dashboard/assets/next/static/chunks/app/v2/dashboard/page-12a8d96f5c18b411.js +1 -0
  17. package/dist/dashboard/assets/next/static/chunks/app/v2/layout-fb241571c2a60362.js +1 -0
  18. package/dist/dashboard/assets/next/static/chunks/app/v2/login/page-7ac4be578a219d6e.js +1 -0
  19. package/dist/dashboard/assets/next/static/chunks/app/v2/onboarding/{page-abfe2f36213848d7.js → page-16d9efad4103fb58.js} +1 -1
  20. package/dist/dashboard/assets/next/static/chunks/app/v2/{page-df6a34eff716d18e.js → page-1d465878abb57f0f.js} +1 -1
  21. package/dist/dashboard/assets/next/static/chunks/app/v2/signup/page-7ac4be578a219d6e.js +1 -0
  22. package/dist/dashboard/assets/next/static/chunks/{webpack-44457f45df749a89.js → webpack-9ed8651d8c2c40a2.js} +1 -1
  23. package/dist/dashboard/index.html +2 -2
  24. package/dist/gateway.js +11 -1
  25. package/package.json +1 -1
  26. package/dist/dashboard/assets/next/static/chunks/app/login/page-2e29d4b17645c34c.js +0 -1
  27. package/dist/dashboard/assets/next/static/chunks/app/pricing/page-c27282cd7bfb0fcf.js +0 -1
  28. package/dist/dashboard/assets/next/static/chunks/app/signup/page-2e29d4b17645c34c.js +0 -1
  29. package/dist/dashboard/assets/next/static/chunks/app/v2/dashboard/page-df34bcef0394d10d.js +0 -1
  30. package/dist/dashboard/assets/next/static/chunks/app/v2/layout-d1d715b5b2dae3cd.js +0 -1
  31. package/dist/dashboard/assets/next/static/chunks/app/v2/login/page-4f60d050bf954194.js +0 -1
  32. package/dist/dashboard/assets/next/static/chunks/app/v2/signup/page-4f60d050bf954194.js +0 -1
  33. /package/dist/dashboard/assets/next/static/{BbTZs0rKnsmj45peSnlwJ → O8JeB5KAl7-h1hCNIyUY7}/_buildManifest.js +0 -0
  34. /package/dist/dashboard/assets/next/static/{BbTZs0rKnsmj45peSnlwJ → O8JeB5KAl7-h1hCNIyUY7}/_ssgManifest.js +0 -0
@@ -1 +1 @@
1
- (self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[9436],{964:(e,t,a)=>{"use strict";a.d(t,{default:()=>o});var s=a(1778),n=a(5226);function o(){return(0,n.useEffect)(()=>{let e=!1;return queueMicrotask(()=>{e||function(){var e;let t=e=>document.querySelector(e),a=["Connect production","Create replica","Run code","Introduce failures","Diagnose, fix, rerun"],s=["Connect","Create replica","Run code","Add failures","Diagnose & rerun"],n=e=>[{id:"perm",name:"Expired permissions",desc:"The ".concat(e.permTool," connection loses ").concat(e.perm," write permission."),code:"403 \xb7 access denied",failCount:0,passCount:0,failure:{t:"".concat(e.action," failure swallowed"),d:"The caller received no actionable permission error."},recovery:{t:"Permission failure surfaced",d:"Workflow stops with an actionable error and no partial ".concat(e.noun," records.")}},{id:"down",name:"Service unavailable",desc:"".concat(e.downTool," is unavailable after the ").concat(e.noun," succeeds."),code:"503 \xb7 ".concat(String(e.downTool).toLowerCase()," unavailable"),failCount:1,passCount:1,failure:{t:"".concat(e.action," saved; ").concat(e.follow," lost"),d:"".concat(e.stateLabel," was written, but ").concat(e.follow," never happened.")},recovery:{t:"Outage handled",d:"".concat(e.action," preserved; ").concat(e.follow," queued for recovery.")}},{id:"late",name:"Delayed event",desc:"A completion event arrives after the caller times out.",code:"+30s \xb7 event delivery",failCount:1,passCount:1,failure:{t:"Late event overwrote newer state",d:"The expired operation updated a completed ".concat(e.noun,".")},recovery:{t:"Stale event ignored",d:"The event version check prevents a stale state transition."}},{id:"timeout",name:"Timeout after success",desc:"The operation completes, but its response is lost.",code:"ETIMEDOUT \xb7 after write",failCount:2,passCount:1,failure:{t:"Retry created a second ".concat(e.noun),d:"The original write succeeded; the retry used a new operation key."},recovery:{t:"Retry reused the operation key",d:"The existing operation is returned; no duplicate is created."}},{id:"dup",name:"Duplicate delivery",desc:"The same request or event is delivered twice.",code:"2\xd7 \xb7 same operation",failCount:2,passCount:1,failure:{t:"Duplicate processed twice",d:"No atomic deduplication guarded the repeated operation."},recovery:{t:"Duplicate safely ignored",d:"The atomic deduplication guard permits one ".concat(e.noun," state mutation.")}},{id:"rate",name:"Rate limit",desc:"".concat(e.rateTool," rejects the burst."),code:"429 \xb7 retry after ".concat(e.after),failCount:1,passCount:1,failure:{t:"".concat(e.action," dropped without retry"),d:"The retry-after interval was ignored."},recovery:{t:"Retry-after respected",d:"The simulated scheduler retries after the required delay."}}],o=(e,t,a,s,n,o,r)=>({brand:e,icon:t,sub:a,name:s,mode:n,kind:o,boundary:r}),r=[{id:"support",logo:"co-pylon.png",company:"Pylon",tag:"B2B support agent",badge:"SUPPORT",name:"pylon-support-twin",blurb:"A B2B SaaS company runs support through an agent: look up the account, decide the credit, file the engineering escalation, and answer the customer once. The stack below is the one a team like this actually runs.",caution:"The tool stack and the workflows under test are modelled for this demo. Pylon is a prospect, not an AgentTwin customer. This does not represent Pylon private architecture or a reported failure.",links:[{label:"AI support agents",href:"https://www.usepylon.com/ai-agents/support"},{label:"Slack agent",href:"https://www.usepylon.com/ai-agents/slack"}],services:[o("Slack","#","Threads \xb7 replies","Customer conversation","Simulated","amber","Thread state only; no real delivery"),o("HubSpot","H","Accounts \xb7 plans","Account and plan state","Simulated","amber","Synthetic accounts and plan data"),o("Stripe","$","Billing \xb7 credits","Billing state","Simulated","amber","Synthetic charges and credits; no money movement"),o("Linear","L","Issues \xb7 escalations","Engineering escalation","Simulated","amber","Synthetic issues; nothing filed"),o("Gmail","M","Email \xb7 replies","Email channel","Simulated","amber","Message state only; no real mail"),o("Notion","N","Runbooks \xb7 macros","Agent knowledge","Seeded fixture","","Invented macros and escalation runbooks"),o("GitHub","G","Repros \xb7 linked bugs","Bug reproduction","Sanitized copy","","Synthetic repositories and issue links"),o("Datadog","D","Service health","Dependency health","Simulated","amber","Synthetic monitors; no live telemetry"),o("Okta","O","SSO \xb7 roles","Identity and roles","Sanitized copy","","Synthetic users and role grants")],runs:[{id:"credit",label:"Issue billing credit \xb7 account #8841",entry:"issueBillingCredit()",testFile:"tests/issue-billing-credit.ts",startTitle:"Credit requested",startEvent:"issueBillingCredit() \xb7 over-billed account \xb7 #8841",settled:"One credit recorded; customer notified once.",stateKey:"stripe.credits",faults:n({permTool:"HubSpot",downTool:"Slack",perm:"billing",action:"Credit",noun:"credit",follow:"customer reply",stateLabel:"Credit state",rateTool:"Linear",after:"10s"})},{id:"escalation",label:"Escalate P1 \xb7 SLA at risk \xb7 ticket #4412",entry:"escalateToEngineering()",testFile:"tests/escalate-p1.ts",startTitle:"Escalation opened",startEvent:"escalateToEngineering() \xb7 P1 \xb7 ticket #4412",settled:"One issue created; the on-call engineer paged once.",stateKey:"linear.escalations",faults:n({permTool:"Linear",downTool:"Slack",perm:"issue-create",action:"Escalation",noun:"escalation",follow:"on-call page",stateLabel:"Escalation state",rateTool:"Linear",after:"15s"})},{id:"summary",label:"Summarize 40-message thread \xb7 enterprise account",entry:"draftResolutionSummary()",testFile:"tests/draft-summary.ts",startTitle:"Summary requested",startEvent:"draftResolutionSummary() \xb7 40 messages \xb7 acct-119",settled:"One summary stored; nothing sent to the customer.",stateKey:"pylon.summaries",faults:n({permTool:"Notion",downTool:"Slack",perm:"write",action:"Summary",noun:"summary",follow:"Slack digest",stateLabel:"Summary state",rateTool:"Datadog",after:"30s"})}]},{id:"ecom",logo:"co-intercom.svg",company:"Intercom",tag:"E-commerce support agent",badge:"SUPPORT",name:"intercom-returns-twin",blurb:"A Shopify brand lets a support agent resolve post-purchase conversations: find the order, approve the return or exchange, process the refund, and message the shopper in the brand voice.",caution:"The tool stack and the workflows under test are modelled for this demo. Intercom is a prospect, not an AgentTwin customer. This does not represent their product architecture or a reported failure.",links:[{label:"Fin AI agent",href:"https://www.intercom.com/fin"},{label:"Intercom AI",href:"https://www.intercom.com/ai"}],services:[o("Shopify","S","Orders \xb7 returns","Order state","Simulated","amber","Synthetic orders and returns; no money movement"),o("Intercom","I","Inbox \xb7 Fin replies","Support conversation","Simulated","amber","Ticket state and replies; no customer contact"),o("Stripe","$","Refunds \xb7 charges","Payment state","Simulated","amber","Synthetic refunds; no money movement"),o("Klaviyo","K","Email \xb7 SMS flows","Shopper notification","Simulated","amber","Message state only; no real delivery"),o("Slack","#","Internal escalation","Internal handoff","Simulated","amber","Channel state only; no real messages"),o("Notion","N","Macros \xb7 policy","Support knowledge","Seeded fixture","","Invented macros and exchange rules"),o("Gmail","M","Email fallback","Email channel","Simulated","amber","Message state only; no real mail"),o("Postgres","Pg","Orders \xb7 customers","Order store","Sanitized copy","","Synthetic orders, no production rows")],runs:[{id:"return",label:"Resolve post-purchase return \xb7 order #2210",entry:"resolveReturnRequest()",testFile:"tests/resolve-return.ts",startTitle:"Return requested",startEvent:"resolveReturnRequest() \xb7 exchange requested \xb7 order #2210",settled:"One return created; shopper notified once.",stateKey:"shopify.returns",faults:n({permTool:"Shopify",downTool:"Klaviyo",perm:"returns",action:"Return",noun:"return",follow:"shopper notification",stateLabel:"Return state",rateTool:"Klaviyo",after:"30s"})},{id:"address",label:"Change delivery address \xb7 order #88231",entry:"changeDeliveryAddress()",testFile:"tests/change-address.ts",startTitle:"Address change requested",startEvent:"changeDeliveryAddress() \xb7 order #88231 \xb7 pre-fulfilment",settled:"One order updated; fulfilment notified once.",stateKey:"shopify.orders",faults:n({permTool:"Shopify",downTool:"Slack",perm:"orders",action:"Address",noun:"address change",follow:"fulfilment notice",stateLabel:"Order state",rateTool:"Shopify",after:"20s"})},{id:"refund",label:"Refund damaged item \xb7 order #40117",entry:"issueRefund()",testFile:"tests/issue-refund.ts",startTitle:"Refund requested",startEvent:"issueRefund() \xb7 damaged item \xb7 order #40117",settled:"One refund issued; shopper receipt sent once.",stateKey:"stripe.refunds",faults:n({permTool:"Stripe",downTool:"Klaviyo",perm:"refunds",action:"Refund",noun:"refund",follow:"shopper receipt",stateLabel:"Refund state",rateTool:"Stripe",after:"60s"})}]},{id:"finance",logo:"co-ramp.png",company:"Ramp",tag:"Accounts payable agent",badge:"FINANCE",name:"ramp-ap-twin",blurb:"A finance team runs an AP agent: read the vendor invoice out of the inbox, code the line items against the ledger, check for duplicates, route the approval, and schedule the payment.",caution:"The tool stack and the workflows under test are modelled for this demo. Ramp is a prospect, not an AgentTwin customer. This does not represent their product architecture or a reported failure.",links:[{label:"Accounts payable",href:"https://ramp.com/accounts-payable"},{label:"Agents for AP",href:"https://ramp.com/blog/ramp-ap-agents-announcement"}],services:[o("Gmail","M","Invoices \xb7 inbox","Invoice intake","Simulated","amber","Synthetic invoices; no real mail"),o("NetSuite","N","ERP \xb7 ledger","General ledger","Sanitized copy","","Synthetic chart of accounts; no production import"),o("Slack","#","Approvals \xb7 alerts","Approval routing","Simulated","amber","Approval state; no real messages"),o("Bank rail","B","ACH \xb7 wires","Payment rail","Simulated","amber","Payment state only; no money movement"),o("Snowflake","Sf","Spend analytics","Spend warehouse","Sanitized copy","","Synthetic spend rows; no production data"),o("Postgres","Pg","Bills \xb7 vendors","Bill store","Sanitized copy","","Synthetic bills and vendors"),o("Okta","O","Roles \xb7 limits","Approval authority","Sanitized copy","","Synthetic roles and approval thresholds"),o("Calendar","C","Close calendar","Close schedule","Seeded fixture","","Invented close dates and reminders")],runs:[{id:"invoice",label:"Process vendor invoice \xb7 INV-40981",entry:"processInvoice()",testFile:"tests/process-invoice.ts",startTitle:"Invoice received",startEvent:"processInvoice() \xb7 invoice INV-40981 \xb7 18,400 USD",settled:"One invoice coded, approved, and scheduled once.",stateKey:"erp.bills",faults:n({permTool:"NetSuite",downTool:"Slack",perm:"bill-posting",action:"Invoice",noun:"invoice",follow:"approval request",stateLabel:"Bill state",rateTool:"Bank rail",after:"60s"})},{id:"approval",label:"Approval escalation \xb7 bill #7712 over threshold",entry:"routeApproval()",testFile:"tests/route-approval.ts",startTitle:"Approval needed",startEvent:"routeApproval() \xb7 42,000 USD \xb7 threshold 25,000",settled:"One approval routed; the bill held once.",stateKey:"erp.approvals",faults:n({permTool:"Okta",downTool:"Slack",perm:"approve",action:"Approval",noun:"approval",follow:"approver page",stateLabel:"Approval state",rateTool:"Slack",after:"20s"})},{id:"vendor",label:"Duplicate vendor onboarding \xb7 ACME Corp",entry:"detectDuplicateVendor()",testFile:"tests/dedupe-vendor.ts",startTitle:"Vendor submitted",startEvent:"detectDuplicateVendor() \xb7 ACME Corp \xb7 tax ID match",settled:"One vendor kept; the duplicate merged once.",stateKey:"erp.vendors",faults:n({permTool:"NetSuite",downTool:"Gmail",perm:"vendor-create",action:"Vendor",noun:"vendor record",follow:"welcome email",stateLabel:"Vendor state",rateTool:"Snowflake",after:"30s"})}]},{id:"gtm",logo:"co-clay.png",company:"Clay",tag:"GTM agent",badge:"GTM",name:"clay-gtm-twin",blurb:"A revenue team runs an agent that enriches each inbound lead, scores it against the ICP, routes it to the right rep, and writes the result back to the CRM without duplicating records.",caution:"The tool stack and the workflows under test are modelled for this demo. Clay is a prospect, not an AgentTwin customer. This does not represent their product architecture or a reported failure.",links:[{label:"Claygent",href:"https://www.clay.com/claygent"},{label:"Clay",href:"https://www.clay.com/"}],services:[o("Salesforce","Sf","Leads \xb7 owners","CRM system of record","Simulated","amber","Synthetic leads and ownership; no production writes"),o("HubSpot","H","Lifecycle \xb7 staging","Marketing CRM","Simulated","amber","Synthetic lifecycle stages"),o("Slack","#","Rep alerts","Routing notifications","Simulated","amber","Message state only; no real messages"),o("Gmail","M","Sequences \xb7 replies","Outbound channel","Simulated","amber","Message state only; no real mail"),o("Postgres","Pg","Enrichment store","Enrichment cache","Sanitized copy","","Synthetic enrichment rows"),o("Snowflake","Sf","Warehouse sync","Analytics warehouse","Sanitized copy","","Synthetic rows; no production export"),o("Mixpanel","Mx","Product signals","Usage signals","Simulated","amber","Synthetic event counts"),o("Notion","N","ICP \xb7 playbooks","GTM knowledge","Seeded fixture","","Invented ICP definitions and playbooks"),o("Calendar","C","Meeting booking","Scheduling","Seeded fixture","","Synthetic availability; no bookings")],runs:[{id:"enrich",label:"Enrich inbound lead \xb7 acme.io",entry:"enrichAndScore()",testFile:"tests/enrich-lead.ts",startTitle:"Lead submitted",startEvent:"enrichAndScore() \xb7 acme.io \xb7 inbound form",settled:"One enriched record scored and stored once.",stateKey:"crm.leads",faults:n({permTool:"Salesforce",downTool:"Slack",perm:"lead-write",action:"Lead",noun:"lead",follow:"rep alert",stateLabel:"Lead state",rateTool:"Snowflake",after:"30s"})},{id:"route",label:"Round-robin routing \xb7 14 leads \xb7 3 territories",entry:"routeToRep()",testFile:"tests/route-leads.ts",startTitle:"Routing batch started",startEvent:"routeToRep() \xb7 14 leads \xb7 3 territories",settled:"One owner assigned per lead; no double assignment.",stateKey:"crm.assignments",faults:n({permTool:"Salesforce",downTool:"Slack",perm:"assignment",action:"Assignment",noun:"assignment",follow:"rep DM",stateLabel:"Assignment state",rateTool:"Salesforce",after:"15s"})},{id:"sync",label:"Write enrichment back to CRM \xb7 320 records",entry:"syncEnrichment()",testFile:"tests/sync-enrichment.ts",startTitle:"Sync started",startEvent:"syncEnrichment() \xb7 320 records \xb7 nightly job",settled:"One sync completed; every record written once.",stateKey:"crm.records",faults:n({permTool:"HubSpot",downTool:"Snowflake",perm:"record-update",action:"Record",noun:"record",follow:"warehouse sync",stateLabel:"Record state",rateTool:"HubSpot",after:"60s"})}]},{id:"coding",logo:"co-cognition.png",company:"Cognition",tag:"Coding agent",badge:"ENGINEERING",name:"cognition-coding-twin",blurb:"An engineering team lets a coding agent pick up tickets: reproduce the failure, write the patch, run the migration, and roll back the release when the checks disagree.",caution:"The tool stack and the workflows under test are modelled for this demo. Cognition is a prospect, not an AgentTwin customer. This does not represent their product architecture or a reported failure.",links:[{label:"Devin",href:"https://cognition.ai/"},{label:"Platform",href:"https://cognition.ai/platform"}],services:[o("GitHub","G","PRs \xb7 checks","Source control","Simulated","amber","Synthetic branches and checks; nothing pushed"),o("npm registry","Npm","Packages \xb7 deps","Dependency source","Read only","gray","Read-only package metadata"),o("AWS EC2","A","Compute \xb7 deploys","Runtime infrastructure","Simulated","amber","No instances provisioned or changed"),o("Terraform","Tf","Plans \xb7 state","Infrastructure definition","Read only","gray","Plans read and evaluated only"),o("Postgres","Pg","Schema \xb7 rows","Application database","Sanitized copy","","Synthetic rows; migrations evaluated offline"),o("Datadog","D","Metrics \xb7 traces","Service telemetry","Simulated","amber","Synthetic metrics; no live telemetry"),o("PagerDuty","Pd","Escalations","Incident escalation","Simulated","amber","No real pages sent"),o("Slack","#","PR \xb7 deploy notices","Team notifications","Simulated","amber","Message state only; no real messages"),o("Linear","L","Issues \xb7 intake","Issue tracker","Simulated","amber","Synthetic issues; nothing filed")],runs:[{id:"ci",label:"Fix failing CI on main \xb7 PR #1842",entry:"resolveIssue()",testFile:"tests/resolve-issue.ts",startTitle:"Check failure observed",startEvent:"resolveIssue() \xb7 PR #1842 \xb7 3 failing jobs",settled:"One patch pushed; the checks turned green once.",stateKey:"gh.check_runs",faults:n({permTool:"GitHub",downTool:"Slack",perm:"checks:write",action:"Patch",noun:"patch",follow:"review request",stateLabel:"Check state",rateTool:"GitHub",after:"30s"})},{id:"migrate",label:"Migrate users table \xb7 12,340 rows",entry:"migrateSchema()",testFile:"tests/migrate-users.ts",startTitle:"Migration started",startEvent:"migrateSchema() \xb7 users \xb7 12,340 rows \xb7 2 steps",settled:"One migration recorded; every row migrated once.",stateKey:"db.migrations",faults:n({permTool:"Postgres",downTool:"Slack",perm:"ddl-write",action:"Migration",noun:"migration",follow:"status message",stateLabel:"Migration state",rateTool:"Postgres",after:"45s"})},{id:"rollback",label:"Roll back bad deploy \xb7 svc-api release 4.18.2",entry:"rollBackDeploy()",testFile:"tests/rollback-deploy.ts",startTitle:"Rollback requested",startEvent:"rollBackDeploy() \xb7 svc-api \xb7 release 4.18.2",settled:"One release rolled back; traffic restored once.",stateKey:"deploy.releases",faults:n({permTool:"AWS EC2",downTool:"PagerDuty",perm:"deploy:write",action:"Rollback",noun:"rollback",follow:"incident note",stateLabel:"Release state",rateTool:"Datadog",after:"20s"})}]},{id:"oncall",logo:"co-sentry.svg",company:"Sentry",tag:"On-call agent",badge:"ON-CALL",name:"sentry-oncall-twin",blurb:"An on-call agent watches the error stream: group the new issue, open the incident, page the right responder, and write the root cause summary once the error rate settles.",caution:"The tool stack and the workflows under test are modelled for this demo. Sentry is a prospect, not an AgentTwin customer. This does not represent their product architecture or a reported failure.",links:[{label:"Sentry platform",href:"https://sentry.io/platform/"},{label:"Sentry",href:"https://sentry.io/"}],services:[o("PagerDuty","Pd","Rotations \xb7 pages","On-call paging","Simulated","amber","No real pages sent"),o("Slack","#","Incident channel","Incident comms","Simulated","amber","Channel state only; no real messages"),o("GitHub","G","Fix PRs","Remediation code","Simulated","amber","Synthetic PRs; nothing pushed"),o("Linear","L","Follow-up issues","Follow-up tracking","Simulated","amber","Synthetic issues; nothing filed"),o("Datadog","D","Correlated metrics","Correlated telemetry","Simulated","amber","Synthetic metrics; no live telemetry"),o("AWS EC2","A","Hosted services","Service inventory","Sanitized copy","","No instances provisioned or changed"),o("Terraform","Tf","Service definitions","Service registry","Read only","gray","Read-only service definitions"),o("Okta","O","Identity context","User identity","Sanitized copy","","Synthetic users and groups"),o("Postgres","Pg","Event store","Event archive","Sanitized copy","","Synthetic events; no production rows")],runs:[{id:"triage",label:"Triage new issue \xb7 checkout-api",entry:"triageAlert()",testFile:"tests/triage-issue.ts",startTitle:"Issue seen",startEvent:"triageAlert() \xb7 checkout-api \xb7 1,204 events",settled:"One triage posted; the assignee notified once.",stateKey:"issues.groups",faults:n({permTool:"Linear",downTool:"Slack",perm:"issue-create",action:"Triage",noun:"triage",follow:"assignee notice",stateLabel:"Triage state",rateTool:"Slack",after:"20s"})},{id:"incident",label:"Page on-call \xb7 error spike 5x baseline",entry:"openIncident()",testFile:"tests/open-incident.ts",startTitle:"Spike detected",startEvent:"openIncident() \xb7 5x baseline \xb7 3 minute window",settled:"One incident opened; on-call paged once.",stateKey:"incidents.active",faults:n({permTool:"PagerDuty",downTool:"Slack",perm:"incident-write",action:"Incident",noun:"incident",follow:"on-call page",stateLabel:"Incident state",rateTool:"PagerDuty",after:"60s"})},{id:"rca",label:"Root cause summary \xb7 47 events after resolution",entry:"summarizeRootCause()",testFile:"tests/rca-summary.ts",startTitle:"Resolution observed",startEvent:"summarizeRootCause() \xb7 47 events \xb7 12 minutes",settled:"One RCA stored; stakeholders notified once.",stateKey:"rca.reports",faults:n({permTool:"Postgres",downTool:"Slack",perm:"rca-write",action:"RCA",noun:"RCA",follow:"stakeholder summary",stateLabel:"RCA state",rateTool:"Datadog",after:"30s"})}]},{id:"healthcare",logo:"co-abridge.png",company:"Abridge",tag:"Clinical documentation agent",badge:"HEALTHCARE",name:"abridge-clinical-twin",blurb:"A health system runs a documentation agent: draft the encounter note from the visit, apply coding flags for review, and reconcile the orders against the medication list before sign-off.",caution:"The tool stack and the workflows under test are modelled for this demo. Abridge is a prospect, not an AgentTwin customer. This does not represent their product architecture or a reported failure.",links:[{label:"Abridge",href:"https://abridge.com/"},{label:"For clinicians",href:"https://abridge.com/clinicians"}],services:[o("EHR","Eh","Encounters \xb7 orders","Source of truth","Sanitized copy","","Synthetic encounters; no production patient data"),o("Clinical notes","Cn","Drafts \xb7 sign-off","Note drafts","Seeded fixture","","Invented note content awaiting sign-off"),o("Coding rules","Cr","ICD-10 \xb7 CPT","Coding reference","Seeded fixture","","Invented coding hints, clinician review required"),o("Slack","#","Care-team review","Care-team handoff","Simulated","amber","Message state only; no real messages"),o("Gmail","M","Patient follow-up","Follow-up channel","Simulated","amber","Message state only; no real mail"),o("Postgres","Pg","Normalized store","Normalized records","Sanitized copy","","Synthetic records; no production rows"),o("Okta","O","Clinician roles","Access control","Sanitized copy","","Synthetic users and clinical roles"),o("Calendar","C","Scheduling","Visit schedule","Seeded fixture","","Synthetic appointments; no bookings")],runs:[{id:"note",label:"Draft encounter note \xb7 visit #8821",entry:"fileEncounterNote()",testFile:"tests/file-note.ts",startTitle:"Visit closed",startEvent:"fileEncounterNote() \xb7 visit #8821 \xb7 18 minute audio",settled:"One note drafted; clinician sign-off requested once.",stateKey:"ehr.notes",faults:n({permTool:"EHR",downTool:"Slack",perm:"note-write",action:"Note",noun:"note",follow:"clinician review request",stateLabel:"Note state",rateTool:"EHR",after:"45s"})},{id:"coding",label:"Apply coding flags \xb7 12 claims for review",entry:"flagCoding()",testFile:"tests/flag-coding.ts",startTitle:"Claims batch opened",startEvent:"flagCoding() \xb7 12 claims \xb7 ICD-10 and CPT",settled:"One flag set applied; each claim flagged once.",stateKey:"ehr.codes",faults:n({permTool:"Coding rules",downTool:"Slack",perm:"code-apply",action:"Flag",noun:"coding flag",follow:"review queue notice",stateLabel:"Flag state",rateTool:"EHR",after:"30s"})},{id:"reconcile",label:"Reconcile orders vs medications \xb7 9 orders",entry:"reconcileOrders()",testFile:"tests/reconcile-orders.ts",startTitle:"Reconciliation started",startEvent:"reconcileOrders() \xb7 9 orders \xb7 3 mismatches",settled:"One reconciliation recorded; each mismatch resolved once.",stateKey:"ehr.orders",faults:n({permTool:"EHR",downTool:"Gmail",perm:"order-write",action:"Reconciliation",noun:"reconciliation",follow:"pharmacy message",stateLabel:"Order state",rateTool:"Postgres",after:"60s"})}]},{id:"security",logo:"co-paloalto.png",company:"Palo Alto Networks",tag:"Security triage agent",badge:"SECURITY",name:"paloalto-triage-twin",blurb:"A security operations team runs a triage agent: open the case from the SIEM alert, correlate the surrounding events, isolate the affected host, and hand the responder a complete picture.",caution:"The tool stack and the workflows under test are modelled for this demo. Palo Alto Networks is a prospect, not an AgentTwin customer. This does not represent their product architecture or a reported failure.",links:[{label:"Cortex",href:"https://www.paloaltonetworks.com/cortex"},{label:"Cortex XDR",href:"https://www.paloaltonetworks.com/cortex/cortex-xdr"}],services:[o("SIEM","Si","Alerts \xb7 detections","Alert intake","Simulated","amber","Synthetic alerts; no production events"),o("EDR","Ed","Endpoints \xb7 isolation","Endpoint control","Simulated","amber","No hosts touched or isolated"),o("PagerDuty","Pd","Responder paging","Responder paging","Simulated","amber","No real pages sent"),o("Slack","#","Triage channel","Analyst comms","Simulated","amber","Channel state only; no real messages"),o("GitHub","G","Detection rules","Detection content","Read only","gray","Read-only rule definitions"),o("AWS EC2","A","Workload inventory","Workload inventory","Sanitized copy","","No instances provisioned or changed"),o("Terraform","Tf","Fleet definitions","Fleet definitions","Read only","gray","Read-only fleet definitions"),o("Okta","O","Identity context","Identity context","Sanitized copy","","Synthetic users and sessions"),o("Datadog","D","Telemetry","Correlated telemetry","Simulated","amber","Synthetic metrics; no live telemetry")],runs:[{id:"alert",label:"Triage endpoint alert \xb7 host web-14",entry:"triageAlert()",testFile:"tests/triage-alert.ts",startTitle:"Alert raised",startEvent:"triageAlert() \xb7 host web-14 \xb7 severity high",settled:"One case opened; the responder notified once.",stateKey:"siem.cases",faults:n({permTool:"EDR",downTool:"Slack",perm:"case-write",action:"Case",noun:"case",follow:"responder notice",stateLabel:"Case state",rateTool:"Datadog",after:"30s"})},{id:"correlate",label:"Correlate 5 events \xb7 suspicious egress",entry:"correlateEvents()",testFile:"tests/correlate-events.ts",startTitle:"Events ingested",startEvent:"correlateEvents() \xb7 5 events \xb7 40 minute window",settled:"One correlation stored; each event linked once.",stateKey:"siem.correlations",faults:n({permTool:"SIEM",downTool:"Slack",perm:"correlation-write",action:"Correlation",noun:"correlation",follow:"analyst digest",stateLabel:"Correlation state",rateTool:"SIEM",after:"45s"})},{id:"isolate",label:"Isolate compromised host \xb7 laptop-207",entry:"isolateHost()",testFile:"tests/isolate-host.ts",startTitle:"Isolation requested",startEvent:"isolateHost() \xb7 laptop-207 \xb7 EDR policy",settled:"One host isolated; the ticket closed once.",stateKey:"edr.isolations",faults:n({permTool:"EDR",downTool:"PagerDuty",perm:"isolation",action:"Isolation",noun:"isolation",follow:"ticket update",stateLabel:"Isolation state",rateTool:"PagerDuty",after:"60s"})}]}],i={step:0,connected:!1,replica:!1,busy:!1,customer:"support",mask:!0,isolated:!0,faults:[],recovery:!1,runs:[],tab:"timeline",notice:"",name:r[0].name,runId:r[0].runs[0].id},c=()=>r.find(e=>e.id===i.customer),l=()=>{let e=c();return e.runs.find(e=>e.id===i.runId)||e.runs[0]},d=e=>String(e).replace(/[&<>"']/g,e=>({"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;"})[e]),u=function(e){let t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"";return'<span class="badge '.concat(t,'">').concat(e,"</span>")},p={GitHub:"github.svg",Gmail:"gmail.svg",Slack:"slack.svg",Shopify:"shopify.svg",Intercom:"intercom.svg",Stripe:"stripe.svg",Postgres:"postgres.svg",Salesforce:"salesforce.svg",Calendar:"google-calendar.svg","npm registry":"npm.svg","AWS EC2":"aws.svg",Terraform:"terraform.svg",PagerDuty:"pagerduty.svg",HubSpot:"hubspot.svg",Linear:"linear.svg",Klaviyo:"klaviyo.png",Clay:"clay.png",NetSuite:"netsuite.png",Datadog:"datadog.svg",Okta:"okta.svg",Notion:"notion.svg",Snowflake:"snowflake.svg",Mixpanel:"mixpanel.svg","Clinical notes":"notes.svg","Coding rules":"codes.svg","Return policy":"policy.svg","Bank rail":"bank.svg","CI runner":"ci.svg",EHR:"ehr.svg",SIEM:"siem.svg",EDR:"edr.svg"},m=e=>p[e.brand]?'<img src="/prototype/dist/icons/'.concat(p[e.brand],'" alt="" aria-hidden="true">'):d(e.icon),v=(e,t)=>e.logo?'<span class="'.concat(t,'"><img src="/prototype/dist/icons/').concat(e.logo,'" alt="').concat(d(e.company),'" title="').concat(d(e.company),'"></span>'):'<span class="'.concat(t,'">').concat(d(e.company[0].toLowerCase()),"</span>"),h=function(e,t){let a=arguments.length>2&&void 0!==arguments[2]?arguments[2]:"primary",s=arguments.length>3&&void 0!==arguments[3]&&arguments[3];return'<button class="btn '.concat(a,'" data-action="').concat(t,'" ').concat(s?"disabled":"",">").concat(e,"</button>")},g=function(e,t){let a=arguments.length>2&&void 0!==arguments[2]?arguments[2]:"";return'<section class="panel"><div class="panel-head"><h2>'.concat(e,"</h2><span>").concat(a,"</span></div>").concat(t,"</section>")};function f(e){return 0===e||1===e&&i.connected||e>=2&&i.replica}function y(e){t("#announcer").textContent=e}function b(e){var t;null==(t=document.querySelector(".toast"))||t.remove();let a=document.createElement("div");a.className="toast",a.textContent=e,document.body.append(a),y(e),setTimeout(()=>a.remove(),3300)}function w(e){var a;!i.busy&&f(e)&&(i.step=e,K(),null==(a=t("#step-title"))||a.focus({preventScroll:!0}))}function S(){let e=c();return'<div class="map"><div class="map-label">'.concat(i.replica?"REPLICA TOPOLOGY":"DISCOVERED TOPOLOGY",' / ILLUSTRATIVE DATA</div><div class="rootnode">').concat(v(e,"service-icon"),'<div class="node-title">').concat(d(e.company),'<div class="node-sub">').concat(i.replica?d(i.name):"production \xb7 illustrative manifest","</div></div>").concat(u(i.replica?"Isolated":"Read only",i.replica?"":"gray"),'</div><div class="services">').concat(e.services.map(e=>'<div class="service"><div class="service-icon">'.concat(m(e),'</div><div class="node-title">').concat(e.brand,'</div><div class="node-sub">').concat(e.sub,"</div>").concat(u(e.mode,e.kind),"</div>")).join(""),'</div></div><div class="map-footer"><span class="key"><i class="sq"></i> Seeded fixture</span><span class="key"><i class="sq amber"></i> Behavioral twin</span><span class="key"><i class="sq gray"></i> Untested</span></div>')}function k(){return g("Replica boundaries",'<div class="panel-body"><div class="detail-row"><span>Production writes</span><strong>Blocked</strong></div><div class="detail-row"><span>Customer data</span><strong>Masked</strong></div><div class="detail-row"><span>Credentials</span><strong>Test only</strong></div><div class="detail-row"><span>Outbound email</span><strong>Captured</strong></div><div class="callout">This prototype uses synthetic fixtures. No cloud accounts, databases, or external services are connected.</div></div>')}function T(e){let t=e.id===i.customer;return'<label class="select-card '.concat(t?"selected":"",'"><input type="radio" name="customer" value="').concat(e.id,'" ').concat(t?"checked":"",' aria-label="').concat(d(e.tag),'">').concat(v(e,"large-icon"),'<div class="content"><div class="card-top"><strong>').concat(d(e.company),"</strong>").concat(u(e.badge,"gray"),"</div><p>").concat(d(e.tag)," \xb7 ").concat(e.services.length," tools \xb7 ").concat(e.runs.length,' runs in flight</p><ul class="card-runs">').concat(e.runs.map(e=>"<li>".concat(d(e.label),"</li>")).join(""),"</ul></div></label>")}function C(){let e=c();return'<div class="grid"><div class="stacked">'.concat(g("Example customers",'<div class="panel-body"><div class="connection-header"><div class="large-icon">⌘</div><div><h2>Start with a customer.</h2><p>'.concat(r.length," real companies, each modelled with the tool stack it actually runs and ").concat(r[0].runs.length,' workflows already in twin runs. Pick one to see what AgentTwin would catch.</p></div></div><div class="customer-list">').concat(r.map(T).join(""),'</div><div class="selected-detail"><p class="aside-note">').concat(d(e.blurb),"</p>").concat(e.links.length?'<p class="aside-note" style="margin-top:10px">'.concat(e.links.map(e=>'<a href="'.concat(e.href,'" target="_blank" rel="noopener noreferrer">').concat(e.label,"</a>")).join(" \xb7 "),"</p>"):"",'<div class="callout amber">').concat(d(e.caution),'</div></div><div class="callout">An AgentTwin connector would use scoped, read-only discovery. This prototype loads an illustrative manifest — no credentials, no live systems.</div>').concat(h(i.busy?"Discovering resources…":i.connected?"Review discovered environment":"Run production discovery","discover","primary full",i.busy)).concat(i.busy?'<div class="progress"><div></div></div>':"","</div>"))," ").concat(i.connected?g("Environment discovered",S(),"".concat(e.services.length," DEPENDENCIES")):"",'</div><aside class="stacked">').concat(g("Connection checklist",'<div class="panel-body"><div class="eyebrow">01 / DISCOVERY</div><h3 class="side-title" style="margin-top:15px">Know what you depend on.</h3><p class="aside-note">Build a map before making a replica.</p>'.concat(["Application & entrypoints","Infrastructure & region","Database schema & state","External services","Configuration & permissions"].map(e=>'<div class="detail-row"><span>'.concat(e,'</span><strong class="text-green">').concat(i.connected?"✓":"—","</strong></div>")).join(""),'<div class="callout amber">A replica is only as useful as its coverage. Unverified behavior stays visible.</div></div>'))).concat(k(),"</aside></div>")}function R(){let e=c();return'<div class="grid"><div class="stacked">'.concat(g("Your environment, safely replicated",S(),"".concat(e.services.length," RESOURCES"))).concat(g("What goes into your replica",'<div class="table-scroll"><table class="resource-table"><thead><tr><th>Resource</th><th>Replica behavior</th><th>Coverage boundary</th></tr></thead><tbody>'.concat(c().services.map(e=>'<tr><td><div class="resource-name"><div class="service-icon">'.concat(m(e),"</div><div>").concat(e.brand,'<div class="secondary">').concat(e.name,"</div></div></div></td><td>").concat(u(e.mode,e.kind),'</td><td class="subtle">').concat(e.boundary,"</td></tr>")).join(""),"</tbody></table></div>")),'</div><aside class="stacked">').concat(g("Configure replica",'<div class="panel-body"><label class="label" for="replica-name" style="margin-top:0">Replica name</label><input class="field" id="replica-name" maxlength="40" value="'.concat(d(i.name),'" ').concat(i.replica?"disabled":"",'><label class="toggle-row"><input type="checkbox" checked disabled><div>Sanitize personal data<p>Replace names, emails, and identifiers.</p></div></label><label class="toggle-row"><input type="checkbox" checked disabled><div>Isolate credentials<p>Use test identities. Block production writes.</p></div></label><div class="detail-row"><span>Baseline</span><strong>snapshot_001</strong></div><div class="detail-row"><span>External behavior</span>').concat(u("Simulated","amber"),"</div>").concat(h(i.busy?"Creating replica…":i.replica?"Continue to run code":"Create test replica",i.replica?"run-page":"create","primary full",i.busy)).concat(i.busy?'<div class="progress"><div></div></div>':"",'<p class="safe-note">Prototype \xb7 no infrastructure provisioned</p></div>'))).concat(k(),"</aside></div>")}function E(){let e=c(),t=l();return'<div class="metric-grid"><div class="metric"><strong>'.concat(e.services.length,'</strong><span>Tools in the stack</span></div><div class="metric"><strong>').concat(e.runs.length,'</strong><span>Twin runs in flight</span></div><div class="metric"><strong>').concat(i.runs.length,'</strong><span>Completed test runs</span></div></div><div class="grid"><div class="stacked">').concat(g("Run against your replica",'<div class="panel-body">'.concat(function(){let e=c();return'<span class="label" style="margin-top:0">Twin runs in flight</span><div class="run-list" role="radiogroup" aria-label="Twin runs in flight">'.concat(e.runs.map(e=>{let t=e.id===i.runId,a=i.runs.filter(t=>t.runId===e.id).at(-1),s=a?u(a.pass?"PASS":"FAIL",a.pass?"":"red"):u("In flight","gray");return'<label class="run-card '.concat(t?"selected":"",'"><input type="radio" name="twinrun" value="').concat(e.id,'" ').concat(t?"checked":"",' aria-label="').concat(d(e.label),'"><span class="run-mark" aria-hidden="true">').concat(t?"●":"○",'</span><span class="run-body"><strong>').concat(d(e.label),"</strong><small>").concat(d(e.entry)," \xb7 ").concat(d(e.testFile),"</small></span>").concat(s,"</label>")}).join(""),"</div>")}(),'<div class="code"><span class="comment"># Illustrative integration command</span>\nagenttwin run ').concat(t.testFile," \\\n --world ").concat(d(i.name),' \\\n --snapshot snapshot_001</div><p class="aside-note">This demo runs a scripted workflow against in-memory state. Executing your repository code requires a connected runtime.</p><label class="toggle-row"><input id="recovery" type="checkbox" ').concat(i.recovery?"checked":"",'><div>Preview recovery fixture<p>Show a separate scripted example with safe retries, deduplication, and explicit failure handling.</p></div></label><div class="row-buttons">').concat(h(i.busy?"Running simulation…":"Run simulated workflow","run","primary",i.busy)).concat(h("Configure failures","fault-page","",i.busy),"</div>").concat(i.busy?'<div class="progress"><div></div></div>':"","</div>"))).concat(g("Recent runs",'<div class="panel-body">'.concat(i.runs.length?i.runs.slice().reverse().slice(0,4).map(e=>'<div class="history"><span style="font-family:var(--mono)">run_'.concat(String(e.id).padStart(3,"0"),'</span><span class="subtle">').concat(d(e.runLabel||"")," \xb7 ").concat(e.faults.length?e.faults.length+" conditions":"baseline"," \xb7 ").concat(e.recovery?"recovery preview":"original fixture","</span>").concat(u(e.pass?"PASS":"FAIL",e.pass?"":"red"),"</div>")).join(""):'<p class="aside-note">No runs yet. Start with a baseline, then introduce a failure.</p>',"</div>")),' </div><aside class="stacked">').concat(g("Execution context",'<div class="panel-body"><div class="detail-row"><span>Environment</span><strong>'.concat(d(i.name),'</strong></div><div class="detail-row"><span>Starting state</span><strong>snapshot_001</strong></div><div class="detail-row"><span>Entrypoint</span><strong>').concat(d(t.entry),'</strong></div><div class="detail-row"><span>Network</span><strong>Simulated</strong></div><div class="callout">Each demo run starts from the same baseline. Faults are applied only inside the replica.</div></div>'))).concat(k(),"</aside></div>")}function A(){let e=c(),t=l();return'<div class="grid"><div class="stacked">'.concat(g("Choose what breaks",'<div class="panel-body"><p class="aside-note" style="margin-bottom:6px">Twin run under test \xb7 <strong>'.concat(d(t.label),'</strong></p><p class="aside-note" style="margin-bottom:20px">Combine conditions to test how the workflow recovers.</p><div class="fault-grid">').concat(t.faults.map(e=>'<label class="fault"><div class="fault-head">'.concat(e.name,'<input type="checkbox" name="fault" value="').concat(e.id,'" ').concat(i.faults.includes(e.id)?"checked":"","></div><p>").concat(e.desc,"</p><code>").concat(e.code,"</code></label>")).join(""),'</div><div class="row-buttons">').concat(h(i.busy?"Running simulation…":"Run with selected failures","run","primary",i.busy||!i.faults.length)).concat(h("Clear selection","clear","",i.busy||!i.faults.length),"</div>").concat(i.busy?'<div class="progress"><div></div></div>':"","</div>")),'</div><aside class="stacked">').concat(g("Experiment setup",'<div class="panel-body"><div class="eyebrow">CONTROLLED CONDITIONS</div><h3 class="side-title" style="margin-top:16px">Break the replica.</h3><p class="aside-note">Keep production out of the experiment.</p><div class="detail-row"><span>Conditions selected</span><strong>'.concat(i.faults.length,'</strong></div><div class="detail-row"><span>Target</span><strong>').concat(d(e.company),'</strong></div><div class="detail-row"><span>Twin run</span><strong>').concat(d(t.entry),'</strong></div><label class="toggle-row"><input id="recovery" type="checkbox" ').concat(i.recovery?"checked":"",'><div>Preview recovery fixture<p>Switch to a separate scripted example of recovery behavior.</p></div></label><div class="callout amber">Passing means the expected recovery was observed in this scenario. It does not certify production safety.</div></div>'))).concat(k(),"</aside></div>")}let x=e=>c().runs.find(t=>t.id===e.runId)||l(),I=(e,t)=>x(e).faults.find(e=>e.id===t),P={perm:"Handle the 403 as a visible permission failure. Stop dependent writes and tell the operator which scope or connection needs renewal.",down:"Keep the completed write, persist the unfinished follow-up, and retry that follow-up when the service is available.",late:"Compare event versions or timestamps before applying a delayed event. Ignore an event older than the current state.",timeout:"Create one stable idempotency key for the logical operation, reuse it on every retry, and verify the final provider state.",dup:"Deduplicate by a stable request or event ID with an atomic guard before changing state.",rate:"Respect Retry-After, use bounded backoff, and persist enough context to resume without dropping the operation."};function O(e){var t,a;return e.faults.length?e.pass?Math.max(...e.faults.map(t=>{var a,s;return null!=(s=null==(a=I(e,t))?void 0:a.passCount)?s:1})):null!=(a=null==(t=I(e,e.faults[0]))?void 0:t.failCount)?a:0:1}function D(e){let t=c(),a=x(e),s="run_".concat(String(e.id).padStart(3,"0"));return["AgentTwin simulated run: ".concat(s," \xb7 ").concat(e.pass?"PASS":"FAIL"),"Example company: ".concat(t.company),"Workflow: ".concat(a.entry," \xb7 ").concat(a.label),"Faults: ".concat(e.faults.length?e.faults.map(t=>"".concat(I(e,t).name," (").concat(I(e,t).code,")")).join("; "):"none (baseline)"),"State: ".concat(a.stateKey," 0 → ").concat(O(e)),"Failed assertions: ".concat(e.pass?0:e.faults.length),"Production writes: 0","Illustrative source: ".concat(a.testFile)].join("\n")}function N(e){let t=x(e),a=e.faults.map(t=>{let a=I(e,t);return["- ".concat(a.name,": ").concat(a.failure.t,". ").concat(a.failure.d)," Suggested change: ".concat(P[t])," Passing behavior: ".concat(a.recovery.t,". ").concat(a.recovery.d)].join("\n")});return["Help me fix a failing integration workflow in my own repository.","This AgentTwin result is a synthetic demonstration. Inspect the real code and verify every assumption before changing it.","","Workflow: ".concat(t.entry," (").concat(t.label,")"),"Illustrative test path: ".concat(t.testFile," (this may not exist in my repository)"),"Run: run_".concat(String(e.id).padStart(3,"0")),"","Observed failure and suggested direction:",...a,"","Expected final state: one correct ".concat(t.stateKey," change, no duplicate or lost side effects, and zero failed assertions."),"Observed final state: ".concat(t.stateKey," changed from 0 to ").concat(O(e),"; ").concat(e.faults.length," assertion(s) failed."),"","Please locate the matching workflow, identify the actual root cause, make the smallest safe code change, add a regression test for this fault, and report what changed. Then rerun the same scenario and compare the final state and assertions. Do not treat the demo recovery fixture as a patch."].join("\n")}function L(){let e=i.runs.at(-1);if(!e)return g("No result yet",'<div class="empty"><h2>Run a workflow first.</h2><p>AgentTwin will show the outcome, the cause, and your next action here.</p><div class="row-buttons" style="justify-content:center">'.concat(h("Choose a workflow","run-page"),"</div></div>"));let t=x(e),a=!e.pass,s=e.pass?e.faults.length?"handled_error":"completed":"inconsistent",n=e.faults.length?e.faults.map(t=>I(e,t).recovery.t).join("; "):t.settled,o=a?e.faults.map(t=>I(e,t).failure.t).join("; "):"Expected state and assertions matched in this simulated run.",r='<section class="panel"><div class="result-banner '.concat(a?"failed":"",'"><div class="result-icon">').concat(a?"!":"✓","</div><div><h2>").concat(a?"Failed: the final state is wrong":"Passed in the simulated replica","</h2><p>run_").concat(String(e.id).padStart(3,"0")," \xb7 ").concat(e.recovery?"Recovery fixture":"Original fixture"," \xb7 ").concat(e.faults.length?"".concat(e.faults.length," fault").concat(1===e.faults.length?"":"s"):"Baseline",'</p></div></div><div class="decision-summary"><div><span>Expected</span><strong>').concat(d(n),"</strong></div><div><span>Observed</span><strong>").concat(d(o),'</strong></div></div><div class="tabs" role="tablist">').concat(["timeline","state diff","assertions"].map(e=>'<button class="tab '.concat(i.tab===e?"active":"",'" role="tab" aria-selected="').concat(i.tab===e,'" data-tab="').concat(e,'">').concat(e[0].toUpperCase()+e.slice(1),"</button>")).join(""),"</div>").concat("timeline"===i.tab?'<div class="timeline">'.concat(e.events.map(e=>'<div class="event '.concat(e.error?"error":"",'"><time>').concat(e.time,'</time><i class="line-dot"></i><div><strong>').concat(e.title,"</strong><p>").concat(e.desc,"</p></div>").concat(u(e.status,"INJECTED"===e.status?"amber":e.error?"red":""),"</div>")).join(""),"</div>"):"state diff"===i.tab?'<div class="panel-body"><div class="code"><span class="comment"># snapshot_001 → run_'.concat(String(e.id).padStart(3,"0"),"</span>\nworkflow.status: idle → ").concat(s,"\n").concat(t.stateKey,": 0 → ").concat(O(e),"\nproduction.writes: 0 → 0\nassertions.failed: 0 → ").concat(a?e.faults.length:0,'</div><p class="aside-note">Illustrative changes from the scripted demo, not a production trace.</p></div>'):'<div class="panel-body">'.concat(e.faults.length?e.faults.map(t=>{let a=I(e,t);return'<div class="detail-row"><span>'.concat(d(e.pass?a.recovery.t:a.failure.t),"</span>").concat(u(e.pass?"PASS":"FAIL",e.pass?"":"red"),"</div>")}).join(""):'<div class="detail-row"><span>Expected state created exactly once</span>'.concat(u("PASS"),"</div>"),'<div class="detail-row"><span>No production writes</span>').concat(u("PASS"),'</div><div class="detail-row"><span>No external messages delivered</span>').concat(u("PASS"),"</div></div>"),"</section>"),c=a?g("What broke and how to fix it",'<div class="panel-body"><p class="aside-note">These causes come from the demo fixture. Confirm them against your actual code and logs.</p>'.concat(e.faults.map(t=>{let a=I(e,t);return'<div class="diagnosis-item"><span class="eyebrow">'.concat(d(a.name)," \xb7 ").concat(d(a.code),"</span><h3>").concat(d(a.failure.t),"</h3><p>").concat(d(a.failure.d),"</p><p><strong>Change to try:</strong> ").concat(d(P[t]),"</p></div>")}).join(""),"</div>")):"",l=a?g("Next: fix your code, then rerun",'<div class="panel-body"><div class="action-steps"><div><b>1</b><span>Copy this fix prompt into your coding agent or use it to edit the workflow yourself.</span></div><div><b>2</b><span>Make the code change and add a regression test in your repository.</span></div><div><b>3</b><span>Rerun the same fault and check that the final state and assertions pass.</span></div></div><div class="code fix-prompt">'.concat(d(N(e)),'</div><div class="row-buttons">').concat(h("Copy fix prompt","copy-fix","primary")).concat(h("Preview recovery fixture","preview-recovery",""),'</div><p class="safe-note">This prototype cannot read or patch your repository. The recovery preview is a separate scripted fixture.</p></div>')):g("What to do next",'<div class="panel-body"><p class="aside-note">The expected state matched in this simulated run. Keep the scenario as a regression target, then test your real code when a connected runner exists.</p><div class="code fix-prompt">'.concat(d(D(e)),'</div><div class="row-buttons">').concat(h("Copy result report","copy-evidence","primary")).concat(h("Try another failure","fault-page",""),"</div></div>")),p=g("Repeat the same conditions",'<div class="panel-body"><div class="detail-row"><span>Starting state</span><strong>snapshot_001</strong></div><div class="detail-row"><span>Injected faults</span><strong>'.concat(e.faults.length,'</strong></div><div class="detail-row"><span>Result</span>').concat(u(e.pass?"PASS":"FAIL",e.pass?"":"red"),'</div><p class="aside-note" style="margin-top:15px">Rerun uses the same scripted implementation and faults. Reset clears the faults and returns to workflow setup.</p>').concat(h("Rerun current fixture","rerun","primary full",i.busy)).concat(h("Reset to baseline","reset","full"),'<p class="safe-note">All results are simulated.</p></div>'));return'<div class="grid"><div class="stacked">'.concat(r).concat(c).concat(l,'</div><aside class="stacked">').concat(p).concat(k(),"</aside></div>")}let F=["Connect production.","Your production. A safe replica.","Real workflows. Safe consequences.","Find the failures before they find you.","See what broke. Know what to do."],M=["Choose an example customer, then map its production stack before creating an isolated test environment.","Review what is copied, what is simulated, and what stays untouched.","Pick one of the workflows this team already has in flight, then run it against a repeatable baseline.","Put the same workflow through conditions a happy-path test misses.","Read the failed assertion, copy a fix prompt, change your code, and rerun the same scenario. This prototype only previews the recovery behavior."];function K(){let e=c();t("#app").innerHTML='<div class="announce"><span class="dot"></span> Interactive prototype \xb7 all data synthetic \xb7 no live systems connected</div><header class="topnav"><div class="brand"><img class="brandmark" src="assets/logo/mark-twin-rings.svg?v=white-rings" alt="" width="28" height="28">AgentTwin<small>α</small></div><nav class="navlinks" aria-label="Prototype navigation"><span class="navlink active">Customers</span><span class="navlink">Workflows</span><span class="navlink">Receipts</span><span class="navlink">Docs</span></nav><div class="nav-right"><span class="demo-pill">DEMO MODE</span><span class="avatar">SS</span></div></header><section class="hero"><div class="hero-inner"><div class="eyebrow">ENVIRONMENT / '.concat(i.replica?"REPLICA":"SETUP",'</div><h1 tabindex="-1" id="step-title">').concat(F[i.step],'</h1><p class="lead">').concat(M[i.step],'</p></div><div class="hero-side">').concat(i.connected?u(i.replica?"Replica isolated":"Discovery complete"):u("No live connections","gray"),'</div></section><div class="appwindow"><nav class="sidebar" aria-label="Main navigation"><div class="workspace"><span class="avatar">AT</span><div>Customer workspace<div class="secondary">Pick a company to model</div></div></div><div class="nav-label">Build confidence</div>').concat(a.map((e,t)=>'<button class="navbtn '.concat(i.step===t?"active":"",'" data-step="').concat(t,'" ').concat(!f(t)||i.busy?"disabled":"",'><span class="navnum">0').concat(t+1,"</span>").concat(e,"</button>")).join(""),'<div class="sidebar-bottom"><span class="demo-pill"><i class="dot"></i> INTERACTIVE PROTOTYPE</span><p style="margin-top:12px">A safe place to break things.</p><p class="subtle" style="font-size:11px;margin-top:8px">Illustrative data \xb7 no live connections</p></div></nav><main class="main"><header class="topbar"><span class="mobile-brand">AgentTwin</span><div class="crumb"><span class="subtle">Workspace</span><span class="subtle">/</span><span>').concat(d(e.company),'</span><span class="subtle">/</span><span>').concat(a[i.step],'</span></div><div class="topright"><span class="demo-pill">DEMO MODE</span><span class="avatar">SS</span></div></header><div class="main-inner"><div class="steps" aria-label="Setup progress">').concat(a.map((e,t)=>'<button class="step '.concat(i.step===t?"current":i.step>t?"done":"",'" data-step="').concat(t,'" ').concat(!f(t)||i.busy?"disabled":"","><b>").concat(i.step>t?"✓":t+1,"</b>").concat(s[t],"</button>")).join(""),"</div>").concat(i.notice?'<div class="notice" role="status"><strong>'.concat(d(i.notice),"</strong></div>"):"").concat([C,R,E,A,L][i.step](),'<footer class="bottom-note"><span>AGENTTWIN / PRODUCTION REPLICA WORKSPACE</span><span>No real systems are touched.</span></footer></div></main></div></div>')}async function H(e){return new Promise(t=>setTimeout(t,e))}async function j(e){if(!i.busy)if(i.notice="","discover"===e){if(i.connected)return w(1);i.busy=!0,K(),await H(1e3),i.connected=!0,i.busy=!1,i.step=1,K(),y("Discovered ".concat(c().services.length," dependencies. Review your replica."))}else if("create"===e){var a,s;let e=null==(a=t("#replica-name"))?void 0:a.value.trim();if(!e||!/^[a-z0-9][a-z0-9-]{0,39}$/.test(e)){b("Use 1–40 lowercase letters, numbers, or hyphens."),null==(s=t("#replica-name"))||s.focus();return}i.name=e,i.busy=!0,K(),await H(1200),i.replica=!0,i.busy=!1,i.step=2,K(),y("Test replica created. Ready to run a simulated workflow.")}else if("run-page"===e)w(2);else if("fault-page"===e)w(3);else if(["run","rerun","preview-recovery"].includes(e)){if(!i.replica)return;if("rerun"===e||"preview-recovery"===e){let t=i.runs.at(-1);if(!t)return;i.faults=[...t.faults],i.recovery="preview-recovery"===e||t.recovery}i.busy=!0,K(),await H(1100),i.runs.push(function(){let e=l(),t=[...i.faults],a=i.recovery,s=!t.length||a,n=[{time:"0.00s",title:"Baseline restored",desc:"snapshot_001 \xb7 synthetic records and test identities",status:"READY"},{time:"0.08s",title:e.startTitle,desc:e.startEvent,status:"START"}];return t.forEach((t,s)=>{let o=e.faults.find(e=>e.id===t);n.push({time:(.2+.3*s).toFixed(2)+"s",title:o.name,desc:o.desc,status:"INJECTED",error:!0}),n.push({time:(.35+.3*s).toFixed(2)+"s",title:a?o.recovery.t:o.failure.t,desc:a?o.recovery.d:o.failure.d,status:a?"HANDLED":"FAILED",error:!a})}),t.length||n.push({time:"0.46s",title:"State updated once",desc:e.settled,status:"PASS"}),n.push({time:(.7+.3*t.length).toFixed(2)+"s",title:"Final state assertions evaluated",desc:s?"No duplicate actions. Outcome recorded. No production writes.":"Unexpected state detected. Review the failed assertions.",status:s?"PASS":"FAIL",error:!s}),{id:i.runs.length+1,runId:e.id,runLabel:e.label,pass:s,faults:t,recovery:a,events:n}}()),i.busy=!1,i.step=4,i.tab="timeline",K(),y(i.runs.at(-1).pass?"Run passed. Expected outcome verified.":"Run failed. Read what broke, copy the fix prompt, and rerun.")}else if("clear"===e)i.faults=[],K();else if("copy-evidence"===e||"copy-fix"===e){let t=i.runs.at(-1);if(!t)return;let a="copy-fix"===e?N(t):D(t);try{await navigator.clipboard.writeText(a)}catch(t){let e=document.createElement("textarea");e.value=a,e.style.position="fixed",e.style.opacity="0",document.body.appendChild(e),e.select();try{document.execCommand("copy")}catch(e){}e.remove()}b("copy-fix"===e?"Fix prompt copied. Use it with your code, then rerun.":"Result report copied."),y("copy-fix"===e?"Fix prompt copied to the clipboard.":"Result report copied to the clipboard.")}else"reset"===e&&(i.faults=[],i.recovery=!1,i.step=2,i.notice="Replica restored to snapshot_001. Failure conditions cleared. Run history retained.",K(),y(i.notice))}if(document.addEventListener("click",e=>{let t=e.target.closest("button");t&&!t.disabled&&(t.dataset.action&&j(t.dataset.action),void 0!==t.dataset.step&&w(Number(t.dataset.step)),t.dataset.tab&&(i.tab=t.dataset.tab,K()))}),document.addEventListener("change",e=>{if(!i.busy){if("customer"===e.target.name&&(i.customer=e.target.value,i.name=c().name,i.runId=c().runs[0].id,i.connected=!1,i.replica=!1,i.runs=[],i.faults=[],i.recovery=!1,i.step=0,i.notice="",K(),y("Customer switched to ".concat(c().company,". ").concat(c().runs.length," twin runs available."))),"twinrun"===e.target.name){if(e.target.value===i.runId)return;i.runId=e.target.value,i.faults=[],i.recovery=!1,K(),y("Twin run selected: ".concat(l().label,"."))}"fault"===e.target.name&&(i.faults=e.target.checked?[...i.faults,e.target.value]:i.faults.filter(t=>t!==e.target.value),K()),"recovery"===e.target.id&&(i.recovery=e.target.checked,K())}}),K(),null==(e=document.modelContext)?void 0:e.registerTool)for(let e of[{name:"read_replica_demo",description:"Read current simulated replica and latest result. No production systems are connected.",inputSchema:{type:"object",properties:{},additionalProperties:!1},annotations:{readOnlyHint:!0},execute:()=>({connected:i.connected,replica:i.replica,customer:c().company,step:a[i.step],faults:[...i.faults],lastRun:i.runs.at(-1)||null})},{name:"configure_demo_failures",description:"Select failure conditions in the simulated replica. Does not run a test.",inputSchema:{type:"object",properties:{faults:{type:"array",items:{type:"string",enum:[...new Set(r.flatMap(e=>e.runs.flatMap(e=>e.faults.map(e=>e.id))))]}}},required:["faults"],additionalProperties:!1},annotations:{readOnlyHint:!1},execute:e=>{if(!i.replica||i.busy)throw Error("Create an idle replica first");if(!e||!Array.isArray(e.faults)||e.faults.some(e=>!l().faults.some(t=>t.id===e)))throw Error("Invalid failure selection");return i.faults=[...new Set(e.faults)],i.step=3,K(),{faults:i.faults}}}])try{Promise.resolve(document.modelContext.registerTool(e)).catch(()=>{})}catch(e){}}()}),()=>{e=!0}},[]),(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)("a",{href:"/dashboard/",className:"dashboard-link",children:"View actual test results in the AgentTwin dashboard ↗"}),(0,s.jsx)("div",{id:"app"}),(0,s.jsx)("div",{id:"announcer",className:"sr-only",role:"status","aria-live":"polite"})]})}},7537:()=>{},9133:(e,t,a)=>{Promise.resolve().then(a.bind(a,964)),Promise.resolve().then(a.t.bind(a,7537,23))}},e=>{e.O(0,[9742,7903,4816,7358],()=>e(e.s=9133)),_N_E=e.O()}]);
1
+ (self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[9436],{964:(e,t,a)=>{"use strict";a.d(t,{default:()=>o});var s=a(1778),n=a(5226);function o(){return(0,n.useEffect)(()=>{let e=!1;return queueMicrotask(()=>{e||function(){var e;let t=e=>document.querySelector(e),a=["Connect production","Create replica","Run code","Introduce failures","Diagnose, fix, rerun"],s=["Connect","Create replica","Run code","Add failures","Diagnose & rerun"],n=e=>[{id:"perm",name:"Expired permissions",desc:"The ".concat(e.permTool," connection loses ").concat(e.perm," write permission."),code:"403 \xb7 access denied",failCount:0,passCount:0,failure:{t:"".concat(e.action," failure swallowed"),d:"The caller received no actionable permission error."},recovery:{t:"Permission failure surfaced",d:"Workflow stops with an actionable error and no partial ".concat(e.noun," records.")}},{id:"down",name:"Service unavailable",desc:"".concat(e.downTool," is unavailable after the ").concat(e.noun," succeeds."),code:"503 \xb7 ".concat(String(e.downTool).toLowerCase()," unavailable"),failCount:1,passCount:1,failure:{t:"".concat(e.action," saved; ").concat(e.follow," lost"),d:"".concat(e.stateLabel," was written, but ").concat(e.follow," never happened.")},recovery:{t:"Outage handled",d:"".concat(e.action," preserved; ").concat(e.follow," queued for recovery.")}},{id:"late",name:"Delayed event",desc:"A completion event arrives after the caller times out.",code:"+30s \xb7 event delivery",failCount:1,passCount:1,failure:{t:"Late event overwrote newer state",d:"The expired operation updated a completed ".concat(e.noun,".")},recovery:{t:"Stale event ignored",d:"The event version check prevents a stale state transition."}},{id:"timeout",name:"Timeout after success",desc:"The operation completes, but its response is lost.",code:"ETIMEDOUT \xb7 after write",failCount:2,passCount:1,failure:{t:"Retry created a second ".concat(e.noun),d:"The original write succeeded; the retry used a new operation key."},recovery:{t:"Retry reused the operation key",d:"The existing operation is returned; no duplicate is created."}},{id:"dup",name:"Duplicate delivery",desc:"The same request or event is delivered twice.",code:"2\xd7 \xb7 same operation",failCount:2,passCount:1,failure:{t:"Duplicate processed twice",d:"No atomic deduplication guarded the repeated operation."},recovery:{t:"Duplicate safely ignored",d:"The atomic deduplication guard permits one ".concat(e.noun," state mutation.")}},{id:"rate",name:"Rate limit",desc:"".concat(e.rateTool," rejects the burst."),code:"429 \xb7 retry after ".concat(e.after),failCount:1,passCount:1,failure:{t:"".concat(e.action," dropped without retry"),d:"The retry-after interval was ignored."},recovery:{t:"Retry-after respected",d:"The simulated scheduler retries after the required delay."}}],o=(e,t,a,s,n,o,r)=>({brand:e,icon:t,sub:a,name:s,mode:n,kind:o,boundary:r}),r=[{id:"support",logo:"co-pylon.png",company:"Pylon",tag:"B2B support agent",badge:"SUPPORT",name:"pylon-support-twin",blurb:"A B2B SaaS company runs support through an agent: look up the account, decide the credit, file the engineering escalation, and answer the customer once. The stack below is the one a team like this actually runs.",caution:"The tool stack and the workflows under test are modelled for this demo. Pylon is a prospect, not an AgentTwin customer. This does not represent Pylon private architecture or a reported failure.",links:[{label:"AI support agents",href:"https://www.usepylon.com/ai-agents/support"},{label:"Slack agent",href:"https://www.usepylon.com/ai-agents/slack"}],services:[o("Slack","#","Threads \xb7 replies","Customer conversation","Simulated","amber","Thread state only; no real delivery"),o("HubSpot","H","Accounts \xb7 plans","Account and plan state","Simulated","amber","Synthetic accounts and plan data"),o("Stripe","$","Billing \xb7 credits","Billing state","Simulated","amber","Synthetic charges and credits; no money movement"),o("Linear","L","Issues \xb7 escalations","Engineering escalation","Simulated","amber","Synthetic issues; nothing filed"),o("Gmail","M","Email \xb7 replies","Email channel","Simulated","amber","Message state only; no real mail"),o("Notion","N","Runbooks \xb7 macros","Agent knowledge","Seeded fixture","","Invented macros and escalation runbooks"),o("GitHub","G","Repros \xb7 linked bugs","Bug reproduction","Sanitized copy","","Synthetic repositories and issue links"),o("Datadog","D","Service health","Dependency health","Simulated","amber","Synthetic monitors; no live telemetry"),o("Okta","O","SSO \xb7 roles","Identity and roles","Sanitized copy","","Synthetic users and role grants")],runs:[{id:"credit",label:"Issue billing credit \xb7 account #8841",entry:"issueBillingCredit()",testFile:"tests/issue-billing-credit.ts",startTitle:"Credit requested",startEvent:"issueBillingCredit() \xb7 over-billed account \xb7 #8841",settled:"One credit recorded; customer notified once.",stateKey:"stripe.credits",faults:n({permTool:"HubSpot",downTool:"Slack",perm:"billing",action:"Credit",noun:"credit",follow:"customer reply",stateLabel:"Credit state",rateTool:"Linear",after:"10s"})},{id:"escalation",label:"Escalate P1 \xb7 SLA at risk \xb7 ticket #4412",entry:"escalateToEngineering()",testFile:"tests/escalate-p1.ts",startTitle:"Escalation opened",startEvent:"escalateToEngineering() \xb7 P1 \xb7 ticket #4412",settled:"One issue created; the on-call engineer paged once.",stateKey:"linear.escalations",faults:n({permTool:"Linear",downTool:"Slack",perm:"issue-create",action:"Escalation",noun:"escalation",follow:"on-call page",stateLabel:"Escalation state",rateTool:"Linear",after:"15s"})},{id:"summary",label:"Summarize 40-message thread \xb7 enterprise account",entry:"draftResolutionSummary()",testFile:"tests/draft-summary.ts",startTitle:"Summary requested",startEvent:"draftResolutionSummary() \xb7 40 messages \xb7 acct-119",settled:"One summary stored; nothing sent to the customer.",stateKey:"pylon.summaries",faults:n({permTool:"Notion",downTool:"Slack",perm:"write",action:"Summary",noun:"summary",follow:"Slack digest",stateLabel:"Summary state",rateTool:"Datadog",after:"30s"})}]},{id:"ecom",logo:"co-intercom.svg",company:"Intercom",tag:"E-commerce support agent",badge:"SUPPORT",name:"intercom-returns-twin",blurb:"A Shopify brand lets a support agent resolve post-purchase conversations: find the order, approve the return or exchange, process the refund, and message the shopper in the brand voice.",caution:"The tool stack and the workflows under test are modelled for this demo. Intercom is a prospect, not an AgentTwin customer. This does not represent their product architecture or a reported failure.",links:[{label:"Fin AI agent",href:"https://www.intercom.com/fin"},{label:"Intercom AI",href:"https://www.intercom.com/ai"}],services:[o("Shopify","S","Orders \xb7 returns","Order state","Simulated","amber","Synthetic orders and returns; no money movement"),o("Intercom","I","Inbox \xb7 Fin replies","Support conversation","Simulated","amber","Ticket state and replies; no customer contact"),o("Stripe","$","Refunds \xb7 charges","Payment state","Simulated","amber","Synthetic refunds; no money movement"),o("Klaviyo","K","Email \xb7 SMS flows","Shopper notification","Simulated","amber","Message state only; no real delivery"),o("Slack","#","Internal escalation","Internal handoff","Simulated","amber","Channel state only; no real messages"),o("Notion","N","Macros \xb7 policy","Support knowledge","Seeded fixture","","Invented macros and exchange rules"),o("Gmail","M","Email fallback","Email channel","Simulated","amber","Message state only; no real mail"),o("Postgres","Pg","Orders \xb7 customers","Order store","Sanitized copy","","Synthetic orders, no production rows")],runs:[{id:"return",label:"Resolve post-purchase return \xb7 order #2210",entry:"resolveReturnRequest()",testFile:"tests/resolve-return.ts",startTitle:"Return requested",startEvent:"resolveReturnRequest() \xb7 exchange requested \xb7 order #2210",settled:"One return created; shopper notified once.",stateKey:"shopify.returns",faults:n({permTool:"Shopify",downTool:"Klaviyo",perm:"returns",action:"Return",noun:"return",follow:"shopper notification",stateLabel:"Return state",rateTool:"Klaviyo",after:"30s"})},{id:"address",label:"Change delivery address \xb7 order #88231",entry:"changeDeliveryAddress()",testFile:"tests/change-address.ts",startTitle:"Address change requested",startEvent:"changeDeliveryAddress() \xb7 order #88231 \xb7 pre-fulfilment",settled:"One order updated; fulfilment notified once.",stateKey:"shopify.orders",faults:n({permTool:"Shopify",downTool:"Slack",perm:"orders",action:"Address",noun:"address change",follow:"fulfilment notice",stateLabel:"Order state",rateTool:"Shopify",after:"20s"})},{id:"refund",label:"Refund damaged item \xb7 order #40117",entry:"issueRefund()",testFile:"tests/issue-refund.ts",startTitle:"Refund requested",startEvent:"issueRefund() \xb7 damaged item \xb7 order #40117",settled:"One refund issued; shopper receipt sent once.",stateKey:"stripe.refunds",faults:n({permTool:"Stripe",downTool:"Klaviyo",perm:"refunds",action:"Refund",noun:"refund",follow:"shopper receipt",stateLabel:"Refund state",rateTool:"Stripe",after:"60s"})}]},{id:"finance",logo:"co-ramp.png",company:"Ramp",tag:"Accounts payable agent",badge:"FINANCE",name:"ramp-ap-twin",blurb:"A finance team runs an AP agent: read the vendor invoice out of the inbox, code the line items against the ledger, check for duplicates, route the approval, and schedule the payment.",caution:"The tool stack and the workflows under test are modelled for this demo. Ramp is a prospect, not an AgentTwin customer. This does not represent their product architecture or a reported failure.",links:[{label:"Accounts payable",href:"https://ramp.com/accounts-payable"},{label:"Agents for AP",href:"https://ramp.com/blog/ramp-ap-agents-announcement"}],services:[o("Gmail","M","Invoices \xb7 inbox","Invoice intake","Simulated","amber","Synthetic invoices; no real mail"),o("NetSuite","N","ERP \xb7 ledger","General ledger","Sanitized copy","","Synthetic chart of accounts; no production import"),o("Slack","#","Approvals \xb7 alerts","Approval routing","Simulated","amber","Approval state; no real messages"),o("Bank rail","B","ACH \xb7 wires","Payment rail","Simulated","amber","Payment state only; no money movement"),o("Snowflake","Sf","Spend analytics","Spend warehouse","Sanitized copy","","Synthetic spend rows; no production data"),o("Postgres","Pg","Bills \xb7 vendors","Bill store","Sanitized copy","","Synthetic bills and vendors"),o("Okta","O","Roles \xb7 limits","Approval authority","Sanitized copy","","Synthetic roles and approval thresholds"),o("Calendar","C","Close calendar","Close schedule","Seeded fixture","","Invented close dates and reminders")],runs:[{id:"invoice",label:"Process vendor invoice \xb7 INV-40981",entry:"processInvoice()",testFile:"tests/process-invoice.ts",startTitle:"Invoice received",startEvent:"processInvoice() \xb7 invoice INV-40981 \xb7 18,400 USD",settled:"One invoice coded, approved, and scheduled once.",stateKey:"erp.bills",faults:n({permTool:"NetSuite",downTool:"Slack",perm:"bill-posting",action:"Invoice",noun:"invoice",follow:"approval request",stateLabel:"Bill state",rateTool:"Bank rail",after:"60s"})},{id:"approval",label:"Approval escalation \xb7 bill #7712 over threshold",entry:"routeApproval()",testFile:"tests/route-approval.ts",startTitle:"Approval needed",startEvent:"routeApproval() \xb7 42,000 USD \xb7 threshold 25,000",settled:"One approval routed; the bill held once.",stateKey:"erp.approvals",faults:n({permTool:"Okta",downTool:"Slack",perm:"approve",action:"Approval",noun:"approval",follow:"approver page",stateLabel:"Approval state",rateTool:"Slack",after:"20s"})},{id:"vendor",label:"Duplicate vendor onboarding \xb7 ACME Corp",entry:"detectDuplicateVendor()",testFile:"tests/dedupe-vendor.ts",startTitle:"Vendor submitted",startEvent:"detectDuplicateVendor() \xb7 ACME Corp \xb7 tax ID match",settled:"One vendor kept; the duplicate merged once.",stateKey:"erp.vendors",faults:n({permTool:"NetSuite",downTool:"Gmail",perm:"vendor-create",action:"Vendor",noun:"vendor record",follow:"welcome email",stateLabel:"Vendor state",rateTool:"Snowflake",after:"30s"})}]},{id:"gtm",logo:"co-clay.png",company:"Clay",tag:"GTM agent",badge:"GTM",name:"clay-gtm-twin",blurb:"A revenue team runs an agent that enriches each inbound lead, scores it against the ICP, routes it to the right rep, and writes the result back to the CRM without duplicating records.",caution:"The tool stack and the workflows under test are modelled for this demo. Clay is a prospect, not an AgentTwin customer. This does not represent their product architecture or a reported failure.",links:[{label:"Claygent",href:"https://www.clay.com/claygent"},{label:"Clay",href:"https://www.clay.com/"}],services:[o("Salesforce","Sf","Leads \xb7 owners","CRM system of record","Simulated","amber","Synthetic leads and ownership; no production writes"),o("HubSpot","H","Lifecycle \xb7 staging","Marketing CRM","Simulated","amber","Synthetic lifecycle stages"),o("Slack","#","Rep alerts","Routing notifications","Simulated","amber","Message state only; no real messages"),o("Gmail","M","Sequences \xb7 replies","Outbound channel","Simulated","amber","Message state only; no real mail"),o("Postgres","Pg","Enrichment store","Enrichment cache","Sanitized copy","","Synthetic enrichment rows"),o("Snowflake","Sf","Warehouse sync","Analytics warehouse","Sanitized copy","","Synthetic rows; no production export"),o("Mixpanel","Mx","Product signals","Usage signals","Simulated","amber","Synthetic event counts"),o("Notion","N","ICP \xb7 playbooks","GTM knowledge","Seeded fixture","","Invented ICP definitions and playbooks"),o("Calendar","C","Meeting booking","Scheduling","Seeded fixture","","Synthetic availability; no bookings")],runs:[{id:"enrich",label:"Enrich inbound lead \xb7 acme.io",entry:"enrichAndScore()",testFile:"tests/enrich-lead.ts",startTitle:"Lead submitted",startEvent:"enrichAndScore() \xb7 acme.io \xb7 inbound form",settled:"One enriched record scored and stored once.",stateKey:"crm.leads",faults:n({permTool:"Salesforce",downTool:"Slack",perm:"lead-write",action:"Lead",noun:"lead",follow:"rep alert",stateLabel:"Lead state",rateTool:"Snowflake",after:"30s"})},{id:"route",label:"Round-robin routing \xb7 14 leads \xb7 3 territories",entry:"routeToRep()",testFile:"tests/route-leads.ts",startTitle:"Routing batch started",startEvent:"routeToRep() \xb7 14 leads \xb7 3 territories",settled:"One owner assigned per lead; no double assignment.",stateKey:"crm.assignments",faults:n({permTool:"Salesforce",downTool:"Slack",perm:"assignment",action:"Assignment",noun:"assignment",follow:"rep DM",stateLabel:"Assignment state",rateTool:"Salesforce",after:"15s"})},{id:"sync",label:"Write enrichment back to CRM \xb7 320 records",entry:"syncEnrichment()",testFile:"tests/sync-enrichment.ts",startTitle:"Sync started",startEvent:"syncEnrichment() \xb7 320 records \xb7 nightly job",settled:"One sync completed; every record written once.",stateKey:"crm.records",faults:n({permTool:"HubSpot",downTool:"Snowflake",perm:"record-update",action:"Record",noun:"record",follow:"warehouse sync",stateLabel:"Record state",rateTool:"HubSpot",after:"60s"})}]},{id:"coding",logo:"co-cognition.png",company:"Cognition",tag:"Coding agent",badge:"ENGINEERING",name:"cognition-coding-twin",blurb:"An engineering team lets a coding agent pick up tickets: reproduce the failure, write the patch, run the migration, and roll back the release when the checks disagree.",caution:"The tool stack and the workflows under test are modelled for this demo. Cognition is a prospect, not an AgentTwin customer. This does not represent their product architecture or a reported failure.",links:[{label:"Devin",href:"https://cognition.ai/"},{label:"Platform",href:"https://cognition.ai/platform"}],services:[o("GitHub","G","PRs \xb7 checks","Source control","Simulated","amber","Synthetic branches and checks; nothing pushed"),o("npm registry","Npm","Packages \xb7 deps","Dependency source","Read only","gray","Read-only package metadata"),o("AWS EC2","A","Compute \xb7 deploys","Runtime infrastructure","Simulated","amber","No instances provisioned or changed"),o("Terraform","Tf","Plans \xb7 state","Infrastructure definition","Read only","gray","Plans read and evaluated only"),o("Postgres","Pg","Schema \xb7 rows","Application database","Sanitized copy","","Synthetic rows; migrations evaluated offline"),o("Datadog","D","Metrics \xb7 traces","Service telemetry","Simulated","amber","Synthetic metrics; no live telemetry"),o("PagerDuty","Pd","Escalations","Incident escalation","Simulated","amber","No real pages sent"),o("Slack","#","PR \xb7 deploy notices","Team notifications","Simulated","amber","Message state only; no real messages"),o("Linear","L","Issues \xb7 intake","Issue tracker","Simulated","amber","Synthetic issues; nothing filed")],runs:[{id:"ci",label:"Fix failing CI on main \xb7 PR #1842",entry:"resolveIssue()",testFile:"tests/resolve-issue.ts",startTitle:"Check failure observed",startEvent:"resolveIssue() \xb7 PR #1842 \xb7 3 failing jobs",settled:"One patch pushed; the checks turned green once.",stateKey:"gh.check_runs",faults:n({permTool:"GitHub",downTool:"Slack",perm:"checks:write",action:"Patch",noun:"patch",follow:"review request",stateLabel:"Check state",rateTool:"GitHub",after:"30s"})},{id:"migrate",label:"Migrate users table \xb7 12,340 rows",entry:"migrateSchema()",testFile:"tests/migrate-users.ts",startTitle:"Migration started",startEvent:"migrateSchema() \xb7 users \xb7 12,340 rows \xb7 2 steps",settled:"One migration recorded; every row migrated once.",stateKey:"db.migrations",faults:n({permTool:"Postgres",downTool:"Slack",perm:"ddl-write",action:"Migration",noun:"migration",follow:"status message",stateLabel:"Migration state",rateTool:"Postgres",after:"45s"})},{id:"rollback",label:"Roll back bad deploy \xb7 svc-api release 4.18.2",entry:"rollBackDeploy()",testFile:"tests/rollback-deploy.ts",startTitle:"Rollback requested",startEvent:"rollBackDeploy() \xb7 svc-api \xb7 release 4.18.2",settled:"One release rolled back; traffic restored once.",stateKey:"deploy.releases",faults:n({permTool:"AWS EC2",downTool:"PagerDuty",perm:"deploy:write",action:"Rollback",noun:"rollback",follow:"incident note",stateLabel:"Release state",rateTool:"Datadog",after:"20s"})}]},{id:"oncall",logo:"co-sentry.svg",company:"Sentry",tag:"On-call agent",badge:"ON-CALL",name:"sentry-oncall-twin",blurb:"An on-call agent watches the error stream: group the new issue, open the incident, page the right responder, and write the root cause summary once the error rate settles.",caution:"The tool stack and the workflows under test are modelled for this demo. Sentry is a prospect, not an AgentTwin customer. This does not represent their product architecture or a reported failure.",links:[{label:"Sentry platform",href:"https://sentry.io/platform/"},{label:"Sentry",href:"https://sentry.io/"}],services:[o("PagerDuty","Pd","Rotations \xb7 pages","On-call paging","Simulated","amber","No real pages sent"),o("Slack","#","Incident channel","Incident comms","Simulated","amber","Channel state only; no real messages"),o("GitHub","G","Fix PRs","Remediation code","Simulated","amber","Synthetic PRs; nothing pushed"),o("Linear","L","Follow-up issues","Follow-up tracking","Simulated","amber","Synthetic issues; nothing filed"),o("Datadog","D","Correlated metrics","Correlated telemetry","Simulated","amber","Synthetic metrics; no live telemetry"),o("AWS EC2","A","Hosted services","Service inventory","Sanitized copy","","No instances provisioned or changed"),o("Terraform","Tf","Service definitions","Service registry","Read only","gray","Read-only service definitions"),o("Okta","O","Identity context","User identity","Sanitized copy","","Synthetic users and groups"),o("Postgres","Pg","Event store","Event archive","Sanitized copy","","Synthetic events; no production rows")],runs:[{id:"triage",label:"Triage new issue \xb7 checkout-api",entry:"triageAlert()",testFile:"tests/triage-issue.ts",startTitle:"Issue seen",startEvent:"triageAlert() \xb7 checkout-api \xb7 1,204 events",settled:"One triage posted; the assignee notified once.",stateKey:"issues.groups",faults:n({permTool:"Linear",downTool:"Slack",perm:"issue-create",action:"Triage",noun:"triage",follow:"assignee notice",stateLabel:"Triage state",rateTool:"Slack",after:"20s"})},{id:"incident",label:"Page on-call \xb7 error spike 5x baseline",entry:"openIncident()",testFile:"tests/open-incident.ts",startTitle:"Spike detected",startEvent:"openIncident() \xb7 5x baseline \xb7 3 minute window",settled:"One incident opened; on-call paged once.",stateKey:"incidents.active",faults:n({permTool:"PagerDuty",downTool:"Slack",perm:"incident-write",action:"Incident",noun:"incident",follow:"on-call page",stateLabel:"Incident state",rateTool:"PagerDuty",after:"60s"})},{id:"rca",label:"Root cause summary \xb7 47 events after resolution",entry:"summarizeRootCause()",testFile:"tests/rca-summary.ts",startTitle:"Resolution observed",startEvent:"summarizeRootCause() \xb7 47 events \xb7 12 minutes",settled:"One RCA stored; stakeholders notified once.",stateKey:"rca.reports",faults:n({permTool:"Postgres",downTool:"Slack",perm:"rca-write",action:"RCA",noun:"RCA",follow:"stakeholder summary",stateLabel:"RCA state",rateTool:"Datadog",after:"30s"})}]},{id:"healthcare",logo:"co-abridge.png",company:"Abridge",tag:"Clinical documentation agent",badge:"HEALTHCARE",name:"abridge-clinical-twin",blurb:"A health system runs a documentation agent: draft the encounter note from the visit, apply coding flags for review, and reconcile the orders against the medication list before sign-off.",caution:"The tool stack and the workflows under test are modelled for this demo. Abridge is a prospect, not an AgentTwin customer. This does not represent their product architecture or a reported failure.",links:[{label:"Abridge",href:"https://abridge.com/"},{label:"For clinicians",href:"https://abridge.com/clinicians"}],services:[o("EHR","Eh","Encounters \xb7 orders","Source of truth","Sanitized copy","","Synthetic encounters; no production patient data"),o("Clinical notes","Cn","Drafts \xb7 sign-off","Note drafts","Seeded fixture","","Invented note content awaiting sign-off"),o("Coding rules","Cr","ICD-10 \xb7 CPT","Coding reference","Seeded fixture","","Invented coding hints, clinician review required"),o("Slack","#","Care-team review","Care-team handoff","Simulated","amber","Message state only; no real messages"),o("Gmail","M","Patient follow-up","Follow-up channel","Simulated","amber","Message state only; no real mail"),o("Postgres","Pg","Normalized store","Normalized records","Sanitized copy","","Synthetic records; no production rows"),o("Okta","O","Clinician roles","Access control","Sanitized copy","","Synthetic users and clinical roles"),o("Calendar","C","Scheduling","Visit schedule","Seeded fixture","","Synthetic appointments; no bookings")],runs:[{id:"note",label:"Draft encounter note \xb7 visit #8821",entry:"fileEncounterNote()",testFile:"tests/file-note.ts",startTitle:"Visit closed",startEvent:"fileEncounterNote() \xb7 visit #8821 \xb7 18 minute audio",settled:"One note drafted; clinician sign-off requested once.",stateKey:"ehr.notes",faults:n({permTool:"EHR",downTool:"Slack",perm:"note-write",action:"Note",noun:"note",follow:"clinician review request",stateLabel:"Note state",rateTool:"EHR",after:"45s"})},{id:"coding",label:"Apply coding flags \xb7 12 claims for review",entry:"flagCoding()",testFile:"tests/flag-coding.ts",startTitle:"Claims batch opened",startEvent:"flagCoding() \xb7 12 claims \xb7 ICD-10 and CPT",settled:"One flag set applied; each claim flagged once.",stateKey:"ehr.codes",faults:n({permTool:"Coding rules",downTool:"Slack",perm:"code-apply",action:"Flag",noun:"coding flag",follow:"review queue notice",stateLabel:"Flag state",rateTool:"EHR",after:"30s"})},{id:"reconcile",label:"Reconcile orders vs medications \xb7 9 orders",entry:"reconcileOrders()",testFile:"tests/reconcile-orders.ts",startTitle:"Reconciliation started",startEvent:"reconcileOrders() \xb7 9 orders \xb7 3 mismatches",settled:"One reconciliation recorded; each mismatch resolved once.",stateKey:"ehr.orders",faults:n({permTool:"EHR",downTool:"Gmail",perm:"order-write",action:"Reconciliation",noun:"reconciliation",follow:"pharmacy message",stateLabel:"Order state",rateTool:"Postgres",after:"60s"})}]},{id:"security",logo:"co-paloalto.png",company:"Palo Alto Networks",tag:"Security triage agent",badge:"SECURITY",name:"paloalto-triage-twin",blurb:"A security operations team runs a triage agent: open the case from the SIEM alert, correlate the surrounding events, isolate the affected host, and hand the responder a complete picture.",caution:"The tool stack and the workflows under test are modelled for this demo. Palo Alto Networks is a prospect, not an AgentTwin customer. This does not represent their product architecture or a reported failure.",links:[{label:"Cortex",href:"https://www.paloaltonetworks.com/cortex"},{label:"Cortex XDR",href:"https://www.paloaltonetworks.com/cortex/cortex-xdr"}],services:[o("SIEM","Si","Alerts \xb7 detections","Alert intake","Simulated","amber","Synthetic alerts; no production events"),o("EDR","Ed","Endpoints \xb7 isolation","Endpoint control","Simulated","amber","No hosts touched or isolated"),o("PagerDuty","Pd","Responder paging","Responder paging","Simulated","amber","No real pages sent"),o("Slack","#","Triage channel","Analyst comms","Simulated","amber","Channel state only; no real messages"),o("GitHub","G","Detection rules","Detection content","Read only","gray","Read-only rule definitions"),o("AWS EC2","A","Workload inventory","Workload inventory","Sanitized copy","","No instances provisioned or changed"),o("Terraform","Tf","Fleet definitions","Fleet definitions","Read only","gray","Read-only fleet definitions"),o("Okta","O","Identity context","Identity context","Sanitized copy","","Synthetic users and sessions"),o("Datadog","D","Telemetry","Correlated telemetry","Simulated","amber","Synthetic metrics; no live telemetry")],runs:[{id:"alert",label:"Triage endpoint alert \xb7 host web-14",entry:"triageAlert()",testFile:"tests/triage-alert.ts",startTitle:"Alert raised",startEvent:"triageAlert() \xb7 host web-14 \xb7 severity high",settled:"One case opened; the responder notified once.",stateKey:"siem.cases",faults:n({permTool:"EDR",downTool:"Slack",perm:"case-write",action:"Case",noun:"case",follow:"responder notice",stateLabel:"Case state",rateTool:"Datadog",after:"30s"})},{id:"correlate",label:"Correlate 5 events \xb7 suspicious egress",entry:"correlateEvents()",testFile:"tests/correlate-events.ts",startTitle:"Events ingested",startEvent:"correlateEvents() \xb7 5 events \xb7 40 minute window",settled:"One correlation stored; each event linked once.",stateKey:"siem.correlations",faults:n({permTool:"SIEM",downTool:"Slack",perm:"correlation-write",action:"Correlation",noun:"correlation",follow:"analyst digest",stateLabel:"Correlation state",rateTool:"SIEM",after:"45s"})},{id:"isolate",label:"Isolate compromised host \xb7 laptop-207",entry:"isolateHost()",testFile:"tests/isolate-host.ts",startTitle:"Isolation requested",startEvent:"isolateHost() \xb7 laptop-207 \xb7 EDR policy",settled:"One host isolated; the ticket closed once.",stateKey:"edr.isolations",faults:n({permTool:"EDR",downTool:"PagerDuty",perm:"isolation",action:"Isolation",noun:"isolation",follow:"ticket update",stateLabel:"Isolation state",rateTool:"PagerDuty",after:"60s"})}]}],i={step:0,connected:!1,replica:!1,busy:!1,customer:"support",mask:!0,isolated:!0,faults:[],recovery:!1,runs:[],tab:"timeline",notice:"",name:r[0].name,runId:r[0].runs[0].id},c=()=>r.find(e=>e.id===i.customer),l=()=>{let e=c();return e.runs.find(e=>e.id===i.runId)||e.runs[0]},d=e=>String(e).replace(/[&<>"']/g,e=>({"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;"})[e]),u=function(e){let t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"";return'<span class="badge '.concat(t,'">').concat(e,"</span>")},p={GitHub:"github.svg",Gmail:"gmail.svg",Slack:"slack.svg",Shopify:"shopify.svg",Intercom:"intercom.svg",Stripe:"stripe.svg",Postgres:"postgres.svg",Salesforce:"salesforce.svg",Calendar:"google-calendar.svg","npm registry":"npm.svg","AWS EC2":"aws.svg",Terraform:"terraform.svg",PagerDuty:"pagerduty.svg",HubSpot:"hubspot.svg",Linear:"linear.svg",Klaviyo:"klaviyo.png",Clay:"clay.png",NetSuite:"netsuite.png",Datadog:"datadog.svg",Okta:"okta.svg",Notion:"notion.svg",Snowflake:"snowflake.svg",Mixpanel:"mixpanel.svg","Clinical notes":"notes.svg","Coding rules":"codes.svg","Return policy":"policy.svg","Bank rail":"bank.svg","CI runner":"ci.svg",EHR:"ehr.svg",SIEM:"siem.svg",EDR:"edr.svg"},m=e=>p[e.brand]?'<img src="/prototype/dist/icons/'.concat(p[e.brand],'" alt="" aria-hidden="true">'):d(e.icon),v=(e,t)=>e.logo?'<span class="'.concat(t,'"><img src="/prototype/dist/icons/').concat(e.logo,'" alt="').concat(d(e.company),'" title="').concat(d(e.company),'"></span>'):'<span class="'.concat(t,'">').concat(d(e.company[0].toLowerCase()),"</span>"),h=function(e,t){let a=arguments.length>2&&void 0!==arguments[2]?arguments[2]:"primary",s=arguments.length>3&&void 0!==arguments[3]&&arguments[3];return'<button class="btn '.concat(a,'" data-action="').concat(t,'" ').concat(s?"disabled":"",">").concat(e,"</button>")},g=function(e,t){let a=arguments.length>2&&void 0!==arguments[2]?arguments[2]:"";return'<section class="panel"><div class="panel-head"><h2>'.concat(e,"</h2><span>").concat(a,"</span></div>").concat(t,"</section>")};function f(e){return 0===e||1===e&&i.connected||e>=2&&i.replica}function y(e){t("#announcer").textContent=e}function b(e){var t;null==(t=document.querySelector(".toast"))||t.remove();let a=document.createElement("div");a.className="toast",a.textContent=e,document.body.append(a),y(e),setTimeout(()=>a.remove(),3300)}function w(e){var a;!i.busy&&f(e)&&(i.step=e,K(),null==(a=t("#step-title"))||a.focus({preventScroll:!0}))}function S(){let e=c();return'<div class="map"><div class="map-label">'.concat(i.replica?"REPLICA TOPOLOGY":"DISCOVERED TOPOLOGY",' / ILLUSTRATIVE DATA</div><div class="rootnode">').concat(v(e,"service-icon"),'<div class="node-title">').concat(d(e.company),'<div class="node-sub">').concat(i.replica?d(i.name):"production \xb7 illustrative manifest","</div></div>").concat(u(i.replica?"Isolated":"Read only",i.replica?"":"gray"),'</div><div class="services">').concat(e.services.map(e=>'<div class="service"><div class="service-icon">'.concat(m(e),'</div><div class="node-title">').concat(e.brand,'</div><div class="node-sub">').concat(e.sub,"</div>").concat(u(e.mode,e.kind),"</div>")).join(""),'</div></div><div class="map-footer"><span class="key"><i class="sq"></i> Seeded fixture</span><span class="key"><i class="sq amber"></i> Behavioral twin</span><span class="key"><i class="sq gray"></i> Untested</span></div>')}function k(){return g("Replica boundaries",'<div class="panel-body"><div class="detail-row"><span>Production writes</span><strong>Blocked</strong></div><div class="detail-row"><span>Customer data</span><strong>Masked</strong></div><div class="detail-row"><span>Credentials</span><strong>Test only</strong></div><div class="detail-row"><span>Outbound email</span><strong>Captured</strong></div><div class="callout">This prototype uses synthetic fixtures. No cloud accounts, databases, or external services are connected.</div></div>')}function T(e){let t=e.id===i.customer;return'<label class="select-card '.concat(t?"selected":"",'"><input type="radio" name="customer" value="').concat(e.id,'" ').concat(t?"checked":"",' aria-label="').concat(d(e.tag),'">').concat(v(e,"large-icon"),'<div class="content"><div class="card-top"><strong>').concat(d(e.company),"</strong>").concat(u(e.badge,"gray"),"</div><p>").concat(d(e.tag)," \xb7 ").concat(e.services.length," tools \xb7 ").concat(e.runs.length,' runs in flight</p><ul class="card-runs">').concat(e.runs.map(e=>"<li>".concat(d(e.label),"</li>")).join(""),"</ul></div></label>")}function C(){let e=c();return'<div class="grid"><div class="stacked">'.concat(g("Example customers",'<div class="panel-body"><div class="connection-header"><div class="large-icon">⌘</div><div><h2>Start with a customer.</h2><p>'.concat(r.length," real companies, each modelled with the tool stack it actually runs and ").concat(r[0].runs.length,' workflows already in twin runs. Pick one to see what AgentTwin would catch.</p></div></div><div class="customer-list">').concat(r.map(T).join(""),'</div><div class="selected-detail"><p class="aside-note">').concat(d(e.blurb),"</p>").concat(e.links.length?'<p class="aside-note" style="margin-top:10px">'.concat(e.links.map(e=>'<a href="'.concat(e.href,'" target="_blank" rel="noopener noreferrer">').concat(e.label,"</a>")).join(" \xb7 "),"</p>"):"",'<div class="callout amber">').concat(d(e.caution),'</div></div><div class="callout">An AgentTwin connector would use scoped, read-only discovery. This prototype loads an illustrative manifest — no credentials, no live systems.</div>').concat(h(i.busy?"Discovering resources…":i.connected?"Review discovered environment":"Run production discovery","discover","primary full",i.busy)).concat(i.busy?'<div class="progress"><div></div></div>':"","</div>"))," ").concat(i.connected?g("Environment discovered",S(),"".concat(e.services.length," DEPENDENCIES")):"",'</div><aside class="stacked">').concat(g("Connection checklist",'<div class="panel-body"><div class="eyebrow">01 / DISCOVERY</div><h3 class="side-title" style="margin-top:15px">Know what you depend on.</h3><p class="aside-note">Build a map before making a replica.</p>'.concat(["Application & entrypoints","Infrastructure & region","Database schema & state","External services","Configuration & permissions"].map(e=>'<div class="detail-row"><span>'.concat(e,'</span><strong class="text-green">').concat(i.connected?"✓":"—","</strong></div>")).join(""),'<div class="callout amber">A replica is only as useful as its coverage. Unverified behavior stays visible.</div></div>'))).concat(k(),"</aside></div>")}function R(){let e=c();return'<div class="grid"><div class="stacked">'.concat(g("Your environment, safely replicated",S(),"".concat(e.services.length," RESOURCES"))).concat(g("What goes into your replica",'<div class="table-scroll"><table class="resource-table"><thead><tr><th>Resource</th><th>Replica behavior</th><th>Coverage boundary</th></tr></thead><tbody>'.concat(c().services.map(e=>'<tr><td><div class="resource-name"><div class="service-icon">'.concat(m(e),"</div><div>").concat(e.brand,'<div class="secondary">').concat(e.name,"</div></div></div></td><td>").concat(u(e.mode,e.kind),'</td><td class="subtle">').concat(e.boundary,"</td></tr>")).join(""),"</tbody></table></div>")),'</div><aside class="stacked">').concat(g("Configure replica",'<div class="panel-body"><label class="label" for="replica-name" style="margin-top:0">Replica name</label><input class="field" id="replica-name" maxlength="40" value="'.concat(d(i.name),'" ').concat(i.replica?"disabled":"",'><label class="toggle-row"><input type="checkbox" checked disabled><div>Sanitize personal data<p>Replace names, emails, and identifiers.</p></div></label><label class="toggle-row"><input type="checkbox" checked disabled><div>Isolate credentials<p>Use test identities. Block production writes.</p></div></label><div class="detail-row"><span>Baseline</span><strong>snapshot_001</strong></div><div class="detail-row"><span>External behavior</span>').concat(u("Simulated","amber"),"</div>").concat(h(i.busy?"Creating replica…":i.replica?"Continue to run code":"Create test replica",i.replica?"run-page":"create","primary full",i.busy)).concat(i.busy?'<div class="progress"><div></div></div>':"",'<p class="safe-note">Prototype \xb7 no infrastructure provisioned</p></div>'))).concat(k(),"</aside></div>")}function E(){let e=c(),t=l();return'<div class="metric-grid"><div class="metric"><strong>'.concat(e.services.length,'</strong><span>Tools in the stack</span></div><div class="metric"><strong>').concat(e.runs.length,'</strong><span>Twin runs in flight</span></div><div class="metric"><strong>').concat(i.runs.length,'</strong><span>Completed test runs</span></div></div><div class="grid"><div class="stacked">').concat(g("Run against your replica",'<div class="panel-body">'.concat(function(){let e=c();return'<span class="label" style="margin-top:0">Twin runs in flight</span><div class="run-list" role="radiogroup" aria-label="Twin runs in flight">'.concat(e.runs.map(e=>{let t=e.id===i.runId,a=i.runs.filter(t=>t.runId===e.id).at(-1),s=a?u(a.pass?"PASS":"FAIL",a.pass?"":"red"):u("In flight","gray");return'<label class="run-card '.concat(t?"selected":"",'"><input type="radio" name="twinrun" value="').concat(e.id,'" ').concat(t?"checked":"",' aria-label="').concat(d(e.label),'"><span class="run-mark" aria-hidden="true">').concat(t?"●":"○",'</span><span class="run-body"><strong>').concat(d(e.label),"</strong><small>").concat(d(e.entry)," \xb7 ").concat(d(e.testFile),"</small></span>").concat(s,"</label>")}).join(""),"</div>")}(),'<div class="code"><span class="comment"># Illustrative integration command</span>\nagenttwin run ').concat(t.testFile," \\\n --world ").concat(d(i.name),' \\\n --snapshot snapshot_001</div><p class="aside-note">This demo runs a scripted workflow against in-memory state. Executing your repository code requires a connected runtime.</p><label class="toggle-row"><input id="recovery" type="checkbox" ').concat(i.recovery?"checked":"",'><div>Preview recovery fixture<p>Show a separate scripted example with safe retries, deduplication, and explicit failure handling.</p></div></label><div class="row-buttons">').concat(h(i.busy?"Running simulation…":"Run simulated workflow","run","primary",i.busy)).concat(h("Configure failures","fault-page","",i.busy),"</div>").concat(i.busy?'<div class="progress"><div></div></div>':"","</div>"))).concat(g("Recent runs",'<div class="panel-body">'.concat(i.runs.length?i.runs.slice().reverse().slice(0,4).map(e=>'<div class="history"><span style="font-family:var(--mono)">run_'.concat(String(e.id).padStart(3,"0"),'</span><span class="subtle">').concat(d(e.runLabel||"")," \xb7 ").concat(e.faults.length?e.faults.length+" conditions":"baseline"," \xb7 ").concat(e.recovery?"recovery preview":"original fixture","</span>").concat(u(e.pass?"PASS":"FAIL",e.pass?"":"red"),"</div>")).join(""):'<p class="aside-note">No runs yet. Start with a baseline, then introduce a failure.</p>',"</div>")),' </div><aside class="stacked">').concat(g("Execution context",'<div class="panel-body"><div class="detail-row"><span>Environment</span><strong>'.concat(d(i.name),'</strong></div><div class="detail-row"><span>Starting state</span><strong>snapshot_001</strong></div><div class="detail-row"><span>Entrypoint</span><strong>').concat(d(t.entry),'</strong></div><div class="detail-row"><span>Network</span><strong>Simulated</strong></div><div class="callout">Each demo run starts from the same baseline. Faults are applied only inside the replica.</div></div>'))).concat(k(),"</aside></div>")}function A(){let e=c(),t=l();return'<div class="grid"><div class="stacked">'.concat(g("Choose what breaks",'<div class="panel-body"><p class="aside-note" style="margin-bottom:6px">Twin run under test \xb7 <strong>'.concat(d(t.label),'</strong></p><p class="aside-note" style="margin-bottom:20px">Combine conditions to test how the workflow recovers.</p><div class="fault-grid">').concat(t.faults.map(e=>'<label class="fault"><div class="fault-head">'.concat(e.name,'<input type="checkbox" name="fault" value="').concat(e.id,'" ').concat(i.faults.includes(e.id)?"checked":"","></div><p>").concat(e.desc,"</p><code>").concat(e.code,"</code></label>")).join(""),'</div><div class="row-buttons">').concat(h(i.busy?"Running simulation…":"Run with selected failures","run","primary",i.busy||!i.faults.length)).concat(h("Clear selection","clear","",i.busy||!i.faults.length),"</div>").concat(i.busy?'<div class="progress"><div></div></div>':"","</div>")),'</div><aside class="stacked">').concat(g("Experiment setup",'<div class="panel-body"><div class="eyebrow">CONTROLLED CONDITIONS</div><h3 class="side-title" style="margin-top:16px">Break the replica.</h3><p class="aside-note">Keep production out of the experiment.</p><div class="detail-row"><span>Conditions selected</span><strong>'.concat(i.faults.length,'</strong></div><div class="detail-row"><span>Target</span><strong>').concat(d(e.company),'</strong></div><div class="detail-row"><span>Twin run</span><strong>').concat(d(t.entry),'</strong></div><label class="toggle-row"><input id="recovery" type="checkbox" ').concat(i.recovery?"checked":"",'><div>Preview recovery fixture<p>Switch to a separate scripted example of recovery behavior.</p></div></label><div class="callout amber">Passing means the expected recovery was observed in this scenario. It does not certify production safety.</div></div>'))).concat(k(),"</aside></div>")}let x=e=>c().runs.find(t=>t.id===e.runId)||l(),I=(e,t)=>x(e).faults.find(e=>e.id===t),P={perm:"Handle the 403 as a visible permission failure. Stop dependent writes and tell the operator which scope or connection needs renewal.",down:"Keep the completed write, persist the unfinished follow-up, and retry that follow-up when the service is available.",late:"Compare event versions or timestamps before applying a delayed event. Ignore an event older than the current state.",timeout:"Create one stable idempotency key for the logical operation, reuse it on every retry, and verify the final provider state.",dup:"Deduplicate by a stable request or event ID with an atomic guard before changing state.",rate:"Respect Retry-After, use bounded backoff, and persist enough context to resume without dropping the operation."};function O(e){var t,a;return e.faults.length?e.pass?Math.max(...e.faults.map(t=>{var a,s;return null!=(s=null==(a=I(e,t))?void 0:a.passCount)?s:1})):null!=(a=null==(t=I(e,e.faults[0]))?void 0:t.failCount)?a:0:1}function D(e){let t=c(),a=x(e),s="run_".concat(String(e.id).padStart(3,"0"));return["AgentTwin simulated run: ".concat(s," \xb7 ").concat(e.pass?"PASS":"FAIL"),"Example company: ".concat(t.company),"Workflow: ".concat(a.entry," \xb7 ").concat(a.label),"Faults: ".concat(e.faults.length?e.faults.map(t=>"".concat(I(e,t).name," (").concat(I(e,t).code,")")).join("; "):"none (baseline)"),"State: ".concat(a.stateKey," 0 → ").concat(O(e)),"Failed assertions: ".concat(e.pass?0:e.faults.length),"Production writes: 0","Illustrative source: ".concat(a.testFile)].join("\n")}function N(e){let t=x(e),a=e.faults.map(t=>{let a=I(e,t);return["- ".concat(a.name,": ").concat(a.failure.t,". ").concat(a.failure.d)," Suggested change: ".concat(P[t])," Passing behavior: ".concat(a.recovery.t,". ").concat(a.recovery.d)].join("\n")});return["Help me fix a failing integration workflow in my own repository.","This AgentTwin result is a synthetic demonstration. Inspect the real code and verify every assumption before changing it.","","Workflow: ".concat(t.entry," (").concat(t.label,")"),"Illustrative test path: ".concat(t.testFile," (this may not exist in my repository)"),"Run: run_".concat(String(e.id).padStart(3,"0")),"","Observed failure and suggested direction:",...a,"","Expected final state: one correct ".concat(t.stateKey," change, no duplicate or lost side effects, and zero failed assertions."),"Observed final state: ".concat(t.stateKey," changed from 0 to ").concat(O(e),"; ").concat(e.faults.length," assertion(s) failed."),"","Please locate the matching workflow, identify the actual root cause, make the smallest safe code change, add a regression test for this fault, and report what changed. Then rerun the same scenario and compare the final state and assertions. Do not treat the demo recovery fixture as a patch."].join("\n")}function L(){let e=i.runs.at(-1);if(!e)return g("No result yet",'<div class="empty"><h2>Run a workflow first.</h2><p>AgentTwin will show the outcome, the cause, and your next action here.</p><div class="row-buttons" style="justify-content:center">'.concat(h("Choose a workflow","run-page"),"</div></div>"));let t=x(e),a=!e.pass,s=e.pass?e.faults.length?"handled_error":"completed":"inconsistent",n=e.faults.length?e.faults.map(t=>I(e,t).recovery.t).join("; "):t.settled,o=a?e.faults.map(t=>I(e,t).failure.t).join("; "):"Expected state and assertions matched in this simulated run.",r='<section class="panel"><div class="result-banner '.concat(a?"failed":"",'"><div class="result-icon">').concat(a?"!":"✓","</div><div><h2>").concat(a?"Failed: the final state is wrong":"Passed in the simulated replica","</h2><p>run_").concat(String(e.id).padStart(3,"0")," \xb7 ").concat(e.recovery?"Recovery fixture":"Original fixture"," \xb7 ").concat(e.faults.length?"".concat(e.faults.length," fault").concat(1===e.faults.length?"":"s"):"Baseline",'</p></div></div><div class="decision-summary"><div><span>Expected</span><strong>').concat(d(n),"</strong></div><div><span>Observed</span><strong>").concat(d(o),'</strong></div></div><div class="tabs" role="tablist">').concat(["timeline","state diff","assertions"].map(e=>'<button class="tab '.concat(i.tab===e?"active":"",'" role="tab" aria-selected="').concat(i.tab===e,'" data-tab="').concat(e,'">').concat(e[0].toUpperCase()+e.slice(1),"</button>")).join(""),"</div>").concat("timeline"===i.tab?'<div class="timeline">'.concat(e.events.map(e=>'<div class="event '.concat(e.error?"error":"",'"><time>').concat(e.time,'</time><i class="line-dot"></i><div><strong>').concat(e.title,"</strong><p>").concat(e.desc,"</p></div>").concat(u(e.status,"INJECTED"===e.status?"amber":e.error?"red":""),"</div>")).join(""),"</div>"):"state diff"===i.tab?'<div class="panel-body"><div class="code"><span class="comment"># snapshot_001 → run_'.concat(String(e.id).padStart(3,"0"),"</span>\nworkflow.status: idle → ").concat(s,"\n").concat(t.stateKey,": 0 → ").concat(O(e),"\nproduction.writes: 0 → 0\nassertions.failed: 0 → ").concat(a?e.faults.length:0,'</div><p class="aside-note">Illustrative changes from the scripted demo, not a production trace.</p></div>'):'<div class="panel-body">'.concat(e.faults.length?e.faults.map(t=>{let a=I(e,t);return'<div class="detail-row"><span>'.concat(d(e.pass?a.recovery.t:a.failure.t),"</span>").concat(u(e.pass?"PASS":"FAIL",e.pass?"":"red"),"</div>")}).join(""):'<div class="detail-row"><span>Expected state created exactly once</span>'.concat(u("PASS"),"</div>"),'<div class="detail-row"><span>No production writes</span>').concat(u("PASS"),'</div><div class="detail-row"><span>No external messages delivered</span>').concat(u("PASS"),"</div></div>"),"</section>"),c=a?g("What broke and how to fix it",'<div class="panel-body"><p class="aside-note">These causes come from the demo fixture. Confirm them against your actual code and logs.</p>'.concat(e.faults.map(t=>{let a=I(e,t);return'<div class="diagnosis-item"><span class="eyebrow">'.concat(d(a.name)," \xb7 ").concat(d(a.code),"</span><h3>").concat(d(a.failure.t),"</h3><p>").concat(d(a.failure.d),"</p><p><strong>Change to try:</strong> ").concat(d(P[t]),"</p></div>")}).join(""),"</div>")):"",l=a?g("Next: fix your code, then rerun",'<div class="panel-body"><div class="action-steps"><div><b>1</b><span>Copy this fix prompt into your coding agent or use it to edit the workflow yourself.</span></div><div><b>2</b><span>Make the code change and add a regression test in your repository.</span></div><div><b>3</b><span>Rerun the same fault and check that the final state and assertions pass.</span></div></div><div class="code fix-prompt">'.concat(d(N(e)),'</div><div class="row-buttons">').concat(h("Copy fix prompt","copy-fix","primary")).concat(h("Preview recovery fixture","preview-recovery",""),'</div><p class="safe-note">This prototype cannot read or patch your repository. The recovery preview is a separate scripted fixture.</p></div>')):g("What to do next",'<div class="panel-body"><p class="aside-note">The expected state matched in this simulated run. Keep the scenario as a regression target, then test your real code when a connected runner exists.</p><div class="code fix-prompt">'.concat(d(D(e)),'</div><div class="row-buttons">').concat(h("Copy result report","copy-evidence","primary")).concat(h("Try another failure","fault-page",""),"</div></div>")),p=g("Repeat the same conditions",'<div class="panel-body"><div class="detail-row"><span>Starting state</span><strong>snapshot_001</strong></div><div class="detail-row"><span>Injected faults</span><strong>'.concat(e.faults.length,'</strong></div><div class="detail-row"><span>Result</span>').concat(u(e.pass?"PASS":"FAIL",e.pass?"":"red"),'</div><p class="aside-note" style="margin-top:15px">Rerun uses the same scripted implementation and faults. Reset clears the faults and returns to workflow setup.</p>').concat(h("Rerun current fixture","rerun","primary full",i.busy)).concat(h("Reset to baseline","reset","full"),'<p class="safe-note">All results are simulated.</p></div>'));return'<div class="grid"><div class="stacked">'.concat(r).concat(c).concat(l,'</div><aside class="stacked">').concat(p).concat(k(),"</aside></div>")}let F=["Connect production.","Your production. A safe replica.","Real workflows. Safe consequences.","Find the failures before they find you.","See what broke. Know what to do."],M=["Choose an example customer, then map its production stack before creating an isolated test environment.","Review what is copied, what is simulated, and what stays untouched.","Pick one of the workflows this team already has in flight, then run it against a repeatable baseline.","Put the same workflow through conditions a happy-path test misses.","Read the failed assertion, copy a fix prompt, change your code, and rerun the same scenario. This prototype only previews the recovery behavior."];function K(){let e=c();t("#app").innerHTML='<div class="announce"><span class="dot"></span> Interactive prototype \xb7 all data synthetic \xb7 no live systems connected</div><header class="topnav"><div class="brand"><img class="brandmark" src="assets/logo/mark-twin-rings.svg?v=white-rings" alt="" width="28" height="28">AgentTwin<small>α</small></div><nav class="navlinks" aria-label="Prototype navigation"><span class="navlink active">Customers</span><span class="navlink">Workflows</span><span class="navlink">Receipts</span><span class="navlink">Docs</span></nav><div class="nav-right"><span class="demo-pill">DEMO MODE</span><span class="avatar">SS</span></div></header><section class="hero"><div class="hero-inner"><div class="eyebrow">ENVIRONMENT / '.concat(i.replica?"REPLICA":"SETUP",'</div><h1 tabindex="-1" id="step-title">').concat(F[i.step],'</h1><p class="lead">').concat(M[i.step],'</p></div><div class="hero-side">').concat(i.connected?u(i.replica?"Replica isolated":"Discovery complete"):u("No live connections","gray"),'</div></section><div class="appwindow"><nav class="sidebar" aria-label="Main navigation"><div class="workspace"><span class="avatar">AT</span><div>Customer workspace<div class="secondary">Pick a company to model</div></div></div><div class="nav-label">Build confidence</div>').concat(a.map((e,t)=>'<button class="navbtn '.concat(i.step===t?"active":"",'" data-step="').concat(t,'" ').concat(!f(t)||i.busy?"disabled":"",'><span class="navnum">0').concat(t+1,"</span>").concat(e,"</button>")).join(""),'<div class="sidebar-bottom"><span class="demo-pill"><i class="dot"></i> INTERACTIVE PROTOTYPE</span><p style="margin-top:12px">A safe place to break things.</p><p class="subtle" style="font-size:11px;margin-top:8px">Illustrative data \xb7 no live connections</p></div></nav><main class="main"><header class="topbar"><span class="mobile-brand">AgentTwin</span><div class="crumb"><span class="subtle">Workspace</span><span class="subtle">/</span><span>').concat(d(e.company),'</span><span class="subtle">/</span><span>').concat(a[i.step],'</span></div><div class="topright"><span class="demo-pill">DEMO MODE</span><span class="avatar">SS</span></div></header><div class="main-inner"><div class="steps" aria-label="Setup progress">').concat(a.map((e,t)=>'<button class="step '.concat(i.step===t?"current":i.step>t?"done":"",'" data-step="').concat(t,'" ').concat(!f(t)||i.busy?"disabled":"","><b>").concat(i.step>t?"✓":t+1,"</b>").concat(s[t],"</button>")).join(""),"</div>").concat(i.notice?'<div class="notice" role="status"><strong>'.concat(d(i.notice),"</strong></div>"):"").concat([C,R,E,A,L][i.step](),'<footer class="bottom-note"><span>AGENTTWIN / PRODUCTION REPLICA WORKSPACE</span><span>No real systems are touched.</span></footer></div></main></div></div>')}async function H(e){return new Promise(t=>setTimeout(t,e))}async function j(e){if(!i.busy)if(i.notice="","discover"===e){if(i.connected)return w(1);i.busy=!0,K(),await H(1e3),i.connected=!0,i.busy=!1,i.step=1,K(),y("Discovered ".concat(c().services.length," dependencies. Review your replica."))}else if("create"===e){var a,s;let e=null==(a=t("#replica-name"))?void 0:a.value.trim();if(!e||!/^[a-z0-9][a-z0-9-]{0,39}$/.test(e)){b("Use 1–40 lowercase letters, numbers, or hyphens."),null==(s=t("#replica-name"))||s.focus();return}i.name=e,i.busy=!0,K(),await H(1200),i.replica=!0,i.busy=!1,i.step=2,K(),y("Test replica created. Ready to run a simulated workflow.")}else if("run-page"===e)w(2);else if("fault-page"===e)w(3);else if(["run","rerun","preview-recovery"].includes(e)){if(!i.replica)return;if("rerun"===e||"preview-recovery"===e){let t=i.runs.at(-1);if(!t)return;i.faults=[...t.faults],i.recovery="preview-recovery"===e||t.recovery}i.busy=!0,K(),await H(1100),i.runs.push(function(){let e=l(),t=[...i.faults],a=i.recovery,s=!t.length||a,n=[{time:"0.00s",title:"Baseline restored",desc:"snapshot_001 \xb7 synthetic records and test identities",status:"READY"},{time:"0.08s",title:e.startTitle,desc:e.startEvent,status:"START"}];return t.forEach((t,s)=>{let o=e.faults.find(e=>e.id===t);n.push({time:(.2+.3*s).toFixed(2)+"s",title:o.name,desc:o.desc,status:"INJECTED",error:!0}),n.push({time:(.35+.3*s).toFixed(2)+"s",title:a?o.recovery.t:o.failure.t,desc:a?o.recovery.d:o.failure.d,status:a?"HANDLED":"FAILED",error:!a})}),t.length||n.push({time:"0.46s",title:"State updated once",desc:e.settled,status:"PASS"}),n.push({time:(.7+.3*t.length).toFixed(2)+"s",title:"Final state assertions evaluated",desc:s?"No duplicate actions. Outcome recorded. No production writes.":"Unexpected state detected. Review the failed assertions.",status:s?"PASS":"FAIL",error:!s}),{id:i.runs.length+1,runId:e.id,runLabel:e.label,pass:s,faults:t,recovery:a,events:n}}()),i.busy=!1,i.step=4,i.tab="timeline",K(),y(i.runs.at(-1).pass?"Run passed. Expected outcome verified.":"Run failed. Read what broke, copy the fix prompt, and rerun.")}else if("clear"===e)i.faults=[],K();else if("copy-evidence"===e||"copy-fix"===e){let t=i.runs.at(-1);if(!t)return;let a="copy-fix"===e?N(t):D(t);try{await navigator.clipboard.writeText(a)}catch(t){let e=document.createElement("textarea");e.value=a,e.style.position="fixed",e.style.opacity="0",document.body.appendChild(e),e.select();try{document.execCommand("copy")}catch(e){}e.remove()}b("copy-fix"===e?"Fix prompt copied. Use it with your code, then rerun.":"Result report copied."),y("copy-fix"===e?"Fix prompt copied to the clipboard.":"Result report copied to the clipboard.")}else"reset"===e&&(i.faults=[],i.recovery=!1,i.step=2,i.notice="Replica restored to snapshot_001. Failure conditions cleared. Run history retained.",K(),y(i.notice))}if(document.addEventListener("click",e=>{let t=e.target.closest("button");t&&!t.disabled&&(t.dataset.action&&j(t.dataset.action),void 0!==t.dataset.step&&w(Number(t.dataset.step)),t.dataset.tab&&(i.tab=t.dataset.tab,K()))}),document.addEventListener("change",e=>{if(!i.busy){if("customer"===e.target.name&&(i.customer=e.target.value,i.name=c().name,i.runId=c().runs[0].id,i.connected=!1,i.replica=!1,i.runs=[],i.faults=[],i.recovery=!1,i.step=0,i.notice="",K(),y("Customer switched to ".concat(c().company,". ").concat(c().runs.length," twin runs available."))),"twinrun"===e.target.name){if(e.target.value===i.runId)return;i.runId=e.target.value,i.faults=[],i.recovery=!1,K(),y("Twin run selected: ".concat(l().label,"."))}"fault"===e.target.name&&(i.faults=e.target.checked?[...i.faults,e.target.value]:i.faults.filter(t=>t!==e.target.value),K()),"recovery"===e.target.id&&(i.recovery=e.target.checked,K())}}),K(),null==(e=document.modelContext)?void 0:e.registerTool)for(let e of[{name:"read_replica_demo",description:"Read current simulated replica and latest result. No production systems are connected.",inputSchema:{type:"object",properties:{},additionalProperties:!1},annotations:{readOnlyHint:!0},execute:()=>({connected:i.connected,replica:i.replica,customer:c().company,step:a[i.step],faults:[...i.faults],lastRun:i.runs.at(-1)||null})},{name:"configure_demo_failures",description:"Select failure conditions in the simulated replica. Does not run a test.",inputSchema:{type:"object",properties:{faults:{type:"array",items:{type:"string",enum:[...new Set(r.flatMap(e=>e.runs.flatMap(e=>e.faults.map(e=>e.id))))]}}},required:["faults"],additionalProperties:!1},annotations:{readOnlyHint:!1},execute:e=>{if(!i.replica||i.busy)throw Error("Create an idle replica first");if(!e||!Array.isArray(e.faults)||e.faults.some(e=>!l().faults.some(t=>t.id===e)))throw Error("Invalid failure selection");return i.faults=[...new Set(e.faults)],i.step=3,K(),{faults:i.faults}}}])try{Promise.resolve(document.modelContext.registerTool(e)).catch(()=>{})}catch(e){}}()}),()=>{e=!0}},[]),(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)("a",{href:"/dashboard/",className:"dashboard-link",children:"View actual test results in the AgentTwin dashboard ↗"}),(0,s.jsx)("div",{id:"app"}),(0,s.jsx)("div",{id:"announcer",className:"sr-only",role:"status","aria-live":"polite"})]})}},2465:(e,t,a)=>{Promise.resolve().then(a.bind(a,964)),Promise.resolve().then(a.t.bind(a,7537,23))},7537:()=>{}},e=>{e.O(0,[9742,7903,4816,7358],()=>e(e.s=2465)),_N_E=e.O()}]);