Skip to content

[2624 by GPT-6 Astra] New goal and task screen standardization - #2625

Merged
integry merged 6 commits into
mainfrom
2624/gpt-6-astra-new-goal-and-task-screen--20260929-1202-2hj
Sep 30, 2026
Merged

integry merged 6 commits into
mainfrom
2624/gpt-6-astra-new-goal-and-task-screen--20260929-1202-2hj

Conversation

@propr-dev

@propr-dev propr-dev Bot commented Sep 29, 2026 •

Copy link
Copy Markdown
Contributor

AI Implementation Summary

Closes #2624

Branch: 2624/gpt-6-astra-new-goal-and-task-screen--20260929-1202-2hj
Commits: ✅ Changes committed (93e0c85)


AI Processing Completed

Execution Details:

  • Issue: New goal and task screen standardization #2624
  • Repository: integry/propr
  • Status: Success
  • Execution Time: 10m 1s
  • Tokens used: 1.77M tokens [1.76M input + 13.88K output]
  • API cost: $3.26
  • Timestamp: Sep 29, 2026, 12:12 PM UTC
  • LLM Model: GPT-6 Astra
  • Subscription usage: Weekly +1%

Summary:
Implemented shared centered modals for task and goal creation, consistent “Prompt” labels, docked attachments, collapsed Advanced Options, compact strategy controls, and removal of promotional cards.

Validated with 65 unit tests, 13 browser checks, TypeScript, and lint. Captured desktop and mobile previews.

Detailed Logs:

  • Conversation: 60 messages
  • Session: 01a0ed0c-4e9c-7411-97dc-7454b86b8921

Log files stored at:

  • conversation: /tmp/claude-logs/issue-2624-2026-09-29T12-12-24-611Z-conversation.json
  • output: /tmp/claude-logs/issue-2624-2026-09-29T12-12-24-611Z-output.txt
Latest Conversation Messages

This PR was created automatically by ProPR after processing issue #2624.


💡 Need changes?

Comment on this PR to request refinements — the AI agent monitors comments and will update the implementation based on your feedback. Keep iterating until you're satisfied!


Visual preview

New goal dialog

New goal dialog

Goal creation uses the same centered layout, prompt vocabulary, docked attachments, and collapsed session settings.

Original unavailable: managed storage is unavailable or the upload has expired.

New goal on mobile

New goal on mobile

The matching goal creation dialog with an attached requirements file on mobile.

Original unavailable: managed storage is unavailable or the upload has expired.

Goal advanced options

Goal advanced options

Expanded session settings with compact strategy radios, model, concurrency, and Ultrafix controls.

Original unavailable: managed storage is unavailable or the upload has expired.

New goal options mobile

New goal options mobile

Original unavailable: managed storage is unavailable or the upload has expired.

New task dialog

New task dialog

Centered task creation with a prompt, docked attachments, collapsed Advanced Options, and Cancel / Run task actions.

Original unavailable: managed storage is unavailable or the upload has expired.

New task error mobile

New task error mobile

Original unavailable: managed storage is unavailable or the upload has expired.

New task on mobile

New task on mobile

Task creation fits a mobile viewport with the primary actions visible.

Original unavailable: managed storage is unavailable or the upload has expired.

New task rejected desktop

New task rejected desktop

Original unavailable: managed storage is unavailable or the upload has expired.

Implemented by ProPR AI using gpt-6-astra model.

Implementation completed successfully.
@github-actions

Copy link
Copy Markdown

Full Test Suite Results

Validation failed during: Test shard (shard 2).

  • Docs site validation: skipped (classifier decision: false)
  • Shard coverage verification: success
  • Hosted native Electron units: skipped (classifier decision: false)
  • Shard 1/4: passed in 286.6s on GitHub Actions 1000051205
  • Shard 2/4: failed during Test shard in 421.2s on GitHub Actions 1000051206
    • apps/desktop/scripts/desktop-native-menu.test.mjs: exit 1
  • Shard 3/4: passed in 276.0s on GitHub Actions 1000051207
  • Shard 4/4: passed in 261.3s on GitHub Actions 1000051208
View shard 2/4 output
...(truncated)

ferred record after successful wake
    ok 4 - resume clears deferred record after successful wake
      ---
      duration_ms: 0.222087
      type: 'test'
      ...
    # Subtest: resume keeps deferred record when still not ready
    ok 5 - resume keeps deferred record when still not ready
      ---
      duration_ms: 0.243277
      type: 'test'
      ...
    # Subtest: no overlap: blocks when competing ultrafix job exists
    ok 6 - no overlap: blocks when competing ultrafix job exists
      ---
      duration_ms: 0.147086
      type: 'test'
      ...
    # Subtest: cooldown is not a readiness condition (handled by enqueue delay)
    ok 7 - cooldown is not a readiness condition (handled by enqueue delay)
      ---
      duration_ms: 0.131096
      type: 'test'
      ...
    1..7
ok 8 - defer and resume behavior
  ---
  duration_ms: 1.57103
  type: 'suite'
  ...
# Subtest: parseDeferredKey
    # Subtest: parses a valid key
    ok 1 - parses a valid key
      ---
      duration_ms: 0.261781
      type: 'test'
      ...
    # Subtest: returns null for invalid key format
    ok 2 - returns null for invalid key format
      ---
      duration_ms: 0.087184
      type: 'test'
      ...
    # Subtest: returns null for key with too few parts
    ok 3 - returns null for key with too few parts
      ---
      duration_ms: 0.156324
      type: 'test'
      ...
    # Subtest: returns null for key with non-numeric PR
    ok 4 - returns null for key with non-numeric PR
      ---
      duration_ms: 0.139803
      type: 'test'
      ...
    1..4
ok 9 - parseDeferredKey
  ---
  duration_ms: 0.816684
  type: 'suite'
  ...
1..9
# tests 40
# suites 9
# pass 40
# fail 0
# cancelled 0
# skipped 0
# todo 0
# duration_ms 329.981277
[143/150] passed test/ultrafixReadiness.test.ts in 0.5s

[144/150] test/usageTipsSelectionRunner.test.ts
TAP version 13
# Subtest: replicas and overlapping ticks select once per day; reloads do not advance epochs
ok 1 - replicas and overlapping ticks select once per day; reloads do not advance epochs
  ---
  duration_ms: 2.812952
  type: 'test'
  ...
# Subtest: failed runs retain epoch; persistence failure does not consume it
ok 2 - failed runs retain epoch; persistence failure does not consume it
  ---
  duration_ms: 0.594527
  type: 'test'
  ...
# Subtest: freshness and enablement are rechecked after acquisition
ok 3 - freshness and enablement are rechecked after acquisition
  ---
  duration_ms: 0.549052
  type: 'test'
  ...
# Subtest: lost leases and disablement during model calls cannot persist
ok 4 - lost leases and disablement during model calls cannot persist
  ---
  duration_ms: 0.695737
  type: 'test'
  ...
# Subtest: long model runs renew ownership
ok 5 - long model runs renew ownership
  ---
  duration_ms: 50.260355
  type: 'test'
  ...
1..5
# tests 5
# suites 0
# pass 5
# fail 0
# cancelled 0
# skipped 0
# todo 0
# duration_ms 515.089087
[144/150] passed test/usageTipsSelectionRunner.test.ts in 0.6s

[145/150] test/vibeAgent.test.ts
TAP version 13
# Subtest: parseVibeOutput
    # Subtest: returns plain output as the summary when output is not JSON
    ok 1 - returns plain output as the summary when output is not JSON
      ---
      duration_ms: 1.69846
      type: 'test'
      ...
    # Subtest: parses nested message content and metadata from JSON output
    ok 2 - parses nested message content and metadata from JSON output
      ---
      duration_ms: 3.101755
      type: 'test'
      ...
    # Subtest: extracts text from common Vibe content object shapes
    ok 3 - extracts text from common Vibe content object shapes
      ---
      duration_ms: 1.494597
      type: 'test'
      ...
    # Subtest: separates adjacent structured array text parts
    ok 4 - separates adjacent structured array text parts
      ---
      duration_ms: 0.386216
      type: 'test'
      ...
    # Subtest: does not promote nested metadata objects to output events
    ok 5 - does not promote nested metadata objects to output events
      ---
      duration_ms: 0.802667
      type: 'test'
      ...
    # Subtest: prefers known final events over trailing metadata text
    ok 6 - prefers known final events over trailing metadata text
      ---
      duration_ms: 0.230262
      type: 'test'
      ...
    # Subtest: treats assistant transcript arrays as complete Vibe output
    ok 7 - treats assistant transcript arrays as complete Vibe output
      ---
      duration_ms: 0.202189
      type: 'test'
      ...
    # Subtest: converts Vibe transcript arrays into structured conversation log entries
    ok 8 - converts Vibe transcript arrays into structured conversation log entries
      ---
      duration_ms: 0.917383
      type: 'test'
      ...
    # Subtest: captures explicit error events
    ok 9 - captures explicit error events
      ---
      duration_ms: 0.291607
      type: 'test'
      ...
    # Subtest: ignores transient errors followed by a final response
    ok 10 - ignores transient errors followed by a final response
      ---
      duration_ms: 0.369114
      type: 'test'
      ...
    # Subtest: marks JSON text output incomplete when no final event is present and treats it as failure
    ok 11 - marks JSON text output incomplete when no final event is present and treats it as failure
      ---
      duration_ms: 0.199725
      type: 'test'
      ...
    1..11
ok 1 - parseVibeOutput
  ---
  duration_ms: 11.165368
  type: 'suite'
  ...
# Subtest: readLatestVibeSessionTokenUsage
    # Subtest: reads token totals from Vibe session meta stats
    ok 1 - reads token totals from Vibe session meta stats
      ---
      duration_ms: 1.4276
      type: 'test'
      ...
    1..1
ok 2 - readLatestVibeSessionTokenUsage
  ---
  duration_ms: 1.524793
  type: 'suite'
  ...
# Subtest: Vibe CLI args
    # Subtest: splits shell-like VIBE_CLI_ARGS without invoking a shell
    ok 1 - splits shell-like VIBE_CLI_ARGS without invoking a shell
      ---
      duration_ms: 0.577023
      type: 'test'
      ...
    # Subtest: does not forward VIBE_CLI_ARGS into the container environment
    ok 2 - does not forward VIBE_CLI_ARGS into the container environment
      ---
      duration_ms: 0.237005
      type: 'test'
      ...
    # Subtest: reports which VIBE_CLI_ARGS source is invalid
    ok 3 - reports which VIBE_CLI_ARGS source is invalid
      ---
      duration_ms: 1.19819
      type: 'test'
      ...
    1..3
ok 3 - Vibe CLI args
  ---
  duration_ms: 2.139037
  type: 'suite'
  ...
# Subtest: VibeAgent Docker args
    # Subtest: resolves Mistral API key from ProPR settings when explicit env is absent
    ok 1 - resolves Mistral API key from ProPR settings when explicit env is absent
      ---
      duration_ms: 0.261772
      type: 'test'
      ...
    # Subtest: uses stdin-oriented structured default command and read-only sandbox for analysis
    ok 2 - uses stdin-oriented structured default command and read-only sandbox for analysis
      ---
      duration_ms: 1.271758
      type: 'test'
      ...
    # Subtest: analysis mode uses bridge network for outbound Mistral API access
    ok 3 - analysis mode uses bridge network for outbound Mistral API access
      ---
      duration_ms: 0.645201
      type: 'test'
      ...
    # Subtest: hasUsableConfigDir requires config.toml or credentials.json
    ok 4 - hasUsableConfigDir requires config.toml or credentials.json
      ---
      duration_ms: 1.609723
      type: 'test'
      ...
    # Subtest: wraps implementation runs for repo setup and honors VIBE_CLI_ARGS
    ok 5 - wraps implementation runs for repo setup and honors VIBE_CLI_ARGS
      ---
      duration_ms: 0.605417
      type: 'test'
      ...
    # Subtest: mounts Vibe runtime home through the shared prompt cache host path
    ok 6 - mounts Vibe runtime home through the shared prompt cache host path
      ---
      duration_ms: 0.381436
      type: 'test'
      ...
    # Subtest: expands tilde config paths before checking Docker mountability
    ok 7 - expands tilde config paths before checking Docker mountability
      ---
      duration_ms: 1.014436
      type: 'test'
      ...
    # Subtest: entrypoint forces Vibe runtime home after dropping privileges
    ok 8 - entrypoint forces Vibe runtime home after dropping privileges
      ---
      duration_ms: 0.392547
      type: 'test'
      ...
    # Subtest: Vibe image provides a su-exec-compatible helper for no-new-privileges user switching
    ok 9 - Vibe image provides a su-exec-compatible helper for no-new-privileges user switching
      ---
      duration_ms: 0.267353
      type: 'test'
      ...
    # Subtest: propagates Mistral API key through the explicit credential path
    ok 10 - propagates Mistral API key through the explicit credential path
      ---
      duration_ms: 0.684356
      type: 'test'
      ...
    # Subtest: uses structured output in the default execution command
    ok 11 - uses structured output in the default execution command
      ---
      duration_ms: 0.322235
      type: 'test'
      ...
    1..11
ok 4 - VibeAgent Docker args
  ---
  duration_ms: 7.798555
  type: 'suite'
  ...
# Subtest: Docker command stdin delivery
    # Subtest: passes prompt data through stdin
    ok 1 - passes prompt data through stdin
      ---
      duration_ms: 45.473257
      type: 'test'
      ...
    1..1
ok 5 - Docker command stdin delivery
  ---
  duration_ms: 45.699712
  type: 'suite'
  ...
# [2026-09-29 12:20:02.324 +0000] �[32mINFO�[39m: �[36mSQLite database connection established successfully�[39m
#     filename: "/tmp/propr-test-suite-vUHz0x/145-vibeAgent.test.ts/propr.test.sqlite"
#     environment: "test"
# [2026-09-29 12:20:02.332 +0000] �[32mINFO�[39m: �[36mDocker args built for Vibe agent�[39m
#     issueNumber: 0
#     agentAlias: "vibe-test"
#     mode: "analysis"
#     dockerImage: "propr/agent:bundle-test"
#     configPath: "/tmp/vibe-config-test-7qW1kw"
#     configPathMounted: true
#     workspaceMountMode: "ro"
#     cliArgsSource: "default"
#     cliArgCount: 2
# [2026-09-29 12:20:02.333 +0000] �[32mINFO�[39m: �[36mDocker args built for Vibe agent�[39m
#     issueNumber: 0
#     agentAlias: "vibe-test"
#     mode: "analysis"
#     dockerImage: "propr/agent:bundle-test"
#     configPath: "/tmp/missing-vibe-config"
#     configPathMounted: false
#     workspaceMountMode: "ro"
#     cliArgsSource: "default"
#     cliArgCount: 2
# [2026-09-29 12:20:02.334 +0000] �[32mINFO�[39m: �[36mDocker args built for Vibe agent�[39m
#     issueNumber: 1477
#     agentAlias: "vibe-test"
#     mode: "execute"
#     dockerImage: "propr/agent:bundle-test"
#     configPath: "/tmp/vibe-empty-Lxfgls"
#     configPathMounted: false
#     workspaceMountMode: "rw"
#     cliArgsSource: "default"
#     cliArgCount: 2
# [2026-09-29 12:20:02.335 +0000] �[32mINFO�[39m: �[36mDocker args built for Vibe agent�[39m
#     issueNumber: 1477
#     agentAlias: "vibe-test"
#     mode: "execute"
#     dockerImage: "propr/agent:bundle-test"
#     configPath: "/tmp/vibe-cache-6bD4c7"
#     configPathMounted: false
#     workspaceMountMode: "rw"
#     cliArgsSource: "default"
#     cliArgCount: 2
# [2026-09-29 12:20:02.335 +0000] �[32mINFO�[39m: �[36mDocker args built for Vibe agent�[39m
#     issueNumber: 1477
#     agentAlias: "vibe-test"
#     mode: "execute"
#     dockerImage: "propr/agent:bundle-test"
#     configPath: "/tmp/vibe-valid-Ee58Wl"
#     configPathMounted: true
#     workspaceMountMode: "rw"
#     cliArgsSource: "default"
#     cliArgCount: 2
# [2026-09-29 12:20:02.336 +0000] �[32mINFO�[39m: �[36mDocker args built for Vibe agent�[39m
#     issueNumber: 1477
#     agentAlias: "vibe-test"
#     mode: "execute"
#     dockerImage: "propr/agent:bundle-test"
#     configPath: "/tmp/missing-vibe-config"
#     configPathMounted: false
#     workspaceMountMode: "rw"
#     cliArgsSource: "custom"
#     cliArgCount: 5
# [2026-09-29 12:20:02.336 +0000] �[32mINFO�[39m: �[36mDocker args built for Vibe agent�[39m
#     issueNumber: 1477
#     agentAlias: "vibe-test"
#     mode: "execute"
#     dockerImage: "propr/agent:bundle-test"
#     configPath: "/tmp/missing-vibe-config"
#     configPathMounted: false
#     workspaceMountMode: "rw"
#     cliArgsSource: "default"
#     cliArgCount: 2
# [2026-09-29 12:20:02.337 +0000] �[32mINFO�[39m: �[36mDocker args built for Vibe agent�[39m
#     issueNumber: 0
#     agentAlias: "vibe-test"
#     mode: "analysis"
#     dockerImage: "propr/agent:bundle-test"
#     configPath: "/tmp/vibe-home-sQpwMe/.vibe"
#     configPathMounted: true
#     workspaceMountMode: "ro"
#     cliArgsSource: "default"
#     cliArgCount: 2
# [2026-09-29 12:20:02.339 +0000] �[33mWARN�[39m: �[36mSkipping invalid Vibe Docker environment variable�[39m
#     agentAlias: "vibe-test"
#     envVar: "BAD-ENV"
# [2026-09-29 12:20:02.339 +0000] �[33mWARN�[39m: �[36mSkipping invalid Vibe Docker environment variable�[39m
#     agentAlias: "vibe-test"
#     envVar: "MULTILINE_ENV"
# [2026-09-29 12:20:02.339 +0000] �[32mINFO�[39m: �[36mDocker args built for Vibe agent�[39m
#     issueNumber: 1477
#     agentAlias: "vibe-test"
#     mode: "execute"
#     dockerImage: "propr/agent:bundle-test"
#     configPath: "/tmp/empty-vibe-config-2innvP"
#     configPathMounted: false
#     workspaceMountMode: "rw"
#     cliArgsSource: "custom"
#     cliArgCount: 3
# [2026-09-29 12:20:02.339 +0000] �[32mINFO�[39m: �[36mDocker args built for Vibe agent�[39m
#     issueNumber: 1477
#     agentAlias: "vibe-test"
#     mode: "execute"
#     dockerImage: "propr/agent:bundle-test"
#     configPath: "/tmp/missing-vibe-config"
#     configPathMounted: false
#     workspaceMountMode: "rw"
#     cliArgsSource: "default"
#     cliArgCount: 2
# [2026-09-29 12:20:02.386 +0000] �[32mINFO�[39m: �[36mSQLite database connection closed�[39m
1..5
# tests 27
# suites 5
# pass 27
# fail 0
# cancelled 0
# skipped 0
# todo 0
# duration_ms 1591.610364
[145/150] passed test/vibeAgent.test.ts in 1.7s

[146/150] test/webhookReplayProtection.test.ts
TAP version 13
# [webhook] Missing x-github-delivery header
# Subtest: Webhook Replay Protection
    # Subtest: Missing delivery ID
        # Subtest: rejects request with no x-github-delivery header
        ok 1 - rejects request with no x-github-delivery header
          ---
          duration_ms: 30.125114
          type: 'test'
          ...
        1..1
    ok 1 - Missing delivery ID
      ---
      duration_ms: 30.876275
      type: 'suite'
      ...
# [webhook] Rejecting multi-valued x-github-delivery header
    # Subtest: Array-valued delivery ID
        # Subtest: rejects request with multi-valued x-github-delivery header
        ok 1 - rejects request with multi-valued x-github-delivery header
          ---
          duration_ms: 5.977535
          type: 'test'
          ...
        1..1
    ok 2 - Array-valued delivery ID
      ---
      duration_ms: 6.212958
      type: 'suite'
      ...
# [webhook] Event received: issues, action: opened, repo: test/repo, delivery: unique-delivery-001
    # Subtest: Duplicate delivery rejection
        # Subtest: accepts first delivery
        ok 1 - accepts first delivery
          ---
          duration_ms: 4.809692
          type: 'test'
          ...
# [webhook] Event received: issues, action: opened, repo: test/repo, delivery: unique-delivery-002
# [webhook] Duplicate delivery rejected: unique-delivery-002
        # Subtest: rejects second delivery with same ID
        ok 2 - rejects second delivery with same ID
          ---
          duration_ms: 5.424507
          type: 'test'
          ...
# [webhook] Event received: issues, action: opened, repo: test/repo, delivery: delivery-aaa
# [webhook] Event received: issues, action: opened, repo: test/repo, delivery: delivery-bbb
        # Subtest: accepts different delivery IDs with same body
        ok 3 - accepts different delivery IDs with same body
          ---
          duration_ms: 4.523294
          type: 'test'
          ...
        1..3
    ok 3 - Duplicate delivery rejection
      ---
      duration_ms: 15.136295
      type: 'suite'
      ...
