# ====================================================================
# WebPilot Master Configuration (YAML Format)
# ====================================================================

# 1. Framework General Options
framework:
  name: "WebPilot AI-Native QE Framework"
  version: "1.0.0"
  activeProvider: "azure"
  defaultEnvironment: "qa"
  interactive: true
  useBrowserUse: true
  codegenMode: openhands
  openhands:
    enabled: true
    model: null
    # Scoped folder OpenHands may edit (discovery evidence stays in WebPilot runtime).
    # Defaults to framework.generatedCodePath when unset. Override with WEBPILOT_OPENHANDS_WORKSPACE.
    workspace: "./packages/test-framework"
    maxIterations: 40
  codegenQuality:
    # Set false to reject deterministic specs containing raw page.* fallbacks
    # for interactions/assertions. Waits and screenshots remain audit-visible
    # but do not count against the primary POM mapping quality ratio.
    allowRawPageFallback: true
    # 0 disables ratio enforcement; values are clamped to the range 0..1.
    minPomMappedStepRatio: 0.6
  healingCachePath: "./runtime/healing-cache/cache.json"
  # ActHistory locator self-heal on failure (default on). Override: --no-heal or WEBPILOT_REPLAY_HEAL=0
  replayHeal: true
  generatedCodePath: "./packages/test-framework"
  validationLoopEnabled: true
  validationRetries: 3
  reportsPath: "./runtime/reports"
  artifactsPath: "./runtime/artifacts"
  htmlReport: true # generate reports/index.html after each WebPilot agent run
  htmlReportAiAnalysis: true # LLM quality analysis section (editable in prompts/reports/)
  apiCodegenEnabled: true # generate packages/test-framework/apis + packages/test-framework/tests/api after successful API runs
  useApiPlaywright: true # execute API tests via Playwright request (not axios)

# Codegen stack (set by `webpilot init --language …`). Without this block, language defaults to typescript.
# Python Playwright → tests/generated/test_*.py. TypeScript Playwright → packages/test-framework/tests/*.spec.ts.
project:
  name: "webpilot"
  target: "web"
  language: "typescript"
  automationTool: "playwright"
  testFramework: "playwright-test"
  frameworkPattern: "pom"

# 1b. Azure DevOps Test Plans (bundled official MCP)
# Enable this when WebPilot is installed in a consumer repo. WebPilot spawns the
# pinned @azure-devops/mcp package — no Cursor mcp.json required.
# Auth: set AZURE_DEVOPS_EXT_PAT / ADO_MCP_AUTH_TOKEN (pat) or use auth: azcli.
ado:
  enabled: false
  organization: ""          # e.g. contoso
  project: ""
  auth: pat                 # pat | azcli
  # tenant: ""              # optional Entra tenant for azcli
  domains: [core, work-items, test-plans]
  timeoutMs: 90000
  testPlans:
    defaultPlanName: "WebPilot Automation"
    autoPublishResults: false
  # Optional spawn override (defaults to bundled @azure-devops/mcp):
  # command: "node"
  # args: []

# 1c. Dataverse MCP (bundled official @microsoft/dataverse)
# Data / schema plane for Dynamics / Dataverse — complements dynamics365 UI rulebooks.
# No Cursor mcp.json: WebPilot spawns the pinned package over stdio.
# Auth: Dataverse CLI profiles — run once:
#   npx @microsoft/dataverse auth create --environment https://contoso.crm.dynamics.com
# Admin prereqs: enable MCP in PPAC + allow Dataverse CLI client
#   (app id 0c412cc3-0dd6-449b-987f-05b053db9457). See docs/guides/dataverse-mcp.md
dataverse:
  enabled: false
  environmentUrl: ""        # e.g. https://contoso.crm.dynamics.com
  preview: false            # true → /api/mcp_preview
  timeoutMs: 120000
  # Optional spawn override (defaults to bundled @microsoft/dataverse):
  # command: "node"
  # args: []

# 1d. API / OpenAPI suite generation
api:
  openapi:
    importMode: full          # full | smoke
    generateNegatives: false
    splitBy: none             # none | tag
    schemaSidecars: true
  auth:
    bearerEnv: AUTH_TOKEN
    apiKeyEnv: API_KEY

