version: 1
kind: HwlabNodeLaneConfig
metadata:
  name: hwlab-node-lanes
defaults:
  node: NC01
  lane: v03
requiredNoProxy:
  - hyueapi.com
  - .hyueapi.com
nodes:
  NC01:
    route: NC01
    kubeRoute: NC01:k3s
    sourceWorkspace: /root/hwlab-v03
    gitopsRoot: deploy/gitops/node
    networkProfile: jd01-node-ci-egress
    downloadProfile: jd01-node-default
lanes:
  v03:
    node: NC01
    activeTarget: NC01
    minor: 3
    version: v0.3
    sourceBranch: v0.3
    sourceAuthority:
      mode: gitMirrorSnapshot
      resolver: k8s-git-mirror
      allowHostGit: false
      allowHostWorkspace: false
      allowGithubDirectInPipeline: false
    sourceSnapshot:
      stageRefPrefix: "refs/unidesk/snapshots/hwlab-node-runtime/{branch}"
      missingObjectPolicy: fail-fast
      refreshPolicy: sync-before-snapshot
    workspace: /root/hwlab-v03
    cicdRepo: /root/hwlab-v03-cicd.git
    cicdRepoLock: /tmp/hwlab-v03-cicd-repo.lock
    app: hwlab-node-v03
    pipeline: hwlab-v03-ci-image-publish
    pipelineRunPrefix: hwlab-v03-ci-poll
    serviceAccountName: hwlab-v03-tekton-runner
    controlPlaneFieldManager: unidesk-hwlab-v03-control-plane
    git:
      url: git@github.com:pikasTech/HWLAB.git
      readUrl: http://git-mirror-http.devops-infra.svc.cluster.local/pikasTech/HWLAB.git
      writeUrl: http://git-mirror-write.devops-infra.svc.cluster.local/pikasTech/HWLAB.git
    gitopsBranch: v0.3-gitops
    catalogPath: deploy/artifact-catalog.v03.json
    runtime:
      path: deploy/gitops/node/runtime-v03
      namespace: hwlab-v03
      renderDir: runtime-v03
    tektonDir: tekton-v03
    argoApplicationFile: application-v03.yaml
    registryPrefix: 127.0.0.1:5000/hwlab
    baseImage: 127.0.0.1:5000/hwlab/hwlab-node20-base:20-bookworm-slim
    baseImageSource: node:20-bookworm-slim
    serviceIds:
      - hwlab-cloud-api
      - hwlab-workbench-runtime
      - hwlab-user-billing
      - hwlab-project-management
      - hwlab-tasktree-api
      - hwlab-tasktree-worker
      - hwlab-harnessrl-api
      - hwlab-harnessrl-worker
      - hwlab-workbench-api
      - hwlab-workbench-worker
      - hwlab-hwpod-api
      - hwlab-hwpod-worker
      - hwlab-hwpod-web
      - hwlab-cloud-web
      - hwlab-gateway
      - hwlab-edge-proxy
      - hwlab-agent-skills
    observability:
      prometheusOperator: true
    public:
      webUrl: http://74.48.78.17:20666
      apiUrl: http://74.48.78.17:20667
    bootstrapAdmin:
      username: admin
      displayName: HWLAB v0.3 Admin
      passwordSourceRef: /root/.unidesk/.env/unified-admin-password.txt
      passwordSourceKey: contents
      passwordSourceLine: 1
      passwordHashTransform: hwlab-sha256
      secretName: hwlab-v03-bootstrap-admin
      secretKey: password-hash
      rollout:
        deployment: hwlab-cloud-api
    targets:
      NC01:
        environment: development
        node: NC01
        workspace: /root/hwlab-v03
        sourceWorkspace:
          git:
            remoteName: origin
            remoteUrl: git@github.com:pikasTech/HWLAB.git
            identityTarget: NC01
            identityId: github.com
            proxyEnvPath: /etc/unidesk/proxy.env
            verifyRemote: false
            requireUpToDate: false
          requiredCommands:
            - git
            - node
            - npm
          requiredFiles:
            - AGENTS.md
            - package.json
            - package-lock.json
          install:
            executor: host
            dependencyCommand: npm ci
            browserCommand: npx playwright install chromium
            stateDir: /tmp/hwlab-v03-source-workspace-bootstrap
            timeoutSeconds: 1800
        nativeDevelopment:
          tasktree:
            publicExposure:
              publicBaseUrl: https://lab-dev-tasktree.hwpod.com
              hostname: lab-dev-tasktree.hwpod.com
              expectedA: 152.53.229.148
              upstream: http://127.0.0.1:4173
              healthPath: /health/live
            stateDir: .state/tasktree-native
            api:
              bindHost: 127.0.0.1
              probeHost: 127.0.0.1
              port: 6673
            worker:
              bindHost: 127.0.0.1
              probeHost: 127.0.0.1
              healthPort: 6674
            web:
              bindHost: 0.0.0.0
              probeHost: 127.0.0.1
              port: 4173
          workbench:
            publicExposure:
              publicBaseUrl: https://lab-dev-workbench.hwpod.com
              hostname: lab-dev-workbench.hwpod.com
              expectedA: 152.53.229.148
              upstream: http://127.0.0.1:5174
              healthPath: /health/live
            stateDir: .state/workbench-native/services
            stateFile: .state/workbench-native/state.json
            mode: agentrun-native
            temporal:
              address: 10.43.145.243:7233
              namespace: unidesk
              taskQueue: hwlab-v03-workbench-native-l1
              activity:
                startToCloseTimeoutMs: 900000
                retryInitialIntervalMs: 1000
                retryMaximumIntervalMs: 10000
                retryMaximumAttempts: 1
            agentRun:
              managerUrl: http://127.0.0.1:6680
              runtimeApiUrl: http://hwlab-cloud-api.hwlab-v03.svc.cluster.local:6667
              runtimeWebUrl: http://hwlab-cloud-web.hwlab-v03.svc.cluster.local:8080
            kafka:
              configRef: codeAgentRuntime.kafkaEventBridge
              bootstrapServers: 10.43.4.158:9092
              dnsServers:
                - 10.43.0.10
              dnsSearchDomains:
                - cluster.local
              clientId: hwlab-v03-workbench-native-l1
              hwlabEventConsumerGroupId: hwlab-v03-workbench-native-l1-live-sse
              refreshReplay:
                groupIdPrefix: hwlab-v03-workbench-native-l1-refresh
                timeoutMs: 30000
                scanLimit: 1000000
                matchedEventLimit: 2000
                liveBufferLimit: 2000
                sessionIndex:
                  enabled: true
                  maxEvents: 100000
                  maxEventsPerSession: 10000
                  bootstrapTimeoutMs: 30000
                  rebuildIntervalMs: 300000
                  rebuildCooldownMs: 30000
            api:
              bindHost: 0.0.0.0
              probeHost: 127.0.0.1
              port: 6677
              idleTimeoutSeconds: 60
            worker:
              bindHost: 127.0.0.1
              probeHost: 127.0.0.1
              healthPort: 6678
            web:
              bindHost: 0.0.0.0
              probeHost: 127.0.0.1
              port: 5174
              runtimeConfig: &hwlabV03NativeCloudWebRuntimeConfig
                displayTime:
                  timeZone: Asia/Shanghai
                  locale: zh-CN
                  label: 北京时间
                workbench:
                  realtimeFeatures:
                    liveKafkaSse: true
                    kafkaRefreshReplay: true
                    projectionRealtime: false
                  debugCapabilities:
                    isolatedKafka: false
                    rawHwlabEventWindow:
                      enabled: false
                      maxEntries: 1
                      maxRetainedBytes: 1
                  traceTimeline:
                    autoExpandRunning: false
                    autoCollapseTerminal: false
          hwpod:
            healthTimeoutMs: 6000
            nodeAuth:
              sourceRef: hwlab/nc01-v03-hwpod-node.env
              sourceKey: HWLAB_HWPOD_NODE_WS_TOKEN
            specRegistry:
              database:
                sourceRef: hwlab/nc01-v03-cloud-api-db.env
                sourceKey: DATABASE_URL
                schema: hwpod
                table: runtime_specs
                connectionTimeoutMs: 5000
              builtInConfigRefs:
                - config/hwlab-hwpod-preinstalls/constart-71freq-c.yaml#hwpodPreinstall.specDocument
            publicExposure:
              publicBaseUrl: https://lab-dev-hwpod.hwpod.com
              hostname: lab-dev-hwpod.hwpod.com
              expectedA: 152.53.229.148
              upstream: http://127.0.0.1:5175
              healthPath: /health/live
            stateDir: .state/hwpod-native/services
            temporal:
              address: 10.43.145.243:7233
              namespace: unidesk
              taskQueue: hwlab-v03-hwpod-native-l1
              activity:
                startToCloseTimeoutMs: 900000
                retryInitialIntervalMs: 1000
                retryMaximumIntervalMs: 10000
                retryMaximumAttempts: 1
            api:
              bindHost: 0.0.0.0
              probeHost: 127.0.0.1
              port: 6681
            worker:
              bindHost: 127.0.0.1
              probeHost: 127.0.0.1
              healthPort: 6682
            web:
              bindHost: 0.0.0.0
              probeHost: 127.0.0.1
              port: 5175
              runtimeConfig: *hwlabV03NativeCloudWebRuntimeConfig
              accessProfile:
                id: hwpod-native-l1
                allowedNavIds:
                  - admin.hwpodGroups
                startPath: /hwpods/devices
          caserun:
            publicExposure:
              publicBaseUrl: https://lab-dev-caserun.hwpod.com
              hostname: lab-dev-caserun.hwpod.com
              expectedA: 152.53.229.148
              upstream: http://127.0.0.1:5173
              healthPath: /health/live
            stateDir: .state/caserun-native/services
            api:
              bindHost: 0.0.0.0
              probeHost: 127.0.0.1
              port: 4316
            web:
              bindHost: 0.0.0.0
              probeHost: 127.0.0.1
              port: 5173
        hwpodPreinstall:
          enabled: true
          configRefs:
            preinstall: config/hwlab-hwpod-preinstalls/constart-71freq-c.yaml#hwpodPreinstall
            projectManagementSource: config/hwlab-project-management/constart-71freq-mdtodo.yaml#projectManagement.sources[0]
            gatewayProfile: config/hwlab-gateway/constart-71freq.yaml#gateway.profile
        sourceAuthority:
          extends: templates.hwlabV03.sourceAuthorityGiteaSnapshot
          giteaMirrorRepoKey: hwlab-nc01-v03
        sourceSnapshot:
          extends: templates.hwlabV03.sourceSnapshotGiteaControlled
        cicdRepo: /root/hwlab-v03-cicd.git
        cicdRepoLock: /tmp/hwlab-v03-cicd-repo.lock
        app: hwlab-node-v03
        pipeline: hwlab-nc01-v03-ci-image-publish
        pipelineRunPrefix: hwlab-nc01-v03-ci-poll
        serviceAccountName: hwlab-nc01-v03-tekton-runner
        controlPlaneFieldManager: unidesk-hwlab-nc01-v03-control-plane
        pipelineProvenance:
          configRef: config/hwlab-node-lanes.yaml#lanes.v03.targets.NC01
          renderer: hwlab-runtime-lane
          mode: remote-pipeline-annotation
          maxInlineScriptBytes: 32768
        git:
          url: git@github.com:pikasTech/HWLAB.git
          readUrl: http://gitea-http.devops-infra.svc.cluster.local:3000/mirrors/pikasTech-HWLAB.git
          writeUrl: http://git-mirror-write.devops-infra.svc.cluster.local:8080/pikasTech/HWLAB.git
        argo:
          repoURL: http://git-mirror-http.devops-infra.svc.cluster.local:8080/pikasTech/HWLAB.git
        gitopsBranch: v0.3-gitops
        catalogPath: deploy/artifact-catalog.nc01-v03.json
        runtime:
          path: deploy/gitops/node/nc01/runtime-v03
          namespace: hwlab-v03
          renderDir: runtime-v03
        runtimeStore:
          postgres:
            mode: platform-service
            serviceName: nc01-host-postgres
            poolMax: 16
        buildkit:
          sidecarImage: 127.0.0.1:5000/hwlab/buildkit:rootless
          sourceImage: docker.io/moby/buildkit:rootless
        ciResourceGovernance:
          build:
            matrixTaskName: build-services
            maxParallelServices: 2
            taskTimeout: 20m
            priorityClassName: unidesk-ci-batch
            stepResources:
              requests:
                cpu: 100m
                memory: 128Mi
              limits:
                cpu: 750m
                memory: 768Mi
            sidecarResources:
              requests:
                cpu: 250m
                memory: 256Mi
              limits:
                cpu: 1500m
                memory: 1536Mi
          dedupe:
            identityFields:
              - repository
              - lane
              - sourceCommit
              - pipelineIntent
          coreProtection:
            configRefs:
              - config/hwlab-node-control-plane.yaml#targets.NC01.k3s
              - config/platform-infra/sub2api.yaml#targets.NC01.resourceProtection
              - config/platform-infra/public-edge.yaml#targets.NC01.runtime.resourceProtection
        stepEnv:
          HOME: /tekton/home
          XDG_CONFIG_HOME: /tekton/home/.config
        runtimeImageRewrites:
          - extends: templates.hwlabV03.runtimeImageRewrites.frpc
          - extends: templates.hwlabV03.runtimeImageRewrites.openfga
          - extends: templates.hwlabV03.runtimeImageRewrites.opencode
        runtimeImageBuilds:
          - extends: templates.hwlabV03.runtimeImageBuilds.moonbridge
          - extends: templates.hwlabV03.runtimeImageBuilds.opencodeGit
        webProbe:
          extends: templates.hwlabV03.webProbeWorkbench
          playwrightBrowsersPath: "0"
        public:
          webUrl: https://lab-dev.hwpod.com
          apiUrl: https://lab-dev.hwpod.com
        observability:
          prometheusOperator: false
          webProbe:
            monitor:
              configRef: config/hwlab-web-probe-monitor/runtime.yaml#monitor
            monitorRoot:
              enabled: true
              sentinelId: nc01-web-probe-sentinel
              publicBaseUrl: https://monitor.pikapython.com
              routePrefix: /
              caddyManagedBlockOwner: hwlab-web-probe-sentinel-active-root
            sentinels:
              - id: nc01-web-probe-sentinel
                enabled: true
                configRef: "config/hwlab-web-probe-sentinel/profiles.yaml#nodes.${NODE}.sentinels.${nodeLower}-web-probe-sentinel.sentinel"
        bootstrapAdmin:
          username: admin
          displayName: HWLAB v0.3 Admin
          usernameSourceRef: /root/.unidesk/.env/hwlab.auth
          usernameSourceLine: 1
          passwordSourceRef: /root/.unidesk/.env/unified-admin-password.txt
          passwordSourceKey: contents
          passwordSourceLine: 1
          passwordHashTransform: hwlab-sha256
          secretName: hwlab-v03-bootstrap-admin
          secretKey: password-hash
          rollout:
            deployment: hwlab-cloud-api
        codeAgentProvider:
          secretName: hwlab-v03-code-agent-provider
          sourceRef: hwlab/nc01-v03-code-agent-provider.env
          openaiSourceKey: OPENAI_API_KEY
          opencodeSourceKey: OPENCODE_API_KEY
        codeAgentRuntime:
          enabled: true
          adapter: agentrun-v02
          controlPlaneTarget:
            node: NC01
            lane: nc01-v02
          managerUrl: http://agentrun-mgr.agentrun-v02.svc.cluster.local:8080
          apiKeySourceRef: hwlab/nc01-v03-admin.env
          apiKeySourceKey: HWLAB_API_KEY
          apiKeySecretName: hwlab-v03-master-server-admin-api-key
          apiKeySecretKey: api-key
          runnerNamespace: agentrun-v02
          secretNamespace: agentrun-v02
          providerSecretNames:
            codex: agentrun-v01-provider-codex
            gpt-pika: agentrun-v02-provider-gpt-pika
            grok: agentrun-v02-provider-grok
            dsflash-go: agentrun-v01-provider-dsflash-go
          toolSecretNames:
            githubPr: agentrun-v01-tool-github-pr
            unideskSsh: agentrun-v01-tool-unidesk-ssh
          repoUrlFrom: runtimeGitReadUrl
          providerIdFrom: runtimeNodeId
          defaultProviderProfile: gpt.pika
          codexStdioSupervisor: repo-owned
          kafkaEventBridge:
            enabled: true
            features:
              directPublish: true
              liveKafkaSse: true
              kafkaRefreshReplay: true
              transactionalProjector: false
              projectionOutboxRelay: false
              projectionRealtime: false
            refreshReplay:
              groupIdPrefix: hwlab-v03-cloud-api-sse
              timeoutMs: 30000
              scanLimit: 1000000
              matchedEventLimit: 2000
              liveBufferLimit: 2000
            configRef: config/platform-infra/kafka.yaml#clients.hwlab-v03-cloud-api
            bootstrapServers: platform-infra-kafka-kafka-bootstrap.platform-infra.svc.cluster.local:9092
            stdioTopic: codex-stdio.raw.v1
            agentRunEventTopic: agentrun.event.v1
            hwlabEventTopic: hwlab.event.v1
            clientId: hwlab-v03-cloud-api
            directPublishConsumerGroupId: hwlab-agentrun-event-direct-publish
            transactionalProjectorConsumerGroupId: hwlab-v03-agentrun-event-projector
            hwlabEventConsumerGroupId: hwlab-v03-workbench-live-sse
        externalPostgres:
          extends: templates.hwlabV03.externalPostgresConsumer
          provider: NC01
          configRef: config/platform-db/postgres-nc01.yaml
          serviceName: nc01-host-postgres
          endpointAddress: 10.42.0.1
          runtimeAccess:
            routeName: nc01-host-postgres
            endpointAddress: 10.42.0.1
            port: 5432
          database: hwlab_nc01_v03
          cloudApi:
            sourceRef: hwlab/nc01-v03-cloud-api-db.env
            role: hwlab_nc01_v03_app
          openfga:
            sourceRef: hwlab/nc01-v03-openfga-db.env
            role: hwlab_nc01_v03_app
        variables:
          LANE: v03
          NODE: NC01
  production:
    extends: lanes.v03
    variables:
      LANE: production
      NODE: NC01
    environment: production
    version: v0.3
    sourceBranch: release
    workspace: /root/hwlab-release
    webProbe:
      extends: templates.hwlabV03.webProbeWorkbench
      playwrightBrowsersPath: "0"
      overrides:
        origins:
          internal:
            mode: k8s-service-cluster-ip
            serviceName: hwlab-cloud-web
            namespace: hwlab-production
            port: 8080
            scheme: http
            browserProxyMode: direct
    cicdRepo: /root/hwlab-release-cicd.git
    cicdRepoLock: /tmp/hwlab-release-cicd-repo.lock
    app: hwlab-node-production
    pipeline: hwlab-production-ci-image-publish
    pipelineRunPrefix: hwlab-production-ci-poll
    serviceAccountName: hwlab-production-tekton-runner
    controlPlaneFieldManager: unidesk-hwlab-production-control-plane
    gitopsBranch: release-gitops
    catalogPath: deploy/artifact-catalog.production.json
    runtime:
      path: deploy/gitops/node/runtime-production
      namespace: hwlab-production
      renderDir: runtime-production
    tektonDir: tekton-production
    argoApplicationFile: application-production.yaml
    public:
      webUrl: https://lab.hwpod.com
      apiUrl: https://lab.hwpod.com
    targets:
      NC01:
        environment: production
        workspace: /root/hwlab-release
        webProbe:
          extends: templates.hwlabV03.webProbeWorkbench
          playwrightBrowsersPath: "0"
          overrides:
            origins:
              internal:
                mode: k8s-service-cluster-ip
                serviceName: hwlab-cloud-web
                namespace: hwlab-production
                port: 8080
                scheme: http
                browserProxyMode: direct
        sourceWorkspace:
          install:
            stateDir: /tmp/hwlab-release-source-workspace-bootstrap
        sourceAuthority:
          giteaMirrorRepoKey: hwlab-nc01-v03
        cicdRepo: /root/hwlab-release-cicd.git
        cicdRepoLock: /tmp/hwlab-release-cicd-repo.lock
        app: hwlab-node-production
        pipeline: hwlab-nc01-production-ci-image-publish
        pipelineRunPrefix: hwlab-nc01-production-ci-poll
        serviceAccountName: hwlab-nc01-production-tekton-runner
        controlPlaneFieldManager: unidesk-hwlab-nc01-production-control-plane
        pipelineProvenance:
          configRef: config/hwlab-node-lanes.yaml#lanes.production.targets.NC01
        gitopsBranch: release-gitops
        catalogPath: deploy/artifact-catalog.nc01-production.json
        runtime:
          path: deploy/gitops/node/nc01/runtime-production
          namespace: hwlab-production
          renderDir: runtime-production
        public:
          webUrl: https://lab.hwpod.com
          apiUrl: https://lab.hwpod.com
        bootstrapAdmin:
          displayName: HWLAB Production Admin
          passwordSourceRef: /root/.unidesk/.env/unified-admin-password.txt
          passwordSourceKey: contents
          passwordSourceLine: 1
          secretName: hwlab-production-bootstrap-admin
        codeAgentProvider:
          secretName: hwlab-production-code-agent-provider
          sourceRef: hwlab/nc01-v03-code-agent-provider.env
        codeAgentRuntime:
          controlPlaneTarget:
            node: NC01
            lane: nc01-release
          managerUrl: http://agentrun-mgr.agentrun-release.svc.cluster.local:8080
          apiKeySecretName: hwlab-production-master-server-admin-api-key
          runnerNamespace: agentrun-release
          secretNamespace: agentrun-release
          providerSecretNames:
            codex: agentrun-release-provider-codex
            gpt-pika: agentrun-release-provider-gpt-pika
            grok: agentrun-release-provider-grok
            dsflash-go: agentrun-release-provider-dsflash-go
          toolSecretNames:
            githubPr: agentrun-release-tool-github-pr
            unideskSsh: agentrun-release-tool-unidesk-ssh
          kafkaEventBridge:
            refreshReplay:
              groupIdPrefix: hwlab-production-cloud-api-sse
            configRef: config/platform-infra/kafka.yaml#clients.hwlab-production-cloud-api
            clientId: hwlab-production-cloud-api
            directPublishConsumerGroupId: hwlab-agentrun-event-direct-publish
            transactionalProjectorConsumerGroupId: hwlab-production-agentrun-event-projector
            hwlabEventConsumerGroupId: hwlab-production-workbench-live-sse
        externalPostgres:
          database: hwlab_nc01_production
          migrationLedger:
            identity: hwlab-nc01-production
            table: hwlab_schema_migrations
          cloudApi:
            secretName: hwlab-cloud-api-production-db
            sourceRef: hwlab/nc01-production-cloud-api-db.env
            role: hwlab_nc01_production_app
            migrationSecretKey: migration-database-url
            migrationEnvKey: MIGRATION_DATABASE_URL
          openfga:
            secretName: hwlab-production-openfga
            sourceRef: hwlab/nc01-production-openfga-db.env
            role: hwlab_nc01_production_app
        variables:
          LANE: production
          NODE: NC01