# [webhook] Event received: issues, action: opened, repo: test/repo, delivery: test-delivery-123
    # Subtest: Redis key storage
        # Subtest: stores delivery ID with correct key prefix and TTL
        ok 1 - stores delivery ID with correct key prefix and TTL
          ---
          duration_ms: 3.558823
          type: 'test'
          ...
# [webhook] Missing x-github-delivery header
        # Subtest: does not store key when delivery ID is missing
        ok 2 - does not store key when delivery ID is missing
          ---
          duration_ms: 4.530468
          type: 'test'
          ...
        1..2
    ok 4 - Redis key storage
      ---
      duration_ms: 8.387992
      type: 'suite'
      ...
# [webhook] Event received: issues, action: opened, repo: test/repo, delivery: delivery-will-fail
# [webhook] Duplicate delivery rejected: delivery-will-fail
    # Subtest: Failure keeps delivery ID reserved
        # Subtest: retains Redis key when processing fails to prevent duplicate side effects
        ok 1 - retains Redis key when processing fails to prevent duplicate side effects
          ---
          duration_ms: 6.013816
          type: 'test'
          ...
# [webhook] Failed to parse JSON body for delivery delivery-bad-parse
        # Subtest: retains Redis key when body parsing fails and returns generic 400
        ok 2 - retains Redis key when body parsing fails and returns generic 400
          ---
          duration_ms: 4.110309
          type: 'test'
          ...
        1..2
    ok 5 - Failure keeps delivery ID reserved
      ---
      duration_ms: 10.373703
      type: 'suite'
      ...
# [webhook] No signature provided
    # Subtest: Signature verification
        # Subtest: rejects request with missing signature
        ok 1 - rejects request with missing signature
          ---
          duration_ms: 4.486986
          type: 'test'
          ...
# [webhook] Signature mismatch
        # Subtest: rejects request with invalid signature
        ok 2 - rejects request with invalid signature
          ---
          duration_ms: 3.245094
          type: 'test'
          ...
# [webhook] Signature mismatch
        # Subtest: rejects request with malformed signature of different length
        ok 3 - rejects request with malformed signature of different length
          ---
          duration_ms: 4.79773
          type: 'test'
          ...
# [webhook] Rejecting multi-valued x-hub-signature-256 header
        # Subtest: rejects request with multi-valued x-hub-signature-256 header
        ok 4 - rejects request with multi-valued x-hub-signature-256 header
          ---
          duration_ms: 2.462494
          type: 'test'
          ...
# [webhook] Signature mismatch
        # Subtest: does not store delivery ID when signature is invalid
        ok 5 - does not store delivery ID when signature is invalid
          ---
          duration_ms: 2.327431
          type: 'test'
          ...
        1..5
    ok 6 - Signature verification
      ---
      duration_ms: 17.655517
      type: 'suite'
      ...
# [webhook] Missing x-github-event header
    # Subtest: Missing x-github-event header
        # Subtest: rejects request with no x-github-event header
        ok 1 - rejects request with no x-github-event header
          ---
          duration_ms: 3.206401
          type: 'test'
          ...
        1..1
    ok 7 - Missing x-github-event header
      ---
      duration_ms: 3.319864
      type: 'suite'
      ...
# [webhook] GH_WEBHOOK_SECRET is not configured — rejecting request. Set GH_WEBHOOK_SECRET in the environment to accept webhooks. This is a security requirement: all webhook deliveries are rejected until a secret is provisioned.
    # Subtest: Webhook secret not configured (fail closed)
        # Subtest: rejects request when webhookSecret is undefined
        ok 1 - rejects request when webhookSecret is undefined
          ---
          duration_ms: 5.917483
          type: 'test'
          ...
        1..1
    ok 8 - Webhook secret not configured (fail closed)
      ---
      duration_ms: 6.118641
      type: 'suite'
      ...
# [webhook] Ignoring unsupported event type: unknown_event_type
    # Subtest: Unsupported event type
        # Subtest: ignores request with unsupported x-github-event value with 200
        ok 1 - ignores request with unsupported x-github-event value with 200
          ---
          duration_ms: 2.437688
          type: 'test'
          ...
        1..1
    ok 9 - Unsupported event type
      ---
      duration_ms: 2.549097
      type: 'suite'
      ...
# [webhook] Event received: issues, action: opened, repo: test/repo, delivery: delivery-for-forwarding
    # Subtest: Preview routing: delivery ID passed to processor
        # Subtest: processor receives the delivery ID for downstream forwarding
        ok 1 - processor receives the delivery ID for downstream forwarding
          ---
          duration_ms: 4.992794
          type: 'test'
          ...
# [webhook] Event received: issues, action: opened, repo: test/repo, delivery: delivery-original
# [webhook] Event received: issues, action: opened, repo: test/repo, delivery: fwd-delivery-original
        # Subtest: forwarded delivery with fwd- prefix is accepted as a distinct delivery
        ok 2 - forwarded delivery with fwd- prefix is accepted as a distinct delivery
          ---
          duration_ms: 4.816265
          type: 'test'
          ...
        1..2
    ok 10 - Preview routing: delivery ID passed to processor
      ---
      duration_ms: 10.874249
      type: 'suite'
      ...
    # Subtest: Redis adapter shape (server.ts integration path)
        # Subtest: adapter reshapes NX/EX options correctly
        ok 1 - adapter reshapes NX/EX options correctly
          ---
          duration_ms: 4.066005
          type: 'test'
          ...
        # Subtest: adapter passes through plain set without options
        ok 2 - adapter passes through plain set without options
          ---
          duration_ms: 1.015196
          type: 'test'
          ...
        # Subtest: adapter returns null when NX key already exists
        ok 3 - adapter returns null when NX key already exists
          ---
          duration_ms: 0.865075
          type: 'test'
          ...
        1..3
    ok 11 - Redis adapter shape (server.ts integration path)
      ---
      duration_ms: 6.170327
      type: 'suite'
      ...
    1..11
ok 1 - Webhook Replay Protection
  ---
  duration_ms: 119.267923
  type: 'suite'
  ...
# [2026-09-29 12:20:04.832 +0000] �[32mINFO�[39m: �[36mSQLite database connection established successfully�[39m
#     filename: "/tmp/propr-test-suite-vUHz0x/146-webhookReplayProtection.test.ts/propr.test.sqlite"
#     environment: "test"
# [2026-09-29 12:20:04.945 +0000] �[32mINFO�[39m: �[36mSQLite database connection closed�[39m
1..1
# tests 22
# suites 12
# pass 22
# fail 0
# cancelled 0
# skipped 0
# todo 0
# duration_ms 2343.545038
[146/150] passed test/webhookReplayProtection.test.ts in 2.5s

[147/150] test/worker.integration.test.ts
TAP version 13
# Subtest: Worker Integration - Concurrent Model Execution
    # Subtest: concurrent jobs with different models create unique worktrees
    ok 1 - concurrent jobs with different models create unique worktrees
      ---
      duration_ms: 11.602239
      type: 'test'
      ...
    # Subtest: delay function prevents exact simultaneous execution
    ok 2 - delay function prevents exact simultaneous execution
      ---
      duration_ms: 280.152031
      type: 'test'
      ...
    # Subtest: worktree cleanup after concurrent execution
    ok 3 - worktree cleanup after concurrent execution
      ---
      duration_ms: 5.461549
      type: 'test'
      ...
    # Subtest: file system isolation between concurrent workers
    ok 4 - file system isolation between concurrent workers
      ---
      duration_ms: 5.294594
      type: 'test'
      ...
    # Subtest: error handling in concurrent execution
    ok 5 - error handling in concurrent execution
      ---
      duration_ms: 82.718331
      type: 'test'
      ...
    1..5
ok 1 - Worker Integration - Concurrent Model Execution
  ---
  duration_ms: 386.692562
  type: 'suite'
  ...
1..1
# tests 5
# suites 1
# pass 5
# fail 0
# cancelled 0
# skipped 0
# todo 0
# duration_ms 676.832549
[147/150] passed test/worker.integration.test.ts in 0.8s

[148/150] test/workerStateManager.test.ts
TAP version 13
# (node:20258) ExperimentalWarning: Module mocking is an experimental feature and might change at any time
# (Use `node --trace-warnings ...` to show where the warning was created)
# Subtest: createTaskState creates state with correct structure
ok 1 - createTaskState creates state with correct structure
  ---
  duration_ms: 2.508922
  type: 'test'
  ...
# Subtest: createTaskState stores state in Redis with TTL
ok 2 - createTaskState stores state in Redis with TTL
  ---
  duration_ms: 0.329288
  type: 'test'
  ...
# Subtest: createTaskState uses default TTL when not specified
ok 3 - createTaskState uses default TTL when not specified
  ---
  duration_ms: 0.276239
  type: 'test'
  ...
# Subtest: createTaskState inserts task into database
ok 4 - createTaskState inserts task into database
  ---
  duration_ms: 0.270678
  type: 'test'
  ...
# Subtest: createTaskState generates correlation ID when not provided
ok 5 - createTaskState generates correlation ID when not provided
  ---
  duration_ms: 0.269577
  type: 'test'
  ...
# Subtest: createTaskState publishes real-time event
ok 6 - createTaskState publishes real-time event
  ---
  duration_ms: 0.269416
  type: 'test'
  ...
# Subtest: createTaskState handles missing optional issueRef fields
ok 7 - createTaskState handles missing optional issueRef fields
  ---
  duration_ms: 0.246352
  type: 'test'
  ...
# Subtest: createTaskState sets correct initial history entry
ok 8 - createTaskState sets correct initial history entry
  ---
  duration_ms: 0.314981
  type: 'test'
  ...
# Subtest: createTaskState handles database error gracefully
ok 9 - createTaskState handles database error gracefully
  ---
  duration_ms: 0.539564
  type: 'test'
  ...
# Subtest: createTaskState generates unique task keys
ok 10 - createTaskState generates unique task keys
  ---
  duration_ms: 0.678524
  type: 'test'
  ...
# Subtest: createTaskState stores valid JSON in Redis
ok 11 - createTaskState stores valid JSON in Redis
  ---
  duration_ms: 0.423034
  type: 'test'
  ...
# Subtest: createTaskState uses correct repository format in database
ok 12 - createTaskState uses correct repository format in database
  ---
  duration_ms: 0.23406
  type: 'test'
  ...
# Subtest: createTaskStateIfAbsent preserves a state that became processing before the atomic create
ok 13 - createTaskStateIfAbsent preserves a state that became processing before the atomic create
  ---
  duration_ms: 0.950916
  type: 'test'
  ...
# Subtest: updateTaskState throws when task not found
ok 14 - updateTaskState throws when task not found
  ---
  duration_ms: 0.677943
  type: 'test'
  ...
# Subtest: updateTaskState transitions state and appends to history
ok 15 - updateTaskState transitions state and appends to history
  ---
  duration_ms: 0.723519
  type: 'test'
  ...
# Subtest: updateTaskState publishes real-time event
ok 16 - updateTaskState publishes real-time event
  ---
  duration_ms: 0.459934
  type: 'test'
  ...
# Subtest: updateTaskState increments attempts on retry
ok 17 - updateTaskState increments attempts on retry
  ---
  duration_ms: 0.393018
  type: 'test'
  ...
# Subtest: updateTaskState does not increment attempts when not a retry
ok 18 - updateTaskState does not increment attempts when not a retry
  ---
  duration_ms: 0.393148
  type: 'test'
  ...
# Subtest: updateTaskState stores error metadata
ok 19 - updateTaskState stores error metadata
  ---
  duration_ms: 0.418085
  type: 'test'
  ...
# Subtest: updateTaskState uses default error category when not specified
ok 20 - updateTaskState uses default error category when not specified
  ---
  duration_ms: 0.412955
  type: 'test'
  ...
# Subtest: updateTaskState stores worktreeInfo metadata
ok 21 - updateTaskState stores worktreeInfo metadata
  ---
  duration_ms: 0.419398
  type: 'test'
  ...
# Subtest: updateTaskState stores claudeResult metadata
ok 22 - updateTaskState stores claudeResult metadata
  ---
  duration_ms: 1.664385
  type: 'test'
  ...
# Subtest: updateTaskState stores prResult metadata
ok 23 - updateTaskState stores prResult metadata
  ---
  duration_ms: 0.498686
  type: 'test'
  ...
# Subtest: updateTaskState persists to Redis with TTL renewal
ok 24 - updateTaskState persists to Redis with TTL renewal
  ---
  duration_ms: 0.427574
  type: 'test'
  ...
# Subtest: updateTaskState inserts history record into database
ok 25 - updateTaskState inserts history record into database
  ---
  duration_ms: 0.36254
  type: 'test'
  ...
# Subtest: updateTaskState uses default reason when not provided
ok 26 - updateTaskState uses default reason when not provided
  ---
  duration_ms: 0.320722
  type: 'test'
  ...
# Subtest: updateTaskState stores historyMetadata in history entry
ok 27 - updateTaskState stores historyMetadata in history entry
  ---
  duration_ms: 0.325041
  type: 'test'
  ...
# Subtest: updateTaskState handles database error gracefully
ok 28 - updateTaskState handles database error gracefully
  ---
  duration_ms: 0.359134
  type: 'test'
  ...
# Subtest: updateTaskState includes commitHash in database metadata
ok 29 - updateTaskState includes commitHash in database metadata
  ---
  duration_ms: 0.414278
  type: 'test'
  ...
# Subtest: markTaskFailed sets state to FAILED
ok 30 - markTaskFailed sets state to FAILED
  ---
  duration_ms: 0.41533
  type: 'test'
  ...
# Subtest: markTaskFailed stores error message in lastError
ok 31 - markTaskFailed stores error message in lastError
  ---
  duration_ms: 0.458912
  type: 'test'
  ...
# Subtest: markTaskFailed defaults errorCategory to unknown when not specified
ok 32 - markTaskFailed defaults errorCategory to unknown when not specified
  ---
  duration_ms: 0.346451
  type: 'test'
  ...
# Subtest: markTaskFailed uses provided errorCategory from metadata
ok 33 - markTaskFailed uses provided errorCategory from metadata
  ---
  duration_ms: 0.350138
  type: 'test'
  ...
# Subtest: markTaskFailed sets appropriate failure reason
ok 34 - markTaskFailed sets appropriate failure reason
  ---
  duration_ms: 0.384081
  type: 'test'
  ...
# Subtest: markTaskFailed appends failure to history
ok 35 - markTaskFailed appends failure to history
  ---
  duration_ms: 0.345689
  type: 'test'
  ...
# Subtest: markTaskFailed preserves additional metadata
ok 36 - markTaskFailed preserves additional metadata
  ---
  duration_ms: 0.40467
  type: 'test'
  ...
# Subtest: markTaskFailed publishes real-time event
ok 37 - markTaskFailed publishes real-time event
  ---
  duration_ms: 0.352051
  type: 'test'
  ...
# Subtest: markTaskFailed persists failure to Redis
ok 38 - markTaskFailed persists failure to Redis
  ---
  duration_ms: 0.364384
  type: 'test'
  ...
# Subtest: markTaskFailed inserts failure record into database
ok 39 - markTaskFailed inserts failure record into database
  ---
  duration_ms: 0.460945
  type: 'test'
  ...
# Subtest: markTaskFailed throws when task not found
ok 40 - markTaskFailed throws when task not found
  ---
  duration_ms: 0.25569
  type: 'test'
  ...
# Subtest: markTaskFailed handles different error categories
ok 41 - markTaskFailed handles different error categories
  ---
  duration_ms: 1.107079
  type: 'test'
  ...
# Subtest: markTaskFailed updates timestamp in lastError
ok 42 - markTaskFailed updates timestamp in lastError
  ---
  duration_ms: 0.388079
  type: 'test'
  ...
# Subtest: getResumableTask returns null when task not found
ok 43 - getResumableTask returns null when task not found
  ---
  duration_ms: 0.247304
  type: 'test'
  ...
# Subtest: getResumableTask returns null for COMPLETED state
ok 44 - getResumableTask returns null for COMPLETED state
  ---
  duration_ms: 0.265939
  type: 'test'
  ...
# Subtest: getResumableTask returns null for PENDING state
ok 45 - getResumableTask returns null for PENDING state
  ---
  duration_ms: 0.215916
  type: 'test'
  ...
# Subtest: getResumableTask returns null for FAILED state
ok 46 - getResumableTask returns null for FAILED state
  ---
  duration_ms: 0.267102
  type: 'test'
  ...
# Subtest: getResumableTask returns null for CANCELLED state
ok 47 - getResumableTask returns null for CANCELLED state
  ---
  duration_ms: 0.214102
  type: 'test'
  ...
# Subtest: getResumableTask returns task in PROCESSING state for recovery
ok 48 - getResumableTask returns task in PROCESSING state for recovery
  ---
  duration_ms: 0.234671
  type: 'test'
  ...
# Subtest: getResumableTask returns task in CLAUDE_EXECUTION state
ok 49 - getResumableTask returns task in CLAUDE_EXECUTION state
  ---
  duration_ms: 0.262483
  type: 'test'
  ...
# Subtest: getResumableTask returns task in POST_PROCESSING state
ok 50 - getResumableTask returns task in POST_PROCESSING state
  ---
  duration_ms: 0.308019
  type: 'test'
  ...
# Subtest: getResumableTask marks task as stale if updated more than 30 minutes ago
ok 51 - getResumableTask marks task as stale if updated more than 30 minutes ago
  ---
  duration_ms: 0.269586
  type: 'test'
  ...
# Subtest: getResumableTask returns isStale=false for recently updated tasks
ok 52 - getResumableTask returns isStale=false for recently updated tasks
  ---
  duration_ms: 0.247505
  type: 'test'
  ...
# Subtest: getResumableTask logs warning for stale tasks
ok 53 - getResumableTask logs warning for stale tasks
  ---
  duration_ms: 0.352312
  type: 'test'
  ...
# Subtest: getResumableTask returns correct staleDuration for stale tasks
ok 54 - getResumableTask returns correct staleDuration for stale tasks
  ---
  duration_ms: 0.445517
  type: 'test'
  ...
# Subtest: getResumableTask does not return staleDuration for non-stale tasks
ok 55 - getResumableTask does not return staleDuration for non-stale tasks
  ---
  duration_ms: 0.37258
  type: 'test'
  ...
# Subtest: getResumableTask preserves all task state data
ok 56 - getResumableTask preserves all task state data
  ---
  duration_ms: 0.419819
  type: 'test'
  ...
# Subtest: getResumableTask handles task at exactly 30 minute threshold
ok 57 - getResumableTask handles task at exactly 30 minute threshold
  ---
  duration_ms: 0.329078
  type: 'test'
  ...
# Subtest: getResumableTask does not log warning for non-stale tasks
ok 58 - getResumableTask does not log warning for non-stale tasks
  ---
  duration_ms: 0.352091
  type: 'test'
  ...
# Subtest: cleanupOldTasks removes tasks older than maxAge
ok 59 - cleanupOldTasks removes tasks older than maxAge
  ---
  duration_ms: 0.567025
  type: 'test'
  ...
# Subtest: cleanupOldTasks skips tasks within maxAge
ok 60 - cleanupOldTasks skips tasks within maxAge
  ---
  duration_ms: 0.40453
  type: 'test'
  ...
# Subtest: cleanupOldTasks skips PROCESSING state tasks even if old
ok 61 - cleanupOldTasks skips PROCESSING state tasks even if old
  ---
  duration_ms: 0.326664
  type: 'test'
  ...
# Subtest: cleanupOldTasks skips PENDING state tasks even if old
ok 62 - cleanupOldTasks skips PENDING state tasks even if old
  ---
  duration_ms: 0.290315
  type: 'test'
  ...
# Subtest: cleanupOldTasks skips CLAUDE_EXECUTION state tasks even if old
ok 63 - cleanupOldTasks skips CLAUDE_EXECUTION state tasks even if old
  ---
  duration_ms: 0.259267
  type: 'test'
  ...
# Subtest: cleanupOldTasks skips POST_PROCESSING state tasks even if old
ok 64 - cleanupOldTasks skips POST_PROCESSING state tasks even if old
  ---
  duration_ms: 0.296206
  type: 'test'
  ...
# Subtest: cleanupOldTasks removes old FAILED tasks
ok 65 - cleanupOldTasks removes old FAILED tasks
  ---
  duration_ms: 0.337694
  type: 'test'
  ...
# Subtest: cleanupOldTasks removes old CANCELLED tasks
ok 66 - cleanupOldTasks removes old CANCELLED tasks
  ---
  duration_ms: 0.274325
  type: 'test'
  ...
# Subtest: cleanupOldTasks handles corrupted JSON gracefully
ok 67 - cleanupOldTasks handles corrupted JSON gracefully
  ---
  duration_ms: 0.255489
  type: 'test'
  ...
# Subtest: cleanupOldTasks uses custom maxAge parameter
ok 68 - cleanupOldTasks uses custom maxAge parameter
  ---
  duration_ms: 0.266551
  type: 'test'
  ...