# 1e. Requirements coverage sync (Feature 09)
# WebPilot can sync stories/requirements directly from official ADO/Jira MCP
# servers, normalize them, then generate coverage without requiring users to
# hand-author requirements JSON. When ado.enabled is true and ado.command is
# unset, requirements sync reuses the bundled ADO MCP launcher.
requirements:
  mcp:
    timeoutMs: 90000
    ado:
      enabled: false
      # Leave command empty to reuse bundled MCP when top-level ado: is configured.
      command: ""
      args: []
      env:
        AZURE_DEVOPS_ORG_URL: "${AZURE_DEVOPS_ORG_URL}"
      # Optional overrides when the MCP server uses non-standard tool/arg names.
      # toolName: "query_work_items"
      # queryArgument: "wiql"
      # resultPath: "value"
    jira:
      enabled: false
      # Configure the official Jira/Atlassian MCP server command for your site.
      # Example shape only; use the command/args from Atlassian's MCP docs.
      command: ""
      args: []
      env:
        JIRA_SITE_URL: "${JIRA_SITE_URL}"
      # Optional overrides when the MCP server uses non-standard tool/arg names.
      # toolName: "search_issues"
      # queryArgument: "jql"
      # resultPath: "issues"

# 2. Intelligent runner and learned site knowledge
intelligentRunner:
  enabled: true
  knowledgePath: "./runtime/site-knowledge/knowledge.json"
  # global: share learned steps per page (default). test: isolate per scenario file.
  knowledgeScope: global
  # partitioned: pages/*.json (global) or scenarios/*.json (test). legacy: single knowledge.json
  knowledgeStorage: partitioned
  # native = one WebPilot agent for the full scenario (default — preserves engine intelligence).
  # scoped = one agent per NL step (legacy wrapper; use for knowledge repair / WEBPILOT_KNOWLEDGE_ONLY).
  engineMode: native
  # Origin-gated site rulebooks (resources/rulebooks/*) injected into discovery hints.
  # autoLearn distills high-trust locators into runtime/rulebooks/<pack>/learned.md
  rulebooks:
    enabled: true
    autoLearn: true
    minSuccessCount: 2
  scopedAgentMaxSteps: 12
  nativeAgentMaxSteps: 80
  # Fresh agent per discovery step avoids LLM context drift on 15+ step scenarios (scoped mode only).
  freshAgentPerStep: true
  maxHistoryItems: 30
  longScenarioStepWarning: 15
  # auto: tune agent for single-file 15+ step flows (fresh agent, retries, higher step budget)
  longScenarioMode: auto
  stepRetryOnFailure: 0
  # Performance tuning: speeds up execution without lowering execution/codegen quality.
  # The independent LLM judge is the most expensive add-on (one extra LLM call per
  # step). It does NOT override the agent's own success/failure self-report, so it is
  # only needed as a false-positive guard on assertion steps.
  performance:
    # discoveryFastMode (default false): full browser-use agent (judge/thinking/planning).
    # Opt into lean mode: discoveryFastMode: true + WEBPILOT_FULL_AGENT_MODE=0
    # or WEBPILOT_DISCOVERY_FAST_MODE=1 (requires WEBPILOT_FULL_AGENT_MODE=0).
    discoveryFastMode: false
    judgeMode: "verification" # verification | always | off — run the judge only on verify/assert steps
    maxActionsPerStep: 6      # let the agent batch more actions per LLM round-trip
    useVision: "auto"         # auto | always | off
    useThinking: true         # browser-use default; forced off when discoveryFastMode is true
    flashMode: false          # browser-use default; forced on when discoveryFastMode is true
    # Browser wait tuning in seconds. Page-load / network-idle waits keep WebPilot agent
    # defaults (null) so the agent never acts on a not-yet-settled DOM (reliability).
    # Only the pure dead-time between actions is trimmed (0.5 -> 0.3).
    minPageLoadWait: null
    networkIdleWait: null
    waitBetweenActions: 0.3