networkProfiles:
  node-ci-egress:
    proxy:
      http: http://g14-provider-egress-proxy.unidesk.svc.cluster.local:18789
      https: http://g14-provider-egress-proxy.unidesk.svc.cluster.local:18789
      all: http://g14-provider-egress-proxy.unidesk.svc.cluster.local:18789
      noProxy:
        - localhost
        - 127.0.0.1
        - "::1"
        - host.docker.internal
        - .svc
        - .cluster.local
        - ci-git-mirror
        - ci-git-mirror.unidesk-ci
        - ci-git-mirror.unidesk-ci.svc
        - ci-git-mirror.unidesk-ci.svc.cluster.local
        - g14-provider-egress-proxy
        - g14-provider-egress-proxy.unidesk
        - g14-provider-egress-proxy.unidesk.svc
        - g14-provider-egress-proxy.unidesk.svc.cluster.local
        - g14-tcp-egress-gateway
        - g14-tcp-egress-gateway.unidesk
        - g14-tcp-egress-gateway.unidesk.svc
        - g14-tcp-egress-gateway.unidesk.svc.cluster.local
        - code-queue-ci-read
        - code-queue-ci-read.unidesk-ci
        - code-queue-ci-read.unidesk-ci.svc
        - code-queue-ci-read.unidesk-ci.svc.cluster.local
        - backend-core
        - oa-event-flow
        - database
    dockerBuildProxy:
      http: http://127.0.0.1:18789
      https: http://127.0.0.1:18789
      all: http://127.0.0.1:18789
      noProxy:
        - localhost
        - 127.0.0.1
        - "::1"
        - host.docker.internal
        - registry.npmmirror.com
        - cdn.npmmirror.com
  node-local-vpn:
    proxy:
      http: http://127.0.0.1:10808
      https: http://127.0.0.1:10808
      all: socks5h://127.0.0.1:10808
      socks5: socks5h://127.0.0.1:10808
      noProxy:
        - localhost
        - 127.0.0.1
        - "::1"
        - .svc
        - .cluster.local
        - 10.0.0.0/8
        - 172.16.0.0/12
        - 192.168.0.0/16
    dockerBuildProxy:
      http: http://127.0.0.1:10808
      https: http://127.0.0.1:10808
      all: socks5h://127.0.0.1:10808
      noProxy:
        - localhost
        - 127.0.0.1
        - "::1"
        - host.docker.internal
        - 127.0.0.1:5000
  d601-node-ci-egress:
    proxy:
      http: http://sub2api-egress-proxy.platform-infra.svc.cluster.local:10808
      https: http://sub2api-egress-proxy.platform-infra.svc.cluster.local:10808
      all: http://sub2api-egress-proxy.platform-infra.svc.cluster.local:10808
      noProxy:
        - localhost
        - 127.0.0.1
        - "::1"
        - 127.0.0.1:5000
        - localhost:5000
        - .svc
        - .svc.cluster.local
        - .cluster.local
        - kubernetes
        - kubernetes.default
        - kubernetes.default.svc
        - 10.0.0.0/8
        - 10.42.0.0/16
        - 10.43.0.0/16
        - 172.16.0.0/12
        - 192.168.0.0/16
        - 82.156.23.220
        - 74.48.78.17
        - hyueapi.com
        - .hyueapi.com
    dockerBuildProxy:
      http: http://127.0.0.1:10808
      https: http://127.0.0.1:10808
      all: http://127.0.0.1:10808
      noProxy:
        - localhost
        - 127.0.0.1
        - "::1"
        - 127.0.0.1:5000
        - localhost:5000
        - .svc
        - .svc.cluster.local
        - .cluster.local
  d518-node-ci-egress:
    proxy:
      http: http://sub2api-egress-proxy.platform-infra.svc.cluster.local:10808
      https: http://sub2api-egress-proxy.platform-infra.svc.cluster.local:10808
      all: http://sub2api-egress-proxy.platform-infra.svc.cluster.local:10808
      noProxy:
        - localhost
        - 127.0.0.1
        - "::1"
        - 127.0.0.1:5000
        - localhost:5000
        - .svc
        - .svc.cluster.local
        - .cluster.local
        - kubernetes
        - kubernetes.default
        - kubernetes.default.svc
        - 10.0.0.0/8
        - 10.42.0.0/16
        - 10.43.0.0/16
        - 172.16.0.0/12
        - 192.168.0.0/16
        - 82.156.23.220
        - 74.48.78.17
    dockerBuildProxy:
      http: http://127.0.0.1:10808
      https: http://127.0.0.1:10808
      all: http://127.0.0.1:10808
      noProxy:
        - localhost
        - 127.0.0.1
        - "::1"
        - 127.0.0.1:5000
        - localhost:5000
        - .svc
        - .svc.cluster.local
        - .cluster.local
  jd01-node-ci-egress:
    proxy:
      http: http://127.0.0.1:10808
      https: http://127.0.0.1:10808
      all: http://127.0.0.1:10808
      noProxy:
        - localhost
        - 127.0.0.1
        - "::1"
        - 127.0.0.1:5000
        - localhost:5000
        - .svc
        - .svc.cluster.local
        - .cluster.local
        - kubernetes
        - kubernetes.default
        - kubernetes.default.svc
        - 10.0.0.0/8
        - 10.42.0.0/16
        - 10.43.0.0/16
        - 172.16.0.0/12
        - 192.168.0.0/16
        - 82.156.23.220
        - 74.48.78.17
    dockerBuildProxy:
      http: http://127.0.0.1:10808
      https: http://127.0.0.1:10808
      all: http://127.0.0.1:10808
      noProxy:
        - localhost
        - 127.0.0.1
        - "::1"
        - 127.0.0.1:5000
        - localhost:5000
        - .svc
        - .svc.cluster.local
        - .cluster.local