# Subtest: cleanupOldTasks skips task when maxAge is longer than task age
ok 69 - cleanupOldTasks skips task when maxAge is longer than task age
  ---
  duration_ms: 0.273463
  type: 'test'
  ...
# Subtest: cleanupOldTasks handles multiple tasks with mixed states and ages
ok 70 - cleanupOldTasks handles multiple tasks with mixed states and ages
  ---
  duration_ms: 0.372429
  type: 'test'
  ...
# Subtest: cleanupOldTasks returns 0 when no keys exist
ok 71 - cleanupOldTasks returns 0 when no keys exist
  ---
  duration_ms: 0.184887
  type: 'test'
  ...
# Subtest: cleanupOldTasks skips keys with null values
ok 72 - cleanupOldTasks skips keys with null values
  ---
  duration_ms: 0.220744
  type: 'test'
  ...
# Subtest: cleanupOldTasks logs debug message for each cleaned task
ok 73 - cleanupOldTasks logs debug message for each cleaned task
  ---
  duration_ms: 0.292449
  type: 'test'
  ...
# Subtest: cleanupOldTasks logs info message with summary
ok 74 - cleanupOldTasks logs info message with summary
  ---
  duration_ms: 0.289354
  type: 'test'
  ...
# Subtest: cleanupOldTasks uses key prefix pattern for searching
ok 75 - cleanupOldTasks uses key prefix pattern for searching
  ---
  duration_ms: 0.179267
  type: 'test'
  ...
# Subtest: cleanupOldTasks handles Redis errors during delete gracefully
ok 76 - cleanupOldTasks handles Redis errors during delete gracefully
  ---
  duration_ms: 0.345318
  type: 'test'
  ...
# Subtest: cleanupOldTasks determines age based on updatedAt not createdAt
ok 77 - cleanupOldTasks determines age based on updatedAt not createdAt
  ---
  duration_ms: 0.252985
  type: 'test'
  ...
# Subtest: cleanupOldTasks handles task at exactly maxAge boundary
ok 78 - cleanupOldTasks handles task at exactly maxAge boundary
  ---
  duration_ms: 0.244338
  type: 'test'
  ...
# Subtest: updateTaskStateIfCurrent atomically updates a matching task snapshot
ok 79 - updateTaskStateIfCurrent atomically updates a matching task snapshot
  ---
  duration_ms: 0.61758
  type: 'test'
  ...
# Subtest: updateTaskStateIfCurrent does not publish a lost compare-and-set race
ok 80 - updateTaskStateIfCurrent does not publish a lost compare-and-set race
  ---
  duration_ms: 0.291928
  type: 'test'
  ...
# Subtest: stale metadata updates retry without resurrecting a finalized task
ok 81 - stale metadata updates retry without resurrecting a finalized task
  ---
  duration_ms: 38.694388
  type: 'test'
  ...
# Subtest: ordinary state writers cannot move a terminal task back to processing
ok 82 - ordinary state writers cannot move a terminal task back to processing
  ---
  duration_ms: 0.487325
  type: 'test'
  ...
# Subtest: a retry writer that loses to cancellation cannot resurrect the task
ok 83 - a retry writer that loses to cancellation cannot resurrect the task
  ---
  duration_ms: 6.077984
  type: 'test'
  ...
1..83
# tests 83
# suites 0
# pass 83
# fail 0
# cancelled 0
# skipped 0
# todo 0
# duration_ms 449.541428
[148/150] passed test/workerStateManager.test.ts in 0.6s

[149/150] test/workEvidenceMarker.test.ts
TAP version 13
# Subtest: work evidence marker
    # Subtest: builds stable, deduplicated evidence independent of visible comment copy
    ok 1 - builds stable, deduplicated evidence independent of visible comment copy
      ---
      duration_ms: 0.768013
      type: 'test'
      ...
    # Subtest: drops synthetic and invalid comment IDs
    ok 2 - drops synthetic and invalid comment IDs
      ---
      duration_ms: 0.125085
      type: 'test'
      ...
    1..2
ok 1 - work evidence marker
  ---
  duration_ms: 1.776796
  type: 'suite'
  ...
1..1
# tests 2
# suites 1
# pass 2
# fail 0
# cancelled 0
# skipped 0
# todo 0
# duration_ms 409.296602
[149/150] passed test/workEvidenceMarker.test.ts in 0.5s

[150/150] propr-ui#2/4 (workspace test script)

> propr-ui@0.0.1 test
> vitest run --shard=2/4