# 3. Browser Execution Options
browser:
  target: "chrome" # chrome (Google Chrome), chromium, msedge — WebPilot agent channel
  headless: false
  video: "on" # off | on | retain-on-failure — prefer discovery-session video (ffmpeg); else codegen harvest; else one-shot ActHistory evidence replay
  # BA discovery records video when ffmpeg is available so a second Playwright session is not required.
  # Generated specs use playwright.config.ts for their own video.
  # Agent console: progress one-liners (goal + actions) always print.
  # Full browser-use dumps: WEBPILOT_VERBOSE=1 or `webpilot run --verbose`.
  # Or set BROWSER_USE_LOGGING_LEVEL=info|debug directly.
  screenshots: "only-on-failure" # off, on, only-on-failure — report media for failed steps only
  trace: "on" # off, on, retain-on-failure — saves Playwright trace zips under reports/traces
  viewport:
    width: 1280
    height: 720
  # TestMu AI remote browser (WebPilot agent connects via CDP WebSocket)
  testmu:
    enabled: false
    username: "${TESTMU_USERNAME}"
    accessKey: "${TESTMU_ACCESS_KEY}"
    adapter: "puppeteer" # puppeteer (WebPilot agent / raw CDP) | playwright
    browserName: "Chrome" # Chrome | MicrosoftEdge | pw-chromium | pw-firefox | pw-webkit
    browserVersion: "latest"
    platform: "Windows 10"
    build: "WebPilot"
    name: "WebPilot Test" # overridden per run with the test file slug
    network: true
    video: true
    console: true
    tunnel: false
    tunnelName: ""
    geoLocation: ""
  emulateMobile: false
  permissions:
    - "geolocation"
    - "notifications"
  networkThrottling: "none"
  downloadsPath: "./runtime/artifacts/downloads"

# 3b. Browser Provider Matrix
browserProviders:
  active: "browser-use" # local-playwright | browser-use (WebPilot agent) | testmu | remote-cdp | selenium-grid | browserstack | lambdatest
  local-playwright:
    browserName: "chromium"
    headless: false
  browser-use:
    browserName: "chrome"
    headless: false
  remote-cdp:
    endpoint: "${REMOTE_CDP_URL}"
  selenium-grid:
    endpoint: "${SELENIUM_GRID_URL}"
  testmu:
    enabled: false
    username: "${TESTMU_USERNAME}"
    accessKey: "${TESTMU_ACCESS_KEY}"
    adapter: "puppeteer"
    browserName: "Chrome"
    browserVersion: "latest"
    platform: "Windows 10"

# 3c. Feature flags — trust / evidence / lifecycle roadmap
# Roll out in order: eventLedger → fixtureLifecycle → semanticAssertions
# → healingClassification (shadow then enforce) → groundedRootCause.
features:
  eventLedger: true
  fixtureLifecycle: false
  semanticAssertions: false
  healingClassification: shadow   # off | shadow | enforce
  groundedRootCause: false

healing:
  # legacy: cache write on propose when classification !== enforce
  # postvalidated: only commit after action + classification allows
  commitPolicy: postvalidated

evidence:
  enabled: true
  writeBundle: true
  captureNetwork: errors     # off | errors | metadata
  captureConsole: errors     # off | errors | all
  failOnInvalidCitation: true
  risk:
    failWeight: 40
    healingPerStep: 10
    healingCap: 25
    codegenDegraded: 20
    unverifiedLocatorMax: 20
    weakAssertionOnly: 15
    missingFailureArtifacts: 10
    pageDrift: 10
  completeness:
    requireVerifiedLocatorRatio: 0.8
    requireTraceOnFailure: true
    requireAssertionOnPass: true
  pageInventoryHistory:
    enabled: true
    maxSnapshotsPerPage: 20

# 4. Test Runner & Execution Options
execution:
  parallelWorkers: 4
  timeout: 60000
  retries: 1
  sharding:
    enabled: false
    totalShards: 1
    shardIndex: 0
  selfHealing:
    enabled: true
    similarityThreshold: 0.7
    autoUpdateCache: true
  reporters:
    - "html"
    - "json"
    - "junit"
  accessibilityTesting:
    enabled: true
    standards:
      - "WCAG2AA"
  visualTesting:
    enabled: false
    diffTolerance: 0.05
