# SPEC: PJ2026-01060505 Workbench Performance draft-2026-06-17-p0.
version: 1
kind: HwlabNodeLaneConfig
metadata:
  name: hwlab-node-lanes

defaults:
  node: G14
  lane: v03

requiredNoProxy:
  - hyueapi.com
  - .hyueapi.com

nodes:
  G14:
    route: G14
    kubeRoute: G14:k3s
    sourceWorkspace: /root/hwlab
    gitopsRoot: deploy/gitops/node
    networkProfile: node-ci-egress
    downloadProfile: node-default
  D601:
    route: D601
    kubeRoute: D601:k3s
    sourceWorkspace: /home/ubuntu/workspace/hwlab-v03
    gitopsRoot: deploy/gitops/node
    networkProfile: d601-node-ci-egress
    downloadProfile: d601-node-default

lanes:
  v02:
    node: G14
    minor: 2
    version: v0.2
    sourceBranch: v0.2
    workspace: /root/hwlab-v02
    cicdRepo: /root/hwlab-v02-cicd.git
    cicdRepoLock: /tmp/hwlab-v02-cicd-repo.lock
    app: hwlab-g14-v02
    pipeline: hwlab-v02-ci-image-publish
    pipelineRunPrefix: hwlab-v02-ci-poll
    serviceAccountName: hwlab-v02-tekton-runner
    controlPlaneFieldManager: unidesk-hwlab-v02-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.2-gitops
    catalogPath: deploy/artifact-catalog.v02.json
    runtime:
      path: deploy/gitops/g14/runtime-v02
      namespace: hwlab-v02
      renderDir: runtime-v02
    tektonDir: tekton-v02
    argoApplicationFile: application-v02.yaml
    registryPrefix: 127.0.0.1:5000/hwlab
    baseImage: 127.0.0.1:5000/hwlab/hwlab-node20-base:20-bookworm-slim
    serviceIds:
      - hwlab-cloud-api
      - hwlab-cloud-web
      - hwlab-gateway
      - hwlab-edge-proxy
      - hwlab-agent-skills
    observability:
      prometheusOperator: true
    public:
      webUrl: http://74.48.78.17:19666
      apiUrl: http://74.48.78.17:19667
  v03:
    node: G14
    minor: 3
    version: v0.3
    sourceBranch: v0.3
    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-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: hwlab/g14-v03-bootstrap-admin.env
      passwordSourceKey: HWLAB_BOOTSTRAP_ADMIN_PASSWORD
      passwordHashTransform: hwlab-sha256
      secretName: hwlab-v03-bootstrap-admin
      secretKey: password-hash
      rollout:
        deployment: hwlab-cloud-api
    targets:
      D601:
        workspace: /home/ubuntu/workspace/hwlab-v03
        cicdRepo: /home/ubuntu/workspace/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-d601-v03-control-plane
        git:
          url: git@github.com:pikasTech/HWLAB.git
          readUrl: http://git-mirror-http.devops-infra.svc.cluster.local:8080/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.d601-v03.json
        runtime:
          path: deploy/gitops/node/d601/runtime-v03
          namespace: hwlab-v03
          renderDir: runtime-v03
        runtimeStore:
          postgres:
            poolMax: 16
            connectionTimeoutMs: 5000
            queryRetryMaxAttempts: 5
            queryRetryInitialDelayMs: 250
            queryRetryMaxDelayMs: 5000
        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-cloud-web
          - hwlab-gateway
          - hwlab-edge-proxy
          - hwlab-agent-skills
        buildkit:
          sidecarImage: 127.0.0.1:5000/hwlab/buildkit:rootless
        stepEnv:
          HOME: /tekton/home
          XDG_CONFIG_HOME: /tekton/home/.config
        observability:
          prometheusOperator: false
          traceExplorerUrlTemplate: /v1/workbench/traces/{trace_id}/events
          metricsEndpoint:
            serviceName: hwlab-cloud-api
            containerName: hwlab-cloud-api
            port: 6667
            scheme: http
            path: /v1/web-performance/metrics
            scrapeMode: pod-loopback
            publicRawMetrics: denied
          workbench:
            enabled: true
            summaryPath: /v1/web-performance/summary
            lowSampleThreshold: 5
            metricPrefixes:
              - hwlab_workbench_
              - hwlab_agentrun_
              - hwlab_webui_
              - hwlab_http_
            requiredSeries: []
            backendLabelDenylist:
              - unknown
            maxUnknownEventLines: 0
          recordingRules:
            - id: workbench_submit_first_visible_p95
              metric: hwlab:workbench_submit_first_visible:p95_seconds
              sourceMetric: hwlab_workbench_journey_duration_seconds
              quantile: 0.95
              window: 5m
              minSamples: 5
              groupBy: [namespace, gitops_target, journey, route, backend, transport, entry, outcome]
              matchLabels:
                journey: submit_to_first_visible
            - id: workbench_backend_event_visible_p95
              metric: hwlab:workbench_backend_event_visible:p95_seconds
              sourceMetric: hwlab_workbench_backend_event_visible_latency_seconds
              quantile: 0.95
              window: 5m
              minSamples: 5
              groupBy: [namespace, gitops_target, event_type, backend, transport, outcome]
            - id: workbench_session_switch_p95
              metric: hwlab:workbench_session_switch:p95_seconds
              sourceMetric: hwlab_workbench_journey_duration_seconds
              quantile: 0.95
              window: 5m
              minSamples: 5
              groupBy: [namespace, gitops_target, journey, route, target_state, cache, source, outcome]
              matchLabels:
                journey: session_switch_first_visible|session_switch_full_load
            - id: workbench_open_p95
              metric: hwlab:workbench_open:p95_seconds
              sourceMetric: hwlab_workbench_journey_duration_seconds
              quantile: 0.95
              window: 5m
              minSamples: 5
              groupBy: [namespace, gitops_target, journey, route, cache, auth_state, outcome]
              matchLabels:
                journey: workbench_open_first_visible|workbench_open_full_load
            - id: workbench_projection_lag_p95
              metric: hwlab:workbench_projection_lag:p95_seconds
              sourceMetric: hwlab_workbench_projection_lag_seconds
              quantile: 0.95
              window: 5m
              minSamples: 1
              groupBy: [namespace, gitops_target, node, lane, projection_status, source, status, reason]
            - id: workbench_terminal_projection_delay_p95
              metric: hwlab:workbench_terminal_projection_delay:p95_seconds
              sourceMetric: hwlab_workbench_terminal_projection_delay_seconds
              quantile: 0.95
              window: 5m
              minSamples: 1
              groupBy: [namespace, gitops_target, node, lane, projection_status, source, status, reason]
            - id: workbench_turn_get_p95
              metric: hwlab:workbench_turn_get:p95_seconds
              sourceMetric: hwlab_workbench_turn_get_duration_seconds
              quantile: 0.95
              window: 5m
              minSamples: 1
              groupBy: [namespace, gitops_target, node, lane, route, status, degraded_reason]
            - id: agentrun_result_p95
              metric: hwlab:agentrun_result:p95_seconds
              sourceMetric: hwlab_agentrun_result_duration_seconds
              quantile: 0.95
              window: 5m
              minSamples: 1
              groupBy: [namespace, gitops_target, node, lane, event_count_bucket, status]
            - id: workbench_projector_batch_p95
              metric: hwlab:workbench_projector_batch:p95_seconds
              sourceMetric: hwlab_workbench_projector_batch_duration_seconds
              quantile: 0.95
              window: 5m
              minSamples: 1
              groupBy: [namespace, gitops_target, node, lane, phase, status]
          warningAlerts:
            - id: HWLABWorkbenchSubmitFirstVisibleSlow
              ruleId: workbench_submit_first_visible_p95
              severity: warning
              thresholdSeconds: 15
              minSamples: 5
              for: 10m
              matchLabels:
                journey: submit_to_first_visible
            - id: HWLABWorkbenchBackendEventVisibleSlow
              ruleId: workbench_backend_event_visible_p95
              severity: warning
              thresholdSeconds: 10
              minSamples: 5
              for: 10m
            - id: HWLABWorkbenchSessionSwitchSlow
              ruleId: workbench_session_switch_p95
              severity: warning
              thresholdSeconds: 8
              minSamples: 5
              for: 10m
            - id: HWLABWorkbenchOpenSlow
              ruleId: workbench_open_p95
              severity: warning
              thresholdSeconds: 13
              minSamples: 5
              for: 10m
            - id: WorkbenchProjectionStuck
              ruleId: workbench_projection_lag_p95
              severity: warning
              thresholdSeconds: 60
              minSamples: 1
              for: 10m
            - id: WorkbenchTerminalProjectionMissing
              ruleId: workbench_terminal_projection_delay_p95
              severity: warning
              thresholdSeconds: 60
              minSamples: 1
              for: 10m
            - id: WorkbenchTurnReadSlow
              ruleId: workbench_turn_get_p95
              severity: warning
              thresholdSeconds: 5
              minSamples: 1
              for: 10m
            - id: AgentRunResultSlowLongTrace
              ruleId: agentrun_result_p95
              severity: warning
              thresholdSeconds: 2.5
              minSamples: 1
              for: 10m
            - id: WorkbenchProjectorNoProgress
              ruleId: workbench_projector_batch_p95
              severity: warning
              thresholdSeconds: 10
              minSamples: 1
              for: 10m
        runtimeImageRewrites:
          - source: fatedier/frpc:v0.68.1
            target: 127.0.0.1:5000/hwlab/frpc:v0.68.1
        public:
          webUrl: https://hwlab.pikapython.com
          apiUrl: https://hwlab.pikapython.com
        bootstrapAdmin:
          username: admin
          displayName: HWLAB v0.3 Admin
          passwordSourceRef: hwlab/d601-v03-bootstrap-admin.env
          passwordSourceKey: HWLAB_BOOTSTRAP_ADMIN_PASSWORD
          passwordHashTransform: hwlab-sha256
          secretName: hwlab-v03-bootstrap-admin
          secretKey: password-hash
          rollout:
            deployment: hwlab-cloud-api
        publicExposure:
          mode: pk01-caddy-frp
          publicBaseUrl: https://hwlab.pikapython.com
          hostname: hwlab.pikapython.com
          expectedA: 82.156.23.220
          frpc:
            serverAddr: 82.156.23.220
            serverPort: 22000
            tokenSourceRef: platform-infra/pk01-frp.env
            tokenSourceKey: FRP_TOKEN
            secretName: hwlab-v03-frpc-secrets
            secretKey: frpc.toml
            tokenKey: token
            webProxy:
              name: hwlab-d601-v03-cloud-web
              remotePort: 22096
              localIP: hwlab-cloud-web.hwlab-v03.svc.cluster.local
              localPort: 8080
            apiProxy:
              name: hwlab-d601-v03-edge-proxy
              remotePort: 22095
              localIP: hwlab-edge-proxy.hwlab-v03.svc.cluster.local
              localPort: 6667
          caddy:
            route: PK01
            configPath: /etc/caddy/Caddyfile
            serviceName: caddy
            email: ops@pikapython.com
            tls: auto
            responseHeaderTimeoutSeconds: 600
        externalPostgres:
          provider: PK01
          configRef: config/platform-db/postgres-pk01.yaml
          serviceName: pk01-platform-postgres
          endpointAddress: 82.156.23.220
          port: 5432
          sslmode: require
          database: hwlab_d601_v03
          cloudApi:
            secretName: hwlab-cloud-api-v03-db
            secretKey: database-url
            sourceRef: hwlab/d601-v03-cloud-api-db.env
            envKey: DATABASE_URL
            role: hwlab_d601_v03_app
          openfga:
            secretName: hwlab-v03-openfga
            secretKey: datastore-uri
            sourceRef: hwlab/d601-v03-openfga-db.env
            envKey: DATASTORE_URI
            authnKey: authn-preshared-key
            role: hwlab_d601_v03_app

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.npmjs.org
        - .registry.npmjs.org
  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
        - deb.debian.org
        - .debian.org
        - goproxy.cn
        - .goproxy.cn
        - .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
        - hwlab.pikapython.com
    dockerBuildProxy:
      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
        - deb.debian.org
        - .debian.org
        - goproxy.cn
        - .goproxy.cn
        - .svc
        - .svc.cluster.local
        - .cluster.local

downloadProfiles:
  node-default:
    git:
      proxyMode: inherit
      retries: 3
      timeoutSeconds: 240
    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
  d601-node-default:
    git:
      proxyMode: inherit
      retries: 3
      timeoutSeconds: 60
    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