�[1m�[30m�[46m RUN �[49m�[39m�[22m �[36mv5.0.0 �[39m�[90m/home/runner/work/propr/propr/propr-ui�[39m

�[90mstdout�[2m | src/contexts/SocketProvider.test.tsx�[2m > �[22m�[2mSocketProvider�[2m > �[22m�[2mcreates one force-new scoped Manager on null-to-A activation
�[22m�[39m[SocketContext] Cleaning up socket connection

�[90mstdout�[2m | src/contexts/SocketProvider.test.tsx�[2m > �[22m�[2mSocketProvider�[2m > �[22m�[2mfully detaches A before creating a distinct Manager for scope rotation
�[22m�[39m[SocketContext] Cleaning up socket connection

�[90mstdout�[2m | src/contexts/SocketProvider.test.tsx�[2m > �[22m�[2mSocketProvider�[2m > �[22m�[2mfully detaches A before creating a distinct Manager for scope rotation
�[22m�[39m[SocketContext] Cleaning up socket connection

�[90mstdout�[2m | src/contexts/SocketProvider.test.tsx�[2m > �[22m�[2mSocketProvider�[2m > �[22m�[2mfully detaches A before creating a distinct Manager for same-origin A-to-B
�[22m�[39m[SocketContext] Cleaning up socket connection

�[90mstdout�[2m | src/contexts/SocketProvider.test.tsx�[2m > �[22m�[2mSocketProvider�[2m > �[22m�[2mfully detaches A before creating a distinct Manager for same-origin A-to-B
�[22m�[39m[SocketContext] Cleaning up socket connection

�[90mstdout�[2m | src/contexts/SocketProvider.test.tsx�[2m > �[22m�[2mSocketProvider�[2m > �[22m�[2mreports a replacement Manager as disconnected until its own connect event
�[22m�[39m[SocketContext] Connected to WebSocket server
[SocketContext] Cleaning up socket connection
[SocketContext] Connected to WebSocket server

�[90mstderr�[2m | src/contexts/SocketProvider.test.tsx�[2m > �[22m�[2mSocketProvider�[2m > �[22m�[2mreports a replacement Manager as disconnected until its own connect event
�[22m�[39m[SocketContext] Connection error: not connected

�[90mstdout�[2m | src/contexts/SocketProvider.test.tsx�[2m > �[22m�[2mSocketProvider�[2m > �[22m�[2mreports a replacement Manager as disconnected until its own connect event
�[22m�[39m[SocketContext] Cleaning up socket connection

�[90mstdout�[2m | src/contexts/SocketProvider.test.tsx�[2m > �[22m�[2mSocketProvider�[2m > �[22m�[2mrotates the Manager when the effective API origin changes
�[22m�[39m[SocketContext] Cleaning up socket connection

�[90mstdout�[2m | src/contexts/SocketProvider.test.tsx�[2m > �[22m�[2mSocketProvider�[2m > �[22m�[2mrotates the Manager when the effective API origin changes
�[22m�[39m[SocketContext] Cleaning up socket connection

�[90mstdout�[2m | src/contexts/SocketProvider.test.tsx�[2m > �[22m�[2mSocketProvider�[2m > �[22m�[2mdisconnects on deactivate and creates no replacement
�[22m�[39m[SocketContext] Cleaning up socket connection

�[90mstdout�[2m | src/contexts/SocketProvider.test.tsx�[2m > �[22m�[2mSocketProvider�[2m > �[22m�[2mkeeps the hosted browser cookie socket without a desktop marker
�[22m�[39m[SocketContext] Cleaning up socket connection

�[90mstdout�[2m | src/contexts/SocketProvider.test.tsx�[2m > �[22m�[2mSocketProvider�[2m > �[22m�[2mclassifies authentication errors against the immutable activation scope
�[22m�[39m[SocketContext] Cleaning up socket connection

�[90mstdout�[2m | src/contexts/SocketProvider.test.tsx�[2m > �[22m�[2mSocketProvider�[2m > �[22m�[2mreconnects the current Manager when authorization changes without invalidating its token
�[22m�[39m[SocketContext] Cleaning up socket connection

�[90mstdout�[2m | src/contexts/SocketProvider.test.tsx�[2m > �[22m�[2mSocketProvider�[2m > �[22m�[2mnever reconnects a stale same-origin Manager after deferred authorization work resolves
�[22m�[39m[SocketContext] Cleaning up socket connection

�[90mstdout�[2m | src/contexts/SocketProvider.test.tsx�[2m > �[22m�[2mSocketProvider�[2m > �[22m�[2mnever reconnects a stale same-origin Manager after deferred authorization work resolves
�[22m�[39m[SocketContext] Cleaning up socket connection

�[90mstdout�[2m | src/contexts/SocketProvider.test.tsx�[2m > �[22m�[2mSocketProvider�[2m > �[22m�[2mdrops application events delivered by an old desktop scope
�[22m�[39m[SocketContext] Cleaning up socket connection
[SocketContext] Received task update: { eventType: �[32m'task:update'�[39m }

�[90mstdout�[2m | src/contexts/SocketProvider.test.tsx�[2m > �[22m�[2mSocketProvider�[2m > �[22m�[2mdrops application events delivered by an old desktop scope
�[22m�[39m[SocketContext] Cleaning up socket connection

�[90mstdout�[2m | src/contexts/SocketProvider.test.tsx�[2m > �[22m�[2mSocketProvider�[2m > �[22m�[2mdelivers live events without logging their potentially large payload
�[22m�[39m[SocketContext] Cleaning up socket connection

�[90mstdout�[2m | src/contexts/SocketProvider.test.tsx�[2m > �[22m�[2mSocketProvider�[2m > �[22m�[2mreference-counts the activity room and rejoins it after a reconnect
�[22m�[39m[SocketContext] Connected to WebSocket server
[SocketContext] Disconnected from WebSocket server: transport close
[SocketContext] Connected to WebSocket server
[SocketContext] Unsubscribed from activity

�[90mstdout�[2m | src/contexts/SocketProvider.test.tsx�[2m > �[22m�[2mSocketProvider�[2m > �[22m�[2mreference-counts the activity room and rejoins it after a reconnect
�[22m�[39m[SocketContext] Cleaning up socket connection

�[90mstdout�[2m | src/contexts/SocketProvider.test.tsx�[2m > �[22m�[2mSocketProvider�[2m > �[22m�[2mnegotiates direct snapshots without recreating the connection
�[22m�[39m[SocketContext] Connected to WebSocket server
[SocketContext] Disconnected from WebSocket server: transport close

�[90mstdout�[2m | src/contexts/SocketProvider.test.tsx�[2m > �[22m�[2mSocketProvider�[2m > �[22m�[2mnegotiates direct snapshots without recreating the connection
�[22m�[39m[SocketContext] Cleaning up socket connection

�[90mstdout�[2m | src/contexts/SocketProvider.test.tsx�[2m > �[22m�[2mSocketProvider�[2m > �[22m�[2mrefreshes browser authorization before reconnecting after a permission change
�[22m�[39m[SocketContext] Cleaning up socket connection

�[90mstdout�[2m | src/contexts/SocketProvider.test.tsx�[2m > �[22m�[2mSocketProvider�[2m > �[22m�[2mdelivers activity, goal, notification and usage events without logging their payloads
�[22m�[39m[SocketContext] Cleaning up socket connection

�[90mstdout�[2m | src/contexts/SocketProvider.test.tsx�[2m > �[22m�[2mSocketProvider�[2m > �[22m�[2mdrops activity events delivered by an old desktop scope
�[22m�[39m[SocketContext] Cleaning up socket connection

�[90mstdout�[2m | src/contexts/SocketProvider.test.tsx�[2m > �[22m�[2mSocketProvider�[2m > �[22m�[2mdrops activity events delivered by an old desktop scope
�[22m�[39m[SocketContext] Cleaning up socket connection

�[90mstdout�[2m | src/contexts/SocketProvider.test.tsx�[2m > �[22m�[2mSocketProvider�[2m > �[22m�[2mfully detaches listeners and disconnects on unmount
�[22m�[39m[SocketContext] Cleaning up socket connection

 �[32m✓�[39m src/contexts/SocketProvider.test.tsx �[2m(�[22m�[2m19 tests�[22m�[2m)�[22m�[32m 176�[2mms�[22m�[39m
�[90mstdout�[2m | src/components/TaskDetails/useTaskData.followup.test.ts�[2m > �[22m�[2mfull history follow-up regressions�[2m > �[22m�[2mrefetches on task completion with initial HTTP pending=false
�[22m�[39m[useTaskData] Received task update via WebSocket: { taskId: �[32m'task'�[39m, state: �[32m'COMPLETED'�[39m }

�[90mstdout�[2m | src/components/TaskDetails/useTaskData.followup.test.ts�[2m > �[22m�[2mfull history follow-up regressions�[2m > �[22m�[2mrefetches on task completion with initial HTTP pending=true
�[22m�[39m[useTaskData] Received task update via WebSocket: { taskId: �[32m'task'�[39m, state: �[32m'COMPLETED'�[39m }

�[90mstdout�[2m | src/components/TaskDetails/useTaskData.followup.test.ts�[2m > �[22m�[2mfull history follow-up regressions�[2m > �[22m�[2mtask page replays a large increment once during HTTP/completion
�[22m�[39m[useTaskData] Received task update via WebSocket: { taskId: �[32m'task'�[39m, state: �[32m'COMPLETED'�[39m }

�[90mstdout�[2m | src/components/TaskDetails/useTaskData.followup.test.ts�[2m > �[22m�[2mfull history follow-up regressions�[2m > �[22m�[2mtask page orders growing messages: HTTP past socket
�[22m�[39m[useTaskData] Received task update via WebSocket: { taskId: �[32m'task'�[39m, state: �[32m'COMPLETED'�[39m }

�[90mstdout�[2m | src/components/TaskDetails/useTaskData.followup.test.ts�[2m > �[22m�[2mfull history follow-up regressions�[2m > �[22m�[2mtask page orders growing messages: socket past HTTP
�[22m�[39m[useTaskData] Received task update via WebSocket: { taskId: �[32m'task'�[39m, state: �[32m'COMPLETED'�[39m }

�[90mstdout�[2m | src/components/TaskDetails/useTaskData.followup.test.ts�[2m > �[22m�[2mfull history follow-up regressions�[2m > �[22m�[2mbuffered updates of an execution a newer read replaced�[2m > �[22m�[2mtask page discards a buffered old increment and its late deliveries after a new-execution read
�[22m�[39m[useTaskData] Received task update via WebSocket: { taskId: �[32m'task'�[39m, state: �[32m'COMPLETED'�[39m }

�[90mstdout�[2m | src/components/TaskDetails/useTaskData.followup.test.ts�[2m > �[22m�[2mfull history follow-up regressions�[2m > �[22m�[2mbuffered updates of an execution a newer read replaced�[2m > �[22m�[2mtask page discards a buffered old full state and its late deliveries after a new-execution read
�[22m�[39m[useTaskData] Received task update via WebSocket: { taskId: �[32m'task'�[39m, state: �[32m'COMPLETED'�[39m }

�[90mstdout�[2m | src/components/TaskDetails/useTaskData.followup.test.ts�[2m > �[22m�[2mfull history follow-up regressions�[2m > �[22m�[2mbuffered updates of an execution a newer read replaced�[2m > �[22m�[2mtask page keeps the newer HTTP execution over an intermediate execution received during the read
�[22m�[39m[useTaskData] Received task update via WebSocket: { taskId: �[32m'task'�[39m, state: �[32m'COMPLETED'�[39m }

 �[32m✓�[39m src/components/TaskDetails/useTaskData.followup.test.ts �[2m(�[22m�[2m45 tests�[22m�[2m)�[22m�[33m 910�[2mms�[22m�[39m
   �[32m✓�[39m full history follow-up regressions �[2m(45)�[22m
     �[33m�[2m✓�[22m�[39m merges large full histories, including unshared prefixes and suffixes, without positional arguments�[33m 648�[2mms�[22m�[39m
 �[32m✓�[39m src/serviceWorker.test.ts �[2m(�[22m�[2m24 tests�[22m�[2m)�[22m�[32m 63�[2mms�[22m�[39m
 �[32m✓�[39m src/hooks/useBrowserPush.test.tsx �[2m(�[22m�[2m20 tests�[22m�[2m)�[22m�[33m 502�[2mms�[22m�[39m
�[90mstderr�[2m | src/desktop/DesktopExperience.transport.test.tsx�[2m > �[22m�[2mDesktopExperience transport and fencing�[2m > �[22m�[2mignores a delayed access-invalid event from A after B has connected
�[22m�[39mAn update to DesktopExperience inside a test was not wrapped in act(...).

When testing, code that causes React state updates should be wrapped into act(...):

act(() => {
  /* fire events that update state */
});
/* assert on the output */

This ensures that you're testing the behavior the user would see in the browser. Learn more at https://react.dev/link/wrap-tests-with-act

 �[32m✓�[39m src/desktop/DesktopExperience.transport.test.tsx �[2m(�[22m�[2m11 tests�[22m�[2m)�[22m�[33m 752�[2mms�[22m�[39m
 �[32m✓�[39m src/components/RepositorySelector.test.tsx �[2m(�[22m�[2m24 tests�[22m�[2m)�[22m�[33m 1067�[2mms�[22m�[39m
 �[32m✓�[39m src/api/demoMode.test.ts �[2m(�[22m�[2m21 tests�[22m�[2m)�[22m�[32m 49�[2mms�[22m�[39m
�[90mstdout�[2m | src/desktop/account-switching.integration.test.tsx�[2m > �[22m�[2mpairs two users through the production bridge, fences late A traffic, logs B out offline and preserves identity after reload
�[22m�[39m[SocketContext] Connected to WebSocket server

�[90mstdout�[2m | src/desktop/account-switching.integration.test.tsx�[2m > �[22m�[2mpairs two users through the production bridge, fences late A traffic, logs B out offline and preserves identity after reload
�[22m�[39m[SocketContext] Received task update: { id: �[32m'101'�[39m, username: �[32m'alice'�[39m, avatarUrl: �[1mnull�[22m }

�[90mstdout�[2m | src/desktop/account-switching.integration.test.tsx�[2m > �[22m�[2mpairs two users through the production bridge, fences late A traffic, logs B out offline and preserves identity after reload
�[22m�[39m[SocketContext] Cleaning up socket connection

�[90mstdout�[2m | src/desktop/account-switching.integration.test.tsx�[2m > �[22m�[2mpairs two users through the production bridge, fences late A traffic, logs B out offline and preserves identity after reload
�[22m�[39m[SocketContext] Connected to WebSocket server

�[90mstderr�[2m | src/desktop/account-switching.integration.test.tsx�[2m > �[22m�[2mpairs two users through the production bridge, fences late A traffic, logs B out offline and preserves identity after reload
�[22m�[39mAn update to SocketProvider inside a test was not wrapped in act(...).

When testing, code that causes React state updates should be wrapped into act(...):

act(() => {
  /* fire events that update state */
});
/* assert on the output */

This ensures that you're testing the behavior the user would see in the browser. Learn more at https://react.dev/link/wrap-tests-with-act

�[90mstdout�[2m | src/desktop/account-switching.integration.test.tsx�[2m > �[22m�[2mpairs two users through the production bridge, fences late A traffic, logs B out offline and preserves identity after reload
�[22m�[39m[SocketContext] Received task update: { id: �[32m'202'�[39m, username: �[32m'bob'�[39m, avatarUrl: �[1mnull�[22m }

�[90mstdout�[2m | src/desktop/account-switching.integration.test.tsx�[2m > �[22m�[2mpairs two users through the production bridge, fences late A traffic, logs B out offline and preserves identity after reload
�[22m�[39m[SocketContext] Cleaning up socket connection

 �[32m✓�[39m src/desktop/account-switching.integration.test.tsx �[2m(�[22m�[2m1 test�[22m�[2m)�[22m�[33m 1000�[2mms�[22m�[39m
   �[33m�[2m✓�[22m�[39m pairs two users through the production bridge, fences late A traffic, logs B out offline and preserves identity after reload�[33m 998�[2mms�[22m�[39m
 �[32m✓�[39m src/pages/NewTaskPage.test.tsx �[2m(�[22m�[2m10 tests�[22m�[2m)�[22m�[33m 1325�[2mms�[22m�[39m
   �[32m✓�[39m New Task issue launcher �[2m(10)�[22m
     �[33m�[2m✓�[22m�[39m reopens unresolved work after starting another request and reloading, preserving its key and files�[33m 335�[2mms�[22m�[39m
 �[32m✓�[39m src/hooks/useGenerationPolling.test.tsx �[2m(�[22m�[2m10 tests�[22m�[2m)�[22m�[32m 73�[2mms�[22m�[39m
 �[32m✓�[39m src/desktop/DesktopExperience.deep-link-presentation.test.tsx �[2m(�[22m�[2m5 tests�[22m�[2m)�[22m�[33m 939�[2mms�[22m�[39m
   �[33m�[2m✓�[22m�[39m preserves the warm Open account after tunnel presentation with cold delivery after profile loading�[33m 467�[2mms�[22m�[39m
 �[32m✓�[39m src/components/PreviewLightbox.test.tsx �[2m(�[22m�[2m13 tests�[22m�[2m)�[22m�[33m 651�[2mms�[22m�[39m
 �[32m✓�[39m src/desktop/DesktopExperience.recovery.test.tsx �[2m(�[22m�[2m16 tests�[22m�[2m)�[22m�[33m 828�[2mms�[22m�[39m
 �[32m✓�[39m src/desktop/DesktopExperience.discovery.test.tsx �[2m(�[22m�[2m4 tests�[22m�[2m)�[22m�[33m 628�[2mms�[22m�[39m
   �[32m✓�[39m DesktopExperience production Connect discovery pipeline �[2m(4)�[22m
     �[33m�[2m✓�[22m�[39m prefills through main discovery, IPC, preload, and the MacIntel Electron adapter before explicit confirmation�[33m 347�[2mms�[22m�[39m
 �[32m✓�[39m src/desktop/DesktopExperience.authentication.test.tsx �[2m(�[22m�[2m8 tests�[22m�[2m)�[22m�[33m 730�[2mms�[22m�[39m
 �[32m✓�[39m src/pages/SettingsPage/SettingsNavigation.test.tsx �[2m(�[22m�[2m7 tests�[22m�[2m)�[22m�[33m 642�[2mms�[22m�[39m
   �[32m✓�[39m SettingsNavigation �[2m(7)�[22m
     �[33m�[2m✓�[22m�[39m organizes settings into category tabs�[33m 343�[2mms�[22m�[39m
 �[32m✓�[39m src/pages/SettingsPage/AIModelSelectionSection.test.tsx �[2m(�[22m�[2m6 tests�[22m�[2m)�[22m�[33m 482�[2mms�[22m�[39m
 �[32m✓�[39m src/components/Mcp/McpConnectedAppRow.test.tsx �[2m(�[22m�[2m13 tests�[22m�[2m)�[22m�[33m 609�[2mms�[22m�[39m
 �[32m✓�[39m src/api/voiceApi.test.ts �[2m(�[22m�[2m11 tests�[22m�[2m)�[22m�[32m 120�[2mms�[22m�[39m
 �[32m✓�[39m src/components/TaskDetails/reviewPromptOverview.test.ts �[2m(�[22m�[2m18 tests�[22m�[2m)�[22m�[32m 24�[2mms�[22m�[39m
 �[32m✓�[39m src/pages/LoginPage.oauthUrl.test.tsx �[2m(�[22m�[2m16 tests�[22m�[2m)�[22m�[32m 17�[2mms�[22m�[39m
 �[32m✓�[39m src/components/GlobalHeaderComponents.status.test.tsx �[2m(�[22m�[2m7 tests�[22m�[2m)�[22m�[33m 346�[2mms�[22m�[39m
 �[32m✓�[39m src/hooks/useHeaderStats.scope.test.tsx �[2m(�[22m�[2m2 tests�[22m�[2m)�[22m�[33m 392�[2mms�[22m�[39m
   �[32m✓�[39m useHeaderStats request scope reconciliation �[2m(2)�[22m
     �[33m�[2m✓�[22m�[39m discards an in-flight live read across reconnect and completes the full recovery�[33m 333�[2mms�[22m�[39m
 �[32m✓�[39m src/components/Dashboard/UsageTipsSection.test.tsx �[2m(�[22m�[2m9 tests�[22m�[2m)�[22m�[33m 1411�[2mms�[22m�[39m
   �[32m✓�[39m usage tips �[2m(9)�[22m
     �[33m�[2m✓�[22m�[39m removes immediately, reuses event ID on bounded retries, and fetches replacements�[33m 351�[2mms�[22m�[39m
     �[33m�[2m✓�[22m�[39m restores a failed dismissal with a retry control using the original event�[33m 832�[2mms�[22m�[39m
 �[32m✓�[39m src/pages/LoginPage.hostedOAuthLifecycle.test.tsx �[2m(�[22m�[2m2 tests�[22m�[2m)�[22m�[32m 277�[2mms�[22m�[39m
 �[32m✓�[39m src/desktop/windowChromeStyles.test.ts �[2m(�[22m�[2m6 tests�[22m�[2m)�[22m�[32m 11�[2mms�[22m�[39m
 �[32m✓�[39m src/serviceWorkerRegistration.test.ts �[2m(�[22m�[2m11 tests�[22m�[2m)�[22m�[32m 16�[2mms�[22m�[39m
 �[32m✓�[39m src/api/notificationApi.test.ts �[2m(�[22m�[2m2 tests�[22m�[2m)�[22m�[32m 15�[2mms�[22m�[39m
 �[32m✓�[39m src/components/TaskPlanner/SetupWizardHeaders.test.tsx �[2m(�[22m�[2m4 tests�[22m�[2m)�[22m�[32m 267�[2mms�[22m�[39m
 �[32m✓�[39m src/pages/SettingsPage/SettingsLayout.test.tsx �[2m(�[22m�[2m4 tests�[22m�[2m)�[22m�[32m 253�[2mms�[22m�[39m
 �[32m✓�[39m src/pages/LoginPage.desktopAuthentication.test.tsx �[2m(�[22m�[2m1 test�[22m�[2m)�[22m�[32m 227�[2mms�[22m�[39m
 �[32m✓�[39m src/pages/SettingsPage/ManagedPreviewStorageSection.test.tsx �[2m(�[22m�[2m4 tests�[22m�[2m)�[22m�[32m 231�[2mms�[22m�[39m
 �[32m✓�[39m src/api/goals.test.ts �[2m(�[22m�[2m3 tests�[22m�[2m)�[22m�[32m 20�[2mms�[22m�[39m
 �[32m✓�[39m src/components/AIActivityMonitor.test.tsx �[2m(�[22m�[2m5 tests�[22m�[2m)�[22m�[33m 443�[2mms�[22m�[39m
�[90mstderr�[2m | src/components/GlobalSearch.loading.test.tsx�[2m > �[22m�[2mGlobalSearch loading states�[2m > �[22m�[2mrenders a search failure as an error rather than an empty result
�[22m�[39mSearch failed: Error: Search unavailable
    at �[90m/home/runner/work/propr/propr/propr-ui/�[39msrc/components/GlobalSearch.loading.test.tsx:49:44
    at file:///home/runner/work/propr/propr/node_modules/�[4mvitest�[24m/dist/chunks/run.CQOUYP-x.js:1628:35
    at file:///home/runner/work/propr/propr/node_modules/�[4mvitest�[24m/dist/chunks/run.CQOUYP-x.js:2783:26
    at file:///home/runner/work/propr/propr/node_modules/�[4mvitest�[24m/dist/chunks/run.CQOUYP-x.js:3319:20
    at new Promise (<anonymous>)
    at runWithCancel (file:///home/runner/work/propr/propr/node_modules/�[4mvitest�[24m/dist/chunks/run.CQOUYP-x.js:3314:10)
    at file:///home/runner/work/propr/propr/node_modules/�[4mvitest�[24m/dist/chunks/run.CQOUYP-x.js:3299:20
    at new Promise (<anonymous>)
    at runWithTimeout (file:///home/runner/work/propr/propr/node_modules/�[4mvitest�[24m/dist/chunks/run.CQOUYP-x.js:3257:10)
    at file:///home/runner/work/propr/propr/node_modules/�[4mvitest�[24m/dist/chunks/run.CQOUYP-x.js:3876:64

 �[32m✓�[39m src/components/GlobalSearch.loading.test.tsx �[2m(�[22m�[2m2 tests�[22m�[2m)�[22m�[33m 836�[2mms�[22m�[39m
   �[32m✓�[39m GlobalSearch loading states �[2m(2)�[22m
     �[33m�[2m✓�[22m�[39m waits for successful task and plan reads before showing no results�[33m 497�[2mms�[22m�[39m
     �[33m�[2m✓�[22m�[39m renders a search failure as an error rather than an empty result�[33m 336�[2mms�[22m�[39m
 �[32m✓�[39m src/components/Dashboard/sectionState.visibility.test.tsx �[2m(�[22m�[2m2 tests�[22m�[2m)�[22m�[32m 32�[2mms�[22m�[39m
 �[32m✓�[39m src/desktop/preloadWindowFrame.test.ts �[2m(�[22m�[2m2 tests�[22m�[2m)�[22m�[32m 12�[2mms�[22m�[39m
 �[32m✓�[39m src/desktop/electronAdapters.localSetup.test.ts �[2m(�[22m�[2m2 tests�[22m�[2m)�[22m�[32m 7�[2mms�[22m�[39m
 �[32m✓�[39m src/App.invalidConfiguration.test.tsx �[2m(�[22m�[2m4 tests�[22m�[2m)�[22m�[33m 1249�[2mms�[22m�[39m
   �[32m✓�[39m invalid eager API configuration �[2m(4)�[22m
     �[33m�[2m✓�[22m�[39m renders a bounded safe connection screen without leaking configured input�[33m 1100�[2mms�[22m�[39m
 �[32m✓�[39m src/components/TaskDetails/apiDataGuards.test.ts �[2m(�[22m�[2m2 tests�[22m�[2m)�[22m�[32m 8�[2mms�[22m�[39m
 �[32m✓�[39m src/api/taskPathEncoding.test.ts �[2m(�[22m�[2m1 test�[22m�[2m)�[22m�[32m 12�[2mms�[22m�[39m
 �[32m✓�[39m src/hooks/headerStatsRequestCoordinator.test.ts �[2m(�[22m�[2m2 tests�[22m�[2m)�[22m�[32m 9�[2mms�[22m�[39m
 �[32m✓�[39m src/components/TaskList/ReferenceChips.test.tsx �[2m(�[22m�[2m3 tests�[22m�[2m)�[22m�[32m 54�[2mms�[22m�[39m
 �[32m✓�[39m src/hooks/useDesktopLayout.test.tsx �[2m(�[22m�[2m1 test�[22m�[2m)�[22m�[32m 30�[2mms�[22m�[39m
 �[32m✓�[39m src/api/previewStorageApi.test.ts �[2m(�[22m�[2m2 tests�[22m�[2m)�[22m�[32m 13�[2mms�[22m�[39m
 �[32m✓�[39m src/components/TaskPlanner/AgentModelSelectorParts.responsive.test.tsx �[2m(�[22m�[2m1 test�[22m�[2m)�[22m�[32m 53�[2mms�[22m�[39m
 �[32m✓�[39m src/components/ui/SystemAlert.test.tsx �[2m(�[22m�[2m2 tests�[22m�[2m)�[22m�[32m 178�[2mms�[22m�[39m
 �[32m✓�[39m src/components/creationActions.test.ts �[2m(�[22m�[2m20 tests�[22m�[2m)�[22m�[32m 14�[2mms�[22m�[39m

�[2m Test Files �[22m �[1m�[32m48 passed�[39m�[22m�[90m (48)�[39m
�[2m      Tests �[22m �[1m�[32m408 passed�[39m�[22m�[90m (408)�[39m
�[2m   Start at �[22m 12:20:07
�[2m   Duration �[22m 40.78s�[2m (environment 52%, tests 24%, setup 10%, import 9%, transform 5%)�[22m

�[2mEnvironment �[22m �[33mjsdom was created 48 times�[39m�[2m · 39.11s total, 52% of tracked time�[22m
�[2m            �[22m �[2mcreate it once per worker with �[22m�[33mpool: 'vmThreads'�[39m�[2m (keeps per-file isolation) or �[22m�[33misolate: false�[39m�[2m (shares it across files)�[22m
�[2m            �[22m �[2mlearn more: https://vitest.dev/guide/improving-performance#test-environments�[22m


> propr-ui@0.0.1 posttest
> npm run test:docker-context


> propr-ui@0.0.1 test:docker-context
> node --test scripts/docker-context-inputs.test.mjs

TAP version 13
# Subtest: focused UI selectors are forwarded only to Vitest
ok 1 - focused UI selectors are forwarded only to Vitest
  ---
  duration_ms: 0.949194
  type: 'test'
  ...
# Subtest: the UI Docker context contains its complete non-type external source import closure
ok 2 - the UI Docker context contains its complete non-type external source import closure
  ---
  duration_ms: 50.672763
  type: 'test'
  ...
1..2
# tests 2
# suites 0
# pass 2
# fail 0
# cancelled 0
# skipped 0
# todo 0
# duration_ms 109.471013
[150/150] passed propr-ui#2/4 (workspace test script) in 41.6s

### Shard 2/4: 149/150 passed in 421.2s

Assigned 150 of 600 discovered units.

| Duration | Status | Unit |
| ---: | --- | --- |
| 64.0s | passed | `packages/api/test/mcpAccessLog.test.ts` |
| 41.6s | passed | `propr-ui#2/4` (workspace) |
| 29.7s | passed | `apps/desktop/src/profile-store.crash-recovery.test.ts` |
| 18.2s | passed | `packages/api/test/mcpBrowser.test.ts` |
| 15.2s | passed | `packages/core/test/notificationService.test.ts` |
| 11.3s | passed | `apps/desktop/src/saved-accounts.test.ts` |
| 10.2s | failed | `apps/desktop/scripts/desktop-native-menu.test.mjs` |
| 9.9s | passed | `test/prPublicationRecoveryJob.test.ts` |
| 7.3s | passed | `packages/cli/src/commands/initCommands.test.ts` |
| 6.1s | passed | `test/reviewContextBudget.test.ts` |
| 6.0s | passed | `test/prContinuation.test.ts` |
| 5.8s | passed | `apps/desktop/src/credential-service.test.ts` |
| 4.8s | passed | `packages/api/test/notificationProjectionService.test.ts` |
| 4.8s | passed | `apps/desktop/scripts/macos-window-chrome.test.mjs` |
| 4.5s | passed | `packages/api/test/mcpGoalTaskDepth.test.ts` |


1/150 test runs failed in shard 2/4 after 421.2s:
- apps/desktop/scripts/desktop-native-menu.test.mjs: exit 1

Details truncated; see the uploaded artifacts for complete failure rows and logs.

View Workflow
View uploaded artifacts

@propr-dev

propr-dev Bot commented Sep 29, 2026 •

Copy link
Copy Markdown
Contributor Author

✅ Applied the requested follow-up changes in commit b10b7da

Summary of Changes

Fixed the stale assertions in desktop-native-menu.test.mjs to check the new dialog, focused “Prompt” field, and “Plan first” under Advanced Options.

The test now passes for both macOS and Linux paths through the suite runner. git diff --check also passes.

Only test code changed; no visual previews were needed.


🤖 Implementation Details

  • Model: GPT-6 Astra (high)
  • Requested By: @github-actions[bot]
  • Time: 2m 6s
  • Tokens: 358,685 (357,484 in / 1,201 out)
  • Cost: $0.87

Undo Changes • View Task Execution


💡 ProPR Slash Commands
Command Description Example
/merge Merge target branch into this PR and resolve conflicts /merge
/review Request an AI code review /review or /review claude-sonnet
/fix Implement fixes for issues found by /review /fix or /fix address the null check issue
/switch Change the AI model for this PR /switch claude-opus
/use Override the model for a single follow-up run /use claude-sonnet
/ultrafix Loop review→fix cycles until score goal is met /ultrafix or /ultrafix goal=8 max=10

🤖 Generated by ProPR
Processing comment ID: 5890198871✓

…` to check the new dialog, focused “Prompt” field, and “Plan first” under Advanced Options.

Fixed the stale assertions in `desktop-native-menu.test.mjs` to check the new dialog, focused “Prompt” field, and “Plan first” under Advanced Options.

The test now passes for both macOS and Linux paths through the suite runner. `git diff --check` also passes.

Only test code changed; no visual previews were needed.

PR: #2625
Comment by: @github-actions[bot] (ID: 5890198871)
Model: gpt-6-astra
@integry

integry commented Sep 29, 2026

Copy link
Copy Markdown
Owner

The architectural split-personality has been resolved. Both creation flows now share an identical modal dialog layout, unified Prompt terminology, docked attachment toolbars, and clean progressive disclosure (▶ Advanced Options).

However, you still have several micro-inconsistencies and a border-collision bug.

Here is the critical breakdown:


1. Primary Action Button Asymmetry

Compare the primary buttons in the bottom right of both dialogs:

  • Start a Goal: [ Start goal ] (Text only, no icon).
  • New Task: [ ▶ Run task ] (Has a leading play/execute icon).
  • The Flaw: These are twin modal components in the same design system. One has a leading SVG icon; the other is plain text.
  • The Fix: Standardize. Either give Start goal a leading icon (e.g., + or ⟳), or drop the play icon from Run task so both buttons rely on clean text.

2. Focus Ring Collision on the Docked Textarea

Look at the prompt input in both modals:

  • The Flaw: The textarea has an active focus state (border-teal-500), drawing a bright teal line across its bottom edge. Immediately below it, the docked attachment drop-zone has a standard static gray border (border-slate-200).
  • The Reality: A bright teal dividing line sitting directly on top of a gray container looks like two separate elements colliding rather than a single unified input tool.
  • The Fix: When an input has a docked toolbar, the focus ring must wrap the outer composite container:
    • The textarea itself should have border-none focus:ring-0.
    • The outer parent container (wrapping both the textarea and the attachment bar) should receive the active focus ring: border border-slate-200 focus-within:border-teal-500 focus-within:ring-1 focus-within:ring-teal-500 rounded-md.

3. Repository / Branch String Inconsistency

Look at the Repository selector across both dialogs:

  • Start a Goal: [ ⎇ acme/web ▾ ] (No branch indicated).
  • New Task: [ ⎇ acme/billing (main) ▾ ] (Branch explicitly declared).
  • The Flaw: In one modal, the repository slug includes the target branch (main); in the other, it omits the branch entirely.
  • The Reality: If a Goal or Task targets a specific git branch, that metadata must be rendered consistently across both selectors. If it doesn't target a branch, strip (main).

4. Attached File Chip Formatting

Look at [ 📄 dashboard-requirements.txt ✕ ] inside the Goal modal:

  • The Flaw: The attached file is rendered as a plain sans-serif text pill floating above an unstyled dashed line.
  • The Fix: Code, config, and requirement files are technical entities. Use your established Monospace Code Chip specification:
    • font-mono text-[12px] bg-slate-100 border border-slate-200 text-slate-800 rounded-sm px-2 py-1 flex items-center gap-1.5.
    • Make the filename monospace so it reads like a filesystem artifact.

@propr-dev

propr-dev Bot commented Sep 29, 2026 •

Copy link
Copy Markdown
Contributor Author

✅ Applied the requested follow-up changes in commit e1c980d

Summary of Changes

Applied all four fixes:

  • Text-only primary buttons.
  • Focus borders around the full prompt and attachment area.
  • Consistent repository-only labels.
  • Monospace attachment chips with the requested styling.

Validation passed: 65 unit tests, 13 browser checks, TypeScript, and lint. Captured desktop and mobile previews for both dialogs.

Visual preview

Goal creation — desktop

Goal creation — desktop

Focused prompt with a unified outer border, docked attachment toolbar, repository-only label, and text-only primary action. Includes an attached monospace file chip.

Original unavailable: managed storage is unavailable or the upload has expired.

Goal creation — mobile

Goal creation — mobile

Focused prompt with a unified outer border, docked attachment toolbar, repository-only label, and text-only primary action. Includes an attached monospace file chip.

Original unavailable: managed storage is unavailable or the upload has expired.

New goal options desktop

New goal options desktop

Original unavailable: managed storage is unavailable or the upload has expired.

New goal options mobile

New goal options mobile

Original unavailable: managed storage is unavailable or the upload has expired.

Task creation — desktop

Task creation — desktop

Focused prompt with a unified outer border, docked attachment toolbar, repository-only label, and text-only primary action.

Original unavailable: managed storage is unavailable or the upload has expired.

New task error mobile

New task error mobile

Original unavailable: managed storage is unavailable or the upload has expired.

Task creation — mobile

Task creation — mobile

Focused prompt with a unified outer border, docked attachment toolbar, repository-only label, and text-only primary action.

Original unavailable: managed storage is unavailable or the upload has expired.

New task rejected desktop

New task rejected desktop

Original unavailable: managed storage is unavailable or the upload has expired.


🤖 Implementation Details

  • Model: GPT-6 Astra (high)
  • Requested By: @integry
  • Time: 4m 18s
  • Tokens: 661,802 (657,706 in / 4,096 out)
  • Cost: $1.34

Undo Changes • View Task Execution


💡 ProPR Slash Commands
Command Description Example
/merge Merge target branch into this PR and resolve conflicts /merge
/review Request an AI code review /review or /review claude-sonnet
/fix Implement fixes for issues found by /review /fix or /fix address the null check issue
/switch Change the AI model for this PR /switch claude-opus
/use Override the model for a single follow-up run /use claude-sonnet
/ultrafix Loop review→fix cycles until score goal is met /ultrafix or /ultrafix goal=8 max=10

🤖 Generated by ProPR
Processing comment ID: 5891418520✓

Applied all four fixes:

- Text-only primary buttons.
- Focus borders around the full prompt and attachment area.
- Consistent repository-only labels.
- Monospace attachment chips with the requested styling.

Validation passed: 65 unit tests, 13 browser checks, TypeScript, and lint. Captured desktop and mobile previews for both dialogs.

PR: #2625
Comment by: @integry (ID: 5891418520)
Model: gpt-6-astra
@integry

integry commented Sep 29, 2026

Copy link
Copy Markdown
Owner

1. Redundant Summary String in the Expanded State (Image 2)

Look at the accordion header when open:
▼ Advanced Options GPT-5.6 Sol · 5 parallel tasks · Orchestrate

  • The Flaw: Directly below that header, the user sees:
    • Model dropdown: GPT-5.6 Sol
    • Concurrency input: 5
    • Radio button: Orchestrate through ProPR
  • The Reality: Displaying a summary string while the actual interactive inputs for those exact values are open and editable 8 pixels below it is pure redundancy. Summary strings exist for collapsed states.
  • The Fix: Conditionally render the parameter summary only when the accordion is closed (!isOpen). When open, the header should simply read ▼ Advanced Options.

2. The Asymmetric Grid Hole (Row 2)

Look at Maximum parallel tasks (optional):

  • The Flaw: Because Row 1 uses a 2-column grid (Coding agent $\leftrightarrow$ Model), Row 2 inherits that grid. As a result, Maximum parallel tasks takes up the left 50% of the modal, leaving the entire right 50% as a gaping empty hole.
  • The Fix:
    • Option A (3-Column Top Row): Make Row 1 a 3-column grid: Coding Agent (40%) $\leftrightarrow$ Model (40%) $\leftrightarrow$ Max Tasks (20%). Concurrency is just a small integer input; it doesn't need half the modal width.
    • Option B (Span & Constrain): Let Maximum parallel tasks occupy Row 2, but make the input width compact (w-32) and pair it with inline helper text or the Ultrafix checkbox on the right.

3. The Unbranded Blue Radio Button

Look at the selected radio button: ◉ Orchestrate through ProPR.

  • The Flaw: It is rendered in generic browser-default blue (#2563eb), while the focus ring, the Start goal button, and the app's active states are all Brand Teal (#0d9488 / teal-600).
  • The Fix: Apply accent-teal-600 to the radio input (or use a custom SVG radio) so the selected state respects the brand palette rather than falling back to default OS blue.

4. Textarea Resize Grip Collision

Look at the bottom-right corner of the prompt textarea (above the file chip):

  • The Flaw: The native browser resize handle (///) is still active.
  • The Reality: If a user drags that resize handle downward, the textarea will expand and physically tear away from or overflow the docked attachment toolbar below it.
  • The Fix: Set resize-none on the textarea. In modern IDEs and chat inputs with docked toolbars, the textarea should auto-expand its height based on input content (field-sizing: content in modern CSS, or a simple JS auto-grow listener) rather than using a manual browser resize grip.

What to Tackle Next

This modal is now structurally solid and consistent with the design system. The remaining areas that still need review and cleanup:

  1. The Plans Screen: Ensure the plan creation and review views don't suffer from the same card-hell or un-docked form issues that Goals and Tasks originally had.
  2. The Tasks Index / Detail Views: Ensure the task execution console matches the Split-Pane and Gutter-style layout established for Goals.

@propr-dev

propr-dev Bot commented Sep 29, 2026 •

Copy link
Copy Markdown
Contributor Author

✅ Applied the requested follow-up changes in commit bdf0753

Summary of Changes

Implemented all four dialog fixes:

  • Summaries appear only when Advanced Options is collapsed.
  • Concurrency uses a compact input with inline helper text.
  • Strategy radios use brand teal.
  • Both prompts auto-grow without manual resize grips.

Validated with 65 unit tests, 13 browser tests, TypeScript, and lint. Captured desktop and mobile previews.

Visual preview

Collapsed goal options

Collapsed goal options

Collapsed Advanced Options retains its settings summary; the prompt has no manual resize grip.

Original unavailable: managed storage is unavailable or the upload has expired.

Expanded goal options on desktop

Expanded goal options on desktop

Expanded header without duplicate settings, compact concurrency input with inline help, and teal strategy radios.

Original unavailable: managed storage is unavailable or the upload has expired.

Expanded goal options on mobile

Expanded goal options on mobile

Responsive compact concurrency field, collapsed-only summary, and teal strategy selection.

Original unavailable: managed storage is unavailable or the upload has expired.

Expanded task options on desktop

Expanded task options on desktop

Task settings hide their summary while expanded; the auto-growing prompt stays docked to attachments.

Original unavailable: managed storage is unavailable or the upload has expired.

Expanded task options on mobile

Expanded task options on mobile

The same task dialog changes at mobile width.

Original unavailable: managed storage is unavailable or the upload has expired.


🤖 Implementation Details

  • Model: GPT-6 Astra (high)
  • Requested By: @integry
  • Time: 4m 43s
  • Tokens: 636,238 (631,234 in / 5,004 out)
  • Cost: $1.32

Undo Changes • View Task Execution


💡 ProPR Slash Commands
Command Description Example
/merge Merge target branch into this PR and resolve conflicts /merge
/review Request an AI code review /review or /review claude-sonnet
/fix Implement fixes for issues found by /review /fix or /fix address the null check issue
/switch Change the AI model for this PR /switch claude-opus
/use Override the model for a single follow-up run /use claude-sonnet
/ultrafix Loop review→fix cycles until score goal is met /ultrafix or /ultrafix goal=8 max=10

🤖 Generated by ProPR
Processing comment ID: 5897552788✓

Implemented all four dialog fixes:

- Summaries appear only when Advanced Options is collapsed.
- Concurrency uses a compact input with inline helper text.
- Strategy radios use brand teal.
- Both prompts auto-grow without manual resize grips.

Validated with 65 unit tests, 13 browser tests, TypeScript, and lint. Captured desktop and mobile previews.

PR: #2625
Comment by: @integry (ID: 5897552788)
Model: gpt-6-astra
@integry

integry commented Sep 29, 2026

Copy link
Copy Markdown
Owner

2. Lead with Visual Identity (The Missing Concept Icons)

Look at the titles: Start a goal and New task.

  • The Flaw: Both are unadorned plain text.
  • The Fix: Anchor each modal to its respective icon from your sidebar navigation:
    • Goal: ◎ Start a goal (Concentric target/bullseye icon in the header).
    • Task: ⚡ New task (Lightning bolt icon in the header).
  • Why it works: The human eye reads icons before text. Anchoring the bullseye icon to Goals and the lightning bolt to Tasks immediately anchors the mental model to what is in the sidebar.

3. The "Plan First" Action Trap (Image 3)

Look inside Advanced Options in the New Task modal:

  • The Flaw: You took [ ⛶ Plan first ]—which is an alternative execution action—and buried it inside the collapsed accordion under the agent dropdown.
  • The Reality: "Plan first" is not a configuration setting; it is an action that means: "Don't write code yet; generate a plan first." Burying an action button inside an advanced options drawer makes it completely undiscoverable.
  • The Fix: Move it to the action footer alongside Run task:
    • Left: Cancel (ghost)
    • Right: [ ⛶ Plan first ] (bordered secondary ghost button) $\leftrightarrow$ [ Run task ] (solid teal button).
    • This restores the intentional workflow choice without cluttering the options drawer.

4. Label Inconsistency (Agent vs. Coding agent)

Look at the first dropdown in Advanced Options:

  • Goal (Image 2): Labeled Coding agent.
  • Task (Image 3): Labeled Agent.
  • The Flaw: You are using two different labels for the exact same field across sibling modals.
  • The Fix: Standardize to Agent globally.

5. Differentiating the Mental Models (The Strategy Row)

The true difference between a Task and a Goal is scope and duration:

  • A Task is bounded: It touches one repo, one issue, runs once, and opens a PR. Keep its options minimal: Agent, Model, and Base Branch.
  • A Goal is an orchestration engine: It decomposes work, manages concurrency, and spawns multiple sub-tasks.
  • The Fix: Keep the Goal Launch Strategy (Direct vs Orchestrate through ProPR) and Max Parallel Tasks exclusively in the Goal modal. That operational complexity is what legitimately differentiates a Goal from a Task.

Summary

Do not artificially change the layout of one modal just to make it look "different."
2. Anchor the headers with their respective sidebar icons (◎ vs. ⚡).
3. Move [ Plan first ] out of the accordion and onto the footer action bar.
4. Keep the shared structural mechanics identical.

@propr-dev

propr-dev Bot commented Sep 29, 2026 •

Copy link
Copy Markdown
Contributor Author

✅ Applied the requested follow-up changes in commit 24867be

Summary of Changes

Implemented the follow-up:

  • Added bullseye and lightning bolt header icons.
  • Moved “Plan first” beside “Run task,” with Cancel on the left.
  • Standardized the dropdown label to “Agent.”
  • Preserved shared modal structure and Goal-only strategy/concurrency controls.

Validation passed: 65 unit tests, 13 browser checks, TypeScript, and lint. Captured four desktop/mobile previews.

Visual preview

New goal desktop

New goal desktop

Original unavailable: managed storage is unavailable or the upload has expired.

New goal mobile

New goal mobile

Original unavailable: managed storage is unavailable or the upload has expired.

Start a goal — desktop

Start a goal — desktop

Bullseye header and standardized Agent label, with goal-only concurrency and launch strategy controls.

Original unavailable: managed storage is unavailable or the upload has expired.

Start a goal — mobile

Start a goal — mobile

Bullseye header and standardized Agent label, with goal-only concurrency and launch strategy controls.

Original unavailable: managed storage is unavailable or the upload has expired.

New task — desktop

New task — desktop

Lightning bolt header and visible Plan first action beside Run task, with Cancel on the left.

Original unavailable: managed storage is unavailable or the upload has expired.

New task error mobile

New task error mobile

Original unavailable: managed storage is unavailable or the upload has expired.

New task — mobile

New task — mobile

Lightning bolt header and visible Plan first action beside Run task, with Cancel on the left.

Original unavailable: managed storage is unavailable or the upload has expired.

New task rejected desktop

New task rejected desktop

Original unavailable: managed storage is unavailable or the upload has expired.


🤖 Implementation Details

  • Model: GPT-6 Astra (high)
  • Requested By: @integry
  • Time: 4m 16s
  • Tokens: 559,080 (554,901 in / 4,179 out)
  • Cost: $1.27
  • Subscription usage: Weekly +1%

Undo Changes • View Task Execution


💡 ProPR Slash Commands
Command Description Example
/merge Merge target branch into this PR and resolve conflicts /merge
/review Request an AI code review /review or /review claude-sonnet
/fix Implement fixes for issues found by /review /fix or /fix address the null check issue
/switch Change the AI model for this PR /switch claude-opus
/use Override the model for a single follow-up run /use claude-sonnet
/ultrafix Loop review→fix cycles until score goal is met /ultrafix or /ultrafix goal=8 max=10

🤖 Generated by ProPR
Processing comment ID: 5897817279✓

Implemented the follow-up:

- Added bullseye and lightning bolt header icons.
- Moved “Plan first” beside “Run task,” with Cancel on the left.
- Standardized the dropdown label to “Agent.”
- Preserved shared modal structure and Goal-only strategy/concurrency controls.

Validation passed: 65 unit tests, 13 browser checks, TypeScript, and lint. Captured four desktop/mobile previews.

PR: #2625
Comment by: @integry (ID: 5897817279)
Model: gpt-6-astra
@github-actions

Copy link
Copy Markdown

Full Test Suite Results

Validation failed during: Test shard (shard 2).

  • Docs site validation: skipped (classifier decision: false)
  • Shard coverage verification: success
  • Hosted native Electron units: success
  • Shard 1/4: passed in 301.3s on GitHub Actions 1000052338
  • Shard 2/4: failed during Test shard in 421.2s on GitHub Actions 1000052337
    • apps/desktop/scripts/desktop-native-menu.test.mjs: exit 1
  • Shard 3/4: passed in 306.5s on GitHub Actions 1000052336
  • Shard 4/4: passed in 270.9s on GitHub Actions 1000052335
View shard 2/4 output
...(truncated)

.
# Subtest: createMockLabel
    # Subtest: creates label with default values
    ok 1 - creates label with default values
      ---
      duration_ms: 0.254033
      type: 'test'
      ...
    # Subtest: creates label with custom values
    ok 2 - creates label with custom values
      ---
      duration_ms: 0.172381
      type: 'test'
      ...
    1..2
ok 2 - createMockLabel
  ---
  duration_ms: 0.723939
  type: 'suite'
  ...
# Subtest: createMockRepository
    # Subtest: creates repository with default values
    ok 1 - creates repository with default values
      ---
      duration_ms: 0.853671
      type: 'test'
      ...
    # Subtest: creates repository with custom values
    ok 2 - creates repository with custom values
      ---
      duration_ms: 0.422017
      type: 'test'
      ...
    1..2
ok 3 - createMockRepository
  ---
  duration_ms: 1.639726
  type: 'suite'
  ...
# Subtest: createMockIssue
    # Subtest: creates issue with default values
    ok 1 - creates issue with default values
      ---
      duration_ms: 1.005463
      type: 'test'
      ...
    # Subtest: creates issue with labels as strings
    ok 2 - creates issue with labels as strings
      ---
      duration_ms: 0.284971
      type: 'test'
      ...
    # Subtest: creates issue with label objects
    ok 3 - creates issue with label objects
      ---
      duration_ms: 0.277026
      type: 'test'
      ...
    # Subtest: creates closed issue
    ok 4 - creates closed issue
      ---
      duration_ms: 0.384266
      type: 'test'
      ...
    1..4
ok 4 - createMockIssue
  ---
  duration_ms: 2.325123
  type: 'suite'
  ...
# Subtest: createMockPullRequest
    # Subtest: creates PR with default values
    ok 1 - creates PR with default values
      ---
      duration_ms: 0.530398
      type: 'test'
      ...
    # Subtest: creates PR with custom values
    ok 2 - creates PR with custom values
      ---
      duration_ms: 0.370219
      type: 'test'
      ...
    # Subtest: creates PR from fork
    ok 3 - creates PR from fork
      ---
      duration_ms: 0.200052
      type: 'test'
      ...
    1..3
ok 5 - createMockPullRequest
  ---
  duration_ms: 1.294302
  type: 'suite'
  ...
# Subtest: createWebhookIssuesEvent
    # Subtest: creates opened event by default
    ok 1 - creates opened event by default
      ---
      duration_ms: 0.237041
      type: 'test'
      ...
    # Subtest: creates event with custom action
    ok 2 - creates event with custom action
      ---
      duration_ms: 0.166861
      type: 'test'
      ...
    1..2
ok 6 - createWebhookIssuesEvent
  ---
  duration_ms: 1.382226
  type: 'suite'
  ...
# Subtest: createWebhookIssuesLabeledEvent
    # Subtest: creates labeled event with label property
    ok 1 - creates labeled event with label property
      ---
      duration_ms: 0.19821
      type: 'test'
      ...
    1..1
ok 7 - createWebhookIssuesLabeledEvent
  ---
  duration_ms: 0.271205
  type: 'suite'
  ...
# Subtest: createWebhookIssuesClosedEvent
    # Subtest: creates closed event with closed state
    ok 1 - creates closed event with closed state
      ---
      duration_ms: 0.175217
      type: 'test'
      ...
    1..1
ok 8 - createWebhookIssuesClosedEvent
  ---
  duration_ms: 0.239196
  type: 'suite'
  ...
# Subtest: createWebhookIssuesReopenedEvent
    # Subtest: creates reopened event with open state
    ok 1 - creates reopened event with open state
      ---
      duration_ms: 0.218186
      type: 'test'
      ...
    1..1
ok 9 - createWebhookIssuesReopenedEvent
  ---
  duration_ms: 0.282778
  type: 'suite'
  ...
# Subtest: createWebhookIssueCommentEvent
    # Subtest: creates created event by default
    ok 1 - creates created event by default
      ---
      duration_ms: 0.319746
      type: 'test'
      ...
    # Subtest: creates event with custom comment body
    ok 2 - creates event with custom comment body
      ---
      duration_ms: 0.170467
      type: 'test'
      ...
    1..2
ok 10 - createWebhookIssueCommentEvent
  ---
  duration_ms: 0.598265
  type: 'suite'
  ...
# Subtest: createWebhookIssueCommentCreatedEvent
    # Subtest: creates created event
    ok 1 - creates created event
      ---
      duration_ms: 0.167993
      type: 'test'
      ...
    1..1
ok 11 - createWebhookIssueCommentCreatedEvent
  ---
  duration_ms: 0.228326
  type: 'suite'
  ...
# Subtest: createWebhookIssueCommentDeletedEvent
    # Subtest: creates deleted event
    ok 1 - creates deleted event
      ---
      duration_ms: 0.181207
      type: 'test'
      ...
    1..1
ok 12 - createWebhookIssueCommentDeletedEvent
  ---
  duration_ms: 0.240047
  type: 'suite'
  ...
# Subtest: createWebhookIssueCommentEditedEvent
    # Subtest: creates edited event
    ok 1 - creates edited event
      ---
      duration_ms: 0.151573
      type: 'test'
      ...
    1..1
ok 13 - createWebhookIssueCommentEditedEvent
  ---
  duration_ms: 0.207988
  type: 'suite'
  ...
# Subtest: createWebhookPullRequestEvent
    # Subtest: creates opened event by default
    ok 1 - creates opened event by default
      ---
      duration_ms: 0.221733
      type: 'test'
      ...
    # Subtest: creates event with custom PR
    ok 2 - creates event with custom PR
      ---
      duration_ms: 0.170668
      type: 'test'
      ...
    1..2
ok 14 - createWebhookPullRequestEvent
  ---
  duration_ms: 0.469474
  type: 'suite'
  ...
# Subtest: createWebhookPullRequestLabeledEvent
    # Subtest: creates labeled event with label
    ok 1 - creates labeled event with label
      ---
      duration_ms: 0.239837
      type: 'test'
      ...
    1..1
ok 15 - createWebhookPullRequestLabeledEvent
  ---
  duration_ms: 0.300039
  type: 'suite'
  ...
# Subtest: createWebhookPullRequestClosedEvent
    # Subtest: creates closed event
    ok 1 - creates closed event
      ---
      duration_ms: 0.188451
      type: 'test'
      ...
    1..1
ok 16 - createWebhookPullRequestClosedEvent
  ---
  duration_ms: 0.247642
  type: 'suite'
  ...
# Subtest: createWebhookPRReviewCommentEvent
    # Subtest: creates created event by default
    ok 1 - creates created event by default
      ---
      duration_ms: 0.378265
      type: 'test'
      ...
    # Subtest: creates event with custom comment
    ok 2 - creates event with custom comment
      ---
      duration_ms: 0.341687
      type: 'test'
      ...
    1..2
ok 17 - createWebhookPRReviewCommentEvent
  ---
  duration_ms: 0.803347
  type: 'suite'
  ...
# Subtest: createWebhookPRReviewCommentCreatedEvent
    # Subtest: creates created event
    ok 1 - creates created event
      ---
      duration_ms: 0.222435
      type: 'test'
      ...
    1..1
ok 18 - createWebhookPRReviewCommentCreatedEvent
  ---
  duration_ms: 0.282887
  type: 'suite'
  ...
# Subtest: createWebhookPRReviewCommentDeletedEvent
    # Subtest: creates deleted event
    ok 1 - creates deleted event
      ---
      duration_ms: 0.184834
      type: 'test'
      ...
    1..1
ok 19 - createWebhookPRReviewCommentDeletedEvent
  ---
  duration_ms: 0.241971
  type: 'suite'
  ...
# Subtest: createWebhookPRReviewCommentEditedEvent
    # Subtest: creates edited event
    ok 1 - creates edited event
      ---
      duration_ms: 0.251108
      type: 'test'
      ...
    1..1
ok 20 - createWebhookPRReviewCommentEditedEvent
  ---
  duration_ms: 0.325547
  type: 'suite'
  ...
# Subtest: createWebhookCheckRunEvent
    # Subtest: creates completed success event by default
    ok 1 - creates completed success event by default
      ---
      duration_ms: 0.535428
      type: 'test'
      ...
    # Subtest: creates event with custom values
    ok 2 - creates event with custom values
      ---
      duration_ms: 0.240258
      type: 'test'
      ...
    # Subtest: creates in-progress event
    ok 3 - creates in-progress event
      ---
      duration_ms: 0.19826
      type: 'test'
      ...
    # Subtest: creates event with no PRs
    ok 4 - creates event with no PRs
      ---
      duration_ms: 0.33237
      type: 'test'
      ...
    # Subtest: creates skipped check run
    ok 5 - creates skipped check run
      ---
      duration_ms: 0.253573
      type: 'test'
      ...
    1..5
ok 21 - createWebhookCheckRunEvent
  ---
  duration_ms: 1.854285
  type: 'suite'
  ...
# Subtest: Webhook Event Factory Integration
    # Subtest: all factories generate valid typed events
    ok 1 - all factories generate valid typed events
      ---
      duration_ms: 1.608167
      type: 'test'
      ...
    # Subtest: events can be customized for realistic scenarios
    ok 2 - events can be customized for realistic scenarios
      ---
      duration_ms: 0.33811
      type: 'test'
      ...
    1..2
ok 22 - Webhook Event Factory Integration
  ---
  duration_ms: 2.088872
  type: 'suite'
  ...
1..22
# tests 39
# suites 22
# pass 39
# fail 0
# cancelled 0
# skipped 0
# todo 0
# duration_ms 327.869417
[146/150] passed test/webhookFactories.test.ts in 0.5s

[147/150] test/windowsStandardUserConnectHarness.test.ts
TAP version 13
# Subtest: the disabled Windows scenario omits its token while enabled scenarios retain the sentinel
ok 1 - the disabled Windows scenario omits its token while enabled scenarios retain the sentinel
  ---
  duration_ms: 10.091035
  type: 'test'
  ...
# Subtest: the Windows authority fixtures isolate pre-import root injection markers
ok 2 - the Windows authority fixtures isolate pre-import root injection markers
  ---
  duration_ms: 27.432812
  type: 'test'
  ...
# Subtest: the ordinary-user Windows proof retains native security paths and bounds result-matrix reuse
ok 3 - the ordinary-user Windows proof retains native security paths and bounds result-matrix reuse
  ---
  duration_ms: 0.764976
  type: 'test'
  ...
# Subtest: the ordinary-user Windows diagnostic has fixed allowlists and redacts all other values
ok 4 - the ordinary-user Windows diagnostic has fixed allowlists and redacts all other values
  ---
  duration_ms: 1.700399
  type: 'test'
  ...
# Subtest: the staged hosted probe and production inspector both use the inherited standard handle
ok 5 - the staged hosted probe and production inspector both use the inherited standard handle
  ---
  duration_ms: 0.347187
  type: 'test'
  ...
# Subtest: the production inspector duplicates its standard handle before the split native operations
ok 6 - the production inspector duplicates its standard handle before the split native operations
  ---
  duration_ms: 0.62802
  type: 'test'
  ...
# Subtest: the staged probe accepts only ordered milestone tokens and coarse timing buckets
ok 7 - the staged probe accepts only ordered milestone tokens and coarse timing buckets
  ---
  duration_ms: 1.087336
  type: 'test'
  ...
# Subtest: the diagnostic allowance precedes a cumulatively bounded production standard-handle proof
ok 8 - the diagnostic allowance precedes a cumulatively bounded production standard-handle proof
  ---
  duration_ms: 0.537472
  type: 'test'
  ...
# Subtest: the hostile path ABA remains replaced through validation and is rejected as INVALID_ROOT
ok 9 - the hostile path ABA remains replaced through validation and is rejected as INVALID_ROOT
  ---
  duration_ms: 0.375019
  type: 'test'
  ...
1..9
# tests 9
# suites 0
# pass 9
# fail 0
# cancelled 0
# skipped 0
# todo 0
# duration_ms 319.352627
[147/150] passed test/windowsStandardUserConnectHarness.test.ts in 0.4s

[148/150] test/workerAgentPreparation.test.ts
TAP version 13
# (node:17651) ExperimentalWarning: Module mocking is an experimental feature and might change at any time
# (Use `node --trace-warnings ...` to show where the warning was created)
# Subtest: startup remains alive without task capacity after preparation failure (throws=false)
ok 1 - startup remains alive without task capacity after preparation failure (throws=false)
  ---
  duration_ms: 5.095136
  type: 'test'
  ...
# Subtest: startup remains alive without task capacity after preparation failure (throws=true)
# (node:17651) ExperimentalWarning: The MockTimers API is an experimental feature and might change at any time
ok 2 - startup remains alive without task capacity after preparation failure (throws=true)
  ---
  duration_ms: 1.617615
  type: 'test'
  ...
# Subtest: automatic jobs defer to the owner deadline and retry through guarded recovery
ok 3 - automatic jobs defer to the owner deadline and retry through guarded recovery
  ---
  duration_ms: 2.169423
  type: 'test'
  ...
# Subtest: requeued automatic jobs propagate the recorded open-circuit error: ENOSPC
ok 4 - requeued automatic jobs propagate the recorded open-circuit error: ENOSPC
  ---
  duration_ms: 0.469074
  type: 'test'
  ...
# Subtest: requeued automatic jobs propagate the recorded open-circuit error: temporary download failure
ok 5 - requeued automatic jobs propagate the recorded open-circuit error: temporary download failure
  ---
  duration_ms: 0.60669
  type: 'test'
  ...
# Subtest: failed explicit builds preserve the build error without refreshing readiness
ok 6 - failed explicit builds preserve the build error without refreshing readiness
  ---
  duration_ms: 0.327149
  type: 'test'
  ...
1..6
# tests 6
# suites 0
# pass 6
# fail 0
# cancelled 0
# skipped 0
# todo 0
# duration_ms 545.019802
[148/150] passed test/workerAgentPreparation.test.ts in 0.7s

[149/150] test/workerTaskStateRecovery.test.ts
TAP version 13
# (node:17692) ExperimentalWarning: Module mocking is an experimental feature and might change at any time
# (Use `node --trace-warnings ...` to show where the warning was created)
# Subtest: coalesces overlapping runs and releases the distributed lease
ok 1 - coalesces overlapping runs and releases the distributed lease
  ---
  duration_ms: 3.188011
  type: 'test'
  ...
# Subtest: does not reconcile when another worker owns the lease
ok 2 - does not reconcile when another worker owns the lease
  ---
  duration_ms: 4.330439
  type: 'test'
  ...
# Subtest: contains lease acquisition failures instead of creating an unhandled rejection
ok 3 - contains lease acquisition failures instead of creating an unhandled rejection
  ---
  duration_ms: 1.006145
  type: 'test'
  ...
# Subtest: retains an unfinished page backlog across recovery runs
ok 4 - retains an unfinished page backlog across recovery runs
  ---
  duration_ms: 1.955545
  type: 'test'
  ...
# Subtest: bounds a stalled lease acquisition by the recovery budget
ok 5 - bounds a stalled lease acquisition by the recovery budget
  ---
  duration_ms: 9.842798
  type: 'test'
  ...
# Subtest: close aborts a stalled active recovery run
ok 6 - close aborts a stalled active recovery run
  ---
  duration_ms: 1.790016
  type: 'test'
  ...
# Subtest: runs once at startup and continues on the configured interval
ok 7 - runs once at startup and continues on the configured interval
  ---
  duration_ms: 20.931019
  type: 'test'
  ...
# Subtest: reconciles follow-up CI suspensions under the same lease
ok 8 - reconciles follow-up CI suspensions under the same lease
  ---
  duration_ms: 0.645192
  type: 'test'
  ...
1..8
# tests 8
# suites 0
# pass 8
# fail 0
# cancelled 0
# skipped 0
# todo 0
# duration_ms 643.531747
[149/150] passed test/workerTaskStateRecovery.test.ts in 0.8s

[150/150] propr-ui#1/4 (workspace test script)

> propr-ui@0.0.1 test
> vitest run --shard=1/4


�[1m�[30m�[46m RUN �[49m�[39m�[22m �[36mv5.0.0 �[39m�[90m/home/runner/work/propr/propr/propr-ui�[39m

�[90mstderr�[2m | src/config/runtimeConfig.test.ts�[2m > �[22m�[2mgetApiBaseUrl�[2m > �[22m�[2mblocks API client construction when the hosted UI has no selected stack
�[22m�[39m[propr] HOSTED_STACK_REQUIRED

�[90mstderr�[2m | src/config/runtimeConfig.test.ts�[2m > �[22m�[2mgetApiBaseUrl�[2m > �[22m�[2mblocks API client construction for a non-Connect hosted runtime URL
�[22m�[39m[propr] INVALID_RUNTIME_CONFIGURATION

�[90mstderr�[2m | src/config/runtimeConfig.test.ts�[2m > �[22m�[2mhosted tunnel query API base�[2m > �[22m�[2mdoes not let an encoded tunnel name fall through to valid runtime configuration
�[22m�[39m[propr] INVALID_RUNTIME_CONFIGURATION

�[90mstderr�[2m | src/config/runtimeConfig.test.ts�[2m > �[22m�[2mhosted tunnel query API base�[2m > �[22m�[2mdoes not let an encoded tunnel name fall through to a valid stored endpoint
�[22m�[39m[propr] INVALID_RUNTIME_CONFIGURATION

 �[32m✓�[39m src/config/runtimeConfig.test.ts �[2m(�[22m�[2m67 tests�[22m�[2m)�[22m�[33m 1203�[2mms�[22m�[39m
   �[32m✓�[39m getApiBaseUrl �[2m(16)�[22m
     �[33m�[2m✓�[22m�[39m uses the runtime-configured apiBaseUrl when present�[33m 488�[2mms�[22m�[39m
�[90mstderr�[2m | src/pages/InboxPage.test.tsx�[2m > �[22m�[2mInbox page�[2m > �[22m�[2mexpands a system notification in place instead of navigating
�[22m�[39mAn update to InboxPage inside a test was not wrapped in act(...).

When testing, code that causes React state updates should be wrapped into act(...):

act(() => {
  /* fire events that update state */
});
/* assert on the output */

This ensures that you're testing the behavior the user would see in the browser. Learn more at https://react.dev/link/wrap-tests-with-act

 �[32m✓�[39m src/pages/InboxPage.test.tsx �[2m(�[22m�[2m38 tests�[22m�[2m)�[22m�[33m 3308�[2mms�[22m�[39m
   �[32m✓�[39m Inbox page �[2m(38)�[22m
     �[33m�[2m✓�[22m�[39m renders activity as one newest-first list with only System kept apart and collapsed�[33m 428�[2mms�[22m�[39m
 �[32m✓�[39m src/desktop/DesktopExperience.test.tsx �[2m(�[22m�[2m22 tests�[22m�[2m)�[22m�[33m 1439�[2mms�[22m�[39m
 �[32m✓�[39m src/hooks/useVoicePreference.test.tsx �[2m(�[22m�[2m20 tests�[22m�[2m)�[22m�[33m 495�[2mms�[22m�[39m
�[90mstderr�[2m | src/components/RepositorySettingsBar.test.tsx�[2m > �[22m�[2mRepositorySettingsBar follow-up CI cancellation�[2m > �[22m�[2mrenders the option off by default with helper text about restarting checks
�[22m�[39mEncountered two children with the same key, `repo-1`. Keys should be unique so that components maintain their identity across updates. Non-unique keys may cause children to be duplicated and/or omitted — the behavior is unsupported and could change in a future version.

�[90mstderr�[2m | src/components/RepositorySettingsBar.test.tsx�[2m > �[22m�[2mRepositorySettingsBar follow-up CI cancellation�[2m > �[22m�[2masks for a selection and discloses the instance fallback while the enabled option selects nothing
�[22m�[39mEncountered two children with the same key, `repo-1`. Keys should be unique so that components maintain their identity across updates. Non-unique keys may cause children to be duplicated and/or omitted — the behavior is unsupported and could change in a future version.

�[90mstderr�[2m | src/components/RepositorySettingsBar.test.tsx�[2m > �[22m�[2mRepositorySettingsBar follow-up CI cancellation�[2m > �[22m�[2masks for a selection and discloses the instance fallback while the enabled option selects nothing
�[22m�[39mAn update to CancelCiDuringFollowupControl inside a test was not wrapped in act(...).

When testing, code that causes React state updates should be wrapped into act(...):

act(() => {
  /* fire events that update state */
});
/* assert on the output */

This ensures that you're testing the behavior the user would see in the browser. Learn more at https://react.dev/link/wrap-tests-with-act

�[90mstderr�[2m | src/components/RepositorySettingsBar.test.tsx�[2m > �[22m�[2mRepositorySettingsBar follow-up CI cancellation�[2m > �[22m�[2mshows the selected workflows and reports an edited selection as exact identities
�[22m�[39mEncountered two children with the same key, `repo-1`. Keys should be unique so that components maintain their identity across updates. Non-unique keys may cause children to be duplicated and/or omitted — the behavior is unsupported and could change in a future version.

�[90mstderr�[2m | src/components/RepositorySettingsBar.test.tsx�[2m > �[22m�[2mRepositorySettingsBar follow-up CI cancellation�[2m > �[22m�[2mdoes not report a selection that did not change
�[22m�[39mEncountered two children with the same key, `repo-1`. Keys should be unique so that components maintain their identity across updates. Non-unique keys may cause children to be duplicated and/or omitted — the behavior is unsupported and could change in a future version.

�[90mstderr�[2m | src/components/RepositorySettingsBar.test.tsx�[2m > �[22m�[2mRepositorySettingsBar follow-up CI cancellation�[2m > �[22m�[2mpreserves comma-containing names on unchanged blur and when editing another selection
�[22m�[39mEncountered two children with the same key, `repo-1`. Keys should be unique so that components maintain their identity across updates. Non-unique keys may cause children to be duplicated and/or omitted — the behavior is unsupported and could change in a future version.

�[90mstderr�[2m | src/components/RepositorySettingsBar.test.tsx�[2m > �[22m�[2mRepositorySettingsBar follow-up CI cancellation�[2m > �[22m�[2mdoes not save incomplete quoted input
�[22m�[39mEncountered two children with the same key, `repo-1`. Keys should be unique so that components maintain their identity across updates. Non-unique keys may cause children to be duplicated and/or omitted — the behavior is unsupported and could change in a future version.

�[90mstderr�[2m | src/components/RepositorySettingsBar.test.tsx�[2m > �[22m�[2mRepositorySettingsBar follow-up CI cancellation�[2m > �[22m�[2mreflects the stored value and reports a toggle
�[22m�[39mEncountered two children with the same key, `repo-1`. Keys should be unique so that components maintain their identity across updates. Non-unique keys may cause children to be duplicated and/or omitted — the behavior is unsupported and could change in a future version.

�[90mstderr�[2m | src/components/RepositorySettingsBar.test.tsx�[2m > �[22m�[2mRepositorySettingsBar follow-up CI cancellation�[2m > �[22m�[2mreflects the stored value and reports a toggle
�[22m�[39mAn update to CancelCiDuringFollowupControl inside a test was not wrapped in act(...).

When testing, code that causes React state updates should be wrapped into act(...):

act(() => {
  /* fire events that update state */
});
/* assert on the output */

This ensures that you're testing the behavior the user would see in the browser. Learn more at https://react.dev/link/wrap-tests-with-act

�[90mstderr�[2m | src/components/RepositorySettingsBar.test.tsx�[2m > �[22m�[2mRepositorySettingsBar detected workflows�[2m > �[22m�[2mrecognizes and deselects a padded display name with triggers [ 'pull_request' ]
�[22m�[39mEncountered two children with the same key, `repo-1`. Keys should be unique so that components maintain their identity across updates. Non-unique keys may cause children to be duplicated and/or omitted — the behavior is unsupported and could change in a future version.

�[90mstderr�[2m | src/components/RepositorySettingsBar.test.tsx�[2m > �[22m�[2mRepositorySettingsBar detected workflows�[2m > �[22m�[2mrecognizes and deselects a padded display name with triggers [ 'push' ]
�[22m�[39mEncountered two children with the same key, `repo-1`. Keys should be unique so that components maintain their identity across updates. Non-unique keys may cause children to be duplicated and/or omitted — the behavior is unsupported and could change in a future version.

�[90mstderr�[2m | src/components/RepositorySettingsBar.test.tsx�[2m > �[22m�[2mRepositorySettingsBar detected workflows�[2m > �[22m�[2mrecognizes and deselects a padded display name with triggers null
�[22m�[39mEncountered two children with the same key, `repo-1`. Keys should be unique so that components maintain their identity across updates. Non-unique keys may cause children to be duplicated and/or omitted — the behavior is unsupported and could change in a future version.

�[90mstderr�[2m | src/components/RepositorySettingsBar.test.tsx�[2m > �[22m�[2mRepositorySettingsBar detected workflows�[2m > �[22m�[2mpreserves a normalized display name when removing unavailable selections after discovery
�[22m�[39mEncountered two children with the same key, `repo-1`. Keys should be unique so that components maintain their identity across updates. Non-unique keys may cause children to be duplicated and/or omitted — the behavior is unsupported and could change in a future version.

�[90mstderr�[2m | src/components/RepositorySettingsBar.test.tsx�[2m > �[22m�[2mRepositorySettingsBar detected workflows�[2m > �[22m�[2moffers the repository workflows and matches stored entries by any identity
�[22m�[39mEncountered two children with the same key, `repo-1`. Keys should be unique so that components maintain their identity across updates. Non-unique keys may cause children to be duplicated and/or omitted — the behavior is unsupported and could change in a future version.

�[90mstderr�[2m | src/components/RepositorySettingsBar.test.tsx�[2m > �[22m�[2mRepositorySettingsBar detected workflows�[2m > �[22m�[2mallows manual identities outside a cached listing and keeps checkbox edits in sync
�[22m�[39mEncountered two children with the same key, `repo-1`. Keys should be unique so that components maintain their identity across updates. Non-unique keys may cause children to be duplicated and/or omitted — the behavior is unsupported and could change in a future version.

�[90mstderr�[2m | src/components/RepositorySettingsBar.test.tsx�[2m > �[22m�[2mRepositorySettingsBar detected workflows�[2m > �[22m�[2mallows manual identities outside a cached listing and keeps checkbox edits in sync
�[22m�[39mEncountered two children with the same key, `repo-1`. Keys should be unique so that components maintain their identity across updates. Non-unique keys may cause children to be duplicated and/or omitted — the behavior is unsupported and could change in a future version.

�[90mstderr�[2m | src/components/RepositorySettingsBar.test.tsx�[2m > �[22m�[2mRepositorySettingsBar detected workflows�[2m > �[22m�[2mpreserves manual input across a successful populated discovery without saving it
�[22m�[39mEncountered two children with the same key, `repo-1`. Keys should be unique so that components maintain their identity across updates. Non-unique keys may cause children to be duplicated and/or omitted — the behavior is unsupported and could change in a future version.

�[90mstderr�[2m | src/components/RepositorySettingsBar.test.tsx�[2m > �[22m�[2mRepositorySettingsBar detected workflows�[2m > �[22m�[2mpreserves manual input across a successful empty discovery without saving it
�[22m�[39mEncountered two children with the same key, `repo-1`. Keys should be unique so that components maintain their identity across updates. Non-unique keys may cause children to be duplicated and/or omitted — the behavior is unsupported and could change in a future version.

�[90mstdout�[2m | src/hooks/useHeaderStats.recovery.test.tsx�[2m > �[22m�[2museHeaderStats live recovery�[2m > �[22m�[2mcommits untouched initial resources when a partial live refresh supersedes queue
�[22m�[39m[useHeaderStats] Received changed queue stats, scheduling stats refresh

�[90mstderr�[2m | src/components/RepositorySettingsBar.test.tsx�[2m > �[22m�[2mRepositorySettingsBar detected workflows�[2m > �[22m�[2mstores a picked workflow by file name and removes every spelling of an unpicked one
�[22m�[39mEncountered two children with the same key, `repo-1`. Keys should be unique so that components maintain their identity across updates. Non-unique keys may cause children to be duplicated and/or omitted — the behavior is unsupported and could change in a future version.

�[90mstderr�[2m | src/components/RepositorySettingsBar.test.tsx�[2m > �[22m�[2mRepositorySettingsBar detected workflows�[2m > �[22m�[2mflags stored entries that match no workflow in the repository
�[22m�[39mEncountered two children with the same key, `repo-1`. Keys should be unique so that components maintain their identity across updates. Non-unique keys may cause children to be duplicated and/or omitted — the behavior is unsupported and could change in a future version.

�[90mstderr�[2m | src/components/RepositorySettingsBar.test.tsx�[2m > �[22m�[2mRepositorySettingsBar detected workflows�[2m > �[22m�[2mflags a stored selection only after an empty listing successfully loads
�[22m�[39mEncountered two children with the same key, `repo-1`. Keys should be unique so that components maintain their identity across updates. Non-unique keys may cause children to be duplicated and/or omitted — the behavior is unsupported and could change in a future version.

�[90mstderr�[2m | src/components/RepositorySettingsBar.test.tsx�[2m > �[22m�[2mRepositorySettingsBar detected workflows�[2m > �[22m�[2mdoes not flag an empty selection after an empty listing successfully loads
�[22m�[39mEncountered two children with the same key, `repo-1`. Keys should be unique so that components maintain their identity across updates. Non-unique keys may cause children to be duplicated and/or omitted — the behavior is unsupported and could change in a future version.

�[90mstderr�[2m | src/components/RepositorySettingsBar.test.tsx�[2m > �[22m�[2mRepositorySettingsBar detected workflows�[2m > �[22m�[2mfalls back to typing workflows when GitHub cannot list them
�[22m�[39mEncountered two children with the same key, `repo-1`. Keys should be unique so that components maintain their identity across updates. Non-unique keys may cause children to be duplicated and/or omitted — the behavior is unsupported and could change in a future version.

�[90mstderr�[2m | src/components/RepositorySettingsBar.test.tsx�[2m > �[22m�[2mRepositorySettingsBar detected workflows�[2m > �[22m�[2mdoes not ask GitHub for workflows while the option is off
�[22m�[39mEncountered two children with the same key, `repo-1`. Keys should be unique so that components maintain their identity across updates. Non-unique keys may cause children to be duplicated and/or omitted — the behavior is unsupported and could change in a future version.

�[90mstderr�[2m | src/components/RepositorySettingsBar.test.tsx�[2m > �[22m�[2mRepositorySettingsBar non-blocking checks�[2m > �[22m�[2mshows the stored checks and saves an edited list on blur
�[22m�[39mEncountered two children with the same key, `repo-1`. Keys should be unique so that components maintain their identity across updates. Non-unique keys may cause children to be duplicated and/or omitted — the behavior is unsupported and could change in a future version.

�[90mstderr�[2m | src/components/RepositorySettingsBar.test.tsx�[2m > �[22m�[2mRepositorySettingsBar non-blocking checks�[2m > �[22m�[2mdoes not save unchanged or malformed input
�[22m�[39mEncountered two children with the same key, `repo-1`. Keys should be unique so that components maintain their identity across updates. Non-unique keys may cause children to be duplicated and/or omitted — the behavior is unsupported and could change in a future version.

 �[32m✓�[39m src/components/RepositorySettingsBar.test.tsx �[2m(�[22m�[2m25 tests�[22m�[2m)�[22m�[33m 1668�[2mms�[22m�[39m
�[90mstdout�[2m | src/hooks/useHeaderStats.recovery.test.tsx�[2m > �[22m�[2museHeaderStats live recovery�[2m > �[22m�[2mreconciles a successful completion to zero from the queue subscription
�[22m�[39m[useHeaderStats] Received changed queue stats, scheduling stats refresh

�[90mstdout�[2m | src/hooks/useHeaderStats.recovery.test.tsx�[2m > �[22m�[2museHeaderStats live recovery�[2m > �[22m�[2mrefreshes only queue activity and bounds identical periodic invalidations
�[22m�[39m[useHeaderStats] Received changed queue stats, scheduling stats refresh

�[90mstdout�[2m | src/hooks/useHeaderStats.recovery.test.tsx�[2m > �[22m�[2museHeaderStats live recovery�[2m > �[22m�[2mretries only a failed queue reconciliation and commits its fingerprint after recovery
�[22m�[39m[useHeaderStats] Received changed queue stats, scheduling stats refresh

�[90mstdout�[2m | src/hooks/useHeaderStats.recovery.test.tsx�[2m > �[22m�[2museHeaderStats live recovery�[2m > �[22m�[2mdefers hidden-tab churn and performs one full visible recovery
�[22m�[39m[useHeaderStats] Received changed queue stats, scheduling stats refresh

�[90mstdout�[2m | src/hooks/useHeaderStats.recovery.test.tsx�[2m > �[22m�[2museHeaderStats live recovery�[2m > �[22m�[2mrevalidates missed same-count draft and health changes after a web reconnect
�[22m�[39m[useHeaderStats] Received changed queue stats, scheduling stats refresh

�[90mstdout�[2m | src/hooks/useHeaderStats.recovery.test.tsx�[2m > �[22m�[2museHeaderStats live recovery�[2m > �[22m�[2mrevalidates missed same-count draft and health changes after a web reconnect
�[22m�[39m[useHeaderStats] Received changed queue stats, scheduling stats refresh

 �[32m✓�[39m src/hooks/useHeaderStats.recovery.test.tsx �[2m(�[22m�[2m11 tests�[22m�[2m)�[22m�[33m 1422�[2mms�[22m�[39m
   �[32m✓�[39m useHeaderStats live recovery �[2m(11)�[22m
     �[33m�[2m✓�[22m�[39m refreshes only queue activity and bounds identical periodic invalidations�[33m 308�[2mms�[22m�[39m
     �[33m�[2m✓�[22m�[39m revalidates missed same-count draft and health changes after a web reconnect�[33m 310�[2mms�[22m�[39m
�[90mstderr�[2m | src/components/TaskPlanner/SetupWizard.test.tsx�[2m > �[22m�[2mSetupWizard�[2m > �[22m�[2mignores stale repo switches in edit mode when a newer selection finishes first
�[22m�[39mAn update to SetupWizard inside a test was not wrapped in act(...).

When testing, code that causes React state updates should be wrapped into act(...):

act(() => {
  /* fire events that update state */
});
/* assert on the output */

This ensures that you're testing the behavior the user would see in the browser. Learn more at https://react.dev/link/wrap-tests-with-act
An update to SetupWizard inside a test was not wrapped in act(...).

When testing, code that causes React state updates should be wrapped into act(...):

act(() => {
  /* fire events that update state */
});
/* assert on the output */

This ensures that you're testing the behavior the user would see in the browser. Learn more at https://react.dev/link/wrap-tests-with-act
An update to SetupWizard inside a test was not wrapped in act(...).

When testing, code that causes React state updates should be wrapped into act(...):

act(() => {
  /* fire events that update state */
});
/* assert on the output */

This ensures that you're testing the behavior the user would see in the browser. Learn more at https://react.dev/link/wrap-tests-with-act
An update to SetupWizard inside a test was not wrapped in act(...).

When testing, code that causes React state updates should be wrapped into act(...):

act(() => {
  /* fire events that update state */
});
/* assert on the output */

This ensures that you're testing the behavior the user would see in the browser. Learn more at https://react.dev/link/wrap-tests-with-act

 �[32m✓�[39m src/components/TaskPlanner/SetupWizard.test.tsx �[2m(�[22m�[2m13 tests�[22m�[2m)�[22m�[33m 349�[2mms�[22m�[39m
�[90mstdout�[2m | src/hooks/useCurrentUserBootstrap.test.tsx�[2m > �[22m�[2mdesktop current-user bootstrap�[2m > �[22m�[2mmounts an active scope at generation one and enables exactly one stable Manager after current validation
�[22m�[39m[SocketContext] Cleaning up socket connection

�[90mstdout�[2m | src/hooks/useCurrentUserBootstrap.test.tsx�[2m > �[22m�[2mdesktop current-user bootstrap�[2m > �[22m�[2moverlaps validation with demo-mode loading but keeps Manager disabled until mode resolves in StrictMode
�[22m�[39m[SocketContext] Cleaning up socket connection

�[90mstdout�[2m | src/hooks/useCurrentUserBootstrap.test.tsx�[2m > �[22m�[2mdesktop current-user bootstrap�[2m > �[22m�[2mconstructs once after activated validation and removes that Manager when revalidation fails
�[22m�[39m[SocketContext] Cleaning up socket connection

 �[32m✓�[39m src/hooks/useCurrentUserBootstrap.test.tsx �[2m(�[22m�[2m8 tests�[22m�[2m)�[22m�[33m 311�[2mms�[22m�[39m
 �[32m✓�[39m src/pages/AiAgentsPage.test.tsx �[2m(�[22m�[2m11 tests�[22m�[2m)�[22m�[33m 2693�[2mms�[22m�[39m
   �[32m✓�[39m AiAgentsPage model selection �[2m(11)�[22m
     �[33m�[2m✓�[22m�[39m places each desktop header and content region in the same resizable pane�[33m 521�[2mms�[22m�[39m
     �[33m�[2m✓�[22m�[39m replaces Playground selections with the exact enabled agent/model pair and opens the mobile Playground�[33m 680�[2mms�[22m�[39m
     �[33m�[2m✓�[22m�[39m sends the stable synthetic configuration ID and virtual model from the Playground�[33m 328�[2mms�[22m�[39m
�[90mstderr�[2m | src/components/MobileBottomNavigation.test.tsx�[2m > �[22m�[2mMobileBottomNavigation�[2m > �[22m�[2mkeeps all creation options inert in demo mode on /
�[22m�[39mAn update to AgentTankSidebar inside a test was not wrapped in act(...).

When testing, code that causes React state updates should be wrapped into act(...):

act(() => {
  /* fire events that update state */
});
/* assert on the output */

This ensures that you're testing the behavior the user would see in the browser. Learn more at https://react.dev/link/wrap-tests-with-act

�[90mstderr�[2m | src/components/MobileBottomNavigation.test.tsx�[2m > �[22m�[2mMobileBottomNavigation�[2m > �[22m�[2mkeeps all creation options inert in demo mode on /
�[22m�[39mAn update to AgentTankSidebar inside a test was not wrapped in act(...).

When testing, code that causes React state updates should be wrapped into act(...):

act(() => {
  /* fire events that update state */
});
/* assert on the output */

This ensures that you're testing the behavior the user would see in the browser. Learn more at https://react.dev/link/wrap-tests-with-act

�[90mstderr�[2m | src/components/MobileBottomNavigation.test.tsx�[2m > �[22m�[2mMobileBottomNavigation�[2m > �[22m�[2mkeeps all creation options inert in demo mode on /plans
�[22m�[39mAn update to AgentTankSidebar inside a test was not wrapped in act(...).

When testing, code that causes React state updates should be wrapped into act(...):

act(() => {
  /* fire events that update state */
});
/* assert on the output */

This ensures that you're testing the behavior the user would see in the browser. Learn more at https://react.dev/link/wrap-tests-with-act

�[90mstderr�[2m | src/components/MobileBottomNavigation.test.tsx�[2m > �[22m�[2mMobileBottomNavigation�[2m > �[22m�[2mkeeps all creation options inert in demo mode on /plans
�[22m�[39mAn update to AgentTankSidebar inside a test was not wrapped in act(...).

When testing, code that causes React state updates should be wrapped into act(...):

act(() => {
  /* fire events that update state */
});
/* assert on the output */

This ensures that you're testing the behavior the user would see in the browser. Learn more at https://react.dev/link/wrap-tests-with-act

�[90mstderr�[2m | src/components/MobileBottomNavigation.test.tsx�[2m > �[22m�[2mMobileBottomNavigation�[2m > �[22m�[2mkeeps all creation options inert in demo mode on /goals
�[22m�[39mAn update to AgentTankSidebar inside a test was not wrapped in act(...).

When testing, code that causes React state updates should be wrapped into act(...):

act(() => {
  /* fire events that update state */
});
/* assert on the output */

This ensures that you're testing the behavior the user would see in the browser. Learn more at https://react.dev/link/wrap-tests-with-act

�[90mstderr�[2m | src/components/MobileBottomNavigation.test.tsx�[2m > �[22m�[2mMobileBottomNavigation�[2m > �[22m�[2mkeeps all creation options inert in demo mode on /goals
�[22m�[39mAn update to AgentTankSidebar inside a test was not wrapped in act(...).

When testing, code that causes React state updates should be wrapped into act(...):

act(() => {
  /* fire events that update state */
});
/* assert on the output */

This ensures that you're testing the behavior the user would see in the browser. Learn more at https://react.dev/link/wrap-tests-with-act

�[90mstderr�[2m | src/components/MobileBottomNavigation.test.tsx�[2m > �[22m�[2mMobileBottomNavigation�[2m > �[22m�[2mhides the MCP log without the settings permission
�[22m�[39mAn update to AgentTankSidebar inside a test was not wrapped in act(...).

When testing, code that causes React state updates should be wrapped into act(...):

act(() => {
  /* fire events that update state */
});
/* assert on the output */

This ensures that you're testing the behavior the user would see in the browser. Learn more at https://react.dev/link/wrap-tests-with-act

�[90mstderr�[2m | src/components/MobileBottomNavigation.test.tsx�[2m > �[22m�[2mMobileBottomNavigation�[2m > �[22m�[2mhides the MCP log without the settings permission
�[22m�[39mAn update to AgentTankSidebar inside a test was not wrapped in act(...).

When testing, code that causes React state updates should be wrapped into act(...):

act(() => {
  /* fire events that update state */
});
/* assert on the output */

This ensures that you're testing the behavior the user would see in the browser. Learn more at https://react.dev/link/wrap-tests-with-act

�[90mstderr�[2m | src/components/MobileBottomNavigation.test.tsx�[2m > �[22m�[2mMobileBottomNavigation�[2m > �[22m�[2mhides Access without member management permission
�[22m�[39mAn update to AgentTankSidebar inside a test was not wrapped in act(...).

When testing, code that causes React state updates should be wrapped into act(...):

act(() => {
  /* fire events that update state */
});
/* assert on the output */

This ensures that you're testing the behavior the user would see in the browser. Learn more at https://react.dev/link/wrap-tests-with-act

�[90mstderr�[2m | src/components/MobileBottomNavigation.test.tsx�[2m > �[22m�[2mMobileBottomNavigation�[2m > �[22m�[2mhides Access without member management permission
�[22m�[39mAn update to AgentTankSidebar inside a test was not wrapped in act(...).

When testing, code that causes React state updates should be wrapped into act(...):

act(() => {
  /* fire events that update state */
});
/* assert on the output */

This ensures that you're testing the behavior the user would see in the browser. Learn more at https://react.dev/link/wrap-tests-with-act

�[90mstderr�[2m | src/components/MobileBottomNavigation.test.tsx�[2m > �[22m�[2mMobileBottomNavigation�[2m > �[22m�[2msigns out from the identity section
�[22m�[39mAn update to AgentTankSidebar inside a test was not wrapped in act(...).

When testing, code that causes React state updates should be wrapped into act(...):

act(() => {
  /* fire events that update state */
});
/* assert on the output */

This ensures that you're testing the behavior the user would see in the browser. Learn more at https://react.dev/link/wrap-tests-with-act

�[90mstderr�[2m | src/components/MobileBottomNavigation.test.tsx�[2m > �[22m�[2mMobileBottomNavigation�[2m > �[22m�[2msigns out from the identity section
�[22m�[39mAn update to AgentTankSidebar inside a test was not wrapped in act(...).

When testing, code that causes React state updates should be wrapped into act(...):

act(() => {
  /* fire events that update state */
});
/* assert on the output */

This ensures that you're testing the behavior the user would see in the browser. Learn more at https://react.dev/link/wrap-tests-with-act

 �[32m✓�[39m src/components/MobileBottomNavigation.test.tsx �[2m(�[22m�[2m26 tests�[22m�[2m)�[22m�[33m 1900�[2mms�[22m�[39m
   �[32m✓�[39m MobileBottomNavigation �[2m(26)�[22m
     �[33m�[2m✓�[22m�[39m matches the primary action and More options to /�[33m 325�[2mms�[22m�[39m
 �[32m✓�[39m src/components/VoiceBriefingControl.test.tsx �[2m(�[22m�[2m14 tests�[22m�[2m)�[22m�[33m 809�[2mms�[22m�[39m
 �[32m✓�[39m src/pages/inboxUtils.test.ts �[2m(�[22m�[2m25 tests�[22m�[2m)�[22m�[32m 26�[2mms�[22m�[39m
�[90mstderr�[2m | src/components/TaskPlanner/useAutoDraftCreation.test.tsx�[2m > �[22m�[2museAutoDraftCreation�[2m > �[22m�[2mkeeps navigating when persisting the resolved baseBranch fails after auto-creating a draft
�[22m�[39mFailed to persist draft setup snapshot: Error: Transient update failure
    at �[90m/home/runner/work/propr/propr/propr-ui/�[39msrc/components/TaskPlanner/useAutoDraftCreation.test.tsx:103:39
    at file:///home/runner/work/propr/propr/node_modules/�[4mvitest�[24m/dist/chunks/run.CQOUYP-x.js:1628:35
    at file:///home/runner/work/propr/propr/node_modules/�[4mvitest�[24m/dist/chunks/run.CQOUYP-x.js:2783:26
    at file:///home/runner/work/propr/propr/node_modules/�[4mvitest�[24m/dist/chunks/run.CQOUYP-x.js:3319:20
    at new Promise (<anonymous>)
    at runWithCancel (file:///home/runner/work/propr/propr/node_modules/�[4mvitest�[24m/dist/chunks/run.CQOUYP-x.js:3314:10)
    at file:///home/runner/work/propr/propr/node_modules/�[4mvitest�[24m/dist/chunks/run.CQOUYP-x.js:3299:20
    at new Promise (<anonymous>)
    at runWithTimeout (file:///home/runner/work/propr/propr/node_modules/�[4mvitest�[24m/dist/chunks/run.CQOUYP-x.js:3257:10)
    at file:///home/runner/work/propr/propr/node_modules/�[4mvitest�[24m/dist/chunks/run.CQOUYP-x.js:3876:64

�[90mstderr�[2m | src/components/TaskPlanner/useAutoDraftCreation.test.tsx�[2m > �[22m�[2museAutoDraftCreation�[2m > �[22m�[2msurfaces the persistence warning only for in-place auto-created drafts
�[22m�[39mFailed to persist draft setup snapshot: Error: Transient update failure
    at �[90m/home/runner/work/propr/propr/propr-ui/�[39msrc/components/TaskPlanner/useAutoDraftCreation.test.tsx:268:39
    at file:///home/runner/work/propr/propr/node_modules/�[4mvitest�[24m/dist/chunks/run.CQOUYP-x.js:1628:35
    at file:///home/runner/work/propr/propr/node_modules/�[4mvitest�[24m/dist/chunks/run.CQOUYP-x.js:2783:26
    at file:///home/runner/work/propr/propr/node_modules/�[4mvitest�[24m/dist/chunks/run.CQOUYP-x.js:3319:20
    at new Promise (<anonymous>)
    at runWithCancel (file:///home/runner/work/propr/propr/node_modules/�[4mvitest�[24m/dist/chunks/run.CQOUYP-x.js:3314:10)
    at file:///home/runner/work/propr/propr/node_modules/�[4mvitest�[24m/dist/chunks/run.CQOUYP-x.js:3299:20
    at new Promise (<anonymous>)
    at runWithTimeout (file:///home/runner/work/propr/propr/node_modules/�[4mvitest�[24m/dist/chunks/run.CQOUYP-x.js:3257:10)
    at file:///home/runner/work/propr/propr/node_modules/�[4mvitest�[24m/dist/chunks/run.CQOUYP-x.js:3876:64

 �[32m✓�[39m src/components/TaskPlanner/useAutoDraftCreation.test.tsx �[2m(�[22m�[2m11 tests�[22m�[2m)�[22m�[32m 76�[2mms�[22m�[39m
 �[32m✓�[39m src/components/GlobalHeader.desktop.test.tsx �[2m(�[22m�[2m15 tests�[22m�[2m)�[22m�[33m 1094�[2mms�[22m�[39m
   �[32m✓�[39m GlobalHeader desktop toolbar �[2m(15)�[22m
     �[33m�[2m✓�[22m�[39m uses the route action and remaining menu options on /�[33m 327�[2mms�[22m�[39m
 �[32m✓�[39m src/components/Layout.desktop.test.tsx �[2m(�[22m�[2m8 tests�[22m�[2m)�[22m�[33m 1102�[2mms�[22m�[39m
   �[32m✓�[39m Layout desktop instance selector �[2m(8)�[22m
     �[33m�[2m✓�[22m�[39m keeps version and copyright on web but out of the desktop sidebar�[33m 393�[2mms�[22m�[39m
 �[32m✓�[39m src/desktop/nativeCommands.integration.test.tsx �[2m(�[22m�[2m12 tests�[22m�[2m)�[22m�[32m 264�[2mms�[22m�[39m
�[90mstdout�[2m | src/hooks/useHeaderStats.push.test.tsx�[2m > �[22m�[2museHeaderStats pushed changes�[2m > �[22m�[2mdoes not re-read the queue for its subscription snapshot
�[22m�[39m[useHeaderStats] Received changed queue stats, scheduling stats refresh

 �[32m✓�[39m src/hooks/useContextRefresh.test.tsx �[2m(�[22m�[2m8 tests�[22m�[2m)�[22m�[32m 52�[2mms�[22m�[39m
 �[32m✓�[39m src/hooks/useHeaderStats.push.test.tsx �[2m(�[22m�[2m6 tests�[22m�[2m)�[22m�[33m 1365�[2mms�[22m�[39m
   �[32m✓�[39m useHeaderStats pushed changes �[2m(6)�[22m
     �[33m�[2m✓�[22m�[39m reads system status when indexing or capacity changes, and nothing else�[33m 360�[2mms�[22m�[39m
     �[33m�[2m✓�[22m�[39m ignores a repeated pushed state for a task it already reconciled�[33m 409�[2mms�[22m�[39m
     �[33m�[2m✓�[22m�[39m reconciles exactly once per reconnect transition�[33m 306�[2mms�[22m�[39m
�[90mstderr�[2m | src/pages/SettingsPage/AgentConfigModal.test.tsx�[2m > �[22m�[2mAgentConfigModal�[2m > �[22m�[2madds a loginable agent with an isolated managed credential path and requests login
�[22m�[39mAn update to AgentConfigModal inside a test was not wrapped in act(...).

When testing, code that causes React state updates should be wrapped into act(...):

act(() => {
  /* fire events that update state */
});
/* assert on the output */

This ensures that you're testing the behavior the user would see in the browser. Learn more at https://react.dev/link/wrap-tests-with-act
An update to AgentConfigModal inside a test was not wrapped in act(...).

When testing, code that causes React state updates should be wrapped into act(...):

act(() => {
  /* fire events that update state */
});
/* assert on the output */

This ensures that you're testing the behavior the user would see in the browser. Learn more at https://react.dev/link/wrap-tests-with-act
An update to AgentConfigModal inside a test was not wrapped in act(...).

When testing, code that causes React state updates should be wrapped into act(...):

act(() => {
  /* fire events that update state */
});
/* assert on the output */

This ensures that you're testing the behavior the user would see in the browser. Learn more at https://react.dev/link/wrap-tests-with-act
An update to AgentConfigModal inside a test was not wrapped in act(...).

When testing, code that causes React state updates should be wrapped into act(...):

act(() => {
  /* fire events that update state */
});
/* assert on the output */

This ensures that you're testing the behavior the user would see in the browser. Learn more at https://react.dev/link/wrap-tests-with-act
An update to AgentConfigModal inside a test was not wrapped in act(...).

When testing, code that causes React state updates should be wrapped into act(...):

act(() => {
  /* fire events that update state */
});
/* assert on the output */

This ensures that you're testing the behavior the user would see in the browser. Learn more at https://react.dev/link/wrap-tests-with-act

�[90mstderr�[2m | src/pages/SettingsPage/AgentConfigModal.test.tsx�[2m > �[22m�[2mAgentConfigModal�[2m > �[22m�[2mallows a new agent to reuse an existing config directory instead of logging in
�[22m�[39mAn update to AgentConfigModal inside a test was not wrapped in act(...).

When testing, code that causes React state updates should be wrapped into act(...):

act(() => {
  /* fire events that update state */
});
/* assert on the output */

This ensures that you're testing the behavior the user would see in the browser. Learn more at https://react.dev/link/wrap-tests-with-act
An update to AgentConfigModal inside a test was not wrapped in act(...).

When testing, code that causes React state updates should be wrapped into act(...):

act(() => {
  /* fire events that update state */
});
/* assert on the output */

This ensures that you're testing the behavior the user would see in the browser. Learn more at https://react.dev/link/wrap-tests-with-act

�[90mstderr�[2m | src/pages/SettingsPage/AgentConfigModal.test.tsx�[2m > �[22m�[2mAgentConfigModal�[2m > �[22m�[2muses the agent alias in long model labels
�[22m�[39mAn update to AgentConfigModal inside a test was not wrapped in act(...).

When testing, code that causes React state updates should be wrapped into act(...):

act(() => {
  /* fire events that update state */
});
/* assert on the output */

This ensures that you're testing the behavior the user would see in the browser. Learn more at https://react.dev/link/wrap-tests-with-act
An update to AgentConfigModal inside a test was not wrapped in act(...).

When testing, code that causes React state updates should be wrapped into act(...):

act(() => {
  /* fire events that update state */
});
/* assert on the output */

This ensures that you're testing the behavior the user would see in the browser. Learn more at https://react.dev/link/wrap-tests-with-act
An update to AgentConfigModal inside a test was not wrapped in act(...).

When testing, code that causes React state updates should be wrapped into act(...):

act(() => {
  /* fire events that update state */
});
/* assert on the output */

This ensures that you're testing the behavior the user would see in the browser. Learn more at https://react.dev/link/wrap-tests-with-act
An update to AgentConfigModal inside a test was not wrapped in act(...).

When testing, code that causes React state updates should be wrapped into act(...):

act(() => {
  /* fire events that update state */
});
/* assert on the output */

This ensures that you're testing the behavior the user would see in the browser. Learn more at https://react.dev/link/wrap-tests-with-act

�[90mstderr�[2m | src/pages/SettingsPage/AgentConfigModal.test.tsx�[2m > �[22m�[2mAgentConfigModal�[2m > �[22m�[2msaves a model-specific reasoning level for Codex agents
�[22m�[39mAn update to AgentConfigModal inside a test was not wrapped in act(...).

When testing, code that causes React state updates should be wrapped into act(...):

act(() => {
  /* fire events that update state */
});
/* assert on the output */

This ensures that you're testing the behavior the user would see in the browser. Learn more at https://react.dev/link/wrap-tests-with-act
An update to AgentConfigModal inside a test was not wrapped in act(...).

When testing, code that causes React state updates should be wrapped into act(...):

act(() => {
  /* fire events that update state */
});
/* assert on the output */

This ensures that you're testing the behavior the user would see in the browser. Learn more at https://react.dev/link/wrap-tests-with-act
An update to AgentConfigModal inside a test was not wrapped in act(...).

When testing, code that causes React state updates should be wrapped into act(...):

act(() => {
  /* fire events that update state */
});
/* assert on the output */

This ensures that you're testing the behavior the user would see in the browser. Learn more at https://react.dev/link/wrap-tests-with-act
An update to AgentConfigModal inside a test was not wrapped in act(...).

When testing, code that causes React state updates should be wrapped into act(...):

act(() => {
  /* fire events that update state */
});
/* assert on the output */

This ensures that you're testing the behavior the user would see in the browser. Learn more at https://react.dev/link/wrap-tests-with-act

�[90mstderr�[2m | src/pages/SettingsPage/AgentConfigModal.test.tsx�[2m > �[22m�[2mAgentConfigModal�[2m > �[22m�[2mmarks a legacy cross-agent reasoning value as unsupported
�[22m�[39mAn update to AgentConfigModal inside a test was not wrapped in act(...).

When testing, code that causes React state updates should be wrapped into act(...):

act(() => {
  /* fire events that update state */
});
/* assert on the output */

This ensures that you're testing the behavior the user would see in the browser. Learn more at https://react.dev/link/wrap-tests-with-act
An update to AgentConfigModal inside a test was not wrapped in act(...).

When testing, code that causes React state updates should be wrapped into act(...):

act(() => {
  /* fire events that update state */
});
/* assert on the output */

This ensures that you're testing the behavior the user would see in the browser. Learn more at https://react.dev/link/wrap-tests-with-act
An update to AgentConfigModal inside a test was not wrapped in act(...).

When testing, code that causes React state updates should be wrapped into act(...):

act(() => {
  /* fire events that update state */
});
/* assert on the output */

This ensures that you're testing the behavior the user would see in the browser. Learn more at https://react.dev/link/wrap-tests-with-act
An update to AgentConfigModal inside a test was not wrapped in act(...).

When testing, code that causes React state updates should be wrapped into act(...):

act(() => {
  /* fire events that update state */
});
/* assert on the output */

This ensures that you're testing the behavior the user would see in the browser. Learn more at https://react.dev/link/wrap-tests-with-act

 �[32m✓�[39m src/pages/SettingsPage/AgentConfigModal.test.tsx �[2m(�[22m�[2m7 tests�[22m�[2m)�[22m�[33m 1355�[2mms�[22m�[39m
   �[32m✓�[39m AgentConfigModal �[2m(7)�[22m
     �[33m�[2m✓�[22m�[39m adds a loginable agent with an isolated managed credential path and requests login�[33m 482�[2mms�[22m�[39m
 �[32m✓�[39m src/components/ApplicationShell.idle.test.tsx �[2m(�[22m�[2m2 tests�[22m�[2m)�[22m�[32m 78�[2mms�[22m�[39m
 �[32m✓�[39m src/desktop-deep-link.test.ts �[2m(�[22m�[2m9 tests�[22m�[2m)�[22m�[32m 15�[2mms�[22m�[39m
 �[32m✓�[39m src/pages/SettingsPage/NotificationSettingsSection.test.tsx �[2m(�[22m�[2m7 tests�[22m�[2m)�[22m�[33m 1229�[2mms�[22m�[39m
 �[32m✓�[39m src/components/QuickAddTodo.test.tsx �[2m(�[22m�[2m9 tests�[22m�[2m)�[22m�[33m 3066�[2mms�[22m�[39m
   �[32m✓�[39m QuickAddTodo popover �[2m(2)�[22m
     �[33m�[2m✓�[22m�[39m keeps the success confirmation and Add another available until dismissed�[33m 548�[2mms�[22m�[39m
     �[33m�[2m✓�[22m�[39m resets content and category, retains the submitted repository, focuses and submits again�[33m 369�[2mms�[22m�[39m
   �[32m✓�[39m QuickAddTodo inline �[2m(2)�[22m
     �[33m�[2m✓�[22m�[39m resets content and category, retains the submitted repository, focuses and submits again�[33m 337�[2mms�[22m�[39m
   �[33m�[2m✓�[22m�[39m uses the normal repository fallback: acme/gamma�[33m 307�[2mms�[22m�[39m
   �[33m�[2m✓�[22m�[39m uses the normal repository fallback: acme/alpha�[33m 365�[2mms�[22m�[39m
   �[33m�[2m✓�[22m�[39m uses the normal repository fallback: acme/gamma�[33m 378�[2mms�[22m�[39m
   �[33m�[2m✓�[22m�[39m uses the normal repository fallback: null�[33m 305�[2mms�[22m�[39m
 �[32m✓�[39m src/api/currentUserResponse.test.ts �[2m(�[22m�[2m5 tests�[22m�[2m)�[22m�[32m 15�[2mms�[22m�[39m
 �[32m✓�[39m src/pages/SettingsPage/AgentRuntimePackagesSection.test.tsx �[2m(�[22m�[2m6 tests�[22m�[2m)�[22m�[33m 755�[2mms�[22m�[39m
   �[32m✓�[39m AgentRuntimePackagesSection �[2m(6)�[22m
     �[33m�[2m✓�[22m�[39m adds a package and submits the complete desired profile�[33m 326�[2mms�[22m�[39m
     �[33m�[2m✓�[22m�[39m offers catalog suggestions and validates a selected package�[33m 361�[2mms�[22m�[39m
 �[32m✓�[39m src/components/TaskPlanner/PlanIssuesManager.notificationIntent.test.tsx �[2m(�[22m�[2m3 tests�[22m�[2m)�[22m�[33m 685�[2mms�[22m�[39m
   �[32m✓�[39m PlanIssuesManager execution intent �[2m(3)�[22m
     �[33m�[2m✓�[22m�[39m cancel closes without starting implementation�[33m 372�[2mms�[22m�[39m
 �[32m✓�[39m src/components/TaskPlanner/PlanEditor.notificationIntent.test.tsx �[2m(�[22m�[2m4 tests�[22m�[2m)�[22m�[33m 653�[2mms�[22m�[39m
   �[32m✓�[39m PlanEditor notification intents �[2m(4)�[22m
     �[33m�[2m✓�[22m�[39m never approves from navigation and cancel leaves the plan unchanged�[33m 596�[2mms�[22m�[39m
 �[32m✓�[39m src/hooks/useCurrentUserBootstrap.mainProxy.test.tsx �[2m(�[22m�[2m1 test�[22m�[2m)�[22m�[32m 88�[2mms�[22m�[39m
 �[32m✓�[39m src/desktop/packagedAcceptanceRendererLifecycle.test.ts �[2m(�[22m�[2m3 tests�[22m�[2m)�[22m�[32m 9�[2mms�[22m�[39m
 �[32m✓�[39m src/components/TaskPlanner/planIssueDefaultSelection.test.ts �[2m(�[22m�[2m5 tests�[22m�[2m)�[22m�[32m 10�[2mms�[22m�[39m
 �[32m✓�[39m src/components/TaskDetails/TaskVisualPreviews.test.tsx �[2m(�[22m�[2m4 tests�[22m�[2m)�[22m�[33m 341�[2mms�[22m�[39m
 �[32m✓�[39m src/api/dashboardApi.test.ts �[2m(�[22m�[2m3 tests�[22m�[2m)�[22m�[32m 22�[2mms�[22m�[39m
 �[32m✓�[39m src/pages/SettingsPage/VoiceSettingsSection.test.tsx �[2m(�[22m�[2m4 tests�[22m�[2m)�[22m�[33m 331�[2mms�[22m�[39m
 �[32m✓�[39m src/desktop/DesktopExperience.accounts.test.tsx �[2m(�[22m�[2m3 tests�[22m�[2m)�[22m�[33m 517�[2mms�[22m�[39m
 �[32m✓�[39m src/components/TaskPlanner/planDisplayName.test.ts �[2m(�[22m�[2m12 tests�[22m�[2m)�[22m�[32m 11�[2mms�[22m�[39m
 �[32m✓�[39m src/components/TaskList/displayTitles.test.ts �[2m(�[22m�[2m7 tests�[22m�[2m)�[22m�[32m 11�[2mms�[22m�[39m
 �[32m✓�[39m src/components/UserAvatar.test.tsx �[2m(�[22m�[2m2 tests�[22m�[2m)�[22m�[32m 277�[2mms�[22m�[39m
 �[32m✓�[39m src/components/TaskList/durations.test.ts �[2m(�[22m�[2m4 tests�[22m�[2m)�[22m�[32m 7�[2mms�[22m�[39m
 �[32m✓�[39m src/pages/PlanStudioPage.notificationIntent.test.tsx �[2m(�[22m�[2m2 tests�[22m�[2m)�[22m�[32m 82�[2mms�[22m�[39m
 �[32m✓�[39m src/components/RouteChunkErrorBoundary.test.tsx �[2m(�[22m�[2m3 tests�[22m�[2m)�[22m�[32m 229�[2mms�[22m�[39m
 �[32m✓�[39m src/desktop/scopedTaskEvents.test.ts �[2m(�[22m�[2m3 tests�[22m�[2m)�[22m�[32m 6�[2mms�[22m�[39m
�[90mstdout�[2m | src/components/TaskDetails/LiveFileChips.test.tsx�[2m > �[22m�[2mLiveFileChips live refreshes�[2m > �[22m�[2mturns the fixture baseline of three burst invalidations into one additional file-changes request
�[22m�[39m[LiveFileChips] Received task update, refreshing file changes: { taskId: �[32m'task-1'�[39m }
[LiveFileChips] Received task update, refreshing file changes: { taskId: �[32m'task-1'�[39m }
[LiveFileChips] Received task update, refreshing file changes: { taskId: �[32m'task-1'�[39m }

 �[32m✓�[39m src/components/TaskDetails/LiveFileChips.test.tsx �[2m(�[22m�[2m1 test�[22m�[2m)�[22m�[32m 38�[2mms�[22m�[39m
 �[32m✓�[39m src/components/TaskPlanner/setupWizardDraftConfig.test.ts �[2m(�[22m�[2m9 tests�[22m�[2m)�[22m�[32m 12�[2mms�[22m�[39m
 �[32m✓�[39m src/hooks/repositoryNonBlockingChecks.test.ts �[2m(�[22m�[2m2 tests�[22m�[2m)�[22m�[32m 6�[2mms�[22m�[39m
 �[32m✓�[39m src/components/TaskDetails/syntaxHighlighter.test.ts �[2m(�[22m�[2m3 tests�[22m�[2m)�[22m�[32m 16�[2mms�[22m�[39m
 �[32m✓�[39m src/api/proprApi.instanceCatalog.test.ts �[2m(�[22m�[2m1 test�[22m�[2m)�[22m�[32m 12�[2mms�[22m�[39m
 �[32m✓�[39m src/components/Repositories/RepoBrowsePanel.test.tsx �[2m(�[22m�[2m1 test�[22m�[2m)�[22m�[32m 39�[2mms�[22m�[39m
 �[32m✓�[39m src/components/TaskPlanner/RefinementChat.focus.test.tsx �[2m(�[22m�[2m1 test�[22m�[2m)�[22m�[32m 212�[2mms�[22m�[39m
 �[32m✓�[39m src/components/TaskDetails/ExecutionEventUtils.test.ts �[2m(�[22m�[2m2 tests�[22m�[2m)�[22m�[32m 5�[2mms�[22m�[39m

�[2m Test Files �[22m �[1m�[32m49 passed�[39m�[22m�[90m (49)�[39m
�[2m      Tests �[22m �[1m�[32m468 passed�[39m�[22m�[90m (468)�[39m
�[2m   Start at �[22m 20:21:57
�[2m   Duration �[22m 48.58s�[2m (environment 44%, tests 33%, import 9%, setup 9%, transform 5%)�[22m

�[2mEnvironment �[22m �[33mjsdom was created 49 times�[39m�[2m · 39.71s total, 44% of tracked time�[22m
�[2m            �[22m �[2mcreate it once per worker with �[22m�[33mpool: 'vmThreads'�[39m�[2m (keeps per-file isolation) or �[22m�[33misolate: false�[39m�[2m (shares it across files)�[22m
�[2m            �[22m �[2mlearn more: https://vitest.dev/guide/improving-performance#test-environments�[22m


> propr-ui@0.0.1 posttest
> npm run test:docker-context


> propr-ui@0.0.1 test:docker-context
> node --test scripts/docker-context-inputs.test.mjs

TAP version 13
# Subtest: focused UI selectors are forwarded only to Vitest
ok 1 - focused UI selectors are forwarded only to Vitest
  ---
  duration_ms: 0.935343
  type: 'test'
  ...
# Subtest: the UI Docker context contains its complete non-type external source import closure
ok 2 - the UI Docker context contains its complete non-type external source import closure
  ---
  duration_ms: 50.778394
  type: 'test'
  ...
1..2
# tests 2
# suites 0
# pass 2
# fail 0
# cancelled 0
# skipped 0
# todo 0
# duration_ms 107.503138
[150/150] passed propr-ui#1/4 (workspace test script) in 49.4s

### Shard 2/4: 149/150 passed in 421.2s

Assigned 150 of 601 discovered units.

| Duration | Status | Unit |
| ---: | --- | --- |
| 64.1s | passed | `packages/api/test/mcpAccessLog.test.ts` |
| 49.4s | passed | `propr-ui#1/4` (workspace) |
| 30.1s | passed | `apps/desktop/src/profile-store.crash-recovery.test.ts` |
| 24.3s | passed | `packages/api/test/mcpBrowser.test.ts` |
| 11.3s | passed | `apps/desktop/src/saved-accounts.test.ts` |
| 11.0s | failed | `apps/desktop/scripts/desktop-native-menu.test.mjs` |
| 10.6s | passed | `packages/api/test/mcpWorkflows.test.ts` |
| 10.5s | passed | `test/antigravityAgent.test.ts` |
| 6.9s | passed | `packages/api/test/webPushDispatcher.test.ts` |
| 6.0s | passed | `apps/desktop/src/credential-service.test.ts` |
| 5.7s | passed | `test/notificationPublicEntrypoint.test.ts` |
| 5.5s | passed | `test/generateContext.test.ts` |
| 4.9s | passed | `apps/desktop/scripts/macos-window-chrome.test.mjs` |
| 4.5s | passed | `packages/api/test/mcpOperatorSurface.test.ts` |
| 4.5s | passed | `packages/api/test/mcpGoalTaskDepth.test.ts` |


1/150 test runs failed in shard 2/4 after 421.2s:
- apps/desktop/scripts/desktop-native-menu.test.mjs: exit 1

Details truncated; see the uploaded artifacts for complete failure rows and logs.

View Workflow
View uploaded artifacts

@propr-dev

propr-dev Bot commented Sep 29, 2026 •

Copy link
Copy Markdown
Contributor Author

✅ Applied the requested follow-up changes in commit 12bc771

Summary of Changes

Fixed the stale assertion in desktop-native-menu.test.mjs. It now verifies that “Plan first” stays visible while Advanced Options expands and collapses Agent/Model settings.

The targeted suite passes for both Linux and macOS fixture flows through the CI test runner. Full suite not rerun. Test-only change; no visual previews needed.


🤖 Implementation Details

  • Model: GPT-6 Astra (high)
  • Requested By: @github-actions[bot]
  • Time: 2m 41s
  • Tokens: 608,780 (606,874 in / 1,906 out)
  • Cost: $1.14

Undo Changes • View Task Execution


💡 ProPR Slash Commands
Command Description Example
/merge Merge target branch into this PR and resolve conflicts /merge
/review Request an AI code review /review or /review claude-sonnet
/fix Implement fixes for issues found by /review /fix or /fix address the null check issue
/switch Change the AI model for this PR /switch claude-opus
/use Override the model for a single follow-up run /use claude-sonnet
/ultrafix Loop review→fix cycles until score goal is met /ultrafix or /ultrafix goal=8 max=10

🤖 Generated by ProPR
Processing comment ID: 5898092748✓

…. It now verifies that “Plan first” stays visible while Advanced Options expands and collapses Agent/Model settings.

Fixed the stale assertion in `desktop-native-menu.test.mjs`. It now verifies that “Plan first” stays visible while Advanced Options expands and collapses Agent/Model settings.

The targeted suite passes for both Linux and macOS fixture flows through the CI test runner. Full suite not rerun. Test-only change; no visual previews needed.

PR: #2625
Comment by: @github-actions[bot] (ID: 5898092748)
Model: gpt-6-astra
@integry
integry merged commit b0c5fb5 into main Sep 30, 2026
48 checks passed
@integry
integry deleted the 2624/gpt-6-astra-new-goal-and-task-screen--20260929-1202-2hj branch September 30, 2026 14:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

New goal and task screen standardization

1 participant