downloadProfiles:
  node-default:
    git:
      proxyMode: inherit
      retries: 3
      timeoutSeconds: 240
    npm:
      registry: https://registry.npmmirror.com/
      retries: 3
      fetchTimeoutSeconds: 120
    pip:
      indexUrl: https://pypi.org/simple
      retries: 3
      timeoutSeconds: 120
    docker:
      registryMirrors:
        []
      pullRetries: 3
    curl:
      retries: 3
      connectTimeoutSeconds: 10
      maxTimeSeconds: 120
  d601-node-default:
    git:
      proxyMode: inherit
      retries: 3
      timeoutSeconds: 60
    npm:
      registry: https://registry.npmmirror.com/
      retries: 3
      fetchTimeoutSeconds: 120
    pip:
      indexUrl: https://pypi.org/simple
      retries: 3
      timeoutSeconds: 120
    docker:
      registryMirrors:
        []
      pullRetries: 3
    curl:
      retries: 3
      connectTimeoutSeconds: 10
      maxTimeSeconds: 120
  d518-node-default:
    git:
      proxyMode: inherit
      retries: 3
      timeoutSeconds: 60
    npm:
      registry: https://registry.npmmirror.com/
      retries: 3
      fetchTimeoutSeconds: 120
    pip:
      indexUrl: https://pypi.org/simple
      retries: 3
      timeoutSeconds: 120
    docker:
      registryMirrors:
        []
      pullRetries: 3
    curl:
      retries: 3
      connectTimeoutSeconds: 10
      maxTimeSeconds: 120
  jd01-node-default:
    git:
      proxyMode: inherit
      retries: 3
      timeoutSeconds: 60
    npm:
      registry: https://registry.npmmirror.com/
      retries: 3
      fetchTimeoutSeconds: 120
    pip:
      indexUrl: https://pypi.org/simple
      retries: 3
      timeoutSeconds: 120
    docker:
      registryMirrors:
        []
      pullRetries: 3
    curl:
      retries: 3
      connectTimeoutSeconds: 10
      maxTimeSeconds: 120
  d601-node-no-mirror-benchmark:
    git:
      proxyMode: inherit
      retries: 3
      timeoutSeconds: 120
    npm:
      registry: https://registry.npmjs.org/
      retries: 3
      fetchTimeoutSeconds: 120
    pip:
      indexUrl: https://pypi.org/simple
      retries: 3
      timeoutSeconds: 120
    docker:
      registryMirrors:
        []
      pullRetries: 3
    curl:
      retries: 3
      connectTimeoutSeconds: 10
      maxTimeSeconds: 120
templates:
  hwlabV03:
    webProbeWorkbench:
      browserProxyMode: auto
      defaultOrigin: internal
      resourcePolicy:
        memoryStartGuard:
          metric: MemAvailable
          source: /proc/meminfo
          swapExcluded: true
          # 唯一启动门槛；只有用户明确授权时才允许修改。
          thresholdBytes: 2147483648
          manualComparator: less-than-or-equal
          sentinelComparator: less-than
          snapshotTimeoutSeconds: 30
          launchLockPath: /tmp/unidesk-web-probe-observer-launch.lock
          launchLockTimeoutSeconds: 15
          launchReadyTimeoutSeconds: 10
          launchReadyPollMilliseconds: 200
        observerLifecycle:
          maxRunSeconds: 3600
          maxSamples: 720
          maxScreenshots: 24
          maxPerformanceEntries: 1000
          maxBrowserProcessHistoryEntries: 360
          maxBrowserFreezeSignalHistoryEntries: 120
          maxRealtimeEventEntries: 256
          maxRealtimeEventBodyBytes: 65536
          maxDomEvidenceRows: 1000
          maxProcessScanEntries: 8192
          maxPerformanceCaptureSeconds: 30
          maxResponseBodyBytes: 524288
          maxWebPerformanceBodyBytes: 65536
          maxJsonlQueueEntries: 512
          maxJsonlQueueBytes: 4194304
          maxJsonlLineBytes: 262144
          jsonlFlushTimeoutMs: 5000
          maxResponseBodyInFlight: 2
          maxPassiveListenerTasks: 64
          passiveTaskFlushTimeoutMs: 5000
          closeStepTimeoutMs: 5000
          maxProcessReadConcurrency: 32
          maxRealtimeTotalEntries: 512
          maxRealtimeTotalBodyBytes: 4194304
        browserEvidence:
          screenshotMode: viewport
          maxNetworkRequestEntries: 200
          maxNetworkRequestBytes: 262144
          maxNetworkFailureEntries: 100
          maxNetworkFailureBytes: 131072
      origins:
        internal:
          mode: k8s-service-cluster-ip
          serviceName: hwlab-cloud-web
          namespace: "hwlab-${lane}"
          port: 8080
          scheme: http
          browserProxyMode: direct
        public:
          mode: public
          browserProxyMode: auto
      authLogin:
        maxAttempts: 6
        requestTimeoutMs: 30000
        initialDelayMs: 500
        maxDelayMs: 10000
      defaultNativeReadinessProfile: workbench
      nativeReadinessProfiles:
        tasktree:
          application: tasktree
          path: /projects/tasktree
          navigationTimeoutMs: 30000
          settleMs: 700
          commandTimeoutSeconds: 120
          viewport:
            width: 1920
            height: 1080
          readySelectors:
            - .tasktree-gantt
            - .tasktree-label
            - .desktop-sidebar-toggle
          minBodyTextLength: 20
          interaction:
            selector: .desktop-sidebar-toggle
            observedSelector: .platform-sidebar
            observedAttribute: data-collapsed
          failedResponseStatus: 400
          criticalPathPrefixes:
            - /v1/tasktree
          screenshotName: native-tasktree-ready.png
          outputLimits:
            errors: 20
            failedResponses: 20
            textPreviewChars: 160
        hwpod:
          application: hwpod
          authentication: none
          path: /hwpods/devices
          navigationTimeoutMs: 30000
          settleMs: 700
          commandTimeoutSeconds: 120
          viewport:
            width: 1920
            height: 1080
          readySelectors:
            - "[data-testid='hwpod-console']"
            - .platform-sidebar
          minBodyTextLength: 40
          interaction:
            selector: .desktop-sidebar-toggle
            observedSelector: .platform-sidebar
            observedAttribute: data-collapsed
          failedResponseStatus: 400
          criticalPathPrefixes:
            - /v1/hwpod
            - /health/ready
          screenshotName: native-hwpod-ready.png
          layout:
            requireNoDocumentOverflow: true
            requireNoMainContentOverflow: true
            mainContentSelector: .platform-content
            internalScrollSelectors:
              - .bounded-workspace-main
          outputLimits:
            errors: 20
            failedResponses: 20
            textPreviewChars: 160
        hwpod-onboarding:
          application: hwpod
          authentication: none
          path: /hwpods/onboarding
          navigationTimeoutMs: 30000
          settleMs: 700
          commandTimeoutSeconds: 120
          viewport:
            width: 1920
            height: 1080
          readySelectors:
            - "[data-testid='hwpod-console']"
            - .platform-sidebar
          minBodyTextLength: 40
          interaction:
            selector: .desktop-sidebar-toggle
            observedSelector: .platform-sidebar
            observedAttribute: data-collapsed
          failedResponseStatus: 400
          criticalPathPrefixes:
            - /v1/hwpod
            - /v1/hwlab-node
            - /health/ready
          screenshotName: native-hwpod-onboarding-ready.png
          layout:
            requireNoDocumentOverflow: true
            requireNoMainContentOverflow: true
            mainContentSelector: .platform-content
            internalScrollSelectors:
              - .bounded-workspace-main
          outputLimits:
            errors: 20
            failedResponses: 20
            textPreviewChars: 160
        workbench:
          application: workbench
          path: /workbench
          navigationTimeoutMs: 30000
          settleMs: 500
          commandTimeoutSeconds: 120
          viewport:
            width: 1920
            height: 1080
          readySelectors:
            - "#workspace"
            - .desktop-sidebar-toggle
          minBodyTextLength: 20
          contentReadiness:
            settledSelector: "#session-tabs:not([data-loading='true'])"
            itemSelector: .session-tab
            selectedSelector: ".session-tab[data-active='true']"
            contentSelector: "#conversation-list > :is(.message-card, .conversation-empty-hint, .timeline-row)"
            timeoutMs: 30000
          geometryChecks:
            - selector: ".semantic-failure-banner[data-emphasis='quiet']"
              maxHeightPx: 40
              required: false
          interaction:
            selector: .desktop-sidebar-toggle
            observedSelector: .platform-sidebar
            observedAttribute: data-collapsed
          failedResponseStatus: 400
          criticalPathPrefixes:
            - /v1/
          screenshotName: native-workbench-ready.png
          outputLimits:
            errors: 20
            failedResponses: 20
            textPreviewChars: 160
        caserun:
          application: caserun
          path: /caserun
          navigationTimeoutMs: 30000
          settleMs: 700
          commandTimeoutSeconds: 120
          viewport:
            width: 1920
            height: 1080
          readySelectors:
            - "#caserun-page"
            - "#caserun-panel"
          minBodyTextLength: 40
          interaction:
            selector: ".caserun-run-row:first-child"
            observedSelector: ".caserun-run-row:first-child"
            observedAttribute: class
          failedResponseStatus: 400
          criticalPathPrefixes:
            - /v1/caserun
          screenshotName: native-caserun-ready.png
          layout: &caserunNativeLayout
            requireNoDocumentOverflow: true
            requireNoMainContentOverflow: true
            mainContentSelector: .platform-content
            internalScrollSelectors:
              - .caserun-run-list
              - .caserun-events
              - .evidence-body
          outputLimits:
            errors: 20
            failedResponses: 20
            textPreviewChars: 160
        caserun-compact:
          application: caserun
          path: /caserun
          navigationTimeoutMs: 30000
          settleMs: 700
          commandTimeoutSeconds: 120
          viewport:
            width: 1180
            height: 800
          readySelectors:
            - "#caserun-page"
            - "#caserun-panel"
          minBodyTextLength: 40
          interaction:
            selector: ".caserun-run-row:first-child"
            observedSelector: ".caserun-run-row:first-child"
            observedAttribute: class
          failedResponseStatus: 400
          criticalPathPrefixes:
            - /v1/caserun
          screenshotName: native-caserun-compact-ready.png
          layout: *caserunNativeLayout
          outputLimits:
            errors: 20
            failedResponses: 20
            textPreviewChars: 160
        caserun-mobile:
          application: caserun
          path: /caserun
          navigationTimeoutMs: 30000
          settleMs: 700
          commandTimeoutSeconds: 120
          viewport:
            width: 390
            height: 844
          readySelectors:
            - "#caserun-page"
            - "#caserun-panel"
          minBodyTextLength: 40
          interaction:
            selector: ".caserun-run-row:first-child"
            observedSelector: ".caserun-run-row:first-child"
            observedAttribute: class
          failedResponseStatus: 400
          criticalPathPrefixes:
            - /v1/caserun
          screenshotName: native-caserun-mobile-ready.png
          layout:
            requireNoDocumentOverflow: true
            requireNoMainContentOverflow: true
            mainContentSelector: .platform-content
            internalScrollSelectors:
              - .caserun-workspace
              - .caserun-run-list
              - .caserun-events
              - .evidence-body
          outputLimits:
            errors: 20
            failedResponses: 20
            textPreviewChars: 160
      defaultConsoleVerificationProfile: cloud-console
      consoleVerificationProfiles:
        cloud-console:
          navigationTimeoutMs: 30000
          settleMs: 350
          commandTimeoutSeconds: 900
          minTextLength: 8
          maxHorizontalOverflowPx: 2
          outputLimits:
            failures: 100
            pageErrors: 100
            consoleErrors: 100
            requestFailures: 100
            responseErrors: 100
            screenshots: 24
            textPreviewChars: 160
          viewports:
            - id: desktop
              width: 1920
              height: 1080
            - id: compact
              width: 960
              height: 600
            - id: mobile
              width: 390
              height: 844
          routes:
            - id: dashboard
              path: /dashboard
              readySelector: "#app"
              screenshot: false
            - id: projects
              path: /projects
              readySelector: "[data-testid='project-management-root']"
              screenshot: true
            - id: mdtodo
              path: /projects/mdtodo
              readySelector: "[data-testid='project-management-mdtodo']"
              screenshot: true
            - id: api-keys
              path: /api-keys
              readySelector: "#app"
              screenshot: false
            - id: usage
              path: /usage
              readySelector: "#app"
              screenshot: false
            - id: billing
              path: /billing
              readySelector: "#app"
              screenshot: false
            - id: performance
              path: /performance
              readySelector: "#app"
              screenshot: false
            - id: access
              path: /admin/access
              readySelector: "#app"
              screenshot: true
            - id: secrets
              path: /admin/secrets
              readySelector: "#app"
              screenshot: false
            - id: users
              path: /admin/users
              readySelector: "#app"
              screenshot: false
            - id: admin-billing
              path: /admin/billing
              readySelector: "#app"
              screenshot: false
            - id: hwpod-devices
              path: /hwpods/devices
              readySelector: "[data-testid='hwpod-console']"
              screenshot: true
            - id: hwpod-nodes
              path: /hwpods/nodes
              readySelector: "[data-testid='hwpod-console']"
              screenshot: true
            - id: hwpod-onboarding
              path: /hwpods/onboarding
              readySelector: "[data-testid='hwpod-console']"
              screenshot: true
            - id: provider-profiles
              path: /admin/provider-profiles
              readySelector: "#app"
              screenshot: false
            - id: skills
              path: /skills
              readySelector: "#app"
              screenshot: false
            - id: settings
              path: /settings
              readySelector: "#app"
              screenshot: false
            - id: gate
              path: /gate
              readySelector: "#app"
              screenshot: false
            - id: help
              path: /help
              readySelector: "#app"
              screenshot: false
            - id: agent-runs
              path: /agents/runs?view=table
              readySelector: ".agent-observer-page"
              screenshot: true
          workflows:
            projects:
              routeId: projects
              listButtonName: 列表
              viewQueryKey: view
            hwpod:
              devicesRouteId: hwpod-devices
              nodesRouteId: hwpod-nodes
              onboardingRouteId: hwpod-onboarding
              listButtonName: 列表
              cardButtonName: 电路板卡片
              devicesListSelector: "[aria-label='HWPOD 设备列表']"
              devicesCardSelector: "[aria-label='HWPOD 设备卡片']"
              nodesListSelector: "[aria-label='HWPOD Node 列表']"
              pcbTraceSelector: .pcb-trace
              detailButtonName: 查看详情
              detailPathPrefix: /hwpods/devices/
              onboardingCommandSelector: .install-steps code
              requiredCommandPrefixes:
                - 'Get-FileHash .\'
                - 'python .\'
              downloadSelector: a.download-button
              forbiddenDownloadSubstrings:
                - hwlab.pikapython.com
              forbiddenInternalSelector: .stage-action code
            mdtodo:
              routeId: mdtodo
              taskSelector: "[data-task-ref]"
              taskDeepLinkSegment: /tasks/
              taskDetailSelector: "[data-testid='mdtodo-task-detail']"
              reportLinkSelector: "[data-testid='mdtodo-report-link']:not([disabled])"
              reportPreviewSelector: "[data-testid='mdtodo-report-preview']"
              fullscreenButtonSelector: "[data-testid='mdtodo-report-fullscreen']"
              fullscreenDialogSelector: "[data-testid='mdtodo-report-fullscreen-dialog']"
            agentObserver:
              routeId: agent-runs
              eventSourcePath: /v1/agent-observer/events
              phaseSelector: .agent-observer-stream strong
              blockedPhases:
                - 未连接
                - 传输错误
              streamSettleMs: 1200
              views:
                - buttonName: 卡片
                  queryValue: cards
                  screenshotName: agentrun-cards.png
                - buttonName: 树
                  queryValue: tree
                  screenshotName: agentrun-tree.png
                - buttonName: 表格
                  queryValue: table
                  screenshotName: agentrun-table.png
        agentrun-tree:
          navigationTimeoutMs: 30000
          settleMs: 1200
          commandTimeoutSeconds: 120
          minTextLength: 8
          maxHorizontalOverflowPx: 2
          outputLimits:
            failures: 20
            pageErrors: 20
            consoleErrors: 20
            requestFailures: 20
            responseErrors: 20
            screenshots: 2
            textPreviewChars: 160
          viewports:
            - id: desktop
              width: 1920
              height: 1080
          routes:
            - id: agent-runs-tree
              path: /agents/runs?view=tree
              readySelector: .agent-mind-map
              screenshot: false
          workflows:
            agentObserver:
              routeId: agent-runs-tree
              eventSourcePath: /v1/agent-observer/events
              phaseSelector: .agent-observer-stream strong
              blockedPhases:
                - 未连接
                - 传输错误
              streamSettleMs: 1200
              views:
                - buttonName: 树
                  queryValue: tree
                  screenshotName: agentrun-tree.png
              selection:
                selector: ".agent-mind-map-node[data-kind='run']"
                inspectorSelector: .agent-observer-inspector
                screenshotName: agentrun-tree-inspector.png
        tasktree:
          navigationTimeoutMs: 30000
          settleMs: 700
          commandTimeoutSeconds: 180
          minTextLength: 8
          maxHorizontalOverflowPx: 2
          outputLimits:
            failures: 20
            pageErrors: 20
            consoleErrors: 20
            requestFailures: 20
            responseErrors: 20
            screenshots: 5
            textPreviewChars: 200
          viewports:
            - id: desktop
              width: 1920
              height: 1080
            - id: compact
              width: 960
              height: 600
            - id: mobile
              width: 390
              height: 844
          routes:
            - id: tasktree
              path: /projects/tasktree
              readySelector: body
              screenshot: true
          workflows:
            tasktree:
              routeId: tasktree
              taskSelector: .tasktree-label
              barSelector: .tasktree-bar
              milestoneSelector: .tasktree-milestone
              ganttSelector: .tasktree-gantt
              scrollSelector: .tasktree-timeline-body
              labelPaneSelector: .tasktree-labels
              scaleSelector: .tasktree-zoom output
              tickSelector: .tasktree-days span
              zoomInButtonName: 放大时间尺度
              secondsScaleLabel: 秒
              zoomScreenshotName: tasktree-timescale-second.png
              detailSelector: .tasktree-detail-panel
              dialogSelector: "[role='dialog']"
              dockedSelector: .tasktree-docked-detail
              reportSelector: .tasktree-reports article
              detailScreenshotName: tasktree-detail.png
      realtimeFanoutProfiles:
        pure-kafka-live:
          subscriberCount: 2
          debugStreams:
            - stdio
            - agentrun
            - hwlab
          productEventsPath: /v1/workbench/events
          debugEventsPath: /v1/workbench/debug/kafka-sse/events
          productReadyEvent: workbench.connected
          debugReadyEvent: hwlab.kafka.connected
          businessEvent: hwlab.event.v1
          fromBeginning: false
          barrierTimeoutMs: 45000
          terminalTimeoutMs: 480000
          terminalQuietMs: 2000
          navigationMaxAttempts: 4
          navigationRetryDelayMs: 1000
          reconnectQuietMs: 3000
          expectedProductSse:
            deliverySemantics: kafka-retention-then-live
            liveOnly: false
            replay: true
            replaySupported: true
            lossPossible: false
            refreshHandoff: true
            replayPriorTraceOnReconnect: true
          forbiddenRequestPaths:
            - /v1/workbench/sync
            - /v1/agent/chat/result/
            - /v1/agent/chat/inspect
            - /snapshot
            - /replay
            - /gap-fill
            - /finalizer
          requiredEventTypes:
            agentrun:
              - user_message
              - assistant_message
              - terminal_status
            hwlab:
              - user
              - assistant
              - terminal
          conditionalEventTypePairs:
            tool-call:
              agentrun: tool_call
              hwlab: tool
            command-output:
              agentrun: command_output
              hwlab: status
      workbenchKafkaDebugReplay:
        enabled: true
        topic: hwlab.event.debug.v1
        groupPrefix: hwlab-v03-workbench-isolated-debug
        completionTimeoutMs: 30000
      workbenchTraceReadability:
        enabled: true
        runningCardTimeoutMs: 15000
        disclosureActionTimeoutMs: 15000
        disclosureOpenTimeoutMs: 10000
        runningReadableTimeoutMs: 480000
        terminalTimeoutMs: 480000
        domStableQuietMs: 2000
        domStableTimeoutMs: 6000
        pollIntervalMs: 100
      alertThresholds:
        sameOriginApiSlowMs: 10000
        partialApiSlowMs: 10000
        longLivedStreamOpenSlowMs: 10000
        visibleLoadingSlowMs: 10000
        turnTimingSampleSlackSeconds: 3
        turnElapsedSevereTimeoutSeconds: 120
        domEvaluateTimeoutRedCount: 2
        domEvaluateTimeoutRedWindowMs: 30000
        screenshotTimeoutRedCount: 2
        pageErrorRedCount: 2
        longTaskRedMs: 1000
        longAnimationFrameRedMs: 1000
        eventLoopGapRedMs: 1000
        browserProcessSampleIntervalMs: 1000
        requestRateBucketMs: 10000
        requestRateTotalRedPerMinute: 300
        requestRatePageRedPerMinute: 240
        requestRateApiPathRedPerMinute: 120
        browserTotalRssRedMb: 800
        browserProcessRssRedMb: 600
        browserRssGrowthRedMb: 300
        browserRssGrowthWindowMs: 30000
        playwrightResponsivenessRedMs: 5000
        playwrightResponsivenessTimeoutRedCount: 2
        cdpMetricsTimeoutRedCount: 2
        uncommandedStateChangeCommandWindowMs: 10000
        scrollJumpCommandWindowMs: 8000
        scrollJumpFromY: 250
        scrollJumpToY: 40
        sessionRailFallbackRatio: 0.5
      browserFreezePolicy:
        enabled: true
        blockerWindowMs: 30000
        memory:
          totalRssBlockerMb: 800
          processRssBlockerMb: 500
          growthBlockerMb: 300
        responsiveness:
          latencyBlockerMs: 5000
          eventBlockerCount: 2
        cdp:
          metricsTimeoutBlockerCount: 2
        kill:
          enabled: true
          gracefulSignal: SIGTERM
          forceSignal: SIGKILL
          graceMs: 3000
          pollIntervalMs: 100
          exitCode: 7
      projectManagement:
        enabled: true
        targetPaths:
          - /projects
          - /projects/mdtodo
        readinessSelectors:
          - "[data-testid=\"project-management-root\"]"
          - "[data-testid=\"project-management-mdtodo\"]"
        naturalApiPathPrefixes:
          - /v1/project-management/
          - /v1/workbench/launches
          - /v1/agent/chat
        commandAllowlist:
          - gotoProjectMdtodo
          - openMdtodoSourceConfig
          - closeMdtodoSourceConfig
          - configureMdtodoHwpodSource
          - probeMdtodoSource
          - reindexMdtodoSource
          - selectProjectSource
          - selectMdtodoSource
          - selectMdtodoFile
          - selectMdtodoTask
          - expandMdtodoTask
          - openMdtodoReportPreview
          - toggleMdtodoReportFullscreen
          - editMdtodoTaskInline
          - editMdtodoTaskTitle
          - editMdtodoTaskBody
          - toggleMdtodoTaskStatus
          - addMdtodoRootTask
          - addMdtodoSubTask
          - continueMdtodoTask
          - deleteMdtodoTask
          - launchWorkbenchFromTask
          - launchWorkbenchFromMdtodo
        launchRoute: /v1/workbench/launches
        slowApiBudgetMs: 10000
    runtimeImageRewrites:
      postgres:
        source: postgres:16-alpine
        target: 127.0.0.1:5000/hwlab/postgres:16-alpine
      frpc:
        source: fatedier/frpc:v0.68.1
        target: 127.0.0.1:5000/hwlab/frpc:v0.68.1
      openfga:
        source: openfga/openfga:v1.17.0
        target: 127.0.0.1:5000/hwlab/openfga:v1.17.0
      opencode:
        source: ghcr.io/anomalyco/opencode:1.17.7
        target: 127.0.0.1:5000/hwlab/opencode:1.17.7
    runtimeImageBuilds:
      moonbridge:
        id: moonbridge
        kind: moonbridge
        target: 127.0.0.1:5000/hwlab/moonbridge:1b99888d3dae
        sourceRepo: https://github.com/ZhiYi-R/moon-bridge.git
        sourceRef: 1b99888d3dae889b79ee602cb875c7907f7e76f2
        builderImage: golang:1.25-bookworm
        goProxy: "https://goproxy.cn,direct"
        dockerNetworkMode: host
      opencodeGit:
        id: opencode-git
        kind: opencode-git
        target: 127.0.0.1:5000/hwlab/opencode:1.17.7-git
        sourceImage: ghcr.io/anomalyco/opencode:1.17.7
        dockerNetworkMode: host
    externalPostgresConsumer:
      port: 5432
      sslmode: require
      migrationLedger:
        identity: "hwlab-${nodeLower}-${lane}"
        table: hwlab_schema_migrations
      cloudApi:
        secretName: hwlab-cloud-api-v03-db
        secretKey: database-url
        envKey: DATABASE_URL
      openfga:
        secretName: hwlab-v03-openfga
        secretKey: datastore-uri
        envKey: DATASTORE_URI
        authnKey: authn-preshared-key
    sourceAuthorityGiteaSnapshot:
      mode: giteaSnapshot
      resolver: gitea-mirror
      allowHostGit: false
      allowHostWorkspace: false
      allowGithubDirectInPipeline: false
    sourceSnapshotGiteaControlled:
      stageRefPrefix: "refs/unidesk/snapshots/gitea-actions/hwlab-node-runtime/{branch}"
      missingObjectPolicy: fail-fast
      refreshPolicy: gitea-controlled-snapshot
